@@ -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,19 @@ 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
+ mods : CanonicalizationParams ,
49
+ ) -> Self {
34
50
let anchors = tx_graph. all_anchors ( ) ;
51
+ let unprocessed_assumed_txs = Box :: new (
52
+ mods. assume_canonical
53
+ . into_iter ( )
54
+ . rev ( )
55
+ . filter_map ( |txid| Some ( ( txid, tx_graph. get_tx ( txid) ?) ) ) ,
56
+ ) ;
35
57
let unprocessed_anchored_txs = Box :: new (
36
58
tx_graph
37
59
. txids_by_descending_anchor_height ( )
@@ -46,6 +68,7 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> {
46
68
tx_graph,
47
69
chain,
48
70
chain_tip,
71
+ unprocessed_assumed_txs,
49
72
unprocessed_anchored_txs,
50
73
unprocessed_seen_txs,
51
74
unprocessed_leftover_txs : VecDeque :: new ( ) ,
@@ -190,6 +213,12 @@ impl<A: Anchor, C: ChainOracle> Iterator for CanonicalIter<'_, A, C> {
190
213
return Some ( Ok ( ( txid, tx, reason) ) ) ;
191
214
}
192
215
216
+ if let Some ( ( txid, tx) ) = self . unprocessed_assumed_txs . next ( ) {
217
+ if !self . is_canonicalized ( txid) {
218
+ self . mark_canonical ( txid, tx, CanonicalReason :: assumed ( ) ) ;
219
+ }
220
+ }
221
+
193
222
if let Some ( ( txid, tx, anchors) ) = self . unprocessed_anchored_txs . next ( ) {
194
223
if !self . is_canonicalized ( txid) {
195
224
if let Err ( err) = self . scan_anchors ( txid, tx, anchors) {
@@ -232,6 +261,12 @@ pub enum ObservedIn {
232
261
/// The reason why a transaction is canonical.
233
262
#[ derive( Debug , Clone , PartialEq , Eq ) ]
234
263
pub enum CanonicalReason < A > {
264
+ /// This transaction is explicitly assumed to be canonical by the caller, superceding all other
265
+ /// canonicalization rules.
266
+ Assumed {
267
+ /// Whether it is a descendant that is assumed to be canonical.
268
+ descendant : Option < Txid > ,
269
+ } ,
235
270
/// This transaction is anchored in the best chain by `A`, and therefore canonical.
236
271
Anchor {
237
272
/// The anchor that anchored the transaction in the chain.
@@ -250,6 +285,12 @@ pub enum CanonicalReason<A> {
250
285
}
251
286
252
287
impl < A : Clone > CanonicalReason < A > {
288
+ /// Constructs a [`CanonicalReason`] for a transaction that is assumed to supercede all other
289
+ /// transactions.
290
+ pub fn assumed ( ) -> Self {
291
+ Self :: Assumed { descendant : None }
292
+ }
293
+
253
294
/// Constructs a [`CanonicalReason`] from an `anchor`.
254
295
pub fn from_anchor ( anchor : A ) -> Self {
255
296
Self :: Anchor {
@@ -272,6 +313,9 @@ impl<A: Clone> CanonicalReason<A> {
272
313
/// descendant, but is transitively relevant.
273
314
pub fn to_transitive ( & self , descendant : Txid ) -> Self {
274
315
match self {
316
+ CanonicalReason :: Assumed { .. } => Self :: Assumed {
317
+ descendant : Some ( descendant) ,
318
+ } ,
275
319
CanonicalReason :: Anchor { anchor, .. } => Self :: Anchor {
276
320
anchor : anchor. clone ( ) ,
277
321
descendant : Some ( descendant) ,
@@ -287,6 +331,7 @@ impl<A: Clone> CanonicalReason<A> {
287
331
/// descendant.
288
332
pub fn descendant ( & self ) -> & Option < Txid > {
289
333
match self {
334
+ CanonicalReason :: Assumed { descendant, .. } => descendant,
290
335
CanonicalReason :: Anchor { descendant, .. } => descendant,
291
336
CanonicalReason :: ObservedIn { descendant, .. } => descendant,
292
337
}
0 commit comments