Skip to content

Commit

Permalink
test(rpc): add bip158 tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ValuedMammal committed Sep 17, 2024
1 parent 9e64ee5 commit aa8c49e
Showing 1 changed file with 114 additions and 0 deletions.
114 changes: 114 additions & 0 deletions crates/bitcoind_rpc/tests/bip158.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use bitcoin::{constants, Network};

use bdk_bitcoind_rpc::bip158::FilterIter;
use bdk_core::{BlockId, CheckPoint};
use bdk_testenv::{anyhow, bitcoind, TestEnv};
use bitcoincore_rpc::RpcApi;

macro_rules! block_id {
($height:expr, $hash:literal) => {{
BlockId {
height: $height,
hash: bdk_core::bitcoin::hashes::Hash::hash($hash.as_bytes()),
}
}};
}

// Test the result of `chain_update` given a local checkpoint.
//
// new blocks
// 2--3--4--5--6--7--8--9--10--11
//
// case 1: base below new blocks
// 0-
// case 2: base overlaps with new blocks
// 0--1--2--3--4
// case 3: stale tip (with overlap)
// 0--1--2--3--4--x
// case 4: stale tip (no overlap)
// 0--x
#[test]
fn get_tip_and_chain_update() -> anyhow::Result<()> {
let mut conf = bitcoind::Conf::default();
conf.args.push("-blockfilterindex=1");
conf.args.push("-peerblockfilters=1");
let env = TestEnv::new_with_config(bdk_testenv::Config {
bitcoind: conf,
..Default::default()
})?;

// Start by mining ten blocks
let hash = env.rpc_client().get_best_block_hash()?;
let header = env.rpc_client().get_block_header_info(&hash)?;
assert_eq!(header.height, 1);
let block_1 = BlockId {
height: header.height as u32,
hash,
};

let genesis_hash = constants::genesis_block(Network::Regtest).block_hash();
let genesis = BlockId {
height: 0,
hash: genesis_hash,
};

// `FilterIter` will try to return up to ten recent blocks
// so we keep them for reference
let new_blocks: Vec<BlockId> = (2..=11)
.zip(env.mine_blocks(10, None)?)
.map(BlockId::from)
.collect();

struct TestCase {
// name
name: &'static str,
// local blocks
chain: Vec<BlockId>,
// expected blocks
exp: Vec<BlockId>,
}

// For each test we create a new `FilterIter` with the checkpoint given
// by the blocks in the test chain. Then we sync to the remote tip and
// check the blocks that are returned in the chain update.
[
TestCase {
name: "point of agreement below new blocks, expect base + new",
chain: vec![genesis, block_1],
exp: [block_1].into_iter().chain(new_blocks.clone()).collect(),
},
TestCase {
name: "point of agreement genesis, expect base + new",
chain: vec![genesis],
exp: [genesis].into_iter().chain(new_blocks.clone()).collect(),
},
TestCase {
name: "point of agreement within new blocks, expect base + remaining",
chain: new_blocks[..=2].to_vec(),
exp: new_blocks[2..].to_vec(),
},
TestCase {
name: "stale tip within new blocks, expect base + corrected + remaining",
// base height: 4, stale height: 5
chain: vec![new_blocks[2], block_id!(5, "E")],
exp: new_blocks[2..].to_vec(),
},
TestCase {
name: "stale tip below new blocks, expect base + corrected + new",
chain: vec![genesis, block_id!(1, "A")],
exp: [genesis, block_1].into_iter().chain(new_blocks).collect(),
},
]
.into_iter()
.for_each(|test| {
let cp = CheckPoint::from_block_ids(test.chain).unwrap();
let mut it = FilterIter::new_with_checkpoint(env.rpc_client(), cp);
let _ = it.get_tip().unwrap();
let update_cp = it.chain_update().unwrap();
let mut update_blocks: Vec<_> = update_cp.iter().map(|cp| cp.block_id()).collect();
update_blocks.reverse();
assert_eq!(update_blocks, test.exp, "{}", test.name);
});

Ok(())
}

0 comments on commit aa8c49e

Please sign in to comment.