1
1
use bdk_core:: collections:: { BTreeMap , BTreeSet , HashSet } ;
2
- use bdk_core:: spk_client:: { FullScanRequest , FullScanResponse , SyncRequest , SyncResponse } ;
2
+ use bdk_core:: spk_client:: {
3
+ FullScanRequest , FullScanResponse , SpkWithExpectedTxids , SyncRequest , SyncResponse ,
4
+ } ;
3
5
use bdk_core:: {
4
- bitcoin:: { BlockHash , OutPoint , ScriptBuf , Txid } ,
6
+ bitcoin:: { BlockHash , OutPoint , Txid } ,
5
7
BlockId , CheckPoint , ConfirmationBlockTime , Indexed , TxUpdate ,
6
8
} ;
7
9
use esplora_client:: { OutputStatus , Tx } ;
@@ -53,7 +55,7 @@ impl EsploraExt for esplora_client::BlockingClient {
53
55
stop_gap : usize ,
54
56
parallel_requests : usize ,
55
57
) -> Result < FullScanResponse < K > , Error > {
56
- let mut request = request. into ( ) ;
58
+ let mut request: FullScanRequest < K > = request. into ( ) ;
57
59
let start_time = request. start_time ( ) ;
58
60
59
61
let chain_tip = request. chain_tip ( ) ;
@@ -67,7 +69,9 @@ impl EsploraExt for esplora_client::BlockingClient {
67
69
let mut inserted_txs = HashSet :: < Txid > :: new ( ) ;
68
70
let mut last_active_indices = BTreeMap :: < K , u32 > :: new ( ) ;
69
71
for keychain in request. keychains ( ) {
70
- let keychain_spks = request. iter_spks ( keychain. clone ( ) ) ;
72
+ let keychain_spks = request
73
+ . iter_spks ( keychain. clone ( ) )
74
+ . map ( |( spk_i, spk) | ( spk_i, spk. into ( ) ) ) ;
71
75
let ( update, last_active_index) = fetch_txs_with_keychain_spks (
72
76
self ,
73
77
start_time,
@@ -120,7 +124,7 @@ impl EsploraExt for esplora_client::BlockingClient {
120
124
self ,
121
125
start_time,
122
126
& mut inserted_txs,
123
- request. iter_spks ( ) ,
127
+ request. iter_spks_with_expected_txids ( ) ,
124
128
parallel_requests,
125
129
) ?) ;
126
130
tx_update. extend ( fetch_txs_with_txids (
@@ -254,15 +258,15 @@ fn chain_update(
254
258
Ok ( tip)
255
259
}
256
260
257
- fn fetch_txs_with_keychain_spks < I : Iterator < Item = Indexed < ScriptBuf > > > (
261
+ fn fetch_txs_with_keychain_spks < I : Iterator < Item = Indexed < SpkWithExpectedTxids > > > (
258
262
client : & esplora_client:: BlockingClient ,
259
263
start_time : u64 ,
260
264
inserted_txs : & mut HashSet < Txid > ,
261
265
mut keychain_spks : I ,
262
266
stop_gap : usize ,
263
267
parallel_requests : usize ,
264
268
) -> Result < ( TxUpdate < ConfirmationBlockTime > , Option < u32 > ) , Error > {
265
- type TxsOfSpkIndex = ( u32 , Vec < esplora_client:: Tx > ) ;
269
+ type TxsOfSpkIndex = ( u32 , Vec < esplora_client:: Tx > , HashSet < Txid > ) ;
266
270
267
271
let mut update = TxUpdate :: < ConfirmationBlockTime > :: default ( ) ;
268
272
let mut last_index = Option :: < u32 > :: None ;
@@ -273,21 +277,27 @@ fn fetch_txs_with_keychain_spks<I: Iterator<Item = Indexed<ScriptBuf>>>(
273
277
. by_ref ( )
274
278
. take ( parallel_requests)
275
279
. map ( |( spk_index, spk) | {
276
- std :: thread :: spawn ( {
277
- let client = client . clone ( ) ;
278
- move || -> Result < TxsOfSpkIndex , Error > {
279
- let mut last_seen = None ;
280
- let mut spk_txs = Vec :: new ( ) ;
281
- loop {
282
- let txs = client . scripthash_txs ( & spk , last_seen ) ? ;
283
- let tx_count = txs . len ( ) ;
284
- last_seen = txs. last ( ) . map ( |tx| tx . txid ) ;
285
- spk_txs . extend ( txs ) ;
286
- if tx_count < 25 {
287
- break Ok ( ( spk_index , spk_txs ) ) ;
288
- }
280
+ let client = client . clone ( ) ;
281
+ let expected_txids = spk . expected_txids ;
282
+ let spk = spk . spk ;
283
+ std :: thread :: spawn ( move || -> Result < TxsOfSpkIndex , Error > {
284
+ let mut last_txid = None ;
285
+ let mut spk_txs = Vec :: new ( ) ;
286
+ loop {
287
+ let txs = client . scripthash_txs ( & spk , last_txid ) ? ;
288
+ let tx_count = txs. len ( ) ;
289
+ last_txid = txs . last ( ) . map ( |tx| tx . txid ) ;
290
+ spk_txs . extend ( txs ) ;
291
+ if tx_count < 25 {
292
+ break ;
289
293
}
290
294
}
295
+ let got_txids = spk_txs. iter ( ) . map ( |tx| tx. txid ) . collect :: < HashSet < _ > > ( ) ;
296
+ let evicted_txids = expected_txids
297
+ . difference ( & got_txids)
298
+ . copied ( )
299
+ . collect :: < HashSet < _ > > ( ) ;
300
+ Ok ( ( spk_index, spk_txs, evicted_txids) )
291
301
} )
292
302
} )
293
303
. collect :: < Vec < JoinHandle < Result < TxsOfSpkIndex , Error > > > > ( ) ;
@@ -297,7 +307,7 @@ fn fetch_txs_with_keychain_spks<I: Iterator<Item = Indexed<ScriptBuf>>>(
297
307
}
298
308
299
309
for handle in handles {
300
- let ( index, txs) = handle. join ( ) . expect ( "thread must not panic" ) ?;
310
+ let ( index, txs, evicted ) = handle. join ( ) . expect ( "thread must not panic" ) ?;
301
311
last_index = Some ( index) ;
302
312
if !txs. is_empty ( ) {
303
313
last_active_index = Some ( index) ;
@@ -309,6 +319,9 @@ fn fetch_txs_with_keychain_spks<I: Iterator<Item = Indexed<ScriptBuf>>>(
309
319
insert_anchor_or_seen_at_from_status ( & mut update, start_time, tx. txid , tx. status ) ;
310
320
insert_prevouts ( & mut update, tx. vin ) ;
311
321
}
322
+ update
323
+ . evicted_ats
324
+ . extend ( evicted. into_iter ( ) . map ( |txid| ( txid, start_time) ) ) ;
312
325
}
313
326
314
327
let last_index = last_index. expect ( "Must be set since handles wasn't empty." ) ;
@@ -333,7 +346,7 @@ fn fetch_txs_with_keychain_spks<I: Iterator<Item = Indexed<ScriptBuf>>>(
333
346
/// requests to make in parallel.
334
347
///
335
348
/// Refer to [crate-level docs](crate) for more.
336
- fn fetch_txs_with_spks < I : IntoIterator < Item = ScriptBuf > > (
349
+ fn fetch_txs_with_spks < I : IntoIterator < Item = SpkWithExpectedTxids > > (
337
350
client : & esplora_client:: BlockingClient ,
338
351
start_time : u64 ,
339
352
inserted_txs : & mut HashSet < Txid > ,
0 commit comments