20 #include <boost/scoped_ptr.hpp>
21 #include <boost/thread.hpp>
25 static uint64_t nAccountingEntryNumber = 0;
27 static std::atomic<unsigned int> nWalletDBUpdateCounter;
34 std::string currentList;
36 currentList = accountName;
38 currentList = currentList +
"," + accountName;
39 nWalletDBUpdateCounter++;
40 Erase(std::string(
"accountlist"));
42 nWalletDBUpdateCounter++;
43 return Write(std::string(
"accountlist"), currentList);
47 return Read(std::string(
"accountlist"), accountList);
52 nWalletDBUpdateCounter++;
53 return Write(std::make_pair(std::string(
"name"), strAddress), strName);
60 nWalletDBUpdateCounter++;
61 return Erase(std::make_pair(std::string(
"name"), strAddress));
66 nWalletDBUpdateCounter++;
67 return Write(std::make_pair(std::string(
"purpose"), strAddress), strPurpose);
72 nWalletDBUpdateCounter++;
73 return Erase(std::make_pair(std::string(
"purpose"), strPurpose));
78 nWalletDBUpdateCounter++;
79 return Write(std::make_pair(std::string(
"tx"), hash), wtx);
84 nWalletDBUpdateCounter++;
85 return Erase(std::make_pair(std::string(
"tx"), hash));
90 nWalletDBUpdateCounter++;
92 if (!
Write(std::make_pair(std::string(
"keymeta"), vchPubKey),
97 std::vector<unsigned char> vchKey;
98 vchKey.reserve(vchPubKey.
size() + vchPrivKey.size());
99 vchKey.insert(vchKey.end(), vchPubKey.
begin(), vchPubKey.
end());
100 vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
102 return Write(std::make_pair(std::string(
"key"), vchPubKey), std::make_pair(vchPrivKey,
Hash(vchKey.begin(), vchKey.end())),
false);
106 const std::vector<unsigned char>& vchCryptedSecret,
109 const bool fEraseUnencryptedKey =
true;
110 nWalletDBUpdateCounter++;
112 if (!
Write(std::make_pair(std::string(
"keymeta"), vchPubKey),
116 if (!
Write(std::make_pair(std::string(
"ckey"), vchPubKey), vchCryptedSecret,
false))
118 if (fEraseUnencryptedKey) {
119 Erase(std::make_pair(std::string(
"key"), vchPubKey));
120 Erase(std::make_pair(std::string(
"wkey"), vchPubKey));
127 nWalletDBUpdateCounter++;
128 return Write(std::make_pair(std::string(
"mkey"), nID), kMasterKey,
true);
133 nWalletDBUpdateCounter++;
134 return Write(std::make_pair(std::string(
"cscript"), hash), *(
const CScriptBase*)(&redeemScript),
false);
139 nWalletDBUpdateCounter++;
140 return Write(std::make_pair(std::string(
"watchs"), *(
const CScriptBase*)(&dest)),
'1');
145 nWalletDBUpdateCounter++;
146 return Erase(std::make_pair(std::string(
"watchs"), *(
const CScriptBase*)(&dest)));
151 nWalletDBUpdateCounter++;
152 return Write(std::make_pair(std::string(
"multisig"), *(
const CScriptBase*)(&dest)),
'1');
157 nWalletDBUpdateCounter++;
158 return Erase(std::make_pair(std::string(
"multisig"), *(
const CScriptBase*)(&dest)));
163 nWalletDBUpdateCounter++;
164 return Write(std::string(
"reservebalance"), amount);
169 return Read(std::string(
"reservebalance"), amount);
174 nWalletDBUpdateCounter++;
176 return Write(std::string(
"bestblock_nomerkle"), locator);
181 if (
Read(std::string(
"bestblock"), locator) && !locator.
vHave.empty())
return true;
182 return Read(std::string(
"bestblock_nomerkle"), locator);
187 nWalletDBUpdateCounter++;
188 return Write(std::string(
"orderposnext"), nOrderPosNext);
194 nWalletDBUpdateCounter++;
195 return Write(std::string(
"stakeSplitThreshold"), nStakeSplitThreshold);
201 nWalletDBUpdateCounter++;
203 for (
unsigned int i = 0; i < vMultiSend.size(); i++) {
204 std::pair<std::string, int> pMultiSend;
205 pMultiSend = vMultiSend[i];
206 if (!
Write(std::make_pair(std::string(
"multisend"), i), pMultiSend,
true))
214 nWalletDBUpdateCounter++;
216 for (
unsigned int i = 0; i < vMultiSend.size(); i++) {
217 std::pair<std::string, int> pMultiSend;
218 pMultiSend = vMultiSend[i];
219 if (!
Erase(std::make_pair(std::string(
"multisend"), i)))
227 nWalletDBUpdateCounter++;
228 std::pair<bool, bool> enabledMS(fMultiSendStake, fMultiSendMasternode);
229 std::pair<std::pair<bool, bool>,
int> pSettings(enabledMS, nLastMultiSendHeight);
231 return Write(std::string(
"msettingsv2"), pSettings,
true);
236 nWalletDBUpdateCounter++;
238 for (
unsigned int i = 0; i < vDisabledAddresses.size(); i++) {
239 if (!
Write(std::make_pair(std::string(
"mdisabled"), i), vDisabledAddresses[i]))
247 nWalletDBUpdateCounter++;
249 for (
unsigned int i = 0; i < vDisabledAddresses.size(); i++) {
250 if (!
Erase(std::make_pair(std::string(
"mdisabled"), i)))
257 nWalletDBUpdateCounter++;
258 std::pair<bool, CAmount> pSettings;
259 pSettings.first = fEnable;
260 pSettings.second = nCombineThreshold;
261 return Write(std::string(
"autocombinesettings"), pSettings,
true);
266 nWalletDBUpdateCounter++;
267 return Write(std::string(
"defaultkey"), vchPubKey);
272 return Read(std::make_pair(std::string(
"pool"), nPool), keypool);
277 nWalletDBUpdateCounter++;
278 return Write(std::make_pair(std::string(
"pool"), nPool), keypool);
283 nWalletDBUpdateCounter++;
284 return Erase(std::make_pair(std::string(
"pool"), nPool));
289 return Write(std::string(
"minversion"), nVersion);
293 return Write(std::string(
"stakingstatus"), status);
298 if (!
Read(std::string(
"stakingstatus"), status)) {
306 return Write(std::string(
"scannedblockheight"), height);
310 return Read(std::string(
"scannedblockheight"), height);
315 return Write(std::string(
"2fa"), status);
320 if (!
Read(std::string(
"2fa"), status)) {
328 return Write(std::string(
"2fasecret"), secret);
333 if (!
Read(std::string(
"2fasecret"), secret))
340 return Write(std::string(
"2faperiod"), period);
345 if (!
Read(std::string(
"2faperiod"), period))
352 return Write(std::string(
"2falasttime"), lastTime);
357 if (!
Read(std::string(
"2falasttime"), lastTime))
365 return Read(std::make_pair(std::string(
"acc"), strAccount), account);
370 return Write(std::string(
"autoconsolidatetime"), settingTime);
375 uint32_t settingTime = 0;
376 if (!
Read(std::string(
"autoconsolidatetime"), settingTime)) {
385 return Write(std::make_pair(std::string(
"acc"), strAccount), account);
390 if (strAccount ==
"masteraccount") {
397 if (strAccount ==
"masteraccount") {
405 return Write(std::make_pair(std::string(
"acentry"), std::make_pair(acentry.
strAccount, nAccEntryNum)), acentry);
415 std::list<CAccountingEntry> entries;
420 nCreditDebit += entry.nCreditDebit;
427 bool fAllAccounts = (strAccount ==
"*");
431 throw std::runtime_error(
"CWalletDB::ListAccountCreditDebit() : cannot create DB cursor");
432 unsigned int fFlags = DB_SET_RANGE;
436 if (fFlags == DB_SET_RANGE)
437 ssKey << std::make_pair(std::string(
"acentry"), std::make_pair((fAllAccounts ? std::string(
"") : strAccount), uint64_t(0)));
439 int ret =
ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
441 if (ret == DB_NOTFOUND)
445 throw std::runtime_error(
"CWalletDB::ListAccountCreditDebit() : error scanning DB");
451 if (strType !=
"acentry")
455 if (!fAllAccounts && acentry.
strAccount != strAccount)
459 ssKey >> acentry.nEntryNo;
460 entries.push_back(acentry);
473 typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;
474 typedef std::multimap<int64_t, TxPair> TxItems;
477 for (std::map<uint256, CWalletTx>::iterator it = pwallet->
mapWallet.begin(); it != pwallet->
mapWallet.end(); ++it) {
481 std::list<CAccountingEntry> acentries;
484 txByTime.insert(std::make_pair(entry.nTime, TxPair((
CWalletTx*)0, &entry)));
489 std::vector<int64_t> nOrderPosOffsets;
490 for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it) {
491 CWalletTx*
const pwtx = (*it).second.first;
495 if (nOrderPos == -1) {
496 nOrderPos = nOrderPosNext++;
497 nOrderPosOffsets.push_back(nOrderPos);
505 int64_t nOrderPosOff = 0;
506 for (
const int64_t& nOffsetStart : nOrderPosOffsets) {
507 if (nOrderPos >= nOffsetStart)
510 nOrderPos += nOrderPosOff;
511 nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
556 if (strType ==
"name") {
557 std::string strAddress;
560 }
else if (strType ==
"purpose") {
561 std::string strAddress;
564 }
else if (strType ==
"tx") {
569 if (wtx.GetHash() != hash)
572 if (wtx.nOrderPos == -1)
576 }
else if (strType ==
"acentry") {
577 std::string strAccount;
581 if (nNumber > nAccountingEntryNumber)
582 nAccountingEntryNumber = nNumber;
587 if (acentry.nOrderPos == -1)
590 }
else if (strType ==
"watchs") {
601 }
else if (strType ==
"key" || strType ==
"wkey") {
604 if (!vchPubKey.IsValid()) {
605 strErr =
"Error reading wallet database: CPubKey corrupt";
612 if (strType ==
"key") {
631 bool fSkipCheck =
false;
635 std::vector<unsigned char> vchKey;
636 vchKey.reserve(vchPubKey.size() + pkey.size());
637 vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
638 vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
640 if (
Hash(vchKey.begin(), vchKey.end()) != hash) {
641 strErr =
"Error reading wallet database: CPubKey/CPrivKey corrupt";
648 if (!
key.
Load(pkey, vchPubKey, fSkipCheck)) {
649 strErr =
"Error reading wallet database: CPrivKey corrupt";
653 strErr =
"Error reading wallet database: LoadKey failed";
656 }
else if (strType ==
"mkey") {
660 ssValue >> kMasterKey;
662 strErr =
strprintf(
"Error reading wallet database: duplicate CMasterKey id %u", nID);
668 }
else if (strType ==
"ckey") {
669 std::vector<unsigned char> vchPubKey;
671 std::vector<unsigned char> vchPrivKey;
672 ssValue >> vchPrivKey;
676 strErr =
"Error reading wallet database: LoadCryptedKey failed";
680 }
else if (strType ==
"keymeta") {
693 }
else if (strType ==
"defaultkey") {
695 }
else if (strType ==
"pool") {
705 CKeyID keyid = keypool.vchPubKey.GetID();
708 }
else if (strType ==
"version") {
712 }
else if (strType ==
"cscript") {
718 strErr =
"Error reading wallet database: LoadCScript failed";
721 }
else if (strType ==
"orderposnext") {
723 }
else if (strType ==
"stakeSplitThreshold")
726 }
else if (strType ==
"multisend")
730 std::pair<std::string, int> pMultiSend;
731 ssValue >> pMultiSend;
735 }
else if (strType ==
"msettingsv2")
737 std::pair<std::pair<bool, bool>,
int> pSettings;
738 ssValue >> pSettings;
742 }
else if (strType ==
"mdisabled")
744 std::string strDisabledAddress;
745 ssValue >> strDisabledAddress;
747 }
else if (strType ==
"autocombinesettings") {
748 std::pair<bool, CAmount> pSettings;
749 ssValue >> pSettings;
752 }
else if (strType ==
"destdata") {
753 std::string strAddress, strKey, strValue;
758 strErr =
"Error reading wallet database: LoadDestData failed";
761 }
else if (strType ==
"hdchain") {
766 strErr =
"Error reading wallet database: SetHDChain failed";
770 else if (strType ==
"chdchain")
776 strErr =
"Error reading wallet database: SetHDCryptedChain failed";
780 else if (strType ==
"hdpubkey")
788 if(vchPubKey != hdPubKey.extPubKey.pubkey)
790 strErr =
"Error reading wallet database: CHDPubKey corrupt";
795 strErr =
"Error reading wallet database: LoadHDPubKey failed";
805 static bool IsKeyType(std::string strType)
807 return (strType ==
"key" || strType ==
"wkey" ||
808 strType ==
"mkey" || strType ==
"ckey");
815 bool fNoncriticalErrors =
false;
821 if (
Read((std::string)
"minversion", nMinVersion)) {
822 if (nMinVersion > CLIENT_VERSION)
830 LogPrintf(
"Error getting wallet database cursor\n");
839 if (ret == DB_NOTFOUND)
842 LogPrintf(
"Error reading next record from wallet database\n");
847 std::string strType, strErr;
848 if (!
ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr)) {
851 if (IsKeyType(strType))
855 fNoncriticalErrors =
true;
865 }
catch (
const boost::thread_interrupted&) {
871 if (fNoncriticalErrors && result ==
DB_LOAD_OK)
881 LogPrintf(
"Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\n",
910 bool fNoncriticalErrors =
false;
916 if (
Read((std::string)
"minversion", nMinVersion)) {
917 if (nMinVersion > CLIENT_VERSION)
925 LogPrintf(
"Error getting wallet database cursor\n");
934 if (ret == DB_NOTFOUND)
937 LogPrintf(
"Error reading next record from wallet database\n");
943 if (strType ==
"tx") {
950 vTxHash.push_back(hash);
955 }
catch (
const boost::thread_interrupted&) {
961 if (fNoncriticalErrors && result ==
DB_LOAD_OK)
970 std::vector<uint256> vTxHash;
976 for (
uint256& hash : vTxHash) {
989 static bool fOneThread;
998 int64_t nLastWalletUpdate =
GetTime();
1004 nLastWalletUpdate =
GetTime();
1014 nRefCount += (*mi).second;
1018 if (nRefCount == 0) {
1019 boost::this_thread::interruption_point();
1047 fs::path pathCustom;
1048 fs::path pathWithFile;
1051 }
else if(fEnableCustom) {
1052 pathWithFile =
GetArg(
"-backuppath",
"");
1053 if(!pathWithFile.empty()) {
1054 if(!pathWithFile.has_extension()) {
1055 pathCustom = pathWithFile;
1058 pathCustom = pathWithFile.parent_path();
1061 fs::create_directories(pathCustom);
1062 }
catch(
const fs::filesystem_error& e) {
1079 fs::path pathDest(strDest);
1081 if (is_directory(pathDest)) {
1082 if(!exists(pathDest)) create_directory(pathDest);
1087 if(defaultPath && !pathCustom.empty()) {
1088 int nThreshold =
GetArg(
"-custombackupthreshold", DEFAULT_CUSTOMBACKUPTHRESHOLD);
1089 if (nThreshold > 0) {
1091 typedef std::multimap<std::time_t, fs::path> folder_set_t;
1092 folder_set_t folderSet;
1093 fs::directory_iterator end_iter;
1095 pathCustom.make_preferred();
1098 fs::path currentFile;
1099 for (fs::directory_iterator dir_iter(pathCustom); dir_iter != end_iter; ++dir_iter) {
1101 if (fs::is_regular_file(dir_iter->status())) {
1102 currentFile = dir_iter->path().filename();
1104 if (dir_iter->path().stem().string() == wallet.
strWalletFile) {
1105 folderSet.insert(folder_set_t::value_type(fs::last_write_time(dir_iter->path()), *dir_iter));
1111 for (
auto entry : folderSet) {
1113 if(entry.second == pathWithFile) {
1114 pathWithFile +=
"(1)";
1118 if (counter >= nThreshold) {
1120 for(
auto entry : folderSet) {
1121 if(oldestBackup == 0 || entry.first < oldestBackup) {
1122 oldestBackup = entry.first;
1127 auto entry = folderSet.find(oldestBackup);
1128 if (entry != folderSet.end()) {
1129 fs::remove(entry->second);
1130 LogPrintf(
"Old backup deleted: %s\n", (*entry).second);
1132 }
catch (fs::filesystem_error&
error) {
1133 std::string strMessage =
strprintf(
"Failed to delete backup %s\n",
error.what());
1152 std::string strMessage;
1154 if (fs::equivalent(pathSrc, pathDest)) {
1155 LogPrintf(
"cannot backup to wallet source file %s\n", pathDest.string());
1158 #if BOOST_VERSION >= 105800
1159 fs::copy_file(pathSrc, pathDest, fs::copy_option::overwrite_if_exists);
1161 std::ifstream src(pathSrc, std::ios::binary | std::ios::in);
1162 std::ofstream dst(pathDest, std::ios::binary | std::ios::out | std::ios::trunc);
1168 strMessage =
strprintf(
"copied wallet.dat to %s\n", pathDest.string());
1169 LogPrintf(
"%s : %s\n", __func__, strMessage);
1171 }
catch (
const fs::filesystem_error& e) {
1173 strMessage =
strprintf(
"%s\n", e.what());
1174 LogPrintf(
"%s : %s\n", __func__, strMessage);
1199 std::string newFilename =
strprintf(
"wallet.%d.bak", now);
1201 int result = dbenv.
dbenv->dbrename(NULL, filename.c_str(), NULL,
1202 newFilename.c_str(), DB_AUTO_COMMIT);
1204 LogPrintf(
"Renamed %s to %s\n", filename, newFilename);
1206 LogPrintf(
"Failed to rename %s to %s\n", filename, newFilename);
1210 std::vector<CDBEnv::KeyValPair> salvagedData;
1211 bool allOK = dbenv.
Salvage(newFilename,
true, salvagedData);
1212 if (salvagedData.empty()) {
1213 LogPrintf(
"Salvage(aggressive) found no records in %s.\n", newFilename);
1216 LogPrintf(
"Salvage(aggressive) found %u records\n", salvagedData.size());
1218 bool fSuccess = allOK;
1219 boost::scoped_ptr<Db> pdbCopy(
new Db(dbenv.
dbenv, 0));
1220 int ret = pdbCopy->open(NULL,
1227 LogPrintf(
"Cannot create database file %s\n", filename);
1238 std::string strType, strErr;
1239 bool fReadOK =
ReadKeyValue(&dummyWallet, ssKey, ssValue,
1240 wss, strType, strErr);
1241 if (!IsKeyType(strType))
1244 LogPrintf(
"WARNING: CWalletDB::Recover skipping %s: %s\n", strType, strErr);
1248 Dbt datKey(&row.first[0], row.first.size());
1249 Dbt datValue(&row.second[0], row.second.size());
1250 int ret2 = pdbCopy->put(ptxn, &datKey, &datValue, DB_NOOVERWRITE);
1267 nWalletDBUpdateCounter++;
1268 return Write(std::make_pair(std::string(
"destdata"), std::make_pair(address,
key)), value);
1273 return Write(std::make_pair(std::string(
"txpriv"), outpointKey), k);
1278 return Read(std::make_pair(std::string(
"txpriv"), outpointKey), k);
1283 return Write(std::make_pair(std::string(
"outpointkeyimage"), outpointKey), k);
1287 return Read(std::make_pair(std::string(
"outpointkeyimage"), outpointKey), k);
1293 nWalletDBUpdateCounter++;
1294 return Erase(std::make_pair(std::string(
"destdata"), std::make_pair(address,
key)));
1299 nWalletDBUpdateCounter++;
1300 return Write(std::string(
"hdchain"), chain);
1305 nWalletDBUpdateCounter++;
1307 if (!
Write(std::string(
"chdchain"), chain))
1310 Erase(std::string(
"hdchain"));
1318 nWalletDBUpdateCounter++;
1323 return Write(std::make_pair(std::string(
"hdpubkey"), hdPubKey.
extPubKey.
pubkey), hdPubKey,
false);
1328 nWalletDBUpdateCounter++;
1333 return nWalletDBUpdateCounter;