//! This module provides the necessary helper methods for tests
//!
use assert_cmd::Command;
+use bdk_testenv::{TestEnv, anyhow, bitcoincore_rpc::RpcApi, electrum_client::ElectrumApi};
use std::path::PathBuf;
+use std::time::{Duration, Instant};
/// The bdk-cli command struct
#[allow(dead_code)]
cmd
}
}
+
+/// Waits until electrs has indexed up to bitcoind's current tip.
+///
+/// `TestEnv::wait_until_electrum_sees_block` returns on the first queued header
+/// notification, which may be a stale one left over from an earlier `mine_blocks`
+/// call, so a following scan can run before the latest blocks are indexed.
+#[allow(unused)]
+pub fn wait_for_electrum_tip(env: &TestEnv, timeout: Duration) -> anyhow::Result<()> {
+ let tip = env.rpc_client().get_block_count()? as usize;
+ let client = env.electrum_client();
+ client.block_headers_subscribe()?;
+ let start = Instant::now();
+
+ while start.elapsed() < timeout {
+ env.electrsd.trigger()?;
+ client.ping()?;
+ while let Some(notif) = client.block_headers_pop()? {
+ if notif.height >= tip {
+ return Ok(());
+ }
+ }
+ std::thread::sleep(Duration::from_millis(200));
+ }
+
+ Err(anyhow::anyhow!(
+ "electrs did not reach tip {tip} within {timeout:?}"
+ ))
+}
#[cfg(feature = "electrum")]
mod test_online {
- use crate::common::BdkCli;
+ use crate::common::{BdkCli, wait_for_electrum_tip};
use assert_cmd::Command;
use bdk_testenv::{TestEnv, bitcoincore_rpc::RpcApi};
use bdk_wallet::bitcoin::{Address, Amount, Network, Txid};
.mine_blocks(101, Some(node_address))
.expect("Failed to mine initial blocks");
assert_eq!(mined_blocks.len(), 101, "expected exactly 101 blocks mined");
- env.wait_until_electrum_sees_block(Duration::from_secs(10))
+ wait_for_electrum_tip(env, Duration::from_secs(10))
.expect("Electrum did not catch up to initial blocks");
let txid = env
env.mine_blocks(3, None)
.expect("Failed to confirm funding tx");
- env.wait_until_electrum_sees_block(Duration::from_secs(10))
+ wait_for_electrum_tip(env, Duration::from_secs(10))
.expect("Electrum did not catch up to confirmation blocks");
cli_full_scan(cli);
env.mine_blocks(1, None)
.expect("Failed to mine drain confirmation block");
- env.wait_until_electrum_sees_block(Duration::from_secs(10))
+ wait_for_electrum_tip(&env, Duration::from_secs(10))
.expect("Electrum did not catch up to drain confirmation");
cli_sync(&cli);
// Confirm the spend and verify the final balance
env.mine_blocks(1, None)
.expect("Failed to mine spend confirmation block");
- env.wait_until_electrum_sees_block(Duration::from_secs(10))
+ wait_for_electrum_tip(&env, Duration::from_secs(10))
.expect("Electrum did not catch up to spend confirmation");
cli_sync(&cli);
env.mine_blocks(1, None)
.expect("Failed to confirm bumped tx");
- env.wait_until_electrum_sees_block(Duration::from_secs(10))
+ wait_for_electrum_tip(&env, Duration::from_secs(10))
.expect("Electrum did not catch up after bump confirmation");
cli_sync(&cli);
.unwrap()
.assume_checked();
env.mine_blocks(101, Some(node_addr)).unwrap();
- env.wait_until_electrum_sees_block(Duration::from_secs(10))
- .unwrap();
+ wait_for_electrum_tip(&env, Duration::from_secs(10)).unwrap();
let a1 = cli_new_address(&cli);
let t1 = env.send(&a1, Amount::from_btc(0.3).unwrap()).unwrap();
env.wait_until_electrum_sees_txid(t1, Duration::from_secs(10))
env.wait_until_electrum_sees_txid(t2, Duration::from_secs(10))
.unwrap();
env.mine_blocks(3, None).unwrap();
- env.wait_until_electrum_sees_block(Duration::from_secs(10))
- .unwrap();
+ wait_for_electrum_tip(&env, Duration::from_secs(10)).unwrap();
cli_full_scan(&cli);
let unspent = run_wallet_json(&cli, &["unspent"]);
.unwrap()
.assume_checked();
env.mine_blocks(101, Some(node_address)).unwrap();
- env.wait_until_electrum_sees_block(Duration::from_secs(10))
- .unwrap();
+ wait_for_electrum_tip(&env, Duration::from_secs(10)).unwrap();
let txid = env.send(&addr, Amount::from_btc(0.5).unwrap()).unwrap();
env.wait_until_electrum_sees_txid(txid, Duration::from_secs(10))
.unwrap();
env.mine_blocks(3, None).unwrap();
- env.wait_until_electrum_sees_block(Duration::from_secs(10))
- .unwrap();
+ wait_for_electrum_tip(&env, Duration::from_secs(10)).unwrap();
cli.wallet_cmd(&["--wallet", WALLET, "full_scan"])
.assert()
.success();
.unwrap()
.assume_checked();
env.mine_blocks(101, Some(node_addr)).unwrap();
- env.wait_until_electrum_sees_block(Duration::from_secs(10))
- .unwrap();
+ wait_for_electrum_tip(&env, Duration::from_secs(10)).unwrap();
let txid = env.send(&address, Amount::from_sat(5_000)).unwrap();
env.wait_until_electrum_sees_txid(txid, Duration::from_secs(10))
.unwrap();
env.mine_blocks(3, None).unwrap();
- env.wait_until_electrum_sees_block(Duration::from_secs(10))
- .unwrap();
+ wait_for_electrum_tip(&env, Duration::from_secs(10)).unwrap();
cli_full_scan(&cli);
// The funded outpoint to prove control of.
#[cfg(feature = "esplora")]
mod test_esplora {
- use crate::common::BdkCli;
+ use crate::common::{BdkCli, wait_for_electrum_tip};
use bdk_testenv::{TestEnv, bitcoincore_rpc::RpcApi};
use bdk_wallet::bitcoin::{Address, Amount, Network};
use serde_json::Value;
.unwrap()
.assume_checked();
env.mine_blocks(101, Some(node_addr)).unwrap();
- env.wait_until_electrum_sees_block(Duration::from_secs(10))
- .unwrap();
+ wait_for_electrum_tip(&env, Duration::from_secs(10)).unwrap();
let txid = env.send(&address, Amount::from_btc(0.5).unwrap()).unwrap();
env.wait_until_electrum_sees_txid(txid, Duration::from_secs(10))
.unwrap();
env.mine_blocks(3, None).unwrap();
- env.wait_until_electrum_sees_block(Duration::from_secs(10))
- .unwrap();
+ wait_for_electrum_tip(&env, Duration::from_secs(10)).unwrap();
let scan = cli
.wallet_cmd(&["--wallet", WALLET_NAME, "full_scan"])