@@ -731,3 +731,103 @@ fn no_agreement_point() -> anyhow::Result<()> {
731731
732732 Ok ( ( ) )
733733}
734+
735+ #[ test]
736+ fn test_expect_tx_evicted ( ) -> anyhow:: Result < ( ) > {
737+ use bdk_bitcoind_rpc:: bitcoincore_rpc:: bitcoin;
738+ use bdk_bitcoind_rpc:: bitcoincore_rpc:: bitcoincore_rpc_json:: CreateRawTransactionInput ;
739+ use bdk_chain:: miniscript;
740+ use bdk_chain:: spk_txout:: SpkTxOutIndex ;
741+ use bdk_chain:: ConfirmationBlockTime ;
742+ use bitcoin:: constants:: genesis_block;
743+ use bitcoin:: secp256k1:: Secp256k1 ;
744+ use bitcoin:: Network ;
745+ use std:: collections:: HashMap ;
746+ let env = TestEnv :: new ( ) ?;
747+
748+ let s = bdk_testenv:: utils:: DESCRIPTORS [ 0 ] ;
749+ let desc = miniscript:: Descriptor :: parse_descriptor ( & Secp256k1 :: new ( ) , s)
750+ . unwrap ( )
751+ . 0 ;
752+ let spk = desc. at_derivation_index ( 0 ) ?. script_pubkey ( ) ;
753+
754+ let chain = LocalChain :: from_genesis_hash ( genesis_block ( Network :: Regtest ) . block_hash ( ) ) . 0 ;
755+ let chain_tip = chain. tip ( ) . block_id ( ) ;
756+
757+ let mut index = SpkTxOutIndex :: default ( ) ;
758+ index. insert_spk ( ( "external" , 0u32 ) , spk. clone ( ) ) ;
759+ let mut graph = IndexedTxGraph :: < ConfirmationBlockTime , _ > :: new ( index) ;
760+
761+ // Receive tx1.
762+ let _ = env. mine_blocks ( 100 , None ) ?;
763+ let txid_1 = env. send (
764+ & Address :: from_script ( & spk, Network :: Regtest ) ?,
765+ Amount :: ONE_BTC ,
766+ ) ?;
767+
768+ let mut emitter = Emitter :: new ( env. rpc_client ( ) , chain. tip ( ) , 1 ) ;
769+ let changeset = graph. batch_insert_unconfirmed ( emitter. mempool ( ) ?) ;
770+ assert ! ( changeset
771+ . tx_graph
772+ . txs
773+ . iter( )
774+ . any( |tx| tx. compute_txid( ) == txid_1) ) ;
775+ let seen_at = graph
776+ . graph ( )
777+ . get_tx_node ( txid_1)
778+ . unwrap ( )
779+ . last_seen_unconfirmed
780+ . unwrap ( ) ;
781+
782+ // Double spend tx1.
783+
784+ // Get `prevout` from core.
785+ let core = env. rpc_client ( ) ;
786+ let tx1 = & core. get_raw_transaction ( & txid_1, None ) ?;
787+ let txin = & tx1. input [ 0 ] ;
788+ let op = txin. previous_output ;
789+
790+ // Create `tx1b` using the previous output from tx1.
791+ let utxo = CreateRawTransactionInput {
792+ txid : op. txid ,
793+ vout : op. vout ,
794+ sequence : None ,
795+ } ;
796+ let addr = core. get_new_address ( None , None ) ?. assume_checked ( ) ;
797+ let tx = core. create_raw_transaction (
798+ & [ utxo] ,
799+ & HashMap :: from ( [ ( addr. to_string ( ) , Amount :: from_btc ( 49.99 ) ?) ] ) ,
800+ None ,
801+ None ,
802+ ) ?;
803+ let res = core. sign_raw_transaction_with_wallet ( & tx, None , None ) ?;
804+ let tx1b = res. transaction ( ) ?;
805+
806+ // Send the tx.
807+ let txid_2 = core. send_raw_transaction ( & tx1b) ?;
808+
809+ // We evict the expected txs that are missing from mempool.
810+ let exp_txids = graph
811+ . iter_spks_with_expected_txids ( & chain, ..)
812+ . collect :: < Vec < _ > > ( ) ;
813+ assert_eq ! ( exp_txids, vec![ ( txid_1, spk) ] ) ;
814+ let mempool = emitter
815+ . mempool ( ) ?
816+ . into_iter ( )
817+ . map ( |( tx, _) | tx. compute_txid ( ) )
818+ . collect :: < Vec < _ > > ( ) ;
819+ assert ! ( mempool. contains( & txid_2) ) ;
820+ for ( txid, _) in exp_txids {
821+ if !mempool. contains ( & txid) {
822+ let _ = graph. insert_evicted_at ( txid, seen_at + 1 ) ;
823+ }
824+ }
825+
826+ assert ! ( graph
827+ . graph( )
828+ . list_canonical_txs( & chain, chain_tip)
829+ . next( )
830+ . is_none( ) ) ;
831+
832+ Ok ( ( ) )
833+ }
0 commit comments