Skip to content

Commit dc08959

Browse files
committed
test(electrum): add criterion benchmark for sync
1 parent b4b8d7c commit dc08959

File tree

3 files changed

+110
-49
lines changed

3 files changed

+110
-49
lines changed

crates/electrum/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ electrum-client = { version = "0.23.1", features = [ "proxy" ], default-features
1919
[dev-dependencies]
2020
bdk_testenv = { path = "../testenv" }
2121
bdk_chain = { path = "../chain" }
22+
criterion = { version = "0.2" }
2223

2324
[features]
2425
default = ["use-rustls"]
@@ -29,3 +30,7 @@ use-openssl = ["electrum-client/use-openssl"]
2930
[[test]]
3031
name = "test_electrum"
3132
required-features = ["use-rustls"]
33+
34+
[[bench]]
35+
name = "test_sync"
36+
harness = false

crates/electrum/benches/test_sync.rs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
use bdk_chain::{
2+
bitcoin::{Address, Amount, ScriptBuf},
3+
local_chain::LocalChain,
4+
spk_client::{SyncRequest, SyncResponse},
5+
spk_txout::SpkTxOutIndex,
6+
ConfirmationBlockTime, IndexedTxGraph, Indexer, Merge,
7+
};
8+
use bdk_core::bitcoin::{
9+
key::{Secp256k1, UntweakedPublicKey},
10+
Network,
11+
};
12+
use bdk_electrum::BdkElectrumClient;
13+
use bdk_testenv::{anyhow, bitcoincore_rpc::RpcApi, TestEnv};
14+
use criterion::{black_box, criterion_group, criterion_main, Criterion};
15+
16+
// Batch size for `sync_with_electrum`.
17+
const BATCH_SIZE: usize = 5;
18+
19+
pub fn get_test_spk() -> ScriptBuf {
20+
const PK_BYTES: &[u8] = &[
21+
12, 244, 72, 4, 163, 4, 211, 81, 159, 82, 153, 123, 125, 74, 142, 40, 55, 237, 191, 231,
22+
31, 114, 89, 165, 83, 141, 8, 203, 93, 240, 53, 101,
23+
];
24+
let secp = Secp256k1::new();
25+
let pk = UntweakedPublicKey::from_slice(PK_BYTES).expect("Must be valid PK");
26+
ScriptBuf::new_p2tr(&secp, pk, None)
27+
}
28+
29+
fn sync_with_electrum<I, Spks>(
30+
client: &BdkElectrumClient<electrum_client::Client>,
31+
spks: Spks,
32+
chain: &mut LocalChain,
33+
graph: &mut IndexedTxGraph<ConfirmationBlockTime, I>,
34+
) -> anyhow::Result<SyncResponse>
35+
where
36+
I: Indexer,
37+
I::ChangeSet: Default + Merge,
38+
Spks: IntoIterator<Item = ScriptBuf>,
39+
Spks::IntoIter: ExactSizeIterator + Send + 'static,
40+
{
41+
let update = client.sync(
42+
SyncRequest::builder().chain_tip(chain.tip()).spks(spks),
43+
BATCH_SIZE,
44+
true,
45+
)?;
46+
47+
if let Some(chain_update) = update.chain_update.clone() {
48+
let _ = chain
49+
.apply_update(chain_update)
50+
.map_err(|err| anyhow::anyhow!("LocalChain update error: {:?}", err))?;
51+
}
52+
let _ = graph.apply_update(update.tx_update.clone());
53+
54+
Ok(update)
55+
}
56+
57+
pub fn test_sync_performance(c: &mut Criterion) {
58+
let env = TestEnv::new().unwrap();
59+
let electrum_client = electrum_client::Client::new(env.electrsd.electrum_url.as_str()).unwrap();
60+
let client = BdkElectrumClient::new(electrum_client);
61+
62+
// Generate test addresses.
63+
const NUM_ADDRS: usize = 1000;
64+
let mut spks = Vec::with_capacity(NUM_ADDRS);
65+
for _ in 0..NUM_ADDRS {
66+
spks.push(get_test_spk());
67+
}
68+
69+
// Mine some blocks and send transactions.
70+
env.mine_blocks(101, None).unwrap();
71+
for spk in spks.iter().take(10) {
72+
let addr = Address::from_script(spk, Network::Regtest).unwrap();
73+
env.send(&addr, Amount::from_sat(10_000)).unwrap();
74+
}
75+
env.mine_blocks(1, None).unwrap();
76+
77+
// Setup receiver.
78+
let genesis = env.bitcoind.client.get_block_hash(0).unwrap();
79+
let (chain, _) = LocalChain::from_genesis_hash(genesis);
80+
let graph = IndexedTxGraph::<ConfirmationBlockTime, _>::new({
81+
let mut idx = SpkTxOutIndex::default();
82+
for spk in &spks {
83+
idx.insert_spk((), spk.clone());
84+
}
85+
idx
86+
});
87+
88+
c.bench_function("sync_with_electrum", move |b| {
89+
b.iter(|| {
90+
let spks = black_box(spks.clone());
91+
let mut recv_chain = chain.clone();
92+
let mut recv_graph = graph.clone();
93+
94+
let _ = sync_with_electrum(&client, spks, &mut recv_chain, &mut recv_graph);
95+
})
96+
});
97+
}
98+
99+
criterion_group! {
100+
name = benches;
101+
config = Criterion::default()
102+
.sample_size(2);
103+
targets = test_sync_performance
104+
}
105+
criterion_main!(benches);

crates/electrum/tests/test_electrum.rs

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use core::time::Duration;
2020
use electrum_client::ElectrumApi;
2121
use std::collections::{BTreeSet, HashMap, HashSet};
2222
use std::str::FromStr;
23-
use std::time::Instant;
2423

2524
// Batch size for `sync_with_electrum`.
2625
const BATCH_SIZE: usize = 5;
@@ -882,51 +881,3 @@ fn test_check_fee_calculation() -> anyhow::Result<()> {
882881
}
883882
Ok(())
884883
}
885-
886-
#[test]
887-
pub fn test_sync_performance() -> anyhow::Result<()> {
888-
const EXPECTED_MAX_SYNC_TIME: Duration = Duration::from_secs(15);
889-
const NUM_ADDRESSES: usize = 1000;
890-
891-
let env = TestEnv::new()?;
892-
let electrum_client = electrum_client::Client::new(env.electrsd.electrum_url.as_str())?;
893-
let client = BdkElectrumClient::new(electrum_client);
894-
895-
// Generate test addresses.
896-
let mut spks = Vec::with_capacity(NUM_ADDRESSES);
897-
for _ in 0..NUM_ADDRESSES {
898-
spks.push(get_test_spk());
899-
}
900-
901-
// Mine some blocks and send transactions.
902-
env.mine_blocks(101, None)?;
903-
for spk in spks.iter().take(10) {
904-
let addr = Address::from_script(spk, Network::Regtest)?;
905-
env.send(&addr, Amount::from_sat(10_000))?;
906-
}
907-
env.mine_blocks(1, None)?;
908-
909-
// Setup receiver.
910-
let (mut recv_chain, _) = LocalChain::from_genesis_hash(env.bitcoind.client.get_block_hash(0)?);
911-
let mut recv_graph = IndexedTxGraph::<ConfirmationBlockTime, _>::new({
912-
let mut recv_index = SpkTxOutIndex::default();
913-
for spk in spks.iter() {
914-
recv_index.insert_spk((), spk.clone());
915-
}
916-
recv_index
917-
});
918-
919-
// Measure sync time.
920-
let start = Instant::now();
921-
let _ = sync_with_electrum(&client, spks.clone(), &mut recv_chain, &mut recv_graph)?;
922-
let sync_duration = start.elapsed();
923-
924-
assert!(
925-
sync_duration <= EXPECTED_MAX_SYNC_TIME,
926-
"Sync took {:?}, which is longer than expected {:?}",
927-
sync_duration,
928-
EXPECTED_MAX_SYNC_TIME
929-
);
930-
931-
Ok(())
932-
}

0 commit comments

Comments
 (0)