diff options
Diffstat (limited to 'src/validation.cpp')
-rw-r--r-- | src/validation.cpp | 89 |
1 files changed, 42 insertions, 47 deletions
diff --git a/src/validation.cpp b/src/validation.cpp index 3e51221a5e..512a3619ca 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -35,9 +35,9 @@ #include <txmempool.h> #include <ui_interface.h> #include <undo.h> -#include <util.h> -#include <utilmoneystr.h> -#include <utilstrencodings.h> +#include <util/system.h> +#include <util/moneystr.h> +#include <util/strencodings.h> #include <validationinterface.h> #include <warnings.h> @@ -217,8 +217,8 @@ CCriticalSection cs_main; BlockMap& mapBlockIndex = g_chainstate.mapBlockIndex; CChain& chainActive = g_chainstate.chainActive; CBlockIndex *pindexBestHeader = nullptr; -CWaitableCriticalSection g_best_block_mutex; -CConditionVariable g_best_block_cv; +Mutex g_best_block_mutex; +std::condition_variable g_best_block_cv; uint256 g_best_block; int nScriptCheckThreads = 0; std::atomic_bool fImporting(false); @@ -361,10 +361,10 @@ bool TestLockPointValidity(const LockPoints* lp) return true; } -bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool useExistingLockPoints) +bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flags, LockPoints* lp, bool useExistingLockPoints) { AssertLockHeld(cs_main); - AssertLockHeld(mempool.cs); + AssertLockHeld(pool.cs); CBlockIndex* tip = chainActive.Tip(); assert(tip != nullptr); @@ -387,7 +387,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool } else { // pcoinsTip contains the UTXO set for chainActive.Tip() - CCoinsViewMemPool viewMemPool(pcoinsTip.get(), mempool); + CCoinsViewMemPool viewMemPool(pcoinsTip.get(), pool); std::vector<int> prevheights; prevheights.resize(tx.vin.size()); for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) { @@ -421,7 +421,7 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool // lock on a mempool input, so we can use the return value of // CheckSequenceLocks to indicate the LockPoints validity int maxInputHeight = 0; - for (int height : prevheights) { + for (const int height : prevheights) { // Can ignore mempool inputs since we'll fail if they had non-zero locks if (height != tip->nHeight+1) { maxInputHeight = std::max(maxInputHeight, height); @@ -584,7 +584,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool // Do not work on transactions that are too small. // A transaction with 1 segwit input and 1 P2WPHK output has non-witness size of 82 bytes. // Transactions smaller than this are not relayed to reduce unnecessary malloc overhead. - if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) < MIN_STANDARD_TX_NONWITNESS_SIZE) + if (::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) < MIN_STANDARD_TX_NONWITNESS_SIZE) return state.DoS(0, false, REJECT_NONSTANDARD, "tx-size-small"); // Only accept nLockTime-using transactions that can be mined in the next @@ -602,10 +602,8 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool std::set<uint256> setConflicts; for (const CTxIn &txin : tx.vin) { - auto itConflicting = pool.mapNextTx.find(txin.prevout); - if (itConflicting != pool.mapNextTx.end()) - { - const CTransaction *ptxConflicting = itConflicting->second; + const CTransaction* ptxConflicting = pool.GetConflictTx(txin.prevout); + if (ptxConflicting) { if (!setConflicts.count(ptxConflicting->GetHash())) { // Allow opt-out of transaction replacement by setting @@ -681,7 +679,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool // be mined yet. // Must keep pool.cs for this unless we change CheckSequenceLocks to take a // CoinsViewCache instead of create its own - if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) + if (!CheckSequenceLocks(pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final"); CAmount nFees = 0; @@ -786,16 +784,8 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool CFeeRate newFeeRate(nModifiedFees, nSize); std::set<uint256> setConflictsParents; const int maxDescendantsToVisit = 100; - CTxMemPool::setEntries setIterConflicting; - for (const uint256 &hashConflicting : setConflicts) - { - CTxMemPool::txiter mi = pool.mapTx.find(hashConflicting); - if (mi == pool.mapTx.end()) - continue; - - // Save these to avoid repeated lookups - setIterConflicting.insert(mi); - + const CTxMemPool::setEntries setIterConflicting = pool.GetIterSet(setConflicts); + for (const auto& mi : setIterConflicting) { // Don't allow the replacement to reduce the feerate of the // mempool. // @@ -861,11 +851,12 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool // Rather than check the UTXO set - potentially expensive - // it's cheaper to just check if the new input refers to a // tx that's in the mempool. - if (pool.mapTx.find(tx.vin[j].prevout.hash) != pool.mapTx.end()) + if (pool.exists(tx.vin[j].prevout.hash)) { return state.DoS(0, false, REJECT_NONSTANDARD, "replacement-adds-unconfirmed", false, strprintf("replacement %s adds unconfirmed input, idx %d", hash.ToString(), j)); + } } } @@ -927,7 +918,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool // There is a similar check in CreateNewBlock() to prevent creating // invalid blocks (using TestBlockValidity), however allowing such // transactions into the mempool can be exploited as a DoS attack. - unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(chainActive.Tip(), Params().GetConsensus()); + unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(chainActive.Tip(), chainparams.GetConsensus()); if (!CheckInputsFromMempoolAndCache(tx, state, view, pool, currentBlockScriptVerifyFlags, true, txdata)) { return error("%s: BUG! PLEASE REPORT THIS! CheckInputs failed against latest-block but not STANDARD flags %s, %s", __func__, hash.ToString(), FormatStateMessage(state)); @@ -959,7 +950,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool bool validForFeeEstimation = !fReplacementTransaction && !bypass_limits && IsCurrentForFeeEstimation() && pool.HasNoInputsOf(tx); // Store transaction in memory - pool.addUnchecked(hash, entry, setAncestors, validForFeeEstimation); + pool.addUnchecked(entry, setAncestors, validForFeeEstimation); // trim mempool and check if tx was trimmed if (!bypass_limits) { @@ -1060,7 +1051,7 @@ static bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMes return error("WriteBlockToDisk: OpenBlockFile failed"); // Write index header - unsigned int nSize = GetSerializeSize(fileout, block); + unsigned int nSize = GetSerializeSize(block, fileout.GetVersion()); fileout << messageStart << nSize; // Write block @@ -1470,7 +1461,7 @@ bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint return error("%s: OpenUndoFile failed", __func__); // Write index header - unsigned int nSize = GetSerializeSize(fileout, blockundo); + unsigned int nSize = GetSerializeSize(blockundo, fileout.GetVersion()); fileout << messageStart << nSize; // Write undo data @@ -1668,7 +1659,7 @@ static bool WriteUndoDataForBlock(const CBlockUndo& blockundo, CValidationState& // Write undo information to disk if (pindex->GetUndoPos().IsNull()) { CDiskBlockPos _pos; - if (!FindUndoPos(state, pindex->nFile, _pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40)) + if (!FindUndoPos(state, pindex->nFile, _pos, ::GetSerializeSize(blockundo, CLIENT_VERSION) + 40)) return error("ConnectBlock(): FindUndoPos failed"); if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart())) return AbortNode(state, "Failed to write undo data"); @@ -1689,8 +1680,7 @@ void ThreadScriptCheck() { scriptcheckqueue.Thread(); } -// Protected by cs_main -VersionBitsCache versionbitscache; +VersionBitsCache versionbitscache GUARDED_BY(cs_main); int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params) { @@ -1731,8 +1721,7 @@ public: } }; -// Protected by cs_main -static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS]; +static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS] GUARDED_BY(cs_main); // 0.13.0 was shipped with a segwit deployment defined for testnet, but not for // mainnet. We no longer need to support disabling the segwit deployment @@ -2239,7 +2228,7 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar mempool.AddTransactionsUpdated(1); { - WaitableLock lock(g_best_block_mutex); + LOCK(g_best_block_mutex); g_best_block = pindexNew->GetBlockHash(); g_best_block_cv.notify_all(); } @@ -2448,7 +2437,7 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp if (!rv) { if (state.IsInvalid()) InvalidBlockFound(pindexNew, state); - return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); + return error("%s: ConnectBlock %s failed, %s", __func__, pindexNew->GetBlockHash().ToString(), FormatStateMessage(state)); } nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2; LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime3 - nTime2) * MILLI, nTimeConnectTotal * MICRO, nTimeConnectTotal * MILLI / nBlocksTotal); @@ -3119,7 +3108,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P // checks that use witness data may be performed here. // Size limits - if (block.vtx.empty() || block.vtx.size() * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT) + if (block.vtx.empty() || block.vtx.size() * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT || ::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT) return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed"); // First transaction must be coinbase, the rest must not be @@ -3131,7 +3120,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P // Check transactions for (const auto& tx : block.vtx) - if (!CheckTransaction(*tx, state, false)) + if (!CheckTransaction(*tx, state, true)) return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(), strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage())); @@ -3436,7 +3425,7 @@ bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidatio /** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */ static CDiskBlockPos SaveBlockToDisk(const CBlock& block, int nHeight, const CChainParams& chainparams, const CDiskBlockPos* dbp) { - unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); + unsigned int nBlockSize = ::GetSerializeSize(block, CLIENT_VERSION); CDiskBlockPos blockPos; if (dbp != nullptr) blockPos = *dbp; @@ -3541,12 +3530,14 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons CBlockIndex *pindex = nullptr; if (fNewBlock) *fNewBlock = false; CValidationState state; - // Ensure that CheckBlock() passes before calling AcceptBlock, as - // belt-and-suspenders. - bool ret = CheckBlock(*pblock, state, chainparams.GetConsensus()); + // CheckBlock() does not support multi-threaded block validation because CBlock::fChecked can cause data race. + // Therefore, the following critical section must include the CheckBlock() call as well. LOCK(cs_main); + // Ensure that CheckBlock() passes before calling AcceptBlock, as + // belt-and-suspenders. + bool ret = CheckBlock(*pblock, state, chainparams.GetConsensus()); if (ret) { // Store to disk ret = g_chainstate.AcceptBlock(pblock, state, chainparams, &pindex, fForceProcessing, nullptr, fNewBlock); @@ -4142,6 +4133,7 @@ bool CChainState::ReplayBlocks(const CChainParams& params, CCoinsView* view) for (int nHeight = nForkHeight + 1; nHeight <= pindexNew->nHeight; ++nHeight) { const CBlockIndex* pindex = pindexNew->GetAncestor(nHeight); LogPrintf("Rolling forward %s (%i)\n", pindex->GetBlockHash().ToString(), nHeight); + uiInterface.ShowProgress(_("Replaying blocks..."), (int) ((nHeight - nForkHeight) * 100.0 / (pindexNew->nHeight - nForkHeight)) , false); if (!RollforwardBlock(pindex, cache, params)) return false; } @@ -4291,7 +4283,7 @@ void UnloadBlockIndex() warningcache[b].clear(); } - for (BlockMap::value_type& entry : mapBlockIndex) { + for (const BlockMap::value_type& entry : mapBlockIndex) { delete entry.second; } mapBlockIndex.clear(); @@ -4492,7 +4484,7 @@ void CChainState::CheckBlockIndex(const Consensus::Params& consensusParams) // Build forward-pointing map of the entire block tree. std::multimap<CBlockIndex*,CBlockIndex*> forward; - for (auto& entry : mapBlockIndex) { + for (const std::pair<const uint256, CBlockIndex*>& entry : mapBlockIndex) { forward.insert(std::make_pair(entry.second->pprev, entry.second)); } @@ -4690,7 +4682,7 @@ int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::D static const uint64_t MEMPOOL_DUMP_VERSION = 1; -bool LoadMempool(void) +bool LoadMempool() { const CChainParams& chainparams = Params(); int64_t nExpiryTimeout = gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60; @@ -4767,13 +4759,16 @@ bool LoadMempool(void) return true; } -bool DumpMempool(void) +bool DumpMempool() { int64_t start = GetTimeMicros(); std::map<uint256, CAmount> mapDeltas; std::vector<TxMempoolInfo> vinfo; + static Mutex dump_mutex; + LOCK(dump_mutex); + { LOCK(mempool.cs); for (const auto &i : mempool.mapDeltas) { |