Skip to content

fix(key-wallet): rewrite branch-and-bound coin selection (#918) - #919

Merged
xdustinface merged 1 commit into
devfrom
fix/bnb-coin-selection-918
Jul 30, 2026
Merged

fix(key-wallet): rewrite branch-and-bound coin selection (#918)#919
xdustinface merged 1 commit into
devfrom
fix/bnb-coin-selection-918

Conversation

@ZocoLini

@ZocoLini ZocoLini commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

BranchAndBound only pruned branches that overshot the target, so a target near
the total balance — where almost nothing overshoots — degenerated into an
exhaustive 2^N walk: ~3s at 22 UTXOs, non-terminating past 32.

Rewrite the search in effective values (each UTXO net of the fee to spend it),
which makes the acceptance test independent of how many inputs are chosen:

  • Bound on feasibility as well as overshoot: a branch that cannot reach the
    target even taking every UTXO left is abandoned. Node budget as a backstop.
  • Accept anything within cost_of_change of the target, keeping the lowest
    surplus, instead of demanding the exact satoshi — a near-exact match avoids
    a change output, which is the whole point of the strategy.
  • Fee is no longer sized from a guessed input count, fixing an off-by-one that
    made an exact match overpay one input's worth of fee.

Closes #918

Summary by CodeRabbit

  • Bug Fixes
    • Improved coin selection accuracy by factoring per-input spending costs into the search for an exact no-change payment.
    • Reduced unnecessary or uneconomical inputs and tightened acceptance rules to better match target amounts within the allowed cost-of-change window.
    • Added additional validation using the final computed transaction fee to ensure selections remain correct after fee rounding.
    • Ensured the Branch-and-Bound search remains bounded for more consistent performance.
  • Tests
    • Expanded unit coverage for exact-match, near-exact surplus handling, skipping uneconomical inputs, and bounded search scenarios.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

The coin-selection API now assumes TX_INPUT_SIZE. Branch-and-Bound uses bounded effective-value search for no-change selections, validates the final transaction fee, and includes tests for surplus handling, uneconomic inputs, and search bounds.

Branch-and-Bound coin selection

Layer / File(s) Summary
Fixed input-size selection contract
key-wallet/src/wallet/managed_wallet_info/coin_selection.rs, key-wallet/src/wallet/managed_wallet_info/transaction_builder.rs
Removes the input_size argument from coin-selection APIs and standardizes sizing and fee calculations on TX_INPUT_SIZE.
Bounded effective-value search
key-wallet/src/wallet/managed_wallet_info/coin_selection.rs
Replaces recursive exact matching with effective-value candidates, suffix feasibility pruning, surplus windows, a node budget, and final real-fee validation.
BnB behavior validation
key-wallet/src/wallet/managed_wallet_info/coin_selection.rs
Tests exact matches, surplus and change-cost behavior, uneconomic inputs, updated calls, and bounded searches.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related issues

Possibly related PRs

Suggested labels: ready-for-review

Suggested reviewers: xdustinface

Sequence Diagram(s)

sequenceDiagram
  participant TransactionBuilder
  participant CoinSelector
  participant BnbSearch
  participant FeeCalculation
  TransactionBuilder->>CoinSelector: request selection with fixed TX_INPUT_SIZE
  CoinSelector->>FeeCalculation: calculate no-change effective target
  CoinSelector->>BnbSearch: search effective-value candidates
  BnbSearch-->>CoinSelector: return bounded best-surplus selection
  CoinSelector->>FeeCalculation: re-check actual transaction fee
  CoinSelector-->>TransactionBuilder: return zero-change SelectionResult
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly reflects the main change: a rewrite of key-wallet's branch-and-bound coin selection.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/bnb-coin-selection-918

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@key-wallet/src/wallet/managed_wallet_info/coin_selection.rs`:
- Around line 1185-1198: The tests
test_branch_and_bound_near_total_target_is_bounded and
test_branch_and_bound_mid_range_target_is_bounded should rely on a deterministic
BnbSearch node-budget or visited-node count, asserting it does not exceed
BNB_NODE_BUDGET. Replace the strict one-second correctness gate with that
deterministic assertion, retaining only a sufficiently generous timing check as
an optional smoke bound.
- Around line 507-529: Update the BnB selection flow rooted at
branch_and_bound_with_size to propagate the caller-provided input_size through
branch_and_bound and its estimated-size calculations, replacing hardcoded
TX_INPUT_SIZE usage. Also pass the caller’s change_output_size into
cost_of_change, and ensure the resulting SelectionResult fee and size
calculations match the accumulate fallback for custom per-input sizes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c4cbcf35-7b77-40c1-948f-e20abd71e615

📥 Commits

Reviewing files that changed from the base of the PR and between 9c87ccb and 9117d29.

📒 Files selected for processing (1)
  • key-wallet/src/wallet/managed_wallet_info/coin_selection.rs

Comment thread key-wallet/src/wallet/managed_wallet_info/coin_selection.rs Outdated
Comment thread key-wallet/src/wallet/managed_wallet_info/coin_selection.rs
@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.54338% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 74.81%. Comparing base (9c87ccb) to head (7a5a07f).

Files with missing lines Patch % Lines
...t/src/wallet/managed_wallet_info/coin_selection.rs 99.54% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              dev     #919      +/-   ##
==========================================
+ Coverage   74.67%   74.81%   +0.13%     
==========================================
  Files         328      328              
  Lines       76451    76593     +142     
==========================================
+ Hits        57093    57302     +209     
+ Misses      19358    19291      -67     
Flag Coverage Δ
core 77.29% <ø> (ø)
ffi 49.71% <ø> (+0.48%) ⬆️
rpc 20.00% <ø> (ø)
spv 91.15% <ø> (+0.01%) ⬆️
wallet 75.69% <99.54%> (+0.23%) ⬆️
Files with missing lines Coverage Δ
.../wallet/managed_wallet_info/transaction_builder.rs 87.05% <ø> (ø)
...t/src/wallet/managed_wallet_info/coin_selection.rs 93.95% <99.54%> (+4.40%) ⬆️

... and 19 files with indirect coverage changes

@ZocoLini
ZocoLini force-pushed the fix/bnb-coin-selection-918 branch 2 times, most recently from b2b7684 to eb5528d Compare July 29, 2026 15:04

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
key-wallet/src/wallet/managed_wallet_info/coin_selection.rs (1)

451-463: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Stale doc comment on branch_and_bound_with_size.

The doc comment still describes the old design ("Recursively explores combinations looking for exact matches", "Prunes branches that exceed the target by too much") rather than the new no-change/effective-value search with a cost_of_change acceptance window implemented below. Worth updating to avoid misleading future readers.

📝 Suggested doc update
-    /// Branch and bound coin selection with custom sizes (finds exact match if possible)
+    /// Branch and bound coin selection with custom sizes (finds a no-change selection if possible)
     ///
     /// This algorithm:
-    /// - Sorts UTXOs by value descending (largest first)
-    /// - Recursively explores combinations looking for exact matches
-    /// - Prunes branches that exceed the target by too much
+    /// - Sorts UTXOs by value descending (largest first)
+    /// - Depth-first searches subsets using effective values, accepting a surplus within
+    ///   `cost_of_change` of the target (an exact match is just the zero-surplus case)
+    /// - Prunes branches that overshoot the acceptance window or cannot reach the target
     /// - Falls back to simple accumulation if no exact match found
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@key-wallet/src/wallet/managed_wallet_info/coin_selection.rs` around lines 451
- 463, Update the doc comment for branch_and_bound_with_size to describe the
current no-change/effective-value search and its cost_of_change acceptance
window, removing claims about the obsolete recursive exact-match and
oversized-target pruning behavior. Keep the documented trade-offs aligned with
the implementation below.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@key-wallet/src/wallet/managed_wallet_info/coin_selection.rs`:
- Around line 1147-1166: The test_branch_and_bound_mid_range_target_is_bounded
test needs a deterministic assertion that the search respects its node budget
instead of relying only on elapsed time. Add node-count instrumentation or the
existing budget-tracking mechanism, mirroring
test_feasibility_bound_settles_a_near_total_target_in_few_nodes, and assert the
count stays within the configured limit of 200; retain the current 30-second
timing check only as a generous smoke bound.

---

Nitpick comments:
In `@key-wallet/src/wallet/managed_wallet_info/coin_selection.rs`:
- Around line 451-463: Update the doc comment for branch_and_bound_with_size to
describe the current no-change/effective-value search and its cost_of_change
acceptance window, removing claims about the obsolete recursive exact-match and
oversized-target pruning behavior. Keep the documented trade-offs aligned with
the implementation below.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d1b5e31d-9d50-4b68-862e-ab8015543dea

📥 Commits

Reviewing files that changed from the base of the PR and between 9117d29 and eb5528d.

📒 Files selected for processing (2)
  • key-wallet/src/wallet/managed_wallet_info/coin_selection.rs
  • key-wallet/src/wallet/managed_wallet_info/transaction_builder.rs

Comment thread key-wallet/src/wallet/managed_wallet_info/coin_selection.rs
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 29, 2026
@github-actions github-actions Bot added the ready-for-review CodeRabbit has approved this PR label Jul 29, 2026
@ZocoLini
ZocoLini requested a review from xdustinface July 30, 2026 07:19
@xdustinface
xdustinface merged commit 9cbe4e7 into dev Jul 30, 2026
40 of 41 checks passed
@xdustinface
xdustinface deleted the fix/bnb-coin-selection-918 branch July 30, 2026 16:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-review CodeRabbit has approved this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

key-wallet: BranchAndBound coin selection is exponential for near-total-balance targets (find_exact_match missing feasibility prune)

2 participants