@@ -11,12 +11,23 @@ use bitcoin::{Transaction, Txid};
1111type CanonicalMap < A > = HashMap < Txid , ( Arc < Transaction > , CanonicalReason < A > ) > ;
1212type NotCanonicalSet = HashSet < Txid > ;
1313
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+
1424/// Iterates over canonical txs.
1525pub struct CanonicalIter < ' g , A , C > {
1626 tx_graph : & ' g TxGraph < A > ,
1727 chain : & ' g C ,
1828 chain_tip : BlockId ,
1929
30+ unprocessed_assumed_txs : Box < dyn Iterator < Item = ( Txid , Arc < Transaction > ) > + ' g > ,
2031 unprocessed_anchored_txs :
2132 Box < dyn Iterator < Item = ( Txid , Arc < Transaction > , & ' g BTreeSet < A > ) > + ' g > ,
2233 unprocessed_seen_txs : Box < dyn Iterator < Item = ( Txid , Arc < Transaction > , u64 ) > + ' g > ,
@@ -30,8 +41,19 @@ pub struct CanonicalIter<'g, A, C> {
3041
3142impl < ' g , A : Anchor , C : ChainOracle > CanonicalIter < ' g , A , C > {
3243 /// 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 {
3450 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+ ) ;
3557 let unprocessed_anchored_txs = Box :: new (
3658 tx_graph
3759 . txids_by_descending_anchor_height ( )
@@ -46,6 +68,7 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> {
4668 tx_graph,
4769 chain,
4870 chain_tip,
71+ unprocessed_assumed_txs,
4972 unprocessed_anchored_txs,
5073 unprocessed_seen_txs,
5174 unprocessed_leftover_txs : VecDeque :: new ( ) ,
@@ -190,6 +213,12 @@ impl<A: Anchor, C: ChainOracle> Iterator for CanonicalIter<'_, A, C> {
190213 return Some ( Ok ( ( txid, tx, reason) ) ) ;
191214 }
192215
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+
193222 if let Some ( ( txid, tx, anchors) ) = self . unprocessed_anchored_txs . next ( ) {
194223 if !self . is_canonicalized ( txid) {
195224 if let Err ( err) = self . scan_anchors ( txid, tx, anchors) {
@@ -232,6 +261,12 @@ pub enum ObservedIn {
232261/// The reason why a transaction is canonical.
233262#[ derive( Debug , Clone , PartialEq , Eq ) ]
234263pub 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+ } ,
235270 /// This transaction is anchored in the best chain by `A`, and therefore canonical.
236271 Anchor {
237272 /// The anchor that anchored the transaction in the chain.
@@ -250,6 +285,12 @@ pub enum CanonicalReason<A> {
250285}
251286
252287impl < 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+
253294 /// Constructs a [`CanonicalReason`] from an `anchor`.
254295 pub fn from_anchor ( anchor : A ) -> Self {
255296 Self :: Anchor {
@@ -272,6 +313,9 @@ impl<A: Clone> CanonicalReason<A> {
272313 /// descendant, but is transitively relevant.
273314 pub fn to_transitive ( & self , descendant : Txid ) -> Self {
274315 match self {
316+ CanonicalReason :: Assumed { .. } => Self :: Assumed {
317+ descendant : Some ( descendant) ,
318+ } ,
275319 CanonicalReason :: Anchor { anchor, .. } => Self :: Anchor {
276320 anchor : anchor. clone ( ) ,
277321 descendant : Some ( descendant) ,
@@ -287,6 +331,7 @@ impl<A: Clone> CanonicalReason<A> {
287331 /// descendant.
288332 pub fn descendant ( & self ) -> & Option < Txid > {
289333 match self {
334+ CanonicalReason :: Assumed { descendant, .. } => descendant,
290335 CanonicalReason :: Anchor { descendant, .. } => descendant,
291336 CanonicalReason :: ObservedIn { descendant, .. } => descendant,
292337 }
0 commit comments