Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions capnp/mining.capnp
Original file line number Diff line number Diff line change
Expand Up @@ -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") {
Expand Down
95 changes: 95 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use bitcoin_capnp_types::mining_capnp;
use encoding::encode_to_vec;

#[path = "util/bitcoin_core.rs"]
mod bitcoin_core_util;
Expand Down Expand Up @@ -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.
Expand Down
Loading