diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2013-08-03 13:08:34 +0200 |
---|---|---|
committer | Pieter Wuille <pieterw@google.com> | 2013-08-15 23:55:35 +0200 |
commit | 2461aba1ac4e0673ed0568713b48e4bb37c8b041 (patch) | |
tree | 354795fad656bcf84a1edb174b1538dba263bb32 /src/main.cpp | |
parent | f0784ac470a5541343e7985ceb0cb3c28d9a964e (diff) |
Mempool consistency check
Diffstat (limited to 'src/main.cpp')
-rw-r--r-- | src/main.cpp | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/src/main.cpp b/src/main.cpp index 4c568245e0..2ccd5131d1 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<uint256, CTransaction>::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<uint256, CTransaction>::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<COutPoint, CInPoint>::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<COutPoint, CInPoint>::const_iterator it = mapNextTx.begin(); it != mapNextTx.end(); it++) { + uint256 hash = it->second.ptx->GetHash(); + std::map<uint256, CTransaction>::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<uint256>& 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); } } |