@@ -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,20 @@ 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+ params : CanonicalizationParams ,
49+ ) -> Self {
3450 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+ ) ;
3558 let unprocessed_anchored_txs = Box :: new (
3659 tx_graph
3760 . txids_by_descending_anchor_height ( )
@@ -46,6 +69,7 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> {
4669 tx_graph,
4770 chain,
4871 chain_tip,
72+ unprocessed_assumed_txs,
4973 unprocessed_anchored_txs,
5074 unprocessed_seen_txs,
5175 unprocessed_leftover_txs : VecDeque :: new ( ) ,
@@ -190,6 +214,12 @@ impl<A: Anchor, C: ChainOracle> Iterator for CanonicalIter<'_, A, C> {
190214 return Some ( Ok ( ( txid, tx, reason) ) ) ;
191215 }
192216
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+
193223 if let Some ( ( txid, tx, anchors) ) = self . unprocessed_anchored_txs . next ( ) {
194224 if !self . is_canonicalized ( txid) {
195225 if let Err ( err) = self . scan_anchors ( txid, tx, anchors) {
@@ -232,6 +262,12 @@ pub enum ObservedIn {
232262/// The reason why a transaction is canonical.
233263#[ derive( Debug , Clone , PartialEq , Eq ) ]
234264pub 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+ } ,
235271 /// This transaction is anchored in the best chain by `A`, and therefore canonical.
236272 Anchor {
237273 /// The anchor that anchored the transaction in the chain.
@@ -250,6 +286,12 @@ pub enum CanonicalReason<A> {
250286}
251287
252288impl < 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+
253295 /// Constructs a [`CanonicalReason`] from an `anchor`.
254296 pub fn from_anchor ( anchor : A ) -> Self {
255297 Self :: Anchor {
@@ -272,6 +314,9 @@ impl<A: Clone> CanonicalReason<A> {
272314 /// descendant, but is transitively relevant.
273315 pub fn to_transitive ( & self , descendant : Txid ) -> Self {
274316 match self {
317+ CanonicalReason :: Assumed { .. } => Self :: Assumed {
318+ descendant : Some ( descendant) ,
319+ } ,
275320 CanonicalReason :: Anchor { anchor, .. } => Self :: Anchor {
276321 anchor : anchor. clone ( ) ,
277322 descendant : Some ( descendant) ,
@@ -287,6 +332,7 @@ impl<A: Clone> CanonicalReason<A> {
287332 /// descendant.
288333 pub fn descendant ( & self ) -> & Option < Txid > {
289334 match self {
335+ CanonicalReason :: Assumed { descendant, .. } => descendant,
290336 CanonicalReason :: Anchor { descendant, .. } => descendant,
291337 CanonicalReason :: ObservedIn { descendant, .. } => descendant,
292338 }
0 commit comments