1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
10 #include <boost/version.hpp>
11 #include <boost/filesystem.hpp>
14 static uint64_t nAccountingEntryNumber = 0;
15 extern bool fWalletUnlockMintOnly;
21 bool CWalletDB::WriteName(const std::string& strAddress, const std::string& strName)
24 return Write(make_pair(std::string("name"), strAddress), strName);
27 bool CWalletDB::EraseName(const std::string& strAddress)
29 // This should only be used for sending addresses, never for receiving addresses,
30 // receiving addresses must always have an address book entry if they're not change return.
32 return Erase(make_pair(std::string("name"), strAddress));
35 bool CWalletDB::WriteTx(uint256 hash, const CWalletTx &wtx)
38 return Write(std::make_pair(std::string("tx"), hash), wtx);
41 bool CWalletDB::EraseTx(uint256 hash)
44 return Erase(std::make_pair(std::string("tx"), hash));
47 bool CWalletDB::WriteKey(const CPubKey &key, const CPrivKey &vchPrivKey, const CKeyMetadata &keyMeta)
50 if(!Write(std::make_pair(std::string("keymeta"), key), keyMeta))
53 if(!Write(std::make_pair(std::string("key"), key), vchPrivKey, false))
59 bool CWalletDB::WriteMalleableKey(const CMalleableKeyView &keyView, const CSecret &vchSecretH, const CKeyMetadata &keyMeta)
62 if(!Write(std::make_pair(std::string("malmeta"), keyView.ToString()), keyMeta))
65 if(!Write(std::make_pair(std::string("malpair"), keyView.ToString()), vchSecretH, false))
71 bool CWalletDB::WriteCryptedMalleableKey(const CMalleableKeyView &keyView, const std::vector<unsigned char> &vchCryptedSecretH, const CKeyMetadata &keyMeta)
74 if(!Write(std::make_pair(std::string("malmeta"), keyView.ToString()), keyMeta))
77 if(!Write(std::make_pair(std::string("malcpair"), keyView.ToString()), vchCryptedSecretH, false))
80 Erase(std::make_pair(std::string("malpair"), keyView.ToString()));
85 bool CWalletDB::WriteCryptedKey(const CPubKey &key, const std::vector<unsigned char> &vchCryptedSecret, const CKeyMetadata &keyMeta)
88 bool fEraseUnencryptedKey = true;
90 if(!Write(std::make_pair(std::string("keymeta"), key), keyMeta))
93 if (!Write(std::make_pair(std::string("ckey"), key), vchCryptedSecret, false))
95 if (fEraseUnencryptedKey)
97 Erase(std::make_pair(std::string("key"), key));
98 Erase(std::make_pair(std::string("wkey"), key));
103 bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey &kMasterKey)
106 return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
109 bool CWalletDB::EraseMasterKey(unsigned int nID)
112 return Erase(std::make_pair(std::string("mkey"), nID));
115 bool CWalletDB::EraseCryptedKey(const CPubKey &key)
117 return Erase(std::make_pair(std::string("ckey"), key));
120 bool CWalletDB::EraseCryptedMalleableKey(const CMalleableKeyView &keyView)
122 return Erase(std::make_pair(std::string("malcpair"), keyView.ToString()));
125 bool CWalletDB::WriteCScript(const uint160 &hash, const CScript &redeemScript)
128 return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false);
131 bool CWalletDB::WriteWatchOnly(const CScript &dest)
134 return Write(std::make_pair(std::string("watchs"), dest), '1');
137 bool CWalletDB::EraseWatchOnly(const CScript &dest)
140 return Erase(std::make_pair(std::string("watchs"), dest));
143 bool CWalletDB::WriteBestBlock(const CBlockLocator &locator)
146 return Write(std::string("bestblock"), locator);
149 bool CWalletDB::ReadBestBlock(CBlockLocator &locator)
151 return Read(std::string("bestblock"), locator);
154 bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
157 return Write(std::string("orderposnext"), nOrderPosNext);
160 bool CWalletDB::WriteDefaultKey(const CPubKey &key)
163 return Write(std::string("defaultkey"), key);
166 bool CWalletDB::ReadPool(int64_t nPool, CKeyPool &keypool)
168 return Read(std::make_pair(std::string("pool"), nPool), keypool);
171 bool CWalletDB::WritePool(int64_t nPool, const CKeyPool &keypool)
174 return Write(std::make_pair(std::string("pool"), nPool), keypool);
177 bool CWalletDB::ErasePool(int64_t nPool)
180 return Erase(std::make_pair(std::string("pool"), nPool));
183 bool CWalletDB::WriteMinVersion(int nVersion)
185 return Write(std::string("minversion"), nVersion);
188 bool CWalletDB::ReadAccount(const std::string& strAccount, CAccount& account)
191 return Read(make_pair(std::string("acc"), strAccount), account);
194 bool CWalletDB::WriteAccount(const std::string& strAccount, const CAccount& account)
196 return Write(make_pair(std::string("acc"), strAccount), account);
199 bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry)
201 return Write(std::make_tuple(std::string("acentry"), acentry.strAccount, nAccEntryNum), acentry);
204 bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
206 return WriteAccountingEntry(++nAccountingEntryNumber, acentry);
209 int64_t CWalletDB::GetAccountCreditDebit(const std::string& strAccount)
211 std::list<CAccountingEntry> entries;
212 ListAccountCreditDebit(strAccount, entries);
214 int64_t nCreditDebit = 0;
215 for (const CAccountingEntry& entry : entries)
216 nCreditDebit += entry.nCreditDebit;
221 void CWalletDB::ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& entries)
223 bool fAllAccounts = (strAccount == "*");
225 Dbc* pcursor = GetCursor();
227 throw std::runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor");
228 unsigned int fFlags = DB_SET_RANGE;
232 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
233 if (fFlags == DB_SET_RANGE)
234 ssKey << std::make_tuple(std::string("acentry"), (fAllAccounts? std::string("") : strAccount), uint64_t(0));
235 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
236 int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
238 if (ret == DB_NOTFOUND)
243 throw std::runtime_error("CWalletDB::ListAccountCreditDebit() : error scanning DB");
249 if (strType != "acentry")
251 CAccountingEntry acentry;
252 ssKey >> acentry.strAccount;
253 if (!fAllAccounts && acentry.strAccount != strAccount)
257 ssKey >> acentry.nEntryNo;
258 entries.push_back(acentry);
266 CWalletDB::ReorderTransactions(CWallet* pwallet)
268 LOCK(pwallet->cs_wallet);
269 // Old wallets didn't have any defined order for transactions
270 // Probably a bad idea to change the output of this
272 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
273 typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;
274 typedef std::multimap<int64_t, TxPair > TxItems;
277 for (auto it = pwallet->mapWallet.begin(); it != pwallet->mapWallet.end(); ++it)
279 CWalletTx* wtx = &((*it).second);
280 txByTime.insert(make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)nullptr)));
282 std::list<CAccountingEntry> acentries;
283 ListAccountCreditDebit("", acentries);
284 for (CAccountingEntry& entry : acentries)
286 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)nullptr, &entry)));
289 int64_t& nOrderPosNext = pwallet->nOrderPosNext;
291 std::vector<int64_t> nOrderPosOffsets;
292 for (auto it = txByTime.begin(); it != txByTime.end(); ++it)
294 CWalletTx *const pwtx = (*it).second.first;
295 CAccountingEntry *const pacentry = (*it).second.second;
296 int64_t& nOrderPos = (pwtx != nullptr) ? pwtx->nOrderPos : pacentry->nOrderPos;
300 nOrderPos = nOrderPosNext++;
301 nOrderPosOffsets.push_back(nOrderPos);
304 // Have to write accounting regardless, since we don't keep it in memory
305 if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
310 int64_t nOrderPosOff = 0;
311 for (const int64_t& nOffsetStart : nOrderPosOffsets)
313 if (nOrderPos >= nOffsetStart)
316 nOrderPos += nOrderPosOff;
317 nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
322 // Since we're changing the order, write it back
325 if (!WriteTx(pwtx->GetHash(), *pwtx))
329 if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
337 class CWalletScanState {
341 unsigned int nKeyMeta;
345 std::vector<uint256> vWalletUpgrade;
348 nKeys = nCKeys = nKeyMeta = 0;
349 fIsEncrypted = false;
350 fAnyUnordered = false;
356 ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
357 CWalletScanState &wss, std::string& strType, std::string& strErr)
361 // Taking advantage of the fact that pair serialization
362 // is just the two items serialized one after the other
365 if (strType == "name")
367 std::string strAddress;
369 ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress)];
371 else if (strType == "tx")
375 CWalletTx& wtx = pwallet->mapWallet[hash];
377 if (wtx.CheckTransaction() && (wtx.GetHash() == hash))
378 wtx.BindWallet(pwallet);
381 pwallet->mapWallet.erase(hash);
385 // Undo serialize changes in 31600
386 if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
388 if (!ssValue.empty())
392 ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
393 strErr = strprintf("LoadWallet() upgrading tx ver=%d %d '%s' %s",
394 wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount.c_str(), hash.ToString().c_str());
395 wtx.fTimeReceivedIsTxTime = fTmp;
399 strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str());
400 wtx.fTimeReceivedIsTxTime = 0;
402 wss.vWalletUpgrade.push_back(hash);
405 if (wtx.nOrderPos == -1)
406 wss.fAnyUnordered = true;
409 //printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str());
410 //printf(" %12"PRId64" %s %s %s\n",
411 // wtx.vout[0].nValue,
412 // DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(),
413 // wtx.hashBlock.ToString().substr(0,20).c_str(),
414 // wtx.mapValue["message"].c_str());
416 else if (strType == "acentry")
418 std::string strAccount;
422 if (nNumber > nAccountingEntryNumber)
423 nAccountingEntryNumber = nNumber;
425 if (!wss.fAnyUnordered)
427 CAccountingEntry acentry;
429 if (acentry.nOrderPos == -1)
430 wss.fAnyUnordered = true;
433 else if (strType == "watchs")
440 pwallet->LoadWatchOnly(script);
442 // Watch-only addresses have no birthday information for now,
443 // so set the wallet birthday to the beginning of time.
444 pwallet->nTimeFirstKey = 1;
446 else if (strType == "malpair")
448 std::string strKeyView;
452 ssValue >> vchSecret;
454 CMalleableKeyView keyView(strKeyView);
455 if (!pwallet->LoadKey(keyView, vchSecret))
457 strErr = "Error reading wallet database: LoadKey failed";
461 else if (strType == "malcpair")
463 std::string strKeyView;
465 std::vector<unsigned char> vchCryptedSecret;
467 ssValue >> vchCryptedSecret;
469 CMalleableKeyView keyView(strKeyView);
470 if (!pwallet->LoadCryptedKey(keyView, vchCryptedSecret))
472 strErr = "Error reading wallet database: LoadCryptedKey failed";
476 else if (strType == "key" || strType == "wkey")
481 if (strType == "key")
486 if (!key.SetPrivKey(pkey))
488 strErr = "Error reading wallet database: CPrivKey corrupt";
491 if (key.GetPubKey() != vchPubKey)
493 strErr = "Error reading wallet database: CPrivKey pubkey inconsistency";
496 key.SetCompressedPubKey(vchPubKey.IsCompressed());
499 strErr = "Error reading wallet database: invalid CPrivKey";
507 if (!key.SetPrivKey(wkey.vchPrivKey))
509 strErr = "Error reading wallet database: CPrivKey corrupt";
512 if (key.GetPubKey() != vchPubKey)
514 strErr = "Error reading wallet database: CWalletKey pubkey inconsistency";
517 key.SetCompressedPubKey(vchPubKey.IsCompressed());
520 strErr = "Error reading wallet database: invalid CWalletKey";
524 if (!pwallet->LoadKey(key))
526 strErr = "Error reading wallet database: LoadKey failed";
530 else if (strType == "mkey")
534 CMasterKey kMasterKey;
535 ssValue >> kMasterKey;
537 if(pwallet->mapMasterKeys.count(nID) != 0)
539 strErr = strprintf("Error reading wallet database: duplicate CMasterKey id %u", nID);
542 pwallet->mapMasterKeys[nID] = kMasterKey;
543 if (pwallet->nMasterKeyMaxID < nID)
544 pwallet->nMasterKeyMaxID = nID;
546 else if (strType == "ckey")
551 std::vector<unsigned char> vchPrivKey;
552 ssValue >> vchPrivKey;
553 if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
555 strErr = "Error reading wallet database: LoadCryptedKey failed";
558 wss.fIsEncrypted = true;
560 else if (strType == "malmeta")
562 std::string strKeyView;
565 CMalleableKeyView keyView;
566 keyView.SetString(strKeyView);
568 CKeyMetadata keyMeta;
572 pwallet->LoadKeyMetadata(keyView, keyMeta);
574 else if (strType == "keymeta")
578 CKeyMetadata keyMeta;
582 pwallet->LoadKeyMetadata(vchPubKey, keyMeta);
584 // find earliest key creation time, as wallet birthday
585 if (!pwallet->nTimeFirstKey ||
586 (keyMeta.nCreateTime < pwallet->nTimeFirstKey))
587 pwallet->nTimeFirstKey = keyMeta.nCreateTime;
589 else if (strType == "defaultkey")
591 ssValue >> pwallet->vchDefaultKey;
593 else if (strType == "pool")
599 pwallet->setKeyPool.insert(nIndex);
601 // If no metadata exists yet, create a default with the pool key's
602 // creation time. Note that this may be overwritten by actually
603 // stored metadata for that key later, which is fine.
604 CBitcoinAddress addr = CBitcoinAddress(keypool.vchPubKey.GetID());
605 if (pwallet->mapKeyMetadata.count(addr) == 0)
606 pwallet->mapKeyMetadata[addr] = CKeyMetadata(keypool.nTime);
609 else if (strType == "version")
611 ssValue >> wss.nFileVersion;
612 if (wss.nFileVersion == 10300)
613 wss.nFileVersion = 300;
615 else if (strType == "cscript")
621 if (!pwallet->LoadCScript(script))
623 strErr = "Error reading wallet database: LoadCScript failed";
627 else if (strType == "orderposnext")
629 ssValue >> pwallet->nOrderPosNext;
638 static bool IsKeyType(const std::string& strType)
640 return (strType== "key" || strType == "wkey" ||
641 strType == "mkey" || strType == "ckey" || strType == "malpair" || strType == "malcpair");
644 DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
646 pwallet->vchDefaultKey = CPubKey();
647 CWalletScanState wss;
648 bool fNoncriticalErrors = false;
649 DBErrors result = DB_LOAD_OK;
652 LOCK(pwallet->cs_wallet);
654 if (Read((std::string)"minversion", nMinVersion))
656 if (nMinVersion > CLIENT_VERSION)
658 pwallet->LoadMinVersion(nMinVersion);
662 Dbc* pcursor = GetCursor();
665 printf("Error getting wallet database cursor\n");
672 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
673 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
674 int ret = ReadAtCursor(pcursor, ssKey, ssValue);
675 if (ret == DB_NOTFOUND)
679 printf("Error reading next record from wallet database\n");
683 // Try to be tolerant of single corrupt records:
684 std::string strType, strErr;
685 if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
687 // losing keys is considered a catastrophic error, anything else
688 // we assume the user can live with:
689 if (IsKeyType(strType))
693 // Leave other errors alone, if we try to fix them we might make things worse.
694 fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
696 // Rescan if there is a bad transaction record:
697 SoftSetBoolArg("-rescan", true);
701 printf("%s\n", strErr.c_str());
710 if (fNoncriticalErrors && result == DB_LOAD_OK)
711 result = DB_NONCRITICAL_ERROR;
713 // Any wallet corruption at all: skip any rewriting or
714 // upgrading, we don't want to make it worse.
715 if (result != DB_LOAD_OK)
718 printf("nFileVersion = %d\n", wss.nFileVersion);
720 printf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\n",
721 wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys);
723 // nTimeFirstKey is only reliable if all keys have metadata
724 if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta)
725 pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value'
728 for (uint256 hash : wss.vWalletUpgrade)
729 WriteTx(hash, pwallet->mapWallet[hash]);
731 // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
732 if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000))
733 return DB_NEED_REWRITE;
735 if (wss.nFileVersion < CLIENT_VERSION) // Update
736 WriteVersion(CLIENT_VERSION);
738 if (wss.fAnyUnordered)
739 result = ReorderTransactions(pwallet);
744 DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, std::vector<uint256>& vTxHash)
746 pwallet->vchDefaultKey = CPubKey();
747 CWalletScanState wss;
748 bool fNoncriticalErrors = false;
749 DBErrors result = DB_LOAD_OK;
752 LOCK(pwallet->cs_wallet);
754 if (Read((std::string)"minversion", nMinVersion))
756 if (nMinVersion > CLIENT_VERSION)
758 pwallet->LoadMinVersion(nMinVersion);
762 Dbc* pcursor = GetCursor();
765 printf("Error getting wallet database cursor\n");
772 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
773 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
774 int ret = ReadAtCursor(pcursor, ssKey, ssValue);
775 if (ret == DB_NOTFOUND)
779 printf("Error reading next record from wallet database\n");
785 if (strType == "tx") {
789 vTxHash.push_back(hash);
794 catch (const boost::thread_interrupted&) {
801 if (fNoncriticalErrors && result == DB_LOAD_OK)
802 result = DB_NONCRITICAL_ERROR;
807 DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet)
809 // build list of wallet TXs
810 std::vector<uint256> vTxHash;
811 DBErrors err = FindWalletTx(pwallet, vTxHash);
812 if (err != DB_LOAD_OK)
815 // erase each wallet TX
816 for (uint256& hash : vTxHash) {
824 void ThreadFlushWalletDB(void* parg)
826 // Make this thread recognisable as the wallet flushing thread
827 RenameThread("novacoin-wallet");
829 const std::string& strFile = ((const std::string*)parg)[0];
830 static bool fOneThread;
834 if (!GetBoolArg("-flushwallet", true))
837 unsigned int nLastSeen = nWalletDBUpdated;
838 unsigned int nLastFlushed = nWalletDBUpdated;
839 int64_t nLastWalletUpdate = GetTime();
844 if (nLastSeen != nWalletDBUpdated)
846 nLastSeen = nWalletDBUpdated;
847 nLastWalletUpdate = GetTime();
850 if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2)
852 TRY_LOCK(bitdb.cs_db,lockDb);
855 // Don't do this if any databases are in use
857 auto mi = bitdb.mapFileUseCount.begin();
858 while (mi != bitdb.mapFileUseCount.end())
860 nRefCount += (*mi).second;
864 if (nRefCount == 0 && !fShutdown)
866 auto mi = bitdb.mapFileUseCount.find(strFile);
867 if (mi != bitdb.mapFileUseCount.end())
869 printf("Flushing wallet.dat\n");
870 nLastFlushed = nWalletDBUpdated;
871 int64_t nStart = GetTimeMillis();
873 // Flush wallet.dat so it's self contained
874 bitdb.CloseDb(strFile);
875 bitdb.CheckpointLSN(strFile);
877 bitdb.mapFileUseCount.erase(mi++);
878 printf("Flushed wallet.dat %" PRId64 "ms\n", GetTimeMillis() - nStart);
886 bool BackupWallet(const CWallet& wallet, const std::string& strDest)
888 if (!wallet.fFileBacked)
894 if (!bitdb.mapFileUseCount.count(wallet.strWalletFile) || bitdb.mapFileUseCount[wallet.strWalletFile] == 0)
896 // Flush log data to the dat file
897 bitdb.CloseDb(wallet.strWalletFile);
898 bitdb.CheckpointLSN(wallet.strWalletFile);
899 bitdb.mapFileUseCount.erase(wallet.strWalletFile);
902 boost::filesystem::path pathSrc = GetDataDir() / wallet.strWalletFile;
903 boost::filesystem::path pathDest(strDest);
904 if (boost::filesystem::is_directory(pathDest))
905 pathDest /= wallet.strWalletFile;
908 #if BOOST_VERSION >= 104000
909 boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists);
911 boost::filesystem::copy_file(pathSrc, pathDest);
913 printf("copied wallet.dat to %s\n", pathDest.string().c_str());
915 } catch(const boost::filesystem::filesystem_error &e) {
916 printf("error copying wallet.dat to %s - %s\n", pathDest.string().c_str(), e.what());
926 bool DumpWallet(CWallet* pwallet, const std::string& strDest)
928 if (!pwallet->fFileBacked)
931 std::map<CBitcoinAddress, int64_t> mapAddresses;
932 std::set<CKeyID> setKeyPool;
934 pwallet->GetAddresses(mapAddresses);
935 pwallet->GetAllReserveKeys(setKeyPool);
937 // sort time/key pairs
938 std::vector<std::pair<int64_t, CBitcoinAddress> > vAddresses;
939 for (auto it = mapAddresses.begin(); it != mapAddresses.end(); it++) {
940 vAddresses.push_back(std::make_pair(it->second, it->first));
942 mapAddresses.clear();
943 std::sort(vAddresses.begin(), vAddresses.end());
945 // open outputfile as a stream
947 file.open(strDest.c_str());
952 file << strprintf("# Wallet dump created by NovaCoin %s (%s)\n", CLIENT_BUILD.c_str(), CLIENT_DATE.c_str());
953 file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()).c_str());
954 file << strprintf("# * Best block at time of backup was %i (%s),\n", nBestHeight, hashBestChain.ToString().c_str());
955 file << strprintf("# mined on %s\n", EncodeDumpTime(pindexBest->nTime).c_str());
958 for (auto it = vAddresses.begin(); it != vAddresses.end(); it++) {
959 const CBitcoinAddress &addr = it->second;
960 std::string strTime = EncodeDumpTime(it->first);
961 std::string strAddr = addr.ToString();
964 // Pubkey pair address
965 CMalleableKeyView keyView;
966 CMalleablePubKey mPubKey(addr.GetData());
967 if (!pwallet->GetMalleableView(mPubKey, keyView))
970 pwallet->GetMalleableKey(keyView, mKey);
971 file << mKey.ToString();
972 if (pwallet->mapAddressBook.count(addr))
973 file << strprintf(" %s label=%s # view=%s addr=%s\n", strTime.c_str(), EncodeDumpString(pwallet->mapAddressBook[addr]).c_str(), keyView.ToString().c_str(), strAddr.c_str());
975 file << strprintf(" %s # view=%s addr=%s\n", strTime.c_str(), keyView.ToString().c_str(), strAddr.c_str());
978 // Pubkey hash address
980 addr.GetKeyID(keyid);
983 if (!pwallet->GetKey(keyid, key))
985 CSecret secret = key.GetSecret(IsCompressed);
986 file << CBitcoinSecret(secret, IsCompressed).ToString();
987 if (pwallet->mapAddressBook.count(addr))
988 file << strprintf(" %s label=%s # addr=%s\n", strTime.c_str(), EncodeDumpString(pwallet->mapAddressBook[addr]).c_str(), strAddr.c_str());
989 else if (setKeyPool.count(keyid))
990 file << strprintf(" %s reserve=1 # addr=%s\n", strTime.c_str(), strAddr.c_str());
992 file << strprintf(" %s change=1 # addr=%s\n", strTime.c_str(), strAddr.c_str());
997 file << "# End of dump\n";
1003 bool ImportWallet(CWallet *pwallet, const std::string& strLocation)
1006 if (!pwallet->fFileBacked)
1009 // open inputfile as stream
1011 file.open(strLocation.c_str());
1012 if (!file.is_open())
1016 int64_t nTimeBegin = pindexBest->nTime;
1018 // read through input file checking and importing keys into wallet.
1019 while (file.good()) {
1021 std::getline(file, line);
1022 if (line.empty() || line[0] == '#')
1023 continue; // Skip comments and empty lines
1025 std::vector<std::string> vstr;
1026 std::istringstream iss(line);
1027 copy(std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>(), back_inserter(vstr));
1028 if (vstr.size() < 2)
1031 int64_t nTime = DecodeDumpTime(vstr[1]);
1032 std::string strLabel;
1034 for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) {
1035 if (vstr[nStr].compare(0,1, "#") == 0)
1037 if (vstr[nStr] == "change=1")
1039 if (vstr[nStr] == "reserve=1")
1041 if (vstr[nStr].compare(0,6, "label=") == 0) {
1042 strLabel = DecodeDumpString(vstr[nStr].substr(6));
1047 CBitcoinAddress addr;
1048 CBitcoinSecret vchSecret;
1049 if (vchSecret.SetString(vstr[0])) {
1050 // Simple private key
1054 CSecret secret = vchSecret.GetSecret(fCompressed);
1055 key.SetSecret(secret, fCompressed);
1056 CKeyID keyid = key.GetPubKey().GetID();
1057 addr = CBitcoinAddress(keyid);
1059 if (pwallet->HaveKey(keyid)) {
1060 printf("Skipping import of %s (key already present)\n", addr.ToString().c_str());
1064 printf("Importing %s...\n", addr.ToString().c_str());
1065 if (!pwallet->AddKey(key)) {
1070 // A pair of private keys
1073 if (!mKey.SetString(vstr[0]))
1075 CMalleablePubKey mPubKey = mKey.GetMalleablePubKey();
1076 addr = CBitcoinAddress(mPubKey);
1078 if (pwallet->CheckOwnership(mPubKey)) {
1079 printf("Skipping import of %s (key already present)\n", addr.ToString().c_str());
1083 printf("Importing %s...\n", addr.ToString().c_str());
1084 if (!pwallet->AddKey(mKey)) {
1090 pwallet->mapKeyMetadata[addr].nCreateTime = nTime;
1092 pwallet->SetAddressBookName(addr, strLabel);
1094 nTimeBegin = std::min(nTimeBegin, nTime);
1098 // rescan block chain looking for coins from new keys
1099 CBlockIndex *pindex = pindexBest;
1100 while (pindex && pindex->pprev && pindex->nTime > nTimeBegin - 7200)
1101 pindex = pindex->pprev;
1103 printf("Rescanning last %i blocks\n", pindexBest->nHeight - pindex->nHeight + 1);
1104 pwallet->ScanForWalletTransactions(pindex);
1105 pwallet->ReacceptWalletTransactions();
1106 pwallet->MarkDirty();
1112 // Try to (very carefully!) recover wallet.dat if there is a problem.
1114 bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys)
1116 // Recovery procedure:
1117 // move wallet.dat to wallet.timestamp.bak
1118 // Call Salvage with fAggressive=true to
1119 // get as much data as possible.
1120 // Rewrite salvaged data to wallet.dat
1121 // Set -rescan so any missing transactions will be
1123 int64_t now = GetTime();
1124 std::string newFilename = strprintf("wallet.%" PRId64 ".bak", now);
1126 int result = dbenv.dbenv.dbrename(nullptr, filename.c_str(), nullptr,
1127 newFilename.c_str(), DB_AUTO_COMMIT);
1129 printf("Renamed %s to %s\n", filename.c_str(), newFilename.c_str());
1132 printf("Failed to rename %s to %s\n", filename.c_str(), newFilename.c_str());
1136 std::vector<CDBEnv::KeyValPair> salvagedData;
1137 bool allOK = dbenv.Salvage(newFilename, true, salvagedData);
1138 if (salvagedData.empty())
1140 printf("Salvage(aggressive) found no records in %s.\n", newFilename.c_str());
1143 printf("Salvage(aggressive) found %" PRIszu " records\n", salvagedData.size());
1145 bool fSuccess = allOK;
1146 Db* pdbCopy = new Db(&dbenv.dbenv, 0);
1147 int ret = pdbCopy->open(nullptr, // Txn pointer
1148 filename.c_str(), // Filename
1149 "main", // Logical db name
1150 DB_BTREE, // Database type
1155 printf("Cannot create database file %s\n", filename.c_str());
1158 CWallet dummyWallet;
1159 CWalletScanState wss;
1161 DbTxn* ptxn = dbenv.TxnBegin();
1162 for (CDBEnv::KeyValPair& row : salvagedData)
1166 CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION);
1167 CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);
1168 std::string strType, strErr;
1169 bool fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue,
1170 wss, strType, strErr);
1171 if (!IsKeyType(strType))
1175 printf("WARNING: CWalletDB::Recover skipping %s: %s\n", strType.c_str(), strErr.c_str());
1179 Dbt datKey(&row.first[0], row.first.size());
1180 Dbt datValue(&row.second[0], row.second.size());
1181 int ret2 = pdbCopy->put(ptxn, &datKey, &datValue, DB_NOOVERWRITE);
1192 bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename)
1194 return CWalletDB::Recover(dbenv, filename, false);
1197 CKeyMetadata::CKeyMetadata()
1202 CKeyMetadata::CKeyMetadata(int64_t nCreateTime_)
1204 nVersion = CKeyMetadata::CURRENT_VERSION;
1205 nCreateTime = nCreateTime_;
1208 void CKeyMetadata::SetNull()
1210 nVersion = CKeyMetadata::CURRENT_VERSION;