Skip to content

Commit 71d1d13

Browse files
committed
test: add unit test for AvailableCoins
test that UTXOs are bucketed correctly after running AvailableCoins
1 parent da03cb4 commit 71d1d13

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

src/Makefile.test.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ BITCOIN_TESTS += \
167167
wallet/test/wallet_crypto_tests.cpp \
168168
wallet/test/wallet_transaction_tests.cpp \
169169
wallet/test/coinselector_tests.cpp \
170+
wallet/test/availablecoins_tests.cpp \
170171
wallet/test/init_tests.cpp \
171172
wallet/test/ismine_tests.cpp \
172173
wallet/test/scriptpubkeyman_tests.cpp
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Copyright (c) 2022 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or https://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <validation.h>
6+
#include <wallet/coincontrol.h>
7+
#include <wallet/spend.h>
8+
#include <wallet/test/util.h>
9+
#include <wallet/test/wallet_test_fixture.h>
10+
11+
#include <boost/test/unit_test.hpp>
12+
13+
namespace wallet {
14+
BOOST_FIXTURE_TEST_SUITE(availablecoins_tests, WalletTestingSetup)
15+
class AvailableCoinsTestingSetup : public TestChain100Setup
16+
{
17+
public:
18+
AvailableCoinsTestingSetup()
19+
{
20+
CreateAndProcessBlock({}, {});
21+
wallet = CreateSyncedWallet(*m_node.chain, m_node.chainman->ActiveChain(), m_args, coinbaseKey);
22+
}
23+
24+
~AvailableCoinsTestingSetup()
25+
{
26+
wallet.reset();
27+
}
28+
CWalletTx& AddTx(CRecipient recipient)
29+
{
30+
CTransactionRef tx;
31+
CCoinControl dummy;
32+
{
33+
constexpr int RANDOM_CHANGE_POSITION = -1;
34+
auto res = CreateTransaction(*wallet, {recipient}, RANDOM_CHANGE_POSITION, dummy);
35+
BOOST_CHECK(res);
36+
tx = res.GetObj().tx;
37+
}
38+
wallet->CommitTransaction(tx, {}, {});
39+
CMutableTransaction blocktx;
40+
{
41+
LOCK(wallet->cs_wallet);
42+
blocktx = CMutableTransaction(*wallet->mapWallet.at(tx->GetHash()).tx);
43+
}
44+
CreateAndProcessBlock({CMutableTransaction(blocktx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
45+
46+
LOCK(wallet->cs_wallet);
47+
wallet->SetLastBlockProcessed(wallet->GetLastBlockHeight() + 1, m_node.chainman->ActiveChain().Tip()->GetBlockHash());
48+
auto it = wallet->mapWallet.find(tx->GetHash());
49+
BOOST_CHECK(it != wallet->mapWallet.end());
50+
it->second.m_state = TxStateConfirmed{m_node.chainman->ActiveChain().Tip()->GetBlockHash(), m_node.chainman->ActiveChain().Height(), /*index=*/1};
51+
return it->second;
52+
}
53+
54+
std::unique_ptr<CWallet> wallet;
55+
};
56+
57+
BOOST_FIXTURE_TEST_CASE(BasicOutputTypesTest, AvailableCoinsTestingSetup)
58+
{
59+
CoinsResult available_coins;
60+
BResult<CTxDestination> dest;
61+
LOCK(wallet->cs_wallet);
62+
63+
// Verify our wallet has one usable coinbase UTXO before starting
64+
// This UTXO is a P2PK, so it should show up in the Other bucket
65+
available_coins = AvailableCoins(*wallet);
66+
BOOST_CHECK_EQUAL(available_coins.size(), 1U);
67+
BOOST_CHECK_EQUAL(available_coins.other.size(), 1U);
68+
69+
// We will create a self transfer for each of the OutputTypes and
70+
// verify it is put in the correct bucket after running GetAvailablecoins
71+
//
72+
// For each OutputType, We expect 2 UTXOs in our wallet following the self transfer:
73+
// 1. One UTXO as the recipient
74+
// 2. One UTXO from the change, due to payment address matching logic
75+
76+
// Bech32m
77+
dest = wallet->GetNewDestination(OutputType::BECH32M, "");
78+
BOOST_ASSERT(dest.HasRes());
79+
AddTx(CRecipient{{GetScriptForDestination(dest.GetObj())}, 1 * COIN, /*fSubtractFeeFromAmount=*/true});
80+
available_coins = AvailableCoins(*wallet);
81+
BOOST_CHECK_EQUAL(available_coins.bech32m.size(), 2U);
82+
83+
// Bech32
84+
dest = wallet->GetNewDestination(OutputType::BECH32, "");
85+
BOOST_ASSERT(dest.HasRes());
86+
AddTx(CRecipient{{GetScriptForDestination(dest.GetObj())}, 2 * COIN, /*fSubtractFeeFromAmount=*/true});
87+
available_coins = AvailableCoins(*wallet);
88+
BOOST_CHECK_EQUAL(available_coins.bech32.size(), 2U);
89+
90+
// P2SH-SEGWIT
91+
dest = wallet->GetNewDestination(OutputType::P2SH_SEGWIT, "");
92+
AddTx(CRecipient{{GetScriptForDestination(dest.GetObj())}, 3 * COIN, /*fSubtractFeeFromAmount=*/true});
93+
available_coins = AvailableCoins(*wallet);
94+
BOOST_CHECK_EQUAL(available_coins.P2SH_segwit.size(), 2U);
95+
96+
// Legacy (P2PKH)
97+
dest = wallet->GetNewDestination(OutputType::LEGACY, "");
98+
BOOST_ASSERT(dest.HasRes());
99+
AddTx(CRecipient{{GetScriptForDestination(dest.GetObj())}, 4 * COIN, /*fSubtractFeeFromAmount=*/true});
100+
available_coins = AvailableCoins(*wallet);
101+
BOOST_CHECK_EQUAL(available_coins.legacy.size(), 2U);
102+
}
103+
104+
BOOST_AUTO_TEST_SUITE_END()
105+
} // namespace wallet

0 commit comments

Comments
 (0)