1
- use std:: { str :: FromStr , sync :: Arc , time :: Duration } ;
1
+ use std:: { ops :: Deref , str :: FromStr } ;
2
2
3
3
use anyhow:: Context ;
4
+ use bdk_bitcoind_rpc:: Emitter ;
4
5
use bdk_testenv:: { bitcoincore_rpc:: RpcApi , TestEnv } ;
5
6
use bdk_wallet:: { KeychainKind , SignOptions , Wallet } ;
6
7
use bitcoin:: { Amount , Network , Txid } ;
7
8
8
9
const DESCRIPTOR : & str = bdk_testenv:: utils:: DESCRIPTORS [ 3 ] ;
9
10
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.
10
36
fn main ( ) -> anyhow:: Result < ( ) > {
11
37
let env = TestEnv :: new ( ) . context ( "failed to start testenv" ) ?;
12
38
env. mine_blocks ( 101 , None )
@@ -23,60 +49,53 @@ fn main() -> anyhow::Result<()> {
23
49
0 ,
24
50
wallet
25
51
. transactions ( )
26
- . filter ( |tx| tx. chain_position . is_unconfirmed ( ) )
27
- . map ( |tx| tx. tx_node . txid ) ,
52
+ . filter ( |tx| tx. chain_position . is_unconfirmed ( ) ) ,
28
53
) ;
29
- while let Some ( block_event) = emitter. next_block ( ) ? {
30
- wallet. apply_block ( & block_event. block , block_event. block_height ( ) ) ?;
31
- }
32
54
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.
36
55
let wallet_addr = wallet. next_unused_address ( KeychainKind :: External ) . address ;
37
56
let remote_addr = env
38
57
. rpc_client ( )
39
58
. get_new_address ( None , None ) ?
40
- . assume_checked ( ) ;
41
- let incoming_txid = env. send ( & wallet_addr, Amount :: ONE_BTC ) ?;
59
+ . require_network ( Network :: Regtest ) ?;
42
60
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) ?;
46
66
assert_eq ! ( wallet. balance( ) . total( ) , Amount :: ONE_BTC ) ;
47
67
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
+ } ;
54
76
wallet. track_tx ( outgoing_tx. clone ( ) ) ;
55
77
assert_eq ! ( wallet. uncanonical_txs( ) . count( ) , 1 ) ;
56
78
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);
70
90
71
91
// 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) ?;
80
99
81
100
for uncanonical_tx in wallet. uncanonical_txs ( ) { }
82
101
0 commit comments