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 ,
1+ use bdk_chain:: bitcoin :: { Address , Amount , ScriptBuf } ;
2+ use bdk_core :: {
3+ bitcoin :: {
4+ consensus :: WriteExt ,
5+ hashes :: Hash ,
6+ key :: { Secp256k1 , UntweakedPublicKey } ,
7+ Network , TapNodeHash ,
8+ } ,
9+ spk_client :: SyncRequest ,
10+ CheckPoint ,
1111} ;
1212use bdk_electrum:: BdkElectrumClient ;
1313use bdk_testenv:: { anyhow, bitcoincore_rpc:: RpcApi , TestEnv } ;
1414use criterion:: { criterion_group, criterion_main, Criterion } ;
15- use std:: time:: Duration ;
15+ use electrum_client:: ElectrumApi ;
16+ use std:: { collections:: BTreeSet , time:: Duration } ;
1617
1718// Batch size for `sync_with_electrum`.
18- const BATCH_SIZE : usize = 5 ;
19+ const BATCH_SIZE : usize = 100 ;
1920
20- pub fn get_test_spk ( ) -> ScriptBuf {
21+ pub fn get_test_spk ( i : usize ) -> ScriptBuf {
2122 const PK_BYTES : & [ u8 ] = & [
2223 12 , 244 , 72 , 4 , 163 , 4 , 211 , 81 , 159 , 82 , 153 , 123 , 125 , 74 , 142 , 40 , 55 , 237 , 191 , 231 ,
2324 31 , 114 , 89 , 165 , 83 , 141 , 8 , 203 , 93 , 240 , 53 , 101 ,
2425 ] ;
2526 let secp = Secp256k1 :: new ( ) ;
2627 let pk = UntweakedPublicKey :: from_slice ( PK_BYTES ) . expect ( "Must be valid PK" ) ;
27- ScriptBuf :: new_p2tr ( & secp, pk, None )
28+ let mut engine = TapNodeHash :: engine ( ) ;
29+ engine. emit_u64 ( i as u64 ) . expect ( "must emit" ) ;
30+ ScriptBuf :: new_p2tr ( & secp, pk, Some ( TapNodeHash :: from_engine ( engine) ) )
2831}
2932
30- fn sync_with_electrum < I , Spks > (
31- client : & BdkElectrumClient < electrum_client:: Client > ,
32- spks : Spks ,
33- chain : & mut LocalChain ,
34- graph : & mut IndexedTxGraph < ConfirmationBlockTime , I > ,
35- ) -> anyhow:: Result < SyncResponse >
36- where
37- I : Indexer ,
38- I :: ChangeSet : Default + Merge ,
39- Spks : IntoIterator < Item = ScriptBuf > ,
40- Spks :: IntoIter : ExactSizeIterator + Send + ' static ,
41- {
33+ fn sync_with_electrum < E : ElectrumApi > (
34+ client : & BdkElectrumClient < E > ,
35+ spks : & [ ScriptBuf ] ,
36+ chain_tip : & CheckPoint ,
37+ ) -> anyhow:: Result < ( ) > {
4238 let update = client. sync (
43- SyncRequest :: builder ( ) . chain_tip ( chain. tip ( ) ) . spks ( spks) ,
39+ SyncRequest :: builder ( )
40+ . chain_tip ( chain_tip. clone ( ) )
41+ . spks ( spks. iter ( ) . cloned ( ) ) ,
4442 BATCH_SIZE ,
4543 true ,
4644 ) ?;
@@ -50,20 +48,11 @@ where
5048 "expected some transactions from sync, but got none"
5149 ) ;
5250
53- if let Some ( chain_update) = update. chain_update . clone ( ) {
54- let _ = chain
55- . apply_update ( chain_update)
56- . map_err ( |err| anyhow:: anyhow!( "LocalChain update error: {:?}" , err) ) ?;
57- }
58- let _ = graph. apply_update ( update. tx_update . clone ( ) ) ;
59-
60- Ok ( update)
51+ Ok ( ( ) )
6152}
6253
6354pub fn test_sync_performance ( c : & mut Criterion ) {
6455 let env = TestEnv :: new ( ) . unwrap ( ) ;
65- let electrum_client = electrum_client:: Client :: new ( env. electrsd . electrum_url . as_str ( ) ) . unwrap ( ) ;
66- let client = BdkElectrumClient :: new ( electrum_client) ;
6756
6857 const NUM_BLOCKS : usize = 100 ;
6958 let mut spks = Vec :: with_capacity ( NUM_BLOCKS ) ;
@@ -72,34 +61,52 @@ pub fn test_sync_performance(c: &mut Criterion) {
7261 env. mine_blocks ( 101 , None ) . unwrap ( ) ;
7362
7463 // Scatter UTXOs across many blocks.
75- for _ in 0 ..NUM_BLOCKS {
76- let spk = get_test_spk ( ) ;
64+ for i in 0 ..NUM_BLOCKS {
65+ let spk = get_test_spk ( i ) ;
7766 let addr = Address :: from_script ( & spk, Network :: Regtest ) . unwrap ( ) ;
7867 env. send ( & addr, Amount :: from_sat ( 10_000 ) ) . unwrap ( ) ;
7968 env. mine_blocks ( 1 , None ) . unwrap ( ) ;
8069
8170 spks. push ( spk) ;
8271 }
8372 let _ = env. wait_until_electrum_sees_block ( Duration :: from_secs ( 6 ) ) ;
73+ assert_eq ! (
74+ spks. iter( ) . cloned( ) . collect:: <BTreeSet <_>>( ) . len( ) ,
75+ spks. len( ) ,
76+ "all spks must be unique" ,
77+ ) ;
8478
8579 // Setup receiver.
86- let genesis = env. bitcoind . client . get_block_hash ( 0 ) . unwrap ( ) ;
87- let ( chain, _) = LocalChain :: from_genesis_hash ( genesis) ;
88- let graph = IndexedTxGraph :: < ConfirmationBlockTime , _ > :: new ( {
89- let mut idx = SpkTxOutIndex :: default ( ) ;
90- idx. insert_spk ( ( ) , spks[ 0 ] . clone ( ) ) ;
91- idx
80+ let genesis_cp = CheckPoint :: new ( bdk_core:: BlockId {
81+ height : 0 ,
82+ hash : env. bitcoind . client . get_block_hash ( 0 ) . unwrap ( ) ,
9283 } ) ;
9384
94- c. bench_function ( "sync_with_electrum" , move |b| {
95- b. iter ( || {
96- let spks = spks. clone ( ) ;
97- let mut recv_chain = chain. clone ( ) ;
98- let mut recv_graph = graph. clone ( ) ;
85+ {
86+ let electrum_client =
87+ electrum_client:: Client :: new ( env. electrsd . electrum_url . as_str ( ) ) . unwrap ( ) ;
88+ let spks = spks. clone ( ) ;
89+ let genesis_cp = genesis_cp. clone ( ) ;
90+ c. bench_function ( "sync_with_electrum" , move |b| {
91+ b. iter ( || {
92+ sync_with_electrum (
93+ & BdkElectrumClient :: new ( & electrum_client) ,
94+ & spks,
95+ & genesis_cp,
96+ )
97+ . expect ( "must not error" )
98+ } )
99+ } ) ;
100+ }
99101
100- let _ = sync_with_electrum ( & client, spks, & mut recv_chain, & mut recv_graph) ;
101- } )
102- } ) ;
102+ {
103+ let client = BdkElectrumClient :: new (
104+ electrum_client:: Client :: new ( env. electrsd . electrum_url . as_str ( ) ) . unwrap ( ) ,
105+ ) ;
106+ c. bench_function ( "sync_with_electrum_cached" , move |b| {
107+ b. iter ( || sync_with_electrum ( & client, & spks, & genesis_cp) . expect ( "must not error" ) )
108+ } ) ;
109+ }
103110}
104111
105112criterion_group ! {
0 commit comments