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
13 changes: 10 additions & 3 deletions crates/bitcoind_rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -408,10 +408,17 @@ 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();

// TODO: (@oleonardolima) We should use the `ClientExt` trait instead.
let mut bitcoincore_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(
env.rpc_client(),
&mut bitcoincore_rpc_client,
chain_tip.clone(),
1,
NO_EXPECTED_MEMPOOL_TXS,
Expand Down
20 changes: 20 additions & 0 deletions crates/bitcoind_rpc/tests/common/mod.rs
Original file line number Diff line number Diff line change
@@ -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<bitcoincore_rpc::Client>;
}

impl ClientExt for TestEnv {
fn get_rpc_client(&self) -> anyhow::Result<bitcoincore_rpc::Client> {
Ok(bitcoincore_rpc::Client::new(
&self.bitcoind.rpc_url(),
bitcoincore_rpc::Auth::CookieFile(self.bitcoind.params.cookie_file.clone()),
)?)
}
}
109 changes: 67 additions & 42 deletions crates/bitcoind_rpc/tests/test_emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ use bdk_testenv::{anyhow, TestEnv};
use bitcoin::{hashes::Hash, Block, Network, OutPoint, ScriptBuf, WScriptHash};
use bitcoincore_rpc::RpcApi;

use crate::common::ClientExt;

mod common;

/// Ensure that blocks are emitted in order even after reorg.
///
/// 1. Mine 101 blocks.
Expand All @@ -20,10 +24,12 @@ 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 network_tip = env.rpc_client().get_block_count()?.into_model().0;
let (mut local_chain, _) = LocalChain::from_genesis(env.genesis_hash()?);

let mut bitcoincore_rpc_client = ClientExt::get_rpc_client(&env)?;
let mut emitter = Emitter::new(
env.rpc_client(),
&mut bitcoincore_rpc_client,
local_chain.tip(),
0,
NO_EXPECTED_MEMPOOL_TXS,
Expand All @@ -34,7 +40,11 @@ pub fn test_sync_local_chain() -> anyhow::Result<()> {
// returning block hashes.
let exp_hashes = {
let mut hashes = (0..=network_tip)
.map(|height| env.rpc_client().get_block_hash(height))
.map(|height| {
ClientExt::get_rpc_client(&env)
.unwrap()
.get_block_hash(height)
})
.collect::<Result<Vec<_>, _>>()?;
hashes.extend(env.mine_blocks(101 - network_tip as usize, None)?);
hashes
Expand Down Expand Up @@ -137,22 +147,21 @@ pub fn test_sync_local_chain() -> anyhow::Result<()> {
fn test_into_tx_graph() -> anyhow::Result<()> {
let env = TestEnv::new()?;

let addr_0 = env
.rpc_client()
let mut bitcoincore_rpc_client = ClientExt::get_rpc_client(&env)?;

let addr_0 = bitcoincore_rpc_client
.get_new_address(None, None)?
.assume_checked();
let addr_1 = env
.rpc_client()
let addr_1 = bitcoincore_rpc_client
.get_new_address(None, None)?
.assume_checked();
let addr_2 = env
.rpc_client()
let addr_2 = bitcoincore_rpc_client
.get_new_address(None, None)?
.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::<BlockId, _>::new({
let mut index = SpkTxOutIndex::<usize>::default();
index.insert_spk(0, addr_0.script_pubkey());
Expand All @@ -161,7 +170,12 @@ fn test_into_tx_graph() -> anyhow::Result<()> {
index
});

let emitter = &mut Emitter::new(env.rpc_client(), chain.tip(), 0, NO_EXPECTED_MEMPOOL_TXS);
let emitter = &mut Emitter::new(
&mut bitcoincore_rpc_client,
chain.tip(),
0,
NO_EXPECTED_MEMPOOL_TXS,
);

while let Some(emission) = emitter.next_block()? {
let height = emission.block_height();
Expand All @@ -174,7 +188,7 @@ 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(
txids.insert(ClientExt::get_rpc_client(&env)?.send_to_address(
&addr_0,
Amount::from_sat(10_000),
None,
Expand Down Expand Up @@ -210,7 +224,9 @@ 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 = ClientExt::get_rpc_client(&env)?
.get_block_info(&exp_block_hash)?
.height as u32;
let exp_anchors = exp_txids
.iter()
.map({
Expand Down Expand Up @@ -250,9 +266,11 @@ fn ensure_block_emitted_after_reorg_is_at_reorg_height() -> anyhow::Result<()> {
const CHAIN_TIP_HEIGHT: usize = 110;

let env = TestEnv::new()?;

let mut bitcoincore_rpc_client = ClientExt::get_rpc_client(&env)?;
let mut emitter = Emitter::new(
env.rpc_client(),
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
&mut bitcoincore_rpc_client,
CheckPoint::new(0, env.genesis_hash()?),
EMITTER_START_HEIGHT as _,
NO_EXPECTED_MEMPOOL_TXS,
);
Expand Down Expand Up @@ -325,23 +343,24 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
const SEND_AMOUNT: Amount = Amount::from_sat(10_000);

let env = TestEnv::new()?;

let mut bitcoincore_rpc_client = ClientExt::get_rpc_client(&env)?;
let mut emitter = Emitter::new(
env.rpc_client(),
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
&mut bitcoincore_rpc_client,
CheckPoint::new(0, env.genesis_hash()?),
0,
NO_EXPECTED_MEMPOOL_TXS,
);

// setup addresses
let addr_to_mine = env
.rpc_client()
let addr_to_mine = ClientExt::get_rpc_client(&env)?
.get_new_address(None, None)?
.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::<BlockId, _>::new({
let mut recv_index = SpkTxOutIndex::default();
recv_index.insert_spk((), spk_to_track.clone());
Expand All @@ -356,8 +375,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
let txid = env.send(&addr_to_track, SEND_AMOUNT)?;

// lock outputs that send to `addr_to_track`
let outpoints_to_lock = env
.rpc_client()
let outpoints_to_lock = ClientExt::get_rpc_client(&env)?
.get_transaction(&txid, None)?
.transaction()?
.output
Expand All @@ -366,7 +384,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
.filter(|(_, txo)| txo.script_pubkey == spk_to_track)
.map(|(vout, _)| OutPoint::new(txid, vout as _))
.collect::<Vec<_>>();
env.rpc_client().lock_unspent(&outpoints_to_lock)?;
ClientExt::get_rpc_client(&env)?.lock_unspent(&outpoints_to_lock)?;

let _ = env.mine_blocks(1, None)?;
}
Expand Down Expand Up @@ -413,16 +431,16 @@ fn mempool_avoids_re_emission() -> anyhow::Result<()> {
const MEMPOOL_TX_COUNT: usize = 2;

let env = TestEnv::new()?;
let mut bitcoincore_rpc_client = ClientExt::get_rpc_client(&env)?;
let mut emitter = Emitter::new(
env.rpc_client(),
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
&mut bitcoincore_rpc_client,
CheckPoint::new(0, env.genesis_hash()?),
0,
NO_EXPECTED_MEMPOOL_TXS,
);

// mine blocks and sync up emitter
let addr = env
.rpc_client()
let addr = ClientExt::get_rpc_client(&env)?
.get_new_address(None, None)?
.assume_checked();
env.mine_blocks(BLOCKS_TO_MINE, Some(addr.clone()))?;
Expand Down Expand Up @@ -482,10 +500,11 @@ fn no_agreement_point() -> anyhow::Result<()> {

let env = TestEnv::new()?;

let mut bitcoincore_rpc_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)?),
&mut bitcoincore_rpc_client,
CheckPoint::new(0, env.genesis_hash()?),
(PREMINE_COUNT - 2) as u32,
NO_EXPECTED_MEMPOOL_TXS,
);
Expand All @@ -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 = ClientExt::get_rpc_client(&env)?.get_block_hash(101)?;

// 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)?;
ClientExt::get_rpc_client(&env)?.invalidate_block(&block_hash_99a)?;
ClientExt::get_rpc_client(&env)?.invalidate_block(&block_hash_100a)?;
ClientExt::get_rpc_client(&env)?.invalidate_block(&block_hash_101a)?;

// mine new blocks 99b, 100b, 101b
env.mine_blocks(3, None)?;
Expand Down Expand Up @@ -570,12 +589,17 @@ fn test_expect_tx_evicted() -> anyhow::Result<()> {
&Address::from_script(&spk, Network::Regtest)?,
Amount::ONE_BTC,
)?;
let tx_1 = env
.rpc_client()
let tx_1 = ClientExt::get_rpc_client(&env)?
.get_transaction(&txid_1, None)?
.transaction()?;

let mut emitter = Emitter::new(env.rpc_client(), chain.tip(), 1, core::iter::once(tx_1));
let mut bitcoincore_rpc_client = ClientExt::get_rpc_client(&env)?;
let mut emitter = Emitter::new(
&mut bitcoincore_rpc_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)?;
Expand All @@ -591,7 +615,7 @@ fn test_expect_tx_evicted() -> anyhow::Result<()> {
// Double spend tx1.

// Get `prevout` from core.
let core = env.rpc_client();
let core = ClientExt::get_rpc_client(&env)?;
let tx1 = &core.get_raw_transaction(&txid_1, None)?;
let txin = &tx1.input[0];
let op = txin.previous_output;
Expand Down Expand Up @@ -648,14 +672,15 @@ fn detect_new_mempool_txs() -> anyhow::Result<()> {
let env = TestEnv::new()?;
env.mine_blocks(101, None)?;

let addr = env
.rpc_client()
let mut bitcoincore_rpc_client = ClientExt::get_rpc_client(&env)?;

let addr = bitcoincore_rpc_client
.get_new_address(None, None)?
.require_network(Network::Regtest)?;

let mut emitter = Emitter::new(
env.rpc_client(),
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
&mut bitcoincore_rpc_client,
CheckPoint::new(0, env.genesis_hash()?),
0,
NO_EXPECTED_MEMPOOL_TXS,
);
Expand Down
Loading
Loading