Bitcoin Core  26.99.0
P2P Digital Currency
util.cpp
Go to the documentation of this file.
1 // Copyright (c) 2021-2022 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>
11 #include <test/util/setup_common.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 
19 namespace wallet {
20 std::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  std::unique_ptr<Descriptor> desc = Parse("combo(" + EncodeSecret(key) + ")", provider, error, /* require_checksum=*/ false);
35  assert(desc);
36  WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1);
37  if (!wallet->AddWalletDescriptor(w_desc, provider, "", false)) assert(false);
38  }
39  WalletRescanReserver reserver(*wallet);
40  reserver.reserve();
41  CWallet::ScanResult result = wallet->ScanForWalletTransactions(cchain.Genesis()->GetBlockHash(), /*start_height=*/0, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false);
43  assert(result.last_scanned_block == cchain.Tip()->GetBlockHash());
44  assert(*result.last_scanned_height == cchain.Height());
46  return wallet;
47 }
48 
49 std::shared_ptr<CWallet> TestLoadWallet(std::unique_ptr<WalletDatabase> database, WalletContext& context, uint64_t create_flags)
50 {
52  std::vector<bilingual_str> warnings;
53  auto wallet = CWallet::Create(context, "", std::move(database), create_flags, error, warnings);
54  NotifyWalletLoaded(context, wallet);
55  if (context.chain) {
56  wallet->postInitProcess();
57  }
58  return wallet;
59 }
60 
61 std::shared_ptr<CWallet> TestLoadWallet(WalletContext& context)
62 {
63  DatabaseOptions options;
65  DatabaseStatus status;
67  std::vector<bilingual_str> warnings;
68  auto database = MakeWalletDatabase("", options, status, error);
69  return TestLoadWallet(std::move(database), context, options.create_flags);
70 }
71 
72 void TestUnloadWallet(std::shared_ptr<CWallet>&& wallet)
73 {
75  wallet->m_chain_notifications_handler.reset();
76  UnloadWallet(std::move(wallet));
77 }
78 
79 std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database)
80 {
81  return std::make_unique<MockableDatabase>(dynamic_cast<MockableDatabase&>(database).m_records);
82 }
83 
84 std::string getnewaddress(CWallet& w)
85 {
86  constexpr auto output_type = OutputType::BECH32;
87  return EncodeDestination(getNewDestination(w, output_type));
88 }
89 
91 {
92  return *Assert(w.GetNewDestination(output_type, ""));
93 }
94 
95 // BytePrefix compares equality with other byte spans that begin with the same prefix.
97 bool operator<(BytePrefix a, Span<const std::byte> b) { return a.prefix < b.subspan(0, std::min(a.prefix.size(), b.size())); }
98 bool operator<(Span<const std::byte> a, BytePrefix b) { return a.subspan(0, std::min(a.size(), b.prefix.size())) < b.prefix; }
99 
101 {
102  m_pass = pass;
103  std::tie(m_cursor, m_cursor_end) = records.equal_range(BytePrefix{prefix});
104 }
105 
107 {
108  if (!m_pass) {
109  return Status::FAIL;
110  }
111  if (m_cursor == m_cursor_end) {
112  return Status::DONE;
113  }
114  key.clear();
115  value.clear();
116  const auto& [key_data, value_data] = *m_cursor;
117  key.write(key_data);
118  value.write(value_data);
119  m_cursor++;
120  return Status::MORE;
121 }
122 
124 {
125  if (!m_pass) {
126  return false;
127  }
128  SerializeData key_data{key.begin(), key.end()};
129  const auto& it = m_records.find(key_data);
130  if (it == m_records.end()) {
131  return false;
132  }
133  value.clear();
134  value.write(it->second);
135  return true;
136 }
137 
138 bool MockableBatch::WriteKey(DataStream&& key, DataStream&& value, bool overwrite)
139 {
140  if (!m_pass) {
141  return false;
142  }
143  SerializeData key_data{key.begin(), key.end()};
144  SerializeData value_data{value.begin(), value.end()};
145  auto [it, inserted] = m_records.emplace(key_data, value_data);
146  if (!inserted && overwrite) { // Overwrite if requested
147  it->second = value_data;
148  inserted = true;
149  }
150  return inserted;
151 }
152 
154 {
155  if (!m_pass) {
156  return false;
157  }
158  SerializeData key_data{key.begin(), key.end()};
159  m_records.erase(key_data);
160  return true;
161 }
162 
164 {
165  if (!m_pass) {
166  return false;
167  }
168  SerializeData key_data{key.begin(), key.end()};
169  return m_records.count(key_data) > 0;
170 }
171 
173 {
174  if (!m_pass) {
175  return false;
176  }
177  auto it = m_records.begin();
178  while (it != m_records.end()) {
179  auto& key = it->first;
180  if (key.size() < prefix.size() || std::search(key.begin(), key.end(), prefix.begin(), prefix.end()) != key.begin()) {
181  it++;
182  continue;
183  }
184  it = m_records.erase(it);
185  }
186  return true;
187 }
188 
189 std::unique_ptr<WalletDatabase> CreateMockableWalletDatabase(MockableData records)
190 {
191  return std::make_unique<MockableDatabase>(records);
192 }
193 
195 {
196  return dynamic_cast<MockableDatabase&>(wallet.GetDatabase());
197 }
198 } // namespace wallet
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
Definition: addresstype.h:131
#define Assert(val)
Identity function.
Definition: check.h:77
uint256 GetBlockHash() const
Definition: chain.h:258
An in-memory indexed chain of blocks.
Definition: chain.h:447
CBlockIndex * Genesis() const
Returns the index entry for the genesis block of this chain, or nullptr if none.
Definition: chain.h:457
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:463
int Height() const
Return the maximal height in the chain.
Definition: chain.h:492
An encapsulated private key.
Definition: key.h:33
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:147
void write(Span< const value_type > src)
Definition: streams.h:251
void clear()
Definition: streams.h:187
constexpr std::size_t size() const noexcept
Definition: span.h:187
CONSTEXPR_IF_NOT_DEBUG Span< C > subspan(std::size_t offset) const noexcept
Definition: span.h:195
constexpr bool IsNull() const
Definition: uint256.h:42
Interface giving clients (wallet processes, maybe other analysis tools in the future) ability to acce...
Definition: chain.h:124
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:301
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:2913
bool ReadKey(DataStream &&key, DataStream &value) override
Definition: util.cpp:123
bool EraseKey(DataStream &&key) override
Definition: util.cpp:153
bool HasKey(DataStream &&key) override
Definition: util.cpp:163
bool ErasePrefix(Span< const std::byte > prefix) override
Definition: util.cpp:172
MockableData & m_records
Definition: util.h:74
bool WriteKey(DataStream &&key, DataStream &&value, bool overwrite=true) override
Definition: util.cpp:138
MockableCursor(const MockableData &records, bool pass)
Definition: util.h:64
MockableData::const_iterator m_cursor_end
Definition: util.h:61
MockableData::const_iterator m_cursor
Definition: util.h:60
Status Next(DataStream &key, DataStream &value) override
Definition: util.cpp:106
A WalletDatabase whose contents and return values can be modified as needed for testing.
Definition: util.h:105
An instance of this class represents one database.
Definition: db.h:124
Descriptor with some wallet metadata.
Definition: walletutil.h:85
RAII object to check and reserve a wallet rescan.
Definition: wallet.h:1066
bool reserve(bool with_passphrase=false)
Definition: wallet.h:1076
static UniValue Parse(std::string_view raw)
Parse string to UniValue or throw runtime_error if string contains invalid JSON.
Definition: client.cpp:311
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:8
util::Result< CTxDestination > GetNewDestination(const OutputType type, const std::string label)
Definition: wallet.cpp:2507
std::string EncodeSecret(const CKey &key)
Definition: key_io.cpp:227
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:287
bool error(const char *fmt, const Args &... args)
Definition: logging.h:267
void UnloadWallet(std::shared_ptr< CWallet > &&wallet)
Explicitly unload and delete the wallet.
Definition: wallet.cpp:239
std::shared_ptr< CWallet > TestLoadWallet(std::unique_ptr< WalletDatabase > database, WalletContext &context, uint64_t create_flags)
Definition: util.cpp:49
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:72
std::unique_ptr< WalletDatabase > MakeWalletDatabase(const std::string &name, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error_string)
Definition: wallet.cpp:2889
MockableDatabase & GetMockableDatabase(CWallet &wallet)
Definition: util.cpp:194
void NotifyWalletLoaded(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
Definition: wallet.cpp:207
std::unique_ptr< WalletDatabase > CreateMockableWalletDatabase(MockableData records)
Definition: util.cpp:189
bool operator<(BytePrefix a, Span< const std::byte > b)
Definition: util.cpp:97
std::unique_ptr< WalletDatabase > DuplicateMockDatabase(WalletDatabase &database)
Definition: util.cpp:79
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition: walletutil.h:74
RPCHelpMan getnewaddress()
Definition: addresses.cpp:23
std::map< SerializeData, SerializeData, std::less<> > MockableData
Definition: util.h:55
CTxDestination getNewDestination(CWallet &w, OutputType output_type)
Returns a new destination, of an specific type, from the wallet.
Definition: util.cpp:90
DatabaseStatus
Definition: db.h:196
std::shared_ptr< CWallet > wallet
OutputType
Definition: outputtype.h:17
const char * prefix
Definition: rest.cpp:1005
Bilingual messages:
Definition: translation.h:18
Span< const std::byte > prefix
Definition: util.cpp:96
std::optional< int > last_scanned_height
Definition: wallet.h:627
enum wallet::CWallet::ScanResult::@19 status
uint256 last_scanned_block
Hash and height of most recent block that was successfully scanned.
Definition: wallet.h:626
uint256 last_failed_block
Height of the most recent block that could not be scanned due to read errors or pruning.
Definition: wallet.h:633
uint64_t create_flags
Definition: db.h:186
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())
void SyncWithValidationInterfaceQueue()
This is a synonym for the following, which asserts certain locks are not held: std::promise<void> pro...
std::vector< std::byte, zero_after_free_allocator< std::byte > > SerializeData
Byte-vector that clears its contents before deletion.
Definition: zeroafterfree.h:49