Add -zapwallettxes cli/config option, used for wallet recovery
This diagnostic tool removes all "tx" records from the wallet db, then forces a full rescan, to rebuild "tx" records accurately.
This commit is contained in:
parent
6056c87d25
commit
518f3bdae3
5 changed files with 128 additions and 0 deletions
21
src/init.cpp
21
src/init.cpp
|
@ -270,6 +270,7 @@ std::string HelpMessage(HelpMessageMode hmm)
|
||||||
strUsage += " -disablewallet " + _("Do not load the wallet and disable wallet RPC calls") + "\n";
|
strUsage += " -disablewallet " + _("Do not load the wallet and disable wallet RPC calls") + "\n";
|
||||||
strUsage += " -paytxfee=<amt> " + _("Fee per kB to add to transactions you send") + "\n";
|
strUsage += " -paytxfee=<amt> " + _("Fee per kB to add to transactions you send") + "\n";
|
||||||
strUsage += " -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n";
|
strUsage += " -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n";
|
||||||
|
strUsage += " -zapwallettxes " + _("Clear list of wallet transactions (diagnostic tool; implies -rescan)") + "\n";
|
||||||
strUsage += " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + "\n";
|
strUsage += " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + "\n";
|
||||||
strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + "\n";
|
strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + "\n";
|
||||||
strUsage += " -wallet=<file> " + _("Specify wallet file (within data directory)") + "\n";
|
strUsage += " -wallet=<file> " + _("Specify wallet file (within data directory)") + "\n";
|
||||||
|
@ -454,6 +455,12 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||||
LogPrintf("AppInit2 : parameter interaction: -salvagewallet=1 -> setting -rescan=1\n");
|
LogPrintf("AppInit2 : parameter interaction: -salvagewallet=1 -> setting -rescan=1\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -zapwallettx implies a rescan
|
||||||
|
if (GetBoolArg("-zapwallettxes", false)) {
|
||||||
|
if (SoftSetBoolArg("-rescan", true))
|
||||||
|
LogPrintf("AppInit2 : parameter interaction: -zapwallettxes=1 -> setting -rescan=1\n");
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure enough file descriptors are available
|
// Make sure enough file descriptors are available
|
||||||
int nBind = std::max((int)mapArgs.count("-bind"), 1);
|
int nBind = std::max((int)mapArgs.count("-bind"), 1);
|
||||||
nMaxConnections = GetArg("-maxconnections", 125);
|
nMaxConnections = GetArg("-maxconnections", 125);
|
||||||
|
@ -899,6 +906,20 @@ bool AppInit2(boost::thread_group& threadGroup)
|
||||||
pwalletMain = NULL;
|
pwalletMain = NULL;
|
||||||
LogPrintf("Wallet disabled!\n");
|
LogPrintf("Wallet disabled!\n");
|
||||||
} else {
|
} else {
|
||||||
|
if (GetBoolArg("-zapwallettxes", false)) {
|
||||||
|
uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
|
||||||
|
|
||||||
|
pwalletMain = new CWallet(strWalletFile);
|
||||||
|
DBErrors nZapWalletRet = pwalletMain->ZapWalletTx();
|
||||||
|
if (nZapWalletRet != DB_LOAD_OK) {
|
||||||
|
uiInterface.InitMessage(_("Error loading wallet.dat: Wallet corrupted"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete pwalletMain;
|
||||||
|
pwalletMain = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
uiInterface.InitMessage(_("Loading wallet..."));
|
uiInterface.InitMessage(_("Loading wallet..."));
|
||||||
|
|
||||||
nStart = GetTimeMillis();
|
nStart = GetTimeMillis();
|
||||||
|
|
|
@ -1497,6 +1497,30 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DBErrors CWallet::ZapWalletTx()
|
||||||
|
{
|
||||||
|
if (!fFileBacked)
|
||||||
|
return DB_LOAD_OK;
|
||||||
|
DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this);
|
||||||
|
if (nZapWalletTxRet == DB_NEED_REWRITE)
|
||||||
|
{
|
||||||
|
if (CDB::Rewrite(strWalletFile, "\x04pool"))
|
||||||
|
{
|
||||||
|
LOCK(cs_wallet);
|
||||||
|
setKeyPool.clear();
|
||||||
|
// Note: can't top-up keypool here, because wallet is locked.
|
||||||
|
// User will be prompted to unlock wallet the next operation
|
||||||
|
// the requires a new key.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nZapWalletTxRet != DB_LOAD_OK)
|
||||||
|
return nZapWalletTxRet;
|
||||||
|
|
||||||
|
return DB_LOAD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose)
|
bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_wallet); // mapAddressBook
|
AssertLockHeld(cs_wallet); // mapAddressBook
|
||||||
|
|
|
@ -323,6 +323,7 @@ public:
|
||||||
void SetBestChain(const CBlockLocator& loc);
|
void SetBestChain(const CBlockLocator& loc);
|
||||||
|
|
||||||
DBErrors LoadWallet(bool& fFirstRunRet);
|
DBErrors LoadWallet(bool& fFirstRunRet);
|
||||||
|
DBErrors ZapWalletTx();
|
||||||
|
|
||||||
bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose);
|
bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose);
|
||||||
|
|
||||||
|
|
|
@ -684,6 +684,86 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash)
|
||||||
|
{
|
||||||
|
pwallet->vchDefaultKey = CPubKey();
|
||||||
|
CWalletScanState wss;
|
||||||
|
bool fNoncriticalErrors = false;
|
||||||
|
DBErrors result = DB_LOAD_OK;
|
||||||
|
|
||||||
|
try {
|
||||||
|
LOCK(pwallet->cs_wallet);
|
||||||
|
int nMinVersion = 0;
|
||||||
|
if (Read((string)"minversion", nMinVersion))
|
||||||
|
{
|
||||||
|
if (nMinVersion > CLIENT_VERSION)
|
||||||
|
return DB_TOO_NEW;
|
||||||
|
pwallet->LoadMinVersion(nMinVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get cursor
|
||||||
|
Dbc* pcursor = GetCursor();
|
||||||
|
if (!pcursor)
|
||||||
|
{
|
||||||
|
LogPrintf("Error getting wallet database cursor\n");
|
||||||
|
return DB_CORRUPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// Read next record
|
||||||
|
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
|
||||||
|
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
|
||||||
|
int ret = ReadAtCursor(pcursor, ssKey, ssValue);
|
||||||
|
if (ret == DB_NOTFOUND)
|
||||||
|
break;
|
||||||
|
else if (ret != 0)
|
||||||
|
{
|
||||||
|
LogPrintf("Error reading next record from wallet database\n");
|
||||||
|
return DB_CORRUPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
string strType;
|
||||||
|
ssKey >> strType;
|
||||||
|
if (strType == "tx") {
|
||||||
|
uint256 hash;
|
||||||
|
ssKey >> hash;
|
||||||
|
|
||||||
|
vTxHash.push_back(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pcursor->close();
|
||||||
|
}
|
||||||
|
catch (boost::thread_interrupted) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
result = DB_CORRUPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fNoncriticalErrors && result == DB_LOAD_OK)
|
||||||
|
result = DB_NONCRITICAL_ERROR;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet)
|
||||||
|
{
|
||||||
|
// build list of wallet TXs
|
||||||
|
vector<uint256> vTxHash;
|
||||||
|
DBErrors err = FindWalletTx(pwallet, vTxHash);
|
||||||
|
if (err != DB_LOAD_OK)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
// erase each wallet TX
|
||||||
|
BOOST_FOREACH (uint256& hash, vTxHash) {
|
||||||
|
if (!EraseTx(hash))
|
||||||
|
return DB_CORRUPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DB_LOAD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
void ThreadFlushWalletDB(const string& strFile)
|
void ThreadFlushWalletDB(const string& strFile)
|
||||||
{
|
{
|
||||||
// Make this thread recognisable as the wallet flushing thread
|
// Make this thread recognisable as the wallet flushing thread
|
||||||
|
|
|
@ -122,6 +122,8 @@ public:
|
||||||
|
|
||||||
DBErrors ReorderTransactions(CWallet*);
|
DBErrors ReorderTransactions(CWallet*);
|
||||||
DBErrors LoadWallet(CWallet* pwallet);
|
DBErrors LoadWallet(CWallet* pwallet);
|
||||||
|
DBErrors FindWalletTx(CWallet* pwallet, std::vector<uint256>& vTxHash);
|
||||||
|
DBErrors ZapWalletTx(CWallet* pwallet);
|
||||||
static bool Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys);
|
static bool Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys);
|
||||||
static bool Recover(CDBEnv& dbenv, std::string filename);
|
static bool Recover(CDBEnv& dbenv, std::string filename);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue