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