Skip to content

Commit 6bb1a40

Browse files
committed
feat: added electrum and esplora support to TestEnv
`TestEnv` now supports both `electrum` and `esplora`. `esplora` tests have also been updated to use `TestEnv`.
1 parent 79412aa commit 6bb1a40

File tree

9 files changed

+417
-168
lines changed

9 files changed

+417
-168
lines changed

crates/bitcoind_rpc/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ bdk_chain = { path = "../chain", version = "0.6", default-features = false }
2020

2121
[dev-dependencies]
2222
testenv = { path = "../testenv", version = "0.1.0", default_features = false }
23-
bitcoind = { version = "0.33", features = ["25_0"] }
2423
anyhow = { version = "1" }
2524

2625
[features]

crates/bitcoind_rpc/tests/test_emitter.rs

Lines changed: 61 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,25 @@ fn block_to_chain_update(block: &bitcoin::Block, height: u32) -> local_chain::Up
4343
pub fn test_sync_local_chain() -> anyhow::Result<()> {
4444
let env = TestEnv::new()?;
4545
let mut local_chain = LocalChain::default();
46-
let mut emitter = Emitter::from_height(&env.client, 0);
46+
let tip = env.rpc_client().get_block_count()?;
47+
let mut emitter = Emitter::from_height(env.rpc_client(), tip as u32);
4748

4849
// mine some blocks and returned the actual block hashes
4950
let exp_hashes = {
50-
let mut hashes = vec![env.client.get_block_hash(0)?]; // include genesis block
51-
hashes.extend(env.mine_blocks(101, None)?);
51+
// add the hashes of the genesis block and block generated from initializing electrsd
52+
let mut hashes = (0..=tip)
53+
.map(|height| env.rpc_client().get_block_hash(height))
54+
.collect::<Result<Vec<_>, _>>()?;
55+
hashes.extend(env.mine_blocks(101 - tip as usize, None)?);
5256
hashes
5357
};
5458

59+
// update `local_chain` with block generated from initializing electrsd
60+
for (height, hash) in exp_hashes.iter().enumerate().take(tip as usize) {
61+
let changeset = BTreeMap::from([(height as u32, Some(*hash))]);
62+
local_chain.apply_changeset(&changeset);
63+
}
64+
5565
// see if the emitter outputs the right blocks
5666
println!("first sync:");
5767
while let Some((height, block)) = emitter.next_block()? {
@@ -141,9 +151,18 @@ fn test_into_tx_graph() -> anyhow::Result<()> {
141151
let env = TestEnv::new()?;
142152

143153
println!("getting new addresses!");
144-
let addr_0 = env.client.get_new_address(None, None)?.assume_checked();
145-
let addr_1 = env.client.get_new_address(None, None)?.assume_checked();
146-
let addr_2 = env.client.get_new_address(None, None)?.assume_checked();
154+
let addr_0 = env
155+
.rpc_client()
156+
.get_new_address(None, None)?
157+
.assume_checked();
158+
let addr_1 = env
159+
.rpc_client()
160+
.get_new_address(None, None)?
161+
.assume_checked();
162+
let addr_2 = env
163+
.rpc_client()
164+
.get_new_address(None, None)?
165+
.assume_checked();
147166
println!("got new addresses!");
148167

149168
println!("mining block!");
@@ -159,7 +178,7 @@ fn test_into_tx_graph() -> anyhow::Result<()> {
159178
index
160179
});
161180

162-
let emitter = &mut Emitter::from_height(&env.client, 0);
181+
let emitter = &mut Emitter::from_height(env.rpc_client(), 0);
163182

164183
while let Some((height, block)) = emitter.next_block()? {
165184
let _ = chain.apply_update(block_to_chain_update(&block, height))?;
@@ -171,7 +190,7 @@ fn test_into_tx_graph() -> anyhow::Result<()> {
171190
let exp_txids = {
172191
let mut txids = BTreeSet::new();
173192
for _ in 0..3 {
174-
txids.insert(env.client.send_to_address(
193+
txids.insert(env.rpc_client().send_to_address(
175194
&addr_0,
176195
Amount::from_sat(10_000),
177196
None,
@@ -207,7 +226,7 @@ fn test_into_tx_graph() -> anyhow::Result<()> {
207226

208227
// mine a block that confirms the 3 txs
209228
let exp_block_hash = env.mine_blocks(1, None)?[0];
210-
let exp_block_height = env.client.get_block_info(&exp_block_hash)?.height as u32;
229+
let exp_block_height = env.rpc_client().get_block_info(&exp_block_hash)?.height as u32;
211230
let exp_anchors = exp_txids
212231
.iter()
213232
.map({
@@ -247,13 +266,13 @@ fn ensure_block_emitted_after_reorg_is_at_reorg_height() -> anyhow::Result<()> {
247266
const CHAIN_TIP_HEIGHT: usize = 110;
248267

249268
let env = TestEnv::new()?;
250-
let mut emitter = Emitter::from_height(&env.client, EMITTER_START_HEIGHT as _);
269+
let mut emitter = Emitter::from_height(env.rpc_client(), EMITTER_START_HEIGHT as _);
251270

252271
env.mine_blocks(CHAIN_TIP_HEIGHT, None)?;
253272
while emitter.next_header()?.is_some() {}
254273

255274
for reorg_count in 1..=10 {
256-
let replaced_blocks = env.reorg_empty_blocks(reorg_count)?;
275+
let replaced_blocks = env.reorg_empty_blocks(reorg_count, &env.bitcoind)?;
257276
let (height, next_header) = emitter.next_header()?.expect("must emit block after reorg");
258277
assert_eq!(
259278
(height as usize, next_header.block_hash()),
@@ -315,10 +334,13 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
315334
const SEND_AMOUNT: Amount = Amount::from_sat(10_000);
316335

317336
let env = TestEnv::new()?;
318-
let mut emitter = Emitter::from_height(&env.client, 0);
337+
let mut emitter = Emitter::from_height(env.rpc_client(), 0);
319338

320339
// setup addresses
321-
let addr_to_mine = env.client.get_new_address(None, None)?.assume_checked();
340+
let addr_to_mine = env
341+
.rpc_client()
342+
.get_new_address(None, None)?
343+
.assume_checked();
322344
let spk_to_track = ScriptBuf::new_v0_p2wsh(&WScriptHash::all_zeros());
323345
let addr_to_track = Address::from_script(&spk_to_track, bitcoin::Network::Regtest)?;
324346

@@ -339,7 +361,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
339361

340362
// lock outputs that send to `addr_to_track`
341363
let outpoints_to_lock = env
342-
.client
364+
.rpc_client()
343365
.get_transaction(&txid, None)?
344366
.transaction()?
345367
.output
@@ -348,7 +370,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
348370
.filter(|(_, txo)| txo.script_pubkey == spk_to_track)
349371
.map(|(vout, _)| OutPoint::new(txid, vout as _))
350372
.collect::<Vec<_>>();
351-
env.client.lock_unspent(&outpoints_to_lock)?;
373+
env.rpc_client().lock_unspent(&outpoints_to_lock)?;
352374

353375
let _ = env.mine_blocks(1, None)?;
354376
}
@@ -367,7 +389,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
367389

368390
// perform reorgs with different depths
369391
for reorg_count in 1..=ADDITIONAL_COUNT {
370-
env.reorg_empty_blocks(reorg_count)?;
392+
env.reorg_empty_blocks(reorg_count, &env.bitcoind)?;
371393
sync_from_emitter(&mut recv_chain, &mut recv_graph, &mut emitter)?;
372394

373395
assert_eq!(
@@ -396,10 +418,13 @@ fn mempool_avoids_re_emission() -> anyhow::Result<()> {
396418
const MEMPOOL_TX_COUNT: usize = 2;
397419

398420
let env = TestEnv::new()?;
399-
let mut emitter = Emitter::from_height(&env.client, 0);
421+
let mut emitter = Emitter::from_height(env.rpc_client(), 0);
400422

401423
// mine blocks and sync up emitter
402-
let addr = env.client.get_new_address(None, None)?.assume_checked();
424+
let addr = env
425+
.rpc_client()
426+
.get_new_address(None, None)?
427+
.assume_checked();
403428
env.mine_blocks(BLOCKS_TO_MINE, Some(addr.clone()))?;
404429
while emitter.next_header()?.is_some() {}
405430

@@ -451,10 +476,13 @@ fn mempool_re_emits_if_tx_introduction_height_not_reached() -> anyhow::Result<()
451476
const MEMPOOL_TX_COUNT: usize = 21;
452477

453478
let env = TestEnv::new()?;
454-
let mut emitter = Emitter::from_height(&env.client, 0);
479+
let mut emitter = Emitter::from_height(env.rpc_client(), 0);
455480

456481
// mine blocks to get initial balance, sync emitter up to tip
457-
let addr = env.client.get_new_address(None, None)?.assume_checked();
482+
let addr = env
483+
.rpc_client()
484+
.get_new_address(None, None)?
485+
.assume_checked();
458486
env.mine_blocks(PREMINE_COUNT, Some(addr.clone()))?;
459487
while emitter.next_header()?.is_some() {}
460488

@@ -528,10 +556,13 @@ fn mempool_during_reorg() -> anyhow::Result<()> {
528556
const PREMINE_COUNT: usize = 101;
529557

530558
let env = TestEnv::new()?;
531-
let mut emitter = Emitter::from_height(&env.client, 0);
559+
let mut emitter = Emitter::from_height(env.rpc_client(), 0);
532560

533561
// mine blocks to get initial balance
534-
let addr = env.client.get_new_address(None, None)?.assume_checked();
562+
let addr = env
563+
.rpc_client()
564+
.get_new_address(None, None)?
565+
.assume_checked();
535566
env.mine_blocks(PREMINE_COUNT, Some(addr.clone()))?;
536567

537568
// introduce mempool tx at each block extension
@@ -549,7 +580,7 @@ fn mempool_during_reorg() -> anyhow::Result<()> {
549580
.into_iter()
550581
.map(|(tx, _)| tx.txid())
551582
.collect::<BTreeSet<_>>(),
552-
env.client
583+
env.rpc_client()
553584
.get_raw_mempool()?
554585
.into_iter()
555586
.collect::<BTreeSet<_>>(),
@@ -560,15 +591,15 @@ fn mempool_during_reorg() -> anyhow::Result<()> {
560591
// mempool
561592
for reorg_count in 1..TIP_DIFF {
562593
println!("REORG COUNT: {}", reorg_count);
563-
env.reorg_empty_blocks(reorg_count)?;
594+
env.reorg_empty_blocks(reorg_count, &env.bitcoind)?;
564595

565596
// This is a map of mempool txids to tip height where the tx was introduced to the mempool
566597
// we recalculate this at every loop as reorgs may evict transactions from mempool. We use
567598
// the introduction height to determine whether we expect a tx to appear in a mempool
568599
// emission.
569600
// TODO: How can have have reorg logic in `TestEnv` NOT blacklast old blocks first?
570601
let tx_introductions = dbg!(env
571-
.client
602+
.rpc_client()
572603
.get_raw_mempool_verbose()?
573604
.into_iter()
574605
.map(|(txid, entry)| (txid, entry.height as usize))
@@ -643,7 +674,7 @@ fn no_agreement_point() -> anyhow::Result<()> {
643674
let env = TestEnv::new()?;
644675

645676
// start height is 99
646-
let mut emitter = Emitter::from_height(&env.client, (PREMINE_COUNT - 2) as u32);
677+
let mut emitter = Emitter::from_height(env.rpc_client(), (PREMINE_COUNT - 2) as u32);
647678

648679
// mine 101 blocks
649680
env.mine_blocks(PREMINE_COUNT, None)?;
@@ -658,12 +689,12 @@ fn no_agreement_point() -> anyhow::Result<()> {
658689
let block_hash_100a = block_header_100a.block_hash();
659690

660691
// get hash for block 101a
661-
let block_hash_101a = env.client.get_block_hash(101)?;
692+
let block_hash_101a = env.rpc_client().get_block_hash(101)?;
662693

663694
// invalidate blocks 99a, 100a, 101a
664-
env.client.invalidate_block(&block_hash_99a)?;
665-
env.client.invalidate_block(&block_hash_100a)?;
666-
env.client.invalidate_block(&block_hash_101a)?;
695+
env.rpc_client().invalidate_block(&block_hash_99a)?;
696+
env.rpc_client().invalidate_block(&block_hash_100a)?;
697+
env.rpc_client().invalidate_block(&block_hash_101a)?;
667698

668699
// mine new blocks 99b, 100b, 101b
669700
env.mine_blocks(3, None)?;

crates/electrum/Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ readme = "README.md"
1212
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1313

1414
[dependencies]
15-
bdk_chain = { path = "../chain", version = "0.6.0", default-features = false }
15+
bdk_chain = { path = "../chain", version = "0.6.0", features = [ "miniscript" ] }
1616
electrum-client = { version = "0.18" }
1717
#rustls = { version = "=0.21.1", optional = true, features = ["dangerous_configuration"] }
18+
19+
[dev-dependencies]
20+
testenv = { path = "../testenv", version = "0.1.0", default-features = false }
21+
electrsd = { version= "0.25.0", features = ["bitcoind_25_0", "esplora_a33e97e1", "legacy"] }
22+
anyhow = "1"

0 commit comments

Comments
 (0)