@@ -4,15 +4,26 @@ use crate::{Anchor, ChainOracle, TxGraph};
44use alloc:: boxed:: Box ;
55use alloc:: collections:: BTreeSet ;
66use alloc:: sync:: Arc ;
7+ use alloc:: vec:: Vec ;
78use bdk_core:: BlockId ;
89use bitcoin:: { Transaction , Txid } ;
910
11+ /// Modifies the canonicalization algorithm.
12+ #[ derive( Debug , Default , Clone ) ]
13+ pub struct CanonicalizationParams {
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+ }
1020/// Iterates over canonical txs.
1121pub struct CanonicalIter < ' g , A , C > {
1222 tx_graph : & ' g TxGraph < A > ,
1323 chain : & ' g C ,
1424 chain_tip : BlockId ,
1525
26+ unprocessed_assumed_txs : Box < dyn Iterator < Item = ( Txid , Arc < Transaction > ) > + ' g > ,
1627 unprocessed_anchored_txs :
1728 Box < dyn Iterator < Item = ( Txid , Arc < Transaction > , & ' g BTreeSet < A > ) > + ' g > ,
1829 unprocessed_seen_txs : Box < dyn Iterator < Item = ( Txid , Arc < Transaction > , u64 ) > + ' g > ,
@@ -26,8 +37,19 @@ pub struct CanonicalIter<'g, A, C> {
2637
2738impl < ' g , A : Anchor , C : ChainOracle > CanonicalIter < ' g , A , C > {
2839 /// Constructs [`CanonicalIter`].
29- pub fn new ( tx_graph : & ' g TxGraph < A > , chain : & ' g C , chain_tip : BlockId ) -> Self {
40+ pub fn new (
41+ tx_graph : & ' g TxGraph < A > ,
42+ chain : & ' g C ,
43+ chain_tip : BlockId ,
44+ mods : CanonicalizationParams ,
45+ ) -> Self {
3046 let anchors = tx_graph. all_anchors ( ) ;
47+ let unprocessed_assumed_txs = Box :: new (
48+ mods. assume_canonical
49+ . into_iter ( )
50+ . rev ( )
51+ . filter_map ( |txid| Some ( ( txid, tx_graph. get_tx ( txid) ?) ) ) ,
52+ ) ;
3153 let unprocessed_anchored_txs = Box :: new (
3254 tx_graph
3355 . txids_by_descending_anchor_height ( )
@@ -42,6 +64,7 @@ impl<'g, A: Anchor, C: ChainOracle> CanonicalIter<'g, A, C> {
4264 tx_graph,
4365 chain,
4466 chain_tip,
67+ unprocessed_assumed_txs,
4568 unprocessed_anchored_txs,
4669 unprocessed_seen_txs,
4770 unprocessed_leftover_txs : VecDeque :: new ( ) ,
@@ -147,6 +170,12 @@ impl<A: Anchor, C: ChainOracle> Iterator for CanonicalIter<'_, A, C> {
147170 return Some ( Ok ( ( txid, tx, reason) ) ) ;
148171 }
149172
173+ if let Some ( ( txid, tx) ) = self . unprocessed_assumed_txs . next ( ) {
174+ if !self . is_canonicalized ( txid) {
175+ self . mark_canonical ( txid, tx, CanonicalReason :: assumed ( ) ) ;
176+ }
177+ }
178+
150179 if let Some ( ( txid, tx, anchors) ) = self . unprocessed_anchored_txs . next ( ) {
151180 if !self . is_canonicalized ( txid) {
152181 if let Err ( err) = self . scan_anchors ( txid, tx, anchors) {
@@ -189,6 +218,12 @@ pub enum ObservedIn {
189218/// The reason why a transaction is canonical.
190219#[ derive( Debug , Clone , PartialEq , Eq ) ]
191220pub enum CanonicalReason < A > {
221+ /// This transaction is explicitly assumed to be canonical by the caller, superceding all other
222+ /// canonicalization rules.
223+ Assumed {
224+ /// Whether it is a descendant that is assumed to be canonical.
225+ descendant : Option < Txid > ,
226+ } ,
192227 /// This transaction is anchored in the best chain by `A`, and therefore canonical.
193228 Anchor {
194229 /// The anchor that anchored the transaction in the chain.
@@ -207,6 +242,12 @@ pub enum CanonicalReason<A> {
207242}
208243
209244impl < A : Clone > CanonicalReason < A > {
245+ /// Constructs a [`CanonicalReason`] for a transaction that is assumed to supercede all other
246+ /// transactions.
247+ pub fn assumed ( ) -> Self {
248+ Self :: Assumed { descendant : None }
249+ }
250+
210251 /// Constructs a [`CanonicalReason`] from an `anchor`.
211252 pub fn from_anchor ( anchor : A ) -> Self {
212253 Self :: Anchor {
@@ -229,6 +270,9 @@ impl<A: Clone> CanonicalReason<A> {
229270 /// descendant, but is transitively relevant.
230271 pub fn to_transitive ( & self , descendant : Txid ) -> Self {
231272 match self {
273+ CanonicalReason :: Assumed { .. } => Self :: Assumed {
274+ descendant : Some ( descendant) ,
275+ } ,
232276 CanonicalReason :: Anchor { anchor, .. } => Self :: Anchor {
233277 anchor : anchor. clone ( ) ,
234278 descendant : Some ( descendant) ,
@@ -244,6 +288,7 @@ impl<A: Clone> CanonicalReason<A> {
244288 /// descendant.
245289 pub fn descendant ( & self ) -> & Option < Txid > {
246290 match self {
291+ CanonicalReason :: Assumed { descendant, .. } => descendant,
247292 CanonicalReason :: Anchor { descendant, .. } => descendant,
248293 CanonicalReason :: ObservedIn { descendant, .. } => descendant,
249294 }
0 commit comments