1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2014 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"
9 #include "consensus/validation.h"
12 #include "serialize.h"
16 #include "wallet/wallet.h"
17 #include "zcash/Proof.hpp"
19 #include <boost/filesystem.hpp>
20 #include <boost/foreach.hpp>
21 #include <boost/scoped_ptr.hpp>
22 #include <boost/thread.hpp>
26 static uint64_t nAccountingEntryNumber = 0;
32 bool CWalletDB::WriteName(const string& strAddress, const string& strName)
35 return Write(make_pair(string("name"), strAddress), strName);
38 bool CWalletDB::EraseName(const string& strAddress)
40 // This should only be used for sending addresses, never for receiving addresses,
41 // receiving addresses must always have an address book entry if they're not change return.
43 return Erase(make_pair(string("name"), strAddress));
46 bool CWalletDB::WritePurpose(const string& strAddress, const string& strPurpose)
49 return Write(make_pair(string("purpose"), strAddress), strPurpose);
52 bool CWalletDB::ErasePurpose(const string& strPurpose)
55 return Erase(make_pair(string("purpose"), strPurpose));
58 bool CWalletDB::WriteTx(uint256 hash, const CWalletTx& wtx)
61 return Write(std::make_pair(std::string("tx"), hash), wtx);
64 bool CWalletDB::EraseTx(uint256 hash)
67 return Erase(std::make_pair(std::string("tx"), hash));
70 bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
74 if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
78 // hash pubkey/privkey to accelerate wallet load
79 std::vector<unsigned char> vchKey;
80 vchKey.reserve(vchPubKey.size() + vchPrivKey.size());
81 vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
82 vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
84 return Write(std::make_pair(std::string("key"), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false);
87 bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
88 const std::vector<unsigned char>& vchCryptedSecret,
89 const CKeyMetadata &keyMeta)
91 const bool fEraseUnencryptedKey = true;
94 if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
98 if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
100 if (fEraseUnencryptedKey)
102 Erase(std::make_pair(std::string("key"), vchPubKey));
103 Erase(std::make_pair(std::string("wkey"), vchPubKey));
108 bool CWalletDB::WriteCryptedZKey(const libzcash::PaymentAddress & addr,
109 const libzcash::ViewingKey &vk,
110 const std::vector<unsigned char>& vchCryptedSecret,
111 const CKeyMetadata &keyMeta)
113 const bool fEraseUnencryptedKey = true;
116 if (!Write(std::make_pair(std::string("zkeymeta"), addr), keyMeta))
119 if (!Write(std::make_pair(std::string("czkey"), addr), std::make_pair(vk, vchCryptedSecret), false))
121 if (fEraseUnencryptedKey)
123 Erase(std::make_pair(std::string("zkey"), addr));
128 bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
131 return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
134 bool CWalletDB::WriteZKey(const libzcash::PaymentAddress& addr, const libzcash::SpendingKey& key, const CKeyMetadata &keyMeta)
138 if (!Write(std::make_pair(std::string("zkeymeta"), addr), keyMeta))
141 // pair is: tuple_key("zkey", paymentaddress) --> secretkey
142 return Write(std::make_pair(std::string("zkey"), addr), key, false);
145 bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
148 return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false);
151 bool CWalletDB::WriteWatchOnly(const CScript &dest)
154 return Write(std::make_pair(std::string("watchs"), dest), '1');
157 bool CWalletDB::EraseWatchOnly(const CScript &dest)
160 return Erase(std::make_pair(std::string("watchs"), dest));
163 bool CWalletDB::WriteBestBlock(const CBlockLocator& locator)
166 return Write(std::string("bestblock"), locator);
169 bool CWalletDB::ReadBestBlock(CBlockLocator& locator)
171 return Read(std::string("bestblock"), locator);
174 bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
177 return Write(std::string("orderposnext"), nOrderPosNext);
180 bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)
183 return Write(std::string("defaultkey"), vchPubKey);
186 bool CWalletDB::WriteWitnessCacheSize(int64_t nWitnessCacheSize)
189 return Write(std::string("witnesscachesize"), nWitnessCacheSize);
192 bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
194 return Read(std::make_pair(std::string("pool"), nPool), keypool);
197 bool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool)
200 return Write(std::make_pair(std::string("pool"), nPool), keypool);
203 bool CWalletDB::ErasePool(int64_t nPool)
206 return Erase(std::make_pair(std::string("pool"), nPool));
209 bool CWalletDB::WriteMinVersion(int nVersion)
211 return Write(std::string("minversion"), nVersion);
214 bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account)
217 return Read(make_pair(string("acc"), strAccount), account);
220 bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
222 return Write(make_pair(string("acc"), strAccount), account);
225 bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry)
227 return Write(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry);
230 bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
232 return WriteAccountingEntry(++nAccountingEntryNumber, acentry);
235 CAmount CWalletDB::GetAccountCreditDebit(const string& strAccount)
237 list<CAccountingEntry> entries;
238 ListAccountCreditDebit(strAccount, entries);
240 CAmount nCreditDebit = 0;
241 BOOST_FOREACH (const CAccountingEntry& entry, entries)
242 nCreditDebit += entry.nCreditDebit;
247 void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
249 bool fAllAccounts = (strAccount == "*");
251 Dbc* pcursor = GetCursor();
253 throw runtime_error("CWalletDB::ListAccountCreditDebit(): cannot create DB cursor");
254 unsigned int fFlags = DB_SET_RANGE;
258 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
259 if (fFlags == DB_SET_RANGE)
260 ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? string("") : strAccount), uint64_t(0)));
261 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
262 int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
264 if (ret == DB_NOTFOUND)
269 throw runtime_error("CWalletDB::ListAccountCreditDebit(): error scanning DB");
275 if (strType != "acentry")
277 CAccountingEntry acentry;
278 ssKey >> acentry.strAccount;
279 if (!fAllAccounts && acentry.strAccount != strAccount)
283 ssKey >> acentry.nEntryNo;
284 entries.push_back(acentry);
290 DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet)
292 LOCK(pwallet->cs_wallet);
293 // Old wallets didn't have any defined order for transactions
294 // Probably a bad idea to change the output of this
296 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
297 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
298 typedef multimap<int64_t, TxPair > TxItems;
301 for (map<uint256, CWalletTx>::iterator it = pwallet->mapWallet.begin(); it != pwallet->mapWallet.end(); ++it)
303 CWalletTx* wtx = &((*it).second);
304 txByTime.insert(make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0)));
306 list<CAccountingEntry> acentries;
307 ListAccountCreditDebit("", acentries);
308 BOOST_FOREACH(CAccountingEntry& entry, acentries)
310 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
313 int64_t& nOrderPosNext = pwallet->nOrderPosNext;
315 std::vector<int64_t> nOrderPosOffsets;
316 for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
318 CWalletTx *const pwtx = (*it).second.first;
319 CAccountingEntry *const pacentry = (*it).second.second;
320 int64_t& nOrderPos = (pwtx != 0) ? pwtx->nOrderPos : pacentry->nOrderPos;
324 nOrderPos = nOrderPosNext++;
325 nOrderPosOffsets.push_back(nOrderPos);
329 if (!WriteTx(pwtx->GetHash(), *pwtx))
333 if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
338 int64_t nOrderPosOff = 0;
339 BOOST_FOREACH(const int64_t& nOffsetStart, nOrderPosOffsets)
341 if (nOrderPos >= nOffsetStart)
344 nOrderPos += nOrderPosOff;
345 nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
350 // Since we're changing the order, write it back
353 if (!WriteTx(pwtx->GetHash(), *pwtx))
357 if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
361 WriteOrderPosNext(nOrderPosNext);
366 class CWalletScanState {
370 unsigned int nKeyMeta;
372 unsigned int nCZKeys;
373 unsigned int nZKeyMeta;
377 vector<uint256> vWalletUpgrade;
380 nKeys = nCKeys = nKeyMeta = nZKeys = nCZKeys = nZKeyMeta = 0;
381 fIsEncrypted = false;
382 fAnyUnordered = false;
388 ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
389 CWalletScanState &wss, string& strType, string& strErr)
393 // Taking advantage of the fact that pair serialization
394 // is just the two items serialized one after the other
396 if (strType == "name")
400 ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].name;
402 else if (strType == "purpose")
406 ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].purpose;
408 else if (strType == "tx")
414 CValidationState state;
415 auto verifier = libzcash::ProofVerifier::Strict();
416 if (!(CheckTransaction(wtx, state, verifier) && (wtx.GetHash() == hash) && state.IsValid()))
419 // Undo serialize changes in 31600
420 if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
422 if (!ssValue.empty())
426 ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
427 strErr = strprintf("LoadWallet() upgrading tx ver=%d %d '%s' %s",
428 wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount, hash.ToString());
429 wtx.fTimeReceivedIsTxTime = fTmp;
433 strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
434 wtx.fTimeReceivedIsTxTime = 0;
436 wss.vWalletUpgrade.push_back(hash);
439 if (wtx.nOrderPos == -1)
440 wss.fAnyUnordered = true;
442 pwallet->AddToWallet(wtx, true, NULL);
444 else if (strType == "acentry")
450 if (nNumber > nAccountingEntryNumber)
451 nAccountingEntryNumber = nNumber;
453 if (!wss.fAnyUnordered)
455 CAccountingEntry acentry;
457 if (acentry.nOrderPos == -1)
458 wss.fAnyUnordered = true;
461 else if (strType == "watchs")
468 pwallet->LoadWatchOnly(script);
470 // Watch-only addresses have no birthday information for now,
471 // so set the wallet birthday to the beginning of time.
472 pwallet->nTimeFirstKey = 1;
474 else if (strType == "zkey")
476 libzcash::PaymentAddress addr;
478 libzcash::SpendingKey key;
481 if (!pwallet->LoadZKey(key))
483 strErr = "Error reading wallet database: LoadZKey failed";
489 else if (strType == "key" || strType == "wkey")
493 if (!vchPubKey.IsValid())
495 strErr = "Error reading wallet database: CPubKey corrupt";
502 if (strType == "key")
509 pkey = wkey.vchPrivKey;
512 // Old wallets store keys as "key" [pubkey] => [privkey]
513 // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key
514 // using EC operations as a checksum.
515 // Newer wallets store keys as "key"[pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while
516 // remaining backwards-compatible.
523 bool fSkipCheck = false;
527 // hash pubkey/privkey to accelerate wallet load
528 std::vector<unsigned char> vchKey;
529 vchKey.reserve(vchPubKey.size() + pkey.size());
530 vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
531 vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
533 if (Hash(vchKey.begin(), vchKey.end()) != hash)
535 strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
542 if (!key.Load(pkey, vchPubKey, fSkipCheck))
544 strErr = "Error reading wallet database: CPrivKey corrupt";
547 if (!pwallet->LoadKey(key, vchPubKey))
549 strErr = "Error reading wallet database: LoadKey failed";
553 else if (strType == "mkey")
557 CMasterKey kMasterKey;
558 ssValue >> kMasterKey;
559 if(pwallet->mapMasterKeys.count(nID) != 0)
561 strErr = strprintf("Error reading wallet database: duplicate CMasterKey id %u", nID);
564 pwallet->mapMasterKeys[nID] = kMasterKey;
565 if (pwallet->nMasterKeyMaxID < nID)
566 pwallet->nMasterKeyMaxID = nID;
568 else if (strType == "ckey")
570 vector<unsigned char> vchPubKey;
572 vector<unsigned char> vchPrivKey;
573 ssValue >> vchPrivKey;
576 if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
578 strErr = "Error reading wallet database: LoadCryptedKey failed";
581 wss.fIsEncrypted = true;
583 else if (strType == "czkey")
585 libzcash::PaymentAddress addr;
587 // Deserialization of a pair is just one item after another
590 libzcash::ViewingKey vk(vkValue);
591 vector<unsigned char> vchCryptedSecret;
592 ssValue >> vchCryptedSecret;
595 if (!pwallet->LoadCryptedZKey(addr, vk, vchCryptedSecret))
597 strErr = "Error reading wallet database: LoadCryptedZKey failed";
600 wss.fIsEncrypted = true;
602 else if (strType == "keymeta")
606 CKeyMetadata keyMeta;
610 pwallet->LoadKeyMetadata(vchPubKey, keyMeta);
612 // find earliest key creation time, as wallet birthday
613 if (!pwallet->nTimeFirstKey ||
614 (keyMeta.nCreateTime < pwallet->nTimeFirstKey))
615 pwallet->nTimeFirstKey = keyMeta.nCreateTime;
617 else if (strType == "zkeymeta")
619 libzcash::PaymentAddress addr;
621 CKeyMetadata keyMeta;
625 pwallet->LoadZKeyMetadata(addr, keyMeta);
627 // ignore earliest key creation time as taddr will exist before any zaddr
629 else if (strType == "defaultkey")
631 ssValue >> pwallet->vchDefaultKey;
633 else if (strType == "pool")
639 pwallet->setKeyPool.insert(nIndex);
641 // If no metadata exists yet, create a default with the pool key's
642 // creation time. Note that this may be overwritten by actually
643 // stored metadata for that key later, which is fine.
644 CKeyID keyid = keypool.vchPubKey.GetID();
645 if (pwallet->mapKeyMetadata.count(keyid) == 0)
646 pwallet->mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime);
648 else if (strType == "version")
650 ssValue >> wss.nFileVersion;
651 if (wss.nFileVersion == 10300)
652 wss.nFileVersion = 300;
654 else if (strType == "cscript")
660 if (!pwallet->LoadCScript(script))
662 strErr = "Error reading wallet database: LoadCScript failed";
666 else if (strType == "orderposnext")
668 ssValue >> pwallet->nOrderPosNext;
670 else if (strType == "destdata")
672 std::string strAddress, strKey, strValue;
676 if (!pwallet->LoadDestData(CBitcoinAddress(strAddress).Get(), strKey, strValue))
678 strErr = "Error reading wallet database: LoadDestData failed";
682 else if (strType == "witnesscachesize")
684 ssValue >> pwallet->nWitnessCacheSize;
693 static bool IsKeyType(string strType)
695 return (strType== "key" || strType == "wkey" ||
696 strType == "zkey" || strType == "czkey" ||
697 strType == "mkey" || strType == "ckey");
700 DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
702 pwallet->vchDefaultKey = CPubKey();
703 CWalletScanState wss;
704 bool fNoncriticalErrors = false;
705 DBErrors result = DB_LOAD_OK;
708 LOCK(pwallet->cs_wallet);
710 if (Read((string)"minversion", nMinVersion))
712 if (nMinVersion > CLIENT_VERSION)
714 pwallet->LoadMinVersion(nMinVersion);
718 Dbc* pcursor = GetCursor();
721 LogPrintf("Error getting wallet database cursor\n");
728 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
729 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
730 int ret = ReadAtCursor(pcursor, ssKey, ssValue);
731 if (ret == DB_NOTFOUND)
735 LogPrintf("Error reading next record from wallet database\n");
739 // Try to be tolerant of single corrupt records:
740 string strType, strErr;
741 if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
743 // losing keys is considered a catastrophic error, anything else
744 // we assume the user can live with:
745 if (IsKeyType(strType))
749 // Leave other errors alone, if we try to fix them we might make things worse.
750 fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
752 // Rescan if there is a bad transaction record:
753 SoftSetBoolArg("-rescan", true);
757 LogPrintf("%s\n", strErr);
761 catch (const boost::thread_interrupted&) {
768 if (fNoncriticalErrors && result == DB_LOAD_OK)
769 result = DB_NONCRITICAL_ERROR;
771 // Any wallet corruption at all: skip any rewriting or
772 // upgrading, we don't want to make it worse.
773 if (result != DB_LOAD_OK)
776 LogPrintf("nFileVersion = %d\n", wss.nFileVersion);
778 LogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\n",
779 wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys);
781 LogPrintf("ZKeys: %u plaintext, %u encrypted, %u w/metadata, %u total\n",
782 wss.nZKeys, wss.nCZKeys, wss.nZKeyMeta, wss.nZKeys + wss.nCZKeys);
784 // nTimeFirstKey is only reliable if all keys have metadata
785 if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta)
786 pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value'
788 BOOST_FOREACH(uint256 hash, wss.vWalletUpgrade)
789 WriteTx(hash, pwallet->mapWallet[hash]);
791 // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
792 if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000))
793 return DB_NEED_REWRITE;
795 if (wss.nFileVersion < CLIENT_VERSION) // Update
796 WriteVersion(CLIENT_VERSION);
798 if (wss.fAnyUnordered)
799 result = ReorderTransactions(pwallet);
804 DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash, vector<CWalletTx>& vWtx)
806 pwallet->vchDefaultKey = CPubKey();
807 bool fNoncriticalErrors = false;
808 DBErrors result = DB_LOAD_OK;
811 LOCK(pwallet->cs_wallet);
813 if (Read((string)"minversion", nMinVersion))
815 if (nMinVersion > CLIENT_VERSION)
817 pwallet->LoadMinVersion(nMinVersion);
821 Dbc* pcursor = GetCursor();
824 LogPrintf("Error getting wallet database cursor\n");
831 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
832 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
833 int ret = ReadAtCursor(pcursor, ssKey, ssValue);
834 if (ret == DB_NOTFOUND)
838 LogPrintf("Error reading next record from wallet database\n");
844 if (strType == "tx") {
851 vTxHash.push_back(hash);
857 catch (const boost::thread_interrupted&) {
864 if (fNoncriticalErrors && result == DB_LOAD_OK)
865 result = DB_NONCRITICAL_ERROR;
870 DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, vector<CWalletTx>& vWtx)
872 // build list of wallet TXs
873 vector<uint256> vTxHash;
874 DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx);
875 if (err != DB_LOAD_OK)
878 // erase each wallet TX
879 BOOST_FOREACH (uint256& hash, vTxHash) {
887 void ThreadFlushWalletDB(const string& strFile)
889 // Make this thread recognisable as the wallet flushing thread
890 RenameThread("zcash-wallet");
892 static bool fOneThread;
896 if (!GetBoolArg("-flushwallet", true))
899 unsigned int nLastSeen = nWalletDBUpdated;
900 unsigned int nLastFlushed = nWalletDBUpdated;
901 int64_t nLastWalletUpdate = GetTime();
906 if (nLastSeen != nWalletDBUpdated)
908 nLastSeen = nWalletDBUpdated;
909 nLastWalletUpdate = GetTime();
912 if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2)
914 TRY_LOCK(bitdb.cs_db,lockDb);
917 // Don't do this if any databases are in use
919 map<string, int>::iterator mi = bitdb.mapFileUseCount.begin();
920 while (mi != bitdb.mapFileUseCount.end())
922 nRefCount += (*mi).second;
928 boost::this_thread::interruption_point();
929 map<string, int>::iterator mi = bitdb.mapFileUseCount.find(strFile);
930 if (mi != bitdb.mapFileUseCount.end())
932 LogPrint("db", "Flushing wallet.dat\n");
933 nLastFlushed = nWalletDBUpdated;
934 int64_t nStart = GetTimeMillis();
936 // Flush wallet.dat so it's self contained
937 bitdb.CloseDb(strFile);
938 bitdb.CheckpointLSN(strFile);
940 bitdb.mapFileUseCount.erase(mi++);
941 LogPrint("db", "Flushed wallet.dat %dms\n", GetTimeMillis() - nStart);
949 bool BackupWallet(const CWallet& wallet, const string& strDest)
951 if (!wallet.fFileBacked)
957 if (!bitdb.mapFileUseCount.count(wallet.strWalletFile) || bitdb.mapFileUseCount[wallet.strWalletFile] == 0)
959 // Flush log data to the dat file
960 bitdb.CloseDb(wallet.strWalletFile);
961 bitdb.CheckpointLSN(wallet.strWalletFile);
962 bitdb.mapFileUseCount.erase(wallet.strWalletFile);
965 boost::filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile;
966 boost::filesystem::path pathDest(strDest);
967 if (boost::filesystem::is_directory(pathDest))
968 pathDest /= wallet.strWalletFile;
971 #if BOOST_VERSION >= 104000
972 boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists);
974 boost::filesystem::copy_file(pathSrc, pathDest);
976 LogPrintf("copied wallet.dat to %s\n", pathDest.string());
978 } catch (const boost::filesystem::filesystem_error& e) {
979 LogPrintf("error copying wallet.dat to %s - %s\n", pathDest.string(), e.what());
990 // Try to (very carefully!) recover wallet.dat if there is a problem.
992 bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys)
994 // Recovery procedure:
995 // move wallet.dat to wallet.timestamp.bak
996 // Call Salvage with fAggressive=true to
997 // get as much data as possible.
998 // Rewrite salvaged data to wallet.dat
999 // Set -rescan so any missing transactions will be
1001 int64_t now = GetTime();
1002 std::string newFilename = strprintf("wallet.%d.bak", now);
1004 int result = dbenv.dbenv->dbrename(NULL, filename.c_str(), NULL,
1005 newFilename.c_str(), DB_AUTO_COMMIT);
1007 LogPrintf("Renamed %s to %s\n", filename, newFilename);
1010 LogPrintf("Failed to rename %s to %s\n", filename, newFilename);
1014 std::vector<CDBEnv::KeyValPair> salvagedData;
1015 bool fSuccess = dbenv.Salvage(newFilename, true, salvagedData);
1016 if (salvagedData.empty())
1018 LogPrintf("Salvage(aggressive) found no records in %s.\n", newFilename);
1021 LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
1023 boost::scoped_ptr<Db> pdbCopy(new Db(dbenv.dbenv, 0));
1024 int ret = pdbCopy->open(NULL, // Txn pointer
1025 filename.c_str(), // Filename
1026 "main", // Logical db name
1027 DB_BTREE, // Database type
1032 LogPrintf("Cannot create database file %s\n", filename);
1035 CWallet dummyWallet;
1036 CWalletScanState wss;
1038 DbTxn* ptxn = dbenv.TxnBegin();
1039 BOOST_FOREACH(CDBEnv::KeyValPair& row, salvagedData)
1043 CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION);
1044 CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);
1045 string strType, strErr;
1046 bool fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue,
1047 wss, strType, strErr);
1048 if (!IsKeyType(strType))
1052 LogPrintf("WARNING: CWalletDB::Recover skipping %s: %s\n", strType, strErr);
1056 Dbt datKey(&row.first[0], row.first.size());
1057 Dbt datValue(&row.second[0], row.second.size());
1058 int ret2 = pdbCopy->put(ptxn, &datKey, &datValue, DB_NOOVERWRITE);
1068 bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename)
1070 return CWalletDB::Recover(dbenv, filename, false);
1073 bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
1076 return Write(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value);
1079 bool CWalletDB::EraseDestData(const std::string &address, const std::string &key)
1082 return Erase(std::make_pair(std::string("destdata"), std::make_pair(address, key)));