Skip to content

Commit a86a73e

Browse files
committed
Minor adjustment to fee rate handling in RBF fee bumping
Use user-provided fee rate for bumping transaction and return an error if it is too low, otherwise use system estimated fee rate and retry mechanism. Also switches the RBF test to use `random_chain_source`, and removes unnecessary sleep-based waits.
1 parent 2f5a966 commit a86a73e

File tree

2 files changed

+48
-43
lines changed

2 files changed

+48
-43
lines changed

src/wallet/mod.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -378,8 +378,8 @@ impl Wallet {
378378
);
379379
let payment =
380380
self.payment_store.get(&payment_id).ok_or(Error::InvalidPaymentId)?;
381-
let pending_payment_details = self
382-
.create_pending_payment_from_tx(payment.clone(), conflict_txids.clone());
381+
let pending_payment_details =
382+
self.create_pending_payment_from_tx(payment, conflict_txids.clone());
383383

384384
self.pending_payment_store.insert_or_update(pending_payment_details)?;
385385
},
@@ -1042,6 +1042,16 @@ impl Wallet {
10421042
return Some(direct_payment_id);
10431043
}
10441044

1045+
if let Some(replaced_details) = self
1046+
.pending_payment_store
1047+
.list_filter(
1048+
|p| matches!(p.details.kind, PaymentKind::Onchain { txid, .. } if txid == target_txid),
1049+
)
1050+
.first()
1051+
{
1052+
return Some(replaced_details.details.id);
1053+
}
1054+
10451055
if let Some(replaced_details) = self
10461056
.pending_payment_store
10471057
.list_filter(|p| p.conflicting_txids.contains(&target_txid))
@@ -1125,13 +1135,13 @@ impl Wallet {
11251135
old_fee_rate.to_sat_per_kwu() + INCREMENTAL_RELAY_FEE_SAT_PER_1000_WEIGHT as u64;
11261136

11271137
let confirmation_target = ConfirmationTarget::OnchainPayment;
1128-
let estimated_fee_rate =
1129-
fee_rate.unwrap_or_else(|| self.fee_estimator.estimate_fee_rate(confirmation_target));
1138+
let estimated_fee_rate = self.fee_estimator.estimate_fee_rate(confirmation_target);
11301139

11311140
// Use the higher of minimum RBF requirement or current network estimate
11321141
let final_fee_rate_sat_per_kwu =
11331142
min_required_fee_rate_sat_per_kwu.max(estimated_fee_rate.to_sat_per_kwu());
1134-
let final_fee_rate = FeeRate::from_sat_per_kwu(final_fee_rate_sat_per_kwu);
1143+
let final_fee_rate =
1144+
fee_rate.unwrap_or_else(|| FeeRate::from_sat_per_kwu(final_fee_rate_sat_per_kwu));
11351145

11361146
let mut psbt = {
11371147
let mut builder = locked_wallet.build_fee_bump(txid).map_err(|e| {
@@ -1156,6 +1166,17 @@ impl Wallet {
11561166
match builder.finish() {
11571167
Ok(psbt) => Ok(psbt),
11581168
Err(CreateTxError::FeeRateTooLow { required: required_fee_rate }) => {
1169+
if fee_rate.is_some() {
1170+
log_error!(
1171+
self.logger,
1172+
"Provided fee rate {} is too low for RBF fee bump of txid {}, required minimum fee rate: {}",
1173+
fee_rate.unwrap(),
1174+
txid,
1175+
required_fee_rate
1176+
);
1177+
return Err(Error::InvalidFeeRate);
1178+
}
1179+
11591180
log_info!(self.logger, "BDK requires higher fee rate: {}", required_fee_rate);
11601181

11611182
// BDK may require a higher fee rate than our estimate due to

tests/integration_tests_rust.rs

Lines changed: 22 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2466,7 +2466,7 @@ async fn persistence_backwards_compatibility() {
24662466
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
24672467
async fn onchain_fee_bump_rbf() {
24682468
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
2469-
let chain_source = TestChainSource::Esplora(&electrsd);
2469+
let chain_source = random_chain_source(&bitcoind, &electrsd);
24702470
let (node_a, node_b) = setup_two_nodes(&chain_source, false, true, false);
24712471

24722472
// Fund both nodes
@@ -2490,6 +2490,10 @@ async fn onchain_fee_bump_rbf() {
24902490
let txid =
24912491
node_b.onchain_payment().send_to_address(&addr_a, amount_to_send_sats, None).unwrap();
24922492
wait_for_tx(&electrsd.client, txid).await;
2493+
// Give the chain source time to index the unconfirmed transaction before syncing.
2494+
// Without this, Esplora may not yet have the tx, causing sync to miss it and
2495+
// leaving the BDK wallet graph empty.
2496+
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
24932497
node_a.sync_wallets().unwrap();
24942498
node_b.sync_wallets().unwrap();
24952499

@@ -2515,10 +2519,10 @@ async fn onchain_fee_bump_rbf() {
25152519
// Successful fee bump
25162520
let new_txid = node_b.onchain_payment().bump_fee_rbf(payment_id, None).unwrap();
25172521
wait_for_tx(&electrsd.client, new_txid).await;
2518-
2519-
// Sleep to allow for transaction propagation
2520-
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
2521-
2522+
// Give the chain source time to index the unconfirmed transaction before syncing.
2523+
// Without this, Esplora may not yet have the tx, causing sync to miss it and
2524+
// leaving the BDK wallet graph empty.
2525+
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
25222526
node_a.sync_wallets().unwrap();
25232527
node_b.sync_wallets().unwrap();
25242528

@@ -2540,26 +2544,9 @@ async fn onchain_fee_bump_rbf() {
25402544
_ => panic!("Unexpected payment kind"),
25412545
}
25422546

2543-
// Verify node_a has the inbound payment txid updated to the replacement txid
2544-
let node_a_inbound_payment = node_a.payment(&payment_id).unwrap();
2545-
assert_eq!(node_a_inbound_payment.direction, PaymentDirection::Inbound);
2546-
match &node_a_inbound_payment.kind {
2547-
PaymentKind::Onchain { txid: inbound_txid, .. } => {
2548-
assert_eq!(
2549-
*inbound_txid, new_txid,
2550-
"node_a inbound payment txid should be updated to the replacement txid"
2551-
);
2552-
},
2553-
_ => panic!("Unexpected payment kind"),
2554-
}
2555-
25562547
// Multiple consecutive bumps
25572548
let second_bump_txid = node_b.onchain_payment().bump_fee_rbf(payment_id, None).unwrap();
25582549
wait_for_tx(&electrsd.client, second_bump_txid).await;
2559-
2560-
// Sleep to allow for transaction propagation
2561-
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
2562-
25632550
node_a.sync_wallets().unwrap();
25642551
node_b.sync_wallets().unwrap();
25652552

@@ -2579,19 +2566,6 @@ async fn onchain_fee_bump_rbf() {
25792566
_ => panic!("Unexpected payment kind"),
25802567
}
25812568

2582-
// Verify node_a has the inbound payment txid updated to the second replacement txid
2583-
let node_a_second_inbound_payment = node_a.payment(&payment_id).unwrap();
2584-
assert_eq!(node_a_second_inbound_payment.direction, PaymentDirection::Inbound);
2585-
match &node_a_second_inbound_payment.kind {
2586-
PaymentKind::Onchain { txid: inbound_txid, .. } => {
2587-
assert_eq!(
2588-
*inbound_txid, second_bump_txid,
2589-
"node_a inbound payment txid should be updated to the second replacement txid"
2590-
);
2591-
},
2592-
_ => panic!("Unexpected payment kind"),
2593-
}
2594-
25952569
// Confirm the transaction and try to bump again (should fail)
25962570
generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await;
25972571
node_a.sync_wallets().unwrap();
@@ -2613,10 +2587,20 @@ async fn onchain_fee_bump_rbf() {
26132587
}
26142588

26152589
// Verify node A received the funds correctly
2616-
let node_a_received_payment = node_a.list_payments_with_filter(
2617-
|p| matches!(p.kind, PaymentKind::Onchain { txid, .. } if txid == second_bump_txid),
2618-
);
2590+
let node_a_received_payment = node_a.list_payments_with_filter(|p| {
2591+
p.id == payment_id && matches!(p.kind, PaymentKind::Onchain { .. })
2592+
});
2593+
26192594
assert_eq!(node_a_received_payment.len(), 1);
2595+
match &node_a_received_payment[0].kind {
2596+
PaymentKind::Onchain { txid: inbound_txid, .. } => {
2597+
assert_eq!(
2598+
*inbound_txid, second_bump_txid,
2599+
"node_a inbound payment txid should be updated to the second replacement txid"
2600+
);
2601+
},
2602+
_ => panic!("Unexpected payment kind"),
2603+
}
26202604
assert_eq!(node_a_received_payment[0].amount_msat, Some(amount_to_send_sats * 1000));
26212605
assert_eq!(node_a_received_payment[0].status, PaymentStatus::Succeeded);
26222606
}

0 commit comments

Comments
 (0)