@@ -4,15 +4,26 @@ use crate::{Anchor, ChainOracle, TxGraph};
4
4
use alloc:: boxed:: Box ;
5
5
use alloc:: collections:: BTreeSet ;
6
6
use alloc:: sync:: Arc ;
7
+ use alloc:: vec:: Vec ;
7
8
use bdk_core:: BlockId ;
8
9
use bitcoin:: { Transaction , Txid } ;
9
10
11
+ /// Modifies the canonicalization algorithm.
12
+ #[ derive( Debug , Default , Clone ) ]
13
+ pub struct CanonicalizationParams {
14
+ /// Transactions that will supercede all other transactions.
15
+ ///
16
+ /// In case of conflicting transactions within `assume_canonical`, transactions that appear
17
+ /// later in the list (have higher index) have precedence.
18
+ pub assume_canonical : Vec < Txid > ,
19
+ }
10
20
/// Iterates over canonical txs.
11
21
pub struct CanonicalIter < ' g , A , C > {
12
22
tx_graph : & ' g TxGraph < A > ,
13
23
chain : & ' g C ,
14
24
chain_tip : BlockId ,
15
25
26
+ unprocessed_assumed_txs : Box < dyn Iterator < Item = ( Txid , Arc < Transaction > ) > + ' g > ,
16
27
unprocessed_anchored_txs :
17
28
Box < dyn Iterator < Item = ( Txid , Arc < Transaction > , & ' g BTreeSet < A > ) > + ' g > ,
18
29
unprocessed_seen_txs : Box < dyn Iterator < Item = ( Txid , Arc < Transaction > , u64 ) > + ' g > ,
@@ -26,8 +37,19 @@ pub struct CanonicalIter<'g, A, C> {
26
37
27
38
impl < ' g , A : Anchor , C : ChainOracle > CanonicalIter < ' g , A , C > {
28
39
/// Constructs [`CanonicalIter`].
29
- pub fn new ( tx_graph : & ' g TxGraph < A > , chain : & ' g C , chain_tip : BlockId ) -> Self {
40
+ pub fn new (
41
+ tx_graph : & ' g TxGraph < A > ,
42
+ chain : & ' g C ,
43
+ chain_tip : BlockId ,
44
+ mods : CanonicalizationParams ,
45
+ ) -> Self {
30
46
let anchors = tx_graph. all_anchors ( ) ;
47
+ let unprocessed_assumed_txs = Box :: new (
48
+ mods. assume_canonical
49
+ . into_iter ( )
50
+ . rev ( )
51
+ . filter_map ( |txid| Some ( ( txid, tx_graph. get_tx ( txid) ?) ) ) ,
52
+ ) ;
31
53
let unprocessed_anchored_txs = Box :: new (
32
54
tx_graph
33
55
. txids_by_descending_anchor_height ( )
@@ -42,6 +64,7 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> {
42
64
tx_graph,
43
65
chain,
44
66
chain_tip,
67
+ unprocessed_assumed_txs,
45
68
unprocessed_anchored_txs,
46
69
unprocessed_seen_txs,
47
70
unprocessed_leftover_txs : VecDeque :: new ( ) ,
@@ -147,6 +170,12 @@ impl<A: Anchor, C: ChainOracle> Iterator for CanonicalIter<'_, A, C> {
147
170
return Some ( Ok ( ( txid, tx, reason) ) ) ;
148
171
}
149
172
173
+ if let Some ( ( txid, tx) ) = self . unprocessed_assumed_txs . next ( ) {
174
+ if !self . is_canonicalized ( txid) {
175
+ self . mark_canonical ( txid, tx, CanonicalReason :: assumed ( ) ) ;
176
+ }
177
+ }
178
+
150
179
if let Some ( ( txid, tx, anchors) ) = self . unprocessed_anchored_txs . next ( ) {
151
180
if !self . is_canonicalized ( txid) {
152
181
if let Err ( err) = self . scan_anchors ( txid, tx, anchors) {
@@ -189,6 +218,12 @@ pub enum ObservedIn {
189
218
/// The reason why a transaction is canonical.
190
219
#[ derive( Debug , Clone , PartialEq , Eq ) ]
191
220
pub enum CanonicalReason < A > {
221
+ /// This transaction is explicitly assumed to be canonical by the caller, superceding all other
222
+ /// canonicalization rules.
223
+ Assumed {
224
+ /// Whether it is a descendant that is assumed to be canonical.
225
+ descendant : Option < Txid > ,
226
+ } ,
192
227
/// This transaction is anchored in the best chain by `A`, and therefore canonical.
193
228
Anchor {
194
229
/// The anchor that anchored the transaction in the chain.
@@ -207,6 +242,12 @@ pub enum CanonicalReason<A> {
207
242
}
208
243
209
244
impl < A : Clone > CanonicalReason < A > {
245
+ /// Constructs a [`CanonicalReason`] for a transaction that is assumed to supercede all other
246
+ /// transactions.
247
+ pub fn assumed ( ) -> Self {
248
+ Self :: Assumed { descendant : None }
249
+ }
250
+
210
251
/// Constructs a [`CanonicalReason`] from an `anchor`.
211
252
pub fn from_anchor ( anchor : A ) -> Self {
212
253
Self :: Anchor {
@@ -229,6 +270,9 @@ impl<A: Clone> CanonicalReason<A> {
229
270
/// descendant, but is transitively relevant.
230
271
pub fn to_transitive ( & self , descendant : Txid ) -> Self {
231
272
match self {
273
+ CanonicalReason :: Assumed { .. } => Self :: Assumed {
274
+ descendant : Some ( descendant) ,
275
+ } ,
232
276
CanonicalReason :: Anchor { anchor, .. } => Self :: Anchor {
233
277
anchor : anchor. clone ( ) ,
234
278
descendant : Some ( descendant) ,
@@ -244,6 +288,7 @@ impl<A: Clone> CanonicalReason<A> {
244
288
/// descendant.
245
289
pub fn descendant ( & self ) -> & Option < Txid > {
246
290
match self {
291
+ CanonicalReason :: Assumed { descendant, .. } => descendant,
247
292
CanonicalReason :: Anchor { descendant, .. } => descendant,
248
293
CanonicalReason :: ObservedIn { descendant, .. } => descendant,
249
294
}
0 commit comments