Skip to content

Commit 0025f14

Browse files
committed
refactor(testenv)!: TestEnv::wait_until_electrum_sees_block
Add inputs `block_height` and `block_hash` so that it is more concrete what exactly we are waiting for. Introduce `TestEnv::wait_until_electrum_tip_syncs_with_bitcoind`.
1 parent b9e4e4c commit 0025f14

File tree

2 files changed

+59
-22
lines changed

2 files changed

+59
-22
lines changed

crates/electrum/tests/test_electrum.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ pub fn test_update_tx_graph_without_keychain() -> anyhow::Result<()> {
297297
None,
298298
)?;
299299
env.mine_blocks(1, None)?;
300-
env.wait_until_electrum_sees_block(Duration::from_secs(6))?;
300+
env.wait_until_electrum_tip_syncs_with_bitcoind(Duration::from_secs(6))?;
301301

302302
// use a full checkpoint linked list (since this is not what we are testing)
303303
let cp_tip = env.make_checkpoint_tip();
@@ -409,7 +409,7 @@ pub fn test_update_tx_graph_stop_gap() -> anyhow::Result<()> {
409409
None,
410410
)?;
411411
env.mine_blocks(1, None)?;
412-
env.wait_until_electrum_sees_block(Duration::from_secs(6))?;
412+
env.wait_until_electrum_tip_syncs_with_bitcoind(Duration::from_secs(6))?;
413413

414414
// use a full checkpoint linked list (since this is not what we are testing)
415415
let cp_tip = env.make_checkpoint_tip();
@@ -453,7 +453,7 @@ pub fn test_update_tx_graph_stop_gap() -> anyhow::Result<()> {
453453
None,
454454
)?;
455455
env.mine_blocks(1, None)?;
456-
env.wait_until_electrum_sees_block(Duration::from_secs(6))?;
456+
env.wait_until_electrum_tip_syncs_with_bitcoind(Duration::from_secs(6))?;
457457

458458
// A scan with gap limit 5 won't find the second transaction, but a scan with gap limit 6 will.
459459
// The last active indice won't be updated in the first case but will in the second one.
@@ -521,7 +521,7 @@ fn test_sync() -> anyhow::Result<()> {
521521

522522
// Mine some blocks.
523523
env.mine_blocks(101, Some(addr_to_mine))?;
524-
env.wait_until_electrum_sees_block(Duration::from_secs(6))?;
524+
env.wait_until_electrum_tip_syncs_with_bitcoind(Duration::from_secs(6))?;
525525

526526
// Broadcast transaction to mempool.
527527
let txid = env.send(&addr_to_track, SEND_AMOUNT)?;
@@ -546,7 +546,7 @@ fn test_sync() -> anyhow::Result<()> {
546546

547547
// Mine block to confirm transaction.
548548
env.mine_blocks(1, None)?;
549-
env.wait_until_electrum_sees_block(Duration::from_secs(6))?;
549+
env.wait_until_electrum_tip_syncs_with_bitcoind(Duration::from_secs(6))?;
550550

551551
let _ = sync_with_electrum(
552552
&client,
@@ -567,7 +567,7 @@ fn test_sync() -> anyhow::Result<()> {
567567

568568
// Perform reorg on block with confirmed transaction.
569569
env.reorg_empty_blocks(1)?;
570-
env.wait_until_electrum_sees_block(Duration::from_secs(6))?;
570+
env.wait_until_electrum_tip_syncs_with_bitcoind(Duration::from_secs(6))?;
571571

572572
let _ = sync_with_electrum(
573573
&client,
@@ -587,7 +587,7 @@ fn test_sync() -> anyhow::Result<()> {
587587

588588
// Mine block to confirm transaction again.
589589
env.mine_blocks(1, None)?;
590-
env.wait_until_electrum_sees_block(Duration::from_secs(6))?;
590+
env.wait_until_electrum_tip_syncs_with_bitcoind(Duration::from_secs(6))?;
591591

592592
let _ = sync_with_electrum(&client, [spk_to_track], &mut recv_chain, &mut recv_graph)?;
593593

@@ -630,7 +630,8 @@ fn test_sync() -> anyhow::Result<()> {
630630
Ok(())
631631
}
632632

633-
/// Ensure that confirmed txs that are reorged become unconfirmed.
633+
/// Ensure transactions can become unconfirmed during reorg.
634+
/// ~Ensure that confirmed txs that are reorged become unconfirmed.~
634635
///
635636
/// 1. Mine 101 blocks.
636637
/// 2. Mine 8 blocks with a confirmed tx in each.
@@ -674,7 +675,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
674675
}
675676

676677
// Sync up to tip.
677-
env.wait_until_electrum_sees_block(Duration::from_secs(6))?;
678+
env.wait_until_electrum_tip_syncs_with_bitcoind(Duration::from_secs(6))?;
678679
let update = sync_with_electrum(
679680
&client,
680681
[spk_to_track.clone()],
@@ -705,7 +706,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
705706
for depth in 1..=REORG_COUNT {
706707
env.reorg_empty_blocks(depth)?;
707708

708-
env.wait_until_electrum_sees_block(Duration::from_secs(6))?;
709+
env.wait_until_electrum_tip_syncs_with_bitcoind(Duration::from_secs(6))?;
709710
let update = sync_with_electrum(
710711
&client,
711712
[spk_to_track.clone()],
@@ -716,6 +717,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
716717
// Check that no new anchors are added during current reorg.
717718
assert!(initial_anchors.is_superset(&update.tx_update.anchors));
718719

720+
// TODO: Fails here.
719721
assert_eq!(
720722
get_balance(&recv_chain, &recv_graph)?,
721723
Balance {
@@ -751,7 +753,7 @@ fn test_sync_with_coinbase() -> anyhow::Result<()> {
751753

752754
// Mine some blocks.
753755
env.mine_blocks(101, Some(addr_to_track))?;
754-
env.wait_until_electrum_sees_block(Duration::from_secs(6))?;
756+
env.wait_until_electrum_tip_syncs_with_bitcoind(Duration::from_secs(6))?;
755757

756758
// Check to see if electrum syncs properly.
757759
assert!(sync_with_electrum(
@@ -829,7 +831,7 @@ fn test_check_fee_calculation() -> anyhow::Result<()> {
829831
};
830832

831833
// Sync up to tip.
832-
env.wait_until_electrum_sees_block(Duration::from_secs(6))?;
834+
env.wait_until_electrum_tip_syncs_with_bitcoind(Duration::from_secs(6))?;
833835
let _ = sync_with_electrum(
834836
&client,
835837
[spk_to_track.clone()],

crates/testenv/src/lib.rs

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -188,18 +188,43 @@ impl TestEnv {
188188
Ok((bt.height as usize, block.block_hash()))
189189
}
190190

191-
/// This method waits for the Electrum notification indicating that a new block has been mined.
192-
/// `timeout` is the maximum [`Duration`] we want to wait for a response from Electrsd.
193-
pub fn wait_until_electrum_sees_block(&self, timeout: Duration) -> anyhow::Result<()> {
194-
self.electrsd.client.block_headers_subscribe()?;
191+
/// Wait until Electrum is aware of a block of a given `block_height` (and optionally, matches
192+
/// the given `block_hash`).
193+
pub fn wait_until_electrum_sees_block(
194+
&self,
195+
block_height: usize,
196+
block_hash: Option<BlockHash>,
197+
timeout: Duration,
198+
) -> anyhow::Result<()> {
199+
self.electrsd.trigger()?;
200+
// NOTE: We use the subscribe endpoint because polling Electrs for a block header at
201+
// `block_height` and verifying the `block_hash` does not ensure that the spk histories
202+
// are current. In contrast, getting a notification for a new block tip ensures that the
203+
// confirmed spk histories are current, including the new notified tip. This is a result of
204+
// the internal workings of Electrs.
205+
self.electrum_client().block_headers_subscribe()?;
206+
195207
let delay = Duration::from_millis(200);
196208
let start = std::time::Instant::now();
197209

198210
while start.elapsed() < timeout {
199-
self.electrsd.trigger()?;
200-
self.electrsd.client.ping()?;
201-
if self.electrsd.client.block_headers_pop()?.is_some() {
202-
return Ok(());
211+
self.electrum_client().ping()?;
212+
if let Some(header_notif) = self.electrum_client().block_headers_pop()? {
213+
if header_notif.height >= block_height {
214+
let header = if header_notif.height == block_height {
215+
header_notif.header
216+
} else {
217+
self.electrum_client().block_header(block_height)?
218+
};
219+
match block_hash {
220+
None => return Ok(()),
221+
Some(exp_hash) => {
222+
if exp_hash == header.block_hash() {
223+
return Ok(());
224+
}
225+
}
226+
}
227+
}
203228
}
204229

205230
std::thread::sleep(delay);
@@ -210,6 +235,16 @@ impl TestEnv {
210235
))
211236
}
212237

238+
/// Wait until Electrum is aware of bitcoind's chain tip.
239+
pub fn wait_until_electrum_tip_syncs_with_bitcoind(
240+
&self,
241+
timeout: Duration,
242+
) -> anyhow::Result<()> {
243+
let chain_height = self.rpc_client().get_block_count()?;
244+
let chain_hash = self.rpc_client().get_block_hash(chain_height)?;
245+
self.wait_until_electrum_sees_block(chain_height as _, Some(chain_hash), timeout)
246+
}
247+
213248
/// This method waits for Electrsd to see a transaction with given `txid`. `timeout` is the
214249
/// maximum [`Duration`] we want to wait for a response from Electrsd.
215250
pub fn wait_until_electrum_sees_txid(
@@ -323,15 +358,15 @@ mod test {
323358

324359
// Mine some blocks.
325360
env.mine_blocks(101, None)?;
326-
env.wait_until_electrum_sees_block(Duration::from_secs(6))?;
361+
env.wait_until_electrum_tip_syncs_with_bitcoind(Duration::from_secs(6))?;
327362
let height = env.bitcoind.client.get_block_count()?;
328363
let blocks = (0..=height)
329364
.map(|i| env.bitcoind.client.get_block_hash(i))
330365
.collect::<Result<Vec<_>, _>>()?;
331366

332367
// Perform reorg on six blocks.
333368
env.reorg(6)?;
334-
env.wait_until_electrum_sees_block(Duration::from_secs(6))?;
369+
env.wait_until_electrum_tip_syncs_with_bitcoind(Duration::from_secs(6))?;
335370
let reorged_height = env.bitcoind.client.get_block_count()?;
336371
let reorged_blocks = (0..=height)
337372
.map(|i| env.bitcoind.client.get_block_hash(i))

0 commit comments

Comments
 (0)