Skip to content

Commit

Permalink
Move SelectCoins max_weight test
Browse files Browse the repository at this point in the history
  • Loading branch information
murchandamus committed Jan 17, 2024
1 parent 64a86cc commit 4ce5ee6
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 180 deletions.
1 change: 0 additions & 1 deletion src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,6 @@ BITCOIN_TESTS += \
wallet/test/walletdb_tests.cpp \
wallet/test/wallet_crypto_tests.cpp \
wallet/test/wallet_transaction_tests.cpp \
wallet/test/coinselector_tests.cpp \
wallet/test/coinselection_tests.cpp \
wallet/test/init_tests.cpp \
wallet/test/ismine_tests.cpp \
Expand Down
115 changes: 115 additions & 0 deletions src/wallet/test/coinselection_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,121 @@ BOOST_AUTO_TEST_CASE(bump_fee_test)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////// SelectCoins Test ///////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static bool HasCoin(const CoinSet& set, CAmount amount)
{
return std::any_of(set.begin(), set.end(), [&](const auto& coin) { return coin->GetEffectiveValue() == amount; });
}

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)
{
std::unique_ptr<CWallet> wallet = NewWallet(m_node);
auto available_coins = coin_setup(*wallet);

LOCK(wallet->cs_wallet);
auto result = SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/ {}, target, cc, cs_params);
if (result) {
const auto signedTxSize = 10 + 34 + 68 * result->GetInputSet().size(); // static header size + output size + inputs size (P2WPKH)
BOOST_CHECK_LE(signedTxSize * WITNESS_SCALE_FACTOR, MAX_STANDARD_TX_WEIGHT);

BOOST_CHECK_GE(result->GetSelectedValue(), target);
}
return result;
}

BOOST_AUTO_TEST_CASE(check_max_weight)
{
const CAmount target = 49.5L * COIN;
CCoinControl cc;

FastRandomContext rand;
CoinSelectionParams cs_params{
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,
};

{
// Scenario 1:
// The actor starts with 1x 50.0 BTC and 1515x 0.033 BTC (~100.0 BTC total) unspent outputs
// Then tries to spend 49.5 BTC
// The 50.0 BTC output should be selected, because the transaction would otherwise be too large

// Perform selection

const auto result = select_coins(
target, cs_params, cc, [&](CWallet& wallet) {
CoinsResult available_coins;
for (int j = 0; j < 1515; ++j) {
AddCoinToWallet(available_coins, wallet, CAmount(0.033 * COIN), CFeeRate(0), 144, false, 0, true);
}

AddCoinToWallet(available_coins, wallet, CAmount(50 * COIN), CFeeRate(0), 144, false, 0, true);
return available_coins;
},
m_node);

BOOST_CHECK(result);
// Verify that only the 50 BTC UTXO was selected
const auto& selection_res = result->GetInputSet();
BOOST_CHECK(selection_res.size() == 1);
BOOST_CHECK((*selection_res.begin())->GetEffectiveValue() == 50 * COIN);
}

{
// Scenario 2:

// The actor starts with 400x 0.0625 BTC and 2000x 0.025 BTC (75.0 BTC total) unspent outputs
// Then tries to spend 49.5 BTC
// A combination of coins should be selected, such that the created transaction is not too large

// Perform selection
const auto result = select_coins(
target, cs_params, cc, [&](CWallet& wallet) {
CoinsResult available_coins;
for (int j = 0; j < 400; ++j) {
AddCoinToWallet(available_coins, wallet, CAmount(0.0625 * COIN), CFeeRate(0), 144, false, 0, true);
}
for (int j = 0; j < 2000; ++j) {
AddCoinToWallet(available_coins, wallet, CAmount(0.025 * COIN), CFeeRate(0), 144, false, 0, true);
}
return available_coins;
},
m_node);

BOOST_CHECK(HasCoin(result->GetInputSet(), CAmount(0.0625 * COIN)));
BOOST_CHECK(HasCoin(result->GetInputSet(), CAmount(0.025 * COIN)));
}

{
// Scenario 3:

// The actor starts with 1515x 0.033 BTC (49.995 BTC total) unspent outputs
// No results should be returned, because the transaction would be too large

// Perform selection
const auto result = select_coins(
target, cs_params, cc, [&](CWallet& wallet) {
CoinsResult available_coins;
for (int j = 0; j < 1515; ++j) {
AddCoinToWallet(available_coins, wallet, CAmount(0.033 * COIN), CFeeRate(0), 144, false, 0, true);
}
return available_coins;
},
m_node);

// No results
// 1515 inputs * 68 bytes = 103,020 bytes
// 103,020 bytes * 4 = 412,080 weight, which is above the MAX_STANDARD_TX_WEIGHT of 400,000
BOOST_CHECK(!result);
}
}

// Tests that with the ideal conditions, the coin selector will always be able to find a solution that can pay the target value
BOOST_AUTO_TEST_CASE(SelectCoins_test)
{
Expand Down
179 changes: 0 additions & 179 deletions src/wallet/test/coinselector_tests.cpp

This file was deleted.

0 comments on commit 4ce5ee6

Please sign in to comment.