coinselection: Tiebreak SRD eviction by weight
What changed, and why it matters
This is a small improvement to how Bitcoin Core's wallet picks which coins to spend. When two coins are equally valuable for making a payment, the code now prefers the lighter-weight one, which saves on transaction fees. It is not a security fix and does not create a known vulnerability.
No security action required. Treat as a normal code-quality/fee-optimization improvement. Reviewers may verify the new unit test covers the intended tie-break behavior.
Security signals we found
No security-relevant signals in commit title or message
No mention of vulnerability, bug, exploit, or disclosure
Change is localized to wallet coin-selection comparator
No consensus, P2P, or cryptographic code modified
Evidence from the diff
The commit changes the eviction tie-breaker in the Single Random Draw (SRD) coin-selection algorithm. Previously, when two OutputGroups had the same effective value, the comparator used only GetSelectionAmount(). Now it uses descending_effval_weight(), which first compares effective value and then, if tied, keeps the lower-weight UTXO. A unit test is added to verify the tie-break behavior. This is an optimization/fee-reduction change, not a consensus or cryptography change.
Changed components
src/wallet/coinselection.cppsrc/wallet/test/coinselection_tests.cppInspect captured patch +8 / −1
diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp
index d6ea6851..1b569abd 100644
--- a/src/wallet/coinselection.cpp
+++ b/src/wallet/coinselection.cpp
@@ -529,7 +529,7 @@ class MinOutputGroupComparator
public:
int operator() (const OutputGroup& group1, const OutputGroup& group2) const
{
- return group1.GetSelectionAmount() > group2.GetSelectionAmount();
+ return descending_effval_weight(group1, group2);
}
};
diff --git a/src/wallet/test/coinselection_tests.cpp b/src/wallet/test/coinselection_tests.cpp
index 6e60af1c..68969b6a 100644
--- a/src/wallet/test/coinselection_tests.cpp
+++ b/src/wallet/test/coinselection_tests.cpp
@@ -283,6 +283,13 @@ BOOST_AUTO_TEST_CASE(srd_test)
AddDuplicateCoins(utxo_pool, /*count=*/3, /*amount=*/7 * CENT, cs_params);
TestSRDSuccess("Select most valuable UTXOs for acceptable weight", utxo_pool, /*selection_target=*/20 * CENT, cs_params, /*max_selection_weight=*/4 * 4 * (P2WPKH_INPUT_VSIZE - 1 ));
TestSRDFail("No acceptable weight possible", utxo_pool, /*selection_target=*/25 * CENT, cs_params, /*max_selection_weight=*/4 * 3 * P2WPKH_INPUT_VSIZE, /*expect_max_weight_exceeded=*/true);
+
+ // Create UTXO pool with UTXOs of same effective value but different weights
+ std::vector<OutputGroup> mixed_weight_pool;
+ AddDuplicateCoins(mixed_weight_pool, /*count=*/100, /*amount=*/5 * CENT, cs_params);
+ mixed_weight_pool.push_back(MakeCoin(5 * CENT, true, cs_params, /*custom_spending_vsize=*/P2WPKH_INPUT_VSIZE - 1));
+ TestSRDSuccess("Tie-break same effective value with lower weight", utxo_pool, /*selection_target=*/9 * CENT, cs_params,
+ /*max_selection_weight=*/4 * 3 * (P2WPKH_INPUT_VSIZE - 1));
}
}
Why this scored 19/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.