@@ -14,86 +14,63 @@ use std::{
1414/// We assume that a block of this depth and deeper cannot be reorged.
1515const ASSUME_FINAL_DEPTH : u32 = 8 ;
1616
17- /// Represents an update fetched from an Electrum server, but excludes full
18- /// transactions.
17+ /// Represents a [`TxGraph`] update fetched from an Electrum server, but excludes full transactions.
1918///
2019/// To provide a complete update to [`TxGraph`], you'll need to call [`Self::missing_full_txs`] to
21- /// determine the full transactions missing from [`TxGraph`]. Then call [`Self::finalize`] to fetch
22- /// the full transactions from Electrum and finalize the update.
23- #[ derive( Debug , Clone ) ]
24- pub struct ElectrumUpdate < K , A > {
25- /// Map of [`Txid`]s to associated [`Anchor`]s.
26- pub graph_update : HashMap < Txid , BTreeSet < A > > ,
27- /// The latest chain tip, as seen by the Electrum server.
28- pub new_tip : local_chain:: CheckPoint ,
29- /// Last-used index update for [`KeychainTxOutIndex`](bdk_chain::keychain::KeychainTxOutIndex).
30- pub keychain_update : BTreeMap < K , u32 > ,
31- }
32-
33- impl < K , A : Anchor > ElectrumUpdate < K , A > {
34- fn new ( new_tip : local_chain:: CheckPoint ) -> Self {
35- Self {
36- new_tip,
37- graph_update : HashMap :: new ( ) ,
38- keychain_update : BTreeMap :: new ( ) ,
39- }
40- }
20+ /// determine the full transactions missing from [`TxGraph`]. Then call [`Self::finalize`] to
21+ /// fetch the full transactions from Electrum and finalize the update.
22+ #[ derive( Debug , Default , Clone ) ]
23+ pub struct IncompleteTxGraph < A > ( HashMap < Txid , BTreeSet < A > > ) ;
4124
25+ impl < A : Anchor > IncompleteTxGraph < A > {
4226 /// Determine the full transactions that are missing from `graph`.
4327 ///
44- /// Refer to [`ElectrumUpdate`] .
28+ /// Refer to [`IncompleteTxGraph`] for more .
4529 pub fn missing_full_txs < A2 > ( & self , graph : & TxGraph < A2 > ) -> Vec < Txid > {
46- self . graph_update
30+ self . 0
4731 . keys ( )
4832 . filter ( move |& & txid| graph. as_ref ( ) . get_tx ( txid) . is_none ( ) )
4933 . cloned ( )
5034 . collect ( )
5135 }
5236
53- /// Finalizes update with `missing` txids to fetch from `client`.
37+ /// Finalizes the [`TxGraph`] update by fetching `missing` txids from the `client`.
5438 ///
55- /// Refer to [`ElectrumUpdate`] .
39+ /// Refer to [`IncompleteTxGraph`] for more .
5640 pub fn finalize (
5741 self ,
5842 client : & Client ,
5943 seen_at : Option < u64 > ,
6044 missing : Vec < Txid > ,
61- ) -> Result < ( TxGraph < A > , BTreeMap < K , u32 > , local_chain :: CheckPoint ) , Error > {
45+ ) -> Result < TxGraph < A > , Error > {
6246 let new_txs = client. batch_transaction_get ( & missing) ?;
63- let mut graph_update = TxGraph :: < A > :: new ( new_txs) ;
64- for ( txid, anchors) in self . graph_update {
47+ let mut graph = TxGraph :: < A > :: new ( new_txs) ;
48+ for ( txid, anchors) in self . 0 {
6549 if let Some ( seen_at) = seen_at {
66- let _ = graph_update . insert_seen_at ( txid, seen_at) ;
50+ let _ = graph . insert_seen_at ( txid, seen_at) ;
6751 }
6852 for anchor in anchors {
69- let _ = graph_update . insert_anchor ( txid, anchor) ;
53+ let _ = graph . insert_anchor ( txid, anchor) ;
7054 }
7155 }
72- Ok ( ( graph_update , self . keychain_update , self . new_tip ) )
56+ Ok ( graph )
7357 }
7458}
7559
76- impl < K > ElectrumUpdate < K , ConfirmationHeightAnchor > {
77- /// Finalizes the [`ElectrumUpdate `] with `new_txs` and anchors of type
60+ impl IncompleteTxGraph < ConfirmationHeightAnchor > {
61+ /// Finalizes the [`IncompleteTxGraph `] with `new_txs` and anchors of type
7862 /// [`ConfirmationTimeAnchor`].
7963 ///
8064 /// **Note:** The confirmation time might not be precisely correct if there has been a reorg.
8165 /// Electrum's API intends that we use the merkle proof API, we should change `bdk_electrum` to
8266 /// use it.
83- pub fn finalize_as_confirmation_time (
67+ pub fn finalize_with_confirmation_time (
8468 self ,
8569 client : & Client ,
8670 seen_at : Option < u64 > ,
8771 missing : Vec < Txid > ,
88- ) -> Result <
89- (
90- TxGraph < ConfirmationTimeAnchor > ,
91- BTreeMap < K , u32 > ,
92- local_chain:: CheckPoint ,
93- ) ,
94- Error ,
95- > {
96- let ( graph, keychain_update, update_tip) = self . finalize ( client, seen_at, missing) ?;
72+ ) -> Result < TxGraph < ConfirmationTimeAnchor > , Error > {
73+ let graph = self . finalize ( client, seen_at, missing) ?;
9774
9875 let relevant_heights = {
9976 let mut visited_heights = HashSet :: new ( ) ;
@@ -117,7 +94,7 @@ impl<K> ElectrumUpdate<K, ConfirmationHeightAnchor> {
11794 . collect :: < HashMap < u32 , u64 > > ( ) ;
11895
11996 let graph_changeset = {
120- let old_changeset = TxGraph :: default ( ) . apply_update ( graph. clone ( ) ) ;
97+ let old_changeset = TxGraph :: default ( ) . apply_update ( graph) ;
12198 tx_graph:: ChangeSet {
12299 txs : old_changeset. txs ,
123100 txouts : old_changeset. txouts ,
@@ -139,16 +116,16 @@ impl<K> ElectrumUpdate<K, ConfirmationHeightAnchor> {
139116 }
140117 } ;
141118
142- let mut update = TxGraph :: default ( ) ;
143- update. apply_changeset ( graph_changeset) ;
144-
145- Ok ( ( update, keychain_update, update_tip) )
119+ let mut new_graph = TxGraph :: default ( ) ;
120+ new_graph. apply_changeset ( graph_changeset) ;
121+ Ok ( new_graph)
146122 }
147123}
148124
149125/// Trait to extend [`Client`] functionality.
150126pub trait ElectrumExt < A > {
151- /// Scan the blockchain (via electrum) for the data specified and returns a [`ElectrumUpdate`].
127+ /// Scan the blockchain (via electrum) for the data specified and returns updates for
128+ /// [`bdk_chain`] data structures.
152129 ///
153130 /// - `prev_tip`: the most recent blockchain tip present locally
154131 /// - `keychain_spks`: keychains that we want to scan transactions for
@@ -159,6 +136,7 @@ pub trait ElectrumExt<A> {
159136 /// The scan for each keychain stops after a gap of `stop_gap` script pubkeys with no associated
160137 /// transactions. `batch_size` specifies the max number of script pubkeys to request for in a
161138 /// single batch request.
139+ #[ allow( clippy:: type_complexity) ]
162140 fn scan < K : Ord + Clone > (
163141 & self ,
164142 prev_tip : Option < CheckPoint > ,
@@ -167,7 +145,7 @@ pub trait ElectrumExt<A> {
167145 outpoints : impl IntoIterator < Item = OutPoint > ,
168146 stop_gap : usize ,
169147 batch_size : usize ,
170- ) -> Result < ElectrumUpdate < K , A > , Error > ;
148+ ) -> Result < ( local_chain :: Update , IncompleteTxGraph < A > , BTreeMap < K , u32 > ) , Error > ;
171149
172150 /// Convenience method to call [`scan`] without requiring a keychain.
173151 ///
@@ -179,20 +157,22 @@ pub trait ElectrumExt<A> {
179157 txids : impl IntoIterator < Item = Txid > ,
180158 outpoints : impl IntoIterator < Item = OutPoint > ,
181159 batch_size : usize ,
182- ) -> Result < ElectrumUpdate < ( ) , A > , Error > {
160+ ) -> Result < ( local_chain :: Update , IncompleteTxGraph < A > ) , Error > {
183161 let spk_iter = misc_spks
184162 . into_iter ( )
185163 . enumerate ( )
186164 . map ( |( i, spk) | ( i as u32 , spk) ) ;
187165
188- self . scan (
166+ let ( chain , graph , _ ) = self . scan (
189167 prev_tip,
190168 [ ( ( ) , spk_iter) ] . into ( ) ,
191169 txids,
192170 outpoints,
193171 usize:: MAX ,
194172 batch_size,
195- )
173+ ) ?;
174+
175+ Ok ( ( chain, graph) )
196176 }
197177}
198178
@@ -205,7 +185,14 @@ impl ElectrumExt<ConfirmationHeightAnchor> for Client {
205185 outpoints : impl IntoIterator < Item = OutPoint > ,
206186 stop_gap : usize ,
207187 batch_size : usize ,
208- ) -> Result < ElectrumUpdate < K , ConfirmationHeightAnchor > , Error > {
188+ ) -> Result <
189+ (
190+ local_chain:: Update ,
191+ IncompleteTxGraph < ConfirmationHeightAnchor > ,
192+ BTreeMap < K , u32 > ,
193+ ) ,
194+ Error ,
195+ > {
209196 let mut request_spks = keychain_spks
210197 . into_iter ( )
211198 . map ( |( k, s) | ( k, s. into_iter ( ) ) )
@@ -217,9 +204,8 @@ impl ElectrumExt<ConfirmationHeightAnchor> for Client {
217204
218205 let update = loop {
219206 let ( tip, _) = construct_update_tip ( self , prev_tip. clone ( ) ) ?;
220- let mut update = ElectrumUpdate :: < K , ConfirmationHeightAnchor > :: new ( tip. clone ( ) ) ;
221- let cps = update
222- . new_tip
207+ let mut graph_update = IncompleteTxGraph :: < ConfirmationHeightAnchor > :: default ( ) ;
208+ let cps = tip
223209 . iter ( )
224210 . take ( 10 )
225211 . map ( |cp| ( cp. height ( ) , cp) )
@@ -230,7 +216,7 @@ impl ElectrumExt<ConfirmationHeightAnchor> for Client {
230216 scanned_spks. append ( & mut populate_with_spks (
231217 self ,
232218 & cps,
233- & mut update ,
219+ & mut graph_update ,
234220 & mut scanned_spks
235221 . iter ( )
236222 . map ( |( i, ( spk, _) ) | ( i. clone ( ) , spk. clone ( ) ) ) ,
@@ -243,7 +229,7 @@ impl ElectrumExt<ConfirmationHeightAnchor> for Client {
243229 populate_with_spks (
244230 self ,
245231 & cps,
246- & mut update ,
232+ & mut graph_update ,
247233 keychain_spks,
248234 stop_gap,
249235 batch_size,
@@ -254,18 +240,27 @@ impl ElectrumExt<ConfirmationHeightAnchor> for Client {
254240 }
255241 }
256242
257- populate_with_txids ( self , & cps, & mut update , & mut txids. iter ( ) . cloned ( ) ) ?;
243+ populate_with_txids ( self , & cps, & mut graph_update , & mut txids. iter ( ) . cloned ( ) ) ?;
258244
259- let _txs =
260- populate_with_outpoints ( self , & cps, & mut update, & mut outpoints. iter ( ) . cloned ( ) ) ?;
245+ let _txs = populate_with_outpoints (
246+ self ,
247+ & cps,
248+ & mut graph_update,
249+ & mut outpoints. iter ( ) . cloned ( ) ,
250+ ) ?;
261251
262252 // check for reorgs during scan process
263253 let server_blockhash = self . block_header ( tip. height ( ) as usize ) ?. block_hash ( ) ;
264254 if tip. hash ( ) != server_blockhash {
265255 continue ; // reorg
266256 }
267257
268- update. keychain_update = request_spks
258+ let chain_update = local_chain:: Update {
259+ tip,
260+ introduce_older_blocks : true ,
261+ } ;
262+
263+ let keychain_update = request_spks
269264 . into_keys ( )
270265 . filter_map ( |k| {
271266 scanned_spks
@@ -275,7 +270,8 @@ impl ElectrumExt<ConfirmationHeightAnchor> for Client {
275270 . map ( |( ( _, i) , _) | ( k, * i) )
276271 } )
277272 . collect :: < BTreeMap < _ , _ > > ( ) ;
278- break update;
273+
274+ break ( chain_update, graph_update, keychain_update) ;
279275 } ;
280276
281277 Ok ( update)
@@ -399,10 +395,10 @@ fn determine_tx_anchor(
399395 }
400396}
401397
402- fn populate_with_outpoints < K > (
398+ fn populate_with_outpoints (
403399 client : & Client ,
404400 cps : & BTreeMap < u32 , CheckPoint > ,
405- update : & mut ElectrumUpdate < K , ConfirmationHeightAnchor > ,
401+ graph_update : & mut IncompleteTxGraph < ConfirmationHeightAnchor > ,
406402 outpoints : & mut impl Iterator < Item = OutPoint > ,
407403) -> Result < HashMap < Txid , Transaction > , Error > {
408404 let mut full_txs = HashMap :: new ( ) ;
@@ -451,7 +447,7 @@ fn populate_with_outpoints<K>(
451447 } ;
452448
453449 let anchor = determine_tx_anchor ( cps, res. height , res. tx_hash ) ;
454- let tx_entry = update . graph_update . entry ( res. tx_hash ) . or_default ( ) ;
450+ let tx_entry = graph_update. 0 . entry ( res. tx_hash ) . or_default ( ) ;
455451 if let Some ( anchor) = anchor {
456452 tx_entry. insert ( anchor) ;
457453 }
@@ -460,10 +456,10 @@ fn populate_with_outpoints<K>(
460456 Ok ( full_txs)
461457}
462458
463- fn populate_with_txids < K > (
459+ fn populate_with_txids (
464460 client : & Client ,
465461 cps : & BTreeMap < u32 , CheckPoint > ,
466- update : & mut ElectrumUpdate < K , ConfirmationHeightAnchor > ,
462+ graph_update : & mut IncompleteTxGraph < ConfirmationHeightAnchor > ,
467463 txids : & mut impl Iterator < Item = Txid > ,
468464) -> Result < ( ) , Error > {
469465 for txid in txids {
@@ -488,18 +484,18 @@ fn populate_with_txids<K>(
488484 None => continue ,
489485 } ;
490486
491- let tx_entry = update . graph_update . entry ( txid) . or_default ( ) ;
487+ let tx_entry = graph_update. 0 . entry ( txid) . or_default ( ) ;
492488 if let Some ( anchor) = anchor {
493489 tx_entry. insert ( anchor) ;
494490 }
495491 }
496492 Ok ( ( ) )
497493}
498494
499- fn populate_with_spks < K , I : Ord + Clone > (
495+ fn populate_with_spks < I : Ord + Clone > (
500496 client : & Client ,
501497 cps : & BTreeMap < u32 , CheckPoint > ,
502- update : & mut ElectrumUpdate < K , ConfirmationHeightAnchor > ,
498+ graph_update : & mut IncompleteTxGraph < ConfirmationHeightAnchor > ,
503499 spks : & mut impl Iterator < Item = ( I , ScriptBuf ) > ,
504500 stop_gap : usize ,
505501 batch_size : usize ,
@@ -532,7 +528,7 @@ fn populate_with_spks<K, I: Ord + Clone>(
532528 }
533529
534530 for tx in spk_history {
535- let tx_entry = update . graph_update . entry ( tx. tx_hash ) . or_default ( ) ;
531+ let tx_entry = graph_update. 0 . entry ( tx. tx_hash ) . or_default ( ) ;
536532 if let Some ( anchor) = determine_tx_anchor ( cps, tx. height , tx. tx_hash ) {
537533 tx_entry. insert ( anchor) ;
538534 }
0 commit comments