Skip to content

Commit e051e65

Browse files
author
Jeff Garzik
committed
Merge pull request #3659 from jgarzik/zapall
Add -zapwallettx function, a diagnostic tool to assist in wallet repair
2 parents 8e842cd + 518f3bd commit e051e65

File tree

5 files changed

+128
-0
lines changed

5 files changed

+128
-0
lines changed

src/init.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ std::string HelpMessage(HelpMessageMode hmm)
270270
strUsage += " -disablewallet " + _("Do not load the wallet and disable wallet RPC calls") + "\n";
271271
strUsage += " -paytxfee=<amt> " + _("Fee per kB to add to transactions you send") + "\n";
272272
strUsage += " -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n";
273+
strUsage += " -zapwallettxes " + _("Clear list of wallet transactions (diagnostic tool; implies -rescan)") + "\n";
273274
strUsage += " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + "\n";
274275
strUsage += " -upgradewallet " + _("Upgrade wallet to latest format") + "\n";
275276
strUsage += " -wallet=<file> " + _("Specify wallet file (within data directory)") + "\n";
@@ -454,6 +455,12 @@ bool AppInit2(boost::thread_group& threadGroup)
454455
LogPrintf("AppInit2 : parameter interaction: -salvagewallet=1 -> setting -rescan=1\n");
455456
}
456457

458+
// -zapwallettx implies a rescan
459+
if (GetBoolArg("-zapwallettxes", false)) {
460+
if (SoftSetBoolArg("-rescan", true))
461+
LogPrintf("AppInit2 : parameter interaction: -zapwallettxes=1 -> setting -rescan=1\n");
462+
}
463+
457464
// Make sure enough file descriptors are available
458465
int nBind = std::max((int)mapArgs.count("-bind"), 1);
459466
nMaxConnections = GetArg("-maxconnections", 125);
@@ -899,6 +906,20 @@ bool AppInit2(boost::thread_group& threadGroup)
899906
pwalletMain = NULL;
900907
LogPrintf("Wallet disabled!\n");
901908
} else {
909+
if (GetBoolArg("-zapwallettxes", false)) {
910+
uiInterface.InitMessage(_("Zapping all transactions from wallet..."));
911+
912+
pwalletMain = new CWallet(strWalletFile);
913+
DBErrors nZapWalletRet = pwalletMain->ZapWalletTx();
914+
if (nZapWalletRet != DB_LOAD_OK) {
915+
uiInterface.InitMessage(_("Error loading wallet.dat: Wallet corrupted"));
916+
return false;
917+
}
918+
919+
delete pwalletMain;
920+
pwalletMain = NULL;
921+
}
922+
902923
uiInterface.InitMessage(_("Loading wallet..."));
903924

904925
nStart = GetTimeMillis();

src/wallet.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,6 +1497,30 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
14971497
}
14981498

14991499

1500+
DBErrors CWallet::ZapWalletTx()
1501+
{
1502+
if (!fFileBacked)
1503+
return DB_LOAD_OK;
1504+
DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this);
1505+
if (nZapWalletTxRet == DB_NEED_REWRITE)
1506+
{
1507+
if (CDB::Rewrite(strWalletFile, "\x04pool"))
1508+
{
1509+
LOCK(cs_wallet);
1510+
setKeyPool.clear();
1511+
// Note: can't top-up keypool here, because wallet is locked.
1512+
// User will be prompted to unlock wallet the next operation
1513+
// the requires a new key.
1514+
}
1515+
}
1516+
1517+
if (nZapWalletTxRet != DB_LOAD_OK)
1518+
return nZapWalletTxRet;
1519+
1520+
return DB_LOAD_OK;
1521+
}
1522+
1523+
15001524
bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose)
15011525
{
15021526
AssertLockHeld(cs_wallet); // mapAddressBook

src/wallet.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ class CWallet : public CCryptoKeyStore, public CWalletInterface
323323
void SetBestChain(const CBlockLocator& loc);
324324

325325
DBErrors LoadWallet(bool& fFirstRunRet);
326+
DBErrors ZapWalletTx();
326327

327328
bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose);
328329

src/walletdb.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,86 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
684684
return result;
685685
}
686686

687+
DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash)
688+
{
689+
pwallet->vchDefaultKey = CPubKey();
690+
CWalletScanState wss;
691+
bool fNoncriticalErrors = false;
692+
DBErrors result = DB_LOAD_OK;
693+
694+
try {
695+
LOCK(pwallet->cs_wallet);
696+
int nMinVersion = 0;
697+
if (Read((string)"minversion", nMinVersion))
698+
{
699+
if (nMinVersion > CLIENT_VERSION)
700+
return DB_TOO_NEW;
701+
pwallet->LoadMinVersion(nMinVersion);
702+
}
703+
704+
// Get cursor
705+
Dbc* pcursor = GetCursor();
706+
if (!pcursor)
707+
{
708+
LogPrintf("Error getting wallet database cursor\n");
709+
return DB_CORRUPT;
710+
}
711+
712+
while (true)
713+
{
714+
// Read next record
715+
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
716+
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
717+
int ret = ReadAtCursor(pcursor, ssKey, ssValue);
718+
if (ret == DB_NOTFOUND)
719+
break;
720+
else if (ret != 0)
721+
{
722+
LogPrintf("Error reading next record from wallet database\n");
723+
return DB_CORRUPT;
724+
}
725+
726+
string strType;
727+
ssKey >> strType;
728+
if (strType == "tx") {
729+
uint256 hash;
730+
ssKey >> hash;
731+
732+
vTxHash.push_back(hash);
733+
}
734+
}
735+
pcursor->close();
736+
}
737+
catch (boost::thread_interrupted) {
738+
throw;
739+
}
740+
catch (...) {
741+
result = DB_CORRUPT;
742+
}
743+
744+
if (fNoncriticalErrors && result == DB_LOAD_OK)
745+
result = DB_NONCRITICAL_ERROR;
746+
747+
return result;
748+
}
749+
750+
DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet)
751+
{
752+
// build list of wallet TXs
753+
vector<uint256> vTxHash;
754+
DBErrors err = FindWalletTx(pwallet, vTxHash);
755+
if (err != DB_LOAD_OK)
756+
return err;
757+
758+
// erase each wallet TX
759+
BOOST_FOREACH (uint256& hash, vTxHash) {
760+
if (!EraseTx(hash))
761+
return DB_CORRUPT;
762+
}
763+
764+
return DB_LOAD_OK;
765+
}
766+
687767
void ThreadFlushWalletDB(const string& strFile)
688768
{
689769
// Make this thread recognisable as the wallet flushing thread

src/walletdb.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ class CWalletDB : public CDB
122122

123123
DBErrors ReorderTransactions(CWallet*);
124124
DBErrors LoadWallet(CWallet* pwallet);
125+
DBErrors FindWalletTx(CWallet* pwallet, std::vector<uint256>& vTxHash);
126+
DBErrors ZapWalletTx(CWallet* pwallet);
125127
static bool Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys);
126128
static bool Recover(CDBEnv& dbenv, std::string filename);
127129
};

0 commit comments

Comments
 (0)