From 2461aba1ac4e0673ed0568713b48e4bb37c8b041 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sat, 3 Aug 2013 13:08:34 +0200 Subject: [PATCH] Mempool consistency check --- src/chainparams.h | 4 ++++ src/init.cpp | 1 + src/main.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/main.h | 2 ++ 4 files changed, 52 insertions(+) diff --git a/src/chainparams.h b/src/chainparams.h index 572712b58..2592ad1b1 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -99,4 +99,8 @@ inline bool TestNet() { return Params().NetworkID() == CChainParams::TESTNET; } +inline bool RegTest() { + return Params().NetworkID() == CChainParams::REGTEST; +} + #endif diff --git a/src/init.cpp b/src/init.cpp index 09871c012..9f3d52641 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -424,6 +424,7 @@ bool AppInit2(boost::thread_group& threadGroup) fDebug = GetBoolArg("-debug", false); fBenchmark = GetBoolArg("-benchmark", false); + mempool.fChecks = GetBoolArg("-checkmempool", RegTest()); // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency nScriptCheckThreads = GetArg("-par", 0); diff --git a/src/main.cpp b/src/main.cpp index 4c568245e..2ccd5131d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1014,6 +1014,45 @@ void CTxMemPool::clear() ++nTransactionsUpdated; } +bool CTxMemPool::fChecks = false; + +void CTxMemPool::check(CCoinsViewCache *pcoins) const +{ + if (!fChecks) + return; + + printf("Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); + + LOCK(cs); + for (std::map::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { + unsigned int i = 0; + BOOST_FOREACH(const CTxIn &txin, it->second.vin) { + // Check that every mempool transaction's inputs refer to available coins, or other mempool tx's. + std::map::const_iterator it2 = mapTx.find(txin.prevout.hash); + if (it2 != mapTx.end()) { + assert(it2->second.vout.size() > txin.prevout.n && !it2->second.vout[txin.prevout.n].IsNull()); + } else { + CCoins &coins = pcoins->GetCoins(txin.prevout.hash); + assert(coins.IsAvailable(txin.prevout.n)); + } + // Check whether its inputs are marked in mapNextTx. + std::map::const_iterator it3 = mapNextTx.find(txin.prevout); + assert(it3 != mapNextTx.end()); + assert(it3->second.ptx == &it->second); + assert(it3->second.n == i); + i++; + } + } + for (std::map::const_iterator it = mapNextTx.begin(); it != mapNextTx.end(); it++) { + uint256 hash = it->second.ptx->GetHash(); + std::map::const_iterator it2 = mapTx.find(hash); + assert(it2 != mapTx.end()); + assert(&it2->second == it->second.ptx); + assert(it2->second.vin.size() > it->second.n); + assert(it->first == it->second.ptx->vin[it->second.n].prevout); + } +} + void CTxMemPool::queryHashes(std::vector& vtxid) { vtxid.clear(); @@ -1970,6 +2009,8 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) { + mempool.check(pcoinsTip); + // All modifications to the coin state will be done in this cache. // Only when all have succeeded, we push it to pcoinsTip. CCoinsViewCache view(*pcoinsTip, true); @@ -2093,6 +2134,8 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew) mempool.removeConflicts(tx); } + mempool.check(pcoinsTip); + // Update best block in wallet (so we can detect restored wallets) if ((pindexNew->nHeight % 20160) == 0 || (!fIsInitialDownload && (pindexNew->nHeight % 144) == 0)) { @@ -3678,6 +3721,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) CValidationState state; if (mempool.accept(state, tx, true, &fMissingInputs)) { + mempool.check(pcoinsTip); RelayTransaction(tx, inv.hash); mapAlreadyAskedFor.erase(inv); vWorkQueue.push_back(inv.hash); @@ -3713,6 +3757,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) vEraseQueue.push_back(orphanHash); printf(" removed orphan tx %s\n", orphanHash.ToString().c_str()); } + mempool.check(pcoinsTip); } } diff --git a/src/main.h b/src/main.h index ea86a2bcc..a690a2bc9 100644 --- a/src/main.h +++ b/src/main.h @@ -1077,6 +1077,7 @@ public: class CTxMemPool { public: + static bool fChecks; mutable CCriticalSection cs; std::map mapTx; std::map mapNextTx; @@ -1088,6 +1089,7 @@ public: void clear(); void queryHashes(std::vector& vtxid); void pruneSpent(const uint256& hash, CCoins &coins); + void check(CCoinsViewCache *pcoins) const; unsigned long size() {