fix(wallet): include base tx overhead fee in manual coin selection target - #109
fix(wallet): include base tx overhead fee in manual coin selection target#109Tyagiquamar wants to merge 5 commits into
Conversation
…rget select_utxos_with_algorithm passed target_amount to BDK's coin_select unchanged. BDK only adds the per-input satisfaction fee on top of that target, not the fixed transaction overhead (recipient output + version/ locktime/varints). The transaction builder in send_to_address pays for the whole transaction, so a changeless BranchAndBound selection could be accepted by selection yet rejected by the builder as insufficient by the base-overhead fee. Inflate the selection target by the base-overhead fee so selection and the builder agree. Add a regression test exercising the invariant for the deterministic algorithms (BranchAndBound/LargestFirst/OldestFirst) plus an end-to-end test using send_to_address. Fixes synonymdev#104
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7eb66a4199
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
ovitrif
left a comment
There was a problem hiding this comment.
The manual-send precheck still rejects a valid low-fee selection returned by the new path. The existing P2TR/P2WSH coverage thread also remains unresolved.
Remove the min_fee_buffer heuristic (max(200 vB fee, 1000 sats)) that rejected manually selected UTXOs before the transaction builder ran. At 250 sat/kwu the changeless branch-and-bound match for a 35,000-sat target totals ~35,600 sats and was wrongly rejected below the 36,000-sat clamp. The builder now decides whether the exact selected inputs can fund the recipient plus the actual fee; a genuinely insufficient selection still fails with InsufficientFunds. Also pin selector/builder agreement for P2TR and P2WSH recipients (43 vB outputs, matching the conservative 224 WU base-overhead allowance).
ovitrif
left a comment
There was a problem hiding this comment.
The manual-send precheck issue is fixed. The new P2TR/P2WSH test still does not protect the 224-WU estimate: at 250 sat/kwu, both 188 WU and 224 WU select the same eight inputs totaling 35,600 sats, and the 43-byte-output transaction needs about 35,598 sats. Reverting BASE_TX_WEIGHT to 188 WU would leave this test green. Could we use a boundary fixture that fails with 188 WU and passes with 224 WU?
|
Good catch. The previous fixture didn't distinguish 188 WU from 224 WU. I replaced it with a boundary case where the lower allowance selects an insufficient set while 224 WU selects a builder-valid set (at 1,000 sat/kwu, 188 WU selects 10,470 sats which is insufficient for TxBuilder needing 10,486 sats for a 43-vB output, whereas 224 WU selects 10,970 sats which TxBuilder accepts). I also mutation-checked the regression: it fails when BASE_TX_WEIGHT is reverted to 188 WU and passes at 224 WU. \cargo test -p bdk-wallet-aggregate --lib\ passes. |
1a3f572 to
b375267
Compare
|
I rechecked
|
ovitrif
left a comment
There was a problem hiding this comment.
The replacement boundary fixture fixes the prior 224-WU coverage gap. The compile blockers already reported on the current head still prevent approval: #109 (comment)
|
Thanks — all five findings are addressed in
Verified: aggregate tests 45/45, strict aggregate Clippy, aggregate formatting, and |
|
@Tyagiquamar Please merge master in and push or rebase on master's tip and force-push |
Problem
select_utxos_with_algorithmpassedtarget_amountto BDK'scoin_selectunchanged. BDK's coin selection only adds the per-input satisfaction fee on top of that target — it does not account for the fixed transaction overhead (the recipient output plus version/marker/flag/varints/locktime). The transaction builder used bysend_to_address, however, pays for the entire transaction.As a result, a changeless BranchAndBound selection could be accepted by
select_utxos_with_algorithmyet rejected bysend_to_addressasInsufficientFunds— short by exactly the base-overhead fee. The library effectively said "these UTXOs are enough" and then "these same UTXOs are insufficient".Fixes #104.
Fix
Inflate the selection target by the fee for the fixed base-transaction overhead (
BASE_TX_WEIGHT, ~188 WU ≈ 47 vB) before callingcoin_select. The recipient-output size uses the conservative P2PKH size so the inflation is never too small for other script types. Selection and the builder now agree for the same target and fee rate.Tests
selected_utxos_satisfy_tx_builder_for_all_algorithmsbuilds the spend exactly like the manual-UTXO path ofbuild_transaction_psbtand asserts the builder accepts the selection for the deterministic algorithms (BranchAndBound, LargestFirst, OldestFirst). It failed before the fix withInsufficientFunds { needed: 35722, available: 35700 }and passes after. SingleRandomDraw is omitted because its randomized selection can legitimately land on a dust-change rejection, making the test flaky.test_selected_utxos_are_accepted_by_send_to_addressreproduces the issue's wallet layout (18 P2WPKH UTXOs) against real chain infra and assertssend_to_addressaccepts the selection.cargo test -p bdk-wallet-aggregate --lib— 39 passed, 0 failed.cargo fmt --checkandcargo clippy -p bdk-wallet-aggregate --lib -- -D warningsboth clean.