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