From 2cd3cd1dc34b83c389401da1a629432a66d15282 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Thu, 5 Mar 2026 12:38:38 -0300 Subject: [PATCH 1/2] ci: switch to bitcoin/bitcoin#34020 (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..6038482 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#34020 PR branch + cd bitcoin + git fetch --depth 1 origin pull/34020/head:pr-34020 + git checkout pr-34020 - name: Build Bitcoin Core run: | cd bitcoin From c98e1b9ea594733dfa580310fe9856a432935521 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Thu, 5 Mar 2026 12:17:03 -0300 Subject: [PATCH 2/2] mining: add tx lookup IPC methods and integration coverage Add Mining interface methods getTransactionsByTxID and getTransactionsByWitnessID to the capnp schema. Expand integration tests to call both methods with empty inputs, a real mempool transaction id and witness id, and unknown ids, verifying serialized transaction bytes for hits and empty results for misses. --- capnp/mining.capnp | 2 + tests/test.rs | 95 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/capnp/mining.capnp b/capnp/mining.capnp index f790e12..db68db1 100644 --- a/capnp/mining.capnp +++ b/capnp/mining.capnp @@ -23,6 +23,8 @@ 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 () -> (); + getTransactionsByTxID @7 (context :Proxy.Context, txids: List(Data)) -> (result: List(Data)); + getTransactionsByWitnessID @8 (context :Proxy.Context, wtxids: List(Data)) -> (result: List(Data)); } interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") { diff --git a/tests/test.rs b/tests/test.rs index bf7e0d2..16ab900 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,4 +1,5 @@ use bitcoin_capnp_types::mining_capnp; +use encoding::encode_to_vec; #[path = "util/bitcoin_core.rs"] mod bitcoin_core_util; @@ -235,6 +236,100 @@ async fn mining_block_template_lifecycle() { .await; } +/// getTransactionsByTxID and getTransactionsByWitnessID with empty lists and +/// with a non-existent txid/wtxid. +#[tokio::test] +// Serialized because this test may mine blocks to recover wallet funding. +#[serial_test::serial] +async fn mining_get_transactions() { + with_mining_client(|_client, thread, mining| async move { + let wallet = bitcoin_test_wallet(); + ensure_wallet_loaded_and_funded(&wallet); + + let real_tx = create_mempool_self_transfer(&wallet); + let real_txid = real_tx.compute_txid().to_byte_array(); + let real_wtxid = real_tx.compute_wtxid().to_byte_array(); + let real_raw_tx = encode_to_vec(&real_tx); + + // getTransactionsByTxID — empty list should return empty list. + let mut req = mining.get_transactions_by_tx_i_d_request(); + req.get().get_context().unwrap().set_thread(thread.clone()); + req.get().init_txids(0); + let resp = req.send().promise.await.unwrap(); + let results = resp.get().unwrap().get_result().unwrap(); + assert_eq!( + results.len(), + 0, + "empty txid list should return empty results" + ); + + // getTransactionsByTxID — return real mempool tx and empty for unknown id. + let fake_txid = [0x42u8; 32]; + let mut req = mining.get_transactions_by_tx_i_d_request(); + req.get().get_context().unwrap().set_thread(thread.clone()); + { + let mut txids = req.get().init_txids(2); + txids.set(0, &real_txid); + txids.set(1, &fake_txid); + } + let resp = req.send().promise.await.unwrap(); + let results = resp.get().unwrap().get_result().unwrap(); + assert_eq!( + results.len(), + 2, + "should return one entry per requested txid, including misses" + ); + assert_eq!( + results.get(0).unwrap(), + real_raw_tx.as_slice(), + "known txid should return serialized transaction" + ); + assert!( + results.get(1).unwrap().is_empty(), + "non-existent txid should return empty data" + ); + + // getTransactionsByWitnessID — empty list should return empty list. + let mut req = mining.get_transactions_by_witness_i_d_request(); + req.get().get_context().unwrap().set_thread(thread.clone()); + req.get().init_wtxids(0); + let resp = req.send().promise.await.unwrap(); + let results = resp.get().unwrap().get_result().unwrap(); + assert_eq!( + results.len(), + 0, + "empty wtxid list should return empty results" + ); + + // getTransactionsByWitnessID — return real mempool tx and empty for unknown id. + let fake_wtxid = [0x43u8; 32]; + let mut req = mining.get_transactions_by_witness_i_d_request(); + req.get().get_context().unwrap().set_thread(thread.clone()); + { + let mut wtxids = req.get().init_wtxids(2); + wtxids.set(0, &real_wtxid); + wtxids.set(1, &fake_wtxid); + } + let resp = req.send().promise.await.unwrap(); + let results = resp.get().unwrap().get_result().unwrap(); + assert_eq!( + results.len(), + 2, + "should return one entry per requested wtxid, including misses" + ); + assert_eq!( + results.get(0).unwrap(), + real_raw_tx.as_slice(), + "known wtxid should return serialized transaction" + ); + assert!( + results.get(1).unwrap().is_empty(), + "non-existent wtxid should return empty data" + ); + }) + .await; +} + /// checkBlock with a template block payload, and interrupt. #[tokio::test] // Serialized because interrupt() can affect other in-flight mining waits.