From fa7c2facffe3f0ed6bd6c5c349dc25040bd919e2 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Thu, 5 Mar 2026 15:36:23 -0300 Subject: [PATCH 1/3] capnp: add Mining.submitBlock() method --- capnp/mining.capnp | 1 + tests/test.rs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/capnp/mining.capnp b/capnp/mining.capnp index f790e12..2526323 100644 --- a/capnp/mining.capnp +++ b/capnp/mining.capnp @@ -23,6 +23,7 @@ interface Mining $Proxy.wrap("interfaces::Mining") { createNewBlock @4 (context :Proxy.Context, options: BlockCreateOptions, cooldown: Bool = true) -> (result: BlockTemplate); checkBlock @5 (context :Proxy.Context, block: Data, options: BlockCheckOptions) -> (reason: Text, debug: Text, result: Bool); interrupt @6 () -> (); + submitBlock @7 (context :Proxy.Context, block: Data) -> (reason: Text, debug: Text, result: Bool); } interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") { diff --git a/tests/test.rs b/tests/test.rs index bf7e0d2..774d6e6 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -235,6 +235,39 @@ async fn mining_block_template_lifecycle() { .await; } +/// submitBlock with a template block should be rejected (unsolved high-hash). +#[tokio::test] +#[serial_test::serial] +async fn mining_submit_block() { + with_mining_client(|_client, thread, mining| async move { + let template = make_block_template(&mining, &thread).await; + + 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(); + let block = get_block_resp.get().unwrap().get_result().unwrap().to_vec(); + + let mut req = mining.submit_block_request(); + req.get().get_context().unwrap().set_thread(thread.clone()); + req.get().set_block(&block); + let resp = req.send().promise.await.unwrap(); + let results = resp.get().unwrap(); + assert!( + !results.get_result(), + "unsolved template block must not be accepted" + ); + let _reason = results.get_reason().unwrap(); + let _debug = results.get_debug().unwrap(); + + destroy_template(&template, &thread).await; + }) + .await; +} + /// checkBlock with a template block payload, and interrupt. #[tokio::test] // Serialized because interrupt() can affect other in-flight mining waits. From 58e1c27fc8203d94e0981e3b88c337da22731f2f Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Thu, 5 Mar 2026 17:05:55 -0300 Subject: [PATCH 2/3] ci: switch to bitcoin/bitcoin#33922 (DO NOT MERGE) --- .github/workflows/ci.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2985a39..e3f178f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,12 @@ jobs: key: ccache-${{ runner.os }}-${{ github.sha }} restore-keys: ccache-${{ runner.os }}- - name: Checkout Bitcoin Core - run: git clone --depth 1 --branch master https://github.com/bitcoin/bitcoin.git + run: | + git clone --depth 1 https://github.com/bitcoin/bitcoin.git + # DO NOT MERGE: switch to bitcoin/bitcoin#33922 PR branch + cd bitcoin + git fetch --depth 1 origin pull/33922/head:pr-33922 + git checkout pr-33922 - name: Build Bitcoin Core run: | cd bitcoin From 87fdd0b9de56442a931967c52e1f6d7d37db863e Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Thu, 5 Mar 2026 17:06:06 -0300 Subject: [PATCH 3/3] mining: add getMemoryLoad capnp definition and test coverage --- capnp/mining.capnp | 5 +++++ tests/test.rs | 9 ++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/capnp/mining.capnp b/capnp/mining.capnp index 2526323..25e6ba2 100644 --- a/capnp/mining.capnp +++ b/capnp/mining.capnp @@ -24,6 +24,7 @@ interface Mining $Proxy.wrap("interfaces::Mining") { checkBlock @5 (context :Proxy.Context, block: Data, options: BlockCheckOptions) -> (reason: Text, debug: Text, result: Bool); interrupt @6 () -> (); submitBlock @7 (context :Proxy.Context, block: Data) -> (reason: Text, debug: Text, result: Bool); + getMemoryLoad @8 (context :Proxy.Context) -> (result: MemoryLoad); } interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") { @@ -45,6 +46,10 @@ struct BlockCreateOptions $Proxy.wrap("node::BlockCreateOptions") { coinbaseOutputMaxAdditionalSigops @2 :UInt64 = .defaultCoinbaseOutputMaxAdditionalSigops $Proxy.name("coinbase_output_max_additional_sigops"); } +struct MemoryLoad $Proxy.wrap("interfaces::MemoryLoad") { + usage @0 :UInt64; +} + struct BlockWaitOptions $Proxy.wrap("node::BlockWaitOptions") { timeout @0 : Float64 = .maxDouble $Proxy.name("timeout"); feeThreshold @1 : Int64 = .maxMoney $Proxy.name("fee_threshold"); diff --git a/tests/test.rs b/tests/test.rs index 774d6e6..e9e4ffe 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -69,7 +69,7 @@ fn mining_constants() { ); } -/// isTestChain, isInitialBlockDownload, getTip. +/// isTestChain, isInitialBlockDownload, getTip, getMemoryLoad. #[tokio::test] #[serial_test::parallel] async fn mining_basic_queries() { @@ -96,6 +96,13 @@ async fn mining_basic_queries() { let tip_hash = tip.get_hash().unwrap(); assert_eq!(tip_hash.len(), 32, "block hash must be 32 bytes"); assert!(tip.get_height() >= 0, "height must be non-negative"); + + // getMemoryLoad + let mut req = mining.get_memory_load_request(); + req.get().get_context().unwrap().set_thread(thread.clone()); + let resp = req.send().promise.await.unwrap(); + let memory_load = resp.get().unwrap().get_result().unwrap(); + let _usage: u64 = memory_load.get_usage(); }) .await; }