@@ -455,6 +455,44 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
455
455
}
456
456
}
457
457
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
+
458
496
BOOST_AUTO_TEST_CASE (knapsack_solver_test)
459
497
{
460
498
FastRandomContext rand{};
0 commit comments