1- use std:: { str :: FromStr , sync :: Arc , time :: Duration } ;
1+ use std:: { ops :: Deref , str :: FromStr } ;
22
33use anyhow:: Context ;
4+ use bdk_bitcoind_rpc:: Emitter ;
45use bdk_testenv:: { bitcoincore_rpc:: RpcApi , TestEnv } ;
56use bdk_wallet:: { KeychainKind , SignOptions , Wallet } ;
67use bitcoin:: { Amount , Network , Txid } ;
78
89const DESCRIPTOR : & str = bdk_testenv:: utils:: DESCRIPTORS [ 3 ] ;
910
11+ fn sync_to_tip < C > ( wallet : & mut Wallet , emitter : & mut Emitter < C > ) -> anyhow:: Result < ( ) >
12+ where
13+ C : Deref ,
14+ C :: Target : RpcApi ,
15+ {
16+ while let Some ( block_event) = emitter. next_block ( ) ? {
17+ wallet. apply_block ( & block_event. block , block_event. block_height ( ) ) ?;
18+ }
19+ Ok ( ( ) )
20+ }
21+
22+ fn sync_mempool < C > ( wallet : & mut Wallet , emitter : & mut Emitter < C > ) -> anyhow:: Result < ( ) >
23+ where
24+ C : Deref ,
25+ C :: Target : RpcApi ,
26+ {
27+ let event = emitter. mempool ( ) ?;
28+ wallet. apply_unconfirmed_txs ( event. update ) ;
29+ wallet. apply_evicted_txs ( event. evicted ) ;
30+ Ok ( ( ) )
31+ }
32+
33+ /// Receive an unconfirmed tx, spend from it, and the unconfirmed tx get's RBF'ed.
34+ /// Our API should be able to recognise that the outgoing tx became evicted and allow the caller
35+ /// to respond accordingly.
1036fn main ( ) -> anyhow:: Result < ( ) > {
1137 let env = TestEnv :: new ( ) . context ( "failed to start testenv" ) ?;
1238 env. mine_blocks ( 101 , None )
@@ -23,60 +49,53 @@ fn main() -> anyhow::Result<()> {
2349 0 ,
2450 wallet
2551 . transactions ( )
26- . filter ( |tx| tx. chain_position . is_unconfirmed ( ) )
27- . map ( |tx| tx. tx_node . txid ) ,
52+ . filter ( |tx| tx. chain_position . is_unconfirmed ( ) ) ,
2853 ) ;
29- while let Some ( block_event) = emitter. next_block ( ) ? {
30- wallet. apply_block ( & block_event. block , block_event. block_height ( ) ) ?;
31- }
3254
33- // Receive an unconfirmed tx, spend from it, and the unconfirmed tx get's RBF'ed.
34- // Our API should be able to recognise that the outgoing tx became evicted and allow the caller
35- // to respond accordingly.
3655 let wallet_addr = wallet. next_unused_address ( KeychainKind :: External ) . address ;
3756 let remote_addr = env
3857 . rpc_client ( )
3958 . get_new_address ( None , None ) ?
40- . assume_checked ( ) ;
41- let incoming_txid = env. send ( & wallet_addr, Amount :: ONE_BTC ) ?;
59+ . require_network ( Network :: Regtest ) ?;
4260
43- let mempool_event = emitter. mempool ( ) ?;
44- wallet. apply_evicted_txs ( mempool_event. evicted_ats ( ) ) ;
45- wallet. apply_unconfirmed_txs ( mempool_event. new_txs ) ;
61+ sync_to_tip ( & mut wallet, & mut emitter) ?;
62+
63+ // [INCOMING TX] : Create, broadcast & sync
64+ let incoming_txid = env. send ( & wallet_addr, Amount :: ONE_BTC ) ?;
65+ sync_mempool ( & mut wallet, & mut emitter) ?;
4666 assert_eq ! ( wallet. balance( ) . total( ) , Amount :: ONE_BTC ) ;
4767
48- // Create & broadcast outgoing tx.
49- let mut tx_builder = wallet. build_tx ( ) ;
50- tx_builder. add_recipient ( remote_addr, Amount :: ONE_BTC / 2 ) ;
51- let mut psbt = tx_builder. finish ( ) ?;
52- assert ! ( wallet. sign( & mut psbt, SignOptions :: default ( ) ) ?) ;
53- let outgoing_tx = psbt. extract_tx ( ) ?;
68+ // [OUTGOING TX] : Create & track
69+ let outgoing_tx = {
70+ let mut tx_builder = wallet. build_tx ( ) ;
71+ tx_builder. add_recipient ( remote_addr, Amount :: ONE_BTC / 2 ) ;
72+ let mut psbt = tx_builder. finish ( ) ?;
73+ assert ! ( wallet. sign( & mut psbt, SignOptions :: default ( ) ) ?) ;
74+ psbt. extract_tx ( ) ?
75+ } ;
5476 wallet. track_tx ( outgoing_tx. clone ( ) ) ;
5577 assert_eq ! ( wallet. uncanonical_txs( ) . count( ) , 1 ) ;
5678
57- // Sync.
58- let outgoing_txid = env. rpc_client ( ) . send_raw_transaction ( & outgoing_tx) ?;
59- env. wait_until_electrum_sees_txid ( outgoing_txid, Duration :: from_secs ( 5 ) ) ?;
60- let mempool_event = emitter. mempool ( ) ?;
61- // TODO: Why is `outgoing_txid` not emitted?
62- println ! ( "mempool_event: {mempool_event:#?}" ) ;
63- wallet. apply_evicted_txs ( mempool_event. evicted_ats ( ) ) ;
64- wallet. apply_unconfirmed_txs ( mempool_event. new_txs ) ;
65- let tx = wallet
66- . canonical_txs ( )
67- . find ( |tx| tx. tx_node . txid == outgoing_txid)
68- . expect ( "must find outgoing tx" ) ;
69- assert_eq ! ( wallet. uncanonical_txs( ) . count( ) , 0 ) ;
79+ // let outgoing_txid = env.rpc_client().send_raw_transaction(&outgoing_tx)?;
80+ // env.wait_until_electrum_sees_txid(outgoing_txid, Duration::from_secs(5))?;
81+ // let mempool_event = emitter.mempool()?;
82+ // println!("mempool_event: {mempool_event:?}");
83+ // wallet.apply_unconfirmed_txs(mempool_event.update);
84+ // wallet.apply_evicted_txs(mempool_event.evicted);
85+ // let tx = wallet
86+ // .canonical_txs()
87+ // .find(|tx| tx.tx_node.txid == outgoing_txid)
88+ // .expect("must find outgoing tx");
89+ // assert_eq!(wallet.uncanonical_txs().count(), 0);
7090
7191 // RBF incoming tx.
72- let res = env
73- . rpc_client ( )
74- . call :: < serde_json:: Value > ( "bumpfee" , & [ incoming_txid. to_string ( ) . into ( ) ] ) ?;
75- let incoming_replacement_txid = Txid :: from_str ( res. get ( "txid" ) . unwrap ( ) . as_str ( ) . unwrap ( ) ) ?;
76-
77- let mempool_event = emitter. mempool ( ) ?;
78- wallet. apply_evicted_txs ( mempool_event. evicted_ats ( ) ) ;
79- wallet. apply_unconfirmed_txs ( mempool_event. new_txs ) ;
92+ let incoming_rbf_tx = {
93+ let res = env
94+ . rpc_client ( )
95+ . call :: < serde_json:: Value > ( "bumpfee" , & [ incoming_txid. to_string ( ) . into ( ) ] ) ?;
96+ Txid :: from_str ( res. get ( "txid" ) . unwrap ( ) . as_str ( ) . unwrap ( ) ) ?
97+ } ;
98+ sync_mempool ( & mut wallet, & mut emitter) ?;
8099
81100 for uncanonical_tx in wallet. uncanonical_txs ( ) { }
82101
0 commit comments