11use anyhow:: Ok ;
22use bdk_esplora:: { esplora_client, EsploraAsyncExt } ;
33use bdk_wallet:: {
4- bitcoin:: { Amount , Network , Txid } ,
4+ bitcoin:: { Amount , FeeRate , Network } ,
5+ psbt:: PsbtUtils ,
56 rusqlite:: Connection ,
67 KeychainKind , SignOptions , Wallet ,
78} ;
8- use std:: {
9- collections:: { BTreeSet , HashSet } ,
10- io:: Write ,
11- } ;
9+ use std:: { collections:: BTreeSet , io:: Write } ;
1210
1311const SEND_AMOUNT : Amount = Amount :: from_sat ( 5000 ) ;
1412const STOP_GAP : usize = 5 ;
@@ -23,7 +21,6 @@ const ESPLORA_URL: &str = "http://signet.bitcoindevkit.net";
2321#[ tokio:: main]
2422async fn main ( ) -> Result < ( ) , anyhow:: Error > {
2523 let mut conn = Connection :: open ( DB_PATH ) ?;
26-
2724 let wallet_opt = Wallet :: load ( )
2825 . descriptor ( KeychainKind :: External , Some ( EXTERNAL_DESC ) )
2926 . descriptor ( KeychainKind :: Internal , Some ( INTERNAL_DESC ) )
@@ -39,12 +36,12 @@ async fn main() -> Result<(), anyhow::Error> {
3936
4037 let address = wallet. next_unused_address ( KeychainKind :: External ) ;
4138 wallet. persist ( & mut conn) ?;
42- println ! ( "Next unused address: ({}) {}" , address. index, address ) ;
39+ println ! ( "Next unused address: ({}) {address }" , address. index) ;
4340
4441 let balance = wallet. balance ( ) ;
4542 println ! ( "Wallet balance before syncing: {}" , balance. total( ) ) ;
4643
47- println ! ( "=== Performing Full Sync === " ) ;
44+ println ! ( "Full Sync... " ) ;
4845 let client = esplora_client:: Builder :: new ( ESPLORA_URL ) . build_async ( ) ?;
4946
5047 let request = wallet. start_full_scan ( ) . inspect ( {
@@ -54,7 +51,9 @@ async fn main() -> Result<(), anyhow::Error> {
5451 if once. insert ( keychain) {
5552 print ! ( "\n Scanning keychain [{keychain:?}]" ) ;
5653 }
57- print ! ( " {spk_i:<3}" ) ;
54+ if spk_i. is_multiple_of ( 5 ) {
55+ print ! ( " {spk_i:<3}" ) ;
56+ }
5857 stdout. flush ( ) . expect ( "must flush" )
5958 }
6059 } ) ;
@@ -79,27 +78,22 @@ async fn main() -> Result<(), anyhow::Error> {
7978 println ! ( "Please send at least {SEND_AMOUNT} to the receiving address" ) ;
8079 std:: process:: exit ( 0 ) ;
8180 }
82-
8381 let mut tx_builder = wallet. build_tx ( ) ;
8482 tx_builder. add_recipient ( address. script_pubkey ( ) , SEND_AMOUNT ) ;
8583
8684 let mut psbt = tx_builder. finish ( ) ?;
8785 let finalized = wallet. sign ( & mut psbt, SignOptions :: default ( ) ) ?;
8886 assert ! ( finalized) ;
89-
87+ let original_fee = psbt. fee_amount ( ) . unwrap ( ) ;
88+ let tx_feerate = psbt. fee_rate ( ) . unwrap ( ) ;
9089 let tx = psbt. extract_tx ( ) ?;
9190 client. broadcast ( & tx) . await ?;
92- println ! ( "Tx broadcasted! Txid: {}" , tx. compute_txid( ) ) ;
93-
94- let unconfirmed_txids: HashSet < Txid > = wallet
95- . transactions ( )
96- . filter ( |tx| tx. chain_position . is_unconfirmed ( ) )
97- . map ( |tx| tx. tx_node . txid )
98- . collect ( ) ;
91+ let txid = tx. compute_txid ( ) ;
92+ println ! ( "Tx broadcasted! Txid: {txid}" ) ;
9993
100- println ! ( "\n === Performing Partial Sync === \n " ) ;
94+ println ! ( "Partial Sync... " ) ;
10195 print ! ( "SCANNING: " ) ;
102- let mut printed = 0 ;
96+ let mut printed: u32 = 0 ;
10397 let sync_request = wallet
10498 . start_sync_with_revealed_spks ( )
10599 . inspect ( move |_, sync_progress| {
@@ -114,30 +108,63 @@ async fn main() -> Result<(), anyhow::Error> {
114108 } ) ;
115109 let sync_update = client. sync ( sync_request, PARALLEL_REQUESTS ) . await ?;
116110 println ! ( ) ;
111+ wallet. apply_update ( sync_update) ?;
112+ wallet. persist ( & mut conn) ?;
117113
118- let mut evicted_txs = Vec :: new ( ) ;
119- for txid in unconfirmed_txids {
120- let tx_node = wallet
121- . tx_graph ( )
122- . full_txs ( )
123- . find ( |full_tx| full_tx. txid == txid) ;
124- let wallet_tx = wallet. get_tx ( txid) ;
125-
126- let is_evicted = match wallet_tx {
127- Some ( wallet_tx) => {
128- !wallet_tx. chain_position . is_unconfirmed ( )
129- && !wallet_tx. chain_position . is_confirmed ( )
130- }
131- None => true ,
132- } ;
133-
134- if is_evicted {
135- if let Some ( full_tx) = tx_node {
136- evicted_txs. push ( ( full_tx. txid , full_tx. last_seen . unwrap_or ( 0 ) ) ) ;
137- } else {
138- evicted_txs. push ( ( txid, 0 ) ) ;
114+ let feerate = FeeRate :: from_sat_per_kwu ( tx_feerate. to_sat_per_kwu ( ) + 250 ) ;
115+ let mut builder = wallet. build_fee_bump ( txid) . expect ( "failed to bump tx" ) ;
116+ builder. fee_rate ( feerate) ;
117+ let mut bumped_psbt = builder. finish ( ) . unwrap ( ) ;
118+ let finalize_btx = wallet. sign ( & mut bumped_psbt, SignOptions :: default ( ) ) ?;
119+ assert ! ( finalize_btx) ;
120+ let new_fee = bumped_psbt. fee_amount ( ) . unwrap ( ) ;
121+ let bumped_tx = bumped_psbt. extract_tx ( ) ?;
122+ assert_eq ! (
123+ bumped_tx
124+ . output
125+ . iter( )
126+ . find( |txout| txout. script_pubkey == address. script_pubkey( ) )
127+ . unwrap( )
128+ . value,
129+ SEND_AMOUNT ,
130+ "Outputs should be the same"
131+ ) ;
132+ assert ! (
133+ new_fee > original_fee,
134+ "New fee ({new_fee}) should be higher than original ({original_fee})" ,
135+ ) ;
136+ client. broadcast ( & bumped_tx) . await ?;
137+ println ! ( "Broadcasted bumped tx. Txid: {}" , bumped_tx. compute_txid( ) ) ;
138+
139+ println ! ( "syncing after broadcasting bumped tx..." ) ;
140+ print ! ( "SCANNING: " ) ;
141+ let sync_request = wallet
142+ . start_sync_with_revealed_spks ( )
143+ . inspect ( move |_, sync_progress| {
144+ let progress_percent =
145+ ( 100 * sync_progress. consumed ( ) ) as f32 / sync_progress. total ( ) as f32 ;
146+ let progress_percent = progress_percent. round ( ) as u32 ;
147+ if progress_percent. is_multiple_of ( 10 ) && progress_percent > printed {
148+ print ! ( "{progress_percent}% " ) ;
149+ std:: io:: stdout ( ) . flush ( ) . expect ( "must flush" ) ;
150+ printed = progress_percent;
139151 }
140- }
152+ } ) ;
153+ let sync_update = client. sync ( sync_request, PARALLEL_REQUESTS ) . await ?;
154+ println ! ( ) ;
155+
156+ let mut evicted_txs = Vec :: new ( ) ;
157+
158+ let last_seen = wallet
159+ . tx_graph ( )
160+ . full_txs ( )
161+ . find ( |full_tx| full_tx. txid == txid)
162+ . map_or ( 0 , |full_tx| full_tx. last_seen . unwrap_or ( 0 ) ) ;
163+ if !evicted_txs
164+ . iter ( )
165+ . any ( |( evicted_txid, _) | evicted_txid == & txid)
166+ {
167+ evicted_txs. push ( ( txid, last_seen) ) ;
141168 }
142169
143170 if !evicted_txs. is_empty ( ) {
0 commit comments