Merge #8694: Basic multiwallet support
[bitcoinplatinum.git] / src / wallet / walletdb.cpp
blob7731fa56316f3c819c026fe3c77106fe0fdee008
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/foreach.hpp>
22 #include <boost/thread.hpp>
25 // CWalletDB
28 bool CWalletDB::WriteName(const std::string& strAddress, const std::string& strName)
30 return WriteIC(std::make_pair(std::string("name"), strAddress), strName);
33 bool CWalletDB::EraseName(const std::string& strAddress)
35 // This should only be used for sending addresses, never for receiving addresses,
36 // receiving addresses must always have an address book entry if they're not change return.
37 return EraseIC(std::make_pair(std::string("name"), strAddress));
40 bool CWalletDB::WritePurpose(const std::string& strAddress, const std::string& strPurpose)
42 return WriteIC(std::make_pair(std::string("purpose"), strAddress), strPurpose);
45 bool CWalletDB::ErasePurpose(const std::string& strPurpose)
47 return EraseIC(std::make_pair(std::string("purpose"), strPurpose));
50 bool CWalletDB::WriteTx(const CWalletTx& wtx)
52 return WriteIC(std::make_pair(std::string("tx"), wtx.GetHash()), wtx);
55 bool CWalletDB::EraseTx(uint256 hash)
57 return EraseIC(std::make_pair(std::string("tx"), hash));
60 bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
62 if (!WriteIC(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta, false)) {
63 return false;
66 // hash pubkey/privkey to accelerate wallet load
67 std::vector<unsigned char> vchKey;
68 vchKey.reserve(vchPubKey.size() + vchPrivKey.size());
69 vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
70 vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
72 return WriteIC(std::make_pair(std::string("key"), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false);
75 bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
76 const std::vector<unsigned char>& vchCryptedSecret,
77 const CKeyMetadata &keyMeta)
79 const bool fEraseUnencryptedKey = true;
81 if (!WriteIC(std::make_pair(std::string("keymeta"), vchPubKey), keyMeta)) {
82 return false;
85 if (!WriteIC(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) {
86 return false;
88 if (fEraseUnencryptedKey)
90 EraseIC(std::make_pair(std::string("key"), vchPubKey));
91 EraseIC(std::make_pair(std::string("wkey"), vchPubKey));
94 return true;
97 bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
99 return WriteIC(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
102 bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
104 return WriteIC(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&redeemScript), false);
107 bool CWalletDB::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta)
109 if (!WriteIC(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest)), keyMeta)) {
110 return false;
112 return WriteIC(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1');
115 bool CWalletDB::EraseWatchOnly(const CScript &dest)
117 if (!EraseIC(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest)))) {
118 return false;
120 return EraseIC(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)));
123 bool CWalletDB::WriteBestBlock(const CBlockLocator& locator)
125 WriteIC(std::string("bestblock"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
126 return WriteIC(std::string("bestblock_nomerkle"), locator);
129 bool CWalletDB::ReadBestBlock(CBlockLocator& locator)
131 if (batch.Read(std::string("bestblock"), locator) && !locator.vHave.empty()) return true;
132 return batch.Read(std::string("bestblock_nomerkle"), locator);
135 bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
137 return WriteIC(std::string("orderposnext"), nOrderPosNext);
140 bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)
142 return WriteIC(std::string("defaultkey"), vchPubKey);
145 bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
147 return batch.Read(std::make_pair(std::string("pool"), nPool), keypool);
150 bool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool)
152 return WriteIC(std::make_pair(std::string("pool"), nPool), keypool);
155 bool CWalletDB::ErasePool(int64_t nPool)
157 return EraseIC(std::make_pair(std::string("pool"), nPool));
160 bool CWalletDB::WriteMinVersion(int nVersion)
162 return WriteIC(std::string("minversion"), nVersion);
165 bool CWalletDB::ReadAccount(const std::string& strAccount, CAccount& account)
167 account.SetNull();
168 return batch.Read(std::make_pair(std::string("acc"), strAccount), account);
171 bool CWalletDB::WriteAccount(const std::string& strAccount, const CAccount& account)
173 return WriteIC(std::make_pair(std::string("acc"), strAccount), account);
176 bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry)
178 return WriteIC(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry);
181 CAmount CWalletDB::GetAccountCreditDebit(const std::string& strAccount)
183 std::list<CAccountingEntry> entries;
184 ListAccountCreditDebit(strAccount, entries);
186 CAmount nCreditDebit = 0;
187 BOOST_FOREACH (const CAccountingEntry& entry, entries)
188 nCreditDebit += entry.nCreditDebit;
190 return nCreditDebit;
193 void CWalletDB::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries)
195 bool fAllAccounts = (strAccount == "*");
197 Dbc* pcursor = batch.GetCursor();
198 if (!pcursor)
199 throw std::runtime_error(std::string(__func__) + ": cannot create DB cursor");
200 bool setRange = true;
201 while (true)
203 // Read next record
204 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
205 if (setRange)
206 ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? std::string("") : strAccount), uint64_t(0)));
207 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
208 int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue, setRange);
209 setRange = false;
210 if (ret == DB_NOTFOUND)
211 break;
212 else if (ret != 0)
214 pcursor->close();
215 throw std::runtime_error(std::string(__func__) + ": error scanning DB");
218 // Unserialize
219 std::string strType;
220 ssKey >> strType;
221 if (strType != "acentry")
222 break;
223 CAccountingEntry acentry;
224 ssKey >> acentry.strAccount;
225 if (!fAllAccounts && acentry.strAccount != strAccount)
226 break;
228 ssValue >> acentry;
229 ssKey >> acentry.nEntryNo;
230 entries.push_back(acentry);
233 pcursor->close();
236 class CWalletScanState {
237 public:
238 unsigned int nKeys;
239 unsigned int nCKeys;
240 unsigned int nWatchKeys;
241 unsigned int nKeyMeta;
242 bool fIsEncrypted;
243 bool fAnyUnordered;
244 int nFileVersion;
245 std::vector<uint256> vWalletUpgrade;
247 CWalletScanState() {
248 nKeys = nCKeys = nWatchKeys = nKeyMeta = 0;
249 fIsEncrypted = false;
250 fAnyUnordered = false;
251 nFileVersion = 0;
255 bool
256 ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
257 CWalletScanState &wss, std::string& strType, std::string& strErr)
259 try {
260 // Unserialize
261 // Taking advantage of the fact that pair serialization
262 // is just the two items serialized one after the other
263 ssKey >> strType;
264 if (strType == "name")
266 std::string strAddress;
267 ssKey >> strAddress;
268 ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].name;
270 else if (strType == "purpose")
272 std::string strAddress;
273 ssKey >> strAddress;
274 ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].purpose;
276 else if (strType == "tx")
278 uint256 hash;
279 ssKey >> hash;
280 CWalletTx wtx;
281 ssValue >> wtx;
282 CValidationState state;
283 if (!(CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid()))
284 return false;
286 // Undo serialize changes in 31600
287 if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
289 if (!ssValue.empty())
291 char fTmp;
292 char fUnused;
293 ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
294 strErr = strprintf("LoadWallet() upgrading tx ver=%d %d '%s' %s",
295 wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount, hash.ToString());
296 wtx.fTimeReceivedIsTxTime = fTmp;
298 else
300 strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
301 wtx.fTimeReceivedIsTxTime = 0;
303 wss.vWalletUpgrade.push_back(hash);
306 if (wtx.nOrderPos == -1)
307 wss.fAnyUnordered = true;
309 pwallet->LoadToWallet(wtx);
311 else if (strType == "acentry")
313 std::string strAccount;
314 ssKey >> strAccount;
315 uint64_t nNumber;
316 ssKey >> nNumber;
317 if (nNumber > pwallet->nAccountingEntryNumber) {
318 pwallet->nAccountingEntryNumber = nNumber;
321 if (!wss.fAnyUnordered)
323 CAccountingEntry acentry;
324 ssValue >> acentry;
325 if (acentry.nOrderPos == -1)
326 wss.fAnyUnordered = true;
329 else if (strType == "watchs")
331 wss.nWatchKeys++;
332 CScript script;
333 ssKey >> *(CScriptBase*)(&script);
334 char fYes;
335 ssValue >> fYes;
336 if (fYes == '1')
337 pwallet->LoadWatchOnly(script);
339 else if (strType == "key" || strType == "wkey")
341 CPubKey vchPubKey;
342 ssKey >> vchPubKey;
343 if (!vchPubKey.IsValid())
345 strErr = "Error reading wallet database: CPubKey corrupt";
346 return false;
348 CKey key;
349 CPrivKey pkey;
350 uint256 hash;
352 if (strType == "key")
354 wss.nKeys++;
355 ssValue >> pkey;
356 } else {
357 CWalletKey wkey;
358 ssValue >> wkey;
359 pkey = wkey.vchPrivKey;
362 // Old wallets store keys as "key" [pubkey] => [privkey]
363 // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key
364 // using EC operations as a checksum.
365 // Newer wallets store keys as "key"[pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while
366 // remaining backwards-compatible.
369 ssValue >> hash;
371 catch (...) {}
373 bool fSkipCheck = false;
375 if (!hash.IsNull())
377 // hash pubkey/privkey to accelerate wallet load
378 std::vector<unsigned char> vchKey;
379 vchKey.reserve(vchPubKey.size() + pkey.size());
380 vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
381 vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
383 if (Hash(vchKey.begin(), vchKey.end()) != hash)
385 strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
386 return false;
389 fSkipCheck = true;
392 if (!key.Load(pkey, vchPubKey, fSkipCheck))
394 strErr = "Error reading wallet database: CPrivKey corrupt";
395 return false;
397 if (!pwallet->LoadKey(key, vchPubKey))
399 strErr = "Error reading wallet database: LoadKey failed";
400 return false;
403 else if (strType == "mkey")
405 unsigned int nID;
406 ssKey >> nID;
407 CMasterKey kMasterKey;
408 ssValue >> kMasterKey;
409 if(pwallet->mapMasterKeys.count(nID) != 0)
411 strErr = strprintf("Error reading wallet database: duplicate CMasterKey id %u", nID);
412 return false;
414 pwallet->mapMasterKeys[nID] = kMasterKey;
415 if (pwallet->nMasterKeyMaxID < nID)
416 pwallet->nMasterKeyMaxID = nID;
418 else if (strType == "ckey")
420 CPubKey vchPubKey;
421 ssKey >> vchPubKey;
422 if (!vchPubKey.IsValid())
424 strErr = "Error reading wallet database: CPubKey corrupt";
425 return false;
427 std::vector<unsigned char> vchPrivKey;
428 ssValue >> vchPrivKey;
429 wss.nCKeys++;
431 if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
433 strErr = "Error reading wallet database: LoadCryptedKey failed";
434 return false;
436 wss.fIsEncrypted = true;
438 else if (strType == "keymeta" || strType == "watchmeta")
440 CTxDestination keyID;
441 if (strType == "keymeta")
443 CPubKey vchPubKey;
444 ssKey >> vchPubKey;
445 keyID = vchPubKey.GetID();
447 else if (strType == "watchmeta")
449 CScript script;
450 ssKey >> *(CScriptBase*)(&script);
451 keyID = CScriptID(script);
454 CKeyMetadata keyMeta;
455 ssValue >> keyMeta;
456 wss.nKeyMeta++;
458 pwallet->LoadKeyMetadata(keyID, keyMeta);
460 else if (strType == "defaultkey")
462 ssValue >> pwallet->vchDefaultKey;
464 else if (strType == "pool")
466 int64_t nIndex;
467 ssKey >> nIndex;
468 CKeyPool keypool;
469 ssValue >> keypool;
471 pwallet->LoadKeyPool(nIndex, keypool);
473 else if (strType == "version")
475 ssValue >> wss.nFileVersion;
476 if (wss.nFileVersion == 10300)
477 wss.nFileVersion = 300;
479 else if (strType == "cscript")
481 uint160 hash;
482 ssKey >> hash;
483 CScript script;
484 ssValue >> *(CScriptBase*)(&script);
485 if (!pwallet->LoadCScript(script))
487 strErr = "Error reading wallet database: LoadCScript failed";
488 return false;
491 else if (strType == "orderposnext")
493 ssValue >> pwallet->nOrderPosNext;
495 else if (strType == "destdata")
497 std::string strAddress, strKey, strValue;
498 ssKey >> strAddress;
499 ssKey >> strKey;
500 ssValue >> strValue;
501 if (!pwallet->LoadDestData(CBitcoinAddress(strAddress).Get(), strKey, strValue))
503 strErr = "Error reading wallet database: LoadDestData failed";
504 return false;
507 else if (strType == "hdchain")
509 CHDChain chain;
510 ssValue >> chain;
511 if (!pwallet->SetHDChain(chain, true))
513 strErr = "Error reading wallet database: SetHDChain failed";
514 return false;
517 } catch (...)
519 return false;
521 return true;
524 bool CWalletDB::IsKeyType(const std::string& strType)
526 return (strType== "key" || strType == "wkey" ||
527 strType == "mkey" || strType == "ckey");
530 DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
532 pwallet->vchDefaultKey = CPubKey();
533 CWalletScanState wss;
534 bool fNoncriticalErrors = false;
535 DBErrors result = DB_LOAD_OK;
537 LOCK(pwallet->cs_wallet);
538 try {
539 int nMinVersion = 0;
540 if (batch.Read((std::string)"minversion", nMinVersion))
542 if (nMinVersion > CLIENT_VERSION)
543 return DB_TOO_NEW;
544 pwallet->LoadMinVersion(nMinVersion);
547 // Get cursor
548 Dbc* pcursor = batch.GetCursor();
549 if (!pcursor)
551 LogPrintf("Error getting wallet database cursor\n");
552 return DB_CORRUPT;
555 while (true)
557 // Read next record
558 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
559 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
560 int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue);
561 if (ret == DB_NOTFOUND)
562 break;
563 else if (ret != 0)
565 LogPrintf("Error reading next record from wallet database\n");
566 return DB_CORRUPT;
569 // Try to be tolerant of single corrupt records:
570 std::string strType, strErr;
571 if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
573 // losing keys is considered a catastrophic error, anything else
574 // we assume the user can live with:
575 if (IsKeyType(strType))
576 result = DB_CORRUPT;
577 else
579 // Leave other errors alone, if we try to fix them we might make things worse.
580 fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
581 if (strType == "tx")
582 // Rescan if there is a bad transaction record:
583 SoftSetBoolArg("-rescan", true);
586 if (!strErr.empty())
587 LogPrintf("%s\n", strErr);
589 pcursor->close();
591 catch (const boost::thread_interrupted&) {
592 throw;
594 catch (...) {
595 result = DB_CORRUPT;
598 if (fNoncriticalErrors && result == DB_LOAD_OK)
599 result = DB_NONCRITICAL_ERROR;
601 // Any wallet corruption at all: skip any rewriting or
602 // upgrading, we don't want to make it worse.
603 if (result != DB_LOAD_OK)
604 return result;
606 LogPrintf("nFileVersion = %d\n", wss.nFileVersion);
608 LogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\n",
609 wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys);
611 // nTimeFirstKey is only reliable if all keys have metadata
612 if ((wss.nKeys + wss.nCKeys + wss.nWatchKeys) != wss.nKeyMeta)
613 pwallet->UpdateTimeFirstKey(1);
615 BOOST_FOREACH(uint256 hash, wss.vWalletUpgrade)
616 WriteTx(pwallet->mapWallet[hash]);
618 // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
619 if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000))
620 return DB_NEED_REWRITE;
622 if (wss.nFileVersion < CLIENT_VERSION) // Update
623 WriteVersion(CLIENT_VERSION);
625 if (wss.fAnyUnordered)
626 result = pwallet->ReorderTransactions();
628 pwallet->laccentries.clear();
629 ListAccountCreditDebit("*", pwallet->laccentries);
630 BOOST_FOREACH(CAccountingEntry& entry, pwallet->laccentries) {
631 pwallet->wtxOrdered.insert(make_pair(entry.nOrderPos, CWallet::TxPair((CWalletTx*)0, &entry)));
634 return result;
637 DBErrors CWalletDB::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx)
639 bool fNoncriticalErrors = false;
640 DBErrors result = DB_LOAD_OK;
642 try {
643 int nMinVersion = 0;
644 if (batch.Read((std::string)"minversion", nMinVersion))
646 if (nMinVersion > CLIENT_VERSION)
647 return DB_TOO_NEW;
650 // Get cursor
651 Dbc* pcursor = batch.GetCursor();
652 if (!pcursor)
654 LogPrintf("Error getting wallet database cursor\n");
655 return DB_CORRUPT;
658 while (true)
660 // Read next record
661 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
662 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
663 int ret = batch.ReadAtCursor(pcursor, ssKey, ssValue);
664 if (ret == DB_NOTFOUND)
665 break;
666 else if (ret != 0)
668 LogPrintf("Error reading next record from wallet database\n");
669 return DB_CORRUPT;
672 std::string strType;
673 ssKey >> strType;
674 if (strType == "tx") {
675 uint256 hash;
676 ssKey >> hash;
678 CWalletTx wtx;
679 ssValue >> wtx;
681 vTxHash.push_back(hash);
682 vWtx.push_back(wtx);
685 pcursor->close();
687 catch (const boost::thread_interrupted&) {
688 throw;
690 catch (...) {
691 result = DB_CORRUPT;
694 if (fNoncriticalErrors && result == DB_LOAD_OK)
695 result = DB_NONCRITICAL_ERROR;
697 return result;
700 DBErrors CWalletDB::ZapSelectTx(std::vector<uint256>& vTxHashIn, std::vector<uint256>& vTxHashOut)
702 // build list of wallet TXs and hashes
703 std::vector<uint256> vTxHash;
704 std::vector<CWalletTx> vWtx;
705 DBErrors err = FindWalletTx(vTxHash, vWtx);
706 if (err != DB_LOAD_OK) {
707 return err;
710 std::sort(vTxHash.begin(), vTxHash.end());
711 std::sort(vTxHashIn.begin(), vTxHashIn.end());
713 // erase each matching wallet TX
714 bool delerror = false;
715 std::vector<uint256>::iterator it = vTxHashIn.begin();
716 BOOST_FOREACH (uint256 hash, vTxHash) {
717 while (it < vTxHashIn.end() && (*it) < hash) {
718 it++;
720 if (it == vTxHashIn.end()) {
721 break;
723 else if ((*it) == hash) {
724 if(!EraseTx(hash)) {
725 LogPrint(BCLog::DB, "Transaction was found for deletion but returned database error: %s\n", hash.GetHex());
726 delerror = true;
728 vTxHashOut.push_back(hash);
732 if (delerror) {
733 return DB_CORRUPT;
735 return DB_LOAD_OK;
738 DBErrors CWalletDB::ZapWalletTx(std::vector<CWalletTx>& vWtx)
740 // build list of wallet TXs
741 std::vector<uint256> vTxHash;
742 DBErrors err = FindWalletTx(vTxHash, vWtx);
743 if (err != DB_LOAD_OK)
744 return err;
746 // erase each wallet TX
747 BOOST_FOREACH (uint256& hash, vTxHash) {
748 if (!EraseTx(hash))
749 return DB_CORRUPT;
752 return DB_LOAD_OK;
755 void MaybeCompactWalletDB()
757 static std::atomic<bool> fOneThread;
758 if (fOneThread.exchange(true)) {
759 return;
761 if (!GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) {
762 return;
765 for (CWalletRef pwallet : vpwallets) {
766 CWalletDBWrapper& dbh = pwallet->GetDBHandle();
768 unsigned int nUpdateCounter = dbh.nUpdateCounter;
770 if (dbh.nLastSeen != nUpdateCounter) {
771 dbh.nLastSeen = nUpdateCounter;
772 dbh.nLastWalletUpdate = GetTime();
775 if (dbh.nLastFlushed != nUpdateCounter && GetTime() - dbh.nLastWalletUpdate >= 2) {
776 if (CDB::PeriodicFlush(dbh)) {
777 dbh.nLastFlushed = nUpdateCounter;
782 fOneThread = false;
786 // Try to (very carefully!) recover wallet file if there is a problem.
788 bool CWalletDB::Recover(const std::string& filename, void *callbackDataIn, bool (*recoverKVcallback)(void* callbackData, CDataStream ssKey, CDataStream ssValue), std::string& out_backup_filename)
790 return CDB::Recover(filename, callbackDataIn, recoverKVcallback, out_backup_filename);
793 bool CWalletDB::Recover(const std::string& filename, std::string& out_backup_filename)
795 // recover without a key filter callback
796 // results in recovering all record types
797 return CWalletDB::Recover(filename, NULL, NULL, out_backup_filename);
800 bool CWalletDB::RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, CDataStream ssValue)
802 CWallet *dummyWallet = reinterpret_cast<CWallet*>(callbackData);
803 CWalletScanState dummyWss;
804 std::string strType, strErr;
805 bool fReadOK;
807 // Required in LoadKeyMetadata():
808 LOCK(dummyWallet->cs_wallet);
809 fReadOK = ReadKeyValue(dummyWallet, ssKey, ssValue,
810 dummyWss, strType, strErr);
812 if (!IsKeyType(strType) && strType != "hdchain")
813 return false;
814 if (!fReadOK)
816 LogPrintf("WARNING: CWalletDB::Recover skipping %s: %s\n", strType, strErr);
817 return false;
820 return true;
823 bool CWalletDB::VerifyEnvironment(const std::string& walletFile, const fs::path& dataDir, std::string& errorStr)
825 return CDB::VerifyEnvironment(walletFile, dataDir, errorStr);
828 bool CWalletDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path& dataDir, std::string& warningStr, std::string& errorStr)
830 return CDB::VerifyDatabaseFile(walletFile, dataDir, warningStr, errorStr, CWalletDB::Recover);
833 bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
835 return WriteIC(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value);
838 bool CWalletDB::EraseDestData(const std::string &address, const std::string &key)
840 return EraseIC(std::make_pair(std::string("destdata"), std::make_pair(address, key)));
844 bool CWalletDB::WriteHDChain(const CHDChain& chain)
846 return WriteIC(std::string("hdchain"), chain);
849 bool CWalletDB::TxnBegin()
851 return batch.TxnBegin();
854 bool CWalletDB::TxnCommit()
856 return batch.TxnCommit();
859 bool CWalletDB::TxnAbort()
861 return batch.TxnAbort();
864 bool CWalletDB::ReadVersion(int& nVersion)
866 return batch.ReadVersion(nVersion);
869 bool CWalletDB::WriteVersion(int nVersion)
871 return batch.WriteVersion(nVersion);