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