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.cpp27
-rw-r--r--src/wallet/test/fuzz/notifications.cpp170
-rw-r--r--src/wallet/test/ismine_tests.cpp40
-rw-r--r--src/wallet/test/psbt_wallet_tests.cpp7
-rw-r--r--src/wallet/test/scriptpubkeyman_tests.cpp2
-rw-r--r--src/wallet/test/spend_tests.cpp2
-rw-r--r--src/wallet/test/util.cpp4
-rw-r--r--src/wallet/test/util.h3
-rw-r--r--src/wallet/test/wallet_test_fixture.cpp9
-rw-r--r--src/wallet/test/wallet_test_fixture.h1
-rw-r--r--src/wallet/test/wallet_tests.cpp79
-rw-r--r--src/wallet/test/wallet_transaction_tests.cpp24
12 files changed, 287 insertions, 81 deletions
diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp
index 38edb61ba7..a1fa871ccb 100644
--- a/src/wallet/test/coinselector_tests.cpp
+++ b/src/wallet/test/coinselector_tests.cpp
@@ -86,13 +86,18 @@ static void add_coin(std::vector<COutput>& coins, CWallet& wallet, const CAmount
// so stop vin being empty, and cache a non-zero Debit to fake out IsFromMe()
tx.vin.resize(1);
}
- CWalletTx* wtx = wallet.AddToWallet(MakeTransactionRef(std::move(tx)), /* confirm= */ {});
+ uint256 txid = tx.GetHash();
+
+ LOCK(wallet.cs_wallet);
+ auto ret = wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(txid), std::forward_as_tuple(MakeTransactionRef(std::move(tx)), TxStateInactive{}));
+ assert(ret.second);
+ CWalletTx& wtx = (*ret.first).second;
if (fIsFromMe)
{
- wtx->m_amounts[CWalletTx::DEBIT].Set(ISMINE_SPENDABLE, 1);
- wtx->m_is_cache_empty = false;
+ wtx.m_amounts[CWalletTx::DEBIT].Set(ISMINE_SPENDABLE, 1);
+ wtx.m_is_cache_empty = false;
}
- COutput output(wallet, *wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
+ COutput output(wallet, wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
coins.push_back(output);
}
@@ -163,7 +168,7 @@ inline std::vector<OutputGroup>& KnapsackGroupOutputs(const std::vector<COutput>
/* long_term_feerate= */ CFeeRate(0), /* discard_feerate= */ CFeeRate(0),
/* tx_noinputs_size= */ 0, /* avoid_partial= */ false);
static std::vector<OutputGroup> static_groups;
- static_groups = GroupOutputs(wallet, coins, coin_selection_params, filter, /* positive_only */false);
+ static_groups = GroupOutputs(wallet, coins, coin_selection_params, filter, /*positive_only=*/false);
return static_groups;
}
@@ -300,7 +305,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
/* long_term_feerate= */ CFeeRate(1000), /* discard_feerate= */ CFeeRate(1000),
/* tx_noinputs_size= */ 0, /* avoid_partial= */ false);
{
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", m_args, CreateMockWalletDatabase());
wallet->LoadWallet();
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -323,7 +328,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
}
{
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", m_args, CreateMockWalletDatabase());
wallet->LoadWallet();
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -345,7 +350,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test)
BOOST_AUTO_TEST_CASE(knapsack_solver_test)
{
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", m_args, CreateMockWalletDatabase());
wallet->LoadWallet();
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -654,7 +659,7 @@ BOOST_AUTO_TEST_CASE(knapsack_solver_test)
BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
{
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", m_args, CreateMockWalletDatabase());
wallet->LoadWallet();
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -676,7 +681,7 @@ BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
// 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)
{
- std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", CreateMockWalletDatabase());
+ std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", m_args, CreateMockWalletDatabase());
wallet->LoadWallet();
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -784,7 +789,7 @@ BOOST_AUTO_TEST_CASE(waste_test)
add_coin(1 * COIN, 1, selection, fee, fee);
add_coin(2 * COIN, 2, selection, fee, fee);
const CAmount exact_target{in_amt - fee * 2};
- BOOST_CHECK_EQUAL(0, GetSelectionWaste(selection, /* change_cost */ 0, exact_target));
+ BOOST_CHECK_EQUAL(0, GetSelectionWaste(selection, /*change_cost=*/0, exact_target));
selection.clear();
// No Waste when (fee - long_term_fee) == (-cost_of_change), and no excess
diff --git a/src/wallet/test/fuzz/notifications.cpp b/src/wallet/test/fuzz/notifications.cpp
new file mode 100644
index 0000000000..0601c492cd
--- /dev/null
+++ b/src/wallet/test/fuzz/notifications.cpp
@@ -0,0 +1,170 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+#include <test/util/setup_common.h>
+#include <util/translation.h>
+#include <wallet/context.h>
+#include <wallet/receive.h>
+#include <wallet/wallet.h>
+#include <wallet/walletdb.h>
+#include <wallet/walletutil.h>
+
+#include <cassert>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace {
+const TestingSetup* g_setup;
+
+void initialize_setup()
+{
+ static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
+ g_setup = testing_setup.get();
+}
+
+/**
+ * Wraps a descriptor wallet for fuzzing. The constructor writes the sqlite db
+ * to disk, the destructor deletes it.
+ */
+struct FuzzedWallet {
+ ArgsManager args;
+ WalletContext context;
+ std::shared_ptr<CWallet> wallet;
+ FuzzedWallet(const std::string& name)
+ {
+ context.args = &args;
+ context.chain = g_setup->m_node.chain.get();
+
+ DatabaseOptions options;
+ options.require_create = true;
+ options.create_flags = WALLET_FLAG_DESCRIPTORS;
+ const std::optional<bool> load_on_start;
+ gArgs.ForceSetArg("-keypool", "0"); // Avoid timeout in TopUp()
+
+ DatabaseStatus status;
+ bilingual_str error;
+ std::vector<bilingual_str> warnings;
+ wallet = CreateWallet(context, name, load_on_start, options, status, error, warnings);
+ assert(wallet);
+ assert(error.empty());
+ assert(warnings.empty());
+ assert(wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
+ }
+ ~FuzzedWallet()
+ {
+ const auto name{wallet->GetName()};
+ std::vector<bilingual_str> warnings;
+ std::optional<bool> load_on_start;
+ assert(RemoveWallet(context, wallet, load_on_start, warnings));
+ assert(warnings.empty());
+ UnloadWallet(std::move(wallet));
+ fs::remove_all(GetWalletDir() / name);
+ }
+ CScript GetScriptPubKey(FuzzedDataProvider& fuzzed_data_provider)
+ {
+ auto type{fuzzed_data_provider.PickValueInArray(OUTPUT_TYPES)};
+ CTxDestination dest;
+ bilingual_str error;
+ if (fuzzed_data_provider.ConsumeBool()) {
+ assert(wallet->GetNewDestination(type, "", dest, error));
+ } else {
+ assert(wallet->GetNewChangeDestination(type, dest, error));
+ }
+ assert(error.empty());
+ return GetScriptForDestination(dest);
+ }
+};
+
+FUZZ_TARGET_INIT(wallet_notifications, initialize_setup)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ // The total amount, to be distributed to the wallets a and b in txs
+ // without fee. Thus, the balance of the wallets should always equal the
+ // total amount.
+ const auto total_amount{ConsumeMoney(fuzzed_data_provider)};
+ FuzzedWallet a{"fuzzed_wallet_a"};
+ FuzzedWallet b{"fuzzed_wallet_b"};
+
+ // Keep track of all coins in this test.
+ // Each tuple in the chain represents the coins and the block created with
+ // those coins. Once the block is mined, the next tuple will have an empty
+ // block and the freshly mined coins.
+ using Coins = std::set<std::tuple<CAmount, COutPoint>>;
+ std::vector<std::tuple<Coins, CBlock>> chain;
+ {
+ // Add the initial entry
+ chain.emplace_back();
+ auto& [coins, block]{chain.back()};
+ coins.emplace(total_amount, COutPoint{uint256::ONE, 1});
+ }
+ LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 200)
+ {
+ CallOneOf(
+ fuzzed_data_provider,
+ [&] {
+ auto& [coins_orig, block]{chain.back()};
+ // Copy the coins for this block and consume all of them
+ Coins coins = coins_orig;
+ while (!coins.empty()) {
+ // Create a new tx
+ CMutableTransaction tx{};
+ // Add some coins as inputs to it
+ auto num_inputs{fuzzed_data_provider.ConsumeIntegralInRange<int>(1, coins.size())};
+ CAmount in{0};
+ while (num_inputs-- > 0) {
+ const auto& [coin_amt, coin_outpoint]{*coins.begin()};
+ in += coin_amt;
+ tx.vin.emplace_back(coin_outpoint);
+ coins.erase(coins.begin());
+ }
+ // Create some outputs spending all inputs, without fee
+ LIMITED_WHILE(in > 0 && fuzzed_data_provider.ConsumeBool(), 100)
+ {
+ const auto out_value{ConsumeMoney(fuzzed_data_provider, in)};
+ in -= out_value;
+ auto& wallet{fuzzed_data_provider.ConsumeBool() ? a : b};
+ tx.vout.emplace_back(out_value, wallet.GetScriptPubKey(fuzzed_data_provider));
+ }
+ // Spend the remaining input value, if any
+ auto& wallet{fuzzed_data_provider.ConsumeBool() ? a : b};
+ tx.vout.emplace_back(in, wallet.GetScriptPubKey(fuzzed_data_provider));
+ // Add tx to block
+ block.vtx.emplace_back(MakeTransactionRef(tx));
+ }
+ // Mine block
+ a.wallet->blockConnected(block, chain.size());
+ b.wallet->blockConnected(block, chain.size());
+ // Store the coins for the next block
+ Coins coins_new;
+ for (const auto& tx : block.vtx) {
+ uint32_t i{0};
+ for (const auto& out : tx->vout) {
+ coins_new.emplace(out.nValue, COutPoint{tx->GetHash(), i++});
+ }
+ }
+ chain.emplace_back(coins_new, CBlock{});
+ },
+ [&] {
+ if (chain.size() <= 1) return; // The first entry can't be removed
+ auto& [coins, block]{chain.back()};
+ if (block.vtx.empty()) return; // Can only disconnect if the block was submitted first
+ // Disconnect block
+ a.wallet->blockDisconnected(block, chain.size() - 1);
+ b.wallet->blockDisconnected(block, chain.size() - 1);
+ chain.pop_back();
+ });
+ auto& [coins, first_block]{chain.front()};
+ if (!first_block.vtx.empty()) {
+ // Only check balance when at least one block was submitted
+ const auto bal_a{GetBalance(*a.wallet).m_mine_trusted};
+ const auto bal_b{GetBalance(*b.wallet).m_mine_trusted};
+ assert(total_amount == bal_a + bal_b);
+ }
+ }
+}
+} // namespace
diff --git a/src/wallet/test/ismine_tests.cpp b/src/wallet/test/ismine_tests.cpp
index 5d25885bd4..dda202d55e 100644
--- a/src/wallet/test/ismine_tests.cpp
+++ b/src/wallet/test/ismine_tests.cpp
@@ -34,7 +34,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PK compressed
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
@@ -51,7 +51,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PK uncompressed
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
@@ -68,7 +68,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PKH compressed
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
@@ -85,7 +85,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2PKH uncompressed
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
@@ -102,7 +102,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2SH
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -126,7 +126,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2SH inside P2SH (invalid)
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -144,7 +144,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2SH inside P2WSH (invalid)
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH inside P2WSH (invalid)
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -178,7 +178,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// (P2PKH inside) P2WSH inside P2WSH (invalid)
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -196,7 +196,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH compressed
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -211,7 +211,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WPKH uncompressed
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
@@ -230,7 +230,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// scriptPubKey multisig
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -261,7 +261,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2SH multisig
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
@@ -282,7 +282,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig with compressed keys
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -308,7 +308,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig with uncompressed key
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(uncompressedKey));
@@ -334,7 +334,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// P2WSH multisig wrapped in P2SH
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
@@ -361,7 +361,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// OP_RETURN
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -375,7 +375,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// witness unspendable
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -389,7 +389,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// witness unknown
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
@@ -403,7 +403,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Nonstandard
{
- CWallet keystore(chain.get(), "", CreateDummyWalletDatabase());
+ CWallet keystore(chain.get(), "", m_args, CreateDummyWalletDatabase());
keystore.SetupLegacyScriptPubKeyMan();
LOCK(keystore.GetLegacyScriptPubKeyMan()->cs_KeyStore);
BOOST_CHECK(keystore.GetLegacyScriptPubKeyMan()->AddKey(keys[0]));
diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp
index 120a20749e..7bc2bb5583 100644
--- a/src/wallet/test/psbt_wallet_tests.cpp
+++ b/src/wallet/test/psbt_wallet_tests.cpp
@@ -14,8 +14,9 @@
BOOST_FIXTURE_TEST_SUITE(psbt_wallet_tests, WalletTestingSetup)
static void import_descriptor(CWallet& wallet, const std::string& descriptor)
+ EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
{
- LOCK(wallet.cs_wallet);
+ AssertLockHeld(wallet.cs_wallet);
FlatSigningProvider provider;
std::string error;
std::unique_ptr<Descriptor> desc = Parse(descriptor, provider, error, /* require_checksum=*/ false);
@@ -33,12 +34,12 @@ BOOST_AUTO_TEST_CASE(psbt_updater_test)
CDataStream s_prev_tx1(ParseHex("0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000"), SER_NETWORK, PROTOCOL_VERSION);
CTransactionRef prev_tx1;
s_prev_tx1 >> prev_tx1;
- m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx1->GetHash()), std::forward_as_tuple(prev_tx1));
+ m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx1->GetHash()), std::forward_as_tuple(prev_tx1, TxStateInactive{}));
CDataStream s_prev_tx2(ParseHex("0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000"), SER_NETWORK, PROTOCOL_VERSION);
CTransactionRef prev_tx2;
s_prev_tx2 >> prev_tx2;
- m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx2->GetHash()), std::forward_as_tuple(prev_tx2));
+ m_wallet.mapWallet.emplace(std::piecewise_construct, std::forward_as_tuple(prev_tx2->GetHash()), std::forward_as_tuple(prev_tx2, TxStateInactive{}));
// Import descriptors for keys and scripts
import_descriptor(m_wallet, "sh(multi(2,xprv9s21ZrQH143K2LE7W4Xf3jATf9jECxSb7wj91ZnmY4qEJrS66Qru9RFqq8xbkgT32ya6HqYJweFdJUEDf5Q6JFV7jMiUws7kQfe6Tv4RbfN/0h/0h/0h,xprv9s21ZrQH143K2LE7W4Xf3jATf9jECxSb7wj91ZnmY4qEJrS66Qru9RFqq8xbkgT32ya6HqYJweFdJUEDf5Q6JFV7jMiUws7kQfe6Tv4RbfN/0h/0h/1h))");
diff --git a/src/wallet/test/scriptpubkeyman_tests.cpp b/src/wallet/test/scriptpubkeyman_tests.cpp
index 347a436429..0e78855ced 100644
--- a/src/wallet/test/scriptpubkeyman_tests.cpp
+++ b/src/wallet/test/scriptpubkeyman_tests.cpp
@@ -17,7 +17,7 @@ BOOST_FIXTURE_TEST_SUITE(scriptpubkeyman_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(CanProvide)
{
// Set up wallet and keyman variables.
- CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ CWallet wallet(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
LegacyScriptPubKeyMan& keyman = *wallet.GetOrCreateLegacyScriptPubKeyMan();
// Make a 1 of 2 multisig script
diff --git a/src/wallet/test/spend_tests.cpp b/src/wallet/test/spend_tests.cpp
index d88d8eabdb..926f28686d 100644
--- a/src/wallet/test/spend_tests.cpp
+++ b/src/wallet/test/spend_tests.cpp
@@ -17,7 +17,7 @@ BOOST_FIXTURE_TEST_SUITE(spend_tests, WalletTestingSetup)
BOOST_FIXTURE_TEST_CASE(SubtractFee, TestChain100Setup)
{
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
- auto wallet = CreateSyncedWallet(*m_node.chain, m_node.chainman->ActiveChain(), coinbaseKey);
+ auto wallet = CreateSyncedWallet(*m_node.chain, m_node.chainman->ActiveChain(), m_args, coinbaseKey);
// Check that a subtract-from-recipient transaction slightly less than the
// coinbase input amount does not create a change output (because it would
diff --git a/src/wallet/test/util.cpp b/src/wallet/test/util.cpp
index 2990fc8f8d..93a3404d2c 100644
--- a/src/wallet/test/util.cpp
+++ b/src/wallet/test/util.cpp
@@ -15,9 +15,9 @@
#include <memory>
-std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, const CKey& key)
+std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, ArgsManager& args, const CKey& key)
{
- auto wallet = std::make_unique<CWallet>(&chain, "", CreateMockWalletDatabase());
+ auto wallet = std::make_unique<CWallet>(&chain, "", args, CreateMockWalletDatabase());
{
LOCK2(wallet->cs_wallet, ::cs_main);
wallet->SetLastBlockProcessed(cchain.Height(), cchain.Tip()->GetBlockHash());
diff --git a/src/wallet/test/util.h b/src/wallet/test/util.h
index 288c111571..3adb82b85f 100644
--- a/src/wallet/test/util.h
+++ b/src/wallet/test/util.h
@@ -7,6 +7,7 @@
#include <memory>
+class ArgsManager;
class CChain;
class CKey;
class CWallet;
@@ -14,6 +15,6 @@ namespace interfaces {
class Chain;
} // namespace interfaces
-std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, const CKey& key);
+std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, ArgsManager& args, const CKey& key);
#endif // BITCOIN_WALLET_TEST_UTIL_H
diff --git a/src/wallet/test/wallet_test_fixture.cpp b/src/wallet/test/wallet_test_fixture.cpp
index fc744ebe5b..762702522e 100644
--- a/src/wallet/test/wallet_test_fixture.cpp
+++ b/src/wallet/test/wallet_test_fixture.cpp
@@ -4,11 +4,18 @@
#include <wallet/test/wallet_test_fixture.h>
+#include <scheduler.h>
+
WalletTestingSetup::WalletTestingSetup(const std::string& chainName)
: TestingSetup(chainName),
- m_wallet(m_node.chain.get(), "", CreateMockWalletDatabase())
+ m_wallet(m_node.chain.get(), "", m_args, CreateMockWalletDatabase())
{
m_wallet.LoadWallet();
m_chain_notifications_handler = m_node.chain->handleNotifications({ &m_wallet, [](CWallet*) {} });
m_wallet_client->registerRpcs();
}
+
+WalletTestingSetup::~WalletTestingSetup()
+{
+ if (m_node.scheduler) m_node.scheduler->stop();
+}
diff --git a/src/wallet/test/wallet_test_fixture.h b/src/wallet/test/wallet_test_fixture.h
index ab7fb8c42b..8bf2d36227 100644
--- a/src/wallet/test/wallet_test_fixture.h
+++ b/src/wallet/test/wallet_test_fixture.h
@@ -19,6 +19,7 @@
*/
struct WalletTestingSetup : public TestingSetup {
explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
+ ~WalletTestingSetup();
std::unique_ptr<interfaces::WalletClient> m_wallet_client = interfaces::MakeWalletClient(*m_node.chain, *Assert(m_node.args));
CWallet m_wallet;
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 0965128ade..8cb3cede9b 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -41,7 +41,7 @@ static_assert(WALLET_INCREMENTAL_RELAY_FEE >= DEFAULT_INCREMENTAL_RELAY_FEE, "wa
BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
-static std::shared_ptr<CWallet> TestLoadWallet(WalletContext& context)
+static const std::shared_ptr<CWallet> TestLoadWallet(WalletContext& context)
{
DatabaseOptions options;
options.create_flags = WALLET_FLAG_DESCRIPTORS;
@@ -98,7 +98,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions fails to read an unknown start block.
{
- CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ CWallet wallet(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -118,7 +118,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions picks up transactions in both the old
// and new block files.
{
- CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ CWallet wallet(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -145,7 +145,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions only picks transactions in the new block
// file.
{
- CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ CWallet wallet(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -171,7 +171,7 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
// Verify ScanForWalletTransactions scans no blocks.
{
- CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ CWallet wallet(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
{
LOCK(wallet.cs_wallet);
wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -208,7 +208,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
// before the missing block, and success for a key whose creation time is
// after.
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
wallet->SetupLegacyScriptPubKeyMan();
WITH_LOCK(wallet->cs_wallet, wallet->SetLastBlockProcessed(newTip->nHeight, newTip->GetBlockHash()));
WalletContext context;
@@ -274,7 +274,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
{
WalletContext context;
context.args = &gArgs;
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
{
auto spk_man = wallet->GetOrCreateLegacyScriptPubKeyMan();
LOCK2(wallet->cs_wallet, spk_man->cs_KeyStore);
@@ -296,7 +296,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
// Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
// were scanned, and no prior blocks were scanned.
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
LOCK(wallet->cs_wallet);
wallet->SetupLegacyScriptPubKeyMan();
@@ -329,8 +329,8 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
// debit functions.
BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
{
- CWallet wallet(m_node.chain.get(), "", CreateDummyWalletDatabase());
- CWalletTx wtx(m_coinbase_txns.back());
+ CWallet wallet(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
+ CWalletTx wtx{m_coinbase_txns.back(), TxStateConfirmed{m_node.chainman->ActiveChain().Tip()->GetBlockHash(), m_node.chainman->ActiveChain().Height(), /*position_in_block=*/0}};
LOCK(wallet.cs_wallet);
wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
@@ -338,9 +338,6 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
wallet.SetLastBlockProcessed(m_node.chainman->ActiveChain().Height(), m_node.chainman->ActiveChain().Tip()->GetBlockHash());
- CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, m_node.chainman->ActiveChain().Height(), m_node.chainman->ActiveChain().Tip()->GetBlockHash(), 0);
- wtx.m_confirm = confirm;
-
// Call GetImmatureCredit() once before adding the key to the wallet to
// cache the current immature credit amount, which is 0.
BOOST_CHECK_EQUAL(CachedTxGetImmatureCredit(wallet, wtx), 0);
@@ -355,7 +352,7 @@ BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
static int64_t AddTx(ChainstateManager& chainman, CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64_t blockTime)
{
CMutableTransaction tx;
- CWalletTx::Confirmation confirm;
+ TxState state = TxStateInactive{};
tx.nLockTime = lockTime;
SetMockTime(mockTime);
CBlockIndex* block = nullptr;
@@ -367,13 +364,13 @@ static int64_t AddTx(ChainstateManager& chainman, CWallet& wallet, uint32_t lock
block = inserted.first->second;
block->nTime = blockTime;
block->phashBlock = &hash;
- confirm = {CWalletTx::Status::CONFIRMED, block->nHeight, hash, 0};
+ state = TxStateConfirmed{hash, block->nHeight, /*position_in_block=*/0};
}
-
- // If transaction is already in map, to avoid inconsistencies, unconfirmation
- // is needed before confirm again with different block.
- return wallet.AddToWallet(MakeTransactionRef(tx), confirm, [&](CWalletTx& wtx, bool /* new_tx */) {
- wtx.setUnconfirmed();
+ return wallet.AddToWallet(MakeTransactionRef(tx), state, [&](CWalletTx& wtx, bool /* new_tx */) {
+ // Assign wtx.m_state to simplify test and avoid the need to simulate
+ // reorg events. Without this, AddToWallet asserts false when the same
+ // transaction is confirmed in different blocks.
+ wtx.m_state = state;
return true;
})->nTimeSmart;
}
@@ -503,7 +500,7 @@ public:
ListCoinsTestingSetup()
{
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
- wallet = CreateSyncedWallet(*m_node.chain, m_node.chainman->ActiveChain(), coinbaseKey);
+ wallet = CreateSyncedWallet(*m_node.chain, m_node.chainman->ActiveChain(), m_args, coinbaseKey);
}
~ListCoinsTestingSetup()
@@ -534,8 +531,7 @@ public:
wallet->SetLastBlockProcessed(wallet->GetLastBlockHeight() + 1, m_node.chainman->ActiveChain().Tip()->GetBlockHash());
auto it = wallet->mapWallet.find(tx->GetHash());
BOOST_CHECK(it != wallet->mapWallet.end());
- CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, m_node.chainman->ActiveChain().Height(), m_node.chainman->ActiveChain().Tip()->GetBlockHash(), 1);
- it->second.m_confirm = confirm;
+ it->second.m_state = TxStateConfirmed{m_node.chainman->ActiveChain().Tip()->GetBlockHash(), m_node.chainman->ActiveChain().Height(), /*position_in_block=*/1};
return it->second;
}
@@ -606,7 +602,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoinsTest, ListCoinsTestingSetup)
BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
{
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
wallet->SetupLegacyScriptPubKeyMan();
wallet->SetMinVersion(FEATURE_LATEST);
wallet->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
@@ -616,7 +612,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
BOOST_CHECK(!wallet->GetNewDestination(OutputType::BECH32, "", dest, error));
}
{
- std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", CreateDummyWalletDatabase());
+ const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(m_node.chain.get(), "", m_args, CreateDummyWalletDatabase());
LOCK(wallet->cs_wallet);
wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
wallet->SetMinVersion(FEATURE_LATEST);
@@ -686,7 +682,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_descriptor_test, BasicTestingSetup)
vw << (int32_t)0;
vw << (int32_t)1;
- VectorReader vr(0, 0, malformed_record, 0);
+ SpanReader vr{0, 0, malformed_record};
WalletDescriptor w_desc;
BOOST_CHECK_EXCEPTION(vr >> w_desc, std::ios_base::failure, malformed_descriptor);
}
@@ -783,18 +779,14 @@ BOOST_FIXTURE_TEST_CASE(CreateWallet, TestChain100Setup)
// deadlock during the sync and simulates a new block notification happening
// as soon as possible.
addtx_count = 0;
- auto handler = HandleLoadWallet(context, [&](std::unique_ptr<interfaces::Wallet> wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet->wallet()->cs_wallet, context.wallets_mutex) {
+ auto handler = HandleLoadWallet(context, [&](std::unique_ptr<interfaces::Wallet> wallet) {
BOOST_CHECK(rescan_completed);
m_coinbase_txns.push_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
block_tx = TestSimpleSpend(*m_coinbase_txns[2], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
m_coinbase_txns.push_back(CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
mempool_tx = TestSimpleSpend(*m_coinbase_txns[3], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
BOOST_CHECK(m_node.chain->broadcastTransaction(MakeTransactionRef(mempool_tx), DEFAULT_TRANSACTION_MAXFEE, false, error));
- LEAVE_CRITICAL_SECTION(context.wallets_mutex);
- LEAVE_CRITICAL_SECTION(wallet->wallet()->cs_wallet);
SyncWithValidationInterfaceQueue();
- ENTER_CRITICAL_SECTION(wallet->wallet()->cs_wallet);
- ENTER_CRITICAL_SECTION(context.wallets_mutex);
});
wallet = TestLoadWallet(context);
BOOST_CHECK_EQUAL(addtx_count, 4);
@@ -824,30 +816,35 @@ BOOST_FIXTURE_TEST_CASE(ZapSelectTx, TestChain100Setup)
context.args = &gArgs;
context.chain = m_node.chain.get();
auto wallet = TestLoadWallet(context);
- CKey key;
- key.MakeNewKey(true);
- AddKey(*wallet, key);
+ AddKey(*wallet, coinbaseKey);
- std::string error;
+ // rescan to ensure coinbase transactions from test fixture are picked up by the wallet
+ {
+ WalletRescanReserver reserver(*wallet);
+ reserver.reserve();
+ wallet->ScanForWalletTransactions(m_node.chain->getBlockHash(0), 0, /* max height= */ {}, reserver, /* update= */ true);
+ }
+ // create one more block to get the first block coinbase to maturity
m_coinbase_txns.push_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
- auto block_tx = TestSimpleSpend(*m_coinbase_txns[0], 0, coinbaseKey, GetScriptForRawPubKey(key.GetPubKey()));
- CreateAndProcessBlock({block_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
+ // spend first coinbase tx
+ auto spend_tx = TestSimpleSpend(*m_coinbase_txns[0], 0, coinbaseKey, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
+ CreateAndProcessBlock({spend_tx}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
SyncWithValidationInterfaceQueue();
{
- auto block_hash = block_tx.GetHash();
+ auto spend_tx_hash = spend_tx.GetHash();
auto prev_hash = m_coinbase_txns[0]->GetHash();
LOCK(wallet->cs_wallet);
BOOST_CHECK(wallet->HasWalletSpend(prev_hash));
- BOOST_CHECK_EQUAL(wallet->mapWallet.count(block_hash), 1u);
+ BOOST_CHECK_EQUAL(wallet->mapWallet.count(spend_tx_hash), 1u);
- std::vector<uint256> vHashIn{ block_hash }, vHashOut;
+ std::vector<uint256> vHashIn{spend_tx_hash}, vHashOut;
BOOST_CHECK_EQUAL(wallet->ZapSelectTx(vHashIn, vHashOut), DBErrors::LOAD_OK);
BOOST_CHECK(!wallet->HasWalletSpend(prev_hash));
- BOOST_CHECK_EQUAL(wallet->mapWallet.count(block_hash), 0u);
+ BOOST_CHECK_EQUAL(wallet->mapWallet.count(spend_tx_hash), 0u);
}
TestUnloadWallet(std::move(wallet));
diff --git a/src/wallet/test/wallet_transaction_tests.cpp b/src/wallet/test/wallet_transaction_tests.cpp
new file mode 100644
index 0000000000..5ef2904f66
--- /dev/null
+++ b/src/wallet/test/wallet_transaction_tests.cpp
@@ -0,0 +1,24 @@
+// Copyright (c) 2021 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <wallet/transaction.h>
+
+#include <wallet/test/wallet_test_fixture.h>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(wallet_transaction_tests, WalletTestingSetup)
+
+BOOST_AUTO_TEST_CASE(roundtrip)
+{
+ for (uint8_t hash = 0; hash < 5; ++hash) {
+ for (int index = -2; index < 3; ++index) {
+ TxState state = TxStateInterpretSerialized(TxStateUnrecognized{uint256{hash}, index});
+ BOOST_CHECK_EQUAL(TxStateSerializedBlockHash(state), uint256{hash});
+ BOOST_CHECK_EQUAL(TxStateSerializedIndex(state), index);
+ }
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()