Skip to content

Commit 05e5ff1

Browse files
furszyachow101murchandamus
committed
test: add coverage for BnB-SFFO restriction
Verify the transaction creation process does not produce a BnB solution when SFFO is enabled. This is currently problematic because it could require a change output. And BnB is specialized on changeless solutions. Co-authored-by: Andrew Chow <achow101@gmail.com> Co-authored-by: Murch <murch@murch.one>
1 parent 0c57557 commit 05e5ff1

File tree

1 file changed

+38
-0
lines changed

1 file changed

+38
-0
lines changed

src/wallet/test/coinselector_tests.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,44 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
455455
}
456456
}
457457

458+
BOOST_AUTO_TEST_CASE(bnb_sffo_restriction)
459+
{
460+
// Verify the coin selection process does not produce a BnB solution when SFFO is enabled.
461+
// This is currently problematic because it could require a change output. And BnB is specialized on changeless solutions.
462+
std::unique_ptr<CWallet> wallet = NewWallet(m_node);
463+
WITH_LOCK(wallet->cs_wallet, wallet->SetLastBlockProcessed(300, uint256{})); // set a high block so internal UTXOs are selectable
464+
465+
FastRandomContext rand{};
466+
CoinSelectionParams params{
467+
rand,
468+
/*change_output_size=*/ 31, // unused value, p2wpkh output size (wallet default change type)
469+
/*change_spend_size=*/ 68, // unused value, p2wpkh input size (high-r signature)
470+
/*min_change_target=*/ 0, // dummy, set later
471+
/*effective_feerate=*/ CFeeRate(3000),
472+
/*long_term_feerate=*/ CFeeRate(1000),
473+
/*discard_feerate=*/ CFeeRate(1000),
474+
/*tx_noinputs_size=*/ 0,
475+
/*avoid_partial=*/ false,
476+
};
477+
params.m_subtract_fee_outputs = true;
478+
params.m_change_fee = params.m_effective_feerate.GetFee(params.change_output_size);
479+
params.m_cost_of_change = params.m_discard_feerate.GetFee(params.change_spend_size) + params.m_change_fee;
480+
params.m_min_change_target = params.m_cost_of_change + 1;
481+
// Add spendable coin at the BnB selection upper bound
482+
CoinsResult available_coins;
483+
add_coin(available_coins, *wallet, COIN + params.m_cost_of_change, /*feerate=*/params.m_effective_feerate, /*nAge=*/6, /*fIsFromMe=*/true, /*nInput=*/0, /*spendable=*/true);
484+
add_coin(available_coins, *wallet, 0.5 * COIN + params.m_cost_of_change, /*feerate=*/params.m_effective_feerate, /*nAge=*/6, /*fIsFromMe=*/true, /*nInput=*/0, /*spendable=*/true);
485+
add_coin(available_coins, *wallet, 0.5 * COIN, /*feerate=*/params.m_effective_feerate, /*nAge=*/6, /*fIsFromMe=*/true, /*nInput=*/0, /*spendable=*/true);
486+
// Knapsack will only find a changeless solution on an exact match to the satoshi, SRD doesn’t look for changeless
487+
// If BnB were run, it would produce a single input solution with the best waste score
488+
auto result = WITH_LOCK(wallet->cs_wallet, return SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/{}, COIN, /*coin_control=*/{}, params));
489+
BOOST_CHECK(result.has_value());
490+
BOOST_CHECK_NE(result->GetAlgo(), SelectionAlgorithm::BNB);
491+
BOOST_CHECK(result->GetInputSet().size() == 2);
492+
// We have only considered BnB, SRD, and Knapsack. Test needs to be reevaluated if new algo is added
493+
BOOST_CHECK(result->GetAlgo() == SelectionAlgorithm::SRD || result->GetAlgo() == SelectionAlgorithm::KNAPSACK);
494+
}
495+
458496
BOOST_AUTO_TEST_CASE(knapsack_solver_test)
459497
{
460498
FastRandomContext rand{};

0 commit comments

Comments
 (0)