Skip to content

Commit e84e26f

Browse files
committed
test(esplora): introduce test cases for update_local_chain
1 parent e744f05 commit e84e26f

File tree

1 file changed

+164
-1
lines changed

1 file changed

+164
-1
lines changed

crates/esplora/tests/blocking_ext.rs

Lines changed: 164 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,31 @@
1+
use bdk_chain::local_chain::LocalChain;
2+
use bdk_chain::BlockId;
13
use bdk_esplora::EsploraExt;
24
use electrsd::bitcoind::bitcoincore_rpc::RpcApi;
35
use electrsd::bitcoind::{self, anyhow, BitcoinD};
46
use electrsd::{Conf, ElectrsD};
57
use esplora_client::{self, BlockingClient, Builder};
6-
use std::collections::{BTreeMap, HashSet};
8+
use std::collections::{BTreeMap, BTreeSet, HashSet};
79
use std::str::FromStr;
810
use std::thread::sleep;
911
use std::time::Duration;
1012

1113
use bdk_chain::bitcoin::{Address, Amount, BlockHash, Txid};
1214

15+
macro_rules! h {
16+
($index:literal) => {{
17+
bdk_chain::bitcoin::hashes::Hash::hash($index.as_bytes())
18+
}};
19+
}
20+
21+
macro_rules! local_chain {
22+
[ $(($height:expr, $block_hash:expr)), * ] => {{
23+
#[allow(unused_mut)]
24+
bdk_chain::local_chain::LocalChain::from_blocks([$(($height, $block_hash).into()),*].into_iter().collect())
25+
.expect("chain must have genesis block")
26+
}};
27+
}
28+
1329
struct TestEnv {
1430
bitcoind: BitcoinD,
1531
#[allow(dead_code)]
@@ -39,6 +55,20 @@ impl TestEnv {
3955
})
4056
}
4157

58+
fn reset_electrsd(mut self) -> anyhow::Result<Self> {
59+
let mut electrs_conf = Conf::default();
60+
electrs_conf.http_enabled = true;
61+
let electrs_exe =
62+
electrsd::downloaded_exe_path().expect("electrs version feature must be enabled");
63+
let electrsd = ElectrsD::with_conf(electrs_exe, &self.bitcoind, &electrs_conf)?;
64+
65+
let base_url = format!("http://{}", &electrsd.esplora_url.clone().unwrap());
66+
let client = Builder::new(base_url.as_str()).build_blocking()?;
67+
self.electrsd = electrsd;
68+
self.client = client;
69+
Ok(self)
70+
}
71+
4272
fn mine_blocks(
4373
&self,
4474
count: usize,
@@ -202,3 +232,136 @@ pub fn test_update_tx_graph_gap_limit() -> anyhow::Result<()> {
202232

203233
Ok(())
204234
}
235+
236+
#[test]
237+
fn update_local_chain() -> anyhow::Result<()> {
238+
const TIP_HEIGHT: u32 = 50;
239+
240+
let env = TestEnv::new()?;
241+
let b = {
242+
let bdc = &env.bitcoind.client;
243+
assert_eq!(bdc.get_block_count()?, 1);
244+
[(0, bdc.get_block_hash(0)?), (1, bdc.get_block_hash(1)?)]
245+
.into_iter()
246+
.chain((2..).zip(env.mine_blocks((TIP_HEIGHT - 1) as usize, None)?))
247+
.collect::<BTreeMap<_, _>>()
248+
};
249+
// so new blocks can be seen by Electrs
250+
let env = env.reset_electrsd()?;
251+
252+
struct TestCase {
253+
name: &'static str,
254+
chain: LocalChain,
255+
heights: &'static [u32],
256+
exp_update_heights: &'static [u32],
257+
}
258+
259+
let test_cases = [
260+
TestCase {
261+
name: "request_later_blocks",
262+
chain: local_chain![(0, b[&0]), (21, b[&21])],
263+
heights: &[22, 25, 28],
264+
exp_update_heights: &[21, 22, 25, 28, TIP_HEIGHT],
265+
},
266+
TestCase {
267+
name: "request_prev_blocks",
268+
chain: local_chain![(0, b[&0]), (1, b[&1]), (5, b[&5])],
269+
heights: &[4],
270+
exp_update_heights: &[4, 5, TIP_HEIGHT],
271+
},
272+
TestCase {
273+
name: "request_prev_blocks_2",
274+
chain: local_chain![(0, b[&0]), (1, b[&1]), (10, b[&10])],
275+
heights: &[4, 6],
276+
exp_update_heights: &[4, 6, 10, TIP_HEIGHT],
277+
},
278+
TestCase {
279+
name: "request_later_and_prev_blocks",
280+
chain: local_chain![(0, b[&0]), (7, b[&7]), (11, b[&11])],
281+
heights: &[8, 9, 15],
282+
exp_update_heights: &[8, 9, 11, 15, TIP_HEIGHT],
283+
},
284+
TestCase {
285+
name: "request_tip_only",
286+
chain: local_chain![(0, b[&0]), (5, b[&5]), (49, b[&49])],
287+
heights: &[TIP_HEIGHT],
288+
exp_update_heights: &[49, TIP_HEIGHT],
289+
},
290+
TestCase {
291+
name: "request_nothing",
292+
chain: local_chain![(0, b[&0]), (13, b[&13]), (23, b[&23])],
293+
heights: &[],
294+
exp_update_heights: &[23, TIP_HEIGHT],
295+
},
296+
TestCase {
297+
name: "request_nothing_during_reorg",
298+
chain: local_chain![(0, b[&0]), (13, b[&13]), (23, h!("23"))],
299+
heights: &[],
300+
exp_update_heights: &[13, 23, TIP_HEIGHT],
301+
},
302+
TestCase {
303+
name: "request_nothing_during_reorg_2",
304+
chain: local_chain![(0, b[&0]), (21, b[&21]), (22, h!("22")), (23, h!("23"))],
305+
heights: &[],
306+
exp_update_heights: &[21, 22, 23, TIP_HEIGHT],
307+
},
308+
TestCase {
309+
name: "request_prev_blocks_during_reorg",
310+
chain: local_chain![(0, b[&0]), (21, b[&21]), (22, h!("22")), (23, h!("23"))],
311+
heights: &[17, 20],
312+
exp_update_heights: &[17, 20, 21, 22, 23, TIP_HEIGHT],
313+
},
314+
TestCase {
315+
name: "request_later_blocks_during_reorg",
316+
chain: local_chain![(0, b[&0]), (9, b[&9]), (22, h!("22")), (23, h!("23"))],
317+
heights: &[25, 27],
318+
exp_update_heights: &[9, 22, 23, 25, 27, TIP_HEIGHT],
319+
},
320+
TestCase {
321+
name: "request_later_blocks_during_reorg_2",
322+
chain: local_chain![(0, b[&0]), (9, h!("9"))],
323+
heights: &[10],
324+
exp_update_heights: &[0, 9, 10, TIP_HEIGHT],
325+
},
326+
TestCase {
327+
name: "request_later_and_prev_blocks_during_reorg",
328+
chain: local_chain![(0, b[&0]), (1, b[&1]), (9, h!("9"))],
329+
heights: &[8, 11],
330+
exp_update_heights: &[1, 8, 9, 11, TIP_HEIGHT],
331+
},
332+
];
333+
334+
for (i, t) in test_cases.into_iter().enumerate() {
335+
println!("Case {} : '{}'", i, t.name);
336+
337+
let update = env
338+
.client
339+
.update_local_chain(t.chain.tip(), t.heights.iter().copied())
340+
.map_err(|err| {
341+
anyhow::format_err!("[{}:{}] `update_local_chain` failed: {}", i, t.name, err)
342+
})?;
343+
344+
let update_blocks = update
345+
.tip
346+
.iter()
347+
.map(|cp| cp.block_id())
348+
.collect::<BTreeSet<_>>();
349+
350+
let exp_update_blocks = t
351+
.exp_update_heights
352+
.iter()
353+
.map(|&height| {
354+
let hash = b[&height];
355+
BlockId { height, hash }
356+
})
357+
.collect::<BTreeSet<_>>();
358+
359+
assert_eq!(
360+
update_blocks, exp_update_blocks,
361+
"[{}:{}] unexpected update",
362+
i, t.name
363+
);
364+
}
365+
366+
Ok(())
367+
}

0 commit comments

Comments
 (0)