coinselection: Track whether BnB completed
What changed, and why it matters
This commit changes how Bitcoin Core's coin-selection algorithm tracks whether it finished its search. Previously, the code created the result object after the loop, so it could not record whether the Branch-and-Bound (BnB) search hit its iteration limit or completed the full search. The patch moves the result object earlier and marks it 'completed' or 'not completed' inside the loop. This is a correctness/observability improvement for fee estimation and coin-selection diagnostics, not a direct fix for a remote exploit. It could matter for security indirectly: if BnB aborts early, the wallet may fall back to a less optimal selection, possibly paying higher fees or creating larger change, but there is no evidence in the commit of a vulnerability being disclosed or exploited.
Treat as a routine correctness improvement. Review whether downstream callers of SelectionResult::GetAlgoCompleted (or equivalent) handle the 'not completed' case appropriately, especially for fee-bump and privacy-sensitive transactions. No urgent security patch is indicated by this commit alone.
Security signals we found
No explicit security relevance stated in commit title or message
No CVE, advisory, or researcher attribution in commit
Change is observability/correctness: tracking algorithm completion state
Potential indirect security relevance: incomplete BnB search can lead to suboptimal UTXO selection, higher fees, or privacy-affecting change outputs
No memory safety, cryptographic, or network-layer changes
Evidence from the diff
In SelectCoinsBnB, the SelectionResult was instantiated after the search loop, so the algorithm had no way to communicate whether the search terminated because curr_try reached TOTAL_TRIES or because the selection space was exhausted. The patch instantiates result at loop entry and calls SetAlgoCompleted(false) on the iteration-limit break and SetAlgoCompleted(true) on the exhausted-search-space break. This exposes BnB completion state to downstream coin-selection logic/fee estimation. The change is small (+3/-1), localized to src/wallet/coinselection.cpp, and does not alter the search algorithm itself.
Changed components
src/wallet/coinselection.cppSelectCoinsBnBSelectionResultInspect captured patch +3 / −1
diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp
index 6755376f..e671c3d0 100644
--- a/src/wallet/coinselection.cpp
+++ b/src/wallet/coinselection.cpp
@@ -131,6 +131,7 @@ util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool
};
size_t curr_try = 0;
+ SelectionResult result(selection_target, SelectionAlgorithm::BNB);
while (true) {
bool should_shift{false}, should_cut{false};
// Select `next_utxo`
@@ -166,6 +167,7 @@ util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool
if (curr_try >= TOTAL_TRIES) {
// Solution is not guaranteed to be optimal if `curr_try` hit TOTAL_TRIES
+ result.SetAlgoCompleted(false);
break;
}
@@ -185,6 +187,7 @@ util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool
if (should_shift) {
if (curr_selection.empty()) {
// Exhausted search space before running into attempt limit
+ result.SetAlgoCompleted(true);
break;
}
// Set `next_utxo` to one after last selected, then deselect last selected UTXO
@@ -193,7 +196,6 @@ util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool
}
}
- SelectionResult result(selection_target, SelectionAlgorithm::BNB);
result.SetSelectionsEvaluated(curr_try);
if (best_selection.empty()) {
Why this scored 26/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.