@@ -54,8 +54,8 @@ use crate::{
5454 collections:: * , keychain:: Balance , local_chain:: LocalChain , Anchor , Append , BlockId ,
5555 ChainOracle , ChainPosition , FullTxOut ,
5656} ;
57- use alloc:: vec:: Vec ;
5857use alloc:: collections:: vec_deque:: VecDeque ;
58+ use alloc:: vec:: Vec ;
5959use bitcoin:: { OutPoint , Script , Transaction , TxOut , Txid } ;
6060use core:: {
6161 convert:: Infallible ,
@@ -697,8 +697,9 @@ impl<A: Anchor> TxGraph<A> {
697697 }
698698 }
699699
700- // The tx is not anchored to a block which is in the best chain, let's check whether we can
701- // ignore it by checking conflicts!
700+ // The tx is not anchored to a block which is in the best chain, which means that it
701+ // might be in mempool, or it might have been dropped already.
702+ // Let's check conflicts to find out!
702703 let tx = match tx_node {
703704 TxNodeInternal :: Whole ( tx) => tx,
704705 TxNodeInternal :: Partial ( _) => {
@@ -707,18 +708,71 @@ impl<A: Anchor> TxGraph<A> {
707708 }
708709 } ;
709710
710- // If a conflicting tx is in the best chain, or has `last_seen` higher than this tx, then
711- // this tx cannot exist in the best chain
712- for conflicting_tx in self . walk_conflicts ( tx, |_, txid| self . get_tx_node ( txid) ) {
713- for block in conflicting_tx. anchors . iter ( ) . map ( A :: anchor_block) {
714- if chain. is_block_in_chain ( block, chain_tip) ? == Some ( true ) {
715- // conflicting tx is in best chain, so the current tx cannot be in best chain!
711+ // We want to retrieve all the transactions that conflict with us, plus all the
712+ // transactions that conflict with our unconfirmed ancestors, since they conflict with us
713+ // as well.
714+ // We only traverse unconfirmed ancestors since conflicts of confirmed transactions
715+ // cannot be in the best chain.
716+
717+ // First of all, we retrieve all our ancestors. Since we're using `new_include_root`, the
718+ // resulting array will also include `tx`
719+ let unconfirmed_ancestor_txs =
720+ TxAncestors :: new_include_root ( self , tx, |_, ancestor_tx : & Transaction | {
721+ let tx_node = self . get_tx_node ( ancestor_tx. txid ( ) ) ?;
722+ // We're filtering the ancestors to keep only the unconfirmed ones (= no anchors in
723+ // the best chain)
724+ for block in tx_node. anchors {
725+ match chain. is_block_in_chain ( block. anchor_block ( ) , chain_tip) {
726+ Ok ( Some ( true ) ) => return None ,
727+ Err ( e) => return Some ( Err ( e) ) ,
728+ _ => continue ,
729+ }
730+ }
731+ Some ( Ok ( tx_node) )
732+ } )
733+ . collect :: < Result < Vec < _ > , C :: Error > > ( ) ?;
734+
735+ // We determine our tx's last seen, which is the max between our last seen,
736+ // and our unconf descendants' last seen.
737+ let unconfirmed_descendants_txs =
738+ TxDescendants :: new_include_root ( self , tx. txid ( ) , |_, descendant_txid : Txid | {
739+ let tx_node = self . get_tx_node ( descendant_txid) ?;
740+ // We're filtering the ancestors to keep only the unconfirmed ones (= no anchors in
741+ // the best chain)
742+ for block in tx_node. anchors {
743+ match chain. is_block_in_chain ( block. anchor_block ( ) , chain_tip) {
744+ Ok ( Some ( true ) ) => return None ,
745+ Err ( e) => return Some ( Err ( e) ) ,
746+ _ => continue ,
747+ }
748+ }
749+ Some ( Ok ( tx_node) )
750+ } )
751+ . collect :: < Result < Vec < _ > , C :: Error > > ( ) ?;
752+
753+ let tx_last_seen = unconfirmed_descendants_txs
754+ . iter ( )
755+ . max_by_key ( |tx| tx. last_seen_unconfirmed )
756+ . map ( |tx| tx. last_seen_unconfirmed )
757+ . expect ( "descendants always includes at least one transaction (the root tx" ) ;
758+
759+ // Now we traverse our ancestors and consider all their conflicts
760+ for tx_node in unconfirmed_ancestor_txs {
761+ // We retrieve all the transactions conflicting with this specific ancestor
762+ let conflicting_txs = self . walk_conflicts ( tx_node. tx , |_, txid| self . get_tx_node ( txid) ) ;
763+
764+ // If a conflicting tx is in the best chain, or has `last_seen` higher than this ancestor, then
765+ // this tx cannot exist in the best chain
766+ for conflicting_tx in conflicting_txs {
767+ for block in conflicting_tx. anchors {
768+ if chain. is_block_in_chain ( block. anchor_block ( ) , chain_tip) ? == Some ( true ) {
769+ return Ok ( None ) ;
770+ }
771+ }
772+ if conflicting_tx. last_seen_unconfirmed > tx_last_seen {
716773 return Ok ( None ) ;
717774 }
718775 }
719- if conflicting_tx. last_seen_unconfirmed > * last_seen {
720- return Ok ( None ) ;
721- }
722776 }
723777
724778 Ok ( Some ( ChainPosition :: Unconfirmed ( * last_seen) ) )
0 commit comments