lbrycrd/src/walletdb.h
Gavin Andresen eed1785f70 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)
2012-10-08 17:46:45 -04:00

163 lines
4.8 KiB
C++

// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_WALLETDB_H
#define BITCOIN_WALLETDB_H
#include "db.h"
#include "base58.h"
class CKeyPool;
class CAccount;
class CAccountingEntry;
/** Error statuses for the wallet database */
enum DBErrors
{
DB_LOAD_OK,
DB_CORRUPT,
DB_NONCRITICAL_ERROR,
DB_TOO_NEW,
DB_LOAD_FAIL,
DB_NEED_REWRITE
};
/** Access to the wallet database (wallet.dat) */
class CWalletDB : public CDB
{
public:
CWalletDB(std::string strFilename, const char* pszMode="r+") : CDB(strFilename.c_str(), pszMode)
{
}
private:
CWalletDB(const CWalletDB&);
void operator=(const CWalletDB&);
public:
bool WriteName(const std::string& strAddress, const std::string& strName);
bool EraseName(const std::string& strAddress);
bool WriteTx(uint256 hash, const CWalletTx& wtx)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("tx"), hash), wtx);
}
bool EraseTx(uint256 hash)
{
nWalletDBUpdated++;
return Erase(std::make_pair(std::string("tx"), hash));
}
bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("key"), vchPubKey.Raw()), vchPrivKey, false);
}
bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true)
{
nWalletDBUpdated++;
if (!Write(std::make_pair(std::string("ckey"), vchPubKey.Raw()), vchCryptedSecret, false))
return false;
if (fEraseUnencryptedKey)
{
Erase(std::make_pair(std::string("key"), vchPubKey.Raw()));
Erase(std::make_pair(std::string("wkey"), vchPubKey.Raw()));
}
return true;
}
bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
}
bool WriteCScript(const uint160& hash, const CScript& redeemScript)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false);
}
bool WriteBestBlock(const CBlockLocator& locator)
{
nWalletDBUpdated++;
return Write(std::string("bestblock"), locator);
}
bool ReadBestBlock(CBlockLocator& locator)
{
return Read(std::string("bestblock"), locator);
}
bool WriteOrderPosNext(int64 nOrderPosNext)
{
nWalletDBUpdated++;
return Write(std::string("orderposnext"), nOrderPosNext);
}
bool WriteDefaultKey(const CPubKey& vchPubKey)
{
nWalletDBUpdated++;
return Write(std::string("defaultkey"), vchPubKey.Raw());
}
bool ReadPool(int64 nPool, CKeyPool& keypool)
{
return Read(std::make_pair(std::string("pool"), nPool), keypool);
}
bool WritePool(int64 nPool, const CKeyPool& keypool)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("pool"), nPool), keypool);
}
bool ErasePool(int64 nPool)
{
nWalletDBUpdated++;
return Erase(std::make_pair(std::string("pool"), nPool));
}
// Settings are no longer stored in wallet.dat; these are
// used only for backwards compatibility:
template<typename T>
bool ReadSetting(const std::string& strKey, T& value)
{
return Read(std::make_pair(std::string("setting"), strKey), value);
}
template<typename T>
bool WriteSetting(const std::string& strKey, const T& value)
{
nWalletDBUpdated++;
return Write(std::make_pair(std::string("setting"), strKey), value);
}
bool EraseSetting(const std::string& strKey)
{
nWalletDBUpdated++;
return Erase(std::make_pair(std::string("setting"), strKey));
}
bool WriteMinVersion(int nVersion)
{
return Write(std::string("minversion"), nVersion);
}
bool ReadAccount(const std::string& strAccount, CAccount& account);
bool WriteAccount(const std::string& strAccount, const CAccount& account);
private:
bool WriteAccountingEntry(const uint64 nAccEntryNum, const CAccountingEntry& acentry);
public:
bool WriteAccountingEntry(const CAccountingEntry& acentry);
int64 GetAccountCreditDebit(const std::string& strAccount);
void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
DBErrors ReorderTransactions(CWallet*);
DBErrors LoadWallet(CWallet* pwallet);
static bool Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys);
static bool Recover(CDBEnv& dbenv, std::string filename);
};
#endif // BITCOIN_WALLETDB_H