19 #include <boost/filesystem.hpp> 20 #include <boost/foreach.hpp> 21 #include <boost/scoped_ptr.hpp> 22 #include <boost/thread.hpp> 35 return Write(make_pair(
string(
"name"), strAddress), strName);
43 return Erase(make_pair(
string(
"name"), strAddress));
49 return Write(make_pair(
string(
"purpose"), strAddress), strPurpose);
55 return Erase(make_pair(
string(
"purpose"), strPurpose));
61 return Write(std::make_pair(std::string(
"tx"), hash), wtx);
67 return Erase(std::make_pair(std::string(
"tx"), hash));
74 if (!Write(std::make_pair(std::string(
"keymeta"), vchPubKey),
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);
88 const std::vector<unsigned char>& vchCryptedSecret,
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));
111 return Write(std::make_pair(std::string(
"mkey"), nID), kMasterKey,
true);
117 return Write(std::make_pair(std::string(
"cscript"), hash), *(
const CScriptBase*)(&redeemScript),
false);
123 return Write(std::make_pair(std::string(
"watchs"), *(
const CScriptBase*)(&dest)),
'1');
129 return Erase(std::make_pair(std::string(
"watchs"), *(
const CScriptBase*)(&dest)));
136 return Write(std::string(
"bestblock_nomerkle"), locator);
141 if (Read(std::string(
"bestblock"), locator) && !locator.
vHave.empty())
return true;
142 return Read(std::string(
"bestblock_nomerkle"), locator);
148 return Write(std::string(
"orderposnext"), nOrderPosNext);
154 return Write(std::string(
"defaultkey"), vchPubKey);
159 return Read(std::make_pair(std::string(
"pool"), nPool),
keypool);
165 return Write(std::make_pair(std::string(
"pool"), nPool),
keypool);
171 return Erase(std::make_pair(std::string(
"pool"), nPool));
176 return Write(std::string(
"minversion"), nVersion);
182 return Read(make_pair(
string(
"acc"), strAccount), account);
187 return Write(make_pair(
string(
"acc"), strAccount), account);
192 return Write(std::make_pair(std::string(
"acentry"), std::make_pair(acentry.
strAccount, nAccEntryNum)), acentry);
202 list<CAccountingEntry> entries;
203 ListAccountCreditDebit(strAccount, entries);
214 bool fAllAccounts = (strAccount ==
"*");
216 Dbc* pcursor = GetCursor();
218 throw runtime_error(
"CWalletDB::ListAccountCreditDebit(): cannot create DB cursor");
219 unsigned int fFlags = DB_SET_RANGE;
224 if (fFlags == DB_SET_RANGE)
225 ssKey << std::make_pair(std::string(
"acentry"), std::make_pair((fAllAccounts ?
string(
"") : strAccount), uint64_t(0)));
227 int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
229 if (ret == DB_NOTFOUND)
234 throw runtime_error(
"CWalletDB::ListAccountCreditDebit(): error scanning DB");
240 if (strType !=
"acentry")
244 if (!fAllAccounts && acentry.
strAccount != strAccount)
248 ssKey >> acentry.nEntryNo;
249 entries.push_back(acentry);
262 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
263 typedef multimap<int64_t, TxPair > TxItems;
266 for (map<uint256, CWalletTx>::iterator it = pwallet->
mapWallet.begin(); it != pwallet->
mapWallet.end(); ++it)
271 list<CAccountingEntry> acentries;
272 ListAccountCreditDebit(
"", acentries);
275 txByTime.insert(make_pair(entry.
nTime, TxPair((
CWalletTx*)0, &entry)));
280 std::vector<int64_t> nOrderPosOffsets;
281 for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
283 CWalletTx *
const pwtx = (*it).second.first;
289 nOrderPos = nOrderPosNext++;
290 nOrderPosOffsets.push_back(nOrderPos);
294 if (!WriteTx(pwtx->
GetHash(), *pwtx))
298 if (!WriteAccountingEntry(pacentry->
nEntryNo, *pacentry))
303 int64_t nOrderPosOff = 0;
304 BOOST_FOREACH(
const int64_t& nOffsetStart, nOrderPosOffsets)
306 if (nOrderPos >= nOffsetStart)
309 nOrderPos += nOrderPosOff;
310 nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
318 if (!WriteTx(pwtx->
GetHash(), *pwtx))
322 if (!WriteAccountingEntry(pacentry->
nEntryNo, *pacentry))
326 WriteOrderPosNext(nOrderPosNext);
342 nKeys = nCKeys = nKeyMeta = 0;
343 fIsEncrypted =
false;
344 fAnyUnordered =
false;
358 if (strType ==
"name")
364 else if (strType ==
"purpose")
370 else if (strType ==
"tx")
381 if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
383 if (!ssValue.
empty())
387 ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
388 strErr =
strprintf(
"LoadWallet() upgrading tx ver=%d %d '%s' %s",
389 wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount, hash.ToString());
390 wtx.fTimeReceivedIsTxTime = fTmp;
394 strErr =
strprintf(
"LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
395 wtx.fTimeReceivedIsTxTime = 0;
400 if (wtx.nOrderPos == -1)
405 else if (strType ==
"acentry")
418 if (acentry.nOrderPos == -1)
422 else if (strType ==
"watchs")
435 else if (strType ==
"key" || strType ==
"wkey")
439 if (!vchPubKey.IsValid())
441 strErr =
"Error reading wallet database: CPubKey corrupt";
448 if (strType ==
"key")
469 bool fSkipCheck =
false;
474 std::vector<unsigned char> vchKey;
475 vchKey.reserve(vchPubKey.size() + pkey.size());
476 vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
477 vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
479 if (
Hash(vchKey.begin(), vchKey.end()) != hash)
481 strErr =
"Error reading wallet database: CPubKey/CPrivKey corrupt";
488 if (!
key.Load(pkey, vchPubKey, fSkipCheck))
490 strErr =
"Error reading wallet database: CPrivKey corrupt";
495 strErr =
"Error reading wallet database: LoadKey failed";
499 else if (strType ==
"mkey")
504 ssValue >> kMasterKey;
507 strErr =
strprintf(
"Error reading wallet database: duplicate CMasterKey id %u", nID);
514 else if (strType ==
"ckey")
518 if (!vchPubKey.IsValid())
520 strErr =
"Error reading wallet database: CPubKey corrupt";
523 vector<unsigned char> vchPrivKey;
524 ssValue >> vchPrivKey;
529 strErr =
"Error reading wallet database: LoadCryptedKey failed";
534 else if (strType ==
"keymeta")
549 else if (strType ==
"defaultkey")
553 else if (strType ==
"pool")
561 else if (strType ==
"version")
567 else if (strType ==
"cscript")
575 strErr =
"Error reading wallet database: LoadCScript failed";
579 else if (strType ==
"orderposnext")
583 else if (strType ==
"destdata")
585 std::string strAddress, strKey, strValue;
591 strErr =
"Error reading wallet database: LoadDestData failed";
595 else if (strType ==
"hdchain")
601 strErr =
"Error reading wallet database: SetHDChain failed";
605 else if (strType ==
"chdchain")
611 strErr =
"Error reading wallet database: SetHDCryptedChain failed";
615 else if (strType ==
"hdpubkey")
623 if(vchPubKey != hdPubKey.extPubKey.pubkey)
625 strErr =
"Error reading wallet database: CHDPubKey corrupt";
630 strErr =
"Error reading wallet database: LoadHDPubKey failed";
643 return (strType==
"key" || strType ==
"wkey" ||
644 strType ==
"mkey" || strType ==
"ckey" ||
645 strType ==
"hdchain" || strType ==
"chdchain");
652 bool fNoncriticalErrors =
false;
658 if (Read((
string)
"minversion", nMinVersion))
666 Dbc* pcursor = GetCursor();
669 LogPrintf(
"Error getting wallet database cursor\n");
678 int ret = ReadAtCursor(pcursor, ssKey, ssValue);
679 if (ret == DB_NOTFOUND)
683 LogPrintf(
"Error reading next record from wallet database\n");
688 string strType, strErr;
689 if (!
ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
698 fNoncriticalErrors =
true;
713 catch (
const boost::thread_interrupted&) {
730 LogPrintf(
"Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\n",
748 result = ReorderTransactions(pwallet);
762 bool fNoncriticalErrors =
false;
768 if (Read((
string)
"minversion", nMinVersion))
776 Dbc* pcursor = GetCursor();
779 LogPrintf(
"Error getting wallet database cursor\n");
788 int ret = ReadAtCursor(pcursor, ssKey, ssValue);
789 if (ret == DB_NOTFOUND)
793 LogPrintf(
"Error reading next record from wallet database\n");
799 if (strType ==
"tx") {
806 vTxHash.push_back(hash);
812 catch (
const boost::thread_interrupted&) {
828 vector<uint256> vTxHash;
829 DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx);
834 BOOST_FOREACH (
uint256& hash, vTxHash) {
847 static bool fOneThread;
856 int64_t nLastWalletUpdate =
GetTime();
877 nRefCount += (*mi).second;
883 boost::this_thread::interruption_point();
887 LogPrint(
"db",
"Flushing wallet.dat\n");
921 boost::filesystem::path pathDest(strDest);
922 if (boost::filesystem::is_directory(pathDest))
923 pathDest /=
wallet.strWalletFile;
926 #if BOOST_VERSION >= 104000 927 boost::filesystem::copy_file(pathSrc, pathDest, boost::filesystem::copy_option::overwrite_if_exists);
929 boost::filesystem::copy_file(pathSrc, pathDest);
931 LogPrintf(
"copied wallet.dat to %s\n", pathDest.string());
933 }
catch (
const boost::filesystem::filesystem_error& e) {
934 LogPrintf(
"error copying wallet.dat to %s - %s\n", pathDest.string(), e.what());
948 namespace fs = boost::filesystem;
950 strBackupWarning = strBackupError =
"";
956 if (!fs::exists(backupsDir))
959 LogPrintf(
"Creating backup folder %s\n", backupsDir.string());
960 if(!fs::create_directories(backupsDir)) {
962 strBackupError =
strprintf(
_(
"Wasn't able to create wallet backup folder %s!"), backupsDir.string());
975 strWalletFile =
wallet->strWalletFile;
976 fs::path backupFile = backupsDir / (strWalletFile +
dateTimeStr);
978 strBackupWarning =
strprintf(
_(
"Failed to create backup %s!"), backupFile.string());
984 wallet->nKeysLeftSinceAutoBackup =
wallet->KeypoolCountExternalKeys();
985 LogPrintf(
"nKeysLeftSinceAutoBackup: %d\n",
wallet->nKeysLeftSinceAutoBackup);
986 if(
wallet->IsLocked(
true)) {
987 strBackupWarning =
_(
"Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool.");
994 fs::path sourceFile =
GetDataDir() / strWalletFile;
995 fs::path backupFile = backupsDir / (strWalletFile +
dateTimeStr);
996 sourceFile.make_preferred();
997 backupFile.make_preferred();
998 if (fs::exists(backupFile))
1000 strBackupWarning =
_(
"Failed to create backup, file already exists! This could happen if you restarted wallet in less than 60 seconds. You can continue if you are ok with this.");
1004 if(fs::exists(sourceFile)) {
1006 fs::copy_file(sourceFile, backupFile);
1007 LogPrintf(
"Creating backup of %s -> %s\n", sourceFile.string(), backupFile.string());
1008 }
catch(fs::filesystem_error &
error) {
1009 strBackupWarning =
strprintf(
_(
"Failed to create backup, error: %s"),
error.what());
1018 typedef std::multimap<std::time_t, fs::path> folder_set_t;
1019 folder_set_t folder_set;
1020 fs::directory_iterator end_iter;
1021 backupsDir.make_preferred();
1023 fs::path currentFile;
1024 for (fs::directory_iterator dir_iter(backupsDir); dir_iter != end_iter; ++dir_iter)
1027 if ( fs::is_regular_file(dir_iter->status()))
1029 currentFile = dir_iter->path().filename();
1031 if(dir_iter->path().stem().string() == strWalletFile)
1033 folder_set.insert(folder_set_t::value_type(fs::last_write_time(dir_iter->path()), *dir_iter));
1040 BOOST_REVERSE_FOREACH(
PAIRTYPE(
const std::time_t, fs::path)
file, folder_set)
1047 fs::remove(
file.second);
1049 }
catch(fs::filesystem_error &
error) {
1050 strBackupWarning =
strprintf(
_(
"Failed to delete backup, error: %s"),
error.what());
1059 LogPrintf(
"Automatic wallet backups are disabled!\n");
1076 std::string newFilename =
strprintf(
"wallet.%d.bak", now);
1078 int result = dbenv.
dbenv->dbrename(NULL, filename.c_str(), NULL,
1079 newFilename.c_str(), DB_AUTO_COMMIT);
1081 LogPrintf(
"Renamed %s to %s\n", filename, newFilename);
1084 LogPrintf(
"Failed to rename %s to %s\n", filename, newFilename);
1088 std::vector<CDBEnv::KeyValPair> salvagedData;
1089 bool fSuccess = dbenv.
Salvage(newFilename,
true, salvagedData);
1090 if (salvagedData.empty())
1092 LogPrintf(
"Salvage(aggressive) found no records in %s.\n", newFilename);
1095 LogPrintf(
"Salvage(aggressive) found %u records\n", salvagedData.size());
1097 boost::scoped_ptr<Db> pdbCopy(
new Db(dbenv.
dbenv, 0));
1098 int ret = pdbCopy->open(NULL,
1106 LogPrintf(
"Cannot create database file %s\n", filename);
1119 string strType, strErr;
1125 wss, strType, strErr);
1127 if (!
IsKeyType(strType) && strType !=
"hdpubkey")
1131 LogPrintf(
"WARNING: CWalletDB::Recover skipping %s: %s\n", strType, strErr);
1135 Dbt datKey(&row.first[0], row.first.size());
1136 Dbt datValue(&row.second[0], row.second.size());
1137 int ret2 = pdbCopy->put(ptxn, &datKey, &datValue, DB_NOOVERWRITE);
1155 return Write(std::make_pair(std::string(
"destdata"), std::make_pair(address,
key)), value);
1161 return Erase(std::make_pair(std::string(
"destdata"), std::make_pair(address,
key)));
1167 return Write(std::string(
"hdchain"), chain);
1174 if (!Write(std::string(
"chdchain"), chain))
1177 Erase(std::string(
"hdchain"));
1186 if (!Write(std::make_pair(std::string(
"keymeta"), hdPubKey.
extPubKey.
pubkey), keyMeta,
false))
1189 return Write(std::make_pair(std::string(
"hdpubkey"), hdPubKey.
extPubKey.
pubkey), hdPubKey,
false);
const boost::filesystem::path & GetDataDir(bool fNetSpecific)
unsigned int nWalletDBUpdated
bool ErasePurpose(const std::string &strAddress)
bool WriteCScript(const uint160 &hash, const CScript &redeemScript)
bool WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry &acentry)
void MilliSleep(int64_t n)
#define TRY_LOCK(cs, name)
unsigned int size() const
Simple read-only vector-like interface to the pubkey data.
bool WriteDestData(const std::string &address, const std::string &key, const std::string &value)
Write destination data key,value tuple to database.
CCriticalSection cs_wallet
bool SoftSetBoolArg(const std::string &strArg, bool fValue)
std::string DateTimeStrFormat(const char *pszFormat, int64_t nTime)
bool LoadMinVersion(int nVersion)
bool AddToWallet(const CWalletTx &wtxIn, bool fFromLoadWallet, CWalletDB *pwalletdb)
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector< unsigned char > &vchCryptedSecret)
Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) ...
bool WriteHDPubKey(const CHDPubKey &hdPubKey, const CKeyMetadata &keyMeta)
std::pair< std::vector< unsigned char >, std::vector< unsigned char > > KeyValPair
DBErrors ZapWalletTx(CWallet *pwallet, std::vector< CWalletTx > &vWtx)
std::pair< CWalletTx *, CAccountingEntry * > TxPair
unsigned int nMasterKeyMaxID
bool BackupWallet(const CWallet &wallet, const string &strDest)
bool WriteCryptedKey(const CPubKey &vchPubKey, const std::vector< unsigned char > &vchCryptedSecret, const CKeyMetadata &keyMeta)
void RenameThread(const char *name)
bool EraseTx(uint256 hash)
bool WriteOrderPosNext(int64_t nOrderPosNext)
bool LoadCScript(const CScript &redeemScript)
std::map< uint256, CWalletTx > mapWallet
bool ReadBestBlock(CBlockLocator &locator)
unsigned int nTimeReceived
bool WriteHDChain(const CHDChain &chain)
write the hdchain model (external chain child index counter)
DBErrors FindWalletTx(CWallet *pwallet, std::vector< uint256 > &vTxHash, std::vector< CWalletTx > &vWtx)
std::vector< unsigned char, secure_allocator< unsigned char > > CPrivKey
std::map< std::string, int > mapFileUseCount
DBErrors LoadWallet(CWallet *pwallet)
bool GetBoolArg(const std::string &strArg, bool fDefault)
bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata)
Load metadata (used by LoadWallet)
void ListAccountCreditDebit(const std::string &strAccount, std::list< CAccountingEntry > &acentries)
const unsigned char * begin() const
uint64_t nEntryNo
position in ordered transaction list
bool ReadAccount(const std::string &strAccount, CAccount &account)
std::list< CAccountingEntry > laccentries
bool WritePool(int64_t nPool, const CKeyPool &keypool)
bool WriteCryptedHDChain(const CHDChain &chain)
bool SetHDChain(const CHDChain &chain, bool memonly)
static int LogPrint(const char *category, const char *format)
bool WriteBestBlock(const CBlockLocator &locator)
static bool Recover(CDBEnv &dbenv, const std::string &filename, bool fOnlyKeys)
bool WriteTx(uint256 hash, const CWalletTx &wtx)
bool WriteMasterKey(unsigned int nID, const CMasterKey &kMasterKey)
DbTxn * TxnBegin(int flags=DB_TXN_WRITE_NOSYNC)
static bool error(const char *format)
bool WriteName(const std::string &strAddress, const std::string &strName)
bool WriteKey(const CPubKey &vchPubKey, const CPrivKey &vchPrivKey, const CKeyMetadata &keyMeta)
bool EraseWatchOnly(const CScript &script)
uint256 Hash(const T1 pbegin, const T1 pend)
bool SetCryptedHDChain(const CHDChain &chain, bool memonly)
bool LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
Adds a destination data tuple to the store, without saving it to disk.
bool ErasePool(int64_t nPool)
bool WriteMinVersion(int nVersion)
const unsigned char * end() const
size_t KeypoolCountExternalKeys()
void ThreadFlushWalletDB(const string &strFile)
CTxDestination Get() const
const boost::filesystem::path & GetBackupsDir()
bool WriteDefaultKey(const CPubKey &vchPubKey)
bool WriteAccountingEntry_Backend(const CAccountingEntry &acentry)
void CheckpointLSN(const std::string &strFile)
DBErrors ReorderTransactions(CWallet *pwallet)
static bool IsKeyType(string strType)
static uint64_t nAccountingEntryNumber
bool EraseName(const std::string &strAddress)
const uint256 & GetHash() const
CAmount GetAccountCreditDebit(const std::string &strAccount)
static const bool DEFAULT_FLUSHWALLET
bool Salvage(const std::string &strFile, bool fAggressive, std::vector< KeyValPair > &vResult)
MasterKeyMap mapMasterKeys
bool LoadKey(const CKey &key, const CPubKey &pubkey)
Adds a key to the store, without saving it to disk (used by LoadWallet)
bool ReadPool(int64_t nPool, CKeyPool &keypool)
bool WriteAccount(const std::string &strAccount, const CAccount &account)
bool ReadKeyValue(CWallet *pwallet, CDataStream &ssKey, CDataStream &ssValue, CWalletScanState &wss, string &strType, string &strErr)
std::map< CTxDestination, CAddressBookData > mapAddressBook
bool CheckTransaction(const CTransaction &tx, CValidationState &state)
bool WriteWatchOnly(const CScript &script)
bool LoadWatchOnly(const CScript &dest)
Adds a watch-only address to the store, without saving it to disk (used by LoadWallet) ...
void CloseDb(const std::string &strFile)
bool EraseDestData(const std::string &address, const std::string &key)
Erase destination data tuple from wallet database.
bool LoadHDPubKey(const CHDPubKey &hdPubKey)
loads a HDPubKey into the wallets memory
int64_t GetTime()
For unit testing.
static const int CLIENT_VERSION
bool WritePurpose(const std::string &strAddress, const std::string &purpose)
int64_t nKeysLeftSinceAutoBackup
bool AutoBackupWallet(CWallet *wallet, std::string strWalletFile, std::string &strBackupWarning, std::string &strBackupError)
void LoadKeyPool(int nIndex, const CKeyPool &keypool)
std::string _(const char *psz)
vector< uint256 > vWalletUpgrade
std::vector< uint256 > vHave
QString dateTimeStr(const QDateTime &date)