Bitcoin Core 32.99.0
P2P Digital Currency
walletload_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2022-present 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 <key.h>
6#include <script/descriptor.h>
7#include <wallet/test/util.h>
8#include <wallet/wallet.h>
9#include <test/util/common.h>
10#include <test/util/logging.h>
12
13#include <boost/test/unit_test.hpp>
14
15namespace wallet {
16
17BOOST_AUTO_TEST_SUITE(walletload_tests)
18
19class DummyDescriptor final : public Descriptor {
20private:
21 std::string desc;
22public:
23 explicit DummyDescriptor(const std::string& descriptor) : desc(descriptor) {};
24 ~DummyDescriptor() = default;
25
26 std::string ToString(bool compat_format) const override { return desc; }
27 std::string ToCanonicalString() const override { return desc; }
28 std::optional<OutputType> GetOutputType() const override { return OutputType::UNKNOWN; }
29
30 bool IsRange() const override { return true; }
31 bool IsSolvable() const override { return false; }
32 bool IsSingleType() const override { return true; }
33 bool HavePrivateKeys(const SigningProvider&) const override { return false; }
34 bool ToPrivateString(const SigningProvider& provider, std::string& out) const override { return false; }
35 bool ToNormalizedString(const SigningProvider& provider, std::string& out, const DescriptorCache* cache = nullptr) const override { return false; }
36 bool Expand(int pos, const SigningProvider& provider, std::vector<CScript>& output_scripts, FlatSigningProvider& out, DescriptorCache* write_cache = nullptr) const override { return false; };
37 bool ExpandFromCache(int pos, const DescriptorCache& read_cache, std::vector<CScript>& output_scripts, FlatSigningProvider& out) const override { return false; }
38 void ExpandPrivate(int pos, const SigningProvider& provider, FlatSigningProvider& out) const override {}
39 std::optional<int64_t> ScriptSize() const override { return {}; }
40 std::optional<int64_t> MaxSatisfactionWeight(bool) const override { return {}; }
41 std::optional<int64_t> MaxSatisfactionElems() const override { return {}; }
42 void GetPubKeys(std::set<CPubKey>& pubkeys, std::set<CExtPubKey>& ext_pubs) const override {}
43 bool HasScripts() const override { return true; }
44 std::vector<std::string> Warnings() const override { return {}; }
45 uint32_t GetMaxKeyExpr() const override { return 0; }
46 size_t GetKeyCount() const override { return 0; }
47 bool CanSelfExpand() const final { return false; }
48};
49
50BOOST_FIXTURE_TEST_CASE(wallet_load_descriptors, TestingSetup)
51{
52 bilingual_str _error;
53 std::vector<bilingual_str> _warnings;
54 std::unique_ptr<WalletDatabase> database = CreateMockableWalletDatabase();
55 {
56 // Write unknown active descriptor
57 WalletBatch batch(*database);
58 std::string unknown_desc = "trx(tpubD6NzVbkrYhZ4Y4S7m6Y5s9GD8FqEMBy56AGphZXuagajudVZEnYyBahZMgHNCTJc2at82YX6s8JiL1Lohu5A3v1Ur76qguNH4QVQ7qYrBQx/86'/1'/0'/0/*)#8pn8tzdt";
59 WalletDescriptor wallet_descriptor(std::make_shared<DummyDescriptor>(unknown_desc), 0, 0, 0, 0);
60 BOOST_CHECK(batch.WriteDescriptor(uint256(), wallet_descriptor));
61 BOOST_CHECK(batch.WriteActiveScriptPubKeyMan(static_cast<uint8_t>(OutputType::UNKNOWN), uint256(), false));
62 }
63
64 {
65 // Now try to load the wallet and verify the error.
66 const std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(database)));
67 BOOST_CHECK_EQUAL(wallet->PopulateWalletFromDB(_error, _warnings), DBErrors::UNKNOWN_DESCRIPTOR);
68 }
69
70 // Test 2
71 // Now write a valid descriptor with a different ID which must be accepted
73
74 {
75 // Write valid descriptor with arbitrary ID
76 WalletBatch batch(*database);
77 std::string desc = "wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#cjjspncu";
78 WalletDescriptor wallet_descriptor(std::make_shared<DummyDescriptor>(desc), 0, 0, 0, 0);
79 BOOST_CHECK(batch.WriteDescriptor(uint256::ONE, wallet_descriptor));
80 }
81
82 {
83 // Now try to load the wallet and verify the result.
84 const std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(database)));
85 BOOST_CHECK_EQUAL(wallet->PopulateWalletFromDB(_error, _warnings), DBErrors::LOAD_OK);
86 }
87}
88
89BOOST_FIXTURE_TEST_CASE(wallet_load_descriptor_cache_invalid_xpub_size, TestingSetup)
90{
91 // A cache record whose serialized xpub is not exactly BIP32_EXTKEY_SIZE bytes must be
92 // rejected as corruption.
93 bilingual_str error;
94 std::vector<bilingual_str> warnings;
95
96 const std::string desc_str = "wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#cjjspncu";
98 std::string parse_error;
99 std::vector<std::unique_ptr<Descriptor>> descs = Parse(desc_str, keys, parse_error, /*require_checksum=*/true);
100 BOOST_REQUIRE_MESSAGE(descs.size() == 1, parse_error);
101 std::shared_ptr<Descriptor> descriptor = std::move(descs.at(0));
102 const uint256 desc_id = CompatDescriptorHash(*descriptor);
103
104 auto make_db_with_short_cache_xpub = [&](const std::string& cache_type) {
105 std::unique_ptr<WalletDatabase> database = CreateMockableWalletDatabase();
106 {
107 WalletBatch batch(*database);
108 WalletDescriptor wallet_descriptor(descriptor, 0, 0, 0, 0);
109 BOOST_CHECK(batch.WriteDescriptor(desc_id, wallet_descriptor));
110 }
111 const std::vector<unsigned char> short_xpub(BIP32_EXTKEY_SIZE - 1, 0);
112 std::unique_ptr<DatabaseBatch> raw = database->MakeBatch();
113 BOOST_CHECK(raw->Write(std::make_pair(std::make_pair(cache_type, desc_id), uint32_t{0}), short_xpub));
114 return database;
115 };
116
117 {
118 std::unique_ptr<WalletDatabase> database = make_db_with_short_cache_xpub("walletdescriptorcache");
119 ASSERT_DEBUG_LOG("descriptor cache xpub has invalid size");
120 const std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(database)));
121 BOOST_CHECK_EQUAL(wallet->PopulateWalletFromDB(error, warnings), DBErrors::CORRUPT);
122 }
123
124 {
125 std::unique_ptr<WalletDatabase> database = make_db_with_short_cache_xpub("walletdescriptorlhcache");
126 ASSERT_DEBUG_LOG("descriptor last hardened cache xpub has invalid size");
127 const std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(database)));
128 BOOST_CHECK_EQUAL(wallet->PopulateWalletFromDB(error, warnings), DBErrors::CORRUPT);
129 }
130}
131
133} // namespace wallet
node::NodeContext m_node
Definition: bitcoin-gui.cpp:48
Cache for single descriptor's derived extended pubkeys.
Definition: descriptor.h:30
An interface to be implemented by keystores that support signing.
256-bit opaque blob.
Definition: uint256.h:196
static const uint256 ONE
Definition: uint256.h:205
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:318
bool IsSolvable() const override
Whether this descriptor has all information about signing ignoring lack of private keys.
std::string ToString(bool compat_format) const override
Convert the descriptor back to a string, undoing parsing.
void GetPubKeys(std::set< CPubKey > &pubkeys, std::set< CExtPubKey > &ext_pubs) const override
Return all (extended) public keys for this descriptor, including any from subdescriptors.
bool HavePrivateKeys(const SigningProvider &) const override
Whether the given provider has all private keys required by this descriptor.
bool ToNormalizedString(const SigningProvider &provider, std::string &out, const DescriptorCache *cache=nullptr) const override
Convert the descriptor to a normalized string.
bool CanSelfExpand() const final
Whether the descriptor can be used to produce its address(es) without needing a cache or private keys...
void ExpandPrivate(int pos, const SigningProvider &provider, FlatSigningProvider &out) const override
Expand the private key for a descriptor at a specified position, if possible.
bool ToPrivateString(const SigningProvider &provider, std::string &out) const override
Convert the descriptor to a private string.
bool Expand(int pos, const SigningProvider &provider, std::vector< CScript > &output_scripts, FlatSigningProvider &out, DescriptorCache *write_cache=nullptr) const override
Expand a descriptor at a specified position.
std::string ToCanonicalString() const override
Convert the descriptor to the canonical string.
uint32_t GetMaxKeyExpr() const override
Get the maximum key expression index.
std::optional< int64_t > MaxSatisfactionWeight(bool) const override
Get the maximum size of a satisfaction for this descriptor, in weight units.
size_t GetKeyCount() const override
Get the number of key expressions in this descriptor.
bool ExpandFromCache(int pos, const DescriptorCache &read_cache, std::vector< CScript > &output_scripts, FlatSigningProvider &out) const override
Expand a descriptor at a specified position using cached expansion data.
bool IsRange() const override
Whether the expansion of this descriptor depends on the position.
std::optional< OutputType > GetOutputType() const override
bool IsSingleType() const override
Whether this descriptor will return at most one scriptPubKey or multiple (aka is or is not combo)
bool HasScripts() const override
Whether this descriptor produces any scripts with the Expand functions.
std::vector< std::string > Warnings() const override
Semantic/safety warnings (includes subdescriptors).
std::optional< int64_t > MaxSatisfactionElems() const override
Get the maximum size number of stack elements for satisfying this descriptor.
std::optional< int64_t > ScriptSize() const override
Get the size of the scriptPubKey for this descriptor.
DummyDescriptor(const std::string &descriptor)
Access to the wallet database.
Definition: walletdb.h:199
bool WriteDescriptor(const uint256 &desc_id, const WalletDescriptor &descriptor)
Definition: walletdb.cpp:253
bool WriteActiveScriptPubKeyMan(uint8_t type, const uint256 &id, bool internal)
Definition: walletdb.cpp:217
Descriptor with some wallet metadata.
Definition: walletutil.h:86
static UniValue Parse(std::string_view raw, ParamFormat format=ParamFormat::JSON)
Parse string to UniValue or throw runtime_error if string contains invalid JSON.
Definition: client.cpp:411
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_EQUAL(headers.FindFirst("key"), "value")
std::unique_ptr< WalletDatabase > CreateMockableWalletDatabase()
Definition: util.cpp:126
BOOST_FIXTURE_TEST_CASE(wallet_coinsresult_test, BasicTestingSetup)
#define BOOST_CHECK(expr)
Definition: object.cpp:16
constexpr unsigned int BIP32_EXTKEY_SIZE
Definition: pubkey.h:22
uint256 CompatDescriptorHash(const Descriptor &desc)
Hash of the COMPAT string representation of the descriptor that is not supposed to change over time.
Interface for parsed descriptor objects.
Definition: descriptor.h:109
Testing setup that configures a complete environment.
Definition: setup_common.h:119
Bilingual messages:
Definition: translation.h:24
std::unique_ptr< interfaces::Chain > chain
Definition: context.h:78
std::vector< uint16_t > keys
Definition: dbwrapper.cpp:376
FuzzedDataProvider provider
Definition: dbwrapper.cpp:366
#define ASSERT_DEBUG_LOG(message)
Definition: logging.h:42
std::shared_ptr< CWallet > wallet