Skip to content

Add submitBlock(), misc. test improvements#12

Open
Sjors wants to merge 7 commits into
2140-dev:masterfrom
Sjors:2026/03/submitblock
Open

Add submitBlock(), misc. test improvements#12
Sjors wants to merge 7 commits into
2140-dev:masterfrom
Sjors:2026/03/submitblock

Conversation

@Sjors
Copy link
Copy Markdown
Collaborator

@Sjors Sjors commented Mar 5, 2026

This adds submitBlock() which is introduced by bitcoin/bitcoin#34644.

This PR also cleans up existing tests a bit.

Best reviewed per commit.

@Sjors
Copy link
Copy Markdown
Collaborator Author

Sjors commented Mar 6, 2026

Rebased after #9.

@Sjors
Copy link
Copy Markdown
Collaborator Author

Sjors commented Mar 11, 2026

Rebased after #14.

@Sjors Sjors force-pushed the 2026/03/submitblock branch from fa5ca24 to fa7c2fa Compare May 28, 2026 12:38
@Sjors Sjors marked this pull request as ready for review May 28, 2026 12:47
@Sjors
Copy link
Copy Markdown
Collaborator Author

Sjors commented May 28, 2026

bitcoin/bitcoin#34644 landed in master and should be in v32. Ready for review.

Comment thread tests/test.rs Outdated
Comment on lines +238 to +241
/// submitBlock with a template block should be rejected (unsolved high-hash).
#[tokio::test]
#[serial_test::serial]
async fn mining_submit_block() {
Copy link
Copy Markdown
Collaborator

@plebhash plebhash May 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC this test is asserting an error case (block without solution), so IMO the test name should express that in a more explicit way

Suggested change
/// submitBlock with a template block should be rejected (unsolved high-hash).
#[tokio::test]
#[serial_test::serial]
async fn mining_submit_block() {
/// submitBlock with a template block should be rejected (unsolved high-hash).
#[tokio::test]
#[serial_test::serial]
async fn mining_submit_block_unresolved() {

moreover, I'd also add a mining_submit_block_resolved() counterpart, asserting the successful case

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We now cover both cases.

Comment thread tests/test.rs
#[serial_test::serial]
async fn mining_submit_block() {
with_mining_client(|_client, thread, mining| async move {
let template = make_block_template(&mining, &thread).await;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC this will generate a regtest block, for which the blockhash will be essentially pseudorandom

at regtest genesis difficulty, any random sha256d hash has 50% chance of passing the PoW diff target

so this test will fail non-determinstically for reasons that have nothing to do with the correctness of the underlying submitBlock implementation that we're trying to validate

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now deterministic.

Comment thread tests/test.rs Outdated
Comment on lines +263 to +264
let _reason = results.get_reason().unwrap();
let _debug = results.get_debug().unwrap();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be asserted instead of unwrap or maybe we can remove it?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've already refactored some things offline, but will take a look if it still applies...

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found a similar pattern in mining_check_block_and_interrupt and a bunch of other places, so I added commits to fix those too.

@Sjors Sjors force-pushed the 2026/03/submitblock branch from fa7c2fa to 6d2f7e4 Compare May 29, 2026 07:39
@Sjors
Copy link
Copy Markdown
Collaborator Author

Sjors commented May 29, 2026

@plebhash thanks for looking at the test. In this project tests are not supposed to be thorough end-to-end integration tests, so I hadn't really looked the vibed initial version. But they also shouldn't be unstable. And they should probably cover several expected responses.

I added util/miner.rs which ensures a block either has sufficient PoW or doesn't.

In anticipation of possible change in how submitSolution() will deal with duplicates, I added better coverage for that. See bitcoin/bitcoin#34672 (comment).

I cleaned up the existing submitSolution() tests to use helpers and avoid duplicate boilerplate.

The submitBlock() test now covers:

  • an invalid block
  • valid block with low PoW
  • good block
  • duplicate block

Best reviewed per commit.

@Sjors Sjors changed the title Add submitBlock() Add submitBlock(), misc. test improvements May 29, 2026
Comment thread tests/test.rs Outdated
Comment on lines +235 to +243
assert!(
template
.interrupt_wait_request()
.send()
.promise
.await
.is_ok(),
"interruptWait should not fail"
);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove this assert

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and in similar examples I dropped the outer assert! and instead use .expect.

Comment thread tests/test.rs Outdated
Comment on lines +301 to +304
assert!(
mining.interrupt_request().send().promise.await.is_ok(),
"interrupt should not fail"
);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove this assert

Comment thread tests/util/miner.rs Outdated
Comment on lines +81 to +83
fn header_has_valid_pow(header: &BlockHeader) -> bool {
Target::from_compact(header.bits).is_met_by(header.block_hash())
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove this helper.

Comment thread tests/test.rs Outdated
Comment on lines +7 to +8
#[path = "util/miner.rs"]
mod miner_util;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't really use path attribute that often, can we please correct the imports and have indirections via the util module

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I add a commit to clean that up for pre-existing code. And changed later commits to conform.

Comment thread tests/test.rs Outdated
Comment on lines +17 to +51
async fn template_block(
template: &mining_capnp::block_template::Client,
thread: &thread::Client,
) -> Vec<u8> {
transform_template_block(template, thread, |block| block.to_vec()).await
}

async fn transform_template_block<F>(
template: &mining_capnp::block_template::Client,
thread: &thread::Client,
build_block: F,
) -> Vec<u8>
where
F: FnOnce(&[u8]) -> Vec<u8>,
{
let mut get_block_req = template.get_block_request();
get_block_req
.get()
.get_context()
.unwrap()
.set_thread(thread.clone());
let get_block_resp = get_block_req.send().promise.await.unwrap();
build_block(get_block_resp.get().unwrap().get_result().unwrap())
}

async fn submit_solution(
template: &mining_capnp::block_template::Client,
thread: &thread::Client,
version: u32,
timestamp: u32,
nonce: u32,
coinbase: &[u8],
) -> bool {
let mut req = template.submit_solution_request();
req.get().get_context().unwrap().set_thread(thread.clone());
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets remove these, makes code hard to understand and keep them inline

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added these helpers to make the tests themselves less verbose, to make it easier to see what different things are being tested.

But after playing around with this a bit, it's not really that helpful. I inlined them again.

To make things slightly less ugly, I replaced the repetitive req.get() with a local variable and use a local scope to group the assignments.

I also added a helper to get a block from a block template.

@Sjors Sjors force-pushed the 2026/03/submitblock branch from 6d2f7e4 to 43a69ca Compare May 29, 2026 10:48
@Sjors
Copy link
Copy Markdown
Collaborator Author

Sjors commented May 29, 2026

Applied @Shourya742's suggestions.

I also renamed tests/util/miner.rs to tests/util/block.rs.

I still find constructing request quite ugly:

let mut req = template.submit_solution_request();
{
   let mut params = req.get();
   params.set_version(solution.version);
   params.set_timestamp(solution.timestamp);
   params.set_nonce(solution.nonce);
   params.set_coinbase(&solution.coinbase);
   params.get_context().unwrap().set_thread(thread.clone());
}
let resp = req.send().

In c++ jargon: why can't we pass a struct into submit_solution_request, instead of using .set_? I guess that requires changes to the underlying crate?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants