Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto
2 : // Copyright (c) 2009-2021 The Bitcoin Core developers
3 : // Copyright (c) 2014-2025 The Dash Core developers
4 : // Distributed under the MIT software license, see the accompanying
5 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 :
7 : #include <wallet/walletdb.h>
8 :
9 : #include <key_io.h>
10 : #include <fs.h>
11 : #include <governance/common.h>
12 : #include <protocol.h>
13 : #include <serialize.h>
14 : #include <sync.h>
15 : #include <util/system.h>
16 : #include <util/time.h>
17 : #include <util/translation.h>
18 : #ifdef USE_BDB
19 : #include <wallet/bdb.h>
20 : #endif
21 : #ifdef USE_SQLITE
22 : #include <wallet/sqlite.h>
23 : #endif
24 : #include <wallet/hdchain.h>
25 : #include <wallet/wallet.h>
26 : #include <validation.h>
27 :
28 : #include <atomic>
29 : #include <optional>
30 : #include <string>
31 :
32 : namespace wallet {
33 : namespace DBKeys {
34 : const std::string ACENTRY{"acentry"};
35 : const std::string ACTIVEEXTERNALSPK{"activeexternalspk"};
36 : const std::string ACTIVEINTERNALSPK{"activeinternalspk"};
37 : const std::string BESTBLOCK_NOMERKLE{"bestblock_nomerkle"};
38 : const std::string BESTBLOCK{"bestblock"};
39 : const std::string CRYPTED_KEY{"ckey"};
40 : const std::string CRYPTED_HDCHAIN{"chdchain"};
41 : const std::string COINJOIN_SALT{"cj_salt"};
42 : const std::string CSCRIPT{"cscript"};
43 : const std::string DEFAULTKEY{"defaultkey"};
44 : const std::string DESTDATA{"destdata"};
45 : const std::string FLAGS{"flags"};
46 : const std::string G_OBJECT{"g_object"};
47 : const std::string HDCHAIN{"hdchain"};
48 : const std::string HDPUBKEY{"hdpubkey"};
49 : const std::string KEYMETA{"keymeta"};
50 : const std::string KEY{"key"};
51 : const std::string LOCKED_UTXO{"lockedutxo"};
52 : const std::string MASTER_KEY{"mkey"};
53 : const std::string MINVERSION{"minversion"};
54 : const std::string NAME{"name"};
55 : const std::string OLD_KEY{"wkey"};
56 : const std::string ORDERPOSNEXT{"orderposnext"};
57 : const std::string POOL{"pool"};
58 : const std::string PURPOSE{"purpose"};
59 : const std::string PRIVATESEND_SALT{"ps_salt"};
60 : const std::string SETTINGS{"settings"};
61 : const std::string TX{"tx"};
62 : const std::string VERSION{"version"};
63 : const std::string WALLETDESCRIPTOR{"walletdescriptor"};
64 : const std::string WALLETDESCRIPTORCACHE{"walletdescriptorcache"};
65 3444 : const std::string WALLETDESCRIPTORLHCACHE{"walletdescriptorlhcache"};
66 : const std::string WALLETDESCRIPTORCKEY{"walletdescriptorckey"};
67 : const std::string WALLETDESCRIPTORKEY{"walletdescriptorkey"};
68 : const std::string WATCHMETA{"watchmeta"};
69 : const std::string WATCHS{"watchs"};
70 3444 : const std::unordered_set<std::string> LEGACY_TYPES{CRYPTED_KEY, CRYPTED_HDCHAIN, CSCRIPT, DEFAULTKEY, HDCHAIN, HDPUBKEY, KEYMETA, KEY, OLD_KEY, POOL, PRIVATESEND_SALT, WATCHMETA, WATCHS};
71 : } // namespace DBKeys
72 :
73 : //
74 : // WalletBatch
75 : //
76 :
77 35106 : bool WalletBatch::WriteName(const std::string& strAddress, const std::string& strName)
78 : {
79 35106 : return WriteIC(std::make_pair(DBKeys::NAME, strAddress), strName);
80 0 : }
81 :
82 6 : bool WalletBatch::EraseName(const std::string& strAddress)
83 : {
84 : // This should only be used for sending addresses, never for receiving addresses,
85 : // receiving addresses must always have an address book entry if they're not change return.
86 6 : return EraseIC(std::make_pair(DBKeys::NAME, strAddress));
87 0 : }
88 :
89 35114 : bool WalletBatch::WritePurpose(const std::string& strAddress, const std::string& strPurpose)
90 : {
91 35114 : return WriteIC(std::make_pair(DBKeys::PURPOSE, strAddress), strPurpose);
92 0 : }
93 :
94 6 : bool WalletBatch::ErasePurpose(const std::string& strAddress)
95 : {
96 6 : return EraseIC(std::make_pair(DBKeys::PURPOSE, strAddress));
97 0 : }
98 :
99 80991 : bool WalletBatch::WriteTx(const CWalletTx& wtx)
100 : {
101 80991 : return WriteIC(std::make_pair(DBKeys::TX, wtx.GetHash()), wtx);
102 0 : }
103 :
104 227 : bool WalletBatch::EraseTx(uint256 hash)
105 : {
106 227 : return EraseIC(std::make_pair(DBKeys::TX, hash));
107 0 : }
108 :
109 14934 : bool WalletBatch::WriteKeyMetadata(const CKeyMetadata& keyMeta, const CPubKey& vchPubKey, const bool overwrite)
110 : {
111 14934 : return WriteIC(std::make_pair(DBKeys::KEYMETA, vchPubKey), keyMeta, overwrite);
112 0 : }
113 :
114 13806 : bool WalletBatch::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
115 : {
116 13806 : if (!WriteKeyMetadata(keyMeta, vchPubKey, false)) {
117 0 : return false;
118 : }
119 :
120 : // hash pubkey/privkey to accelerate wallet load
121 13806 : std::vector<unsigned char> vchKey;
122 13806 : vchKey.reserve(vchPubKey.size() + vchPrivKey.size());
123 13806 : vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
124 13806 : vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
125 :
126 13806 : return WriteIC(std::make_pair(DBKeys::KEY, vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey)), false);
127 13806 : }
128 :
129 426 : bool WalletBatch::WriteCryptedKey(const CPubKey& vchPubKey,
130 : const std::vector<unsigned char>& vchCryptedSecret,
131 : const CKeyMetadata &keyMeta)
132 : {
133 426 : if (!WriteKeyMetadata(keyMeta, vchPubKey, true)) {
134 0 : return false;
135 : }
136 :
137 : // Compute a checksum of the encrypted key
138 426 : uint256 checksum = Hash(vchCryptedSecret);
139 :
140 426 : const auto key = std::make_pair(DBKeys::CRYPTED_KEY, vchPubKey);
141 426 : if (!WriteIC(key, std::make_pair(vchCryptedSecret, checksum), false)) {
142 : // It may already exist, so try writing just the checksum
143 0 : std::vector<unsigned char> val;
144 0 : if (!m_batch->Read(key, val)) {
145 0 : return false;
146 : }
147 0 : if (!WriteIC(key, std::make_pair(val, checksum), true)) {
148 0 : return false;
149 : }
150 0 : }
151 426 : EraseIC(std::make_pair(DBKeys::KEY, vchPubKey));
152 426 : return true;
153 426 : }
154 :
155 92 : bool WalletBatch::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
156 : {
157 92 : return WriteIC(std::make_pair(DBKeys::MASTER_KEY, nID), kMasterKey, true);
158 0 : }
159 :
160 167 : bool WalletBatch::WriteCScript(const uint160& hash, const CScript& redeemScript)
161 : {
162 167 : return WriteIC(std::make_pair(DBKeys::CSCRIPT, hash), redeemScript, false);
163 0 : }
164 :
165 1617 : bool WalletBatch::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta)
166 : {
167 1617 : if (!WriteIC(std::make_pair(DBKeys::WATCHMETA, dest), keyMeta)) {
168 0 : return false;
169 : }
170 1617 : return WriteIC(std::make_pair(DBKeys::WATCHS, dest), uint8_t{'1'});
171 1617 : }
172 :
173 18 : bool WalletBatch::EraseWatchOnly(const CScript &dest)
174 : {
175 18 : if (!EraseIC(std::make_pair(DBKeys::WATCHMETA, dest))) {
176 0 : return false;
177 : }
178 18 : return EraseIC(std::make_pair(DBKeys::WATCHS, dest));
179 18 : }
180 :
181 3318 : bool WalletBatch::WriteBestBlock(const CBlockLocator& locator)
182 : {
183 3318 : WriteIC(DBKeys::BESTBLOCK, CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
184 3318 : return WriteIC(DBKeys::BESTBLOCK_NOMERKLE, locator);
185 0 : }
186 :
187 4324 : bool WalletBatch::ReadBestBlock(CBlockLocator& locator)
188 : {
189 4324 : if (m_batch->Read(DBKeys::BESTBLOCK, locator) && !locator.vHave.empty()) return true;
190 4324 : return m_batch->Read(DBKeys::BESTBLOCK_NOMERKLE, locator);
191 4324 : }
192 :
193 67355 : bool WalletBatch::WriteOrderPosNext(int64_t nOrderPosNext)
194 : {
195 67355 : return WriteIC(DBKeys::ORDERPOSNEXT, nOrderPosNext);
196 : }
197 :
198 22624 : bool WalletBatch::ReadPool(int64_t nPool, CKeyPool& keypool)
199 : {
200 22624 : return m_batch->Read(std::make_pair(DBKeys::POOL, nPool), keypool);
201 0 : }
202 :
203 43513 : bool WalletBatch::WritePool(int64_t nPool, const CKeyPool& keypool)
204 : {
205 43513 : return WriteIC(std::make_pair(DBKeys::POOL, nPool), keypool);
206 0 : }
207 :
208 20885 : bool WalletBatch::ErasePool(int64_t nPool)
209 : {
210 20885 : return EraseIC(std::make_pair(DBKeys::POOL, nPool));
211 0 : }
212 :
213 1185 : bool WalletBatch::WriteMinVersion(int nVersion)
214 : {
215 1185 : return WriteIC(DBKeys::MINVERSION, nVersion);
216 : }
217 :
218 3581 : bool WalletBatch::ReadCoinJoinSalt(uint256& salt, bool fLegacy)
219 : {
220 : // TODO: Remove legacy checks after few major releases
221 3581 : return m_batch->Read(std::string(fLegacy ? DBKeys::PRIVATESEND_SALT : DBKeys::COINJOIN_SALT), salt);
222 0 : }
223 :
224 1255 : bool WalletBatch::WriteCoinJoinSalt(const uint256& salt)
225 : {
226 1255 : return WriteIC(DBKeys::COINJOIN_SALT, salt);
227 : }
228 :
229 42 : bool WalletBatch::WriteGovernanceObject(const Governance::Object& obj)
230 : {
231 42 : return WriteIC(std::make_pair(DBKeys::G_OBJECT, obj.GetHash()), obj, false);
232 0 : }
233 :
234 895 : bool WalletBatch::WriteActiveScriptPubKeyMan(const uint256& id, bool internal)
235 : {
236 895 : std::string key = internal ? DBKeys::ACTIVEINTERNALSPK : DBKeys::ACTIVEEXTERNALSPK;
237 895 : return WriteIC(key, id);
238 895 : }
239 :
240 2 : bool WalletBatch::EraseActiveScriptPubKeyMan(bool internal)
241 : {
242 2 : const std::string key{internal ? DBKeys::ACTIVEINTERNALSPK : DBKeys::ACTIVEEXTERNALSPK};
243 2 : return EraseIC(key);
244 2 : }
245 :
246 1497 : bool WalletBatch::WriteDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const CPrivKey& privkey, const SecureString& mnemonic, const SecureString& mnemonic_passphrase)
247 : {
248 : // hash pubkey/privkey to accelerate wallet load
249 1497 : std::vector<unsigned char> key;
250 1497 : key.reserve(pubkey.size() + privkey.size());
251 1497 : key.insert(key.end(), pubkey.begin(), pubkey.end());
252 1497 : key.insert(key.end(), privkey.begin(), privkey.end());
253 :
254 1497 : return WriteIC(std::make_pair(DBKeys::WALLETDESCRIPTORKEY, std::make_pair(desc_id, pubkey)), std::make_pair(std::make_pair(privkey, Hash(key)), std::make_pair(mnemonic, mnemonic_passphrase)), false);
255 1497 : }
256 :
257 134 : bool WalletBatch::WriteCryptedDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const std::vector<unsigned char>& secret, const std::vector<unsigned char>& crypted_mnemonic, const std::vector<unsigned char>& crypted_mnemonic_passphrase)
258 : {
259 134 : if (!WriteIC(std::make_pair(DBKeys::WALLETDESCRIPTORCKEY, std::make_pair(desc_id, pubkey)), std::make_pair(secret, std::make_pair(crypted_mnemonic, crypted_mnemonic_passphrase)), false)) {
260 0 : return false;
261 : }
262 134 : EraseIC(std::make_pair(DBKeys::WALLETDESCRIPTORKEY, std::make_pair(desc_id, pubkey)));
263 134 : return true;
264 134 : }
265 :
266 90265 : bool WalletBatch::WriteDescriptor(const uint256& desc_id, const WalletDescriptor& descriptor/*, const SecureString& mnemonic, const SecureString& mnemonic_passphrase*/)
267 : {
268 90265 : return WriteIC(make_pair(DBKeys::WALLETDESCRIPTOR, desc_id), descriptor);
269 0 : }
270 :
271 1788 : bool WalletBatch::WriteDescriptorDerivedCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index, uint32_t der_index)
272 : {
273 1788 : std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
274 1788 : xpub.Encode(ser_xpub.data());
275 1788 : return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORCACHE, desc_id), std::make_pair(key_exp_index, der_index)), ser_xpub);
276 1788 : }
277 :
278 1458 : bool WalletBatch::WriteDescriptorParentCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index)
279 : {
280 1458 : std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
281 1458 : xpub.Encode(ser_xpub.data());
282 1458 : return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORCACHE, desc_id), key_exp_index), ser_xpub);
283 1458 : }
284 :
285 1267 : bool WalletBatch::WriteDescriptorLastHardenedCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index)
286 : {
287 1267 : std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
288 1267 : xpub.Encode(ser_xpub.data());
289 1267 : return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORLHCACHE, desc_id), key_exp_index), ser_xpub);
290 1267 : }
291 :
292 154632 : bool WalletBatch::WriteDescriptorCacheItems(const uint256& desc_id, const DescriptorCache& cache)
293 : {
294 156090 : for (const auto& parent_xpub_pair : cache.GetCachedParentExtPubKeys()) {
295 1458 : if (!WriteDescriptorParentCache(parent_xpub_pair.second, desc_id, parent_xpub_pair.first)) {
296 0 : return false;
297 : }
298 : }
299 156420 : for (const auto& derived_xpub_map_pair : cache.GetCachedDerivedExtPubKeys()) {
300 3576 : for (const auto& derived_xpub_pair : derived_xpub_map_pair.second) {
301 1788 : if (!WriteDescriptorDerivedCache(derived_xpub_pair.second, desc_id, derived_xpub_map_pair.first, derived_xpub_pair.first)) {
302 0 : return false;
303 : }
304 : }
305 : }
306 155899 : for (const auto& lh_xpub_pair : cache.GetCachedLastHardenedExtPubKeys()) {
307 1267 : if (!WriteDescriptorLastHardenedCache(lh_xpub_pair.second, desc_id, lh_xpub_pair.first)) {
308 0 : return false;
309 : }
310 : }
311 154632 : return true;
312 154632 : }
313 :
314 1039 : bool WalletBatch::WriteLockedUTXO(const COutPoint& output)
315 : {
316 1039 : return WriteIC(std::make_pair(DBKeys::LOCKED_UTXO, std::make_pair(output.hash, output.n)), uint8_t{'1'});
317 0 : }
318 :
319 654 : bool WalletBatch::EraseLockedUTXO(const COutPoint& output)
320 : {
321 654 : return EraseIC(std::make_pair(DBKeys::LOCKED_UTXO, std::make_pair(output.hash, output.n)));
322 0 : }
323 :
324 : class CWalletScanState {
325 : public:
326 2360 : unsigned int nKeys{0};
327 2360 : unsigned int nCKeys{0};
328 2360 : unsigned int nWatchKeys{0};
329 2360 : unsigned int nHDPubKeys{0};
330 2360 : unsigned int nKeyMeta{0};
331 2360 : unsigned int m_unknown_records{0};
332 2360 : bool fIsEncrypted{false};
333 2360 : bool fAnyUnordered{false};
334 : std::vector<uint256> vWalletUpgrade;
335 : std::map<OutputType, uint256> m_active_external_spks;
336 : std::map<OutputType, uint256> m_active_internal_spks;
337 : std::map<uint256, DescriptorCache> m_descriptor_caches;
338 : std::map<std::pair<uint256, CKeyID>, CKey> m_descriptor_keys;
339 : std::map<std::pair<uint256, CKeyID>, std::pair<CPubKey, std::vector<unsigned char>>> m_descriptor_crypt_keys;
340 : std::map<std::pair<uint256, CKeyID>, std::pair<SecureString, SecureString>> mnemonics;
341 : std::map<std::pair<uint256, CKeyID>, std::pair<std::vector<unsigned char>, std::vector<unsigned char>>> crypted_mnemonics;
342 2360 : bool tx_corrupt{false};
343 :
344 9440 : CWalletScanState() = default;
345 : };
346 :
347 : static bool
348 155289 : ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
349 : CWalletScanState &wss, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
350 : {
351 : try {
352 : // Unserialize
353 : // Taking advantage of the fact that pair serialization
354 : // is just the two items serialized one after the other
355 155289 : ssKey >> strType;
356 : // If we have a filter, check if this matches the filter
357 155289 : if (filter_fn && !filter_fn(strType)) {
358 24 : return true;
359 : }
360 155265 : if (strType == DBKeys::NAME) {
361 12052 : std::string strAddress;
362 12052 : ssKey >> strAddress;
363 12052 : std::string label;
364 12052 : ssValue >> label;
365 12052 : pwallet->m_address_book[DecodeDestination(strAddress)].SetLabel(label);
366 155265 : } else if (strType == DBKeys::PURPOSE) {
367 12052 : std::string strAddress;
368 12052 : ssKey >> strAddress;
369 12052 : ssValue >> pwallet->m_address_book[DecodeDestination(strAddress)].purpose;
370 143213 : } else if (strType == DBKeys::TX) {
371 46370 : uint256 hash;
372 46370 : ssKey >> hash;
373 : // LoadToWallet call below creates a new CWalletTx that fill_wtx
374 : // callback fills with transaction metadata.
375 92740 : auto fill_wtx = [&](CWalletTx& wtx, bool new_tx) {
376 46370 : if(!new_tx) {
377 : // There's some corruption here since the tx we just tried to load was already in the wallet.
378 : // We don't consider this type of corruption critical, and can fix it by removing tx data and
379 : // rescanning.
380 0 : wss.tx_corrupt = true;
381 0 : return false;
382 : }
383 46370 : ssValue >> wtx;
384 46370 : if (wtx.GetHash() != hash)
385 0 : return false;
386 :
387 : // Undo serialize changes in 31600
388 46370 : if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
389 : {
390 0 : if (!ssValue.empty())
391 : {
392 : uint8_t fTmp;
393 : uint8_t fUnused;
394 0 : std::string unused_string;
395 0 : ssValue >> fTmp >> fUnused >> unused_string;
396 0 : strErr = strprintf("LoadWallet() upgrading tx ver=%d %d %s",
397 0 : wtx.fTimeReceivedIsTxTime, fTmp, hash.ToString());
398 0 : wtx.fTimeReceivedIsTxTime = fTmp;
399 0 : }
400 : else
401 : {
402 0 : strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
403 0 : wtx.fTimeReceivedIsTxTime = 0;
404 : }
405 0 : wss.vWalletUpgrade.push_back(hash);
406 0 : }
407 :
408 46370 : if (wtx.nOrderPos == -1)
409 0 : wss.fAnyUnordered = true;
410 :
411 46370 : return true;
412 46370 : };
413 46370 : if (!pwallet->LoadToWallet(hash, fill_wtx)) {
414 0 : return false;
415 : }
416 131161 : } else if (strType == DBKeys::WATCHS) {
417 1328 : wss.nWatchKeys++;
418 1328 : CScript script;
419 1328 : ssKey >> script;
420 : uint8_t fYes;
421 1328 : ssValue >> fYes;
422 1328 : if (fYes == '1') {
423 1328 : pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadWatchOnly(script);
424 1328 : }
425 84791 : } else if (strType == DBKeys::KEY) {
426 1668 : CPubKey vchPubKey;
427 1668 : ssKey >> vchPubKey;
428 1668 : if (!vchPubKey.IsValid())
429 : {
430 0 : strErr = "Error reading wallet database: CPubKey corrupt";
431 0 : return false;
432 : }
433 1668 : CKey key;
434 1668 : CPrivKey pkey;
435 1668 : uint256 hash;
436 :
437 1668 : wss.nKeys++;
438 1668 : ssValue >> pkey;
439 :
440 : // Old wallets store keys as DBKeys::KEY [pubkey] => [privkey]
441 : // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key
442 : // using EC operations as a checksum.
443 : // Newer wallets store keys as DBKeys::KEY [pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while
444 : // remaining backwards-compatible.
445 : try
446 : {
447 1668 : ssValue >> hash;
448 1668 : }
449 0 : catch (const std::ios_base::failure&) {}
450 :
451 1668 : bool fSkipCheck = false;
452 :
453 1668 : if (!hash.IsNull())
454 : {
455 : // hash pubkey/privkey to accelerate wallet load
456 1668 : std::vector<unsigned char> vchKey;
457 1668 : vchKey.reserve(vchPubKey.size() + pkey.size());
458 1668 : vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
459 1668 : vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
460 :
461 1668 : if (Hash(vchKey) != hash)
462 : {
463 0 : strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
464 0 : return false;
465 : }
466 :
467 1668 : fSkipCheck = true;
468 1668 : }
469 :
470 1668 : if (!key.Load(pkey, vchPubKey, fSkipCheck))
471 : {
472 0 : strErr = "Error reading wallet database: CPrivKey corrupt";
473 0 : return false;
474 : }
475 1668 : if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKey(key, vchPubKey))
476 : {
477 0 : strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadKey failed";
478 0 : return false;
479 : }
480 83463 : } else if (strType == DBKeys::MASTER_KEY) {
481 : // Master encryption key is loaded into only the wallet and not any of the ScriptPubKeyMans.
482 : unsigned int nID;
483 58 : ssKey >> nID;
484 58 : CMasterKey kMasterKey;
485 58 : ssValue >> kMasterKey;
486 58 : if(pwallet->mapMasterKeys.count(nID) != 0)
487 : {
488 0 : strErr = strprintf("Error reading wallet database: duplicate CMasterKey id %u", nID);
489 0 : return false;
490 : }
491 58 : pwallet->mapMasterKeys[nID] = kMasterKey;
492 58 : if (pwallet->nMasterKeyMaxID < nID)
493 58 : pwallet->nMasterKeyMaxID = nID;
494 81795 : } else if (strType == DBKeys::CRYPTED_KEY) {
495 18 : CPubKey vchPubKey;
496 18 : ssKey >> vchPubKey;
497 18 : if (!vchPubKey.IsValid())
498 : {
499 0 : strErr = "Error reading wallet database: CPubKey corrupt";
500 0 : return false;
501 : }
502 18 : std::vector<unsigned char> vchPrivKey;
503 18 : ssValue >> vchPrivKey;
504 :
505 : // Get the checksum and check it
506 18 : bool checksum_valid = false;
507 18 : if (!ssValue.eof()) {
508 18 : uint256 checksum;
509 18 : ssValue >> checksum;
510 18 : if (!(checksum_valid = Hash(vchPrivKey) == checksum)) {
511 0 : strErr = "Error reading wallet database: Encrypted key corrupt";
512 0 : return false;
513 : }
514 18 : }
515 :
516 18 : wss.nCKeys++;
517 :
518 18 : if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadCryptedKey(vchPubKey, vchPrivKey, checksum_valid))
519 : {
520 0 : strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadCryptedKey failed";
521 0 : return false;
522 : }
523 18 : wss.fIsEncrypted = true;
524 81737 : } else if (strType == DBKeys::KEYMETA) {
525 26247 : CPubKey vchPubKey;
526 26247 : ssKey >> vchPubKey;
527 26247 : CKeyMetadata keyMeta;
528 26247 : ssValue >> keyMeta;
529 26247 : wss.nKeyMeta++;
530 26247 : pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKeyMetadata(vchPubKey.GetID(), keyMeta);
531 81719 : } else if (strType == DBKeys::WATCHMETA) {
532 1328 : CScript script;
533 1328 : ssKey >> script;
534 1328 : CKeyMetadata keyMeta;
535 1328 : ssValue >> keyMeta;
536 1328 : wss.nKeyMeta++;
537 1328 : pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadScriptMetadata(CScriptID(script), keyMeta);
538 55472 : } else if (strType == DBKeys::DEFAULTKEY) {
539 : // We don't want or need the default key, but if there is one set,
540 : // we want to make sure that it is valid so that we can detect corruption
541 0 : CPubKey vchPubKey;
542 0 : ssValue >> vchPubKey;
543 0 : if (!vchPubKey.IsValid()) {
544 0 : strErr = "Error reading wallet database: Default Key corrupt";
545 0 : return false;
546 : }
547 54144 : } else if (strType == DBKeys::POOL) {
548 : int64_t nIndex;
549 16735 : ssKey >> nIndex;
550 16735 : CKeyPool keypool;
551 16735 : ssValue >> keypool;
552 :
553 16735 : pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKeyPool(nIndex, keypool);
554 54144 : } else if (strType == DBKeys::CSCRIPT) {
555 70 : uint160 hash;
556 70 : ssKey >> hash;
557 70 : CScript script;
558 70 : ssValue >> script;
559 70 : if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadCScript(script))
560 : {
561 0 : strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadCScript failed";
562 0 : return false;
563 : }
564 37409 : } else if (strType == DBKeys::ORDERPOSNEXT) {
565 678 : ssValue >> pwallet->nOrderPosNext;
566 37339 : } else if (strType == DBKeys::DESTDATA) {
567 10 : std::string strAddress, strKey, strValue;
568 10 : ssKey >> strAddress;
569 10 : ssKey >> strKey;
570 10 : ssValue >> strValue;
571 10 : const CTxDestination& dest{DecodeDestination(strAddress)};
572 10 : if (strKey.compare("used") == 0) {
573 : // Load "used" key indicating if an IsMine address has
574 : // previously been spent from with avoid_reuse option enabled.
575 : // The strValue is not used for anything currently, but could
576 : // hold more information in the future. Current values are just
577 : // "1" or "p" for present (which was written prior to
578 : // f5ba424cd44619d9b9be88b8593d69a7ba96db26).
579 4 : pwallet->LoadAddressPreviouslySpent(dest);
580 10 : } else if (strKey.compare(0, 2, "rr") == 0) {
581 : // Load "rr##" keys where ## is a decimal number, and strValue
582 : // is a serialized RecentRequestEntry object.
583 6 : pwallet->LoadAddressReceiveRequest(dest, strKey.substr(2), strValue);
584 6 : }
585 36661 : } else if (strType == DBKeys::HDCHAIN || strType == DBKeys::CRYPTED_HDCHAIN) {
586 638 : CHDChain chain;
587 638 : ssValue >> chain;
588 638 : assert ((strType == DBKeys::CRYPTED_HDCHAIN) == chain.IsCrypted());
589 : // Skip encryption check during loading as MASTER_KEY records may not be loaded yet.
590 : // Consistency will be validated after all records are loaded.
591 638 : if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadHDChain(chain, /*skip_encryption_check=*/true)) {
592 0 : strErr = "Error reading wallet database: LoadHDChain failed";
593 0 : return false;
594 : }
595 36651 : } else if (strType == DBKeys::HDPUBKEY) {
596 23941 : wss.nHDPubKeys++;
597 23941 : CPubKey vchPubKey;
598 23941 : ssKey >> vchPubKey;
599 :
600 23941 : CHDPubKey hdPubKey;
601 23941 : ssValue >> hdPubKey;
602 :
603 23941 : if(vchPubKey != hdPubKey.extPubKey.pubkey)
604 : {
605 0 : strErr = "Error reading wallet database: CHDPubKey corrupt";
606 0 : return false;
607 : }
608 23941 : if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadHDPubKey(hdPubKey))
609 : {
610 0 : strErr = "Error reading wallet database: LoadHDPubKey failed";
611 0 : return false;
612 : }
613 36013 : } else if (strType == DBKeys::G_OBJECT) {
614 14 : uint256 nObjectHash;
615 14 : Governance::Object obj;
616 14 : ssKey >> nObjectHash;
617 14 : ssValue >> obj;
618 :
619 14 : if (obj.GetHash() != nObjectHash) {
620 0 : strErr = "Invalid governance object: Hash mismatch";
621 0 : return false;
622 : }
623 :
624 14 : if (!pwallet->LoadGovernanceObject(obj)) {
625 0 : strErr = "Invalid governance object: LoadGovernanceObject";
626 0 : return false;
627 : }
628 12072 : } else if (strType == DBKeys::OLD_KEY) {
629 0 : strErr = "Found unsupported 'wkey' record, try loading with version 0.17";
630 0 : return false;
631 12058 : } else if (strType == DBKeys::ACTIVEEXTERNALSPK || strType == DBKeys::ACTIVEINTERNALSPK) {
632 651 : uint256 id;
633 651 : ssValue >> id;
634 :
635 651 : bool internal = strType == DBKeys::ACTIVEINTERNALSPK;
636 651 : auto& spk_mans = internal ? wss.m_active_internal_spks : wss.m_active_external_spks;
637 651 : const OutputType type = OutputType::LEGACY;
638 651 : if (spk_mans.count(static_cast<OutputType>(type)) > 0) {
639 0 : strErr = "Multiple ScriptPubKeyMans specified for a single type";
640 0 : return false;
641 : }
642 651 : spk_mans[static_cast<OutputType>(type)] = id;
643 12058 : } else if (strType == DBKeys::WALLETDESCRIPTOR) {
644 1296 : uint256 id;
645 1296 : ssKey >> id;
646 1296 : WalletDescriptor desc;
647 1296 : ssValue >> desc;
648 1296 : if (wss.m_descriptor_caches.count(id) == 0) {
649 270 : wss.m_descriptor_caches[id] = DescriptorCache();
650 270 : }
651 1296 : pwallet->LoadDescriptorScriptPubKeyMan(id, desc);
652 11407 : } else if (strType == DBKeys::WALLETDESCRIPTORCACHE) {
653 1040 : bool parent = true;
654 1040 : uint256 desc_id;
655 : uint32_t key_exp_index;
656 : uint32_t der_index;
657 1040 : ssKey >> desc_id;
658 1040 : ssKey >> key_exp_index;
659 :
660 : // if the der_index exists, it's a derived xpub
661 : try
662 : {
663 1040 : ssKey >> der_index;
664 0 : parent = false;
665 1040 : }
666 1040 : catch (...) {}
667 :
668 1040 : std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
669 1040 : ssValue >> ser_xpub;
670 1040 : CExtPubKey xpub;
671 1040 : xpub.Decode(ser_xpub.data());
672 1040 : if (parent) {
673 1040 : wss.m_descriptor_caches[desc_id].CacheParentExtPubKey(key_exp_index, xpub);
674 1040 : } else {
675 0 : wss.m_descriptor_caches[desc_id].CacheDerivedExtPubKey(key_exp_index, der_index, xpub);
676 : }
677 10111 : } else if (strType == DBKeys::WALLETDESCRIPTORLHCACHE) {
678 1015 : uint256 desc_id;
679 : uint32_t key_exp_index;
680 1015 : ssKey >> desc_id;
681 1015 : ssKey >> key_exp_index;
682 :
683 1015 : std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
684 1015 : ssValue >> ser_xpub;
685 1015 : CExtPubKey xpub;
686 1015 : xpub.Decode(ser_xpub.data());
687 1015 : wss.m_descriptor_caches[desc_id].CacheLastHardenedExtPubKey(key_exp_index, xpub);
688 9071 : } else if (strType == DBKeys::WALLETDESCRIPTORKEY) {
689 1161 : uint256 desc_id;
690 1161 : CPubKey pubkey;
691 1161 : ssKey >> desc_id;
692 1161 : ssKey >> pubkey;
693 1161 : if (!pubkey.IsValid())
694 : {
695 0 : strErr = "Error reading wallet database: CPubKey corrupt";
696 0 : return false;
697 : }
698 1161 : CKey key;
699 1161 : CPrivKey pkey;
700 1161 : uint256 hash;
701 :
702 1161 : wss.nKeys++;
703 1161 : ssValue >> pkey;
704 1161 : ssValue >> hash;
705 :
706 : // hash pubkey/privkey to accelerate wallet load
707 1161 : std::vector<unsigned char> to_hash;
708 1161 : to_hash.reserve(pubkey.size() + pkey.size());
709 1161 : to_hash.insert(to_hash.end(), pubkey.begin(), pubkey.end());
710 1161 : to_hash.insert(to_hash.end(), pkey.begin(), pkey.end());
711 :
712 1161 : if (Hash(to_hash) != hash)
713 : {
714 0 : strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
715 0 : return false;
716 : }
717 :
718 1161 : if (!key.Load(pkey, pubkey, true))
719 : {
720 0 : strErr = "Error reading wallet database: CPrivKey corrupt";
721 0 : return false;
722 : }
723 1161 : wss.m_descriptor_keys.insert(std::make_pair(std::make_pair(desc_id, pubkey.GetID()), key));
724 :
725 1161 : SecureString mnemonic;
726 1161 : SecureString mnemonic_passphrase;
727 : // it's okay if wallet doesn't have mnemonic.
728 : // The wallet may be created in an older version of Dash Core or by importing descriptor
729 : try
730 : {
731 1161 : ssValue >> mnemonic;
732 1161 : ssValue >> mnemonic_passphrase;
733 1161 : }
734 0 : catch (const std::ios_base::failure&) {}
735 :
736 1161 : if (!mnemonic.empty()) {
737 925 : wss.mnemonics.insert(std::make_pair(std::make_pair(desc_id, pubkey.GetID()), std::make_pair(mnemonic, mnemonic_passphrase)));
738 925 : }
739 8056 : } else if (strType == DBKeys::WALLETDESCRIPTORCKEY) {
740 88 : uint256 desc_id;
741 88 : CPubKey pubkey;
742 88 : ssKey >> desc_id;
743 88 : ssKey >> pubkey;
744 88 : if (!pubkey.IsValid())
745 : {
746 0 : strErr = "Error reading wallet database: CPubKey corrupt";
747 0 : return false;
748 : }
749 88 : std::vector<unsigned char> privkey;
750 88 : ssValue >> privkey;
751 88 : wss.nCKeys++;
752 :
753 88 : wss.m_descriptor_crypt_keys.insert(std::make_pair(std::make_pair(desc_id, pubkey.GetID()), std::make_pair(pubkey, privkey)));
754 88 : wss.fIsEncrypted = true;
755 :
756 : // TODO : remove copy-paste with plain-text key
757 88 : std::vector<unsigned char> mnemonic;
758 88 : std::vector<unsigned char> mnemonic_passphrase;
759 : // it's okay if wallet doesn't have mnemonic.
760 : // The wallet may be created in an older version of Dash Core or by importing descriptor
761 : try
762 : {
763 88 : ssValue >> mnemonic;
764 88 : ssValue >> mnemonic_passphrase;
765 88 : }
766 0 : catch (const std::ios_base::failure&) {}
767 88 : if (!mnemonic.empty()) {
768 70 : wss.crypted_mnemonics.insert(std::make_pair(std::make_pair(desc_id, pubkey.GetID()), std::make_pair(mnemonic, mnemonic_passphrase)));
769 70 : }
770 :
771 6895 : } else if (strType == DBKeys::LOCKED_UTXO) {
772 309 : uint256 hash;
773 : uint32_t n;
774 309 : ssKey >> hash;
775 309 : ssKey >> n;
776 309 : pwallet->LockCoin(COutPoint(hash, n));
777 7890 : } else if (strType != DBKeys::BESTBLOCK && strType != DBKeys::BESTBLOCK_NOMERKLE &&
778 4340 : strType != DBKeys::MINVERSION && strType != DBKeys::ACENTRY &&
779 3257 : strType != DBKeys::VERSION && strType != DBKeys::SETTINGS &&
780 2170 : strType != DBKeys::PRIVATESEND_SALT && strType != DBKeys::COINJOIN_SALT &&
781 1083 : strType != DBKeys::FLAGS) {
782 0 : wss.m_unknown_records++;
783 0 : }
784 155265 : } catch (const std::exception& e) {
785 0 : if (strErr.empty()) {
786 0 : strErr = e.what();
787 0 : }
788 0 : return false;
789 0 : } catch (...) {
790 0 : if (strErr.empty()) {
791 0 : strErr = "Caught unknown exception in ReadKeyValue";
792 0 : }
793 0 : return false;
794 0 : }
795 155265 : return true;
796 156329 : }
797 :
798 26 : bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn)
799 : {
800 26 : CWalletScanState dummy_wss;
801 26 : LOCK(pwallet->cs_wallet);
802 26 : return ReadKeyValue(pwallet, ssKey, ssValue, dummy_wss, strType, strErr, filter_fn);
803 26 : }
804 :
805 52 : bool WalletBatch::IsKeyType(const std::string& strType)
806 : {
807 104 : return (strType == DBKeys::KEY ||
808 52 : strType == DBKeys::MASTER_KEY || strType == DBKeys::CRYPTED_KEY ||
809 52 : strType == DBKeys::HDCHAIN || strType == DBKeys::CRYPTED_HDCHAIN);
810 : }
811 :
812 2334 : DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
813 : {
814 2334 : CWalletScanState wss;
815 2334 : bool fNoncriticalErrors = false;
816 2334 : DBErrors result = DBErrors::LOAD_OK;
817 :
818 2334 : LOCK(pwallet->cs_wallet);
819 : try {
820 2334 : int nMinVersion = 0;
821 2334 : if (m_batch->Read(DBKeys::MINVERSION, nMinVersion)) {
822 1083 : if (nMinVersion > FEATURE_LATEST)
823 0 : return DBErrors::TOO_NEW;
824 1083 : pwallet->LoadMinVersion(nMinVersion);
825 1083 : }
826 :
827 : // Load wallet flags, so they are known when processing other records.
828 : // The FLAGS key is absent during wallet creation.
829 : uint64_t flags;
830 2334 : if (m_batch->Read(DBKeys::FLAGS, flags)) {
831 1083 : if (!pwallet->LoadWalletFlags(flags)) {
832 0 : pwallet->WalletLogPrintf("Error reading wallet database: Unknown non-tolerable wallet flags found\n");
833 0 : return DBErrors::CORRUPT;
834 : }
835 1083 : }
836 :
837 : #ifndef ENABLE_EXTERNAL_SIGNER
838 : if (pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
839 : pwallet->WalletLogPrintf("Error: External signer wallet being loaded without external signer support compiled\n");
840 : return DBErrors::EXTERNAL_SIGNER_SUPPORT_REQUIRED;
841 : }
842 : #endif
843 :
844 : // Get cursor
845 2334 : if (!m_batch->StartCursor())
846 : {
847 0 : pwallet->WalletLogPrintf("Error getting wallet database cursor\n");
848 0 : return DBErrors::CORRUPT;
849 : }
850 :
851 157597 : while (true)
852 : {
853 : // Read next record
854 157597 : CDataStream ssKey(SER_DISK, CLIENT_VERSION);
855 157597 : CDataStream ssValue(SER_DISK, CLIENT_VERSION);
856 : bool complete;
857 157597 : bool ret = m_batch->ReadAtCursor(ssKey, ssValue, complete);
858 157597 : if (complete) {
859 2334 : break;
860 : }
861 155263 : else if (!ret)
862 : {
863 0 : m_batch->CloseCursor();
864 0 : pwallet->WalletLogPrintf("Error reading next record from wallet database\n");
865 0 : return DBErrors::CORRUPT;
866 : }
867 :
868 : // Try to be tolerant of single corrupt records:
869 155263 : std::string strType, strErr;
870 155263 : if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
871 : {
872 : // losing keys is considered a catastrophic error, anything else
873 : // we assume the user can live with:
874 0 : if (IsKeyType(strType) || strType == DBKeys::DEFAULTKEY) {
875 0 : result = DBErrors::CORRUPT;
876 0 : } else if (strType == DBKeys::FLAGS) {
877 : // reading the wallet flags can only fail if unknown flags are present
878 0 : result = DBErrors::TOO_NEW;
879 0 : } else if (wss.tx_corrupt) {
880 0 : pwallet->WalletLogPrintf("Error: Corrupt transaction found. This can be fixed by removing transactions from wallet and rescanning.\n");
881 : // Set tx_corrupt back to false so that the error is only printed once (per corrupt tx)
882 0 : wss.tx_corrupt = false;
883 0 : result = DBErrors::CORRUPT;
884 0 : } else {
885 : // Leave other errors alone, if we try to fix them we might make things worse.
886 0 : fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
887 0 : if (strType == DBKeys::TX)
888 : // Rescan if there is a bad transaction record:
889 0 : gArgs.SoftSetBoolArg("-rescan", true);
890 : }
891 0 : }
892 155263 : if (!strErr.empty())
893 0 : pwallet->WalletLogPrintf("%s\n", strErr);
894 157597 : }
895 2334 : } catch (...) {
896 0 : result = DBErrors::CORRUPT;
897 0 : }
898 2334 : m_batch->CloseCursor();
899 :
900 : // Validate HD chain encryption consistency now that all data is loaded
901 2334 : if (auto spk_man = pwallet->GetLegacyScriptPubKeyMan()) {
902 713 : CHDChain hdChain;
903 713 : if (spk_man->GetHDChain(hdChain)) {
904 : // If HD chain exists, validate encryption consistency
905 636 : bool fHasMasterKeys = pwallet->HasEncryptionKeys();
906 636 : bool fChainCrypted = hdChain.IsCrypted();
907 :
908 636 : if (fHasMasterKeys != fChainCrypted) {
909 0 : pwallet->WalletLogPrintf("Error: HD chain encryption state (%s) inconsistent with wallet encryption state (%s)\n",
910 0 : fChainCrypted ? "encrypted" : "not encrypted",
911 0 : fHasMasterKeys ? "encrypted" : "not encrypted");
912 0 : return DBErrors::CORRUPT;
913 : }
914 636 : }
915 713 : }
916 :
917 : // Set the active ScriptPubKeyMans
918 2659 : for (auto spk_man : wss.m_active_external_spks) {
919 325 : pwallet->LoadActiveScriptPubKeyMan(spk_man.second, /*internal=*/false);
920 : }
921 2660 : for (auto spk_man : wss.m_active_internal_spks) {
922 326 : pwallet->LoadActiveScriptPubKeyMan(spk_man.second, /*internal=*/true);
923 : }
924 :
925 : // Set the descriptor caches
926 3630 : for (const auto& desc_cache_pair : wss.m_descriptor_caches) {
927 1296 : auto spk_man = pwallet->GetScriptPubKeyMan(desc_cache_pair.first);
928 1296 : assert(spk_man);
929 1296 : ((DescriptorScriptPubKeyMan*)spk_man)->SetCache(desc_cache_pair.second);
930 : }
931 :
932 : // Set the descriptor keys
933 3495 : for (const auto& desc_key_pair : wss.m_descriptor_keys) {
934 1161 : auto spk_man = pwallet->GetScriptPubKeyMan(desc_key_pair.first.first);
935 1161 : auto it = wss.mnemonics.find(desc_key_pair.first);
936 1161 : if (it == wss.mnemonics.end()) {
937 236 : ((DescriptorScriptPubKeyMan*)spk_man)->AddKey(desc_key_pair.first.second, desc_key_pair.second, "", "");
938 236 : } else {
939 925 : ((DescriptorScriptPubKeyMan*)spk_man)->AddKey(desc_key_pair.first.second, desc_key_pair.second, it->second.first, it->second.second);
940 : }
941 : }
942 :
943 2422 : for (const auto& desc_key_pair : wss.m_descriptor_crypt_keys) {
944 88 : auto spk_man = pwallet->GetScriptPubKeyMan(desc_key_pair.first.first);
945 88 : auto it = wss.crypted_mnemonics.find(desc_key_pair.first);
946 88 : if (it == wss.crypted_mnemonics.end()) {
947 18 : ((DescriptorScriptPubKeyMan*)spk_man)->AddCryptedKey(desc_key_pair.first.second, desc_key_pair.second.first, desc_key_pair.second.second, {}, {});
948 18 : } else {
949 70 : ((DescriptorScriptPubKeyMan*)spk_man)->AddCryptedKey(desc_key_pair.first.second, desc_key_pair.second.first, desc_key_pair.second.second, it->second.first, it->second.second);
950 : }
951 : }
952 :
953 2334 : if (fNoncriticalErrors && result == DBErrors::LOAD_OK)
954 0 : result = DBErrors::NONCRITICAL_ERROR;
955 :
956 : // Any wallet corruption at all: skip any rewriting or
957 : // upgrading, we don't want to make it worse.
958 2334 : if (result != DBErrors::LOAD_OK)
959 0 : return result;
960 :
961 : // Store initial external keypool size since we mostly use external keys in mixing
962 2334 : pwallet->nKeysLeftSinceAutoBackup = pwallet->KeypoolCountExternalKeys();
963 2334 : pwallet->WalletLogPrintf("nKeysLeftSinceAutoBackup: %d\n", pwallet->nKeysLeftSinceAutoBackup);
964 :
965 : // Last client version to open this wallet
966 2334 : int last_client = CLIENT_VERSION;
967 2334 : bool has_last_client = m_batch->Read(DBKeys::VERSION, last_client);
968 2334 : pwallet->WalletLogPrintf("Wallet file version = %d, last client version = %d\n", pwallet->GetVersion(), last_client);
969 :
970 2334 : pwallet->WalletLogPrintf("Keys: %u plaintext, %u encrypted, %u total; Watch scripts: %u; HD PubKeys: %u; Metadata: %u; Unknown wallet records: %u\n",
971 2334 : wss.nKeys, wss.nCKeys, wss.nKeys + wss.nCKeys,
972 2334 : wss.nWatchKeys, wss.nHDPubKeys, wss.nKeyMeta, wss.m_unknown_records);
973 :
974 : // nTimeFirstKey is only reliable if all keys have metadata
975 2334 : if (pwallet->IsLegacy() && (wss.nKeys + wss.nCKeys + wss.nWatchKeys + wss.nHDPubKeys) != wss.nKeyMeta) {
976 14 : auto spk_man = pwallet->GetOrCreateLegacyScriptPubKeyMan();
977 14 : if (spk_man) {
978 14 : LOCK(spk_man->cs_KeyStore);
979 14 : spk_man->UpdateTimeFirstKey(1);
980 14 : }
981 14 : }
982 :
983 2334 : for (const uint256& hash : wss.vWalletUpgrade)
984 0 : WriteTx(pwallet->mapWallet.at(hash));
985 :
986 : // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
987 2334 : if (wss.fIsEncrypted && (last_client == 40000 || last_client == 50000))
988 0 : return DBErrors::NEED_REWRITE;
989 :
990 2334 : if (!has_last_client || last_client != CLIENT_VERSION) // Update
991 1247 : m_batch->Write(DBKeys::VERSION, CLIENT_VERSION);
992 :
993 2334 : if (wss.fAnyUnordered)
994 0 : result = pwallet->ReorderTransactions();
995 :
996 : // Upgrade all of the wallet keymetadata to have the hd master key id
997 : // This operation is not atomic, but if it fails, updated entries are still backwards compatible with older software
998 : try {
999 2334 : pwallet->UpgradeKeyMetadata();
1000 2334 : } catch (...) {
1001 0 : result = DBErrors::CORRUPT;
1002 0 : }
1003 :
1004 : // Upgrade all of the descriptor caches to cache the last hardened xpub
1005 : // This operation is not atomic, but if it fails, only new entries are added so it is backwards compatible
1006 : try {
1007 2334 : pwallet->UpgradeDescriptorCache();
1008 2334 : } catch (...) {
1009 0 : result = DBErrors::CORRUPT;
1010 0 : }
1011 :
1012 2334 : return result;
1013 2334 : }
1014 :
1015 23 : DBErrors WalletBatch::FindWalletTxHashes(std::vector<uint256>& tx_hashes)
1016 : {
1017 23 : DBErrors result = DBErrors::LOAD_OK;
1018 :
1019 : try {
1020 23 : int nMinVersion = 0;
1021 23 : if (m_batch->Read(DBKeys::MINVERSION, nMinVersion)) {
1022 23 : if (nMinVersion > FEATURE_LATEST)
1023 0 : return DBErrors::TOO_NEW;
1024 23 : }
1025 :
1026 : // Get cursor
1027 23 : if (!m_batch->StartCursor())
1028 : {
1029 0 : LogPrintf("Error getting wallet database cursor\n");
1030 0 : return DBErrors::CORRUPT;
1031 : }
1032 :
1033 1031 : while (true)
1034 : {
1035 : // Read next record
1036 1031 : CDataStream ssKey(SER_DISK, CLIENT_VERSION);
1037 1031 : CDataStream ssValue(SER_DISK, CLIENT_VERSION);
1038 : bool complete;
1039 1031 : bool ret = m_batch->ReadAtCursor(ssKey, ssValue, complete);
1040 1031 : if (complete) {
1041 23 : break;
1042 1008 : } else if (!ret) {
1043 0 : m_batch->CloseCursor();
1044 0 : LogPrintf("Error reading next record from wallet database\n");
1045 0 : return DBErrors::CORRUPT;
1046 : }
1047 :
1048 1008 : std::string strType;
1049 1008 : ssKey >> strType;
1050 1008 : if (strType == DBKeys::TX) {
1051 439 : uint256 hash;
1052 439 : ssKey >> hash;
1053 439 : tx_hashes.push_back(hash);
1054 439 : }
1055 1031 : }
1056 23 : } catch (...) {
1057 0 : result = DBErrors::CORRUPT;
1058 0 : }
1059 23 : m_batch->CloseCursor();
1060 :
1061 23 : return result;
1062 23 : }
1063 :
1064 23 : DBErrors WalletBatch::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<uint256>& vTxHashOut)
1065 : {
1066 : // build list of wallet TX hashes
1067 23 : std::vector<uint256> vTxHash;
1068 23 : DBErrors err = FindWalletTxHashes(vTxHash);
1069 23 : if (err != DBErrors::LOAD_OK) {
1070 0 : return err;
1071 : }
1072 :
1073 23 : std::sort(vTxHash.begin(), vTxHash.end());
1074 23 : std::sort(vTxHashIn.begin(), vTxHashIn.end());
1075 :
1076 : // erase each matching wallet TX
1077 23 : bool delerror = false;
1078 23 : std::vector<uint256>::iterator it = vTxHashIn.begin();
1079 417 : for (const uint256& hash : vTxHash) {
1080 1008 : while (it < vTxHashIn.end() && (*it) < hash) {
1081 212 : it++;
1082 : }
1083 398 : if (it == vTxHashIn.end()) {
1084 4 : break;
1085 : }
1086 394 : else if ((*it) == hash) {
1087 227 : if(!EraseTx(hash)) {
1088 0 : LogPrint(BCLog::WALLETDB, "Transaction was found for deletion but returned database error: %s\n", hash.GetHex());
1089 0 : delerror = true;
1090 0 : }
1091 227 : vTxHashOut.push_back(hash);
1092 227 : }
1093 : }
1094 :
1095 23 : if (delerror) {
1096 0 : return DBErrors::CORRUPT;
1097 : }
1098 23 : return DBErrors::LOAD_OK;
1099 23 : }
1100 :
1101 46327 : void MaybeCompactWalletDB(WalletContext& context)
1102 : {
1103 : static std::atomic<bool> fOneThread(false);
1104 46327 : if (fOneThread.exchange(true)) {
1105 0 : return;
1106 : }
1107 :
1108 97696 : for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
1109 51369 : WalletDatabase& dbh = pwallet->GetDatabase();
1110 :
1111 51369 : unsigned int nUpdateCounter = dbh.nUpdateCounter;
1112 :
1113 51369 : if (dbh.nLastSeen != nUpdateCounter) {
1114 16069 : dbh.nLastSeen = nUpdateCounter;
1115 16069 : dbh.nLastWalletUpdate = GetTime();
1116 16069 : }
1117 :
1118 51369 : if (dbh.nLastFlushed != nUpdateCounter && GetTime() - dbh.nLastWalletUpdate >= 2) {
1119 4225 : if (dbh.PeriodicFlush()) {
1120 1379 : dbh.nLastFlushed = nUpdateCounter;
1121 1379 : }
1122 4225 : }
1123 : }
1124 :
1125 46327 : fOneThread = false;
1126 46327 : }
1127 :
1128 68 : bool WalletBatch::WriteAddressPreviouslySpent(const CTxDestination& dest, bool previously_spent)
1129 : {
1130 68 : auto key{std::make_pair(DBKeys::DESTDATA, std::make_pair(EncodeDestination(dest), std::string("used")))};
1131 68 : return previously_spent ? WriteIC(key, std::string("1")) : EraseIC(key);
1132 68 : }
1133 :
1134 8 : bool WalletBatch::WriteAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& receive_request)
1135 : {
1136 8 : return WriteIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(EncodeDestination(dest), "rr" + id)), receive_request);
1137 0 : }
1138 :
1139 2 : bool WalletBatch::EraseAddressReceiveRequest(const CTxDestination& dest, const std::string& id)
1140 : {
1141 2 : return EraseIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(EncodeDestination(dest), "rr" + id)));
1142 0 : }
1143 :
1144 8 : bool WalletBatch::EraseAddressData(const CTxDestination& dest)
1145 : {
1146 8 : CDataStream prefix(SER_DISK, CLIENT_VERSION);
1147 8 : prefix << DBKeys::DESTDATA << EncodeDestination(dest);
1148 8 : return m_batch->ErasePrefix({prefix.data(), prefix.size()});
1149 8 : }
1150 :
1151 32502 : bool WalletBatch::WriteHDChain(const CHDChain& chain)
1152 : {
1153 32502 : if (chain.IsCrypted()) {
1154 651 : if (!WriteIC(DBKeys::CRYPTED_HDCHAIN, chain))
1155 0 : return false;
1156 :
1157 651 : EraseIC(DBKeys::HDCHAIN);
1158 :
1159 651 : return true;
1160 : }
1161 31851 : return WriteIC(DBKeys::HDCHAIN, chain);
1162 32502 : }
1163 :
1164 31845 : bool WalletBatch::WriteHDPubKey(const CHDPubKey& hdPubKey, const CKeyMetadata& keyMeta)
1165 : {
1166 31845 : if (!WriteIC(std::make_pair(DBKeys::KEYMETA, hdPubKey.extPubKey.pubkey), keyMeta, false))
1167 0 : return false;
1168 :
1169 31845 : return WriteIC(std::make_pair(DBKeys::HDPUBKEY, hdPubKey.extPubKey.pubkey), hdPubKey, false);
1170 31845 : }
1171 :
1172 69453 : bool WalletBatch::WriteWalletFlags(const uint64_t flags)
1173 : {
1174 69453 : return WriteIC(DBKeys::FLAGS, flags);
1175 : }
1176 :
1177 26 : bool WalletBatch::EraseRecords(const std::unordered_set<std::string>& types)
1178 : {
1179 : // Get cursor
1180 26 : if (!m_batch->StartCursor())
1181 : {
1182 0 : return false;
1183 : }
1184 :
1185 : // Iterate the DB and look for any records that have the type prefixes
1186 918 : while (true)
1187 : {
1188 : // Read next record
1189 918 : CDataStream key(SER_DISK, CLIENT_VERSION);
1190 918 : CDataStream value(SER_DISK, CLIENT_VERSION);
1191 : bool complete;
1192 918 : bool ret = m_batch->ReadAtCursor(key, value, complete);
1193 918 : if (complete) {
1194 26 : break;
1195 : }
1196 892 : else if (!ret)
1197 : {
1198 0 : m_batch->CloseCursor();
1199 0 : return false;
1200 : }
1201 :
1202 : // Make a copy of key to avoid data being deleted by the following read of the type
1203 892 : Span<const unsigned char> key_data = MakeUCharSpan(key);
1204 :
1205 892 : std::string type;
1206 892 : key >> type;
1207 :
1208 892 : if (types.count(type) > 0) {
1209 328 : m_batch->Erase(key_data);
1210 328 : }
1211 918 : }
1212 26 : m_batch->CloseCursor();
1213 26 : return true;
1214 26 : }
1215 :
1216 138 : bool WalletBatch::TxnBegin()
1217 : {
1218 138 : return m_batch->TxnBegin();
1219 : }
1220 :
1221 136 : bool WalletBatch::TxnCommit()
1222 : {
1223 136 : return m_batch->TxnCommit();
1224 : }
1225 :
1226 2 : bool WalletBatch::TxnAbort()
1227 : {
1228 2 : return m_batch->TxnAbort();
1229 : }
1230 :
1231 3773 : std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
1232 : {
1233 : bool exists;
1234 : try {
1235 3773 : exists = fs::symlink_status(path).type() != fs::file_type::not_found;
1236 3773 : } catch (const fs::filesystem_error& e) {
1237 0 : error = Untranslated(strprintf("Failed to access database path '%s': %s", fs::PathToString(path), fsbridge::get_filesystem_error_message(e)));
1238 0 : status = DatabaseStatus::FAILED_BAD_PATH;
1239 0 : return nullptr;
1240 0 : }
1241 :
1242 3773 : std::optional<DatabaseFormat> format;
1243 3773 : if (exists) {
1244 2966 : if (IsBDBFile(BDBDataFile(path))) {
1245 1159 : format = DatabaseFormat::BERKELEY;
1246 1159 : }
1247 2966 : if (IsSQLiteFile(SQLiteDataFile(path))) {
1248 576 : if (format) {
1249 0 : error = Untranslated(strprintf("Failed to load database path '%s'. Data is in ambiguous format.", fs::PathToString(path)));
1250 0 : status = DatabaseStatus::FAILED_BAD_FORMAT;
1251 0 : return nullptr;
1252 : }
1253 576 : format = DatabaseFormat::SQLITE;
1254 576 : }
1255 3773 : } else if (options.require_existing) {
1256 12 : error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", fs::PathToString(path)));
1257 12 : status = DatabaseStatus::FAILED_NOT_FOUND;
1258 12 : return nullptr;
1259 : }
1260 :
1261 3761 : if (!format && options.require_existing) {
1262 781 : error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in recognized format.", fs::PathToString(path)));
1263 781 : status = DatabaseStatus::FAILED_BAD_FORMAT;
1264 781 : return nullptr;
1265 : }
1266 :
1267 2980 : if (format && options.require_create) {
1268 10 : error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", fs::PathToString(path)));
1269 10 : status = DatabaseStatus::FAILED_ALREADY_EXISTS;
1270 10 : return nullptr;
1271 : }
1272 :
1273 : // A db already exists so format is set, but options also specifies the format, so make sure they agree
1274 2970 : if (format && options.require_format && format != options.require_format) {
1275 0 : error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in required format.", fs::PathToString(path)));
1276 0 : status = DatabaseStatus::FAILED_BAD_FORMAT;
1277 0 : return nullptr;
1278 : }
1279 :
1280 : // Format is not set when a db doesn't already exist, so use the format specified by the options if it is set.
1281 2970 : if (!format && options.require_format) format = options.require_format;
1282 :
1283 : // If the format is not specified or detected, choose the default format based on what is available. We prefer BDB over SQLite for now..
1284 2970 : if (!format) {
1285 : #ifdef USE_SQLITE
1286 761 : format = DatabaseFormat::SQLITE;
1287 : #endif
1288 : #ifdef USE_BDB
1289 761 : format = DatabaseFormat::BERKELEY;
1290 : #endif
1291 761 : }
1292 :
1293 2970 : if (format == DatabaseFormat::SQLITE) {
1294 : #ifdef USE_SQLITE
1295 : if constexpr (true) {
1296 1041 : return MakeSQLiteDatabase(path, options, status, error);
1297 : } else
1298 : #endif
1299 : {
1300 : error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support SQLite database format.", fs::PathToString(path)));
1301 : status = DatabaseStatus::FAILED_BAD_FORMAT;
1302 : return nullptr;
1303 : }
1304 : }
1305 :
1306 : #ifdef USE_BDB
1307 : if constexpr (true) {
1308 1929 : return MakeBerkeleyDatabase(path, options, status, error);
1309 : } else
1310 : #endif
1311 : {
1312 : error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support Berkeley DB database format.", fs::PathToString(path)));
1313 : status = DatabaseStatus::FAILED_BAD_FORMAT;
1314 : return nullptr;
1315 : }
1316 3773 : }
1317 :
1318 : /** Return object for accessing dummy database with no read/write capabilities. */
1319 22 : std::unique_ptr<WalletDatabase> CreateDummyWalletDatabase()
1320 : {
1321 22 : return std::make_unique<DummyDatabase>();
1322 : }
1323 :
1324 : /** Return object for accessing temporary in-memory database. */
1325 36 : std::unique_ptr<WalletDatabase> CreateMockWalletDatabase(DatabaseOptions& options)
1326 : {
1327 :
1328 36 : std::optional<DatabaseFormat> format;
1329 36 : if (options.require_format) format = options.require_format;
1330 36 : if (!format) {
1331 : #ifdef USE_BDB
1332 36 : format = DatabaseFormat::BERKELEY;
1333 : #endif
1334 : #ifdef USE_SQLITE
1335 36 : format = DatabaseFormat::SQLITE;
1336 : #endif
1337 36 : }
1338 :
1339 36 : if (format == DatabaseFormat::SQLITE) {
1340 : #ifdef USE_SQLITE
1341 36 : return std::make_unique<SQLiteDatabase>(":memory:", "", options, true);
1342 : #endif
1343 : assert(false);
1344 : }
1345 :
1346 : #ifdef USE_BDB
1347 0 : return std::make_unique<BerkeleyDatabase>(std::make_shared<BerkeleyEnvironment>(), "", options);
1348 : #endif
1349 : assert(false);
1350 36 : }
1351 :
1352 36 : std::unique_ptr<WalletDatabase> CreateMockWalletDatabase()
1353 : {
1354 36 : DatabaseOptions options;
1355 36 : return CreateMockWalletDatabase(options);
1356 36 : }
1357 : } // namespace wallet
|