aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfurszy <matiasfurszyfer@protonmail.com>2023-01-13 13:23:38 -0300
committerfurszy <matiasfurszyfer@protonmail.com>2023-04-05 09:32:39 -0300
commitd3a1c098e4b5df2ebbae20c6e390c3d783950e93 (patch)
tree0592ad898e88741ce14393f5682e55a01ede1643
parent9d9689e5a657956db8a30829c994600ec7d3098b (diff)
downloadbitcoin-d3a1c098e4b5df2ebbae20c6e390c3d783950e93.tar.xz
test: coin selection, add coverage for SRD
-rw-r--r--src/wallet/test/coinselector_tests.cpp94
1 files changed, 94 insertions, 0 deletions
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index db8322e3cb..01ce6d76f4 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -929,6 +929,100 @@ BOOST_AUTO_TEST_CASE(effective_value_test)
BOOST_CHECK_EQUAL(output5.GetEffectiveValue(), nValue); // The effective value should be equal to the absolute value if input_bytes is -1
}
+
+static util::Result<SelectionResult> SelectCoinsSRD(const CAmount& target,
+ const CoinSelectionParams& cs_params,
+ const node::NodeContext& m_node,
+ int max_weight,
+ std::function<CoinsResult(CWallet&)> coin_setup)
+{
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
+ wallet->LoadWallet();
+ LOCK(wallet->cs_wallet);
+ wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
+ wallet->SetupDescriptorScriptPubKeyMans();
+
+ CoinEligibilityFilter filter(0, 0, 0); // accept all coins without ancestors
+ Groups group = GroupOutputs(*wallet, coin_setup(*wallet), cs_params, {{filter}})[filter].all_groups;
+ return SelectCoinsSRD(group.positive_group, target, cs_params.rng_fast, max_weight);
+}
+
+BOOST_AUTO_TEST_CASE(srd_tests)
+{
+ // Test SRD:
+ // 1) Insufficient funds, select all provided coins and fail.
+ // 2) Exceeded max weight, coin selection always surpasses the max allowed weight.
+ // 3) Select coins without surpassing the max weight (some coins surpasses the max allowed weight, some others not)
+
+ FastRandomContext rand;
+ CoinSelectionParams dummy_params{ // Only used to provide the 'avoid_partial' flag.
+ rand,
+ /*change_output_size=*/34,
+ /*change_spend_size=*/68,
+ /*min_change_target=*/CENT,
+ /*effective_feerate=*/CFeeRate(0),
+ /*long_term_feerate=*/CFeeRate(0),
+ /*discard_feerate=*/CFeeRate(0),
+ /*tx_noinputs_size=*/10 + 34, // static header size + output size
+ /*avoid_partial=*/false,
+ };
+
+ {
+ // #########################################################
+ // 1) Insufficient funds, select all provided coins and fail
+ // #########################################################
+ CAmount target = 49.5L * COIN;
+ int max_weight = 10000; // high enough to not fail for this reason.
+ const auto& res = SelectCoinsSRD(target, dummy_params, m_node, max_weight, [&](CWallet& wallet) {
+ CoinsResult available_coins;
+ for (int j = 0; j < 10; ++j) {
+ add_coin(available_coins, wallet, CAmount(1 * COIN));
+ add_coin(available_coins, wallet, CAmount(2 * COIN));
+ }
+ return available_coins;
+ });
+ BOOST_CHECK(!res);
+ BOOST_CHECK(util::ErrorString(res).empty()); // empty means "insufficient funds"
+ }
+
+ {
+ // ###########################
+ // 2) Test max weight exceeded
+ // ###########################
+ CAmount target = 49.5L * COIN;
+ int max_weight = 3000;
+ const auto& res = SelectCoinsSRD(target, dummy_params, m_node, max_weight, [&](CWallet& wallet) {
+ CoinsResult available_coins;
+ for (int j = 0; j < 10; ++j) {
+ add_coin(available_coins, wallet, CAmount(1 * COIN), CFeeRate(0), 144, false, 0, true);
+ add_coin(available_coins, wallet, CAmount(2 * COIN), CFeeRate(0), 144, false, 0, true);
+ }
+ return available_coins;
+ });
+ BOOST_CHECK(!res);
+ BOOST_CHECK(util::ErrorString(res).original.find("The inputs size exceeds the maximum weight") != std::string::npos);
+ }
+
+ {
+ // ################################################################################################################
+ // 3) Test selection when some coins surpass the max allowed weight while others not. --> must find a good solution
+ // ################################################################################################################
+ CAmount target = 25.33L * COIN;
+ int max_weight = 10000; // WU
+ const auto& res = SelectCoinsSRD(target, dummy_params, m_node, max_weight, [&](CWallet& wallet) {
+ CoinsResult available_coins;
+ for (int j = 0; j < 60; ++j) { // 60 UTXO --> 19,8 BTC total --> 60 × 272 WU = 16320 WU
+ add_coin(available_coins, wallet, CAmount(0.33 * COIN), CFeeRate(0), 144, false, 0, true);
+ }
+ for (int i = 0; i < 10; i++) { // 10 UTXO --> 20 BTC total --> 10 × 272 WU = 2720 WU
+ add_coin(available_coins, wallet, CAmount(2 * COIN), CFeeRate(0), 144, false, 0, true);
+ }
+ return available_coins;
+ });
+ BOOST_CHECK(res);
+ }
+}
+
static util::Result<SelectionResult> select_coins(const CAmount& target, const CoinSelectionParams& cs_params, const CCoinControl& cc, std::function<CoinsResult(CWallet&)> coin_setup, interfaces::Chain* chain)
{
std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(chain, "", CreateMockWalletDatabase());