1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2015 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.
5
6 #include "wallet/walletdb.h"
7
8 #include "base58.h"
9 #include "consensus/validation.h"
10 #include "main.h" // For CheckTransaction
11 #include "protocol.h"
12 #include "serialize.h"
13 #include "sync.h"
14 #include "util.h"
15 #include "utiltime.h"
16 #include "wallet/wallet.h"
17
18 #include <boost/version.hpp>
19 #include <boost/filesystem.hpp>
20 #include <boost/foreach.hpp>
21 #include <boost/scoped_ptr.hpp>
22 #include <boost/thread.hpp>
23
24 using namespace std;
25
26 static uint64_t nAccountingEntryNumber = 0;
27
28 //
29 // CWalletDB
30 //
31
WriteName(const string & strAddress,const string & strName)32 bool CWalletDB::WriteName(const string& strAddress, const string& strName)
33 {
34 nWalletDBUpdated++;
35 return Write(make_pair(string("name"), strAddress), strName);
36 }
37
EraseName(const string & strAddress)38 bool CWalletDB::EraseName(const string& strAddress)
39 {
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.
42 nWalletDBUpdated++;
43 return Erase(make_pair(string("name"), strAddress));
44 }
45
WritePurpose(const string & strAddress,const string & strPurpose)46 bool CWalletDB::WritePurpose(const string& strAddress, const string& strPurpose)
47 {
48 nWalletDBUpdated++;
49 return Write(make_pair(string("purpose"), strAddress), strPurpose);
50 }
51
ErasePurpose(const string & strPurpose)52 bool CWalletDB::ErasePurpose(const string& strPurpose)
53 {
54 nWalletDBUpdated++;
55 return Erase(make_pair(string("purpose"), strPurpose));
56 }
57
WriteTx(const CWalletTx & wtx)58 bool CWalletDB::WriteTx(const CWalletTx& wtx)
59 {
60 nWalletDBUpdated++;
61 return Write(std::make_pair(std::string("tx"), wtx.GetHash()), wtx);
62 }
63
EraseTx(uint256 hash)64 bool CWalletDB::EraseTx(uint256 hash)
65 {
66 nWalletDBUpdated++;
67 return Erase(std::make_pair(std::string("tx"), hash));
68 }
69
WriteKey(const CPubKey & vchPubKey,const CPrivKey & vchPrivKey,const CKeyMetadata & keyMeta)70 bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
71 {
72 nWalletDBUpdated++;
73
74 if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
75 keyMeta, false))
76 return false;
77
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());
83
84 return Write(std::make_pair(std::string("key"), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false);
85 }
86
WriteCryptedKey(const CPubKey & vchPubKey,const std::vector<unsigned char> & vchCryptedSecret,const CKeyMetadata & keyMeta)87 bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
88 const std::vector<unsigned char>& vchCryptedSecret,
89 const CKeyMetadata &keyMeta)
90 {
91 const bool fEraseUnencryptedKey = true;
92 nWalletDBUpdated++;
93
94 if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
95 keyMeta))
96 return false;
97
98 if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
99 return false;
100 if (fEraseUnencryptedKey)
101 {
102 Erase(std::make_pair(std::string("key"), vchPubKey));
103 Erase(std::make_pair(std::string("wkey"), vchPubKey));
104 }
105 return true;
106 }
107
WriteMasterKey(unsigned int nID,const CMasterKey & kMasterKey)108 bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
109 {
110 nWalletDBUpdated++;
111 return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
112 }
113
WriteCScript(const uint160 & hash,const CScript & redeemScript)114 bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
115 {
116 nWalletDBUpdated++;
117 return Write(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&redeemScript), false);
118 }
119
WriteWatchOnly(const CScript & dest)120 bool CWalletDB::WriteWatchOnly(const CScript &dest)
121 {
122 nWalletDBUpdated++;
123 return Write(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1');
124 }
125
EraseWatchOnly(const CScript & dest)126 bool CWalletDB::EraseWatchOnly(const CScript &dest)
127 {
128 nWalletDBUpdated++;
129 return Erase(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)));
130 }
131
WriteBestBlock(const CBlockLocator & locator)132 bool CWalletDB::WriteBestBlock(const CBlockLocator& locator)
133 {
134 nWalletDBUpdated++;
135 Write(std::string("bestblock"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
136 return Write(std::string("bestblock_nomerkle"), locator);
137 }
138
ReadBestBlock(CBlockLocator & locator)139 bool CWalletDB::ReadBestBlock(CBlockLocator& locator)
140 {
141 if (Read(std::string("bestblock"), locator) && !locator.vHave.empty()) return true;
142 return Read(std::string("bestblock_nomerkle"), locator);
143 }
144
WriteOrderPosNext(int64_t nOrderPosNext)145 bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
146 {
147 nWalletDBUpdated++;
148 return Write(std::string("orderposnext"), nOrderPosNext);
149 }
150
WriteDefaultKey(const CPubKey & vchPubKey)151 bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)
152 {
153 nWalletDBUpdated++;
154 return Write(std::string("defaultkey"), vchPubKey);
155 }
156
ReadPool(int64_t nPool,CKeyPool & keypool)157 bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
158 {
159 return Read(std::make_pair(std::string("pool"), nPool), keypool);
160 }
161
WritePool(int64_t nPool,const CKeyPool & keypool)162 bool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool)
163 {
164 nWalletDBUpdated++;
165 return Write(std::make_pair(std::string("pool"), nPool), keypool);
166 }
167
ErasePool(int64_t nPool)168 bool CWalletDB::ErasePool(int64_t nPool)
169 {
170 nWalletDBUpdated++;
171 return Erase(std::make_pair(std::string("pool"), nPool));
172 }
173
WriteMinVersion(int nVersion)174 bool CWalletDB::WriteMinVersion(int nVersion)
175 {
176 return Write(std::string("minversion"), nVersion);
177 }
178
ReadAccount(const string & strAccount,CAccount & account)179 bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account)
180 {
181 account.SetNull();
182 return Read(make_pair(string("acc"), strAccount), account);
183 }
184
WriteAccount(const string & strAccount,const CAccount & account)185 bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
186 {
187 return Write(make_pair(string("acc"), strAccount), account);
188 }
189
WriteAccountingEntry(const uint64_t nAccEntryNum,const CAccountingEntry & acentry)190 bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry)
191 {
192 return Write(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry);
193 }
194
WriteAccountingEntry_Backend(const CAccountingEntry & acentry)195 bool CWalletDB::WriteAccountingEntry_Backend(const CAccountingEntry& acentry)
196 {
197 return WriteAccountingEntry(++nAccountingEntryNumber, acentry);
198 }
199
GetAccountCreditDebit(const string & strAccount)200 CAmount CWalletDB::GetAccountCreditDebit(const string& strAccount)
201 {
202 list<CAccountingEntry> entries;
203 ListAccountCreditDebit(strAccount, entries);
204
205 CAmount nCreditDebit = 0;
206 BOOST_FOREACH (const CAccountingEntry& entry, entries)
207 nCreditDebit += entry.nCreditDebit;
208
209 return nCreditDebit;
210 }
211
ListAccountCreditDebit(const string & strAccount,list<CAccountingEntry> & entries)212 void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
213 {
214 bool fAllAccounts = (strAccount == "*");
215
216 Dbc* pcursor = GetCursor();
217 if (!pcursor)
218 throw runtime_error(std::string(__func__) + ": cannot create DB cursor");
219 unsigned int fFlags = DB_SET_RANGE;
220 while (true)
221 {
222 // Read next record
223 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
224 if (fFlags == DB_SET_RANGE)
225 ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? string("") : strAccount), uint64_t(0)));
226 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
227 int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
228 fFlags = DB_NEXT;
229 if (ret == DB_NOTFOUND)
230 break;
231 else if (ret != 0)
232 {
233 pcursor->close();
234 throw runtime_error(std::string(__func__) + ": error scanning DB");
235 }
236
237 // Unserialize
238 string strType;
239 ssKey >> strType;
240 if (strType != "acentry")
241 break;
242 CAccountingEntry acentry;
243 ssKey >> acentry.strAccount;
244 if (!fAllAccounts && acentry.strAccount != strAccount)
245 break;
246
247 ssValue >> acentry;
248 ssKey >> acentry.nEntryNo;
249 entries.push_back(acentry);
250 }
251
252 pcursor->close();
253 }
254
ReorderTransactions(CWallet * pwallet)255 DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet)
256 {
257 LOCK(pwallet->cs_wallet);
258 // Old wallets didn't have any defined order for transactions
259 // Probably a bad idea to change the output of this
260
261 // First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
262 typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
263 typedef multimap<int64_t, TxPair > TxItems;
264 TxItems txByTime;
265
266 for (map<uint256, CWalletTx>::iterator it = pwallet->mapWallet.begin(); it != pwallet->mapWallet.end(); ++it)
267 {
268 CWalletTx* wtx = &((*it).second);
269 txByTime.insert(make_pair(wtx->nTimeReceived, TxPair(wtx, (CAccountingEntry*)0)));
270 }
271 list<CAccountingEntry> acentries;
272 ListAccountCreditDebit("", acentries);
273 BOOST_FOREACH(CAccountingEntry& entry, acentries)
274 {
275 txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
276 }
277
278 int64_t& nOrderPosNext = pwallet->nOrderPosNext;
279 nOrderPosNext = 0;
280 std::vector<int64_t> nOrderPosOffsets;
281 for (TxItems::iterator it = txByTime.begin(); it != txByTime.end(); ++it)
282 {
283 CWalletTx *const pwtx = (*it).second.first;
284 CAccountingEntry *const pacentry = (*it).second.second;
285 int64_t& nOrderPos = (pwtx != 0) ? pwtx->nOrderPos : pacentry->nOrderPos;
286
287 if (nOrderPos == -1)
288 {
289 nOrderPos = nOrderPosNext++;
290 nOrderPosOffsets.push_back(nOrderPos);
291
292 if (pwtx)
293 {
294 if (!WriteTx(*pwtx))
295 return DB_LOAD_FAIL;
296 }
297 else
298 if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
299 return DB_LOAD_FAIL;
300 }
301 else
302 {
303 int64_t nOrderPosOff = 0;
304 BOOST_FOREACH(const int64_t& nOffsetStart, nOrderPosOffsets)
305 {
306 if (nOrderPos >= nOffsetStart)
307 ++nOrderPosOff;
308 }
309 nOrderPos += nOrderPosOff;
310 nOrderPosNext = std::max(nOrderPosNext, nOrderPos + 1);
311
312 if (!nOrderPosOff)
313 continue;
314
315 // Since we're changing the order, write it back
316 if (pwtx)
317 {
318 if (!WriteTx(*pwtx))
319 return DB_LOAD_FAIL;
320 }
321 else
322 if (!WriteAccountingEntry(pacentry->nEntryNo, *pacentry))
323 return DB_LOAD_FAIL;
324 }
325 }
326 WriteOrderPosNext(nOrderPosNext);
327
328 return DB_LOAD_OK;
329 }
330
331 class CWalletScanState {
332 public:
333 unsigned int nKeys;
334 unsigned int nCKeys;
335 unsigned int nKeyMeta;
336 bool fIsEncrypted;
337 bool fAnyUnordered;
338 int nFileVersion;
339 vector<uint256> vWalletUpgrade;
340
CWalletScanState()341 CWalletScanState() {
342 nKeys = nCKeys = nKeyMeta = 0;
343 fIsEncrypted = false;
344 fAnyUnordered = false;
345 nFileVersion = 0;
346 }
347 };
348
349 bool
ReadKeyValue(CWallet * pwallet,CDataStream & ssKey,CDataStream & ssValue,CWalletScanState & wss,string & strType,string & strErr)350 ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
351 CWalletScanState &wss, string& strType, string& strErr)
352 {
353 try {
354 // Unserialize
355 // Taking advantage of the fact that pair serialization
356 // is just the two items serialized one after the other
357 ssKey >> strType;
358 if (strType == "name")
359 {
360 string strAddress;
361 ssKey >> strAddress;
362 ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].name;
363 }
364 else if (strType == "purpose")
365 {
366 string strAddress;
367 ssKey >> strAddress;
368 ssValue >> pwallet->mapAddressBook[CBitcoinAddress(strAddress).Get()].purpose;
369 }
370 else if (strType == "tx")
371 {
372 uint256 hash;
373 ssKey >> hash;
374 CWalletTx wtx;
375 ssValue >> wtx;
376 CValidationState state;
377 if (!(CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid()))
378 return false;
379
380 // Undo serialize changes in 31600
381 if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
382 {
383 if (!ssValue.empty())
384 {
385 char fTmp;
386 char fUnused;
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;
391 }
392 else
393 {
394 strErr = strprintf("LoadWallet() repairing tx ver=%d %s", wtx.fTimeReceivedIsTxTime, hash.ToString());
395 wtx.fTimeReceivedIsTxTime = 0;
396 }
397 wss.vWalletUpgrade.push_back(hash);
398 }
399
400 if (wtx.nOrderPos == -1)
401 wss.fAnyUnordered = true;
402
403 pwallet->AddToWallet(wtx, true, NULL);
404 }
405 else if (strType == "acentry")
406 {
407 string strAccount;
408 ssKey >> strAccount;
409 uint64_t nNumber;
410 ssKey >> nNumber;
411 if (nNumber > nAccountingEntryNumber)
412 nAccountingEntryNumber = nNumber;
413
414 if (!wss.fAnyUnordered)
415 {
416 CAccountingEntry acentry;
417 ssValue >> acentry;
418 if (acentry.nOrderPos == -1)
419 wss.fAnyUnordered = true;
420 }
421 }
422 else if (strType == "watchs")
423 {
424 CScript script;
425 ssKey >> *(CScriptBase*)(&script);
426 char fYes;
427 ssValue >> fYes;
428 if (fYes == '1')
429 pwallet->LoadWatchOnly(script);
430
431 // Watch-only addresses have no birthday information for now,
432 // so set the wallet birthday to the beginning of time.
433 pwallet->nTimeFirstKey = 1;
434 }
435 else if (strType == "key" || strType == "wkey")
436 {
437 CPubKey vchPubKey;
438 ssKey >> vchPubKey;
439 if (!vchPubKey.IsValid())
440 {
441 strErr = "Error reading wallet database: CPubKey corrupt";
442 return false;
443 }
444 CKey key;
445 CPrivKey pkey;
446 uint256 hash;
447
448 if (strType == "key")
449 {
450 wss.nKeys++;
451 ssValue >> pkey;
452 } else {
453 CWalletKey wkey;
454 ssValue >> wkey;
455 pkey = wkey.vchPrivKey;
456 }
457
458 // Old wallets store keys as "key" [pubkey] => [privkey]
459 // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key
460 // using EC operations as a checksum.
461 // Newer wallets store keys as "key"[pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while
462 // remaining backwards-compatible.
463 try
464 {
465 ssValue >> hash;
466 }
467 catch (...) {}
468
469 bool fSkipCheck = false;
470
471 if (!hash.IsNull())
472 {
473 // hash pubkey/privkey to accelerate wallet load
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());
478
479 if (Hash(vchKey.begin(), vchKey.end()) != hash)
480 {
481 strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
482 return false;
483 }
484
485 fSkipCheck = true;
486 }
487
488 if (!key.Load(pkey, vchPubKey, fSkipCheck))
489 {
490 strErr = "Error reading wallet database: CPrivKey corrupt";
491 return false;
492 }
493 if (!pwallet->LoadKey(key, vchPubKey))
494 {
495 strErr = "Error reading wallet database: LoadKey failed";
496 return false;
497 }
498 }
499 else if (strType == "mkey")
500 {
501 unsigned int nID;
502 ssKey >> nID;
503 CMasterKey kMasterKey;
504 ssValue >> kMasterKey;
505 if(pwallet->mapMasterKeys.count(nID) != 0)
506 {
507 strErr = strprintf("Error reading wallet database: duplicate CMasterKey id %u", nID);
508 return false;
509 }
510 pwallet->mapMasterKeys[nID] = kMasterKey;
511 if (pwallet->nMasterKeyMaxID < nID)
512 pwallet->nMasterKeyMaxID = nID;
513 }
514 else if (strType == "ckey")
515 {
516 CPubKey vchPubKey;
517 ssKey >> vchPubKey;
518 if (!vchPubKey.IsValid())
519 {
520 strErr = "Error reading wallet database: CPubKey corrupt";
521 return false;
522 }
523 vector<unsigned char> vchPrivKey;
524 ssValue >> vchPrivKey;
525 wss.nCKeys++;
526
527 if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
528 {
529 strErr = "Error reading wallet database: LoadCryptedKey failed";
530 return false;
531 }
532 wss.fIsEncrypted = true;
533 }
534 else if (strType == "keymeta")
535 {
536 CPubKey vchPubKey;
537 ssKey >> vchPubKey;
538 CKeyMetadata keyMeta;
539 ssValue >> keyMeta;
540 wss.nKeyMeta++;
541
542 pwallet->LoadKeyMetadata(vchPubKey, keyMeta);
543
544 // find earliest key creation time, as wallet birthday
545 if (!pwallet->nTimeFirstKey ||
546 (keyMeta.nCreateTime < pwallet->nTimeFirstKey))
547 pwallet->nTimeFirstKey = keyMeta.nCreateTime;
548 }
549 else if (strType == "defaultkey")
550 {
551 ssValue >> pwallet->vchDefaultKey;
552 }
553 else if (strType == "pool")
554 {
555 int64_t nIndex;
556 ssKey >> nIndex;
557 CKeyPool keypool;
558 ssValue >> keypool;
559 pwallet->setKeyPool.insert(nIndex);
560
561 // If no metadata exists yet, create a default with the pool key's
562 // creation time. Note that this may be overwritten by actually
563 // stored metadata for that key later, which is fine.
564 CKeyID keyid = keypool.vchPubKey.GetID();
565 if (pwallet->mapKeyMetadata.count(keyid) == 0)
566 pwallet->mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime);
567 }
568 else if (strType == "version")
569 {
570 ssValue >> wss.nFileVersion;
571 if (wss.nFileVersion == 10300)
572 wss.nFileVersion = 300;
573 }
574 else if (strType == "cscript")
575 {
576 uint160 hash;
577 ssKey >> hash;
578 CScript script;
579 ssValue >> *(CScriptBase*)(&script);
580 if (!pwallet->LoadCScript(script))
581 {
582 strErr = "Error reading wallet database: LoadCScript failed";
583 return false;
584 }
585 }
586 else if (strType == "orderposnext")
587 {
588 ssValue >> pwallet->nOrderPosNext;
589 }
590 else if (strType == "destdata")
591 {
592 std::string strAddress, strKey, strValue;
593 ssKey >> strAddress;
594 ssKey >> strKey;
595 ssValue >> strValue;
596 if (!pwallet->LoadDestData(CBitcoinAddress(strAddress).Get(), strKey, strValue))
597 {
598 strErr = "Error reading wallet database: LoadDestData failed";
599 return false;
600 }
601 }
602 else if (strType == "hdchain")
603 {
604 CHDChain chain;
605 ssValue >> chain;
606 if (!pwallet->SetHDChain(chain, true))
607 {
608 strErr = "Error reading wallet database: SetHDChain failed";
609 return false;
610 }
611 }
612 } catch (...)
613 {
614 return false;
615 }
616 return true;
617 }
618
IsKeyType(string strType)619 static bool IsKeyType(string strType)
620 {
621 return (strType== "key" || strType == "wkey" ||
622 strType == "mkey" || strType == "ckey");
623 }
624
LoadWallet(CWallet * pwallet)625 DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
626 {
627 pwallet->vchDefaultKey = CPubKey();
628 CWalletScanState wss;
629 bool fNoncriticalErrors = false;
630 DBErrors result = DB_LOAD_OK;
631
632 try {
633 LOCK(pwallet->cs_wallet);
634 int nMinVersion = 0;
635 if (Read((string)"minversion", nMinVersion))
636 {
637 if (nMinVersion > CLIENT_VERSION)
638 return DB_TOO_NEW;
639 pwallet->LoadMinVersion(nMinVersion);
640 }
641
642 // Get cursor
643 Dbc* pcursor = GetCursor();
644 if (!pcursor)
645 {
646 LogPrintf("Error getting wallet database cursor\n");
647 return DB_CORRUPT;
648 }
649
650 while (true)
651 {
652 // Read next record
653 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
654 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
655 int ret = ReadAtCursor(pcursor, ssKey, ssValue);
656 if (ret == DB_NOTFOUND)
657 break;
658 else if (ret != 0)
659 {
660 LogPrintf("Error reading next record from wallet database\n");
661 return DB_CORRUPT;
662 }
663
664 // Try to be tolerant of single corrupt records:
665 string strType, strErr;
666 if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
667 {
668 // losing keys is considered a catastrophic error, anything else
669 // we assume the user can live with:
670 if (IsKeyType(strType))
671 result = DB_CORRUPT;
672 else
673 {
674 // Leave other errors alone, if we try to fix them we might make things worse.
675 fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
676 if (strType == "tx")
677 // Rescan if there is a bad transaction record:
678 SoftSetBoolArg("-rescan", true);
679 }
680 }
681 if (!strErr.empty())
682 LogPrintf("%s\n", strErr);
683 }
684 pcursor->close();
685 }
686 catch (const boost::thread_interrupted&) {
687 throw;
688 }
689 catch (...) {
690 result = DB_CORRUPT;
691 }
692
693 if (fNoncriticalErrors && result == DB_LOAD_OK)
694 result = DB_NONCRITICAL_ERROR;
695
696 // Any wallet corruption at all: skip any rewriting or
697 // upgrading, we don't want to make it worse.
698 if (result != DB_LOAD_OK)
699 return result;
700
701 LogPrintf("nFileVersion = %d\n", wss.nFileVersion);
702
703 LogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\n",
704 wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys);
705
706 // nTimeFirstKey is only reliable if all keys have metadata
707 if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta)
708 pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value'
709
710 BOOST_FOREACH(uint256 hash, wss.vWalletUpgrade)
711 WriteTx(pwallet->mapWallet[hash]);
712
713 // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
714 if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000))
715 return DB_NEED_REWRITE;
716
717 if (wss.nFileVersion < CLIENT_VERSION) // Update
718 WriteVersion(CLIENT_VERSION);
719
720 if (wss.fAnyUnordered)
721 result = ReorderTransactions(pwallet);
722
723 pwallet->laccentries.clear();
724 ListAccountCreditDebit("*", pwallet->laccentries);
725 BOOST_FOREACH(CAccountingEntry& entry, pwallet->laccentries) {
726 pwallet->wtxOrdered.insert(make_pair(entry.nOrderPos, CWallet::TxPair((CWalletTx*)0, &entry)));
727 }
728
729 return result;
730 }
731
FindWalletTx(CWallet * pwallet,vector<uint256> & vTxHash,vector<CWalletTx> & vWtx)732 DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash, vector<CWalletTx>& vWtx)
733 {
734 pwallet->vchDefaultKey = CPubKey();
735 bool fNoncriticalErrors = false;
736 DBErrors result = DB_LOAD_OK;
737
738 try {
739 LOCK(pwallet->cs_wallet);
740 int nMinVersion = 0;
741 if (Read((string)"minversion", nMinVersion))
742 {
743 if (nMinVersion > CLIENT_VERSION)
744 return DB_TOO_NEW;
745 pwallet->LoadMinVersion(nMinVersion);
746 }
747
748 // Get cursor
749 Dbc* pcursor = GetCursor();
750 if (!pcursor)
751 {
752 LogPrintf("Error getting wallet database cursor\n");
753 return DB_CORRUPT;
754 }
755
756 while (true)
757 {
758 // Read next record
759 CDataStream ssKey(SER_DISK, CLIENT_VERSION);
760 CDataStream ssValue(SER_DISK, CLIENT_VERSION);
761 int ret = ReadAtCursor(pcursor, ssKey, ssValue);
762 if (ret == DB_NOTFOUND)
763 break;
764 else if (ret != 0)
765 {
766 LogPrintf("Error reading next record from wallet database\n");
767 return DB_CORRUPT;
768 }
769
770 string strType;
771 ssKey >> strType;
772 if (strType == "tx") {
773 uint256 hash;
774 ssKey >> hash;
775
776 CWalletTx wtx;
777 ssValue >> wtx;
778
779 vTxHash.push_back(hash);
780 vWtx.push_back(wtx);
781 }
782 }
783 pcursor->close();
784 }
785 catch (const boost::thread_interrupted&) {
786 throw;
787 }
788 catch (...) {
789 result = DB_CORRUPT;
790 }
791
792 if (fNoncriticalErrors && result == DB_LOAD_OK)
793 result = DB_NONCRITICAL_ERROR;
794
795 return result;
796 }
797
ZapSelectTx(CWallet * pwallet,vector<uint256> & vTxHashIn,vector<uint256> & vTxHashOut)798 DBErrors CWalletDB::ZapSelectTx(CWallet* pwallet, vector<uint256>& vTxHashIn, vector<uint256>& vTxHashOut)
799 {
800 // build list of wallet TXs and hashes
801 vector<uint256> vTxHash;
802 vector<CWalletTx> vWtx;
803 DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx);
804 if (err != DB_LOAD_OK) {
805 return err;
806 }
807
808 std::sort(vTxHash.begin(), vTxHash.end());
809 std::sort(vTxHashIn.begin(), vTxHashIn.end());
810
811 // erase each matching wallet TX
812 bool delerror = false;
813 vector<uint256>::iterator it = vTxHashIn.begin();
814 BOOST_FOREACH (uint256 hash, vTxHash) {
815 while (it < vTxHashIn.end() && (*it) < hash) {
816 it++;
817 }
818 if (it == vTxHashIn.end()) {
819 break;
820 }
821 else if ((*it) == hash) {
822 pwallet->mapWallet.erase(hash);
823 if(!EraseTx(hash)) {
824 LogPrint("db", "Transaction was found for deletion but returned database error: %s\n", hash.GetHex());
825 delerror = true;
826 }
827 vTxHashOut.push_back(hash);
828 }
829 }
830
831 if (delerror) {
832 return DB_CORRUPT;
833 }
834 return DB_LOAD_OK;
835 }
836
ZapWalletTx(CWallet * pwallet,vector<CWalletTx> & vWtx)837 DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet, vector<CWalletTx>& vWtx)
838 {
839 // build list of wallet TXs
840 vector<uint256> vTxHash;
841 DBErrors err = FindWalletTx(pwallet, vTxHash, vWtx);
842 if (err != DB_LOAD_OK)
843 return err;
844
845 // erase each wallet TX
846 BOOST_FOREACH (uint256& hash, vTxHash) {
847 if (!EraseTx(hash))
848 return DB_CORRUPT;
849 }
850
851 return DB_LOAD_OK;
852 }
853
ThreadFlushWalletDB(const string & strFile)854 void ThreadFlushWalletDB(const string& strFile)
855 {
856 // Make this thread recognisable as the wallet flushing thread
857 RenameThread("zetacoin-wallet");
858
859 static bool fOneThread;
860 if (fOneThread)
861 return;
862 fOneThread = true;
863 if (!GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET))
864 return;
865
866 unsigned int nLastSeen = nWalletDBUpdated;
867 unsigned int nLastFlushed = nWalletDBUpdated;
868 int64_t nLastWalletUpdate = GetTime();
869 while (true)
870 {
871 MilliSleep(500);
872
873 if (nLastSeen != nWalletDBUpdated)
874 {
875 nLastSeen = nWalletDBUpdated;
876 nLastWalletUpdate = GetTime();
877 }
878
879 if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2)
880 {
881 TRY_LOCK(bitdb.cs_db,lockDb);
882 if (lockDb)
883 {
884 // Don't do this if any databases are in use
885 int nRefCount = 0;
886 map<string, int>::iterator mi = bitdb.mapFileUseCount.begin();
887 while (mi != bitdb.mapFileUseCount.end())
888 {
889 nRefCount += (*mi).second;
890 mi++;
891 }
892
893 if (nRefCount == 0)
894 {
895 boost::this_thread::interruption_point();
896 map<string, int>::iterator mi = bitdb.mapFileUseCount.find(strFile);
897 if (mi != bitdb.mapFileUseCount.end())
898 {
899 LogPrint("db", "Flushing %s\n", strFile);
900 nLastFlushed = nWalletDBUpdated;
901 int64_t nStart = GetTimeMillis();
902
903 // Flush wallet file so it's self contained
904 bitdb.CloseDb(strFile);
905 bitdb.CheckpointLSN(strFile);
906
907 bitdb.mapFileUseCount.erase(mi++);
908 LogPrint("db", "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart);
909 }
910 }
911 }
912 }
913 }
914 }
915
916 //
917 // Try to (very carefully!) recover wallet file if there is a problem.
918 //
Recover(CDBEnv & dbenv,const std::string & filename,bool fOnlyKeys)919 bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys)
920 {
921 // Recovery procedure:
922 // move wallet file to wallet.timestamp.bak
923 // Call Salvage with fAggressive=true to
924 // get as much data as possible.
925 // Rewrite salvaged data to fresh wallet file
926 // Set -rescan so any missing transactions will be
927 // found.
928 int64_t now = GetTime();
929 std::string newFilename = strprintf("wallet.%d.bak", now);
930
931 int result = dbenv.dbenv->dbrename(NULL, filename.c_str(), NULL,
932 newFilename.c_str(), DB_AUTO_COMMIT);
933 if (result == 0)
934 LogPrintf("Renamed %s to %s\n", filename, newFilename);
935 else
936 {
937 LogPrintf("Failed to rename %s to %s\n", filename, newFilename);
938 return false;
939 }
940
941 std::vector<CDBEnv::KeyValPair> salvagedData;
942 bool fSuccess = dbenv.Salvage(newFilename, true, salvagedData);
943 if (salvagedData.empty())
944 {
945 LogPrintf("Salvage(aggressive) found no records in %s.\n", newFilename);
946 return false;
947 }
948 LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
949
950 boost::scoped_ptr<Db> pdbCopy(new Db(dbenv.dbenv, 0));
951 int ret = pdbCopy->open(NULL, // Txn pointer
952 filename.c_str(), // Filename
953 "main", // Logical db name
954 DB_BTREE, // Database type
955 DB_CREATE, // Flags
956 0);
957 if (ret > 0)
958 {
959 LogPrintf("Cannot create database file %s\n", filename);
960 return false;
961 }
962 CWallet dummyWallet;
963 CWalletScanState wss;
964
965 DbTxn* ptxn = dbenv.TxnBegin();
966 BOOST_FOREACH(CDBEnv::KeyValPair& row, salvagedData)
967 {
968 if (fOnlyKeys)
969 {
970 CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION);
971 CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);
972 string strType, strErr;
973 bool fReadOK;
974 {
975 // Required in LoadKeyMetadata():
976 LOCK(dummyWallet.cs_wallet);
977 fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue,
978 wss, strType, strErr);
979 }
980 if (!IsKeyType(strType) && strType != "hdchain")
981 continue;
982 if (!fReadOK)
983 {
984 LogPrintf("WARNING: CWalletDB::Recover skipping %s: %s\n", strType, strErr);
985 continue;
986 }
987 }
988 Dbt datKey(&row.first[0], row.first.size());
989 Dbt datValue(&row.second[0], row.second.size());
990 int ret2 = pdbCopy->put(ptxn, &datKey, &datValue, DB_NOOVERWRITE);
991 if (ret2 > 0)
992 fSuccess = false;
993 }
994 ptxn->commit(0);
995 pdbCopy->close(0);
996
997 return fSuccess;
998 }
999
Recover(CDBEnv & dbenv,const std::string & filename)1000 bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename)
1001 {
1002 return CWalletDB::Recover(dbenv, filename, false);
1003 }
1004
WriteDestData(const std::string & address,const std::string & key,const std::string & value)1005 bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
1006 {
1007 nWalletDBUpdated++;
1008 return Write(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value);
1009 }
1010
EraseDestData(const std::string & address,const std::string & key)1011 bool CWalletDB::EraseDestData(const std::string &address, const std::string &key)
1012 {
1013 nWalletDBUpdated++;
1014 return Erase(std::make_pair(std::string("destdata"), std::make_pair(address, key)));
1015 }
1016
1017
WriteHDChain(const CHDChain & chain)1018 bool CWalletDB::WriteHDChain(const CHDChain& chain)
1019 {
1020 nWalletDBUpdated++;
1021 return Write(std::string("hdchain"), chain);
1022 }
1023