Merge #11353: Small refactor of CCoinsViewCache::BatchWrite()
[bitcoinplatinum.git] / src / wallet / walletdb.cpp
blob180706b1ed2bf24405693140d26c3fcc96f2cf77
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2016 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.
6 #include "wallet/walletdb.h"
8 #include "base58.h"
9 #include "consensus/tx_verify.h"
10 #include "consensus/validation.h"
11 #include "fs.h"
12 #include "protocol.h"
13 #include "serialize.h"
14 #include "sync.h"
15 #include "util.h"
16 #include "utiltime.h"
17 #include "wallet/wallet.h"
19 #include <atomic>
21 #include <boost/thread.hpp>
24 // CWalletDB
27 bool CWalletDB::WriteName(const std::string& strAddress, const std::string& strName)
29 return WriteIC(std::make_pair(std::string("name"), strAddress), strName);
32 bool CWalletDB::EraseName(const std::string& strAddress)
34 // This should only be used for sending addresses, never for receiving addresses,
35 // receiving addresses must always have an address book entry if they're not change return.
36 return EraseIC(std::make_pair(std::string("name"), strAddress));
39 bool CWalletDB::WritePurpose(const std::string& strAddress, const std::string& strPurpose)
41 return WriteIC(std::make_pair(std::string("purpose"), strAddress), strPurpose);
44 bool CWalletDB::ErasePurpose(const std::string& strAddress)
46 return EraseIC(std::make_pair(std::string("purpose"), strAddress));
49 bool CWalletDB::WriteTx(const CWalletTx& wtx)
51 return WriteIC(std::make_pair(std::string("tx"), wtx.GetHash()), wtx);
54 bool CWalletDB::EraseTx(uint256 hash)
56 return EraseIC(std::make_pair(std::string("tx"), hash));
59 bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
61 if (!WriteIC(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta, false)) {
62 return false;
65 // hash pubkey/privkey to accelerate wallet load
66 std::vector<unsigned char> vchKey;
67 vchKey.reserve(vchPubKey.size() + vchPrivKey.size());
68 vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
69 vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
71 return WriteIC(std::make_pair(std::string("key"), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false);
74 bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
75 const std::vector<unsigned char>& vchCryptedSecret,
76 const CKeyMetadata &keyMeta)
78 if (!WriteIC(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta)) {
79 return false;
82 if (!WriteIC(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) {
83 return false;
85 EraseIC(std::make_pair(std::string("key"), vchPubKey));
86 EraseIC(std::make_pair(std::string("wkey"), vchPubKey));
87 return true;
90 bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
92 return WriteIC(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
95 bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
97 return WriteIC(std::make_pair(std::string("cscript"), hash), redeemScript, false);
100 bool CWalletDB::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta)
102 if (!WriteIC(std::make_pair(std::string("watchmeta"), dest), keyMeta)) {
103 return false;
105 return WriteIC(std::make_pair(std::string("watchs"), dest), '1');
108 bool CWalletDB::EraseWatchOnly(const CScript &dest)
110 if (!EraseIC(std::make_pair(std::string("watchmeta"), dest))) {
111 return false;
113 return EraseIC(std::make_pair(std::string("watchs"), dest));
116 bool CWalletDB::WriteBestBlock(const CBlockLocator& locator)
118 WriteIC(std::string("bestblock"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
119 return WriteIC(std::string("bestblock_nomerkle"), locator);
122 bool CWalletDB::ReadBestBlock(CBlockLocator& locator)
124 if (batch.Read(std::string("bestblock"), locator) && !locator.vHave.empty()) return true;
125 return batch.Read(std::string("bestblock_nomerkle"), locator);
128 bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
130 return WriteIC(std::string("orderposnext"), nOrderPosNext);
133 bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
135 return batch.Read(std::make_pair(std::string("pool"), nPool), keypool);
138 bool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool)
140 return WriteIC(std::make_pair(std::string("pool"), nPool), keypool);
143 bool CWalletDB::ErasePool(int64_t nPool)
145 return EraseIC(std::make_pair(std::string("pool"), nPool));
148 bool CWalletDB::WriteMinVersion(int nVersion)
150 return WriteIC(std::string("minversion"), nVersion);
153 bool CWalletDB::ReadAccount(const std::string& strAccount, CAccount& account)
155 account.SetNull();
156 return batch.Read(std::make_pair(std::string("acc"), strAccount), account);
159 bool CWalletDB::WriteAccount(const std::string& strAccount, const CAccount& account)
161 return WriteIC(std::make_pair(std::string("acc"), strAccount), account);
164 bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry)
166 return WriteIC(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry);
169 CAmount CWalletDB::GetAccountCreditDebit(const std::string& strAccount)
171 std::list<CAccountingEntry> entries;
172 ListAccountCreditDebit(strAccount, entries);
174 CAmount nCreditDebit = 0;
175 for (const CAccountingEntry& entry : entries)
176 nCreditDebit += entry.nCreditDebit;
178 return nCreditDebit;
181 void CWalletDB::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries)
183 bool fAllAccounts = (strAccount == "*");
185 Dbc* pcursor = batch.GetCursor();
186 if (!pcursor)
187 throw std::runtime_error(std::string(__func__) + ": cannot create DB cursor");
188 bool setRange = true;
189 while (true)
191 // Read next record
192 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
193 if (setRange)
194 ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? std::string("") : strAccount), uint64_t(0)));
195 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
196 int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange);
197 setRange = false;
198 if (ret == DB_NOTFOUND)
199 break;
200 else if (ret != 0)
202 pcursor->close();
203 throw std::runtime_error(std::string(__func__) + ": error scanning DB");
206 // Unserialize
207 std::string strType;
208 ssKey >> strType;
209 if (strType != "acentry")
210 break;
211 CAccountingEntry acentry;
212 ssKey >> acentry.strAccount;
213 if (!fAllAccounts && acentry.strAccount != strAccount)
214 break;
216 ssValue >> acentry;
217 ssKey >> acentry.nEntryNo;
218 entries.push_back(acentry);
221 pcursor->close();
224 class CWalletScanState {
225 public:
226 unsigned int nKeys;
227 unsigned int nCKeys;
228 unsigned int nWatchKeys;
229 unsigned int nKeyMeta;
230 bool fIsEncrypted;
231 bool fAnyUnordered;
232 int nFileVersion;
233 std::vector<uint256> vWalletUpgrade;
235 CWalletScanState() {
236 nKeys = nCKeys = nWatchKeys = nKeyMeta = 0;
237 fIsEncrypted = false;
238 fAnyUnordered = false;
239 nFileVersion = 0;
243 bool
244 ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
245 CWalletScanState &wss, std::string& strType, std::string& strErr)
247 try {
248 // Unserialize
249 // Taking advantage of the fact that pair serialization
250 // is just the two items serialized one after the other
251 ssKey >> strType;
252 if (strType == "name")
254 std::string strAddress;
255 ssKey >> strAddress;
256 ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].name;
258 else if (strType == "purpose")
260 std::string strAddress;
261 ssKey >> strAddress;
262 ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].purpose;
264 else if (strType == "tx")
266 uint256 hash;
267 ssKey >> hash;
268 CWalletTx wtx;
269 ssValue >> wtx;
270 CValidationState state;
271 if (!(CheckTransaction(*wtx.tx, state) && (wtx.GetHash() == hash) && state.IsValid()))
272 return false;
274 // Undo serialize changes in 31600
275 if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
277 if (!ssValue.empty())
279 char fTmp;
280 char fUnused;
281 ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
282 strErr = strprintf("LoadWallet() upgrading tx ver=%d %d '%s' %s",
283 wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount, hash.ToString());
284 wtx.fTimeReceivedIsTxTime = fTmp;
286 else
288 strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
289 wtx.fTimeReceivedIsTxTime = 0;
291 wss.vWalletUpgrade.push_back(hash);
294 if (wtx.nOrderPos == -1)
295 wss.fAnyUnordered = true;
297 pwallet->LoadToWallet(wtx);
299 else if (strType == "acentry")
301 std::string strAccount;
302 ssKey >> strAccount;
303 uint64_t nNumber;
304 ssKey >> nNumber;
305 if (nNumber > pwallet->nAccountingEntryNumber) {
306 pwallet->nAccountingEntryNumber = nNumber;
309 if (!wss.fAnyUnordered)
311 CAccountingEntry acentry;
312 ssValue >> acentry;
313 if (acentry.nOrderPos == -1)
314 wss.fAnyUnordered = true;
317 else if (strType == "watchs")
319 wss.nWatchKeys++;
320 CScript script;
321 ssKey >> script;
322 char fYes;
323 ssValue >> fYes;
324 if (fYes == '1')
325 pwallet->LoadWatchOnly(script);
327 else if (strType == "key" || strType == "wkey")
329 CPubKey vchPubKey;
330 ssKey >> vchPubKey;
331 if (!vchPubKey.IsValid())
333 strErr = "Error reading wallet database: CPubKey corrupt";
334 return false;
336 CKey key;
337 CPrivKey pkey;
338 uint256 hash;
340 if (strType == "key")
342 wss.nKeys++;
343 ssValue >> pkey;
344 } else {
345 CWalletKey wkey;
346 ssValue >> wkey;
347 pkey = wkey.vchPrivKey;
350 // Old wallets store keys as "key" [pubkey] => [privkey]
351 // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key
352 // using EC operations as a checksum.
353 // Newer wallets store keys as "key"[pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while
354 // remaining backwards-compatible.
357 ssValue >> hash;
359 catch (...) {}
361 bool fSkipCheck = false;
363 if (!hash.IsNull())
365 // hash pubkey/privkey to accelerate wallet load
366 std::vector<unsigned char> vchKey;
367 vchKey.reserve(vchPubKey.size() + pkey.size());
368 vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
369 vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
371 if (Hash(vchKey.begin(), vchKey.end()) != hash)
373 strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
374 return false;
377 fSkipCheck = true;
380 if (!key.Load(pkey, vchPubKey, fSkipCheck))
382 strErr = "Error reading wallet database: CPrivKey corrupt";
383 return false;
385 if (!pwallet->LoadKey(key, vchPubKey))
387 strErr = "Error reading wallet database: LoadKey failed";
388 return false;
391 else if (strType == "mkey")
393 unsigned int nID;
394 ssKey >> nID;
395 CMasterKey kMasterKey;
396 ssValue >> kMasterKey;
397 if(pwallet->mapMasterKeys.count(nID) != 0)
399 strErr = strprintf("Error reading wallet database: duplicate CMasterKey id %u", nID);
400 return false;
402 pwallet->mapMasterKeys[nID] = kMasterKey;
403 if (pwallet->nMasterKeyMaxID < nID)
404 pwallet->nMasterKeyMaxID = nID;
406 else if (strType == "ckey")
408 CPubKey vchPubKey;
409 ssKey >> vchPubKey;
410 if (!vchPubKey.IsValid())
412 strErr = "Error reading wallet database: CPubKey corrupt";
413 return false;
415 std::vector<unsigned char> vchPrivKey;
416 ssValue >> vchPrivKey;
417 wss.nCKeys++;
419 if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
421 strErr = "Error reading wallet database: LoadCryptedKey failed";
422 return false;
424 wss.fIsEncrypted = true;
426 else if (strType == "keymeta" || strType == "watchmeta")
428 CTxDestination keyID;
429 if (strType == "keymeta")
431 CPubKey vchPubKey;
432 ssKey >> vchPubKey;
433 keyID = vchPubKey.GetID();
435 else if (strType == "watchmeta")
437 CScript script;
438 ssKey >> script;
439 keyID = CScriptID(script);
442 CKeyMetadata keyMeta;
443 ssValue >> keyMeta;
444 wss.nKeyMeta++;
446 pwallet->LoadKeyMetadata(keyID, keyMeta);
448 else if (strType == "defaultkey")
450 // We don't want or need the default key, but if there is one set,
451 // we want to make sure that it is valid so that we can detect corruption
452 CPubKey vchPubKey;
453 ssValue >> vchPubKey;
454 if (!vchPubKey.IsValid()) {
455 strErr = "Error reading wallet database: Default Key corrupt";
456 return false;
459 else if (strType == "pool")
461 int64_t nIndex;
462 ssKey >> nIndex;
463 CKeyPool keypool;
464 ssValue >> keypool;
466 pwallet->LoadKeyPool(nIndex, keypool);
468 else if (strType == "version")
470 ssValue >> wss.nFileVersion;
471 if (wss.nFileVersion == 10300)
472 wss.nFileVersion = 300;
474 else if (strType == "cscript")
476 uint160 hash;
477 ssKey >> hash;
478 CScript script;
479 ssValue >> script;
480 if (!pwallet->LoadCScript(script))
482 strErr = "Error reading wallet database: LoadCScript failed";
483 return false;
486 else if (strType == "orderposnext")
488 ssValue >> pwallet->nOrderPosNext;
490 else if (strType == "destdata")
492 std::string strAddress, strKey, strValue;
493 ssKey >> strAddress;
494 ssKey >> strKey;
495 ssValue >> strValue;
496 if (!pwallet->LoadDestData(DecodeDestination(strAddress), strKey, strValue))
498 strErr = "Error reading wallet database: LoadDestData failed";
499 return false;
502 else if (strType == "hdchain")
504 CHDChain chain;
505 ssValue >> chain;
506 if (!pwallet->SetHDChain(chain, true))
508 strErr = "Error reading wallet database: SetHDChain failed";
509 return false;
512 } catch (...)
514 return false;
516 return true;
519 bool CWalletDB::IsKeyType(const std::string& strType)
521 return (strType== "key" || strType == "wkey" ||
522 strType == "mkey" || strType == "ckey");
525 DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
527 CWalletScanState wss;
528 bool fNoncriticalErrors = false;
529 DBErrors result = DB_LOAD_OK;
531 LOCK(pwallet->cs_wallet);
532 try {
533 int nMinVersion = 0;
534 if (batch.Read((std::string)"minversion", nMinVersion))
536 if (nMinVersion > CLIENT_VERSION)
537 return DB_TOO_NEW;
538 pwallet->LoadMinVersion(nMinVersion);
541 // Get cursor
542 Dbc* pcursor = batch.GetCursor();
543 if (!pcursor)
545 LogPrintf("Error getting wallet database cursor\n");
546 return DB_CORRUPT;
549 while (true)
551 // Read next record
552 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
553 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
554 int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue);
555 if (ret == DB_NOTFOUND)
556 break;
557 else if (ret != 0)
559 LogPrintf("Error reading next record from wallet database\n");
560 return DB_CORRUPT;
563 // Try to be tolerant of single corrupt records:
564 std::string strType, strErr;
565 if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
567 // losing keys is considered a catastrophic error, anything else
568 // we assume the user can live with:
569 if (IsKeyType(strType) || strType == "defaultkey")
570 result = DB_CORRUPT;
571 else
573 // Leave other errors alone, if we try to fix them we might make things worse.
574 fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
575 if (strType == "tx")
576 // Rescan if there is a bad transaction record:
577 gArgs.SoftSetBoolArg("-rescan", true);
580 if (!strErr.empty())
581 LogPrintf("%s\n", strErr);
583 pcursor->close();
585 catch (const boost::thread_interrupted&) {
586 throw;
588 catch (...) {
589 result = DB_CORRUPT;
592 if (fNoncriticalErrors && result == DB_LOAD_OK)
593 result = DB_NONCRITICAL_ERROR;
595 // Any wallet corruption at all: skip any rewriting or
596 // upgrading, we don't want to make it worse.
597 if (result != DB_LOAD_OK)
598 return result;
600 LogPrintf("nFileVersion = %d\n", wss.nFileVersion);
602 LogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\n",
603 wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys);
605 // nTimeFirstKey is only reliable if all keys have metadata
606 if ((wss.nKeys + wss.nCKeys + wss.nWatchKeys) != wss.nKeyMeta)
607 pwallet->UpdateTimeFirstKey(1);
609 for (uint256 hash : wss.vWalletUpgrade)
610 WriteTx(pwallet->mapWallet[hash]);
612 // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
613 if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000))
614 return DB_NEED_REWRITE;
616 if (wss.nFileVersion < CLIENT_VERSION) // Update
617 WriteVersion(CLIENT_VERSION);
619 if (wss.fAnyUnordered)
620 result = pwallet->ReorderTransactions();
622 pwallet->laccentries.clear();
623 ListAccountCreditDebit("*", pwallet->laccentries);
624 for (CAccountingEntry& entry : pwallet->laccentries) {
625 pwallet->wtxOrdered.insert(make_pair(entry.nOrderPos, CWallet::TxPair(nullptr, &entry)));
628 return result;
631 DBErrors CWalletDB::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx)
633 bool fNoncriticalErrors = false;
634 DBErrors result = DB_LOAD_OK;
636 try {
637 int nMinVersion = 0;
638 if (batch.Read((std::string)"minversion", nMinVersion))
640 if (nMinVersion > CLIENT_VERSION)
641 return DB_TOO_NEW;
644 // Get cursor
645 Dbc* pcursor = batch.GetCursor();
646 if (!pcursor)
648 LogPrintf("Error getting wallet database cursor\n");
649 return DB_CORRUPT;
652 while (true)
654 // Read next record
655 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
656 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
657 int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue);
658 if (ret == DB_NOTFOUND)
659 break;
660 else if (ret != 0)
662 LogPrintf("Error reading next record from wallet database\n");
663 return DB_CORRUPT;
666 std::string strType;
667 ssKey >> strType;
668 if (strType == "tx") {
669 uint256 hash;
670 ssKey >> hash;
672 CWalletTx wtx;
673 ssValue >> wtx;
675 vTxHash.push_back(hash);
676 vWtx.push_back(wtx);
679 pcursor->close();
681 catch (const boost::thread_interrupted&) {
682 throw;
684 catch (...) {
685 result = DB_CORRUPT;
688 if (fNoncriticalErrors && result == DB_LOAD_OK)
689 result = DB_NONCRITICAL_ERROR;
691 return result;
694 DBErrors CWalletDB::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<uint256>& vTxHashOut)
696 // build list of wallet TXs and hashes
697 std::vector<uint256> vTxHash;
698 std::vector<CWalletTx> vWtx;
699 DBErrors err = FindWalletTx(vTxHash, vWtx);
700 if (err != DB_LOAD_OK) {
701 return err;
704 std::sort(vTxHash.begin(), vTxHash.end());
705 std::sort(vTxHashIn.begin(), vTxHashIn.end());
707 // erase each matching wallet TX
708 bool delerror = false;
709 std::vector<uint256>::iterator it = vTxHashIn.begin();
710 for (uint256 hash : vTxHash) {
711 while (it < vTxHashIn.end() && (*it) < hash) {
712 it++;
714 if (it == vTxHashIn.end()) {
715 break;
717 else if ((*it) == hash) {
718 if(!EraseTx(hash)) {
719 LogPrint(BCLog::DB, "Transaction was found for deletion but returned database error: %s\n", hash.GetHex());
720 delerror = true;
722 vTxHashOut.push_back(hash);
726 if (delerror) {
727 return DB_CORRUPT;
729 return DB_LOAD_OK;
732 DBErrors CWalletDB::ZapWalletTx(std::vector<CWalletTx>& vWtx)
734 // build list of wallet TXs
735 std::vector<uint256> vTxHash;
736 DBErrors err = FindWalletTx(vTxHash, vWtx);
737 if (err != DB_LOAD_OK)
738 return err;
740 // erase each wallet TX
741 for (uint256& hash : vTxHash) {
742 if (!EraseTx(hash))
743 return DB_CORRUPT;
746 return DB_LOAD_OK;
749 void MaybeCompactWalletDB()
751 static std::atomic<bool> fOneThread(false);
752 if (fOneThread.exchange(true)) {
753 return;
755 if (!gArgs.GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) {
756 return;
759 for (CWalletRef pwallet : vpwallets) {
760 CWalletDBWrapper& dbh = pwallet->GetDBHandle();
762 unsigned int nUpdateCounter = dbh.nUpdateCounter;
764 if (dbh.nLastSeen != nUpdateCounter) {
765 dbh.nLastSeen = nUpdateCounter;
766 dbh.nLastWalletUpdate = GetTime();
769 if (dbh.nLastFlushed != nUpdateCounter && GetTime() - dbh.nLastWalletUpdate >= 2) {
770 if (CDB::PeriodicFlush(dbh)) {
771 dbh.nLastFlushed = nUpdateCounter;
776 fOneThread = false;
780 // Try to (very carefully!) recover wallet file if there is a problem.
782 bool CWalletDB::Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename)
784 return CDB::Recover(filename, callbackDataIn, recoverKVcallback, out_backup_filename);
787 bool CWalletDB::Recover(const std::string& filename, std::string& out_backup_filename)
789 // recover without a key filter callback
790 // results in recovering all record types
791 return CWalletDB::Recover(filename, nullptr, nullptr, out_backup_filename);
794 bool CWalletDB::RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue)
796 CWallet *dummyWallet = reinterpret_cast<CWallet*>(callbackData);
797 CWalletScanState dummyWss;
798 std::string strType, strErr;
799 bool fReadOK;
801 // Required in LoadKeyMetadata():
802 LOCK(dummyWallet->cs_wallet);
803 fReadOK = ReadKeyValue(dummyWallet, ssKey, ssValue,
804 dummyWss, strType, strErr);
806 if (!IsKeyType(strType) && strType != "hdchain")
807 return false;
808 if (!fReadOK)
810 LogPrintf("WARNING: CWalletDB::Recover skipping %s: %s\n", strType, strErr);
811 return false;
814 return true;
817 bool CWalletDB::VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr)
819 return CDB::VerifyEnvironment(walletFile, dataDir, errorStr);
822 bool CWalletDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr)
824 return CDB::VerifyDatabaseFile(walletFile, dataDir, warningStr, errorStr, CWalletDB::Recover);
827 bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
829 return WriteIC(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value);
832 bool CWalletDB::EraseDestData(const std::string &address, const std::string &key)
834 return EraseIC(std::make_pair(std::string("destdata"), std::make_pair(address, key)));
838 bool CWalletDB::WriteHDChain(const CHDChain& chain)
840 return WriteIC(std::string("hdchain"), chain);
843 bool CWalletDB::TxnBegin()
845 return batch.TxnBegin();
848 bool CWalletDB::TxnCommit()
850 return batch.TxnCommit();
853 bool CWalletDB::TxnAbort()
855 return batch.TxnAbort();
858 bool CWalletDB::ReadVersion(int& nVersion)
860 return batch.ReadVersion(nVersion);
863 bool CWalletDB::WriteVersion(int nVersion)
865 return batch.WriteVersion(nVersion);