Bitcoin Core 29.99.0
P2P Digital Currency
util.cpp
Go to the documentation of this file.
1// Copyright (c) 2021-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <wallet/test/util.h>
6
7#include <chain.h>
8#include <key.h>
9#include <key_io.h>
10#include <streams.h>
12#include <validationinterface.h>
13#include <wallet/context.h>
14#include <wallet/wallet.h>
15#include <wallet/walletdb.h>
16
17#include <memory>
18
19namespace wallet {
20std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, const CKey& key)
21{
22 auto wallet = std::make_unique<CWallet>(&chain, "", CreateMockableWalletDatabase());
23 {
24 LOCK2(wallet->cs_wallet, ::cs_main);
25 wallet->SetLastBlockProcessed(cchain.Height(), cchain.Tip()->GetBlockHash());
26 }
27 {
28 LOCK(wallet->cs_wallet);
29 wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
30 wallet->SetupDescriptorScriptPubKeyMans();
31
32 FlatSigningProvider provider;
33 std::string error;
34 auto descs = Parse("combo(" + EncodeSecret(key) + ")", provider, error, /* require_checksum=*/ false);
35 assert(descs.size() == 1);
36 auto& desc = descs.at(0);
37 WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1);
38 auto spk_manager = *Assert(wallet->AddWalletDescriptor(w_desc, provider, "", false));
39 assert(spk_manager);
40 }
42 reserver.reserve();
43 CWallet::ScanResult result = wallet->ScanForWalletTransactions(cchain.Genesis()->GetBlockHash(), /*start_height=*/0, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false);
45 assert(result.last_scanned_block == cchain.Tip()->GetBlockHash());
46 assert(*result.last_scanned_height == cchain.Height());
48 return wallet;
49}
50
51std::shared_ptr<CWallet> TestLoadWallet(std::unique_ptr<WalletDatabase> database, WalletContext& context, uint64_t create_flags)
52{
53 bilingual_str error;
54 std::vector<bilingual_str> warnings;
55 auto wallet = CWallet::Create(context, "", std::move(database), create_flags, error, warnings);
56 NotifyWalletLoaded(context, wallet);
57 if (context.chain) {
58 wallet->postInitProcess();
59 }
60 return wallet;
61}
62
63std::shared_ptr<CWallet> TestLoadWallet(WalletContext& context)
64{
65 DatabaseOptions options;
67 DatabaseStatus status;
68 bilingual_str error;
69 std::vector<bilingual_str> warnings;
70 auto database = MakeWalletDatabase("", options, status, error);
71 return TestLoadWallet(std::move(database), context, options.create_flags);
72}
73
74void TestUnloadWallet(std::shared_ptr<CWallet>&& wallet)
75{
76 // Calls SyncWithValidationInterfaceQueue
77 wallet->chain().waitForNotificationsIfTipChanged({});
78 wallet->m_chain_notifications_handler.reset();
79 WaitForDeleteWallet(std::move(wallet));
80}
81
82std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database)
83{
84 return std::make_unique<MockableDatabase>(dynamic_cast<MockableDatabase&>(database).m_records);
85}
86
87std::string getnewaddress(CWallet& w)
88{
89 constexpr auto output_type = OutputType::BECH32;
90 return EncodeDestination(getNewDestination(w, output_type));
91}
92
94{
95 return *Assert(w.GetNewDestination(output_type, ""));
96}
97
98MockableCursor::MockableCursor(const MockableData& records, bool pass, std::span<const std::byte> prefix)
99{
100 m_pass = pass;
101 std::tie(m_cursor, m_cursor_end) = records.equal_range(BytePrefix{prefix});
102}
103
105{
106 if (!m_pass) {
107 return Status::FAIL;
108 }
109 if (m_cursor == m_cursor_end) {
110 return Status::DONE;
111 }
112 key.clear();
113 value.clear();
114 const auto& [key_data, value_data] = *m_cursor;
115 key.write(key_data);
116 value.write(value_data);
117 m_cursor++;
118 return Status::MORE;
119}
120
122{
123 if (!m_pass) {
124 return false;
125 }
126 SerializeData key_data{key.begin(), key.end()};
127 const auto& it = m_records.find(key_data);
128 if (it == m_records.end()) {
129 return false;
130 }
131 value.clear();
132 value.write(it->second);
133 return true;
134}
135
136bool MockableBatch::WriteKey(DataStream&& key, DataStream&& value, bool overwrite)
137{
138 if (!m_pass) {
139 return false;
140 }
141 SerializeData key_data{key.begin(), key.end()};
142 SerializeData value_data{value.begin(), value.end()};
143 auto [it, inserted] = m_records.emplace(key_data, value_data);
144 if (!inserted && overwrite) { // Overwrite if requested
145 it->second = value_data;
146 inserted = true;
147 }
148 return inserted;
149}
150
152{
153 if (!m_pass) {
154 return false;
155 }
156 SerializeData key_data{key.begin(), key.end()};
157 m_records.erase(key_data);
158 return true;
159}
160
162{
163 if (!m_pass) {
164 return false;
165 }
166 SerializeData key_data{key.begin(), key.end()};
167 return m_records.count(key_data) > 0;
168}
169
170bool MockableBatch::ErasePrefix(std::span<const std::byte> prefix)
171{
172 if (!m_pass) {
173 return false;
174 }
175 auto it = m_records.begin();
176 while (it != m_records.end()) {
177 auto& key = it->first;
178 if (key.size() < prefix.size() || std::search(key.begin(), key.end(), prefix.begin(), prefix.end()) != key.begin()) {
179 it++;
180 continue;
181 }
182 it = m_records.erase(it);
183 }
184 return true;
185}
186
187std::unique_ptr<WalletDatabase> CreateMockableWalletDatabase(MockableData records)
188{
189 return std::make_unique<MockableDatabase>(records);
190}
191
193{
194 return dynamic_cast<MockableDatabase&>(wallet.GetDatabase());
195}
196
197wallet::ScriptPubKeyMan* CreateDescriptor(CWallet& keystore, const std::string& desc_str, const bool success)
198{
200
202 std::string error;
203 auto parsed_descs = Parse(desc_str, keys, error, false);
204 Assert(success == (!parsed_descs.empty()));
205 if (!success) return nullptr;
206 auto& desc = parsed_descs.at(0);
207
208 const int64_t range_start = 0, range_end = 1, next_index = 0, timestamp = 1;
209
210 WalletDescriptor w_desc(std::move(desc), timestamp, range_start, range_end, next_index);
211
212 LOCK(keystore.cs_wallet);
213 auto spkm = Assert(keystore.AddWalletDescriptor(w_desc, keys,/*label=*/"", /*internal=*/false));
214 return spkm.value();
215};
216} // namespace wallet
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, PayToAnchor, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
Definition: addresstype.h:143
#define Assert(val)
Identity function.
Definition: check.h:106
uint256 GetBlockHash() const
Definition: chain.h:243
An in-memory indexed chain of blocks.
Definition: chain.h:417
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:433
CBlockIndex * Genesis() const
Returns the index entry for the genesis block of this chain, or nullptr if none.
Definition: chain.h:427
int Height() const
Return the maximal height in the chain.
Definition: chain.h:462
An encapsulated private key.
Definition: key.h:35
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:147
void write(std::span< const value_type > src)
Definition: streams.h:251
void clear()
Definition: streams.h:187
constexpr bool IsNull() const
Definition: uint256.h:48
Interface giving clients (wallet processes, maybe other analysis tools in the future) ability to acce...
Definition: chain.h:129
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:300
util::Result< ScriptPubKeyMan * > AddWalletDescriptor(WalletDescriptor &desc, const FlatSigningProvider &signing_provider, const std::string &label, bool internal) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Add a descriptor to the wallet, return a ScriptPubKeyMan & associated output type.
Definition: wallet.cpp:3719
util::Result< CTxDestination > GetNewDestination(const OutputType type, const std::string label)
Definition: wallet.cpp:2471
static std::shared_ptr< CWallet > Create(WalletContext &context, const std::string &name, std::unique_ptr< WalletDatabase > database, uint64_t wallet_creation_flags, bilingual_str &error, std::vector< bilingual_str > &warnings)
Definition: wallet.cpp:2824
RecursiveMutex cs_wallet
Main wallet lock.
Definition: wallet.h:445
bool ReadKey(DataStream &&key, DataStream &value) override
Definition: util.cpp:121
bool EraseKey(DataStream &&key) override
Definition: util.cpp:151
bool ErasePrefix(std::span< const std::byte > prefix) override
Definition: util.cpp:170
bool HasKey(DataStream &&key) override
Definition: util.cpp:161
MockableData & m_records
Definition: util.h:66
bool WriteKey(DataStream &&key, DataStream &&value, bool overwrite=true) override
Definition: util.cpp:136
MockableCursor(const MockableData &records, bool pass)
Definition: util.h:56
MockableData::const_iterator m_cursor_end
Definition: util.h:53
MockableData::const_iterator m_cursor
Definition: util.h:52
Status Next(DataStream &key, DataStream &value) override
Definition: util.cpp:104
A WalletDatabase whose contents and return values can be modified as needed for testing.
Definition: util.h:97
An instance of this class represents one database.
Definition: db.h:130
Descriptor with some wallet metadata.
Definition: walletutil.h:85
RAII object to check and reserve a wallet rescan.
Definition: wallet.h:1067
bool reserve(bool with_passphrase=false)
Definition: wallet.h:1077
static UniValue Parse(std::string_view raw)
Parse string to UniValue or throw runtime_error if string contains invalid JSON.
Definition: client.cpp:317
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:8
void BlockUntilSyncedToCurrentChain() const LOCKS_EXCLUDED(void SetWalletFlag(uint64_t flags)
Blocks until the wallet state is up-to-date to /at least/ the current chain at the time this function...
Definition: wallet.cpp:1663
std::string EncodeSecret(const CKey &key)
Definition: key_io.cpp:231
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:294
std::shared_ptr< CWallet > TestLoadWallet(std::unique_ptr< WalletDatabase > database, WalletContext &context, uint64_t create_flags)
Definition: util.cpp:51
std::unique_ptr< CWallet > CreateSyncedWallet(interfaces::Chain &chain, CChain &cchain, const CKey &key)
Definition: util.cpp:20
void TestUnloadWallet(std::shared_ptr< CWallet > &&wallet)
Definition: util.cpp:74
std::unique_ptr< WalletDatabase > MakeWalletDatabase(const std::string &name, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error_string)
Definition: wallet.cpp:2813
MockableDatabase & GetMockableDatabase(CWallet &wallet)
Definition: util.cpp:192
void NotifyWalletLoaded(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
Definition: wallet.cpp:220
wallet::ScriptPubKeyMan * CreateDescriptor(CWallet &keystore, const std::string &desc_str, const bool success)
Definition: util.cpp:197
std::unique_ptr< WalletDatabase > CreateMockableWalletDatabase(MockableData records)
Definition: util.cpp:187
std::unique_ptr< WalletDatabase > DuplicateMockDatabase(WalletDatabase &database)
Definition: util.cpp:82
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition: walletutil.h:74
void WaitForDeleteWallet(std::shared_ptr< CWallet > &&wallet)
Explicitly delete the wallet.
Definition: wallet.cpp:251
RPCHelpMan getnewaddress()
Definition: addresses.cpp:21
std::map< SerializeData, SerializeData, std::less<> > MockableData
Definition: util.h:47
CTxDestination getNewDestination(CWallet &w, OutputType output_type)
Returns a new destination, of an specific type, from the wallet.
Definition: util.cpp:93
DatabaseStatus
Definition: db.h:183
OutputType
Definition: outputtype.h:17
const char * prefix
Definition: rest.cpp:1009
Bilingual messages:
Definition: translation.h:24
std::optional< int > last_scanned_height
Definition: wallet.h:621
enum wallet::CWallet::ScanResult::@19 status
uint256 last_scanned_block
Hash and height of most recent block that was successfully scanned.
Definition: wallet.h:620
uint256 last_failed_block
Height of the most recent block that could not be scanned due to read errors or pruning.
Definition: wallet.h:627
uint64_t create_flags
Definition: db.h:173
WalletContext struct containing references to state shared between CWallet instances,...
Definition: context.h:36
interfaces::Chain * chain
Definition: context.h:37
#define LOCK2(cs1, cs2)
Definition: sync.h:258
#define LOCK(cs)
Definition: sync.h:257
assert(!tx.IsCoinBase())
std::vector< std::byte, zero_after_free_allocator< std::byte > > SerializeData
Byte-vector that clears its contents before deletion.
Definition: zeroafterfree.h:49