1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2020 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #include <wallet/walletdb.h>
7
8 #include <fs.h>
9 #include <key_io.h>
10 #include <protocol.h>
11 #include <serialize.h>
12 #include <sync.h>
13 #include <util/bip32.h>
14 #include <util/system.h>
15 #include <util/time.h>
16 #include <util/translation.h>
17 #ifdef USE_BDB
18 #include <wallet/bdb.h>
19 #endif
20 #ifdef USE_SQLITE
21 #include <wallet/sqlite.h>
22 #endif
23 #include <wallet/wallet.h>
24
25 #include <atomic>
26 #include <optional>
27 #include <string>
28
29 namespace DBKeys {
30 const std::string ACENTRY{"acentry"};
31 const std::string ACTIVEEXTERNALSPK{"activeexternalspk"};
32 const std::string ACTIVEINTERNALSPK{"activeinternalspk"};
33 const std::string BESTBLOCK_NOMERKLE{"bestblock_nomerkle"};
34 const std::string BESTBLOCK{"bestblock"};
35 const std::string CRYPTED_KEY{"ckey"};
36 const std::string CSCRIPT{"cscript"};
37 const std::string DEFAULTKEY{"defaultkey"};
38 const std::string DESTDATA{"destdata"};
39 const std::string FLAGS{"flags"};
40 const std::string HDCHAIN{"hdchain"};
41 const std::string KEYMETA{"keymeta"};
42 const std::string KEY{"key"};
43 const std::string MASTER_KEY{"mkey"};
44 const std::string MINVERSION{"minversion"};
45 const std::string NAME{"name"};
46 const std::string OLD_KEY{"wkey"};
47 const std::string ORDERPOSNEXT{"orderposnext"};
48 const std::string POOL{"pool"};
49 const std::string PURPOSE{"purpose"};
50 const std::string SETTINGS{"settings"};
51 const std::string TX{"tx"};
52 const std::string VERSION{"version"};
53 const std::string WALLETDESCRIPTOR{"walletdescriptor"};
54 const std::string WALLETDESCRIPTORCACHE{"walletdescriptorcache"};
55 const std::string WALLETDESCRIPTORLHCACHE{"walletdescriptorlhcache"};
56 const std::string WALLETDESCRIPTORCKEY{"walletdescriptorckey"};
57 const std::string WALLETDESCRIPTORKEY{"walletdescriptorkey"};
58 const std::string WATCHMETA{"watchmeta"};
59 const std::string WATCHS{"watchs"};
60 } // namespace DBKeys
61
62 //
63 // WalletBatch
64 //
65
WriteName(const std::string & strAddress,const std::string & strName)66 bool WalletBatch::WriteName(const std::string& strAddress, const std::string& strName)
67 {
68 return WriteIC(std::make_pair(DBKeys::NAME, strAddress), strName);
69 }
70
EraseName(const std::string & strAddress)71 bool WalletBatch::EraseName(const std::string& strAddress)
72 {
73 // This should only be used for sending addresses, never for receiving addresses,
74 // receiving addresses must always have an address book entry if they're not change return.
75 return EraseIC(std::make_pair(DBKeys::NAME, strAddress));
76 }
77
WritePurpose(const std::string & strAddress,const std::string & strPurpose)78 bool WalletBatch::WritePurpose(const std::string& strAddress, const std::string& strPurpose)
79 {
80 return WriteIC(std::make_pair(DBKeys::PURPOSE, strAddress), strPurpose);
81 }
82
ErasePurpose(const std::string & strAddress)83 bool WalletBatch::ErasePurpose(const std::string& strAddress)
84 {
85 return EraseIC(std::make_pair(DBKeys::PURPOSE, strAddress));
86 }
87
WriteTx(const CWalletTx & wtx)88 bool WalletBatch::WriteTx(const CWalletTx& wtx)
89 {
90 return WriteIC(std::make_pair(DBKeys::TX, wtx.GetHash()), wtx);
91 }
92
EraseTx(uint256 hash)93 bool WalletBatch::EraseTx(uint256 hash)
94 {
95 return EraseIC(std::make_pair(DBKeys::TX, hash));
96 }
97
WriteKeyMetadata(const CKeyMetadata & meta,const CPubKey & pubkey,const bool overwrite)98 bool WalletBatch::WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite)
99 {
100 return WriteIC(std::make_pair(DBKeys::KEYMETA, pubkey), meta, overwrite);
101 }
102
WriteKey(const CPubKey & vchPubKey,const CPrivKey & vchPrivKey,const CKeyMetadata & keyMeta)103 bool WalletBatch::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
104 {
105 if (!WriteKeyMetadata(keyMeta, vchPubKey, false)) {
106 return false;
107 }
108
109 // hash pubkey/privkey to accelerate wallet load
110 std::vector<unsigned char> vchKey;
111 vchKey.reserve(vchPubKey.size() + vchPrivKey.size());
112 vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
113 vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
114
115 return WriteIC(std::make_pair(DBKeys::KEY, vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey)), false);
116 }
117
WriteCryptedKey(const CPubKey & vchPubKey,const std::vector<unsigned char> & vchCryptedSecret,const CKeyMetadata & keyMeta)118 bool WalletBatch::WriteCryptedKey(const CPubKey& vchPubKey,
119 const std::vector<unsigned char>& vchCryptedSecret,
120 const CKeyMetadata &keyMeta)
121 {
122 if (!WriteKeyMetadata(keyMeta, vchPubKey, true)) {
123 return false;
124 }
125
126 // Compute a checksum of the encrypted key
127 uint256 checksum = Hash(vchCryptedSecret);
128
129 const auto key = std::make_pair(DBKeys::CRYPTED_KEY, vchPubKey);
130 if (!WriteIC(key, std::make_pair(vchCryptedSecret, checksum), false)) {
131 // It may already exist, so try writing just the checksum
132 std::vector<unsigned char> val;
133 if (!m_batch->Read(key, val)) {
134 return false;
135 }
136 if (!WriteIC(key, std::make_pair(val, checksum), true)) {
137 return false;
138 }
139 }
140 EraseIC(std::make_pair(DBKeys::KEY, vchPubKey));
141 return true;
142 }
143
WriteMasterKey(unsigned int nID,const CMasterKey & kMasterKey)144 bool WalletBatch::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
145 {
146 return WriteIC(std::make_pair(DBKeys::MASTER_KEY, nID), kMasterKey, true);
147 }
148
WriteCScript(const uint160 & hash,const CScript & redeemScript)149 bool WalletBatch::WriteCScript(const uint160& hash, const CScript& redeemScript)
150 {
151 return WriteIC(std::make_pair(DBKeys::CSCRIPT, hash), redeemScript, false);
152 }
153
WriteWatchOnly(const CScript & dest,const CKeyMetadata & keyMeta)154 bool WalletBatch::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta)
155 {
156 if (!WriteIC(std::make_pair(DBKeys::WATCHMETA, dest), keyMeta)) {
157 return false;
158 }
159 return WriteIC(std::make_pair(DBKeys::WATCHS, dest), uint8_t{'1'});
160 }
161
EraseWatchOnly(const CScript & dest)162 bool WalletBatch::EraseWatchOnly(const CScript &dest)
163 {
164 if (!EraseIC(std::make_pair(DBKeys::WATCHMETA, dest))) {
165 return false;
166 }
167 return EraseIC(std::make_pair(DBKeys::WATCHS, dest));
168 }
169
WriteBestBlock(const CBlockLocator & locator)170 bool WalletBatch::WriteBestBlock(const CBlockLocator& locator)
171 {
172 WriteIC(DBKeys::BESTBLOCK, CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
173 return WriteIC(DBKeys::BESTBLOCK_NOMERKLE, locator);
174 }
175
ReadBestBlock(CBlockLocator & locator)176 bool WalletBatch::ReadBestBlock(CBlockLocator& locator)
177 {
178 if (m_batch->Read(DBKeys::BESTBLOCK, locator) && !locator.vHave.empty()) return true;
179 return m_batch->Read(DBKeys::BESTBLOCK_NOMERKLE, locator);
180 }
181
WriteOrderPosNext(int64_t nOrderPosNext)182 bool WalletBatch::WriteOrderPosNext(int64_t nOrderPosNext)
183 {
184 return WriteIC(DBKeys::ORDERPOSNEXT, nOrderPosNext);
185 }
186
ReadPool(int64_t nPool,CKeyPool & keypool)187 bool WalletBatch::ReadPool(int64_t nPool, CKeyPool& keypool)
188 {
189 return m_batch->Read(std::make_pair(DBKeys::POOL, nPool), keypool);
190 }
191
WritePool(int64_t nPool,const CKeyPool & keypool)192 bool WalletBatch::WritePool(int64_t nPool, const CKeyPool& keypool)
193 {
194 return WriteIC(std::make_pair(DBKeys::POOL, nPool), keypool);
195 }
196
ErasePool(int64_t nPool)197 bool WalletBatch::ErasePool(int64_t nPool)
198 {
199 return EraseIC(std::make_pair(DBKeys::POOL, nPool));
200 }
201
WriteMinVersion(int nVersion)202 bool WalletBatch::WriteMinVersion(int nVersion)
203 {
204 return WriteIC(DBKeys::MINVERSION, nVersion);
205 }
206
WriteActiveScriptPubKeyMan(uint8_t type,const uint256 & id,bool internal)207 bool WalletBatch::WriteActiveScriptPubKeyMan(uint8_t type, const uint256& id, bool internal)
208 {
209 std::string key = internal ? DBKeys::ACTIVEINTERNALSPK : DBKeys::ACTIVEEXTERNALSPK;
210 return WriteIC(make_pair(key, type), id);
211 }
212
EraseActiveScriptPubKeyMan(uint8_t type,bool internal)213 bool WalletBatch::EraseActiveScriptPubKeyMan(uint8_t type, bool internal)
214 {
215 const std::string key{internal ? DBKeys::ACTIVEINTERNALSPK : DBKeys::ACTIVEEXTERNALSPK};
216 return EraseIC(make_pair(key, type));
217 }
218
WriteDescriptorKey(const uint256 & desc_id,const CPubKey & pubkey,const CPrivKey & privkey)219 bool WalletBatch::WriteDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const CPrivKey& privkey)
220 {
221 // hash pubkey/privkey to accelerate wallet load
222 std::vector<unsigned char> key;
223 key.reserve(pubkey.size() + privkey.size());
224 key.insert(key.end(), pubkey.begin(), pubkey.end());
225 key.insert(key.end(), privkey.begin(), privkey.end());
226
227 return WriteIC(std::make_pair(DBKeys::WALLETDESCRIPTORKEY, std::make_pair(desc_id, pubkey)), std::make_pair(privkey, Hash(key)), false);
228 }
229
WriteCryptedDescriptorKey(const uint256 & desc_id,const CPubKey & pubkey,const std::vector<unsigned char> & secret)230 bool WalletBatch::WriteCryptedDescriptorKey(const uint256& desc_id, const CPubKey& pubkey, const std::vector<unsigned char>& secret)
231 {
232 if (!WriteIC(std::make_pair(DBKeys::WALLETDESCRIPTORCKEY, std::make_pair(desc_id, pubkey)), secret, false)) {
233 return false;
234 }
235 EraseIC(std::make_pair(DBKeys::WALLETDESCRIPTORKEY, std::make_pair(desc_id, pubkey)));
236 return true;
237 }
238
WriteDescriptor(const uint256 & desc_id,const WalletDescriptor & descriptor)239 bool WalletBatch::WriteDescriptor(const uint256& desc_id, const WalletDescriptor& descriptor)
240 {
241 return WriteIC(make_pair(DBKeys::WALLETDESCRIPTOR, desc_id), descriptor);
242 }
243
WriteDescriptorDerivedCache(const CExtPubKey & xpub,const uint256 & desc_id,uint32_t key_exp_index,uint32_t der_index)244 bool WalletBatch::WriteDescriptorDerivedCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index, uint32_t der_index)
245 {
246 std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
247 xpub.Encode(ser_xpub.data());
248 return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORCACHE, desc_id), std::make_pair(key_exp_index, der_index)), ser_xpub);
249 }
250
WriteDescriptorParentCache(const CExtPubKey & xpub,const uint256 & desc_id,uint32_t key_exp_index)251 bool WalletBatch::WriteDescriptorParentCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index)
252 {
253 std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
254 xpub.Encode(ser_xpub.data());
255 return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORCACHE, desc_id), key_exp_index), ser_xpub);
256 }
257
WriteDescriptorLastHardenedCache(const CExtPubKey & xpub,const uint256 & desc_id,uint32_t key_exp_index)258 bool WalletBatch::WriteDescriptorLastHardenedCache(const CExtPubKey& xpub, const uint256& desc_id, uint32_t key_exp_index)
259 {
260 std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
261 xpub.Encode(ser_xpub.data());
262 return WriteIC(std::make_pair(std::make_pair(DBKeys::WALLETDESCRIPTORLHCACHE, desc_id), key_exp_index), ser_xpub);
263 }
264
WriteDescriptorCacheItems(const uint256 & desc_id,const DescriptorCache & cache)265 bool WalletBatch::WriteDescriptorCacheItems(const uint256& desc_id, const DescriptorCache& cache)
266 {
267 for (const auto& parent_xpub_pair : cache.GetCachedParentExtPubKeys()) {
268 if (!WriteDescriptorParentCache(parent_xpub_pair.second, desc_id, parent_xpub_pair.first)) {
269 return false;
270 }
271 }
272 for (const auto& derived_xpub_map_pair : cache.GetCachedDerivedExtPubKeys()) {
273 for (const auto& derived_xpub_pair : derived_xpub_map_pair.second) {
274 if (!WriteDescriptorDerivedCache(derived_xpub_pair.second, desc_id, derived_xpub_map_pair.first, derived_xpub_pair.first)) {
275 return false;
276 }
277 }
278 }
279 for (const auto& lh_xpub_pair : cache.GetCachedLastHardenedExtPubKeys()) {
280 if (!WriteDescriptorLastHardenedCache(lh_xpub_pair.second, desc_id, lh_xpub_pair.first)) {
281 return false;
282 }
283 }
284 return true;
285 }
286
287 class CWalletScanState {
288 public:
289 unsigned int nKeys{0};
290 unsigned int nCKeys{0};
291 unsigned int nWatchKeys{0};
292 unsigned int nKeyMeta{0};
293 unsigned int m_unknown_records{0};
294 bool fIsEncrypted{false};
295 bool fAnyUnordered{false};
296 std::vector<uint256> vWalletUpgrade;
297 std::map<OutputType, uint256> m_active_external_spks;
298 std::map<OutputType, uint256> m_active_internal_spks;
299 std::map<uint256, DescriptorCache> m_descriptor_caches;
300 std::map<std::pair<uint256, CKeyID>, CKey> m_descriptor_keys;
301 std::map<std::pair<uint256, CKeyID>, std::pair<CPubKey, std::vector<unsigned char>>> m_descriptor_crypt_keys;
302 std::map<uint160, CHDChain> m_hd_chains;
303
CWalletScanState()304 CWalletScanState() {
305 }
306 };
307
308 static bool
ReadKeyValue(CWallet * pwallet,CDataStream & ssKey,CDataStream & ssValue,CWalletScanState & wss,std::string & strType,std::string & strErr,const KeyFilterFn & filter_fn=nullptr)309 ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
310 CWalletScanState &wss, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
311 {
312 try {
313 // Unserialize
314 // Taking advantage of the fact that pair serialization
315 // is just the two items serialized one after the other
316 ssKey >> strType;
317 // If we have a filter, check if this matches the filter
318 if (filter_fn && !filter_fn(strType)) {
319 return true;
320 }
321 if (strType == DBKeys::NAME) {
322 std::string strAddress;
323 ssKey >> strAddress;
324 std::string label;
325 ssValue >> label;
326 pwallet->m_address_book[DecodeDestination(strAddress)].SetLabel(label);
327 } else if (strType == DBKeys::PURPOSE) {
328 std::string strAddress;
329 ssKey >> strAddress;
330 ssValue >> pwallet->m_address_book[DecodeDestination(strAddress)].purpose;
331 } else if (strType == DBKeys::TX) {
332 uint256 hash;
333 ssKey >> hash;
334 // LoadToWallet call below creates a new CWalletTx that fill_wtx
335 // callback fills with transaction metadata.
336 auto fill_wtx = [&](CWalletTx& wtx, bool new_tx) {
337 assert(new_tx);
338 ssValue >> wtx;
339 if (wtx.GetHash() != hash)
340 return false;
341
342 // Undo serialize changes in 31600
343 if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
344 {
345 if (!ssValue.empty())
346 {
347 uint8_t fTmp;
348 uint8_t fUnused;
349 std::string unused_string;
350 ssValue >> fTmp >> fUnused >> unused_string;
351 strErr = strprintf("LoadWallet() upgrading tx ver=%d %d %s",
352 wtx.fTimeReceivedIsTxTime, fTmp, hash.ToString());
353 wtx.fTimeReceivedIsTxTime = fTmp;
354 }
355 else
356 {
357 strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
358 wtx.fTimeReceivedIsTxTime = 0;
359 }
360 wss.vWalletUpgrade.push_back(hash);
361 }
362
363 if (wtx.nOrderPos == -1)
364 wss.fAnyUnordered = true;
365
366 return true;
367 };
368 if (!pwallet->LoadToWallet(hash, fill_wtx)) {
369 return false;
370 }
371 } else if (strType == DBKeys::WATCHS) {
372 wss.nWatchKeys++;
373 CScript script;
374 ssKey >> script;
375 uint8_t fYes;
376 ssValue >> fYes;
377 if (fYes == '1') {
378 pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadWatchOnly(script);
379 }
380 } else if (strType == DBKeys::KEY) {
381 CPubKey vchPubKey;
382 ssKey >> vchPubKey;
383 if (!vchPubKey.IsValid())
384 {
385 strErr = "Error reading wallet database: CPubKey corrupt";
386 return false;
387 }
388 CKey key;
389 CPrivKey pkey;
390 uint256 hash;
391
392 wss.nKeys++;
393 ssValue >> pkey;
394
395 // Old wallets store keys as DBKeys::KEY [pubkey] => [privkey]
396 // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key
397 // using EC operations as a checksum.
398 // Newer wallets store keys as DBKeys::KEY [pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while
399 // remaining backwards-compatible.
400 try
401 {
402 ssValue >> hash;
403 }
404 catch (const std::ios_base::failure&) {}
405
406 bool fSkipCheck = false;
407
408 if (!hash.IsNull())
409 {
410 // hash pubkey/privkey to accelerate wallet load
411 std::vector<unsigned char> vchKey;
412 vchKey.reserve(vchPubKey.size() + pkey.size());
413 vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
414 vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
415
416 if (Hash(vchKey) != hash)
417 {
418 strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
419 return false;
420 }
421
422 fSkipCheck = true;
423 }
424
425 if (!key.Load(pkey, vchPubKey, fSkipCheck))
426 {
427 strErr = "Error reading wallet database: CPrivKey corrupt";
428 return false;
429 }
430 if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKey(key, vchPubKey))
431 {
432 strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadKey failed";
433 return false;
434 }
435 } else if (strType == DBKeys::MASTER_KEY) {
436 // Master encryption key is loaded into only the wallet and not any of the ScriptPubKeyMans.
437 unsigned int nID;
438 ssKey >> nID;
439 CMasterKey kMasterKey;
440 ssValue >> kMasterKey;
441 if(pwallet->mapMasterKeys.count(nID) != 0)
442 {
443 strErr = strprintf("Error reading wallet database: duplicate CMasterKey id %u", nID);
444 return false;
445 }
446 pwallet->mapMasterKeys[nID] = kMasterKey;
447 if (pwallet->nMasterKeyMaxID < nID)
448 pwallet->nMasterKeyMaxID = nID;
449 } else if (strType == DBKeys::CRYPTED_KEY) {
450 CPubKey vchPubKey;
451 ssKey >> vchPubKey;
452 if (!vchPubKey.IsValid())
453 {
454 strErr = "Error reading wallet database: CPubKey corrupt";
455 return false;
456 }
457 std::vector<unsigned char> vchPrivKey;
458 ssValue >> vchPrivKey;
459
460 // Get the checksum and check it
461 bool checksum_valid = false;
462 if (!ssValue.eof()) {
463 uint256 checksum;
464 ssValue >> checksum;
465 if ((checksum_valid = Hash(vchPrivKey) != checksum)) {
466 strErr = "Error reading wallet database: Encrypted key corrupt";
467 return false;
468 }
469 }
470
471 wss.nCKeys++;
472
473 if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadCryptedKey(vchPubKey, vchPrivKey, checksum_valid))
474 {
475 strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadCryptedKey failed";
476 return false;
477 }
478 wss.fIsEncrypted = true;
479 } else if (strType == DBKeys::KEYMETA) {
480 CPubKey vchPubKey;
481 ssKey >> vchPubKey;
482 CKeyMetadata keyMeta;
483 ssValue >> keyMeta;
484 wss.nKeyMeta++;
485 pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKeyMetadata(vchPubKey.GetID(), keyMeta);
486
487 // Extract some CHDChain info from this metadata if it has any
488 if (keyMeta.nVersion >= CKeyMetadata::VERSION_WITH_HDDATA && !keyMeta.hd_seed_id.IsNull() && keyMeta.hdKeypath.size() > 0) {
489 // Get the path from the key origin or from the path string
490 // Not applicable when path is "s" or "m" as those indicate a seed
491 // See https://github.com/bitcoin/bitcoin/pull/12924
492 bool internal = false;
493 uint32_t index = 0;
494 if (keyMeta.hdKeypath != "s" && keyMeta.hdKeypath != "m") {
495 std::vector<uint32_t> path;
496 if (keyMeta.has_key_origin) {
497 // We have a key origin, so pull it from its path vector
498 path = keyMeta.key_origin.path;
499 } else {
500 // No key origin, have to parse the string
501 if (!ParseHDKeypath(keyMeta.hdKeypath, path)) {
502 strErr = "Error reading wallet database: keymeta with invalid HD keypath";
503 return false;
504 }
505 }
506
507 // Extract the index and internal from the path
508 // Path string is m/0'/k'/i'
509 // Path vector is [0', k', i'] (but as ints OR'd with the hardened bit
510 // k == 0 for external, 1 for internal. i is the index
511 if (path.size() != 3) {
512 strErr = "Error reading wallet database: keymeta found with unexpected path";
513 return false;
514 }
515 if (path[0] != 0x80000000) {
516 strErr = strprintf("Unexpected path index of 0x%08x (expected 0x80000000) for the element at index 0", path[0]);
517 return false;
518 }
519 if (path[1] != 0x80000000 && path[1] != (1 | 0x80000000)) {
520 strErr = strprintf("Unexpected path index of 0x%08x (expected 0x80000000 or 0x80000001) for the element at index 1", path[1]);
521 return false;
522 }
523 if ((path[2] & 0x80000000) == 0) {
524 strErr = strprintf("Unexpected path index of 0x%08x (expected to be greater than or equal to 0x80000000)", path[2]);
525 return false;
526 }
527 internal = path[1] == (1 | 0x80000000);
528 index = path[2] & ~0x80000000;
529 }
530
531 // Insert a new CHDChain, or get the one that already exists
532 auto ins = wss.m_hd_chains.emplace(keyMeta.hd_seed_id, CHDChain());
533 CHDChain& chain = ins.first->second;
534 if (ins.second) {
535 // For new chains, we want to default to VERSION_HD_BASE until we see an internal
536 chain.nVersion = CHDChain::VERSION_HD_BASE;
537 chain.seed_id = keyMeta.hd_seed_id;
538 }
539 if (internal) {
540 chain.nVersion = CHDChain::VERSION_HD_CHAIN_SPLIT;
541 chain.nInternalChainCounter = std::max(chain.nInternalChainCounter, index);
542 } else {
543 chain.nExternalChainCounter = std::max(chain.nExternalChainCounter, index);
544 }
545 }
546 } else if (strType == DBKeys::WATCHMETA) {
547 CScript script;
548 ssKey >> script;
549 CKeyMetadata keyMeta;
550 ssValue >> keyMeta;
551 wss.nKeyMeta++;
552 pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadScriptMetadata(CScriptID(script), keyMeta);
553 } else if (strType == DBKeys::DEFAULTKEY) {
554 // We don't want or need the default key, but if there is one set,
555 // we want to make sure that it is valid so that we can detect corruption
556 CPubKey vchPubKey;
557 ssValue >> vchPubKey;
558 if (!vchPubKey.IsValid()) {
559 strErr = "Error reading wallet database: Default Key corrupt";
560 return false;
561 }
562 } else if (strType == DBKeys::POOL) {
563 int64_t nIndex;
564 ssKey >> nIndex;
565 CKeyPool keypool;
566 ssValue >> keypool;
567
568 pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKeyPool(nIndex, keypool);
569 } else if (strType == DBKeys::CSCRIPT) {
570 uint160 hash;
571 ssKey >> hash;
572 CScript script;
573 ssValue >> script;
574 if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadCScript(script))
575 {
576 strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadCScript failed";
577 return false;
578 }
579 } else if (strType == DBKeys::ORDERPOSNEXT) {
580 ssValue >> pwallet->nOrderPosNext;
581 } else if (strType == DBKeys::DESTDATA) {
582 std::string strAddress, strKey, strValue;
583 ssKey >> strAddress;
584 ssKey >> strKey;
585 ssValue >> strValue;
586 pwallet->LoadDestData(DecodeDestination(strAddress), strKey, strValue);
587 } else if (strType == DBKeys::HDCHAIN) {
588 CHDChain chain;
589 ssValue >> chain;
590 pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadHDChain(chain);
591 } else if (strType == DBKeys::OLD_KEY) {
592 strErr = "Found unsupported 'wkey' record, try loading with version 0.18";
593 return false;
594 } else if (strType == DBKeys::ACTIVEEXTERNALSPK || strType == DBKeys::ACTIVEINTERNALSPK) {
595 uint8_t type;
596 ssKey >> type;
597 uint256 id;
598 ssValue >> id;
599
600 bool internal = strType == DBKeys::ACTIVEINTERNALSPK;
601 auto& spk_mans = internal ? wss.m_active_internal_spks : wss.m_active_external_spks;
602 if (spk_mans.count(static_cast<OutputType>(type)) > 0) {
603 strErr = "Multiple ScriptPubKeyMans specified for a single type";
604 return false;
605 }
606 spk_mans[static_cast<OutputType>(type)] = id;
607 } else if (strType == DBKeys::WALLETDESCRIPTOR) {
608 uint256 id;
609 ssKey >> id;
610 WalletDescriptor desc;
611 ssValue >> desc;
612 if (wss.m_descriptor_caches.count(id) == 0) {
613 wss.m_descriptor_caches[id] = DescriptorCache();
614 }
615 pwallet->LoadDescriptorScriptPubKeyMan(id, desc);
616 } else if (strType == DBKeys::WALLETDESCRIPTORCACHE) {
617 bool parent = true;
618 uint256 desc_id;
619 uint32_t key_exp_index;
620 uint32_t der_index;
621 ssKey >> desc_id;
622 ssKey >> key_exp_index;
623
624 // if the der_index exists, it's a derived xpub
625 try
626 {
627 ssKey >> der_index;
628 parent = false;
629 }
630 catch (...) {}
631
632 std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
633 ssValue >> ser_xpub;
634 CExtPubKey xpub;
635 xpub.Decode(ser_xpub.data());
636 if (parent) {
637 wss.m_descriptor_caches[desc_id].CacheParentExtPubKey(key_exp_index, xpub);
638 } else {
639 wss.m_descriptor_caches[desc_id].CacheDerivedExtPubKey(key_exp_index, der_index, xpub);
640 }
641 } else if (strType == DBKeys::WALLETDESCRIPTORLHCACHE) {
642 uint256 desc_id;
643 uint32_t key_exp_index;
644 ssKey >> desc_id;
645 ssKey >> key_exp_index;
646
647 std::vector<unsigned char> ser_xpub(BIP32_EXTKEY_SIZE);
648 ssValue >> ser_xpub;
649 CExtPubKey xpub;
650 xpub.Decode(ser_xpub.data());
651 wss.m_descriptor_caches[desc_id].CacheLastHardenedExtPubKey(key_exp_index, xpub);
652 } else if (strType == DBKeys::WALLETDESCRIPTORKEY) {
653 uint256 desc_id;
654 CPubKey pubkey;
655 ssKey >> desc_id;
656 ssKey >> pubkey;
657 if (!pubkey.IsValid())
658 {
659 strErr = "Error reading wallet database: CPubKey corrupt";
660 return false;
661 }
662 CKey key;
663 CPrivKey pkey;
664 uint256 hash;
665
666 wss.nKeys++;
667 ssValue >> pkey;
668 ssValue >> hash;
669
670 // hash pubkey/privkey to accelerate wallet load
671 std::vector<unsigned char> to_hash;
672 to_hash.reserve(pubkey.size() + pkey.size());
673 to_hash.insert(to_hash.end(), pubkey.begin(), pubkey.end());
674 to_hash.insert(to_hash.end(), pkey.begin(), pkey.end());
675
676 if (Hash(to_hash) != hash)
677 {
678 strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
679 return false;
680 }
681
682 if (!key.Load(pkey, pubkey, true))
683 {
684 strErr = "Error reading wallet database: CPrivKey corrupt";
685 return false;
686 }
687 wss.m_descriptor_keys.insert(std::make_pair(std::make_pair(desc_id, pubkey.GetID()), key));
688 } else if (strType == DBKeys::WALLETDESCRIPTORCKEY) {
689 uint256 desc_id;
690 CPubKey pubkey;
691 ssKey >> desc_id;
692 ssKey >> pubkey;
693 if (!pubkey.IsValid())
694 {
695 strErr = "Error reading wallet database: CPubKey corrupt";
696 return false;
697 }
698 std::vector<unsigned char> privkey;
699 ssValue >> privkey;
700 wss.nCKeys++;
701
702 wss.m_descriptor_crypt_keys.insert(std::make_pair(std::make_pair(desc_id, pubkey.GetID()), std::make_pair(pubkey, privkey)));
703 wss.fIsEncrypted = true;
704 } else if (strType != DBKeys::BESTBLOCK && strType != DBKeys::BESTBLOCK_NOMERKLE &&
705 strType != DBKeys::MINVERSION && strType != DBKeys::ACENTRY &&
706 strType != DBKeys::VERSION && strType != DBKeys::SETTINGS &&
707 strType != DBKeys::FLAGS) {
708 wss.m_unknown_records++;
709 }
710 } catch (const std::exception& e) {
711 if (strErr.empty()) {
712 strErr = e.what();
713 }
714 return false;
715 } catch (...) {
716 if (strErr.empty()) {
717 strErr = "Caught unknown exception in ReadKeyValue";
718 }
719 return false;
720 }
721 return true;
722 }
723
ReadKeyValue(CWallet * pwallet,CDataStream & ssKey,CDataStream & ssValue,std::string & strType,std::string & strErr,const KeyFilterFn & filter_fn)724 bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn)
725 {
726 CWalletScanState dummy_wss;
727 LOCK(pwallet->cs_wallet);
728 return ReadKeyValue(pwallet, ssKey, ssValue, dummy_wss, strType, strErr, filter_fn);
729 }
730
IsKeyType(const std::string & strType)731 bool WalletBatch::IsKeyType(const std::string& strType)
732 {
733 return (strType == DBKeys::KEY ||
734 strType == DBKeys::MASTER_KEY || strType == DBKeys::CRYPTED_KEY);
735 }
736
LoadWallet(CWallet * pwallet)737 DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
738 {
739 CWalletScanState wss;
740 bool fNoncriticalErrors = false;
741 DBErrors result = DBErrors::LOAD_OK;
742
743 LOCK(pwallet->cs_wallet);
744 try {
745 int nMinVersion = 0;
746 if (m_batch->Read(DBKeys::MINVERSION, nMinVersion)) {
747 if (nMinVersion > FEATURE_LATEST)
748 return DBErrors::TOO_NEW;
749 pwallet->LoadMinVersion(nMinVersion);
750 }
751
752 // Load wallet flags, so they are known when processing other records.
753 // The FLAGS key is absent during wallet creation.
754 uint64_t flags;
755 if (m_batch->Read(DBKeys::FLAGS, flags)) {
756 if (!pwallet->LoadWalletFlags(flags)) {
757 pwallet->WalletLogPrintf("Error reading wallet database: Unknown non-tolerable wallet flags found\n");
758 return DBErrors::CORRUPT;
759 }
760 }
761
762 #ifndef ENABLE_EXTERNAL_SIGNER
763 if (pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
764 pwallet->WalletLogPrintf("Error: External signer wallet being loaded without external signer support compiled\n");
765 return DBErrors::TOO_NEW;
766 }
767 #endif
768
769 // Get cursor
770 if (!m_batch->StartCursor())
771 {
772 pwallet->WalletLogPrintf("Error getting wallet database cursor\n");
773 return DBErrors::CORRUPT;
774 }
775
776 while (true)
777 {
778 // Read next record
779 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
780 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
781 bool complete;
782 bool ret = m_batch->ReadAtCursor(ssKey, ssValue, complete);
783 if (complete) {
784 break;
785 }
786 else if (!ret)
787 {
788 m_batch->CloseCursor();
789 pwallet->WalletLogPrintf("Error reading next record from wallet database\n");
790 return DBErrors::CORRUPT;
791 }
792
793 // Try to be tolerant of single corrupt records:
794 std::string strType, strErr;
795 if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
796 {
797 // losing keys is considered a catastrophic error, anything else
798 // we assume the user can live with:
799 if (IsKeyType(strType) || strType == DBKeys::DEFAULTKEY) {
800 result = DBErrors::CORRUPT;
801 } else if (strType == DBKeys::FLAGS) {
802 // reading the wallet flags can only fail if unknown flags are present
803 result = DBErrors::TOO_NEW;
804 } else {
805 // Leave other errors alone, if we try to fix them we might make things worse.
806 fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
807 if (strType == DBKeys::TX)
808 // Rescan if there is a bad transaction record:
809 gArgs.SoftSetBoolArg("-rescan", true);
810 }
811 }
812 if (!strErr.empty())
813 pwallet->WalletLogPrintf("%s\n", strErr);
814 }
815 } catch (...) {
816 result = DBErrors::CORRUPT;
817 }
818 m_batch->CloseCursor();
819
820 // Set the active ScriptPubKeyMans
821 for (auto spk_man_pair : wss.m_active_external_spks) {
822 pwallet->LoadActiveScriptPubKeyMan(spk_man_pair.second, spk_man_pair.first, /* internal */ false);
823 }
824 for (auto spk_man_pair : wss.m_active_internal_spks) {
825 pwallet->LoadActiveScriptPubKeyMan(spk_man_pair.second, spk_man_pair.first, /* internal */ true);
826 }
827
828 // Set the descriptor caches
829 for (auto desc_cache_pair : wss.m_descriptor_caches) {
830 auto spk_man = pwallet->GetScriptPubKeyMan(desc_cache_pair.first);
831 assert(spk_man);
832 ((DescriptorScriptPubKeyMan*)spk_man)->SetCache(desc_cache_pair.second);
833 }
834
835 // Set the descriptor keys
836 for (auto desc_key_pair : wss.m_descriptor_keys) {
837 auto spk_man = pwallet->GetScriptPubKeyMan(desc_key_pair.first.first);
838 ((DescriptorScriptPubKeyMan*)spk_man)->AddKey(desc_key_pair.first.second, desc_key_pair.second);
839 }
840 for (auto desc_key_pair : wss.m_descriptor_crypt_keys) {
841 auto spk_man = pwallet->GetScriptPubKeyMan(desc_key_pair.first.first);
842 ((DescriptorScriptPubKeyMan*)spk_man)->AddCryptedKey(desc_key_pair.first.second, desc_key_pair.second.first, desc_key_pair.second.second);
843 }
844
845 if (fNoncriticalErrors && result == DBErrors::LOAD_OK)
846 result = DBErrors::NONCRITICAL_ERROR;
847
848 // Any wallet corruption at all: skip any rewriting or
849 // upgrading, we don't want to make it worse.
850 if (result != DBErrors::LOAD_OK)
851 return result;
852
853 // Last client version to open this wallet, was previously the file version number
854 int last_client = CLIENT_VERSION;
855 m_batch->Read(DBKeys::VERSION, last_client);
856
857 int wallet_version = pwallet->GetVersion();
858 pwallet->WalletLogPrintf("Wallet File Version = %d\n", wallet_version > 0 ? wallet_version : last_client);
859
860 pwallet->WalletLogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total. Unknown wallet records: %u\n",
861 wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys, wss.m_unknown_records);
862
863 // nTimeFirstKey is only reliable if all keys have metadata
864 if (pwallet->IsLegacy() && (wss.nKeys + wss.nCKeys + wss.nWatchKeys) != wss.nKeyMeta) {
865 auto spk_man = pwallet->GetOrCreateLegacyScriptPubKeyMan();
866 if (spk_man) {
867 LOCK(spk_man->cs_KeyStore);
868 spk_man->UpdateTimeFirstKey(1);
869 }
870 }
871
872 for (const uint256& hash : wss.vWalletUpgrade)
873 WriteTx(pwallet->mapWallet.at(hash));
874
875 // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
876 if (wss.fIsEncrypted && (last_client == 40000 || last_client == 50000))
877 return DBErrors::NEED_REWRITE;
878
879 if (last_client < CLIENT_VERSION) // Update
880 m_batch->Write(DBKeys::VERSION, CLIENT_VERSION);
881
882 if (wss.fAnyUnordered)
883 result = pwallet->ReorderTransactions();
884
885 // Upgrade all of the wallet keymetadata to have the hd master key id
886 // This operation is not atomic, but if it fails, updated entries are still backwards compatible with older software
887 try {
888 pwallet->UpgradeKeyMetadata();
889 } catch (...) {
890 result = DBErrors::CORRUPT;
891 }
892
893 // Upgrade all of the descriptor caches to cache the last hardened xpub
894 // This operation is not atomic, but if it fails, only new entries are added so it is backwards compatible
895 try {
896 pwallet->UpgradeDescriptorCache();
897 } catch (...) {
898 result = DBErrors::CORRUPT;
899 }
900
901 // Set the inactive chain
902 if (wss.m_hd_chains.size() > 0) {
903 LegacyScriptPubKeyMan* legacy_spkm = pwallet->GetLegacyScriptPubKeyMan();
904 if (!legacy_spkm) {
905 pwallet->WalletLogPrintf("Inactive HD Chains found but no Legacy ScriptPubKeyMan\n");
906 return DBErrors::CORRUPT;
907 }
908 for (const auto& chain_pair : wss.m_hd_chains) {
909 if (chain_pair.first != pwallet->GetLegacyScriptPubKeyMan()->GetHDChain().seed_id) {
910 pwallet->GetLegacyScriptPubKeyMan()->AddInactiveHDChain(chain_pair.second);
911 }
912 }
913 }
914
915 return result;
916 }
917
FindWalletTx(std::vector<uint256> & vTxHash,std::list<CWalletTx> & vWtx)918 DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::list<CWalletTx>& vWtx)
919 {
920 DBErrors result = DBErrors::LOAD_OK;
921
922 try {
923 int nMinVersion = 0;
924 if (m_batch->Read(DBKeys::MINVERSION, nMinVersion)) {
925 if (nMinVersion > FEATURE_LATEST)
926 return DBErrors::TOO_NEW;
927 }
928
929 // Get cursor
930 if (!m_batch->StartCursor())
931 {
932 LogPrintf("Error getting wallet database cursor\n");
933 return DBErrors::CORRUPT;
934 }
935
936 while (true)
937 {
938 // Read next record
939 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
940 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
941 bool complete;
942 bool ret = m_batch->ReadAtCursor(ssKey, ssValue, complete);
943 if (complete) {
944 break;
945 } else if (!ret) {
946 m_batch->CloseCursor();
947 LogPrintf("Error reading next record from wallet database\n");
948 return DBErrors::CORRUPT;
949 }
950
951 std::string strType;
952 ssKey >> strType;
953 if (strType == DBKeys::TX) {
954 uint256 hash;
955 ssKey >> hash;
956 vTxHash.push_back(hash);
957 vWtx.emplace_back(nullptr /* wallet */, nullptr /* tx */);
958 ssValue >> vWtx.back();
959 }
960 }
961 } catch (...) {
962 result = DBErrors::CORRUPT;
963 }
964 m_batch->CloseCursor();
965
966 return result;
967 }
968
ZapSelectTx(std::vector<uint256> & vTxHashIn,std::vector<uint256> & vTxHashOut)969 DBErrors WalletBatch::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<uint256>& vTxHashOut)
970 {
971 // build list of wallet TXs and hashes
972 std::vector<uint256> vTxHash;
973 std::list<CWalletTx> vWtx;
974 DBErrors err = FindWalletTx(vTxHash, vWtx);
975 if (err != DBErrors::LOAD_OK) {
976 return err;
977 }
978
979 std::sort(vTxHash.begin(), vTxHash.end());
980 std::sort(vTxHashIn.begin(), vTxHashIn.end());
981
982 // erase each matching wallet TX
983 bool delerror = false;
984 std::vector<uint256>::iterator it = vTxHashIn.begin();
985 for (const uint256& hash : vTxHash) {
986 while (it < vTxHashIn.end() && (*it) < hash) {
987 it++;
988 }
989 if (it == vTxHashIn.end()) {
990 break;
991 }
992 else if ((*it) == hash) {
993 if(!EraseTx(hash)) {
994 LogPrint(BCLog::WALLETDB, "Transaction was found for deletion but returned database error: %s\n", hash.GetHex());
995 delerror = true;
996 }
997 vTxHashOut.push_back(hash);
998 }
999 }
1000
1001 if (delerror) {
1002 return DBErrors::CORRUPT;
1003 }
1004 return DBErrors::LOAD_OK;
1005 }
1006
MaybeCompactWalletDB()1007 void MaybeCompactWalletDB()
1008 {
1009 static std::atomic<bool> fOneThread(false);
1010 if (fOneThread.exchange(true)) {
1011 return;
1012 }
1013
1014 for (const std::shared_ptr<CWallet>& pwallet : GetWallets()) {
1015 WalletDatabase& dbh = pwallet->GetDatabase();
1016
1017 unsigned int nUpdateCounter = dbh.nUpdateCounter;
1018
1019 if (dbh.nLastSeen != nUpdateCounter) {
1020 dbh.nLastSeen = nUpdateCounter;
1021 dbh.nLastWalletUpdate = GetTime();
1022 }
1023
1024 if (dbh.nLastFlushed != nUpdateCounter && GetTime() - dbh.nLastWalletUpdate >= 2) {
1025 if (dbh.PeriodicFlush()) {
1026 dbh.nLastFlushed = nUpdateCounter;
1027 }
1028 }
1029 }
1030
1031 fOneThread = false;
1032 }
1033
WriteDestData(const std::string & address,const std::string & key,const std::string & value)1034 bool WalletBatch::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
1035 {
1036 return WriteIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(address, key)), value);
1037 }
1038
EraseDestData(const std::string & address,const std::string & key)1039 bool WalletBatch::EraseDestData(const std::string &address, const std::string &key)
1040 {
1041 return EraseIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(address, key)));
1042 }
1043
1044
WriteHDChain(const CHDChain & chain)1045 bool WalletBatch::WriteHDChain(const CHDChain& chain)
1046 {
1047 return WriteIC(DBKeys::HDCHAIN, chain);
1048 }
1049
WriteWalletFlags(const uint64_t flags)1050 bool WalletBatch::WriteWalletFlags(const uint64_t flags)
1051 {
1052 return WriteIC(DBKeys::FLAGS, flags);
1053 }
1054
TxnBegin()1055 bool WalletBatch::TxnBegin()
1056 {
1057 return m_batch->TxnBegin();
1058 }
1059
TxnCommit()1060 bool WalletBatch::TxnCommit()
1061 {
1062 return m_batch->TxnCommit();
1063 }
1064
TxnAbort()1065 bool WalletBatch::TxnAbort()
1066 {
1067 return m_batch->TxnAbort();
1068 }
1069
MakeDatabase(const fs::path & path,const DatabaseOptions & options,DatabaseStatus & status,bilingual_str & error)1070 std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
1071 {
1072 bool exists;
1073 try {
1074 exists = fs::symlink_status(path).type() != fs::file_not_found;
1075 } catch (const fs::filesystem_error& e) {
1076 error = Untranslated(strprintf("Failed to access database path '%s': %s", path.string(), fsbridge::get_filesystem_error_message(e)));
1077 status = DatabaseStatus::FAILED_BAD_PATH;
1078 return nullptr;
1079 }
1080
1081 std::optional<DatabaseFormat> format;
1082 if (exists) {
1083 if (IsBDBFile(BDBDataFile(path))) {
1084 format = DatabaseFormat::BERKELEY;
1085 }
1086 if (IsSQLiteFile(SQLiteDataFile(path))) {
1087 if (format) {
1088 error = Untranslated(strprintf("Failed to load database path '%s'. Data is in ambiguous format.", path.string()));
1089 status = DatabaseStatus::FAILED_BAD_FORMAT;
1090 return nullptr;
1091 }
1092 format = DatabaseFormat::SQLITE;
1093 }
1094 } else if (options.require_existing) {
1095 error = Untranslated(strprintf("Failed to load database path '%s'. Path does not exist.", path.string()));
1096 status = DatabaseStatus::FAILED_NOT_FOUND;
1097 return nullptr;
1098 }
1099
1100 if (!format && options.require_existing) {
1101 error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in recognized format.", path.string()));
1102 status = DatabaseStatus::FAILED_BAD_FORMAT;
1103 return nullptr;
1104 }
1105
1106 if (format && options.require_create) {
1107 error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", path.string()));
1108 status = DatabaseStatus::FAILED_ALREADY_EXISTS;
1109 return nullptr;
1110 }
1111
1112 // A db already exists so format is set, but options also specifies the format, so make sure they agree
1113 if (format && options.require_format && format != options.require_format) {
1114 error = Untranslated(strprintf("Failed to load database path '%s'. Data is not in required format.", path.string()));
1115 status = DatabaseStatus::FAILED_BAD_FORMAT;
1116 return nullptr;
1117 }
1118
1119 // Format is not set when a db doesn't already exist, so use the format specified by the options if it is set.
1120 if (!format && options.require_format) format = options.require_format;
1121
1122 // If the format is not specified or detected, choose the default format based on what is available. We prefer BDB over SQLite for now.
1123 if (!format) {
1124 #ifdef USE_SQLITE
1125 format = DatabaseFormat::SQLITE;
1126 #endif
1127 #ifdef USE_BDB
1128 format = DatabaseFormat::BERKELEY;
1129 #endif
1130 }
1131
1132 if (format == DatabaseFormat::SQLITE) {
1133 #ifdef USE_SQLITE
1134 return MakeSQLiteDatabase(path, options, status, error);
1135 #endif
1136 error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support SQLite database format.", path.string()));
1137 status = DatabaseStatus::FAILED_BAD_FORMAT;
1138 return nullptr;
1139 }
1140
1141 #ifdef USE_BDB
1142 return MakeBerkeleyDatabase(path, options, status, error);
1143 #endif
1144 error = Untranslated(strprintf("Failed to open database path '%s'. Build does not support Berkeley DB database format.", path.string()));
1145 status = DatabaseStatus::FAILED_BAD_FORMAT;
1146 return nullptr;
1147 }
1148
1149 /** Return object for accessing dummy database with no read/write capabilities. */
CreateDummyWalletDatabase()1150 std::unique_ptr<WalletDatabase> CreateDummyWalletDatabase()
1151 {
1152 return std::make_unique<DummyDatabase>();
1153 }
1154
1155 /** Return object for accessing temporary in-memory database. */
CreateMockWalletDatabase()1156 std::unique_ptr<WalletDatabase> CreateMockWalletDatabase()
1157 {
1158 #ifdef USE_BDB
1159 return std::make_unique<BerkeleyDatabase>(std::make_shared<BerkeleyEnvironment>(), "");
1160 #elif USE_SQLITE
1161 return std::make_unique<SQLiteDatabase>("", "", true);
1162 #endif
1163 }
1164