21 #include <boost/test/unit_test.hpp> 32 #define RANDOM_REPEATS 5 42 tx.
vout.resize(nInput + 1);
43 tx.
vout[nInput].nValue = nValue;
47 group.Insert(std::make_shared<COutput>(output), 0, 0);
54 tx.
vout.resize(nInput + 1);
55 tx.
vout[nInput].nValue = nValue;
57 std::shared_ptr<COutput> coin = std::make_shared<COutput>(
COutPoint(tx.
GetHash(), nInput), tx.
vout.at(nInput), 1, 148,
true,
true, 0,
false,
fee);
59 group.Insert(coin, 0, 0);
60 coin->long_term_fee = long_term_fee;
68 tx.
vout.resize(nInput + 1);
69 tx.
vout[nInput].nValue = nValue;
79 const auto& txout = wtx.
tx->vout.at(nInput);
80 available_coins.
Add(
OutputType::BECH32, {
COutPoint(wtx.
GetHash(), nInput), txout, nAge, custom_size == 0 ?
CalculateMaximumSignedInputSize(txout, &
wallet,
nullptr) : custom_size,
true,
true, wtx.
GetTxTime(), fIsFromMe, feerate});
88 return res ? std::optional<SelectionResult>(*res) : std::nullopt;
94 return res ? std::optional<SelectionResult>(*res) : std::nullopt;
101 std::vector<CAmount> a_amts;
102 std::vector<CAmount> b_amts;
104 a_amts.push_back(coin->txout.nValue);
107 b_amts.push_back(coin->txout.nValue);
109 std::sort(a_amts.begin(), a_amts.end());
110 std::sort(b_amts.begin(), b_amts.end());
112 std::pair<std::vector<CAmount>::iterator, std::vector<CAmount>::iterator>
ret = std::mismatch(a_amts.begin(), a_amts.end(), b_amts.begin());
113 return ret.first == a_amts.end() &&
ret.second == b_amts.end();
120 [](
const std::shared_ptr<COutput>& a,
const std::shared_ptr<COutput>& b) {
121 return a->outpoint == b->outpoint;
123 return ret.first == a.GetInputSet().end() &&
ret.second == b.
GetInputSet().end();
126 inline std::vector<OutputGroup>&
GroupCoins(
const std::vector<COutput>& available_coins,
bool subtract_fee_outputs =
false)
128 static std::vector<OutputGroup> static_groups;
129 static_groups.clear();
130 for (
auto& coin : available_coins) {
131 static_groups.emplace_back();
133 group.Insert(std::make_shared<COutput>(coin), 0, 0);
134 group.m_subtract_fee_outputs = subtract_fee_outputs;
136 return static_groups;
154 static_groups =
GroupOutputs(
wallet, available_coins, coin_selection_params, {{filter}})[filter];
163 wallet->SetupDescriptorScriptPubKeyMans();
172 std::vector<COutput> utxo_pool;
191 coin_selection_params_bnb.m_change_fee = coin_selection_params_bnb.m_effective_feerate.
GetFee(coin_selection_params_bnb.change_output_size);
192 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;
193 coin_selection_params_bnb.min_viable_change = coin_selection_params_bnb.m_effective_feerate.GetFee(coin_selection_params_bnb.change_spend_size);
200 add_coin(available_coins, *
wallet, 1, coin_selection_params_bnb.m_effective_feerate);
201 available_coins.
All().at(0).input_bytes = 40;
205 available_coins.
Clear();
206 add_coin(available_coins, *
wallet, 1 *
CENT, coin_selection_params_bnb.m_effective_feerate);
207 available_coins.
All().at(0).input_bytes = 40;
218 coin_selection_params_bnb.m_effective_feerate =
CFeeRate(0);
219 add_coin(available_coins, *
wallet, 5 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
220 add_coin(available_coins, *
wallet, 3 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
221 add_coin(available_coins, *
wallet, 2 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
224 COutput select_coin = available_coins.
All().at(0);
231 const auto result10 =
SelectCoins(*
wallet, available_coins, selected_input, 10 *
CENT, coin_control, coin_selection_params_bnb);
241 coin_selection_params_bnb.m_effective_feerate =
CFeeRate(5000);
242 coin_selection_params_bnb.m_long_term_feerate =
CFeeRate(3000);
245 CAmount input_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(68);
246 add_coin(available_coins, *
wallet, 10 *
CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
247 add_coin(available_coins, *
wallet, 9 *
CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
248 add_coin(available_coins, *
wallet, 1 *
CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
255 COutput select_coin = available_coins.
All().at(1);
260 const auto result13 =
SelectCoins(*
wallet, available_coins, selected_input, 10 *
CENT, coin_control, coin_selection_params_bnb);
271 add_coin(available_coins, *
wallet, 10 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
272 add_coin(available_coins, *
wallet, 9 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
273 add_coin(available_coins, *
wallet, 8 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
275 add_coin(available_coins, *
wallet, 3 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
276 add_coin(available_coins, *
wallet, 1 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
281 BOOST_REQUIRE(!no_res);
285 add_coin(available_coins, *
wallet, 5 *
CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24,
false, 0,
true);
315 params.m_subtract_fee_outputs =
true;
316 params.m_change_fee = params.m_effective_feerate.
GetFee(params.change_output_size);
317 params.m_cost_of_change = params.m_discard_feerate.GetFee(params.change_spend_size) + params.m_change_fee;
318 params.m_min_change_target = params.m_cost_of_change + 1;
321 add_coin(available_coins, *
wallet,
COIN + params.m_cost_of_change, params.m_effective_feerate, 6,
true, 0,
true);
322 add_coin(available_coins, *
wallet, 0.5 *
COIN + params.m_cost_of_change, params.m_effective_feerate, 6,
true, 0,
true);
323 add_coin(available_coins, *
wallet, 0.5 *
COIN, params.m_effective_feerate, 6,
true, 0,
true);
346 available_coins.
Clear();
415 available_coins.
Clear();
473 available_coins.
Clear();
505 available_coins.
Clear();
506 for (
int j = 0; j < 20; j++)
518 available_coins.
Clear();
529 available_coins.
Clear();
540 available_coins.
Clear();
560 available_coins.
Clear();
562 for (uint16_t j = 0; j < 676; j++)
570 if (amt - 2000 <
CENT) {
572 uint16_t returnSize = std::ceil((2000.0 +
CENT)/amt);
573 CAmount returnValue = amt * returnSize;
586 available_coins.
Clear();
587 for (
int i2 = 0; i2 < 100; i2++)
650 for (
int i = 0; i < 1000; i++)
667 std::default_random_engine generator;
668 std::exponential_distribution<double> distribution (100);
672 for (
int i = 0; i < 100; ++i)
678 for (
int j = 0; j < 1000; ++j)
680 CAmount val = distribution(generator)*10000000;
703 cs_params.m_cost_of_change = 1;
704 cs_params.min_viable_change = 1;
708 BOOST_CHECK_GE(
result->GetSelectedValue(), target);
715 const CAmount min_viable_change{300};
716 const CAmount change_cost{125};
733 selection1.RecalculateWaste(min_viable_change, change_cost, change_fee);
740 selection2.RecalculateWaste(min_viable_change, change_cost, change_fee);
741 BOOST_CHECK_GT(selection2.GetWaste(), selection1.GetWaste());
748 selection3.RecalculateWaste(min_viable_change, change_cost, change_fee);
750 BOOST_CHECK_LT(selection3.GetWaste(), selection1.GetWaste());
758 selection_nochange1.RecalculateWaste(min_viable_change, change_cost, change_fee);
766 selection_nochange2.RecalculateWaste(min_viable_change, change_cost, change_fee);
768 BOOST_CHECK_LT(selection_nochange2.GetWaste(), selection_nochange1.GetWaste());
776 selection.RecalculateWaste(min_viable_change, change_cost, change_fee);
785 selection.RecalculateWaste(min_viable_change, change_cost, change_fee);
794 selection.RecalculateWaste(min_viable_change, change_cost , change_fee);
803 selection.RecalculateWaste(min_viable_change, fee_diff * 2, change_fee);
809 const CAmount new_target{exact_target - fee_diff * 2};
813 selection.RecalculateWaste(min_viable_change, change_cost, change_fee);
820 const CAmount target_waste1{-2 * fee_diff};
823 selection.RecalculateWaste(min_viable_change, change_cost, change_fee);
830 const CAmount large_fee_diff{90};
831 const CAmount target_waste2{-2 * large_fee_diff + change_cost};
835 assert(target_waste2 == -55);
838 selection.RecalculateWaste(min_viable_change, change_cost, change_fee);
847 const CAmount min_viable_change{200};
848 const CAmount change_cost{125};
857 const std::vector<std::shared_ptr<COutput>> inputs = selection.GetShuffledInputVector();
859 for (
size_t i = 0; i < inputs.size(); ++i) {
860 inputs[i]->ApplyBumpFee(20*(i+1));
863 selection.RecalculateWaste(min_viable_change, change_cost, change_fee);
864 CAmount expected_waste = fee_diff * -2 + change_cost + 60;
867 selection.SetBumpFeeDiscount(30);
868 selection.RecalculateWaste(min_viable_change, change_cost, change_fee);
869 expected_waste = fee_diff * -2 + change_cost + 60 - 30;
883 const std::vector<std::shared_ptr<COutput>> inputs = selection.GetShuffledInputVector();
885 for (
size_t i = 0; i < inputs.size(); ++i) {
886 inputs[i]->ApplyBumpFee(20*(i+1));
889 selection.RecalculateWaste(min_viable_change, change_cost, change_fee);
890 CAmount expected_waste = fee_diff * -2 + 60 + 40;
893 selection.SetBumpFeeDiscount(30);
894 selection.RecalculateWaste(min_viable_change, change_cost, change_fee);
895 expected_waste = fee_diff * -2 + 60 - 30 + 70;
902 const int input_bytes = 148;
905 const int nInput = 0;
909 tx.
vout[nInput].nValue = nValue;
913 const CAmount expected_ev1 = 9852;
922 const CAmount expected_ev3 = -4800;
938 int max_selection_weight,
976 int max_selection_weight = 10
'000; // high enough to not fail for this reason. 977 const auto& res = CoinGrinder(target, dummy_params, m_node, max_selection_weight, [&](CWallet& wallet) { 978 CoinsResult available_coins; 979 for (int j = 0; j < 10; ++j) { 980 add_coin(available_coins, wallet, CAmount(1 * COIN)); 981 add_coin(available_coins, wallet, CAmount(2 * COIN)); 983 return available_coins; 986 BOOST_CHECK(util::ErrorString(res).empty()); // empty means "insufficient funds" 990 // ########################### 991 // 2) Test max weight exceeded 992 // ########################### 993 CAmount target = 29.5L * COIN; 994 int max_selection_weight = 3000; 995 const auto& res = CoinGrinder(target, dummy_params, m_node, max_selection_weight, [&](CWallet& wallet) { 996 CoinsResult available_coins; 997 for (int j = 0; j < 10; ++j) { 998 add_coin(available_coins, wallet, CAmount(1 * COIN), CFeeRate(5000), 144, false, 0, true); 999 add_coin(available_coins, wallet, CAmount(2 * COIN), CFeeRate(5000), 144, false, 0, true); 1001 return available_coins; 1004 BOOST_CHECK(util::ErrorString(res).original.find("The inputs size exceeds the maximum weight") != std::string::npos); 1008 // ############################################################################################################### 1009 // 3) Test that the lowest-weight solution is found when some combinations would exceed the allowed weight 1010 // ################################################################################################################ 1011 CAmount target = 25.33L * COIN; 1012 int max_selection_weight = 10'000;
1015 for (
int j = 0; j < 60; ++j) {
1018 for (
int i = 0; i < 10; i++) {
1021 return available_coins;
1024 for (
int i = 0; i < 10; ++i) {
1027 for (
int j = 0; j < 17; ++j) {
1032 size_t expected_attempts = 37;
1033 BOOST_CHECK_MESSAGE(res->GetSelectionsEvaluated() == expected_attempts,
strprintf(
"Expected %i attempts, but got %i", expected_attempts, res->GetSelectionsEvaluated()));
1041 int max_selection_weight = 400
'000; // WU 1042 const auto& res = CoinGrinder(target, dummy_params, m_node, max_selection_weight, [&](CWallet& wallet) { 1043 CoinsResult available_coins; 1044 add_coin(available_coins, wallet, CAmount(2 * COIN), CFeeRate(5000), 144, false, 0, true, 148); 1045 add_coin(available_coins, wallet, CAmount(1 * COIN), CFeeRate(5000), 144, false, 0, true, 68); 1046 add_coin(available_coins, wallet, CAmount(1 * COIN), CFeeRate(5000), 144, false, 0, true, 68); 1047 return available_coins; 1049 SelectionResult expected_result(CAmount(0), SelectionAlgorithm::CG); 1050 add_coin(1 * COIN, 1, expected_result); 1051 add_coin(1 * COIN, 2, expected_result); 1052 BOOST_CHECK(EquivalentResult(expected_result, *res)); 1053 // Demonstrate how following improvements reduce iteration count and catch any regressions in the future. 1054 size_t expected_attempts = 3; 1055 BOOST_CHECK_MESSAGE(res->GetSelectionsEvaluated() == expected_attempts, strprintf("Expected %i attempts, but got %i", expected_attempts, res->GetSelectionsEvaluated())); 1059 // ############################################################################################################### 1060 // 5) Test finding a solution in a UTXO pool with mixed weights 1061 // ################################################################################################################ 1062 CAmount target = 30L * COIN; 1063 int max_selection_weight = 400'000;
1066 for (
int j = 0; j < 5; ++j) {
1074 return available_coins;
1083 size_t expected_attempts = 92;
1084 BOOST_CHECK_MESSAGE(res->GetSelectionsEvaluated() == expected_attempts,
strprintf(
"Expected %i attempts, but got %i", expected_attempts, res->GetSelectionsEvaluated()));
1092 int max_selection_weight = 400
'000; // WU 1093 const auto& res = CoinGrinder(target, dummy_params, m_node, max_selection_weight, [&](CWallet& wallet) { 1094 CoinsResult available_coins; 1095 // Expected Result: 4 + 3 + 2 + 1 = 10 BTC at 400 vB 1096 add_coin(available_coins, wallet, CAmount(4 * COIN), CFeeRate(5000), 144, false, 0, true, 100); 1097 add_coin(available_coins, wallet, CAmount(3 * COIN), CFeeRate(5000), 144, false, 0, true, 100); 1098 add_coin(available_coins, wallet, CAmount(2 * COIN), CFeeRate(5000), 144, false, 0, true, 100); 1099 add_coin(available_coins, wallet, CAmount(1 * COIN), CFeeRate(5000), 144, false, 0, true, 100); 1100 // Distracting clones: 1101 for (int j = 0; j < 100; ++j) { 1102 add_coin(available_coins, wallet, CAmount(8 * COIN), CFeeRate(5000), 144, false, 0, true, 1000); 1104 for (int j = 0; j < 100; ++j) { 1105 add_coin(available_coins, wallet, CAmount(7 * COIN), CFeeRate(5000), 144, false, 0, true, 800); 1107 for (int j = 0; j < 100; ++j) { 1108 add_coin(available_coins, wallet, CAmount(6 * COIN), CFeeRate(5000), 144, false, 0, true, 600); 1110 for (int j = 0; j < 100; ++j) { 1111 add_coin(available_coins, wallet, CAmount(5 * COIN), CFeeRate(5000), 144, false, 0, true, 400); 1113 return available_coins; 1115 SelectionResult expected_result(CAmount(0), SelectionAlgorithm::CG); 1116 add_coin(4 * COIN, 0, expected_result); 1117 add_coin(3 * COIN, 0, expected_result); 1118 add_coin(2 * COIN, 0, expected_result); 1119 add_coin(1 * COIN, 0, expected_result); 1120 BOOST_CHECK(EquivalentResult(expected_result, *res)); 1121 // Demonstrate how following improvements reduce iteration count and catch any regressions in the future. 1122 size_t expected_attempts = 38; 1123 BOOST_CHECK_MESSAGE(res->GetSelectionsEvaluated() == expected_attempts, strprintf("Expected %i attempts, but got %i", expected_attempts, res->GetSelectionsEvaluated())); 1127 // ################################################################################################################# 1128 // 7) Test that lots of tiny UTXOs can be skipped if they are too heavy while there are enough funds in lookahead 1129 // ################################################################################################################# 1130 CAmount target = 1.9L * COIN; 1131 int max_selection_weight = 40000; // WU 1132 const auto& res = CoinGrinder(target, dummy_params, m_node, max_selection_weight, [&](CWallet& wallet) { 1133 CoinsResult available_coins; 1134 add_coin(available_coins, wallet, CAmount(1.8 * COIN), CFeeRate(5000), 144, false, 0, true, 2500); 1135 add_coin(available_coins, wallet, CAmount(1 * COIN), CFeeRate(5000), 144, false, 0, true, 1000); 1136 add_coin(available_coins, wallet, CAmount(1 * COIN), CFeeRate(5000), 144, false, 0, true, 1000); 1137 for (int j = 0; j < 100; ++j) { 1138 // make a 100 unique coins only differing by one sat 1139 add_coin(available_coins, wallet, CAmount(0.01 * COIN + j), CFeeRate(5000), 144, false, 0, true, 110); 1141 return available_coins; 1143 SelectionResult expected_result(CAmount(0), SelectionAlgorithm::CG); 1144 add_coin(1 * COIN, 1, expected_result); 1145 add_coin(1 * COIN, 2, expected_result); 1146 BOOST_CHECK(EquivalentResult(expected_result, *res)); 1147 // Demonstrate how following improvements reduce iteration count and catch any regressions in the future. 1148 size_t expected_attempts = 7; 1149 BOOST_CHECK_MESSAGE(res->GetSelectionsEvaluated() == expected_attempts, strprintf("Expected %i attempts, but got %i", expected_attempts, res->GetSelectionsEvaluated())); 1153 // ################################################################################################################# 1154 // 8) Test input set that has a solution will not find a solution before reaching the attempt limit 1155 // ################################################################################################################# 1156 CAmount target = 8 * COIN; 1157 int max_selection_weight = 3200; // WU 1158 dummy_params.m_min_change_target = 0; 1159 const auto& result_a = CoinGrinder(target, dummy_params, m_node, max_selection_weight, [&](CWallet& wallet) { 1160 CoinsResult doppelgangers; 1161 for (int i = 0; i < 18; ++i) { 1162 add_coin(doppelgangers, wallet, CAmount(1 * COIN + i), CFeeRate(0), 144, false, 0, true, 96 + i); 1164 return doppelgangers; 1166 BOOST_CHECK(result_a); 1167 SelectionResult expected_result(CAmount(0), SelectionAlgorithm::CG); 1168 for (int i = 0; i < 8; ++i) { 1169 add_coin(1 * COIN + i, 0, expected_result); 1171 BOOST_CHECK(EquivalentResult(expected_result, *result_a)); 1172 // Demonstrate a solution is found before the attempts limit is reached. 1173 size_t expected_attempts = 87'525;
1174 BOOST_CHECK_MESSAGE(result_a->GetSelectionsEvaluated() == expected_attempts,
strprintf(
"Expected %i attempts, but got %i", expected_attempts, result_a->GetSelectionsEvaluated()));
1179 for (
int i = 0; i < 19; ++i) {
1182 return doppelgangers;
1191 int max_selection_weight,
1225 int max_selection_weight = 10000;
1228 for (
int j = 0; j < 10; ++j) {
1232 return available_coins;
1243 int max_selection_weight = 3000;
1246 for (
int j = 0; j < 10; ++j) {
1251 return available_coins;
1262 int max_selection_weight = 10000;
1265 for (
int j = 0; j < 60; ++j) {
1268 for (
int i = 0; i < 10; i++) {
1271 return available_coins;
1274 BOOST_CHECK(res->GetWeight() <= max_selection_weight);
1281 auto available_coins = coin_setup(*
wallet);
1286 const auto signedTxSize = 10 + 34 + 68 *
result->GetInputSet().size();
1289 BOOST_CHECK_GE(
result->GetSelectedValue(), target);
1296 return std::any_of(
set.begin(),
set.end(), [&](
const auto& coin) {
return coin->GetEffectiveValue() == amount; });
1329 for (
int j = 0; j < 1515; ++j) {
1334 return available_coins;
1341 BOOST_CHECK_LE(
result->GetWeight(), max_weight);
1355 for (
int j = 0; j < 400; ++j) {
1358 for (
int j = 0; j < 2000; ++j) {
1361 return available_coins;
1367 BOOST_CHECK_LE(
result->GetWeight(), max_weight);
1380 for (
int j = 0; j < 1515; ++j) {
1383 return available_coins;
1405 add_coin(available_coins, *dummyWallet, 100000);
1424 COutput output = available_coins.
All().at(0);
1444 for (
int i=0; i<10; i++) {
1452 std::unordered_set<COutPoint, SaltedOutpointHasher> outs_to_remove;
1453 const auto& coins = available_coins.
All();
1454 for (
int i = 0; i < 2; i++) {
1455 outs_to_remove.emplace(coins[i].outpoint);
1457 available_coins.
Erase(outs_to_remove);
1460 const auto& updated_coins = available_coins.
All();
1461 for (
const auto&
out: outs_to_remove) {
1462 auto it = std::find_if(updated_coins.begin(), updated_coins.end(), [&
out](
const COutput &coin) {
1463 return coin.outpoint ==
out;
util::Result< SelectionResult > SelectCoins(const CWallet &wallet, CoinsResult &available_coins, const CoinsResult &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.
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.
util::Result< SelectionResult > KnapsackSolver(std::vector< OutputGroup > &groups, const CAmount &nTargetValue, CAmount change_target, FastRandomContext &rng, int max_selection_weight)
util::Result< CoinsResult > FetchSelectedInputs(const CWallet &wallet, const CCoinControl &coin_control, const CoinSelectionParams &coin_selection_params)
Fetch and validate coin control selected inputs.
static const int WITNESS_SCALE_FACTOR
const OutputSet & GetInputSet() const
Get m_selected_inputs.
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...
int tx_noinputs_size
Size of the transaction before coin selection, consisting of the header and recipient output(s)...
std::vector< COutput > All() const
Concatenate and return all COutputs as one vector.
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...
util::Result< SelectionResult > CoinGrinder(std::vector< OutputGroup > &utxo_pool, const CAmount &selection_target, CAmount change_target, int max_selection_weight)
int64_t GetTxTime() const
static void ApproximateBestSubset(FastRandomContext &insecure_rand, const std::vector< OutputGroup > &groups, const CAmount &nTotalLower, const CAmount &nTargetValue, std::vector< char > &vfBest, CAmount &nBest, int max_selection_weight, int iterations=1000)
Find a subset of the OutputGroups that is at least as large as, but as close as possible to...
int change_output_size
Size of a change output in bytes, determined by the output type.
static bool EqualResult(const SelectionResult &a, const SelectionResult &b)
Check if this selection is equal to another one.
CTxOut txout
The output itself.
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.
CAmount m_min_change_target
Mininmum change to target in Knapsack solver and CoinGrinder: select coins to cover the payment and a...
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
util::Result< SelectionResult > SelectCoinsSRD(const std::vector< OutputGroup > &utxo_pool, CAmount target_value, CAmount change_fee, FastRandomContext &rng, int max_selection_weight)
Select coins by Single Random Draw (SRD).
int CalculateMaximumSignedInputSize(const CTxOut &txout, const COutPoint outpoint, const SigningProvider *provider, bool can_grind_r, const CCoinControl *coin_control)
BOOST_AUTO_TEST_SUITE_END()
Indicate that this wallet supports DescriptorScriptPubKeyMan.
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.
Txid GetHash() const
Compute the hash of this CMutableTransaction.
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.
util::Result< SelectionResult > SelectCoinsBnB(std::vector< OutputGroup > &utxo_pool, const CAmount &selection_target, const CAmount &cost_of_change, int max_selection_weight)
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
static CTransactionRef MakeTransactionRef(Tx &&txIn)
std::set< std::shared_ptr< COutput >, OutputPtrComparator > OutputSet
Parameters for filtering which OutputGroups we may use in coin selection.
BOOST_FIXTURE_TEST_CASE(wallet_coinsresult_test, BasicTestingSetup)
std::vector< OutputGroup > mixed_group
const Txid & GetHash() const LIFETIMEBOUND
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)
BOOST_AUTO_TEST_CASE(bnb_test)
static bool has_coin(const OutputSet &set, CAmount amount)
std::unique_ptr< WalletDatabase > CreateMockableWalletDatabase(MockableData records)
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)
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 virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac...
I randrange(I range) noexcept
Generate a random integer in the range [0..range), with range > 0.
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)
A mutable version of CTransaction.
static constexpr CAmount CENT
void Add(OutputType type, const COutput &out)
CAmount GetFee(int32_t virtual_bytes) const
Return the fee in satoshis for the given vsize in vbytes.
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)
PreselectedInput & Select(const COutPoint &outpoint)
Lock-in the given output for spending.
CAmount m_change_fee
Cost of creating the change output.
#define Assert(val)
Identity function.
static void add_coin(const CAmount &nValue, int nInput, SelectionResult &result)
#define BOOST_CHECK(expr)
static const CoinEligibilityFilter filter_confirmed(1, 1, 0)
static constexpr CAmount COIN
The amount of satoshis in one BTC.