Skip to content

Commit f001fd4

Browse files
committed
test(rpc): add bip158 tests
1 parent 9216742 commit f001fd4

File tree

1 file changed

+114
-0
lines changed

1 file changed

+114
-0
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
use bitcoin::{constants, Network};
2+
3+
use bdk_bitcoind_rpc::bip158::FilterIter;
4+
use bdk_core::{BlockId, CheckPoint};
5+
use bdk_testenv::{anyhow, bitcoind, TestEnv};
6+
use bitcoincore_rpc::RpcApi;
7+
8+
macro_rules! block_id {
9+
($height:expr, $hash:literal) => {{
10+
BlockId {
11+
height: $height,
12+
hash: bdk_core::bitcoin::hashes::Hash::hash($hash.as_bytes()),
13+
}
14+
}};
15+
}
16+
17+
// Test the result of `chain_update` given a local checkpoint.
18+
//
19+
// new blocks
20+
// 2--3--4--5--6--7--8--9--10--11
21+
//
22+
// case 1: base below new blocks
23+
// 0-
24+
// case 2: base overlaps with new blocks
25+
// 0--1--2--3--4
26+
// case 3: stale tip (with overlap)
27+
// 0--1--2--3--4--x
28+
// case 4: stale tip (no overlap)
29+
// 0--x
30+
#[test]
31+
fn get_tip_and_chain_update() -> anyhow::Result<()> {
32+
let mut conf = bitcoind::Conf::default();
33+
conf.args.push("-blockfilterindex=1");
34+
conf.args.push("-peerblockfilters=1");
35+
let env = TestEnv::new_with_config(bdk_testenv::Config {
36+
bitcoind: conf,
37+
..Default::default()
38+
})?;
39+
40+
// Start by mining ten blocks
41+
let hash = env.rpc_client().get_best_block_hash()?;
42+
let header = env.rpc_client().get_block_header_info(&hash)?;
43+
assert_eq!(header.height, 1);
44+
let block_1 = BlockId {
45+
height: header.height as u32,
46+
hash,
47+
};
48+
49+
let genesis_hash = constants::genesis_block(Network::Regtest).block_hash();
50+
let genesis = BlockId {
51+
height: 0,
52+
hash: genesis_hash,
53+
};
54+
55+
// `FilterIter` will try to return up to ten recent blocks
56+
// so we keep them for reference
57+
let new_blocks: Vec<BlockId> = (2..=11)
58+
.zip(env.mine_blocks(10, None)?)
59+
.map(BlockId::from)
60+
.collect();
61+
62+
struct TestCase {
63+
// name
64+
name: &'static str,
65+
// local blocks
66+
chain: Vec<BlockId>,
67+
// expected blocks
68+
exp: Vec<BlockId>,
69+
}
70+
71+
// For each test we create a new `FilterIter` with the checkpoint given
72+
// by the blocks in the test chain. Then we sync to the remote tip and
73+
// check the blocks that are returned in the chain update.
74+
[
75+
TestCase {
76+
name: "point of agreement below new blocks, expect base + new",
77+
chain: vec![genesis, block_1],
78+
exp: [block_1].into_iter().chain(new_blocks.clone()).collect(),
79+
},
80+
TestCase {
81+
name: "point of agreement genesis, expect base + new",
82+
chain: vec![genesis],
83+
exp: [genesis].into_iter().chain(new_blocks.clone()).collect(),
84+
},
85+
TestCase {
86+
name: "point of agreement within new blocks, expect base + remaining",
87+
chain: new_blocks[..=2].to_vec(),
88+
exp: new_blocks[2..].to_vec(),
89+
},
90+
TestCase {
91+
name: "stale tip within new blocks, expect base + corrected + remaining",
92+
// base height: 4, stale height: 5
93+
chain: vec![new_blocks[2], block_id!(5, "E")],
94+
exp: new_blocks[2..].to_vec(),
95+
},
96+
TestCase {
97+
name: "stale tip below new blocks, expect base + corrected + new",
98+
chain: vec![genesis, block_id!(1, "A")],
99+
exp: [genesis, block_1].into_iter().chain(new_blocks).collect(),
100+
},
101+
]
102+
.into_iter()
103+
.for_each(|test| {
104+
let cp = CheckPoint::from_block_ids(test.chain).unwrap();
105+
let mut it = FilterIter::new_with_checkpoint(env.rpc_client(), cp);
106+
let _ = it.get_tip().unwrap();
107+
let update_cp = it.chain_update().unwrap().unwrap();
108+
let mut update_blocks: Vec<_> = update_cp.iter().map(|cp| cp.block_id()).collect();
109+
update_blocks.reverse();
110+
assert_eq!(update_blocks, test.exp, "{}", test.name);
111+
});
112+
113+
Ok(())
114+
}

0 commit comments

Comments
 (0)