aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet/test')
-rw-r--r--src/wallet/test/coinselector_tests.cpp78
-rw-r--r--src/wallet/test/fuzz/coincontrol.cpp7
-rw-r--r--src/wallet/test/fuzz/coinselection.cpp3
-rw-r--r--src/wallet/test/fuzz/notifications.cpp3
-rw-r--r--src/wallet/test/spend_tests.cpp3
-rw-r--r--src/wallet/test/util.cpp1
-rw-r--r--src/wallet/test/wallet_tests.cpp3
7 files changed, 68 insertions, 30 deletions
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 9569210ba0..9fea14145f 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -320,7 +320,6 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
coin_selection_params_bnb.m_change_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(coin_selection_params_bnb.change_output_size);
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;
coin_selection_params_bnb.min_viable_change = coin_selection_params_bnb.m_effective_feerate.GetFee(coin_selection_params_bnb.change_spend_size);
- coin_selection_params_bnb.m_subtract_fee_outputs = true;
{
std::unique_ptr<CWallet> wallet = NewWallet(m_node);
@@ -345,6 +344,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
CoinsResult available_coins;
+ coin_selection_params_bnb.m_effective_feerate = CFeeRate(0);
add_coin(available_coins, *wallet, 5 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
add_coin(available_coins, *wallet, 3 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
add_coin(available_coins, *wallet, 2 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
@@ -355,7 +355,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
PreSelectedInputs selected_input;
selected_input.Insert(select_coin, coin_selection_params_bnb.m_subtract_fee_outputs);
available_coins.Erase({available_coins.coins[OutputType::BECH32].begin()->outpoint});
- coin_selection_params_bnb.m_effective_feerate = CFeeRate(0);
+
LOCK(wallet->cs_wallet);
const auto result10 = SelectCoins(*wallet, available_coins, selected_input, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(result10);
@@ -370,12 +370,14 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
coin_selection_params_bnb.m_effective_feerate = CFeeRate(5000);
coin_selection_params_bnb.m_long_term_feerate = CFeeRate(3000);
- add_coin(available_coins, *wallet, 10 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 9 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ // Add selectable outputs, increasing their raw amounts by their input fee to make the effective value equal to the raw amount
+ CAmount input_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(/*num_bytes=*/68); // bech32 input size (default test output type)
+ add_coin(available_coins, *wallet, 10 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 9 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 1 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
expected_result.Clear();
- add_coin(10 * CENT, 2, expected_result);
+ add_coin(10 * CENT + input_fee, 2, expected_result);
CCoinControl coin_control;
const auto result11 = SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/{}, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(EquivalentResult(expected_result, *result11));
@@ -385,13 +387,15 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
coin_selection_params_bnb.m_effective_feerate = CFeeRate(3000);
coin_selection_params_bnb.m_long_term_feerate = CFeeRate(5000);
- add_coin(available_coins, *wallet, 10 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 9 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ // Add selectable outputs, increasing their raw amounts by their input fee to make the effective value equal to the raw amount
+ input_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(/*num_bytes=*/68); // bech32 input size (default test output type)
+ add_coin(available_coins, *wallet, 10 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 9 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 1 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
expected_result.Clear();
- add_coin(9 * CENT, 2, expected_result);
- add_coin(1 * CENT, 2, expected_result);
+ add_coin(9 * CENT + input_fee, 2, expected_result);
+ add_coin(1 * CENT + input_fee, 2, expected_result);
const auto result12 = SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/{}, 10 * CENT, coin_control, coin_selection_params_bnb);
BOOST_CHECK(EquivalentResult(expected_result, *result12));
available_coins.Clear();
@@ -400,13 +404,15 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
coin_selection_params_bnb.m_effective_feerate = CFeeRate(5000);
coin_selection_params_bnb.m_long_term_feerate = CFeeRate(3000);
- add_coin(available_coins, *wallet, 10 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 9 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
- add_coin(available_coins, *wallet, 1 * CENT, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ // Add selectable outputs, increasing their raw amounts by their input fee to make the effective value equal to the raw amount
+ input_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(/*num_bytes=*/68); // bech32 input size (default test output type)
+ add_coin(available_coins, *wallet, 10 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 9 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
+ add_coin(available_coins, *wallet, 1 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true);
expected_result.Clear();
- add_coin(9 * CENT, 2, expected_result);
- add_coin(1 * CENT, 2, expected_result);
+ add_coin(9 * CENT + input_fee, 2, expected_result);
+ add_coin(1 * CENT + input_fee, 2, expected_result);
coin_control.m_allow_other_inputs = true;
COutput select_coin = available_coins.All().at(1); // pre select 9 coin
coin_control.Select(select_coin.outpoint);
@@ -449,6 +455,44 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
}
}
+BOOST_AUTO_TEST_CASE(bnb_sffo_restriction)
+{
+ // Verify the coin selection process does not produce a BnB solution when SFFO is enabled.
+ // This is currently problematic because it could require a change output. And BnB is specialized on changeless solutions.
+ std::unique_ptr<CWallet> wallet = NewWallet(m_node);
+ WITH_LOCK(wallet->cs_wallet, wallet->SetLastBlockProcessed(300, uint256{})); // set a high block so internal UTXOs are selectable
+
+ FastRandomContext rand{};
+ CoinSelectionParams params{
+ rand,
+ /*change_output_size=*/ 31, // unused value, p2wpkh output size (wallet default change type)
+ /*change_spend_size=*/ 68, // unused value, p2wpkh input size (high-r signature)
+ /*min_change_target=*/ 0, // dummy, set later
+ /*effective_feerate=*/ CFeeRate(3000),
+ /*long_term_feerate=*/ CFeeRate(1000),
+ /*discard_feerate=*/ CFeeRate(1000),
+ /*tx_noinputs_size=*/ 0,
+ /*avoid_partial=*/ false,
+ };
+ params.m_subtract_fee_outputs = true;
+ params.m_change_fee = params.m_effective_feerate.GetFee(params.change_output_size);
+ params.m_cost_of_change = params.m_discard_feerate.GetFee(params.change_spend_size) + params.m_change_fee;
+ params.m_min_change_target = params.m_cost_of_change + 1;
+ // Add spendable coin at the BnB selection upper bound
+ CoinsResult available_coins;
+ add_coin(available_coins, *wallet, COIN + params.m_cost_of_change, /*feerate=*/params.m_effective_feerate, /*nAge=*/6, /*fIsFromMe=*/true, /*nInput=*/0, /*spendable=*/true);
+ add_coin(available_coins, *wallet, 0.5 * COIN + params.m_cost_of_change, /*feerate=*/params.m_effective_feerate, /*nAge=*/6, /*fIsFromMe=*/true, /*nInput=*/0, /*spendable=*/true);
+ add_coin(available_coins, *wallet, 0.5 * COIN, /*feerate=*/params.m_effective_feerate, /*nAge=*/6, /*fIsFromMe=*/true, /*nInput=*/0, /*spendable=*/true);
+ // Knapsack will only find a changeless solution on an exact match to the satoshi, SRD doesn’t look for changeless
+ // If BnB were run, it would produce a single input solution with the best waste score
+ auto result = WITH_LOCK(wallet->cs_wallet, return SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/{}, COIN, /*coin_control=*/{}, params));
+ BOOST_CHECK(result.has_value());
+ BOOST_CHECK_NE(result->GetAlgo(), SelectionAlgorithm::BNB);
+ BOOST_CHECK(result->GetInputSet().size() == 2);
+ // We have only considered BnB, SRD, and Knapsack. Test needs to be reevaluated if new algo is added
+ BOOST_CHECK(result->GetAlgo() == SelectionAlgorithm::SRD || result->GetAlgo() == SelectionAlgorithm::KNAPSACK);
+}
+
BOOST_AUTO_TEST_CASE(knapsack_solver_test)
{
FastRandomContext rand{};
@@ -1282,7 +1326,7 @@ BOOST_AUTO_TEST_CASE(SelectCoins_effective_value_test)
cc.m_allow_other_inputs = false;
COutput output = available_coins.All().at(0);
cc.SetInputWeight(output.outpoint, 148);
- cc.SelectExternal(output.outpoint, output.txout);
+ cc.Select(output.outpoint).SetTxOut(output.txout);
LOCK(wallet->cs_wallet);
const auto preset_inputs = *Assert(FetchSelectedInputs(*wallet, cc, cs_params));
diff --git a/src/wallet/test/fuzz/coincontrol.cpp b/src/wallet/test/fuzz/coincontrol.cpp
index 0f71f28df2..f1efbc1cb8 100644
--- a/src/wallet/test/fuzz/coincontrol.cpp
+++ b/src/wallet/test/fuzz/coincontrol.cpp
@@ -60,7 +60,7 @@ FUZZ_TARGET(coincontrol, .init = initialize_coincontrol)
},
[&] {
const CTxOut tx_out{ConsumeMoney(fuzzed_data_provider), ConsumeScript(fuzzed_data_provider)};
- (void)coin_control.SelectExternal(out_point, tx_out);
+ (void)coin_control.Select(out_point).SetTxOut(tx_out);
},
[&] {
(void)coin_control.UnSelect(out_point);
@@ -76,10 +76,7 @@ FUZZ_TARGET(coincontrol, .init = initialize_coincontrol)
(void)coin_control.SetInputWeight(out_point, weight);
},
[&] {
- // Condition to avoid the assertion in GetInputWeight
- if (coin_control.HasInputWeight(out_point)) {
- (void)coin_control.GetInputWeight(out_point);
- }
+ (void)coin_control.GetInputWeight(out_point);
});
}
}
diff --git a/src/wallet/test/fuzz/coinselection.cpp b/src/wallet/test/fuzz/coinselection.cpp
index 4caf96b18d..ade3ec3f60 100644
--- a/src/wallet/test/fuzz/coinselection.cpp
+++ b/src/wallet/test/fuzz/coinselection.cpp
@@ -116,7 +116,8 @@ FUZZ_TARGET(coinselection)
}
// Run coinselection algorithms
- auto result_bnb = SelectCoinsBnB(group_pos, target, coin_params.m_cost_of_change, MAX_STANDARD_TX_WEIGHT);
+ auto result_bnb = coin_params.m_subtract_fee_outputs ? util::Error{Untranslated("BnB disabled when SFFO is enabled")} :
+ SelectCoinsBnB(group_pos, target, coin_params.m_cost_of_change, MAX_STANDARD_TX_WEIGHT);
if (result_bnb) {
assert(result_bnb->GetChange(coin_params.m_cost_of_change, CAmount{0}) == 0);
assert(result_bnb->GetSelectedValue() >= target);
diff --git a/src/wallet/test/fuzz/notifications.cpp b/src/wallet/test/fuzz/notifications.cpp
index 82cdd32302..203ab5f606 100644
--- a/src/wallet/test/fuzz/notifications.cpp
+++ b/src/wallet/test/fuzz/notifications.cpp
@@ -156,10 +156,9 @@ struct FuzzedWallet {
coin_control.fOverrideFeeRate = fuzzed_data_provider.ConsumeBool();
// Add solving data (m_external_provider and SelectExternal)?
- CAmount fee_out;
int change_position{fuzzed_data_provider.ConsumeIntegralInRange<int>(-1, tx.vout.size() - 1)};
bilingual_str error;
- (void)FundTransaction(*wallet, tx, fee_out, change_position, error, /*lockUnspents=*/false, subtract_fee_from_outputs, coin_control);
+ (void)FundTransaction(*wallet, tx, change_position, /*lockUnspents=*/false, subtract_fee_from_outputs, coin_control);
}
};
diff --git a/src/wallet/test/spend_tests.cpp b/src/wallet/test/spend_tests.cpp
index 5926d88129..b2d252b3f9 100644
--- a/src/wallet/test/spend_tests.cpp
+++ b/src/wallet/test/spend_tests.cpp
@@ -28,13 +28,12 @@ BOOST_FIXTURE_TEST_CASE(SubtractFee, TestChain100Setup)
// instead of the miner.
auto check_tx = [&wallet](CAmount leftover_input_amount) {
CRecipient recipient{PubKeyDestination({}), 50 * COIN - leftover_input_amount, /*subtract_fee=*/true};
- constexpr int RANDOM_CHANGE_POSITION = -1;
CCoinControl coin_control;
coin_control.m_feerate.emplace(10000);
coin_control.fOverrideFeeRate = true;
// We need to use a change type with high cost of change so that the leftover amount will be dropped to fee instead of added as a change output
coin_control.m_change_type = OutputType::LEGACY;
- auto res = CreateTransaction(*wallet, {recipient}, RANDOM_CHANGE_POSITION, coin_control);
+ auto res = CreateTransaction(*wallet, {recipient}, std::nullopt, coin_control);
BOOST_CHECK(res);
const auto& txr = *res;
BOOST_CHECK_EQUAL(txr.tx->vout.size(), 1);
diff --git a/src/wallet/test/util.cpp b/src/wallet/test/util.cpp
index ad8613d515..cbf3ccd1ec 100644
--- a/src/wallet/test/util.cpp
+++ b/src/wallet/test/util.cpp
@@ -24,7 +24,6 @@ std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cc
LOCK2(wallet->cs_wallet, ::cs_main);
wallet->SetLastBlockProcessed(cchain.Height(), cchain.Tip()->GetBlockHash());
}
- wallet->LoadWallet();
{
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index dd43705a84..3d1cbe36a8 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -558,8 +558,7 @@ public:
CTransactionRef tx;
CCoinControl dummy;
{
- constexpr int RANDOM_CHANGE_POSITION = -1;
- auto res = CreateTransaction(*wallet, {recipient}, RANDOM_CHANGE_POSITION, dummy);
+ auto res = CreateTransaction(*wallet, {recipient}, std::nullopt, dummy);
BOOST_CHECK(res);
tx = res->tx;
}