Skip to content

Commit de26eb0

Browse files
committed
Do both BnB and Knapsack coin selection in SelectCoinsMinConf
Instead of switching which algorithm to use based on use_bnb, just run both in SelectCoinsMinConf. If BnB fails, do Knapsack.
1 parent 01dc8eb commit de26eb0

File tree

2 files changed

+21
-22
lines changed

2 files changed

+21
-22
lines changed

src/wallet/test/coinselector_tests.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -287,9 +287,9 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
287287
empty_wallet();
288288
add_coin(1 * CENT);
289289
vCoins.at(0).nInputBytes = 40;
290-
BOOST_CHECK(!testWallet.SelectCoinsMinConf( 1 * CENT, filter_standard, vCoins, setCoinsRet, nValueRet, coin_selection_params_bnb, bnb_used));
291290
coin_selection_params_bnb.m_subtract_fee_outputs = true;
292291
BOOST_CHECK(testWallet.SelectCoinsMinConf( 1 * CENT, filter_standard, vCoins, setCoinsRet, nValueRet, coin_selection_params_bnb, bnb_used));
292+
BOOST_CHECK(bnb_used);
293293
BOOST_CHECK_EQUAL(nValueRet, 1 * CENT);
294294

295295
// Make sure that can use BnB when there are preset inputs
@@ -549,17 +549,19 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
549549
for (int i = 0; i < RUN_TESTS; i++) {
550550
// picking 50 from 100 coins doesn't depend on the shuffle,
551551
// but does depend on randomness in the stochastic approximation code
552-
BOOST_CHECK(testWallet.SelectCoinsMinConf(50 * COIN, filter_standard, vCoins, setCoinsRet , nValueRet, coin_selection_params, bnb_used));
553-
BOOST_CHECK(testWallet.SelectCoinsMinConf(50 * COIN, filter_standard, vCoins, setCoinsRet2, nValueRet, coin_selection_params, bnb_used));
552+
BOOST_CHECK(KnapsackSolver(50 * COIN, GroupCoins(vCoins), setCoinsRet, nValueRet));
553+
BOOST_CHECK(KnapsackSolver(50 * COIN, GroupCoins(vCoins), setCoinsRet2, nValueRet));
554554
BOOST_CHECK(!equal_sets(setCoinsRet, setCoinsRet2));
555555

556556
int fails = 0;
557557
for (int j = 0; j < RANDOM_REPEATS; j++)
558558
{
559-
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
560-
// run the test RANDOM_REPEATS times and only complain if all of them fail
561-
BOOST_CHECK(testWallet.SelectCoinsMinConf(COIN, filter_standard, vCoins, setCoinsRet , nValueRet, coin_selection_params, bnb_used));
562-
BOOST_CHECK(testWallet.SelectCoinsMinConf(COIN, filter_standard, vCoins, setCoinsRet2, nValueRet, coin_selection_params, bnb_used));
559+
// Test that the KnapsackSolver selects randomly from equivalent coins (same value and same input size).
560+
// When choosing 1 from 100 identical coins, 1% of the time, this test will choose the same coin twice
561+
// which will cause it to fail.
562+
// To avoid that issue, run the test RANDOM_REPEATS times and only complain if all of them fail
563+
BOOST_CHECK(KnapsackSolver(COIN, GroupCoins(vCoins), setCoinsRet, nValueRet));
564+
BOOST_CHECK(KnapsackSolver(COIN, GroupCoins(vCoins), setCoinsRet2, nValueRet));
563565
if (equal_sets(setCoinsRet, setCoinsRet2))
564566
fails++;
565567
}
@@ -579,10 +581,8 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
579581
int fails = 0;
580582
for (int j = 0; j < RANDOM_REPEATS; j++)
581583
{
582-
// selecting 1 from 100 identical coins depends on the shuffle; this test will fail 1% of the time
583-
// run the test RANDOM_REPEATS times and only complain if all of them fail
584-
BOOST_CHECK(testWallet.SelectCoinsMinConf(90*CENT, filter_standard, vCoins, setCoinsRet , nValueRet, coin_selection_params, bnb_used));
585-
BOOST_CHECK(testWallet.SelectCoinsMinConf(90*CENT, filter_standard, vCoins, setCoinsRet2, nValueRet, coin_selection_params, bnb_used));
584+
BOOST_CHECK(KnapsackSolver(90*CENT, GroupCoins(vCoins), setCoinsRet, nValueRet));
585+
BOOST_CHECK(KnapsackSolver(90*CENT, GroupCoins(vCoins), setCoinsRet2, nValueRet));
586586
if (equal_sets(setCoinsRet, setCoinsRet2))
587587
fails++;
588588
}

src/wallet/wallet.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2406,19 +2406,18 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, const CoinEligibil
24062406
effective_feerate = coin_selection_params.m_effective_feerate;
24072407
}
24082408

2409-
if (coin_selection_params.use_bnb) {
2410-
std::vector<OutputGroup> positive_groups = GroupOutputs(coins, !coin_selection_params.m_avoid_partial_spends, effective_feerate, coin_selection_params.m_long_term_feerate, eligibility_filter, true /* positive_only */);
2409+
std::vector<OutputGroup> positive_groups = GroupOutputs(coins, !coin_selection_params.m_avoid_partial_spends, effective_feerate, coin_selection_params.m_long_term_feerate, eligibility_filter, true /* positive_only */);
2410+
// Note that unlike KnapsackSolver, we do not include the fee for creating a change output as BnB will not create a change output.
2411+
if (SelectCoinsBnB(positive_groups, nTargetValue, coin_selection_params.m_cost_of_change, setCoinsRet, nValueRet)) {
24112412
bnb_used = true;
2412-
// Note that unlike KnapsackSolver, we do not include the fee for creating a change output as BnB will not create a change output.
2413-
return SelectCoinsBnB(positive_groups, nTargetValue, coin_selection_params.m_cost_of_change, setCoinsRet, nValueRet);
2414-
} else {
2415-
// The knapsack solver has some legacy behavior where it will spend dust outputs. We retain this behavior, so don't filter for positive only here.
2416-
std::vector<OutputGroup> all_groups = GroupOutputs(coins, !coin_selection_params.m_avoid_partial_spends, effective_feerate, coin_selection_params.m_long_term_feerate, eligibility_filter, false /* positive_only */);
2417-
bnb_used = false;
2418-
// While nTargetValue includes the transaction fees for non-input things, it does not include the fee for creating a change output.
2419-
// So we need to include that for KnapsackSolver as well, as we are expecting to create a change output.
2420-
return KnapsackSolver(nTargetValue + coin_selection_params.m_change_fee, all_groups, setCoinsRet, nValueRet);
2413+
return true;
24212414
}
2415+
// The knapsack solver has some legacy behavior where it will spend dust outputs. We retain this behavior, so don't filter for positive only here.
2416+
std::vector<OutputGroup> all_groups = GroupOutputs(coins, !coin_selection_params.m_avoid_partial_spends, effective_feerate, coin_selection_params.m_long_term_feerate, eligibility_filter, false /* positive_only */);
2417+
bnb_used = false;
2418+
// While nTargetValue includes the transaction fees for non-input things, it does not include the fee for creating a change output.
2419+
// So we need to include that for KnapsackSolver as well, as we are expecting to create a change output.
2420+
return KnapsackSolver(nTargetValue + coin_selection_params.m_change_fee, all_groups, setCoinsRet, nValueRet);
24222421
}
24232422

24242423
bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CCoinControl& coin_control, CoinSelectionParams& coin_selection_params, bool& bnb_used) const

0 commit comments

Comments
 (0)