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;
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();
417 COutput select_coin = available_coins.
All().at(1);
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);
1134 int max_weight = 10'000;
1137 for (
int j = 0; j < 10; ++j) {
1141 return available_coins;
1152 int max_weight = 3000;
1155 for (
int j = 0; j < 10; ++j) {
1159 return available_coins;
1170 int max_weight = 10'000;
1173 for (
int j = 0; j < 60; ++j) {
1176 for (
int i = 0; i < 10; i++) {
1179 return available_coins;
1183 size_t expected_attempts = 37;
1184 BOOST_CHECK_MESSAGE(res->GetSelectionsEvaluated() == expected_attempts,
strprintf(
"Expected %i attempts, but got %i", expected_attempts, res->GetSelectionsEvaluated()));
1192 int max_weight = 400'000;
1198 return available_coins;
1205 size_t expected_attempts = 3;
1206 BOOST_CHECK_MESSAGE(res->GetSelectionsEvaluated() == expected_attempts,
strprintf(
"Expected %i attempts, but got %i", expected_attempts, res->GetSelectionsEvaluated()));
1214 int max_weight = 400'000;
1217 for (
int j = 0; j < 5; ++j) {
1225 return available_coins;
1234 size_t expected_attempts = 92;
1235 BOOST_CHECK_MESSAGE(res->GetSelectionsEvaluated() == expected_attempts,
strprintf(
"Expected %i attempts, but got %i", expected_attempts, res->GetSelectionsEvaluated()));
1243 int max_weight = 400'000;
1252 for (
int j = 0; j < 100; ++j) {
1255 for (
int j = 0; j < 100; ++j) {
1258 for (
int j = 0; j < 100; ++j) {
1261 for (
int j = 0; j < 100; ++j) {
1264 return available_coins;
1273 size_t expected_attempts = 38;
1274 BOOST_CHECK_MESSAGE(res->GetSelectionsEvaluated() == expected_attempts,
strprintf(
"Expected %i attempts, but got %i", expected_attempts, res->GetSelectionsEvaluated()));
1282 int max_weight = 40000;
1288 for (
int j = 0; j < 100; ++j) {
1292 return available_coins;
1299 size_t expected_attempts = 7;
1300 BOOST_CHECK_MESSAGE(res->GetSelectionsEvaluated() == expected_attempts,
strprintf(
"Expected %i attempts, but got %i", expected_attempts, res->GetSelectionsEvaluated()));
1341 int max_weight = 10000;
1344 for (
int j = 0; j < 10; ++j) {
1348 return available_coins;
1359 int max_weight = 3000;
1362 for (
int j = 0; j < 10; ++j) {
1367 return available_coins;
1378 int max_weight = 10000;
1381 for (
int j = 0; j < 60; ++j) {
1384 for (
int i = 0; i < 10; i++) {
1387 return available_coins;
1396 auto available_coins = coin_setup(*
wallet);
1401 const auto signedTxSize = 10 + 34 + 68 * result->GetInputSet().size();
1404 BOOST_CHECK_GE(result->GetSelectedValue(), target);
1411 return std::any_of(set.begin(), set.end(), [&](
const auto& coin) { return coin->GetEffectiveValue() == amount; });
1443 for (
int j = 0; j < 1515; ++j) {
1448 return available_coins;
1454 const auto& selection_res = result->GetInputSet();
1456 BOOST_CHECK((*selection_res.begin())->GetEffectiveValue() == 50 *
COIN);
1470 for (
int j = 0; j < 400; ++j) {
1473 for (
int j = 0; j < 2000; ++j) {
1476 return available_coins;
1494 for (
int j = 0; j < 1515; ++j) {
1497 return available_coins;
1519 add_coin(available_coins, *dummyWallet, 100000);
1538 COutput output = available_coins.
All().at(0);
1546 const auto result =
SelectCoins(*
wallet, available_coins, preset_inputs, target, cc, cs_params);
1558 for (
int i=0; i<10; i++) {
1566 std::unordered_set<COutPoint, SaltedOutpointHasher> outs_to_remove;
1567 const auto& coins = available_coins.
All();
1568 for (
int i = 0; i < 2; i++) {
1569 outs_to_remove.emplace(coins[i].outpoint);
1571 available_coins.
Erase(outs_to_remove);
1574 const auto& updated_coins = available_coins.
All();
1575 for (
const auto&
out: outs_to_remove) {
1576 auto it = std::find_if(updated_coins.begin(), updated_coins.end(), [&
out](
const COutput &coin) {
1577 return coin.outpoint == out;
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
int64_t CAmount
Amount in satoshis (Can be negative)
static constexpr CAmount COIN
The amount of satoshis in one BTC.
#define Assert(val)
Identity function.
Fee rate in satoshis per kilovirtualbyte: CAmount / kvB.
CAmount GetFee(uint32_t num_bytes) const
Return the fee in satoshis for the given vsize in vbytes.
An outpoint - a combination of a transaction hash and an index n into its vout.
uint64_t randrange(uint64_t range) noexcept
Generate a random integer in the range [0..range).
PreselectedInput & Select(const COutPoint &outpoint)
Lock-in the given output for spending.
bool m_allow_other_inputs
If true, the selection process can add extra unselected inputs from the wallet while requires all sel...
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 transaction with a bunch of additional info that only the owner cares about.
const Txid & GetHash() const LIFETIMEBOUND
int64_t GetTxTime() const
static const int WITNESS_SCALE_FACTOR
BOOST_AUTO_TEST_SUITE_END()
bilingual_str ErrorString(const Result< T > &result)
std::vector< OutputGroup > & KnapsackGroupOutputs(const CoinsResult &available_coins, CWallet &wallet, const CoinEligibilityFilter &filter)
util::Result< SelectionResult > SelectCoinsBnB(std::vector< OutputGroup > &utxo_pool, const CAmount &selection_target, const CAmount &cost_of_change, int max_weight)
static CAmount make_hard_case(int utxos, std::vector< COutput > &utxo_pool)
static const CoinEligibilityFilter filter_standard(1, 6, 0)
FilteredOutputGroups GroupOutputs(const CWallet &wallet, const CoinsResult &coins, const CoinSelectionParams &coin_sel_params, const std::vector< SelectionFilter > &filters, std::vector< OutputGroup > &ret_discarded_groups)
BOOST_FIXTURE_TEST_CASE(wallet_coinsresult_test, BasicTestingSetup)
static void add_coin(const CAmount &nValue, int nInput, std::vector< COutput > &set)
util::Result< SelectionResult > CoinGrinder(std::vector< OutputGroup > &utxo_pool, const CAmount &selection_target, CAmount change_target, int max_weight)
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.
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,...
std::vector< OutputGroup > & GroupCoins(const std::vector< COutput > &available_coins, bool subtract_fee_outputs=false)
util::Result< SelectionResult > KnapsackSolver(std::vector< OutputGroup > &groups, const CAmount &nTargetValue, CAmount change_target, FastRandomContext &rng, int max_weight)
static std::unique_ptr< CWallet > NewWallet(const node::NodeContext &m_node, const std::string &wallet_name="")
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',...
static const CoinEligibilityFilter filter_standard_extra(6, 6, 0)
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.
static bool has_coin(const CoinSet &set, CAmount amount)
std::set< std::shared_ptr< COutput > > CoinSet
static bool EqualResult(const SelectionResult &a, const SelectionResult &b)
Check if this selection is equal to another one.
std::unique_ptr< WalletDatabase > CreateMockableWalletDatabase(MockableData records)
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)
BOOST_AUTO_TEST_CASE(bnb_search_test)
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.
static const CoinEligibilityFilter filter_confirmed(1, 1, 0)
int CalculateMaximumSignedInputSize(const CTxOut &txout, const COutPoint outpoint, const SigningProvider *provider, bool can_grind_r, const CCoinControl *coin_control)
static bool EquivalentResult(const SelectionResult &a, const SelectionResult &b)
Check if SelectionResult a is equivalent to SelectionResult b.
std::shared_ptr< CWallet > wallet
#define BOOST_CHECK_EQUAL(v1, v2)
#define BOOST_CHECK(expr)
static constexpr int32_t MAX_STANDARD_TX_WEIGHT
The maximum weight for transactions we're willing to relay/mine.
static CTransactionRef MakeTransactionRef(Tx &&txIn)
static constexpr CAmount CENT
A mutable version of CTransaction.
std::vector< CTxOut > vout
Txid GetHash() const
Compute the hash of this CMutableTransaction.
NodeContext struct containing references to chain state and connection state.
std::unique_ptr< interfaces::Chain > chain
A UTXO under consideration for use in funding a new transaction.
COutPoint outpoint
The outpoint identifying this UTXO.
CTxOut txout
The output itself.
CAmount GetEffectiveValue() const
Parameters for filtering which OutputGroups we may use in coin selection.
Parameters for one iteration of Coin Selection.
FastRandomContext & rng_fast
Randomness to use in the context of coin selection.
CAmount m_min_change_target
Mininmum change to target in Knapsack solver and CoinGrinder: select coins to cover the payment and a...
CAmount m_change_fee
Cost of creating the change output.
COutputs available for spending, stored by OutputType.
void Add(OutputType type, const COutput &out)
std::vector< COutput > All() const
Concatenate and return all COutputs as one vector.
size_t Size() const
The following methods are provided so that CoinsResult can mimic a vector, i.e., methods can work wit...
std::map< OutputType, std::vector< COutput > > coins
void Erase(const std::unordered_set< COutPoint, SaltedOutpointHasher > &coins_to_remove)
std::vector< OutputGroup > mixed_group
A group of UTXOs paid to the same output script.
Stores several 'Groups' whose were mapped by output type.
const std::set< std::shared_ptr< COutput > > & GetInputSet() const
Get m_selected_inputs.
void AddInput(const OutputGroup &group)
State of transaction not confirmed or conflicting with a known block and not in the mempool.
#define WITH_LOCK(cs, code)
Run code while locking a mutex.