@@ -11,12 +11,23 @@ use bitcoin::{Transaction, Txid};
11
11
type CanonicalMap < A > = HashMap < Txid , ( Arc < Transaction > , CanonicalReason < A > ) > ;
12
12
type NotCanonicalSet = HashSet < Txid > ;
13
13
14
+ /// Modifies the canonicalization algorithm.
15
+ #[ derive( Debug , Default , Clone ) ]
16
+ pub struct CanonicalizationParams {
17
+ /// Transactions that will supercede all other transactions.
18
+ ///
19
+ /// In case of conflicting transactions within `assume_canonical`, transactions that appear
20
+ /// later in the list (have higher index) have precedence.
21
+ pub assume_canonical : Vec < Txid > ,
22
+ }
23
+
14
24
/// Iterates over canonical txs.
15
25
pub struct CanonicalIter < ' g , A , C > {
16
26
tx_graph : & ' g TxGraph < A > ,
17
27
chain : & ' g C ,
18
28
chain_tip : BlockId ,
19
29
30
+ unprocessed_assumed_txs : Box < dyn Iterator < Item = ( Txid , Arc < Transaction > ) > + ' g > ,
20
31
unprocessed_anchored_txs :
21
32
Box < dyn Iterator < Item = ( Txid , Arc < Transaction > , & ' g BTreeSet < A > ) > + ' g > ,
22
33
unprocessed_seen_txs : Box < dyn Iterator < Item = ( Txid , Arc < Transaction > , u64 ) > + ' g > ,
@@ -30,8 +41,20 @@ pub struct CanonicalIter<'g, A, C> {
30
41
31
42
impl < ' g , A : Anchor , C : ChainOracle > CanonicalIter < ' g , A , C > {
32
43
/// Constructs [`CanonicalIter`].
33
- pub fn new ( tx_graph : & ' g TxGraph < A > , chain : & ' g C , chain_tip : BlockId ) -> Self {
44
+ pub fn new (
45
+ tx_graph : & ' g TxGraph < A > ,
46
+ chain : & ' g C ,
47
+ chain_tip : BlockId ,
48
+ params : CanonicalizationParams ,
49
+ ) -> Self {
34
50
let anchors = tx_graph. all_anchors ( ) ;
51
+ let unprocessed_assumed_txs = Box :: new (
52
+ params
53
+ . assume_canonical
54
+ . into_iter ( )
55
+ . rev ( )
56
+ . filter_map ( |txid| Some ( ( txid, tx_graph. get_tx ( txid) ?) ) ) ,
57
+ ) ;
35
58
let unprocessed_anchored_txs = Box :: new (
36
59
tx_graph
37
60
. txids_by_descending_anchor_height ( )
@@ -46,6 +69,7 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> {
46
69
tx_graph,
47
70
chain,
48
71
chain_tip,
72
+ unprocessed_assumed_txs,
49
73
unprocessed_anchored_txs,
50
74
unprocessed_seen_txs,
51
75
unprocessed_leftover_txs : VecDeque :: new ( ) ,
@@ -190,6 +214,12 @@ impl<A: Anchor, C: ChainOracle> Iterator for CanonicalIter<'_, A, C> {
190
214
return Some ( Ok ( ( txid, tx, reason) ) ) ;
191
215
}
192
216
217
+ if let Some ( ( txid, tx) ) = self . unprocessed_assumed_txs . next ( ) {
218
+ if !self . is_canonicalized ( txid) {
219
+ self . mark_canonical ( txid, tx, CanonicalReason :: assumed ( ) ) ;
220
+ }
221
+ }
222
+
193
223
if let Some ( ( txid, tx, anchors) ) = self . unprocessed_anchored_txs . next ( ) {
194
224
if !self . is_canonicalized ( txid) {
195
225
if let Err ( err) = self . scan_anchors ( txid, tx, anchors) {
@@ -232,6 +262,12 @@ pub enum ObservedIn {
232
262
/// The reason why a transaction is canonical.
233
263
#[ derive( Debug , Clone , PartialEq , Eq ) ]
234
264
pub enum CanonicalReason < A > {
265
+ /// This transaction is explicitly assumed to be canonical by the caller, superceding all other
266
+ /// canonicalization rules.
267
+ Assumed {
268
+ /// Whether it is a descendant that is assumed to be canonical.
269
+ descendant : Option < Txid > ,
270
+ } ,
235
271
/// This transaction is anchored in the best chain by `A`, and therefore canonical.
236
272
Anchor {
237
273
/// The anchor that anchored the transaction in the chain.
@@ -250,6 +286,12 @@ pub enum CanonicalReason<A> {
250
286
}
251
287
252
288
impl < A : Clone > CanonicalReason < A > {
289
+ /// Constructs a [`CanonicalReason`] for a transaction that is assumed to supercede all other
290
+ /// transactions.
291
+ pub fn assumed ( ) -> Self {
292
+ Self :: Assumed { descendant : None }
293
+ }
294
+
253
295
/// Constructs a [`CanonicalReason`] from an `anchor`.
254
296
pub fn from_anchor ( anchor : A ) -> Self {
255
297
Self :: Anchor {
@@ -272,6 +314,9 @@ impl<A: Clone> CanonicalReason<A> {
272
314
/// descendant, but is transitively relevant.
273
315
pub fn to_transitive ( & self , descendant : Txid ) -> Self {
274
316
match self {
317
+ CanonicalReason :: Assumed { .. } => Self :: Assumed {
318
+ descendant : Some ( descendant) ,
319
+ } ,
275
320
CanonicalReason :: Anchor { anchor, .. } => Self :: Anchor {
276
321
anchor : anchor. clone ( ) ,
277
322
descendant : Some ( descendant) ,
@@ -287,6 +332,7 @@ impl<A: Clone> CanonicalReason<A> {
287
332
/// descendant.
288
333
pub fn descendant ( & self ) -> & Option < Txid > {
289
334
match self {
335
+ CanonicalReason :: Assumed { descendant, .. } => descendant,
290
336
CanonicalReason :: Anchor { descendant, .. } => descendant,
291
337
CanonicalReason :: ObservedIn { descendant, .. } => descendant,
292
338
}
0 commit comments