Skip to content

Fix(wallet): validate absolute fee bump replacements - #566

Open
Jennycj wants to merge 3 commits into
bitcoindevkit:masterfrom
Jennycj:fix/txbuilder-absolute-fee-bump-checks
Open

Jennycj wants to merge 3 commits into
bitcoindevkit:masterfrom
Jennycj:fix/txbuilder-absolute-fee-bump-checks

Conversation

@Jennycj

@Jennycj Jennycj commented Sep 17, 2026

Copy link
Copy Markdown

Fixes issue #549

Description

Previously, Wallet::create_tx only checks fee < previous_fee.absolute when bumping a fee with TxBuilder::fee_absolute. This misses out on 2 arms of the FeePolicy::FeeRate arm, causing transactions to be built without error, but then be rejected by BIP125 replacement policy (rule 4: must pay for its own bandwidth at the incremental relay fee; Bitcoin Core additionally requires a higher fee rate than the original).

Wallet::create_tx now:

  • Rejects an absolute replacement fee that is less than or equal to the original transaction fee.
  • Calculates the replacement’s effective fee rate after coin selection and final transaction weight are known.
  • Rejects absolute fee replacements whose fee rate is below the original fee rate plus FeeRate::BROADCAST_MIN.

This ensures that the appropriate fee error is returned when TxBuilder::fee_absolute attempts to build replacement transactions that do not satisfy the required absolute fee and incremental relay fee rules

Notes to the reviewers

The selected fee_policy is retained so absolute-fee replacements can be validated after coin selection. The final transaction weight is used to ensure the replacement fee rate exceeds the original fee rate by the required incremental relay fee.

Appropriate regression tests were added, and the absolute-fee values were updated in tests:

  • test_bump_fee_reduce_change
  • test_bump_fee_absolute_force_add_input

These fixtures previously passed the absolute-fee-only check but no longer satisfy the final replacement fee-rate requirement.

Changelog notice

Wallet::create_tx enforces a strictly higher replacement fee and validates the final replacement fee rate after coin selection.

Before submitting

Require replacement transactions to pay a strictly higher absolute fee and meet the required replacement fee rate after coin selection.
Raise absolute fee values used by fee bump tests to satisfy the updated replacement fee-rate requirement

@busayo-OD busayo-OD left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this! There are a few things around the fee validation logic that I wanted to mention.

Comment thread src/wallet/mod.rs
}
}

if matches!(fee_policy, FeePolicy::FeeAmount(_)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This FeeAmount check appears twice consecutively. The duplicate block can be removed.

Comment thread src/wallet/mod.rs

if matches!(fee_policy, FeePolicy::FeeAmount(_)) {
if let Some(previous_fee) = params.bumping_fee {
let required_feerate = FeeRate::from_sat_per_kwu(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This enforces a fee-rate floor (previous_rate + 1 sat/vB) rather than the BIP125 fee requirements. These differ when the replacement's weight changes, so the resulting minimum fee can be either higher or lower than the BIP125 requirement.

Comment thread src/wallet/mod.rs

if matches!(fee_policy, FeePolicy::FeeAmount(_)) {
if let Some(previous_fee) = params.bumping_fee {
let required_feerate = FeeRate::from_sat_per_kwu(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m wondering if this should use the final realized fee instead of the requested fee_amount, since dust handling can add excess to the actual fee.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants