From: valued mammal Date: Sat, 22 Nov 2025 00:36:58 +0000 (-0500) Subject: test(bdk_bitcoind_rpc): update it's tests to use `ClientExt` X-Git-Url: http://internal-gitweb-vhost/%22https:/parse/scripts/database/-script/encode/enum.AnyDatabaseConfig.html?a=commitdiff_plain;h=f3931455da40fa1f4ee9159bfca63931665ef2a7;p=bdk test(bdk_bitcoind_rpc): update it's tests to use `ClientExt` - introduces `ClientExt` trait to `bdk_bitcoind_rpc` common tests module. - update all `bdk_bitcoind_rpc` tests to build the `Emitter` using the `ClientExt` trait, which allows it to use the old `bitcoincore-rpc::RpcApi` with the corepc-node background. --- diff --git a/crates/bitcoind_rpc/src/lib.rs b/crates/bitcoind_rpc/src/lib.rs index 30fc556b..06c4fe0a 100644 --- a/crates/bitcoind_rpc/src/lib.rs +++ b/crates/bitcoind_rpc/src/lib.rs @@ -399,7 +399,7 @@ impl BitcoindRpcErrorExt for bitcoincore_rpc::Error { #[cfg(test)] #[cfg_attr(coverage_nightly, coverage(off))] mod test { - use crate::{bitcoincore_rpc::RpcApi, Emitter, NO_EXPECTED_MEMPOOL_TXS}; + use crate::{Emitter, NO_EXPECTED_MEMPOOL_TXS}; use bdk_chain::local_chain::LocalChain; use bdk_testenv::{anyhow, TestEnv}; use bitcoin::{hashes::Hash, Address, Amount, ScriptBuf, Txid, WScriptHash}; @@ -408,14 +408,15 @@ mod test { #[test] fn test_expected_mempool_txids_accumulate_and_remove() -> anyhow::Result<()> { let env = TestEnv::new()?; - let chain = LocalChain::from_genesis(env.rpc_client().get_block_hash(0)?).0; + let (chain, _) = LocalChain::from_genesis(env.genesis_hash()?); let chain_tip = chain.tip(); - let mut emitter = Emitter::new( - env.rpc_client(), - chain_tip.clone(), - 1, - NO_EXPECTED_MEMPOOL_TXS, - ); + + let rpc_client = bitcoincore_rpc::Client::new( + &env.bitcoind.rpc_url(), + bitcoincore_rpc::Auth::CookieFile(env.bitcoind.params.cookie_file.clone()), + )?; + + let mut emitter = Emitter::new(&rpc_client, chain_tip.clone(), 1, NO_EXPECTED_MEMPOOL_TXS); env.mine_blocks(100, None)?; while emitter.next_block()?.is_some() {} diff --git a/crates/bitcoind_rpc/tests/common/mod.rs b/crates/bitcoind_rpc/tests/common/mod.rs new file mode 100644 index 00000000..bbd914cc --- /dev/null +++ b/crates/bitcoind_rpc/tests/common/mod.rs @@ -0,0 +1,20 @@ +use bdk_testenv::anyhow; +use bdk_testenv::TestEnv; + +/// This trait is used for testing. It allows creating a new [`bitcoincore_rpc::Client`] connected +/// to the instance of bitcoind running in the test environment. This way the `TestEnv` and the +/// `Emitter` aren't required to share the same client. In the future when we no longer depend on +/// `bitcoincore-rpc`, this can be updated to return the production client that is used by BDK. +pub trait ClientExt { + /// Creates a new [`bitcoincore_rpc::Client`] connected to the current node instance. + fn get_rpc_client(&self) -> anyhow::Result; +} + +impl ClientExt for TestEnv { + fn get_rpc_client(&self) -> anyhow::Result { + Ok(bitcoincore_rpc::Client::new( + &self.bitcoind.rpc_url(), + bitcoincore_rpc::Auth::CookieFile(self.bitcoind.params.cookie_file.clone()), + )?) + } +} diff --git a/crates/bitcoind_rpc/tests/test_emitter.rs b/crates/bitcoind_rpc/tests/test_emitter.rs index 6453037e..67cbb329 100644 --- a/crates/bitcoind_rpc/tests/test_emitter.rs +++ b/crates/bitcoind_rpc/tests/test_emitter.rs @@ -7,9 +7,16 @@ use bdk_chain::{ spk_txout::SpkTxOutIndex, Balance, BlockId, CanonicalizationParams, IndexedTxGraph, Merge, }; -use bdk_testenv::{anyhow, TestEnv}; -use bitcoin::{hashes::Hash, Block, Network, OutPoint, ScriptBuf, WScriptHash}; -use bitcoincore_rpc::RpcApi; +use bdk_testenv::{ + anyhow, + corepc_node::{Input, Output}, + TestEnv, +}; +use bitcoin::{hashes::Hash, Block, Network, ScriptBuf, WScriptHash}; + +use crate::common::ClientExt; + +mod common; /// Ensure that blocks are emitted in order even after reorg. /// @@ -20,21 +27,18 @@ use bitcoincore_rpc::RpcApi; #[test] pub fn test_sync_local_chain() -> anyhow::Result<()> { let env = TestEnv::new()?; - let network_tip = env.rpc_client().get_block_count()?; - let (mut local_chain, _) = LocalChain::from_genesis(env.rpc_client().get_block_hash(0)?); - let mut emitter = Emitter::new( - env.rpc_client(), - local_chain.tip(), - 0, - NO_EXPECTED_MEMPOOL_TXS, - ); + let network_tip = env.rpc_client().get_block_count()?.into_model().0; + let (mut local_chain, _) = LocalChain::from_genesis(env.genesis_hash()?); + + let client = ClientExt::get_rpc_client(&env)?; + let mut emitter = Emitter::new(&client, local_chain.tip(), 0, NO_EXPECTED_MEMPOOL_TXS); // Mine some blocks and return the actual block hashes. // Because initializing `ElectrsD` already mines some blocks, we must include those too when // returning block hashes. let exp_hashes = { let mut hashes = (0..=network_tip) - .map(|height| env.rpc_client().get_block_hash(height)) + .map(|height| env.get_block_hash(height)) .collect::, _>>()?; hashes.extend(env.mine_blocks(101 - network_tip as usize, None)?); hashes @@ -140,19 +144,24 @@ fn test_into_tx_graph() -> anyhow::Result<()> { let addr_0 = env .rpc_client() .get_new_address(None, None)? + .address()? .assume_checked(); + let addr_1 = env .rpc_client() .get_new_address(None, None)? + .address()? .assume_checked(); + let addr_2 = env .rpc_client() .get_new_address(None, None)? + .address()? .assume_checked(); env.mine_blocks(101, None)?; - let (mut chain, _) = LocalChain::from_genesis(env.rpc_client().get_block_hash(0)?); + let (mut chain, _) = LocalChain::from_genesis(env.genesis_hash()?); let mut indexed_tx_graph = IndexedTxGraph::::new({ let mut index = SpkTxOutIndex::::default(); index.insert_spk(0, addr_0.script_pubkey()); @@ -161,7 +170,8 @@ fn test_into_tx_graph() -> anyhow::Result<()> { index }); - let emitter = &mut Emitter::new(env.rpc_client(), chain.tip(), 0, NO_EXPECTED_MEMPOOL_TXS); + let client = ClientExt::get_rpc_client(&env)?; + let emitter = &mut Emitter::new(&client, chain.tip(), 0, NO_EXPECTED_MEMPOOL_TXS); while let Some(emission) = emitter.next_block()? { let height = emission.block_height(); @@ -174,16 +184,11 @@ fn test_into_tx_graph() -> anyhow::Result<()> { let exp_txids = { let mut txids = BTreeSet::new(); for _ in 0..3 { - txids.insert(env.rpc_client().send_to_address( - &addr_0, - Amount::from_sat(10_000), - None, - None, - None, - None, - None, - None, - )?); + txids.insert( + env.rpc_client() + .send_to_address(&addr_0, Amount::from_sat(10_000))? + .txid()?, + ); } txids }; @@ -210,7 +215,10 @@ fn test_into_tx_graph() -> anyhow::Result<()> { // mine a block that confirms the 3 txs let exp_block_hash = env.mine_blocks(1, None)?[0]; - let exp_block_height = env.rpc_client().get_block_info(&exp_block_hash)?.height as u32; + let exp_block_height = env + .rpc_client() + .get_block_verbose_one(exp_block_hash)? + .height as u32; let exp_anchors = exp_txids .iter() .map({ @@ -250,9 +258,11 @@ fn ensure_block_emitted_after_reorg_is_at_reorg_height() -> anyhow::Result<()> { const CHAIN_TIP_HEIGHT: usize = 110; let env = TestEnv::new()?; + + let client = ClientExt::get_rpc_client(&env)?; let mut emitter = Emitter::new( - env.rpc_client(), - CheckPoint::new(0, env.rpc_client().get_block_hash(0)?), + &client, + CheckPoint::new(0, env.genesis_hash()?), EMITTER_START_HEIGHT as _, NO_EXPECTED_MEMPOOL_TXS, ); @@ -325,9 +335,11 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> { const SEND_AMOUNT: Amount = Amount::from_sat(10_000); let env = TestEnv::new()?; + + let client = ClientExt::get_rpc_client(&env)?; let mut emitter = Emitter::new( - env.rpc_client(), - CheckPoint::new(0, env.rpc_client().get_block_hash(0)?), + &client, + CheckPoint::new(0, env.genesis_hash()?), 0, NO_EXPECTED_MEMPOOL_TXS, ); @@ -336,12 +348,13 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> { let addr_to_mine = env .rpc_client() .get_new_address(None, None)? + .address()? .assume_checked(); let spk_to_track = ScriptBuf::new_p2wsh(&WScriptHash::all_zeros()); let addr_to_track = Address::from_script(&spk_to_track, Network::Regtest)?; // setup receiver - let (mut recv_chain, _) = LocalChain::from_genesis(env.rpc_client().get_block_hash(0)?); + let (mut recv_chain, _) = LocalChain::from_genesis(env.genesis_hash()?); let mut recv_graph = IndexedTxGraph::::new({ let mut recv_index = SpkTxOutIndex::default(); recv_index.insert_spk((), spk_to_track.clone()); @@ -358,14 +371,16 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> { // lock outputs that send to `addr_to_track` let outpoints_to_lock = env .rpc_client() - .get_transaction(&txid, None)? - .transaction()? + .get_transaction(txid)? + .into_model()? + .tx .output .into_iter() .enumerate() .filter(|(_, txo)| txo.script_pubkey == spk_to_track) - .map(|(vout, _)| OutPoint::new(txid, vout as _)) + .map(|(vout, _)| (txid, vout as u32)) .collect::>(); + env.rpc_client().lock_unspent(&outpoints_to_lock)?; let _ = env.mine_blocks(1, None)?; @@ -413,9 +428,11 @@ fn mempool_avoids_re_emission() -> anyhow::Result<()> { const MEMPOOL_TX_COUNT: usize = 2; let env = TestEnv::new()?; + + let client = ClientExt::get_rpc_client(&env)?; let mut emitter = Emitter::new( - env.rpc_client(), - CheckPoint::new(0, env.rpc_client().get_block_hash(0)?), + &client, + CheckPoint::new(0, env.genesis_hash()?), 0, NO_EXPECTED_MEMPOOL_TXS, ); @@ -424,6 +441,7 @@ fn mempool_avoids_re_emission() -> anyhow::Result<()> { let addr = env .rpc_client() .get_new_address(None, None)? + .address()? .assume_checked(); env.mine_blocks(BLOCKS_TO_MINE, Some(addr.clone()))?; while emitter.next_block()?.is_some() {} @@ -482,10 +500,11 @@ fn no_agreement_point() -> anyhow::Result<()> { let env = TestEnv::new()?; + let client = ClientExt::get_rpc_client(&env)?; // start height is 99 let mut emitter = Emitter::new( - env.rpc_client(), - CheckPoint::new(0, env.rpc_client().get_block_hash(0)?), + &client, + CheckPoint::new(0, env.genesis_hash()?), (PREMINE_COUNT - 2) as u32, NO_EXPECTED_MEMPOOL_TXS, ); @@ -507,12 +526,12 @@ fn no_agreement_point() -> anyhow::Result<()> { let block_hash_100a = block_header_100a.block_hash(); // get hash for block 101a - let block_hash_101a = env.rpc_client().get_block_hash(101)?; + let block_hash_101a = env.rpc_client().get_block_hash(101)?.block_hash()?; // invalidate blocks 99a, 100a, 101a - env.rpc_client().invalidate_block(&block_hash_99a)?; - env.rpc_client().invalidate_block(&block_hash_100a)?; - env.rpc_client().invalidate_block(&block_hash_101a)?; + env.rpc_client().invalidate_block(block_hash_99a)?; + env.rpc_client().invalidate_block(block_hash_100a)?; + env.rpc_client().invalidate_block(block_hash_101a)?; // mine new blocks 99b, 100b, 101b env.mine_blocks(3, None)?; @@ -542,13 +561,11 @@ fn no_agreement_point() -> anyhow::Result<()> { #[test] fn test_expect_tx_evicted() -> anyhow::Result<()> { use bdk_bitcoind_rpc::bitcoincore_rpc::bitcoin; - use bdk_bitcoind_rpc::bitcoincore_rpc::bitcoincore_rpc_json::CreateRawTransactionInput; use bdk_chain::miniscript; use bdk_chain::spk_txout::SpkTxOutIndex; use bitcoin::constants::genesis_block; use bitcoin::secp256k1::Secp256k1; use bitcoin::Network; - use std::collections::HashMap; let env = TestEnv::new()?; let s = bdk_testenv::utils::DESCRIPTORS[0]; @@ -570,12 +587,10 @@ fn test_expect_tx_evicted() -> anyhow::Result<()> { &Address::from_script(&spk, Network::Regtest)?, Amount::ONE_BTC, )?; - let tx_1 = env - .rpc_client() - .get_transaction(&txid_1, None)? - .transaction()?; + let tx_1 = env.rpc_client().get_transaction(txid_1)?.into_model()?.tx; - let mut emitter = Emitter::new(env.rpc_client(), chain.tip(), 1, core::iter::once(tx_1)); + let client = ClientExt::get_rpc_client(&env)?; + let mut emitter = Emitter::new(&client, chain.tip(), 1, core::iter::once(tx_1)); while let Some(emission) = emitter.next_block()? { let height = emission.block_height(); chain.apply_header(&emission.block.header, height)?; @@ -592,25 +607,28 @@ fn test_expect_tx_evicted() -> anyhow::Result<()> { // Get `prevout` from core. let core = env.rpc_client(); - let tx1 = &core.get_raw_transaction(&txid_1, None)?; + let tx1 = core.get_transaction(txid_1)?.into_model()?.tx; let txin = &tx1.input[0]; let op = txin.previous_output; // Create `tx1b` using the previous output from tx1. - let utxo = CreateRawTransactionInput { + let utxo = Input { txid: op.txid, - vout: op.vout, + vout: op.vout as u64, sequence: None, }; - let addr = core.get_new_address(None, None)?.assume_checked(); - let tx = core.create_raw_transaction( - &[utxo], - &HashMap::from([(addr.to_string(), Amount::from_btc(49.99)?)]), - None, - None, - )?; - let res = core.sign_raw_transaction_with_wallet(&tx, None, None)?; - let tx1b = res.transaction()?; + + let addr = core + .get_new_address(None, None)? + .address()? + .assume_checked(); + + let outputs = [Output::new(addr, Amount::from_btc(49.99)?)]; + let tx = core + .create_raw_transaction(&[utxo], &outputs)? + .into_model()? + .0; + let tx1b = core.sign_raw_transaction_with_wallet(&tx)?.into_model()?.tx; // Send the tx. let _txid_2 = core.send_raw_transaction(&tx1b)?; @@ -651,11 +669,13 @@ fn detect_new_mempool_txs() -> anyhow::Result<()> { let addr = env .rpc_client() .get_new_address(None, None)? + .address()? .require_network(Network::Regtest)?; + let client = ClientExt::get_rpc_client(&env)?; let mut emitter = Emitter::new( - env.rpc_client(), - CheckPoint::new(0, env.rpc_client().get_block_hash(0)?), + &client, + CheckPoint::new(0, env.genesis_hash()?), 0, NO_EXPECTED_MEMPOOL_TXS, ); diff --git a/crates/bitcoind_rpc/tests/test_filter_iter.rs b/crates/bitcoind_rpc/tests/test_filter_iter.rs index eafe8250..e45e5331 100644 --- a/crates/bitcoind_rpc/tests/test_filter_iter.rs +++ b/crates/bitcoind_rpc/tests/test_filter_iter.rs @@ -1,11 +1,15 @@ use bdk_bitcoind_rpc::bip158::{Error, FilterIter}; use bdk_core::CheckPoint; -use bdk_testenv::{anyhow, bitcoind, TestEnv}; +use bdk_testenv::{anyhow, corepc_node, TestEnv}; use bitcoin::{Address, Amount, Network, ScriptBuf}; use bitcoincore_rpc::RpcApi; +use crate::common::ClientExt; + +mod common; + fn testenv() -> anyhow::Result { - let mut conf = bitcoind::Conf::default(); + let mut conf = corepc_node::Conf::default(); conf.args.push("-blockfilterindex=1"); conf.args.push("-peerblockfilters=1"); TestEnv::new_with_config(bdk_testenv::Config { @@ -17,13 +21,12 @@ fn testenv() -> anyhow::Result { #[test] fn filter_iter_matches_blocks() -> anyhow::Result<()> { let env = testenv()?; - let addr = env - .rpc_client() + let addr = ClientExt::get_rpc_client(&env)? .get_new_address(None, None)? .assume_checked(); let _ = env.mine_blocks(100, Some(addr.clone()))?; - assert_eq!(env.rpc_client().get_block_count()?, 101); + assert_eq!(ClientExt::get_rpc_client(&env)?.get_block_count()?, 101); // Send tx to external address to confirm at height = 102 let _txid = env.send( @@ -38,7 +41,8 @@ fn filter_iter_matches_blocks() -> anyhow::Result<()> { let genesis_hash = env.genesis_hash()?; let cp = CheckPoint::new(0, genesis_hash); - let iter = FilterIter::new(&env.bitcoind.client, cp, [addr.script_pubkey()]); + let client = ClientExt::get_rpc_client(&env)?; + let iter = FilterIter::new(&client, cp, [addr.script_pubkey()]); for res in iter { let event = res?; @@ -60,7 +64,8 @@ fn filter_iter_error_wrong_network() -> anyhow::Result<()> { // Try to initialize FilterIter with a CP on the wrong network let cp = CheckPoint::new(0, bitcoin::hashes::Hash::hash(b"wrong-hash")); - let mut iter = FilterIter::new(&env.bitcoind.client, cp, [ScriptBuf::new()]); + let client = ClientExt::get_rpc_client(&env)?; + let mut iter = FilterIter::new(&client, cp, [ScriptBuf::new()]); assert!(matches!(iter.next(), Some(Err(Error::ReorgDepthExceeded)))); Ok(()) @@ -72,7 +77,7 @@ fn filter_iter_detects_reorgs() -> anyhow::Result<()> { const MINE_TO: u32 = 16; let env = testenv()?; - let rpc = env.rpc_client(); + let rpc = ClientExt::get_rpc_client(&env)?; while rpc.get_block_count()? < MINE_TO as u64 { let _ = env.mine_blocks(1, None)?; } @@ -81,7 +86,8 @@ fn filter_iter_detects_reorgs() -> anyhow::Result<()> { let cp = CheckPoint::new(0, genesis_hash); let spk = ScriptBuf::from_hex("0014446906a6560d8ad760db3156706e72e171f3a2aa")?; - let mut iter = FilterIter::new(&env.bitcoind.client, cp, [spk]); + let client = ClientExt::get_rpc_client(&env)?; + let mut iter = FilterIter::new(&client, cp, [spk]); // Process events to height (MINE_TO - 1) loop { @@ -131,7 +137,8 @@ fn event_checkpoint_connects_to_local_chain() -> anyhow::Result<()> { .collect(); // Construct iter - let mut iter = FilterIter::new(&env.bitcoind.client, cp, vec![ScriptBuf::new()]); + let client = ClientExt::get_rpc_client(&env)?; + let mut iter = FilterIter::new(&client, cp, vec![ScriptBuf::new()]); // Now reorg 3 blocks (14, 15, 16) let new_hashes: BTreeMap = (14..=16).zip(env.reorg(3)?).collect();