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 ,
11
11
} ;
12
12
use bdk_electrum:: BdkElectrumClient ;
13
13
use bdk_testenv:: { anyhow, bitcoincore_rpc:: RpcApi , TestEnv } ;
14
14
use criterion:: { criterion_group, criterion_main, Criterion } ;
15
- use std:: time:: Duration ;
15
+ use electrum_client:: ElectrumApi ;
16
+ use std:: { collections:: BTreeSet , time:: Duration } ;
16
17
17
18
// Batch size for `sync_with_electrum`.
18
- const BATCH_SIZE : usize = 5 ;
19
+ const BATCH_SIZE : usize = 100 ;
19
20
20
- pub fn get_test_spk ( ) -> ScriptBuf {
21
+ pub fn get_test_spk ( i : usize ) -> ScriptBuf {
21
22
const PK_BYTES : & [ u8 ] = & [
22
23
12 , 244 , 72 , 4 , 163 , 4 , 211 , 81 , 159 , 82 , 153 , 123 , 125 , 74 , 142 , 40 , 55 , 237 , 191 , 231 ,
23
24
31 , 114 , 89 , 165 , 83 , 141 , 8 , 203 , 93 , 240 , 53 , 101 ,
24
25
] ;
25
26
let secp = Secp256k1 :: new ( ) ;
26
27
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) ) )
28
31
}
29
32
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 < ( ) > {
42
38
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 ( ) ) ,
44
42
BATCH_SIZE ,
45
43
true ,
46
44
) ?;
@@ -50,20 +48,11 @@ where
50
48
"expected some transactions from sync, but got none"
51
49
) ;
52
50
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 ( ( ) )
61
52
}
62
53
63
54
pub fn test_sync_performance ( c : & mut Criterion ) {
64
55
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) ;
67
56
68
57
const NUM_BLOCKS : usize = 100 ;
69
58
let mut spks = Vec :: with_capacity ( NUM_BLOCKS ) ;
@@ -72,34 +61,52 @@ pub fn test_sync_performance(c: &mut Criterion) {
72
61
env. mine_blocks ( 101 , None ) . unwrap ( ) ;
73
62
74
63
// 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 ) ;
77
66
let addr = Address :: from_script ( & spk, Network :: Regtest ) . unwrap ( ) ;
78
67
env. send ( & addr, Amount :: from_sat ( 10_000 ) ) . unwrap ( ) ;
79
68
env. mine_blocks ( 1 , None ) . unwrap ( ) ;
80
69
81
70
spks. push ( spk) ;
82
71
}
83
72
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
+ ) ;
84
78
85
79
// 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 ( ) ,
92
83
} ) ;
93
84
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
+ }
99
101
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
+ }
103
110
}
104
111
105
112
criterion_group ! {
0 commit comments