Handle corrupt wallets gracefully.
Corrupt wallets used to cause a DB_RUNRECOVERY uncaught exception and a
crash. This commit does three things:
1) Runs a BDB verify early in the startup process, and if there is a
low-level problem with the database:
+ Moves the bad wallet.dat to wallet.timestamp.bak
+ Runs a 'salvage' operation to get key/value pairs, and
writes them to a new wallet.dat
+ Continues with startup.
2) Much more tolerant of serialization errors. All errors in deserialization
are reported by tolerated EXCEPT for errors related to reading keypairs
or master key records-- those are reported and then shut down, so the user
can get help (or recover from a backup).
3) Adds a new -salvagewallet option, which:
+ Moves the wallet.dat to wallet.timestamp.bak
+ extracts ONLY keypairs and master keys into a new wallet.dat
+ soft-sets -rescan, to recreate transaction history
This was tested by randomly corrupting testnet wallets using a little
python script I wrote (https://gist.github.com/3812689)
This commit is contained in:
@@ -335,7 +335,9 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx)
|
||||
if (mi != mapWallet.end())
|
||||
{
|
||||
CWalletTx& wtx = (*mi).second;
|
||||
if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n]))
|
||||
if (txin.prevout.n >= wtx.vout.size())
|
||||
printf("WalletUpdateSpent: bad wtx %s\n", wtx.GetHash().ToString().c_str());
|
||||
else if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n]))
|
||||
{
|
||||
printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
|
||||
wtx.MarkSpent(txin.prevout.n);
|
||||
@@ -1371,12 +1373,12 @@ string CWallet::SendMoneyToDestination(const CTxDestination& address, int64 nVal
|
||||
|
||||
|
||||
|
||||
int CWallet::LoadWallet(bool& fFirstRunRet)
|
||||
DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
|
||||
{
|
||||
if (!fFileBacked)
|
||||
return DB_LOAD_OK;
|
||||
fFirstRunRet = false;
|
||||
int nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
|
||||
DBErrors nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
|
||||
if (nLoadWalletRet == DB_NEED_REWRITE)
|
||||
{
|
||||
if (CDB::Rewrite(strWalletFile, "\x04pool"))
|
||||
|
||||
Reference in New Issue
Block a user