20 #include <boost/test/unit_test.hpp> 24 BOOST_FIXTURE_TEST_SUITE(coinselector_tests, WalletTestingSetup)
31 #define RANDOM_REPEATS 5 33 typedef std::set<std::shared_ptr<COutput>>
CoinSet;
40 static void add_coin(
const CAmount& nValue,
int nInput, std::vector<COutput>&
set)
43 tx.
vout.resize(nInput + 1);
44 tx.
vout[nInput].nValue = nValue;
46 set.emplace_back(
COutPoint(tx.
GetHash(), nInput), tx.
vout.at(nInput), 1, -1,
true,
true,
true, 0,
false, 0);
52 tx.
vout.resize(nInput + 1);
53 tx.
vout[nInput].nValue = nValue;
55 COutput output(
COutPoint(tx.
GetHash(), nInput), tx.
vout.at(nInput), 1, -1,
true,
true,
true, 0,
false, 0);
57 group.Insert(std::make_shared<COutput>(output), 0, 0);
64 tx.
vout.resize(nInput + 1);
65 tx.
vout[nInput].nValue = nValue;
67 std::shared_ptr<COutput> coin = std::make_shared<COutput>(
COutPoint(tx.
GetHash(), nInput), tx.
vout.at(nInput), 1, 148,
true,
true,
true, 0,
false, fee);
69 group.Insert(coin, 0, 0);
70 coin->long_term_fee = long_term_fee;
78 tx.
vout.resize(nInput + 1);
79 tx.
vout[nInput].nValue = nValue;
89 const auto& txout = wtx.
tx->vout.at(nInput);
90 available_coins.
Add(
OutputType::BECH32, {
COutPoint(wtx.
GetHash(), nInput), txout, nAge, custom_size == 0 ?
CalculateMaximumSignedInputSize(txout, &
wallet,
nullptr) : custom_size,
true,
true,
true, wtx.
GetTxTime(), fIsFromMe, feerate});
98 return res ? std::optional<SelectionResult>(*res) : std::nullopt;
104 return res ? std::optional<SelectionResult>(*res) : std::nullopt;
111 std::vector<CAmount> a_amts;
112 std::vector<CAmount> b_amts;
114 a_amts.push_back(coin->txout.nValue);
117 b_amts.push_back(coin->txout.nValue);
119 std::sort(a_amts.begin(), a_amts.end());
120 std::sort(b_amts.begin(), b_amts.end());
122 std::pair<std::vector<CAmount>::iterator, std::vector<CAmount>::iterator>
ret = std::mismatch(a_amts.begin(), a_amts.end(), b_amts.begin());
123 return ret.first == a_amts.end() &&
ret.second == b_amts.end();
130 [](
const std::shared_ptr<COutput>& a,
const std::shared_ptr<COutput>& b) {
131 return a->outpoint == b->outpoint;
133 return ret.first == a.GetInputSet().end() &&
ret.second == b.
GetInputSet().end();
140 for (
int i = 0; i < utxos; ++i) {
141 target +=
CAmount{1} << (utxos+i);
148 inline std::vector<OutputGroup>&
GroupCoins(
const std::vector<COutput>& available_coins,
bool subtract_fee_outputs =
false)
150 static std::vector<OutputGroup> static_groups;
151 static_groups.clear();
152 for (
auto& coin : available_coins) {
153 static_groups.emplace_back();
155 group.Insert(std::make_shared<COutput>(coin), 0, 0);
156 group.m_subtract_fee_outputs = subtract_fee_outputs;
158 return static_groups;
176 static_groups =
GroupOutputs(
wallet, available_coins, coin_selection_params, {{filter}})[filter];
186 wallet->SetupDescriptorScriptPubKeyMans();
195 std::vector<COutput> utxo_pool;
217 expected_result.
Clear();
225 expected_result.
Clear();
234 expected_result.
Clear();
238 expected_result.
Clear();
246 expected_result.
Clear();
250 expected_result.
Clear();
262 expected_result.
Clear();
266 expected_result.
Clear();
287 for (
int i = 0; i < 50000; ++i) {
300 for (
int i = 5; i <= 20; ++i) {
304 for (
int i = 0; i < 100; ++i) {
320 coin_selection_params_bnb.m_change_fee = coin_selection_params_bnb.m_effective_feerate.
GetFee(coin_selection_params_bnb.change_output_size);
321 coin_selection_params_bnb.m_cost_of_change = coin_selection_params_bnb.m_effective_feerate.GetFee(coin_selection_params_bnb.change_spend_size) + coin_selection_params_bnb.m_change_fee;
322 coin_selection_params_bnb.min_viable_change = coin_selection_params_bnb.m_effective_feerate.GetFee(coin_selection_params_bnb.change_spend_size);
329 add_coin(available_coins, *
wallet, 1, coin_selection_params_bnb.m_effective_feerate);
330 available_coins.
All().at(0).input_bytes = 40;
334 available_coins.
Clear();
335 add_coin(available_coins, *
wallet, 1 *
CENT, coin_selection_params_bnb.m_effective_feerate);
336 available_coins.
All().at(0).input_bytes = 40;
347 coin_selection_params_bnb.m_effective_feerate =
CFeeRate(0);
348 add_coin(available_coins, *
wallet, 5 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
349 add_coin(available_coins, *
wallet, 3 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
350 add_coin(available_coins, *
wallet, 2 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
353 COutput select_coin = available_coins.
All().at(0);
356 selected_input.
Insert(select_coin, coin_selection_params_bnb.m_subtract_fee_outputs);
360 const auto result10 =
SelectCoins(*
wallet, available_coins, selected_input, 10 *
CENT, coin_control, coin_selection_params_bnb);
370 coin_selection_params_bnb.m_effective_feerate =
CFeeRate(5000);
371 coin_selection_params_bnb.m_long_term_feerate =
CFeeRate(3000);
374 CAmount input_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(68);
375 add_coin(available_coins, *
wallet, 10 *
CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
376 add_coin(available_coins, *
wallet, 9 *
CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
377 add_coin(available_coins, *
wallet, 1 *
CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
379 expected_result.
Clear();
382 const auto result11 =
SelectCoins(*
wallet, available_coins, {}, 10 *
CENT, coin_control, coin_selection_params_bnb);
384 available_coins.
Clear();
387 coin_selection_params_bnb.m_effective_feerate =
CFeeRate(3000);
388 coin_selection_params_bnb.m_long_term_feerate =
CFeeRate(5000);
391 input_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(68);
392 add_coin(available_coins, *
wallet, 10 *
CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
393 add_coin(available_coins, *
wallet, 9 *
CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
394 add_coin(available_coins, *
wallet, 1 *
CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
396 expected_result.
Clear();
399 const auto result12 =
SelectCoins(*
wallet, available_coins, {}, 10 *
CENT, coin_control, coin_selection_params_bnb);
401 available_coins.
Clear();
404 coin_selection_params_bnb.m_effective_feerate =
CFeeRate(5000);
405 coin_selection_params_bnb.m_long_term_feerate =
CFeeRate(3000);
408 input_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(68);
409 add_coin(available_coins, *
wallet, 10 *
CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
410 add_coin(available_coins, *
wallet, 9 *
CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
411 add_coin(available_coins, *
wallet, 1 *
CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
413 expected_result.
Clear();
416 coin_control.m_allow_other_inputs =
true;
417 COutput select_coin = available_coins.
All().at(1);
418 coin_control.Select(select_coin.
outpoint);
420 selected_input.
Insert(select_coin, coin_selection_params_bnb.m_subtract_fee_outputs);
422 const auto result13 =
SelectCoins(*
wallet, available_coins, selected_input, 10 *
CENT, coin_control, coin_selection_params_bnb);
433 add_coin(available_coins, *
wallet, 10 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
434 add_coin(available_coins, *
wallet, 9 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
435 add_coin(available_coins, *
wallet, 8 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
437 add_coin(available_coins, *
wallet, 3 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
438 add_coin(available_coins, *
wallet, 1 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
443 BOOST_REQUIRE(!no_res);
447 add_coin(available_coins, *
wallet, 5 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
450 expected_result.
Clear();
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;
483 add_coin(available_coins, *
wallet,
COIN + params.m_cost_of_change, params.m_effective_feerate, 6,
true, 0,
true);
484 add_coin(available_coins, *
wallet, 0.5 *
COIN + params.m_cost_of_change, params.m_effective_feerate, 6,
true, 0,
true);
485 add_coin(available_coins, *
wallet, 0.5 *
COIN, params.m_effective_feerate, 6,
true, 0,
true);
508 available_coins.
Clear();
577 available_coins.
Clear();
635 available_coins.
Clear();
667 available_coins.
Clear();
668 for (
int j = 0; j < 20; j++)
680 available_coins.
Clear();
691 available_coins.
Clear();
702 available_coins.
Clear();
722 available_coins.
Clear();
724 for (uint16_t j = 0; j < 676; j++)
732 if (amt - 2000 <
CENT) {
734 uint16_t returnSize = std::ceil((2000.0 +
CENT)/amt);
735 CAmount returnValue = amt * returnSize;
748 available_coins.
Clear();
749 for (
int i2 = 0; i2 < 100; i2++)
812 for (
int i = 0; i < 1000; i++)
829 std::default_random_engine generator;
830 std::exponential_distribution<double> distribution (100);
834 for (
int i = 0; i < 100; ++i)
840 for (
int j = 0; j < 1000; ++j)
842 CAmount val = distribution(generator)*10000000;
865 cs_params.m_cost_of_change = 1;
866 cs_params.min_viable_change = 1;
868 const auto result =
SelectCoins(*
wallet, available_coins, {}, target, cc, cs_params);
870 BOOST_CHECK_GE(result->GetSelectedValue(), target);
877 const CAmount change_cost{125};
881 const CAmount excess{in_amt - fee * 2 - target};
892 selection1.ComputeAndSetWaste(0, change_cost, 0);
897 add_coin(1 *
COIN, 1, selection2, fee * 2, fee - fee_diff);
898 add_coin(2 *
COIN, 2, selection2, fee * 2, fee - fee_diff);
899 selection2.ComputeAndSetWaste(0, change_cost, 0);
900 BOOST_CHECK_GT(selection2.GetWaste(), selection1.GetWaste());
907 selection3.ComputeAndSetWaste(0, change_cost, 0);
909 BOOST_CHECK_LT(selection3.GetWaste(), selection1.GetWaste());
915 add_coin(1 *
COIN, 1, selection_nochange1, fee, fee - fee_diff);
916 add_coin(2 *
COIN, 2, selection_nochange1, fee, fee - fee_diff);
917 selection_nochange1.ComputeAndSetWaste(0, 0, 0);
923 add_coin(1 *
COIN, 1, selection_nochange2, fee, fee + fee_diff);
924 add_coin(2 *
COIN, 2, selection_nochange2, fee, fee + fee_diff);
925 selection_nochange2.ComputeAndSetWaste(0, 0, 0);
927 BOOST_CHECK_LT(selection_nochange2.GetWaste(), selection_nochange1.GetWaste());
935 selection.ComputeAndSetWaste(0, change_cost, 0);
944 selection.ComputeAndSetWaste(0, 0, 0);
950 const CAmount exact_target{in_amt - fee * 2};
954 selection.ComputeAndSetWaste(0, 0, 0);
961 const CAmount new_change_cost{fee_diff * 2};
964 selection.ComputeAndSetWaste(0, new_change_cost, 0);
970 const CAmount new_target{in_amt - fee * 2 - fee_diff * 2};
974 selection.ComputeAndSetWaste(0, 0, 0);
982 const CAmount target_waste1{-2 * fee_diff};
985 selection.ComputeAndSetWaste(0, 0, 0);
992 const CAmount large_fee_diff{90};
993 const CAmount target_waste2{-2 * large_fee_diff + change_cost};
994 add_coin(1 *
COIN, 1, selection, fee, fee + large_fee_diff);
995 add_coin(2 *
COIN, 2, selection, fee, fee + large_fee_diff);
996 selection.ComputeAndSetWaste(0, change_cost, 0);
1005 const CAmount min_viable_change{200};
1006 const CAmount change_cost{125};
1015 const std::vector<std::shared_ptr<COutput>> inputs = selection.GetShuffledInputVector();
1017 for (
size_t i = 0; i < inputs.size(); ++i) {
1018 inputs[i]->ApplyBumpFee(20*(i+1));
1021 selection.ComputeAndSetWaste(min_viable_change, change_cost, change_fee);
1022 CAmount expected_waste = fee_diff * -2 + change_cost + 60;
1025 selection.SetBumpFeeDiscount(30);
1026 selection.ComputeAndSetWaste(min_viable_change, change_cost, change_fee);
1027 expected_waste = fee_diff * -2 + change_cost + 60 - 30;
1037 CAmount changeless_target = 3 *
COIN - 2 * fee - 100;
1041 const std::vector<std::shared_ptr<COutput>> inputs = selection.GetShuffledInputVector();
1043 for (
size_t i = 0; i < inputs.size(); ++i) {
1044 inputs[i]->ApplyBumpFee(20*(i+1));
1047 selection.ComputeAndSetWaste(min_viable_change, change_cost, change_fee);
1048 CAmount expected_waste = fee_diff * -2 + 60 + 40;
1051 selection.SetBumpFeeDiscount(30);
1052 selection.ComputeAndSetWaste(min_viable_change, change_cost, change_fee);
1053 expected_waste = fee_diff * -2 + 60 - 30 + 70;
1060 const int input_bytes = 148;
1063 const int nInput = 0;
1067 tx.
vout[nInput].nValue = nValue;
1070 COutput output1(
COutPoint(tx.
GetHash(), nInput), tx.
vout.at(nInput), 1, input_bytes,
true,
true,
true, 0,
false, feerate);
1071 const CAmount expected_ev1 = 9852;
1075 COutput output2(
COutPoint(tx.
GetHash(), nInput), tx.
vout.at(nInput), 1, -1,
true,
true,
true, 0,
false, feerate);
1079 COutput output3(
COutPoint(tx.
GetHash(), nInput), tx.
vout.at(nInput), 1, input_bytes,
true,
true,
true, 0,
false,
CFeeRate(100000));
1080 const CAmount expected_ev3 = -4800;
1085 COutput output4(
COutPoint(tx.
GetHash(), nInput), tx.
vout.at(nInput), 1, input_bytes,
true,
true,
true, 0,
false, fees);
1089 COutput output5(
COutPoint(tx.
GetHash(), nInput), tx.
vout.at(nInput), 1, -1,
true,
true,
true, 0,
false, 0);
1131 int max_weight = 10000;
1134 for (
int j = 0; j < 10; ++j) {
1138 return available_coins;
1149 int max_weight = 3000;
1152 for (
int j = 0; j < 10; ++j) {
1156 return available_coins;
1167 int max_weight = 10000;
1170 for (
int j = 0; j < 60; ++j) {
1173 for (
int i = 0; i < 10; i++) {
1176 return available_coins;
1185 auto available_coins = coin_setup(*
wallet);
1190 const auto signedTxSize = 10 + 34 + 68 * result->GetInputSet().size();
1193 BOOST_CHECK_GE(result->GetSelectedValue(), target);
1200 return std::any_of(
set.begin(),
set.end(), [&](
const auto& coin) {
return coin->GetEffectiveValue() == amount; });
1232 for (
int j = 0; j < 1515; ++j) {
1237 return available_coins;
1243 const auto& selection_res = result->GetInputSet();
1245 BOOST_CHECK((*selection_res.begin())->GetEffectiveValue() == 50 *
COIN);
1259 for (
int j = 0; j < 400; ++j) {
1262 for (
int j = 0; j < 2000; ++j) {
1265 return available_coins;
1283 for (
int j = 0; j < 1515; ++j) {
1286 return available_coins;
1308 add_coin(available_coins, *dummyWallet, 100000);
1327 COutput output = available_coins.
All().at(0);
1335 const auto result =
SelectCoins(*
wallet, available_coins, preset_inputs, target, cc, cs_params);
1347 for (
int i=0; i<10; i++) {
1355 std::unordered_set<COutPoint, SaltedOutpointHasher> outs_to_remove;
1356 const auto& coins = available_coins.
All();
1357 for (
int i = 0; i < 2; i++) {
1358 outs_to_remove.emplace(coins[i].outpoint);
1360 available_coins.
Erase(outs_to_remove);
1363 const auto& updated_coins = available_coins.
All();
1364 for (
const auto&
out: outs_to_remove) {
1365 auto it = std::find_if(updated_coins.begin(), updated_coins.end(), [&
out](
const COutput &coin) {
1366 return coin.outpoint ==
out;
util::Result< SelectionResult > SelectCoinsSRD(const std::vector< OutputGroup > &utxo_pool, CAmount target_value, CAmount change_fee, FastRandomContext &rng, int max_weight)
Select coins by Single Random Draw.
COutPoint outpoint
The outpoint identifying this UTXO.
std::unique_ptr< interfaces::Chain > chain
FastRandomContext & rng_fast
Randomness to use in the context of coin selection.
static const int WITNESS_SCALE_FACTOR
std::set< std::shared_ptr< COutput > > CoinSet
Stores several 'Groups' whose were mapped by output type.
static bool EquivalentResult(const SelectionResult &a, const SelectionResult &b)
Check if SelectionResult a is equivalent to SelectionResult b.
size_t Size() const
The following methods are provided so that CoinsResult can mimic a vector, i.e., methods can work wit...
std::vector< COutput > All() const
Concatenate and return all COutputs as one vector.
void AddInput(const OutputGroup &group)
util::Result< SelectionResult > SelectCoinsBnB(std::vector< OutputGroup > &utxo_pool, const CAmount &selection_target, const CAmount &cost_of_change, int max_weight)
static std::unique_ptr< CWallet > NewWallet(const node::NodeContext &m_node, const std::string &wallet_name="")
std::vector< OutputGroup > & GroupCoins(const std::vector< COutput > &available_coins, bool subtract_fee_outputs=false)
State of transaction not confirmed or conflicting with a known block and not in the mempool...
void SelectExternal(const COutPoint &outpoint, const CTxOut &txout)
Lock-in the given output as an external input for spending because it is not in the wallet...
int64_t GetTxTime() const
static bool EqualResult(const SelectionResult &a, const SelectionResult &b)
Check if this selection is equal to another one.
CTxOut txout
The output itself.
void Select(const COutPoint &output)
Lock-in the given output for spending.
std::map< OutputType, std::vector< COutput > > coins
int64_t CAmount
Amount in satoshis (Can be negative)
COutputs available for spending, stored by OutputType.
A transaction with a bunch of additional info that only the owner cares about.
NodeContext struct containing references to chain state and connection state.
static void add_coin(const CAmount &nValue, int nInput, std::vector< COutput > &set)
int CalculateMaximumSignedInputSize(const CTxOut &txout, const COutPoint outpoint, const SigningProvider *provider, bool can_grind_r, const CCoinControl *coin_control)
util::Result< SelectionResult > SelectCoins(const CWallet &wallet, CoinsResult &available_coins, const PreSelectedInputs &pre_set_inputs, const CAmount &nTargetValue, const CCoinControl &coin_control, const CoinSelectionParams &coin_selection_params)
Select all coins from coin_control, and if coin_control 'm_allow_other_inputs=true', call 'AutomaticCoinSelection' to select a set of coins such that nTargetValue - pre_set_inputs.total_amount is met.
BOOST_AUTO_TEST_SUITE_END()
const std::set< std::shared_ptr< COutput > > & GetInputSet() const
Get m_selected_inputs.
Indicate that this wallet supports DescriptorScriptPubKeyMan.
static void ApproximateBestSubset(FastRandomContext &insecure_rand, const std::vector< OutputGroup > &groups, const CAmount &nTotalLower, const CAmount &nTargetValue, std::vector< char > &vfBest, CAmount &nBest, int iterations=1000)
Find a subset of the OutputGroups that is at least as large as, but as close as possible to...
util::Result< SelectionResult > KnapsackSolver(std::vector< OutputGroup > &groups, const CAmount &nTargetValue, CAmount change_target, FastRandomContext &rng, int max_weight)
void SetInputWeight(const COutPoint &outpoint, int64_t weight)
Set an input's weight.
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
A group of UTXOs paid to the same output script.
An outpoint - a combination of a transaction hash and an index n into its vout.
static const CoinEligibilityFilter filter_standard_extra(6, 6, 0)
std::vector< CTxOut > vout
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Parameters for one iteration of Coin Selection.
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Parameters for filtering which OutputGroups we may use in coin selection.
util::Result< PreSelectedInputs > FetchSelectedInputs(const CWallet &wallet, const CCoinControl &coin_control, const CoinSelectionParams &coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
Fetch and validate coin control selected inputs.
BOOST_FIXTURE_TEST_CASE(wallet_coinsresult_test, BasicTestingSetup)
std::vector< OutputGroup > mixed_group
static constexpr int32_t MAX_STANDARD_TX_WEIGHT
The maximum weight for transactions we're willing to relay/mine.
static const CoinEligibilityFilter filter_standard(1, 6, 0)
std::unique_ptr< WalletDatabase > CreateMockableWalletDatabase(MockableData records)
uint256 GetHash() const
Compute the hash of this CMutableTransaction.
void Erase(const std::unordered_set< COutPoint, SaltedOutpointHasher > &coins_to_remove)
#define BOOST_CHECK_EQUAL(v1, v2)
std::vector< OutputGroup > & KnapsackGroupOutputs(const CoinsResult &available_coins, CWallet &wallet, const CoinEligibilityFilter &filter)
const uint256 & GetHash() const
bool m_allow_other_inputs
If true, the selection process can add extra unselected inputs from the wallet while requires all sel...
Fee rate in satoshis per kilovirtualbyte: CAmount / kvB.
static util::Result< SelectionResult > select_coins(const CAmount &target, const CoinSelectionParams &cs_params, const CCoinControl &cc, std::function< CoinsResult(CWallet &)> coin_setup, const node::NodeContext &m_node)
bilingual_str ErrorString(const Result< T > &result)
CAmount GetFee(uint32_t num_bytes) const
Return the fee in satoshis for the given vsize in vbytes.
A mutable version of CTransaction.
static constexpr CAmount CENT
std::shared_ptr< CWallet > wallet
void Add(OutputType type, const COutput &out)
BOOST_AUTO_TEST_CASE(bnb_search_test)
A UTXO under consideration for use in funding a new transaction.
FilteredOutputGroups GroupOutputs(const CWallet &wallet, const CoinsResult &coins, const CoinSelectionParams &coin_sel_params, const std::vector< SelectionFilter > &filters, std::vector< OutputGroup > &ret_discarded_groups)
uint64_t randrange(uint64_t range) noexcept
Generate a random integer in the range [0..range).
CAmount m_change_fee
Cost of creating the change output.
#define Assert(val)
Identity function.
static CAmount make_hard_case(int utxos, std::vector< COutput > &utxo_pool)
#define BOOST_CHECK(expr)
static const CoinEligibilityFilter filter_confirmed(1, 1, 0)
static constexpr CAmount COIN
The amount of satoshis in one BTC.
static bool has_coin(const CoinSet &set, CAmount amount)