@@ -4,15 +4,34 @@ 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 CanonicalizationMods {
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
+ }
20
+
21
+ impl CanonicalizationMods {
22
+ /// No mods.
23
+ pub const NONE : Self = Self {
24
+ assume_canonical : Vec :: new ( ) ,
25
+ } ;
26
+ }
27
+
10
28
/// Iterates over canonical txs.
11
29
pub struct CanonicalIter < ' g , A , C > {
12
30
tx_graph : & ' g TxGraph < A > ,
13
31
chain : & ' g C ,
14
32
chain_tip : BlockId ,
15
33
34
+ unprocessed_assumed_txs : Box < dyn Iterator < Item = ( Txid , Arc < Transaction > ) > + ' g > ,
16
35
unprocessed_anchored_txs :
17
36
Box < dyn Iterator < Item = ( Txid , Arc < Transaction > , & ' g BTreeSet < A > ) > + ' g > ,
18
37
unprocessed_seen_txs : Box < dyn Iterator < Item = ( Txid , Arc < Transaction > , u64 ) > + ' g > ,
@@ -26,8 +45,19 @@ pub struct CanonicalIter<'g, A, C> {
26
45
27
46
impl < ' g , A : Anchor , C : ChainOracle > CanonicalIter < ' g , A , C > {
28
47
/// Constructs [`CanonicalIter`].
29
- pub fn new ( tx_graph : & ' g TxGraph < A > , chain : & ' g C , chain_tip : BlockId ) -> Self {
48
+ pub fn new (
49
+ tx_graph : & ' g TxGraph < A > ,
50
+ chain : & ' g C ,
51
+ chain_tip : BlockId ,
52
+ mods : CanonicalizationMods ,
53
+ ) -> Self {
30
54
let anchors = tx_graph. all_anchors ( ) ;
55
+ let unprocessed_assumed_txs = Box :: new (
56
+ mods. assume_canonical
57
+ . into_iter ( )
58
+ . rev ( )
59
+ . filter_map ( |txid| Some ( ( txid, tx_graph. get_tx ( txid) ?) ) ) ,
60
+ ) ;
31
61
let unprocessed_anchored_txs = Box :: new (
32
62
tx_graph
33
63
. txids_by_descending_anchor_height ( )
@@ -42,6 +72,7 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> {
42
72
tx_graph,
43
73
chain,
44
74
chain_tip,
75
+ unprocessed_assumed_txs,
45
76
unprocessed_anchored_txs,
46
77
unprocessed_seen_txs,
47
78
unprocessed_leftover_txs : VecDeque :: new ( ) ,
@@ -147,6 +178,12 @@ impl<A: Anchor, C: ChainOracle> Iterator for CanonicalIter<'_, A, C> {
147
178
return Some ( Ok ( ( txid, tx, reason) ) ) ;
148
179
}
149
180
181
+ if let Some ( ( txid, tx) ) = self . unprocessed_assumed_txs . next ( ) {
182
+ if !self . is_canonicalized ( txid) {
183
+ self . mark_canonical ( txid, tx, CanonicalReason :: assumed ( ) ) ;
184
+ }
185
+ }
186
+
150
187
if let Some ( ( txid, tx, anchors) ) = self . unprocessed_anchored_txs . next ( ) {
151
188
if !self . is_canonicalized ( txid) {
152
189
if let Err ( err) = self . scan_anchors ( txid, tx, anchors) {
@@ -189,6 +226,12 @@ pub enum ObservedIn {
189
226
/// The reason why a transaction is canonical.
190
227
#[ derive( Debug , Clone , PartialEq , Eq ) ]
191
228
pub enum CanonicalReason < A > {
229
+ /// This transaction is explicitly assumed to be canonical by the caller, superceding all other
230
+ /// canonicalization rules.
231
+ Assumed {
232
+ /// Whether it is a descendant that is assumed to be canonical.
233
+ descendant : Option < Txid > ,
234
+ } ,
192
235
/// This transaction is anchored in the best chain by `A`, and therefore canonical.
193
236
Anchor {
194
237
/// The anchor that anchored the transaction in the chain.
@@ -207,6 +250,12 @@ pub enum CanonicalReason<A> {
207
250
}
208
251
209
252
impl < A : Clone > CanonicalReason < A > {
253
+ /// Constructs a [`CanonicalReason`] for a transaction that is assumed to supercede all other
254
+ /// transactions.
255
+ pub fn assumed ( ) -> Self {
256
+ Self :: Assumed { descendant : None }
257
+ }
258
+
210
259
/// Constructs a [`CanonicalReason`] from an `anchor`.
211
260
pub fn from_anchor ( anchor : A ) -> Self {
212
261
Self :: Anchor {
@@ -229,6 +278,9 @@ impl<A: Clone> CanonicalReason<A> {
229
278
/// descendant, but is transitively relevant.
230
279
pub fn to_transitive ( & self , descendant : Txid ) -> Self {
231
280
match self {
281
+ CanonicalReason :: Assumed { .. } => Self :: Assumed {
282
+ descendant : Some ( descendant) ,
283
+ } ,
232
284
CanonicalReason :: Anchor { anchor, .. } => Self :: Anchor {
233
285
anchor : anchor. clone ( ) ,
234
286
descendant : Some ( descendant) ,
@@ -244,6 +296,7 @@ impl<A: Clone> CanonicalReason<A> {
244
296
/// descendant.
245
297
pub fn descendant ( & self ) -> & Option < Txid > {
246
298
match self {
299
+ CanonicalReason :: Assumed { descendant, .. } => descendant,
247
300
CanonicalReason :: Anchor { descendant, .. } => descendant,
248
301
CanonicalReason :: ObservedIn { descendant, .. } => descendant,
249
302
}
0 commit comments