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