diff --git a/src/init.cpp b/src/init.cpp index 9dccc86..bdc6847 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -282,6 +282,7 @@ std::string HelpMessage() " -upgradewallet " + _("Upgrade wallet to latest format") + "\n" + " -keypool= " + _("Set key pool size to (default: 100)") + "\n" + " -rescan " + _("Rescan the block chain for missing wallet transactions") + "\n" + + " -zapwallettxes " + _("Clear list of wallet transactions (diagnostic tool; implies -rescan)") + "\n" + " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + "\n" + " -checkblocks= " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" + " -checklevel= " + _("How thorough the block verification is (0-6, default: 1)") + "\n" + @@ -388,6 +389,12 @@ bool AppInit2() SoftSetBoolArg("-rescan", true); } + // -zapwallettx implies a rescan + if (GetBoolArg("-zapwallettxes", false)) { + if (SoftSetBoolArg("-rescan", true)) + { /* LogPrintf("AppInit2 : parameter interaction: -zapwallettxes=1 -> setting -rescan=1\n"); */ } + } + // ********************************************************* Step 3: parameter-to-internal-flags fDebug = GetBoolArg("-debug"); @@ -720,6 +727,17 @@ bool AppInit2() } // ********************************************************* Step 8: load wallet + if (GetBoolArg("-zapwallettxes", false)) { + uiInterface.InitMessage(_("Zapping all transactions from wallet...")); + pwalletMain = new CWallet("wallet.dat"); + 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...")); printf("Loading wallet...\n"); diff --git a/src/wallet.cpp b/src/wallet.cpp index bfe4dd5..7c2398f 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1799,6 +1799,28 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) return DB_LOAD_OK; } +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::SetAddressBookName(const CTxDestination& address, const string& strName) { diff --git a/src/wallet.h b/src/wallet.h index d48a747..9015c98 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -272,6 +272,8 @@ public: DBErrors LoadWallet(bool& fFirstRunRet); + DBErrors ZapWalletTx(); + bool SetAddressBookName(const CTxDestination& address, const std::string& strName); bool DelAddressBookName(const CTxDestination& address); diff --git a/src/walletdb.cpp b/src/walletdb.cpp index 96e8d51..e0f0f25 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -482,6 +482,83 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) return result; } +DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector& 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; + } + + return result; +} + +DBErrors CWalletDB::ZapWalletTx(CWallet* pwallet) +{ + // build list of wallet TXs + vector 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(void* parg) { // Make this thread recognisable as the wallet flushing thread diff --git a/src/walletdb.h b/src/walletdb.h index dc1ae64..4ccf87e 100644 --- a/src/walletdb.h +++ b/src/walletdb.h @@ -156,6 +156,8 @@ public: DBErrors ReorderTransactions(CWallet*); DBErrors LoadWallet(CWallet* pwallet); + DBErrors FindWalletTx(CWallet* pwallet, std::vector& vTxHash); + DBErrors ZapWalletTx(CWallet* pwallet); static bool Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys); static bool Recover(CDBEnv& dbenv, std::string filename); };