Permalink
Cannot retrieve contributors at this time
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
5257 lines (4613 sloc)
232 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright (c) 2009-2010 Satoshi Nakamoto | |
// Copyright (c) 2009-2020 The Bitcoin Core developers | |
// Distributed under the MIT software license, see the accompanying | |
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | |
#include <validation.h> | |
#include <arith_uint256.h> | |
#include <chain.h> | |
#include <chainparams.h> | |
#include <checkqueue.h> | |
#include <consensus/consensus.h> | |
#include <consensus/merkle.h> | |
#include <consensus/tx_check.h> | |
#include <consensus/tx_verify.h> | |
#include <consensus/validation.h> | |
#include <cuckoocache.h> | |
#include <flatfile.h> | |
#include <hash.h> | |
#include <index/txindex.h> | |
#include <logging.h> | |
#include <logging/timer.h> | |
#include <optional.h> | |
#include <policy/fees.h> | |
#include <policy/policy.h> | |
#include <policy/settings.h> | |
#include <pow.h> | |
#include <primitives/block.h> | |
#include <primitives/transaction.h> | |
#include <random.h> | |
#include <reverse_iterator.h> | |
#include <script/script.h> | |
#include <script/sigcache.h> | |
#include <shutdown.h> | |
#include <timedata.h> | |
#include <tinyformat.h> | |
#include <txdb.h> | |
#include <txmempool.h> | |
#include <ui_interface.h> | |
#include <uint256.h> | |
#include <undo.h> | |
#include <util/moneystr.h> | |
#include <util/rbf.h> | |
#include <util/strencodings.h> | |
#include <util/system.h> | |
#include <util/translation.h> | |
#include <validationinterface.h> | |
#include <warnings.h> | |
#include <string> | |
#include <boost/algorithm/string/replace.hpp> | |
#include <boost/thread.hpp> | |
#if defined(NDEBUG) | |
# error "Bitcoin cannot be compiled without assertions." | |
#endif | |
#define MICRO 0.000001 | |
#define MILLI 0.001 | |
/** | |
* An extra transaction can be added to a package, as long as it only has one | |
* ancestor and is no larger than this. Not really any reason to make this | |
* configurable as it doesn't materially change DoS parameters. | |
*/ | |
static const unsigned int EXTRA_DESCENDANT_TX_SIZE_LIMIT = 10000; | |
/** Maximum kilobytes for transactions to store for processing during reorg */ | |
static const unsigned int MAX_DISCONNECTED_TX_POOL_SIZE = 20000; | |
/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */ | |
static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB | |
/** The pre-allocation chunk size for rev?????.dat files (since 0.8) */ | |
static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB | |
/** Time to wait (in seconds) between writing blocks/block index to disk. */ | |
static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60; | |
/** Time to wait (in seconds) between flushing chainstate to disk. */ | |
static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60; | |
/** Maximum age of our tip in seconds for us to be considered current for fee estimation */ | |
static const int64_t MAX_FEE_ESTIMATION_TIP_AGE = 3 * 60 * 60; | |
bool CBlockIndexWorkComparator::operator()(const CBlockIndex *pa, const CBlockIndex *pb) const { | |
// First sort by most total work, ... | |
if (pa->nChainWork > pb->nChainWork) return false; | |
if (pa->nChainWork < pb->nChainWork) return true; | |
// ... then by earliest time received, ... | |
if (pa->nSequenceId < pb->nSequenceId) return false; | |
if (pa->nSequenceId > pb->nSequenceId) return true; | |
// Use pointer address as tie breaker (should only happen with blocks | |
// loaded from disk, as those all have id 0). | |
if (pa < pb) return false; | |
if (pa > pb) return true; | |
// Identical blocks. | |
return false; | |
} | |
ChainstateManager g_chainman; | |
CChainState& ChainstateActive() | |
{ | |
LOCK(::cs_main); | |
assert(g_chainman.m_active_chainstate); | |
return *g_chainman.m_active_chainstate; | |
} | |
CChain& ChainActive() | |
{ | |
LOCK(::cs_main); | |
return ::ChainstateActive().m_chain; | |
} | |
/** | |
* Mutex to guard access to validation specific variables, such as reading | |
* or changing the chainstate. | |
* | |
* This may also need to be locked when updating the transaction pool, e.g. on | |
* AcceptToMemoryPool. See CTxMemPool::cs comment for details. | |
* | |
* The transaction pool has a separate lock to allow reading from it and the | |
* chainstate at the same time. | |
*/ | |
RecursiveMutex cs_main; | |
CBlockIndex *pindexBestHeader = nullptr; | |
Mutex g_best_block_mutex; | |
std::condition_variable g_best_block_cv; | |
uint256 g_best_block; | |
bool g_parallel_script_checks{false}; | |
std::atomic_bool fImporting(false); | |
std::atomic_bool fReindex(false); | |
bool fHavePruned = false; | |
bool fPruneMode = false; | |
bool fRequireStandard = true; | |
bool fCheckBlockIndex = false; | |
bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED; | |
size_t nCoinCacheUsage = 5000 * 300; | |
uint64_t nPruneTarget = 0; | |
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; | |
uint256 hashAssumeValid; | |
arith_uint256 nMinimumChainWork; | |
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); | |
CBlockPolicyEstimator feeEstimator; | |
CTxMemPool mempool(&feeEstimator); | |
// Internal stuff | |
namespace { | |
CBlockIndex* pindexBestInvalid = nullptr; | |
RecursiveMutex cs_LastBlockFile; | |
std::vector<CBlockFileInfo> vinfoBlockFile; | |
int nLastBlockFile = 0; | |
/** Global flag to indicate we should check to see if there are | |
* block/undo files that should be deleted. Set on startup | |
* or if we allocate more file space when we're in prune mode | |
*/ | |
bool fCheckForPruning = false; | |
/** Dirty block index entries. */ | |
std::set<CBlockIndex*> setDirtyBlockIndex; | |
/** Dirty block file entries. */ | |
std::set<int> setDirtyFileInfo; | |
} // anon namespace | |
CBlockIndex* LookupBlockIndex(const uint256& hash) | |
{ | |
AssertLockHeld(cs_main); | |
BlockMap::const_iterator it = g_chainman.BlockIndex().find(hash); | |
return it == g_chainman.BlockIndex().end() ? nullptr : it->second; | |
} | |
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) | |
{ | |
AssertLockHeld(cs_main); | |
// Find the latest block common to locator and chain - we expect that | |
// locator.vHave is sorted descending by height. | |
for (const uint256& hash : locator.vHave) { | |
CBlockIndex* pindex = LookupBlockIndex(hash); | |
if (pindex) { | |
if (chain.Contains(pindex)) | |
return pindex; | |
if (pindex->GetAncestor(chain.Height()) == chain.Tip()) { | |
return chain.Tip(); | |
} | |
} | |
} | |
return chain.Genesis(); | |
} | |
std::unique_ptr<CBlockTreeDB> pblocktree; | |
// See definition for documentation | |
static void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight); | |
static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight); | |
bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = nullptr); | |
static FILE* OpenUndoFile(const FlatFilePos &pos, bool fReadOnly = false); | |
static FlatFileSeq BlockFileSeq(); | |
static FlatFileSeq UndoFileSeq(); | |
bool CheckFinalTx(const CTransaction &tx, int flags) | |
{ | |
AssertLockHeld(cs_main); | |
// By convention a negative value for flags indicates that the | |
// current network-enforced consensus rules should be used. In | |
// a future soft-fork scenario that would mean checking which | |
// rules would be enforced for the next block and setting the | |
// appropriate flags. At the present time no soft-forks are | |
// scheduled, so no flags are set. | |
flags = std::max(flags, 0); | |
// CheckFinalTx() uses ::ChainActive().Height()+1 to evaluate | |
// nLockTime because when IsFinalTx() is called within | |
// CBlock::AcceptBlock(), the height of the block *being* | |
// evaluated is what is used. Thus if we want to know if a | |
// transaction can be part of the *next* block, we need to call | |
// IsFinalTx() with one more than ::ChainActive().Height(). | |
const int nBlockHeight = ::ChainActive().Height() + 1; | |
// BIP113 requires that time-locked transactions have nLockTime set to | |
// less than the median time of the previous block they're contained in. | |
// When the next block is created its previous block will be the current | |
// chain tip, so we use that to calculate the median time passed to | |
// IsFinalTx() if LOCKTIME_MEDIAN_TIME_PAST is set. | |
const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST) | |
? ::ChainActive().Tip()->GetMedianTimePast() | |
: GetAdjustedTime(); | |
return IsFinalTx(tx, nBlockHeight, nBlockTime); | |
} | |
bool TestLockPointValidity(const LockPoints* lp) | |
{ | |
AssertLockHeld(cs_main); | |
assert(lp); | |
// If there are relative lock times then the maxInputBlock will be set | |
// If there are no relative lock times, the LockPoints don't depend on the chain | |
if (lp->maxInputBlock) { | |
// Check whether ::ChainActive() is an extension of the block at which the LockPoints | |
// calculation was valid. If not LockPoints are no longer valid | |
if (!::ChainActive().Contains(lp->maxInputBlock)) { | |
return false; | |
} | |
} | |
// LockPoints still valid | |
return true; | |
} | |
bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flags, LockPoints* lp, bool useExistingLockPoints) | |
{ | |
AssertLockHeld(cs_main); | |
AssertLockHeld(pool.cs); | |
CBlockIndex* tip = ::ChainActive().Tip(); | |
assert(tip != nullptr); | |
CBlockIndex index; | |
index.pprev = tip; | |
// CheckSequenceLocks() uses ::ChainActive().Height()+1 to evaluate | |
// height based locks because when SequenceLocks() is called within | |
// ConnectBlock(), the height of the block *being* | |
// evaluated is what is used. | |
// Thus if we want to know if a transaction can be part of the | |
// *next* block, we need to use one more than ::ChainActive().Height() | |
index.nHeight = tip->nHeight + 1; | |
std::pair<int, int64_t> lockPair; | |
if (useExistingLockPoints) { | |
assert(lp); | |
lockPair.first = lp->height; | |
lockPair.second = lp->time; | |
} | |
else { | |
// CoinsTip() contains the UTXO set for ::ChainActive().Tip() | |
CCoinsViewMemPool viewMemPool(&::ChainstateActive().CoinsTip(), pool); | |
std::vector<int> prevheights; | |
prevheights.resize(tx.vin.size()); | |
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) { | |
const CTxIn& txin = tx.vin[txinIndex]; | |
Coin coin; | |
if (!viewMemPool.GetCoin(txin.prevout, coin)) { | |
return error("%s: Missing input", __func__); | |
} | |
if (coin.nHeight == MEMPOOL_HEIGHT) { | |
// Assume all mempool transaction confirm in the next block | |
prevheights[txinIndex] = tip->nHeight + 1; | |
} else { | |
prevheights[txinIndex] = coin.nHeight; | |
} | |
} | |
lockPair = CalculateSequenceLocks(tx, flags, &prevheights, index); | |
if (lp) { | |
lp->height = lockPair.first; | |
lp->time = lockPair.second; | |
// Also store the hash of the block with the highest height of | |
// all the blocks which have sequence locked prevouts. | |
// This hash needs to still be on the chain | |
// for these LockPoint calculations to be valid | |
// Note: It is impossible to correctly calculate a maxInputBlock | |
// if any of the sequence locked inputs depend on unconfirmed txs, | |
// except in the special case where the relative lock time/height | |
// is 0, which is equivalent to no sequence lock. Since we assume | |
// input height of tip+1 for mempool txs and test the resulting | |
// lockPair from CalculateSequenceLocks against tip+1. We know | |
// EvaluateSequenceLocks will fail if there was a non-zero sequence | |
// lock on a mempool input, so we can use the return value of | |
// CheckSequenceLocks to indicate the LockPoints validity | |
int maxInputHeight = 0; | |
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); | |
} | |
} | |
lp->maxInputBlock = tip->GetAncestor(maxInputHeight); | |
} | |
} | |
return EvaluateSequenceLocks(index, lockPair); | |
} | |
// Returns the script flags which should be checked for a given block | |
static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& chainparams); | |
static void LimitMempoolSize(CTxMemPool& pool, size_t limit, std::chrono::seconds age) | |
EXCLUSIVE_LOCKS_REQUIRED(pool.cs, ::cs_main) | |
{ | |
int expired = pool.Expire(GetTime<std::chrono::seconds>() - age); | |
if (expired != 0) { | |
LogPrint(BCLog::MEMPOOL, "Expired %i transactions from the memory pool\n", expired); | |
} | |
std::vector<COutPoint> vNoSpendsRemaining; | |
pool.TrimToSize(limit, &vNoSpendsRemaining); | |
for (const COutPoint& removed : vNoSpendsRemaining) | |
::ChainstateActive().CoinsTip().Uncache(removed); | |
} | |
static bool IsCurrentForFeeEstimation() EXCLUSIVE_LOCKS_REQUIRED(cs_main) | |
{ | |
AssertLockHeld(cs_main); | |
if (::ChainstateActive().IsInitialBlockDownload()) | |
return false; | |
if (::ChainActive().Tip()->GetBlockTime() < (GetTime() - MAX_FEE_ESTIMATION_TIP_AGE)) | |
return false; | |
if (::ChainActive().Height() < pindexBestHeader->nHeight - 1) | |
return false; | |
return true; | |
} | |
/* Make mempool consistent after a reorg, by re-adding or recursively erasing | |
* disconnected block transactions from the mempool, and also removing any | |
* other transactions from the mempool that are no longer valid given the new | |
* tip/height. | |
* | |
* Note: we assume that disconnectpool only contains transactions that are NOT | |
* confirmed in the current chain nor already in the mempool (otherwise, | |
* in-mempool descendants of such transactions would be removed). | |
* | |
* Passing fAddToMempool=false will skip trying to add the transactions back, | |
* and instead just erase from the mempool as needed. | |
*/ | |
static void UpdateMempoolForReorg(DisconnectedBlockTransactions& disconnectpool, bool fAddToMempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs) | |
{ | |
AssertLockHeld(cs_main); | |
std::vector<uint256> vHashUpdate; | |
// disconnectpool's insertion_order index sorts the entries from | |
// oldest to newest, but the oldest entry will be the last tx from the | |
// latest mined block that was disconnected. | |
// Iterate disconnectpool in reverse, so that we add transactions | |
// back to the mempool starting with the earliest transaction that had | |
// been previously seen in a block. | |
auto it = disconnectpool.queuedTx.get<insertion_order>().rbegin(); | |
while (it != disconnectpool.queuedTx.get<insertion_order>().rend()) { | |
// ignore validation errors in resurrected transactions | |
TxValidationState stateDummy; | |
if (!fAddToMempool || (*it)->IsCoinBase() || | |
!AcceptToMemoryPool(mempool, stateDummy, *it, | |
nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */)) { | |
// If the transaction doesn't make it in to the mempool, remove any | |
// transactions that depend on it (which would now be orphans). | |
mempool.removeRecursive(**it, MemPoolRemovalReason::REORG); | |
} else if (mempool.exists((*it)->GetHash())) { | |
vHashUpdate.push_back((*it)->GetHash()); | |
} | |
++it; | |
} | |
disconnectpool.queuedTx.clear(); | |
// AcceptToMemoryPool/addUnchecked all assume that new mempool entries have | |
// no in-mempool children, which is generally not true when adding | |
// previously-confirmed transactions back to the mempool. | |
// UpdateTransactionsFromBlock finds descendants of any transactions in | |
// the disconnectpool that were added back and cleans up the mempool state. | |
mempool.UpdateTransactionsFromBlock(vHashUpdate); | |
// We also need to remove any now-immature transactions | |
mempool.removeForReorg(&::ChainstateActive().CoinsTip(), ::ChainActive().Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); | |
// Re-limit mempool size, in case we added any transactions | |
LimitMempoolSize(mempool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); | |
} | |
// Used to avoid mempool polluting consensus critical paths if CCoinsViewMempool | |
// were somehow broken and returning the wrong scriptPubKeys | |
static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& view, const CTxMemPool& pool, | |
unsigned int flags, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | |
AssertLockHeld(cs_main); | |
// pool.cs should be locked already, but go ahead and re-take the lock here | |
// to enforce that mempool doesn't change between when we check the view | |
// and when we actually call through to CheckInputScripts | |
LOCK(pool.cs); | |
assert(!tx.IsCoinBase()); | |
for (const CTxIn& txin : tx.vin) { | |
const Coin& coin = view.AccessCoin(txin.prevout); | |
// AcceptToMemoryPoolWorker has already checked that the coins are | |
// available, so this shouldn't fail. If the inputs are not available | |
// here then return false. | |
if (coin.IsSpent()) return false; | |
// Check equivalence for available inputs. | |
const CTransactionRef& txFrom = pool.get(txin.prevout.hash); | |
if (txFrom) { | |
assert(txFrom->GetHash() == txin.prevout.hash); | |
assert(txFrom->vout.size() > txin.prevout.n); | |
assert(txFrom->vout[txin.prevout.n] == coin.out); | |
} else { | |
const Coin& coinFromDisk = ::ChainstateActive().CoinsTip().AccessCoin(txin.prevout); | |
assert(!coinFromDisk.IsSpent()); | |
assert(coinFromDisk.out == coin.out); | |
} | |
} | |
// Call CheckInputScripts() to cache signature and script validity against current tip consensus rules. | |
return CheckInputScripts(tx, state, view, flags, /* cacheSigStore = */ true, /* cacheFullSciptStore = */ true, txdata); | |
} | |
namespace { | |
class MemPoolAccept | |
{ | |
public: | |
MemPoolAccept(CTxMemPool& mempool) : m_pool(mempool), m_view(&m_dummy), m_viewmempool(&::ChainstateActive().CoinsTip(), m_pool), | |
m_limit_ancestors(gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT)), | |
m_limit_ancestor_size(gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000), | |
m_limit_descendants(gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT)), | |
m_limit_descendant_size(gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000) {} | |
// We put the arguments we're handed into a struct, so we can pass them | |
// around easier. | |
struct ATMPArgs { | |
const CChainParams& m_chainparams; | |
TxValidationState &m_state; | |
const int64_t m_accept_time; | |
std::list<CTransactionRef>* m_replaced_transactions; | |
const bool m_bypass_limits; | |
const CAmount& m_absurd_fee; | |
/* | |
* Return any outpoints which were not previously present in the coins | |
* cache, but were added as a result of validating the tx for mempool | |
* acceptance. This allows the caller to optionally remove the cache | |
* additions if the associated transaction ends up being rejected by | |
* the mempool. | |
*/ | |
std::vector<COutPoint>& m_coins_to_uncache; | |
const bool m_test_accept; | |
}; | |
// Single transaction acceptance | |
bool AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs& args) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |
private: | |
// All the intermediate state that gets passed between the various levels | |
// of checking a given transaction. | |
struct Workspace { | |
Workspace(const CTransactionRef& ptx) : m_ptx(ptx), m_hash(ptx->GetHash()) {} | |
std::set<uint256> m_conflicts; | |
CTxMemPool::setEntries m_all_conflicting; | |
CTxMemPool::setEntries m_ancestors; | |
std::unique_ptr<CTxMemPoolEntry> m_entry; | |
bool m_replacement_transaction; | |
CAmount m_modified_fees; | |
CAmount m_conflicting_fees; | |
size_t m_conflicting_size; | |
const CTransactionRef& m_ptx; | |
const uint256& m_hash; | |
}; | |
// Run the policy checks on a given transaction, excluding any script checks. | |
// Looks up inputs, calculates feerate, considers replacement, evaluates | |
// package limits, etc. As this function can be invoked for "free" by a peer, | |
// only tests that are fast should be done here (to avoid CPU DoS). | |
bool PreChecks(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs); | |
// Run the script checks using our policy flags. As this can be slow, we should | |
// only invoke this on transactions that have otherwise passed policy checks. | |
bool PolicyScriptChecks(ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |
// Re-run the script checks, using consensus flags, and try to cache the | |
// result in the scriptcache. This should be done after | |
// PolicyScriptChecks(). This requires that all inputs either be in our | |
// utxo set or in the mempool. | |
bool ConsensusScriptChecks(ATMPArgs& args, Workspace& ws, PrecomputedTransactionData &txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |
// Try to add the transaction to the mempool, removing any conflicts first. | |
// Returns true if the transaction is in the mempool after any size | |
// limiting is performed, false otherwise. | |
bool Finalize(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs); | |
// Compare a package's feerate against minimum allowed. | |
bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state) | |
{ | |
CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size); | |
if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) { | |
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee)); | |
} | |
if (package_fee < ::minRelayTxFee.GetFee(package_size)) { | |
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size))); | |
} | |
return true; | |
} | |
private: | |
CTxMemPool& m_pool; | |
CCoinsViewCache m_view; | |
CCoinsViewMemPool m_viewmempool; | |
CCoinsView m_dummy; | |
// The package limits in effect at the time of invocation. | |
const size_t m_limit_ancestors; | |
const size_t m_limit_ancestor_size; | |
// These may be modified while evaluating a transaction (eg to account for | |
// in-mempool conflicts; see below). | |
size_t m_limit_descendants; | |
size_t m_limit_descendant_size; | |
}; | |
bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) | |
{ | |
const CTransactionRef& ptx = ws.m_ptx; | |
const CTransaction& tx = *ws.m_ptx; | |
const uint256& hash = ws.m_hash; | |
// Copy/alias what we need out of args | |
TxValidationState &state = args.m_state; | |
const int64_t nAcceptTime = args.m_accept_time; | |
const bool bypass_limits = args.m_bypass_limits; | |
const CAmount& nAbsurdFee = args.m_absurd_fee; | |
std::vector<COutPoint>& coins_to_uncache = args.m_coins_to_uncache; | |
// Alias what we need out of ws | |
std::set<uint256>& setConflicts = ws.m_conflicts; | |
CTxMemPool::setEntries& allConflicting = ws.m_all_conflicting; | |
CTxMemPool::setEntries& setAncestors = ws.m_ancestors; | |
std::unique_ptr<CTxMemPoolEntry>& entry = ws.m_entry; | |
bool& fReplacementTransaction = ws.m_replacement_transaction; | |
CAmount& nModifiedFees = ws.m_modified_fees; | |
CAmount& nConflictingFees = ws.m_conflicting_fees; | |
size_t& nConflictingSize = ws.m_conflicting_size; | |
if (!CheckTransaction(tx, state)) | |
return false; // state filled in by CheckTransaction | |
// Coinbase is only valid in a block, not as a loose transaction | |
if (tx.IsCoinBase()) | |
return state.Invalid(TxValidationResult::TX_CONSENSUS, "coinbase"); | |
// Rather not work on nonstandard transactions (unless -testnet/-regtest) | |
std::string reason; | |
if (fRequireStandard && !IsStandardTx(tx, reason)) | |
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, reason); | |
// 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 mitigate CVE-2017-12842 by not relaying | |
// 64-byte transactions. | |
if (::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) < MIN_STANDARD_TX_NONWITNESS_SIZE) | |
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "tx-size-small"); | |
// Only accept nLockTime-using transactions that can be mined in the next | |
// block; we don't want our mempool filled up with transactions that can't | |
// be mined yet. | |
if (!CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS)) | |
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-final"); | |
// is it already in the memory pool? | |
if (m_pool.exists(hash)) { | |
return state.Invalid(TxValidationResult::TX_CONFLICT, "txn-already-in-mempool"); | |
} | |
// Check for conflicts with in-memory transactions | |
for (const CTxIn &txin : tx.vin) | |
{ | |
const CTransaction* ptxConflicting = m_pool.GetConflictTx(txin.prevout); | |
if (ptxConflicting) { | |
if (!setConflicts.count(ptxConflicting->GetHash())) | |
{ | |
// Allow opt-out of transaction replacement by setting | |
// nSequence > MAX_BIP125_RBF_SEQUENCE (SEQUENCE_FINAL-2) on all inputs. | |
// | |
// SEQUENCE_FINAL-1 is picked to still allow use of nLockTime by | |
// non-replaceable transactions. All inputs rather than just one | |
// is for the sake of multi-party protocols, where we don't | |
// want a single party to be able to disable replacement. | |
// | |
// The opt-out ignores descendants as anyone relying on | |
// first-seen mempool behavior should be checking all | |
// unconfirmed ancestors anyway; doing otherwise is hopelessly | |
// insecure. | |
bool fReplacementOptOut = true; | |
for (const CTxIn &_txin : ptxConflicting->vin) | |
{ | |
if (_txin.nSequence <= MAX_BIP125_RBF_SEQUENCE) | |
{ | |
fReplacementOptOut = false; | |
break; | |
} | |
} | |
if (fReplacementOptOut) { | |
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "txn-mempool-conflict"); | |
} | |
setConflicts.insert(ptxConflicting->GetHash()); | |
} | |
} | |
} | |
LockPoints lp; | |
m_view.SetBackend(m_viewmempool); | |
CCoinsViewCache& coins_cache = ::ChainstateActive().CoinsTip(); | |
// do all inputs exist? | |
for (const CTxIn& txin : tx.vin) { | |
if (!coins_cache.HaveCoinInCache(txin.prevout)) { | |
coins_to_uncache.push_back(txin.prevout); | |
} | |
// Note: this call may add txin.prevout to the coins cache | |
// (coins_cache.cacheCoins) by way of FetchCoin(). It should be removed | |
// later (via coins_to_uncache) if this tx turns out to be invalid. | |
if (!m_view.HaveCoin(txin.prevout)) { | |
// Are inputs missing because we already have the tx? | |
for (size_t out = 0; out < tx.vout.size(); out++) { | |
// Optimistically just do efficient check of cache for outputs | |
if (coins_cache.HaveCoinInCache(COutPoint(hash, out))) { | |
return state.Invalid(TxValidationResult::TX_CONFLICT, "txn-already-known"); | |
} | |
} | |
// Otherwise assume this might be an orphan tx for which we just haven't seen parents yet | |
return state.Invalid(TxValidationResult::TX_MISSING_INPUTS, "bad-txns-inputs-missingorspent"); | |
} | |
} | |
// Bring the best block into scope | |
m_view.GetBestBlock(); | |
// we have all inputs cached now, so switch back to dummy (to protect | |
// against bugs where we pull more inputs from disk that miss being added | |
// to coins_to_uncache) | |
m_view.SetBackend(m_dummy); | |
// Only accept BIP68 sequence locked transactions that can be mined in the next | |
// block; we don't want our mempool filled up with transactions that can't | |
// be mined yet. | |
// Must keep pool.cs for this unless we change CheckSequenceLocks to take a | |
// CoinsViewCache instead of create its own | |
if (!CheckSequenceLocks(m_pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) | |
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-BIP68-final"); | |
CAmount nFees = 0; | |
if (!Consensus::CheckTxInputs(tx, state, m_view, GetSpendHeight(m_view), nFees)) { | |
return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), state.ToString()); | |
} | |
// Check for non-standard pay-to-script-hash in inputs | |
if (fRequireStandard && !AreInputsStandard(tx, m_view)) | |
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "bad-txns-nonstandard-inputs"); | |
// Check for non-standard witness in P2WSH | |
if (tx.HasWitness() && fRequireStandard && !IsWitnessStandard(tx, m_view)) | |
return state.Invalid(TxValidationResult::TX_WITNESS_MUTATED, "bad-witness-nonstandard"); | |
int64_t nSigOpsCost = GetTransactionSigOpCost(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS); | |
// nModifiedFees includes any fee deltas from PrioritiseTransaction | |
nModifiedFees = nFees; | |
m_pool.ApplyDelta(hash, nModifiedFees); | |
// Keep track of transactions that spend a coinbase, which we re-scan | |
// during reorgs to ensure COINBASE_MATURITY is still met. | |
bool fSpendsCoinbase = false; | |
for (const CTxIn &txin : tx.vin) { | |
const Coin &coin = m_view.AccessCoin(txin.prevout); | |
if (coin.IsCoinBase()) { | |
fSpendsCoinbase = true; | |
break; | |
} | |
} | |
entry.reset(new CTxMemPoolEntry(ptx, nFees, nAcceptTime, ::ChainActive().Height(), | |
fSpendsCoinbase, nSigOpsCost, lp)); | |
unsigned int nSize = entry->GetTxSize(); | |
if (nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST) | |
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "bad-txns-too-many-sigops", | |
strprintf("%d", nSigOpsCost)); | |
// No transactions are allowed below minRelayTxFee except from disconnected | |
// blocks | |
if (!bypass_limits && !CheckFeeRate(nSize, nModifiedFees, state)) return false; | |
if (nAbsurdFee && nFees > nAbsurdFee) | |
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, | |
"absurdly-high-fee", strprintf("%d > %d", nFees, nAbsurdFee)); | |
const CTxMemPool::setEntries setIterConflicting = m_pool.GetIterSet(setConflicts); | |
// Calculate in-mempool ancestors, up to a limit. | |
if (setConflicts.size() == 1) { | |
// In general, when we receive an RBF transaction with mempool conflicts, we want to know whether we | |
// would meet the chain limits after the conflicts have been removed. However, there isn't a practical | |
// way to do this short of calculating the ancestor and descendant sets with an overlay cache of | |
// changed mempool entries. Due to both implementation and runtime complexity concerns, this isn't | |
// very realistic, thus we only ensure a limited set of transactions are RBF'able despite mempool | |
// conflicts here. Importantly, we need to ensure that some transactions which were accepted using | |
// the below carve-out are able to be RBF'ed, without impacting the security the carve-out provides | |
// for off-chain contract systems (see link in the comment below). | |
// | |
// Specifically, the subset of RBF transactions which we allow despite chain limits are those which | |
// conflict directly with exactly one other transaction (but may evict children of said transaction), | |
// and which are not adding any new mempool dependencies. Note that the "no new mempool dependencies" | |
// check is accomplished later, so we don't bother doing anything about it here, but if BIP 125 is | |
// amended, we may need to move that check to here instead of removing it wholesale. | |
// | |
// Such transactions are clearly not merging any existing packages, so we are only concerned with | |
// ensuring that (a) no package is growing past the package size (not count) limits and (b) we are | |
// not allowing something to effectively use the (below) carve-out spot when it shouldn't be allowed | |
// to. | |
// | |
// To check these we first check if we meet the RBF criteria, above, and increment the descendant | |
// limits by the direct conflict and its descendants (as these are recalculated in | |
// CalculateMempoolAncestors by assuming the new transaction being added is a new descendant, with no | |
// removals, of each parent's existing dependent set). The ancestor count limits are unmodified (as | |
// the ancestor limits should be the same for both our new transaction and any conflicts). | |
// We don't bother incrementing m_limit_descendants by the full removal count as that limit never comes | |
// into force here (as we're only adding a single transaction). | |
assert(setIterConflicting.size() == 1); | |
CTxMemPool::txiter conflict = *setIterConflicting.begin(); | |
m_limit_descendants += 1; | |
m_limit_descendant_size += conflict->GetSizeWithDescendants(); | |
} | |
std::string errString; | |
if (!m_pool.CalculateMemPoolAncestors(*entry, setAncestors, m_limit_ancestors, m_limit_ancestor_size, m_limit_descendants, m_limit_descendant_size, errString)) { | |
setAncestors.clear(); | |
// If CalculateMemPoolAncestors fails second time, we want the original error string. | |
std::string dummy_err_string; | |
// Contracting/payment channels CPFP carve-out: | |
// If the new transaction is relatively small (up to 40k weight) | |
// and has at most one ancestor (ie ancestor limit of 2, including | |
// the new transaction), allow it if its parent has exactly the | |
// descendant limit descendants. | |
// | |
// This allows protocols which rely on distrusting counterparties | |
// being able to broadcast descendants of an unconfirmed transaction | |
// to be secure by simply only having two immediately-spendable | |
// outputs - one for each counterparty. For more info on the uses for | |
// this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html | |
if (nSize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || | |
!m_pool.CalculateMemPoolAncestors(*entry, setAncestors, 2, m_limit_ancestor_size, m_limit_descendants + 1, m_limit_descendant_size + EXTRA_DESCENDANT_TX_SIZE_LIMIT, dummy_err_string)) { | |
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too-long-mempool-chain", errString); | |
} | |
} | |
// A transaction that spends outputs that would be replaced by it is invalid. Now | |
// that we have the set of all ancestors we can detect this | |
// pathological case by making sure setConflicts and setAncestors don't | |
// intersect. | |
for (CTxMemPool::txiter ancestorIt : setAncestors) | |
{ | |
const uint256 &hashAncestor = ancestorIt->GetTx().GetHash(); | |
if (setConflicts.count(hashAncestor)) | |
{ | |
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-spends-conflicting-tx", | |
strprintf("%s spends conflicting transaction %s", | |
hash.ToString(), | |
hashAncestor.ToString())); | |
} | |
} | |
// Check if it's economically rational to mine this transaction rather | |
// than the ones it replaces. | |
nConflictingFees = 0; | |
nConflictingSize = 0; | |
uint64_t nConflictingCount = 0; | |
// If we don't hold the lock allConflicting might be incomplete; the | |
// subsequent RemoveStaged() and addUnchecked() calls don't guarantee | |
// mempool consistency for us. | |
fReplacementTransaction = setConflicts.size(); | |
if (fReplacementTransaction) | |
{ | |
CFeeRate newFeeRate(nModifiedFees, nSize); | |
std::set<uint256> setConflictsParents; | |
const int maxDescendantsToVisit = 100; | |
for (const auto& mi : setIterConflicting) { | |
// Don't allow the replacement to reduce the feerate of the | |
// mempool. | |
// | |
// We usually don't want to accept replacements with lower | |
// feerates than what they replaced as that would lower the | |
// feerate of the next block. Requiring that the feerate always | |
// be increased is also an easy-to-reason about way to prevent | |
// DoS attacks via replacements. | |
// | |
// We only consider the feerates of transactions being directly | |
// replaced, not their indirect descendants. While that does | |
// mean high feerate children are ignored when deciding whether | |
// or not to replace, we do require the replacement to pay more | |
// overall fees too, mitigating most cases. | |
CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize()); | |
if (newFeeRate <= oldFeeRate) | |
{ | |
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee", | |
strprintf("rejecting replacement %s; new feerate %s <= old feerate %s", | |
hash.ToString(), | |
newFeeRate.ToString(), | |
oldFeeRate.ToString())); | |
} | |
for (const CTxIn &txin : mi->GetTx().vin) | |
{ | |
setConflictsParents.insert(txin.prevout.hash); | |
} | |
nConflictingCount += mi->GetCountWithDescendants(); | |
} | |
// This potentially overestimates the number of actual descendants | |
// but we just want to be conservative to avoid doing too much | |
// work. | |
if (nConflictingCount <= maxDescendantsToVisit) { | |
// If not too many to replace, then calculate the set of | |
// transactions that would have to be evicted | |
for (CTxMemPool::txiter it : setIterConflicting) { | |
m_pool.CalculateDescendants(it, allConflicting); | |
} | |
for (CTxMemPool::txiter it : allConflicting) { | |
nConflictingFees += it->GetModifiedFee(); | |
nConflictingSize += it->GetTxSize(); | |
} | |
} else { | |
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "too many potential replacements", | |
strprintf("rejecting replacement %s; too many potential replacements (%d > %d)\n", | |
hash.ToString(), | |
nConflictingCount, | |
maxDescendantsToVisit)); | |
} | |
for (unsigned int j = 0; j < tx.vin.size(); j++) | |
{ | |
// We don't want to accept replacements that require low | |
// feerate junk to be mined first. Ideally we'd keep track of | |
// the ancestor feerates and make the decision based on that, | |
// but for now requiring all new inputs to be confirmed works. | |
// | |
// Note that if you relax this to make RBF a little more useful, | |
// this may break the CalculateMempoolAncestors RBF relaxation, | |
// above. See the comment above the first CalculateMempoolAncestors | |
// call for more info. | |
if (!setConflictsParents.count(tx.vin[j].prevout.hash)) | |
{ | |
// 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 (m_pool.exists(tx.vin[j].prevout.hash)) { | |
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "replacement-adds-unconfirmed", | |
strprintf("replacement %s adds unconfirmed input, idx %d", | |
hash.ToString(), j)); | |
} | |
} | |
} | |
// The replacement must pay greater fees than the transactions it | |
// replaces - if we did the bandwidth used by those conflicting | |
// transactions would not be paid for. | |
if (nModifiedFees < nConflictingFees) | |
{ | |
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee", | |
strprintf("rejecting replacement %s, less fees than conflicting txs; %s < %s", | |
hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees))); | |
} | |
// Finally in addition to paying more fees than the conflicts the | |
// new transaction must pay for its own bandwidth. | |
CAmount nDeltaFees = nModifiedFees - nConflictingFees; | |
if (nDeltaFees < ::incrementalRelayFee.GetFee(nSize)) | |
{ | |
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee", | |
strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s", | |
hash.ToString(), | |
FormatMoney(nDeltaFees), | |
FormatMoney(::incrementalRelayFee.GetFee(nSize)))); | |
} | |
} | |
return true; | |
} | |
bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata) | |
{ | |
const CTransaction& tx = *ws.m_ptx; | |
TxValidationState &state = args.m_state; | |
constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS; | |
// Check input scripts and signatures. | |
// This is done last to help prevent CPU exhaustion denial-of-service attacks. | |
if (!CheckInputScripts(tx, state, m_view, scriptVerifyFlags, true, false, txdata)) { | |
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we | |
// need to turn both off, and compare against just turning off CLEANSTACK | |
// to see if the failure is specifically due to witness validation. | |
TxValidationState state_dummy; // Want reported failures to be from first CheckInputScripts | |
if (!tx.HasWitness() && CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, txdata) && | |
!CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, txdata)) { | |
// Only the witness is missing, so the transaction itself may be fine. | |
state.Invalid(TxValidationResult::TX_WITNESS_MUTATED, | |
state.GetRejectReason(), state.GetDebugMessage()); | |
} | |
return false; // state filled in by CheckInputScripts | |
} | |
return true; | |
} | |
bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs& args, Workspace& ws, PrecomputedTransactionData& txdata) | |
{ | |
const CTransaction& tx = *ws.m_ptx; | |
const uint256& hash = ws.m_hash; | |
TxValidationState &state = args.m_state; | |
const CChainParams& chainparams = args.m_chainparams; | |
// Check again against the current block tip's script verification | |
// flags to cache our script execution flags. This is, of course, | |
// useless if the next block has different script flags from the | |
// previous one, but because the cache tracks script flags for us it | |
// will auto-invalidate and we'll just have a few blocks of extra | |
// misses on soft-fork activation. | |
// | |
// This is also useful in case of bugs in the standard flags that cause | |
// transactions to pass as valid when they're actually invalid. For | |
// instance the STRICTENC flag was incorrectly allowing certain | |
// CHECKSIG NOT scripts to pass, even though they were invalid. | |
// | |
// 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(), chainparams.GetConsensus()); | |
if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags, txdata)) { | |
return error("%s: BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s", | |
__func__, hash.ToString(), state.ToString()); | |
} | |
return true; | |
} | |
bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws) | |
{ | |
const CTransaction& tx = *ws.m_ptx; | |
const uint256& hash = ws.m_hash; | |
TxValidationState &state = args.m_state; | |
const bool bypass_limits = args.m_bypass_limits; | |
CTxMemPool::setEntries& allConflicting = ws.m_all_conflicting; | |
CTxMemPool::setEntries& setAncestors = ws.m_ancestors; | |
const CAmount& nModifiedFees = ws.m_modified_fees; | |
const CAmount& nConflictingFees = ws.m_conflicting_fees; | |
const size_t& nConflictingSize = ws.m_conflicting_size; | |
const bool fReplacementTransaction = ws.m_replacement_transaction; | |
std::unique_ptr<CTxMemPoolEntry>& entry = ws.m_entry; | |
// Remove conflicting transactions from the mempool | |
for (CTxMemPool::txiter it : allConflicting) | |
{ | |
LogPrint(BCLog::MEMPOOL, "replacing tx %s with %s for %s additional fees, %d delta bytes\n", | |
it->GetTx().GetHash().ToString(), | |
hash.ToString(), | |
FormatMoney(nModifiedFees - nConflictingFees), | |
(int)entry->GetTxSize() - (int)nConflictingSize); | |
if (args.m_replaced_transactions) | |
args.m_replaced_transactions->push_back(it->GetSharedTx()); | |
} | |
m_pool.RemoveStaged(allConflicting, false, MemPoolRemovalReason::REPLACED); | |
// This transaction should only count for fee estimation if: | |
// - it isn't a BIP 125 replacement transaction (may not be widely supported) | |
// - it's not being re-added during a reorg which bypasses typical mempool fee limits | |
// - the node is not behind | |
// - the transaction is not dependent on any other transactions in the mempool | |
bool validForFeeEstimation = !fReplacementTransaction && !bypass_limits && IsCurrentForFeeEstimation() && m_pool.HasNoInputsOf(tx); | |
// Store transaction in memory | |
m_pool.addUnchecked(*entry, setAncestors, validForFeeEstimation); | |
// trim mempool and check if tx was trimmed | |
if (!bypass_limits) { | |
LimitMempoolSize(m_pool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); | |
if (!m_pool.exists(hash)) | |
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool full"); | |
} | |
return true; | |
} | |
bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs& args) | |
{ | |
AssertLockHeld(cs_main); | |
LOCK(m_pool.cs); // mempool "read lock" (held through GetMainSignals().TransactionAddedToMempool()) | |
Workspace workspace(ptx); | |
if (!PreChecks(args, workspace)) return false; | |
// Only compute the precomputed transaction data if we need to verify | |
// scripts (ie, other policy checks pass). We perform the inexpensive | |
// checks first and avoid hashing and signature verification unless those | |
// checks pass, to mitigate CPU exhaustion denial-of-service attacks. | |
PrecomputedTransactionData txdata; | |
if (!PolicyScriptChecks(args, workspace, txdata)) return false; | |
if (!ConsensusScriptChecks(args, workspace, txdata)) return false; | |
// Tx was accepted, but not added | |
if (args.m_test_accept) return true; | |
if (!Finalize(args, workspace)) return false; | |
GetMainSignals().TransactionAddedToMempool(ptx); | |
return true; | |
} | |
} // anon namespace | |
/** (try to) add transaction to memory pool with a specified acceptance time **/ | |
static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx, | |
int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced, | |
bool bypass_limits, const CAmount nAbsurdFee, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main) | |
{ | |
std::vector<COutPoint> coins_to_uncache; | |
MemPoolAccept::ATMPArgs args { chainparams, state, nAcceptTime, plTxnReplaced, bypass_limits, nAbsurdFee, coins_to_uncache, test_accept }; | |
bool res = MemPoolAccept(pool).AcceptSingleTransaction(tx, args); | |
if (!res) { | |
// Remove coins that were not present in the coins cache before calling ATMPW; | |
// this is to prevent memory DoS in case we receive a large number of | |
// invalid transactions that attempt to overrun the in-memory coins cache | |
// (`CCoinsViewCache::cacheCoins`). | |
for (const COutPoint& hashTx : coins_to_uncache) | |
::ChainstateActive().CoinsTip().Uncache(hashTx); | |
} | |
// After we've (potentially) uncached entries, ensure our coins cache is still within its size limits | |
BlockValidationState state_dummy; | |
::ChainstateActive().FlushStateToDisk(chainparams, state_dummy, FlushStateMode::PERIODIC); | |
return res; | |
} | |
bool AcceptToMemoryPool(CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx, | |
std::list<CTransactionRef>* plTxnReplaced, | |
bool bypass_limits, const CAmount nAbsurdFee, bool test_accept) | |
{ | |
const CChainParams& chainparams = Params(); | |
return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, GetTime(), plTxnReplaced, bypass_limits, nAbsurdFee, test_accept); | |
} | |
/** | |
* Return transaction in txOut, and if it was found inside a block, its hash is placed in hashBlock. | |
* If blockIndex is provided, the transaction is fetched from the corresponding block. | |
*/ | |
bool GetTransaction(const uint256& hash, CTransactionRef& txOut, const Consensus::Params& consensusParams, uint256& hashBlock, const CBlockIndex* const block_index) | |
{ | |
LOCK(cs_main); | |
if (!block_index) { | |
CTransactionRef ptx = mempool.get(hash); | |
if (ptx) { | |
txOut = ptx; | |
return true; | |
} | |
if (g_txindex) { | |
return g_txindex->FindTx(hash, hashBlock, txOut); | |
} | |
} else { | |
CBlock block; | |
if (ReadBlockFromDisk(block, block_index, consensusParams)) { | |
for (const auto& tx : block.vtx) { | |
if (tx->GetHash() == hash) { | |
txOut = tx; | |
hashBlock = block_index->GetBlockHash(); | |
return true; | |
} | |
} | |
} | |
} | |
return false; | |
} | |
////////////////////////////////////////////////////////////////////////////// | |
// | |
// CBlock and CBlockIndex | |
// | |
static bool WriteBlockToDisk(const CBlock& block, FlatFilePos& pos, const CMessageHeader::MessageStartChars& messageStart) | |
{ | |
// Open history file to append | |
CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); | |
if (fileout.IsNull()) | |
return error("WriteBlockToDisk: OpenBlockFile failed"); | |
// Write index header | |
unsigned int nSize = GetSerializeSize(block, fileout.GetVersion()); | |
fileout << messageStart << nSize; | |
// Write block | |
long fileOutPos = ftell(fileout.Get()); | |
if (fileOutPos < 0) | |
return error("WriteBlockToDisk: ftell failed"); | |
pos.nPos = (unsigned int)fileOutPos; | |
fileout << block; | |
return true; | |
} | |
bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::Params& consensusParams) | |
{ | |
block.SetNull(); | |
// Open history file to read | |
CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); | |
if (filein.IsNull()) | |
return error("ReadBlockFromDisk: OpenBlockFile failed for %s", pos.ToString()); | |
// Read block | |
try { | |
filein >> block; | |
} | |
catch (const std::exception& e) { | |
return error("%s: Deserialize or I/O error - %s at %s", __func__, e.what(), pos.ToString()); | |
} | |
// Check the header | |
if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) | |
return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); | |
return true; | |
} | |
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams) | |
{ | |
FlatFilePos blockPos; | |
{ | |
LOCK(cs_main); | |
blockPos = pindex->GetBlockPos(); | |
} | |
if (!ReadBlockFromDisk(block, blockPos, consensusParams)) | |
return false; | |
if (block.GetHash() != pindex->GetBlockHash()) | |
return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s", | |
pindex->ToString(), pindex->GetBlockPos().ToString()); | |
return true; | |
} | |
bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start) | |
{ | |
FlatFilePos hpos = pos; | |
hpos.nPos -= 8; // Seek back 8 bytes for meta header | |
CAutoFile filein(OpenBlockFile(hpos, true), SER_DISK, CLIENT_VERSION); | |
if (filein.IsNull()) { | |
return error("%s: OpenBlockFile failed for %s", __func__, pos.ToString()); | |
} | |
try { | |
CMessageHeader::MessageStartChars blk_start; | |
unsigned int blk_size; | |
filein >> blk_start >> blk_size; | |
if (memcmp(blk_start, message_start, CMessageHeader::MESSAGE_START_SIZE)) { | |
return error("%s: Block magic mismatch for %s: %s versus expected %s", __func__, pos.ToString(), | |
HexStr(blk_start, blk_start + CMessageHeader::MESSAGE_START_SIZE), | |
HexStr(message_start, message_start + CMessageHeader::MESSAGE_START_SIZE)); | |
} | |
if (blk_size > MAX_SIZE) { | |
return error("%s: Block data is larger than maximum deserialization size for %s: %s versus %s", __func__, pos.ToString(), | |
blk_size, MAX_SIZE); | |
} | |
block.resize(blk_size); // Zeroing of memory is intentional here | |
filein.read((char*)block.data(), blk_size); | |
} catch(const std::exception& e) { | |
return error("%s: Read from block file failed: %s for %s", __func__, e.what(), pos.ToString()); | |
} | |
return true; | |
} | |
bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const CBlockIndex* pindex, const CMessageHeader::MessageStartChars& message_start) | |
{ | |
FlatFilePos block_pos; | |
{ | |
LOCK(cs_main); | |
block_pos = pindex->GetBlockPos(); | |
} | |
return ReadRawBlockFromDisk(block, block_pos, message_start); | |
} | |
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) | |
{ | |
int halvings = nHeight / consensusParams.nSubsidyHalvingInterval; | |
// Force block reward to zero when right shift is undefined. | |
if (halvings >= 64) | |
return 0; | |
CAmount nSubsidy = 50 * COIN; | |
// Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years. | |
nSubsidy >>= halvings; | |
return nSubsidy; | |
} | |
CoinsViews::CoinsViews( | |
std::string ldb_name, | |
size_t cache_size_bytes, | |
bool in_memory, | |
bool should_wipe) : m_dbview( | |
GetDataDir() / ldb_name, cache_size_bytes, in_memory, should_wipe), | |
m_catcherview(&m_dbview) {} | |
void CoinsViews::InitCache() | |
{ | |
m_cacheview = MakeUnique<CCoinsViewCache>(&m_catcherview); | |
} | |
CChainState::CChainState(BlockManager& blockman, uint256 from_snapshot_blockhash) | |
: m_blockman(blockman), | |
m_from_snapshot_blockhash(from_snapshot_blockhash) {} | |
void CChainState::InitCoinsDB( | |
size_t cache_size_bytes, | |
bool in_memory, | |
bool should_wipe, | |
std::string leveldb_name) | |
{ | |
if (!m_from_snapshot_blockhash.IsNull()) { | |
leveldb_name += "_" + m_from_snapshot_blockhash.ToString(); | |
} | |
m_coins_views = MakeUnique<CoinsViews>( | |
leveldb_name, cache_size_bytes, in_memory, should_wipe); | |
} | |
void CChainState::InitCoinsCache() | |
{ | |
assert(m_coins_views != nullptr); | |
m_coins_views->InitCache(); | |
} | |
// Note that though this is marked const, we may end up modifying `m_cached_finished_ibd`, which | |
// is a performance-related implementation detail. This function must be marked | |
// `const` so that `CValidationInterface` clients (which are given a `const CChainState*`) | |
// can call it. | |
// | |
bool CChainState::IsInitialBlockDownload() const | |
{ | |
// Optimization: pre-test latch before taking the lock. | |
if (m_cached_finished_ibd.load(std::memory_order_relaxed)) | |
return false; | |
LOCK(cs_main); | |
if (m_cached_finished_ibd.load(std::memory_order_relaxed)) | |
return false; | |
if (fImporting || fReindex) | |
return true; | |
if (m_chain.Tip() == nullptr) | |
return true; | |
if (m_chain.Tip()->nChainWork < nMinimumChainWork) | |
return true; | |
if (m_chain.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge)) | |
return true; | |
LogPrintf("Leaving InitialBlockDownload (latching to false)\n"); | |
m_cached_finished_ibd.store(true, std::memory_order_relaxed); | |
return false; | |
} | |
static CBlockIndex *pindexBestForkTip = nullptr, *pindexBestForkBase = nullptr; | |
BlockMap& BlockIndex() | |
{ | |
LOCK(::cs_main); | |
return g_chainman.m_blockman.m_block_index; | |
} | |
static void AlertNotify(const std::string& strMessage) | |
{ | |
uiInterface.NotifyAlertChanged(); | |
#if HAVE_SYSTEM | |
std::string strCmd = gArgs.GetArg("-alertnotify", ""); | |
if (strCmd.empty()) return; | |
// Alert text should be plain ascii coming from a trusted source, but to | |
// be safe we first strip anything not in safeChars, then add single quotes around | |
// the whole string before passing it to the shell: | |
std::string singleQuote("'"); | |
std::string safeStatus = SanitizeString(strMessage); | |
safeStatus = singleQuote+safeStatus+singleQuote; | |
boost::replace_all(strCmd, "%s", safeStatus); | |
std::thread t(runCommand, strCmd); | |
t.detach(); // thread runs free | |
#endif | |
} | |
static void CheckForkWarningConditions() EXCLUSIVE_LOCKS_REQUIRED(cs_main) | |
{ | |
AssertLockHeld(cs_main); | |
// Before we get past initial download, we cannot reliably alert about forks | |
// (we assume we don't get stuck on a fork before finishing our initial sync) | |
if (::ChainstateActive().IsInitialBlockDownload()) | |
return; | |
// If our best fork is no longer within 72 blocks (+/- 12 hours if no one mines it) | |
// of our head, drop it | |
if (pindexBestForkTip && ::ChainActive().Height() - pindexBestForkTip->nHeight >= 72) | |
pindexBestForkTip = nullptr; | |
if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > ::ChainActive().Tip()->nChainWork + (GetBlockProof(*::ChainActive().Tip()) * 6))) | |
{ | |
if (!GetfLargeWorkForkFound() && pindexBestForkBase) | |
{ | |
std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + | |
pindexBestForkBase->phashBlock->ToString() + std::string("'"); | |
AlertNotify(warning); | |
} | |
if (pindexBestForkTip && pindexBestForkBase) | |
{ | |
LogPrintf("%s: Warning: Large valid fork found\n forking the chain at height %d (%s)\n lasting to height %d (%s).\nChain state database corruption likely.\n", __func__, | |
pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString(), | |
pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString()); | |
SetfLargeWorkForkFound(true); | |
} | |
else | |
{ | |
LogPrintf("%s: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n", __func__); | |
SetfLargeWorkInvalidChainFound(true); | |
} | |
} | |
else | |
{ | |
SetfLargeWorkForkFound(false); | |
SetfLargeWorkInvalidChainFound(false); | |
} | |
} | |
static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) EXCLUSIVE_LOCKS_REQUIRED(cs_main) | |
{ | |
AssertLockHeld(cs_main); | |
// If we are on a fork that is sufficiently large, set a warning flag | |
CBlockIndex* pfork = pindexNewForkTip; | |
CBlockIndex* plonger = ::ChainActive().Tip(); | |
while (pfork && pfork != plonger) | |
{ | |
while (plonger && plonger->nHeight > pfork->nHeight) | |
plonger = plonger->pprev; | |
if (pfork == plonger) | |
break; | |
pfork = pfork->pprev; | |
} | |
// We define a condition where we should warn the user about as a fork of at least 7 blocks | |
// with a tip within 72 blocks (+/- 12 hours if no one mines it) of ours | |
// We use 7 blocks rather arbitrarily as it represents just under 10% of sustained network | |
// hash rate operating on the fork. | |
// or a chain that is entirely longer than ours and invalid (note that this should be detected by both) | |
// We define it this way because it allows us to only store the highest fork tip (+ base) which meets | |
// the 7-block condition and from this always have the most-likely-to-cause-warning fork | |
if (pfork && (!pindexBestForkTip || pindexNewForkTip->nHeight > pindexBestForkTip->nHeight) && | |
pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) && | |
::ChainActive().Height() - pindexNewForkTip->nHeight < 72) | |
{ | |
pindexBestForkTip = pindexNewForkTip; | |
pindexBestForkBase = pfork; | |
} | |
CheckForkWarningConditions(); | |
} | |
// Called both upon regular invalid block discovery *and* InvalidateBlock | |
void static InvalidChainFound(CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(cs_main) | |
{ | |
if (!pindexBestInvalid || pindexNew->nChainWork > pindexBestInvalid->nChainWork) | |
pindexBestInvalid = pindexNew; | |
if (pindexBestHeader != nullptr && pindexBestHeader->GetAncestor(pindexNew->nHeight) == pindexNew) { | |
pindexBestHeader = ::ChainActive().Tip(); | |
} | |
LogPrintf("%s: invalid block=%s height=%d log2_work=%.8g date=%s\n", __func__, | |
pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, | |
log(pindexNew->nChainWork.getdouble())/log(2.0), FormatISO8601DateTime(pindexNew->GetBlockTime())); | |
CBlockIndex *tip = ::ChainActive().Tip(); | |
assert (tip); | |
LogPrintf("%s: current best=%s height=%d log2_work=%.8g date=%s\n", __func__, | |
tip->GetBlockHash().ToString(), ::ChainActive().Height(), log(tip->nChainWork.getdouble())/log(2.0), | |
FormatISO8601DateTime(tip->GetBlockTime())); | |
CheckForkWarningConditions(); | |
} | |
// Same as InvalidChainFound, above, except not called directly from InvalidateBlock, | |
// which does its own setBlockIndexCandidates manageent. | |
void CChainState::InvalidBlockFound(CBlockIndex *pindex, const BlockValidationState &state) { | |
if (state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { | |
pindex->nStatus |= BLOCK_FAILED_VALID; | |
m_blockman.m_failed_blocks.insert(pindex); | |
setDirtyBlockIndex.insert(pindex); | |
setBlockIndexCandidates.erase(pindex); | |
InvalidChainFound(pindex); | |
} | |
} | |
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight) | |
{ | |
// mark inputs spent | |
if (!tx.IsCoinBase()) { | |
txundo.vprevout.reserve(tx.vin.size()); | |
for (const CTxIn &txin : tx.vin) { | |
txundo.vprevout.emplace_back(); | |
bool is_spent = inputs.SpendCoin(txin.prevout, &txundo.vprevout.back()); | |
assert(is_spent); | |
} | |
} | |
// add outputs | |
AddCoins(inputs, tx, nHeight); | |
} | |
void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight) | |
{ | |
CTxUndo txundo; | |
UpdateCoins(tx, inputs, txundo, nHeight); | |
} | |
bool CScriptCheck::operator()() { | |
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; | |
const CScriptWitness *witness = &ptxTo->vin[nIn].scriptWitness; | |
return VerifyScript(scriptSig, m_tx_out.scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, m_tx_out.nValue, cacheStore, *txdata), &error); | |
} | |
int GetSpendHeight(const CCoinsViewCache& inputs) | |
{ | |
LOCK(cs_main); | |
CBlockIndex* pindexPrev = LookupBlockIndex(inputs.GetBestBlock()); | |
return pindexPrev->nHeight + 1; | |
} | |
static CuckooCache::cache<uint256, SignatureCacheHasher> scriptExecutionCache; | |
static uint256 scriptExecutionCacheNonce(GetRandHash()); | |
void InitScriptExecutionCache() { | |
// nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero, | |
// setup_bytes creates the minimum possible cache (2 elements). | |
size_t nMaxCacheSize = std::min(std::max((int64_t)0, gArgs.GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) / 2), MAX_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20); | |
size_t nElems = scriptExecutionCache.setup_bytes(nMaxCacheSize); | |
LogPrintf("Using %zu MiB out of %zu/2 requested for script execution cache, able to store %zu elements\n", | |
(nElems*sizeof(uint256)) >>20, (nMaxCacheSize*2)>>20, nElems); | |
} | |
/** | |
* Check whether all of this transaction's input scripts succeed. | |
* | |
* This involves ECDSA signature checks so can be computationally intensive. This function should | |
* only be called after the cheap sanity checks in CheckTxInputs passed. | |
* | |
* If pvChecks is not nullptr, script checks are pushed onto it instead of being performed inline. Any | |
* script checks which are not necessary (eg due to script execution cache hits) are, obviously, | |
* not pushed onto pvChecks/run. | |
* | |
* Setting cacheSigStore/cacheFullScriptStore to false will remove elements from the corresponding cache | |
* which are matched. This is useful for checking blocks where we will likely never need the cache | |
* entry again. | |
* | |
* Note that we may set state.reason to NOT_STANDARD for extra soft-fork flags in flags, block-checking | |
* callers should probably reset it to CONSENSUS in such cases. | |
* | |
* Non-static (and re-declared) in src/test/txvalidationcache_tests.cpp | |
*/ | |
bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main) | |
{ | |
if (tx.IsCoinBase()) return true; | |
if (pvChecks) { | |
pvChecks->reserve(tx.vin.size()); | |
} | |
// First check if script executions have been cached with the same | |
// flags. Note that this assumes that the inputs provided are | |
// correct (ie that the transaction hash which is in tx's prevouts | |
// properly commits to the scriptPubKey in the inputs view of that | |
// transaction). | |
uint256 hashCacheEntry; | |
// We only use the first 19 bytes of nonce to avoid a second SHA | |
// round - giving us 19 + 32 + 4 = 55 bytes (+ 8 + 1 = 64) | |
static_assert(55 - sizeof(flags) - 32 >= 128/8, "Want at least 128 bits of nonce for script execution cache"); | |
CSHA256().Write(scriptExecutionCacheNonce.begin(), 55 - sizeof(flags) - 32).Write(tx.GetWitnessHash().begin(), 32).Write((unsigned char*)&flags, sizeof(flags)).Finalize(hashCacheEntry.begin()); | |
AssertLockHeld(cs_main); //TODO: Remove this requirement by making CuckooCache not require external locks | |
if (scriptExecutionCache.contains(hashCacheEntry, !cacheFullScriptStore)) { | |
return true; | |
} | |
if (!txdata.m_ready) { | |
txdata.Init(tx); | |
} | |
for (unsigned int i = 0; i < tx.vin.size(); i++) { | |
const COutPoint &prevout = tx.vin[i].prevout; | |
const Coin& coin = inputs.AccessCoin(prevout); | |
assert(!coin.IsSpent()); | |
// We very carefully only pass in things to CScriptCheck which | |
// are clearly committed to by tx' witness hash. This provides | |
// a sanity check that our caching is not introducing consensus | |
// failures through additional data in, eg, the coins being | |
// spent being checked as a part of CScriptCheck. | |
// Verify signature | |
CScriptCheck check(coin.out, tx, i, flags, cacheSigStore, &txdata); | |
if (pvChecks) { | |
pvChecks->push_back(CScriptCheck()); | |
check.swap(pvChecks->back()); | |
} else if (!check()) { | |
if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) { | |
// Check whether the failure was caused by a | |
// non-mandatory script verification check, such as | |
// non-standard DER encodings or non-null dummy | |
// arguments; if so, ensure we return NOT_STANDARD | |
// instead of CONSENSUS to avoid downstream users | |
// splitting the network between upgraded and | |
// non-upgraded nodes by banning CONSENSUS-failing | |
// data providers. | |
CScriptCheck check2(coin.out, tx, i, | |
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore, &txdata); | |
if (check2()) | |
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); | |
} | |
// MANDATORY flag failures correspond to | |
// TxValidationResult::TX_CONSENSUS. Because CONSENSUS | |
// failures are the most serious case of validation | |
// failures, we may need to consider using | |
// RECENT_CONSENSUS_CHANGE for any script failure that | |
// could be due to non-upgraded nodes which we may want to | |
// support, to avoid splitting the network (but this | |
// depends on the details of how net_processing handles | |
// such errors). | |
return state.Invalid(TxValidationResult::TX_CONSENSUS, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))); | |
} | |
} | |
if (cacheFullScriptStore && !pvChecks) { | |
// We executed all of the provided scripts, and were told to | |
// cache the result. Do so now. | |
scriptExecutionCache.insert(hashCacheEntry); | |
} | |
return true; | |
} | |
static bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart) | |
{ | |
// Open history file to append | |
CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); | |
if (fileout.IsNull()) | |
return error("%s: OpenUndoFile failed", __func__); | |
// Write index header | |
unsigned int nSize = GetSerializeSize(blockundo, fileout.GetVersion()); | |
fileout << messageStart << nSize; | |
// Write undo data | |
long fileOutPos = ftell(fileout.Get()); | |
if (fileOutPos < 0) | |
return error("%s: ftell failed", __func__); | |
pos.nPos = (unsigned int)fileOutPos; | |
fileout << blockundo; | |
// calculate & write checksum | |
CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); | |
hasher << hashBlock; | |
hasher << blockundo; | |
fileout << hasher.GetHash(); | |
return true; | |
} | |
bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex) | |
{ | |
FlatFilePos pos = pindex->GetUndoPos(); | |
if (pos.IsNull()) { | |
return error("%s: no undo data available", __func__); | |
} | |
// Open history file to read | |
CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); | |
if (filein.IsNull()) | |
return error("%s: OpenUndoFile failed", __func__); | |
// Read block | |
uint256 hashChecksum; | |
CHashVerifier<CAutoFile> verifier(&filein); // We need a CHashVerifier as reserializing may lose data | |
try { | |
verifier << pindex->pprev->GetBlockHash(); | |
verifier >> blockundo; | |
filein >> hashChecksum; | |
} | |
catch (const std::exception& e) { | |
return error("%s: Deserialize or I/O error - %s", __func__, e.what()); | |
} | |
// Verify checksum | |
if (hashChecksum != verifier.GetHash()) | |
return error("%s: Checksum mismatch", __func__); | |
return true; | |
} | |
/** Abort with a message */ | |
static bool AbortNode(const std::string& strMessage, const std::string& userMessage = "", unsigned int prefix = 0) | |
{ | |
SetMiscWarning(strMessage); | |
LogPrintf("*** %s\n", strMessage); | |
if (!userMessage.empty()) { | |
uiInterface.ThreadSafeMessageBox(userMessage, "", CClientUIInterface::MSG_ERROR | prefix); | |
} else { | |
uiInterface.ThreadSafeMessageBox(_("Error: A fatal internal error occurred, see debug.log for details").translated, "", CClientUIInterface::MSG_ERROR | CClientUIInterface::MSG_NOPREFIX); | |
} | |
StartShutdown(); | |
return false; | |
} | |
static bool AbortNode(BlockValidationState& state, const std::string& strMessage, const std::string& userMessage = "", unsigned int prefix = 0) | |
{ | |
AbortNode(strMessage, userMessage, prefix); | |
return state.Error(strMessage); | |
} | |
/** | |
* Restore the UTXO in a Coin at a given COutPoint | |
* @param undo The Coin to be restored. | |
* @param view The coins view to which to apply the changes. | |
* @param out The out point that corresponds to the tx input. | |
* @return A DisconnectResult as an int | |
*/ | |
int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out) | |
{ | |
bool fClean = true; | |
if (view.HaveCoin(out)) fClean = false; // overwriting transaction output | |
if (undo.nHeight == 0) { | |
// Missing undo metadata (height and coinbase). Older versions included this | |
// information only in undo records for the last spend of a transactions' | |
// outputs. This implies that it must be present for some other output of the same tx. | |
const Coin& alternate = AccessByTxid(view, out.hash); | |
if (!alternate.IsSpent()) { | |
undo.nHeight = alternate.nHeight; | |
undo.fCoinBase = alternate.fCoinBase; | |
} else { | |
return DISCONNECT_FAILED; // adding output for transaction without known metadata | |
} | |
} | |
// If the coin already exists as an unspent coin in the cache, then the | |
// possible_overwrite parameter to AddCoin must be set to true. We have | |
// already checked whether an unspent coin exists above using HaveCoin, so | |
// we don't need to guess. When fClean is false, an unspent coin already | |
// existed and it is an overwrite. | |
view.AddCoin(out, std::move(undo), !fClean); | |
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN; | |
} | |
/** Undo the effects of this block (with given index) on the UTXO set represented by coins. | |
* When FAILED is returned, view is left in an indeterminate state. */ | |
DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view) | |
{ | |
bool fClean = true; | |
CBlockUndo blockUndo; | |
if (!UndoReadFromDisk(blockUndo, pindex)) { | |
error("DisconnectBlock(): failure reading undo data"); | |
return DISCONNECT_FAILED; | |
} | |
if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) { | |
error("DisconnectBlock(): block and undo data inconsistent"); | |
return DISCONNECT_FAILED; | |
} | |
// undo transactions in reverse order | |
for (int i = block.vtx.size() - 1; i >= 0; i--) { | |
const CTransaction &tx = *(block.vtx[i]); | |
uint256 hash = tx.GetHash(); | |
bool is_coinbase = tx.IsCoinBase(); | |
// Check that all outputs are available and match the outputs in the block itself | |
// exactly. | |
for (size_t o = 0; o < tx.vout.size(); o++) { | |
if (!tx.vout[o].scriptPubKey.IsUnspendable()) { | |
COutPoint out(hash, o); | |
Coin coin; | |
bool is_spent = view.SpendCoin(out, &coin); | |
if (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.fCoinBase) { | |
fClean = false; // transaction output mismatch | |
} | |
} | |
} | |
// restore inputs | |
if (i > 0) { // not coinbases | |
CTxUndo &txundo = blockUndo.vtxundo[i-1]; | |
if (txundo.vprevout.size() != tx.vin.size()) { | |
error("DisconnectBlock(): transaction and undo data inconsistent"); | |
return DISCONNECT_FAILED; | |
} | |
for (unsigned int j = tx.vin.size(); j-- > 0;) { | |
const COutPoint &out = tx.vin[j].prevout; | |
int res = ApplyTxInUndo(std::move(txundo.vprevout[j]), view, out); | |
if (res == DISCONNECT_FAILED) return DISCONNECT_FAILED; | |
fClean = fClean && res != DISCONNECT_UNCLEAN; | |
} | |
// At this point, all of txundo.vprevout should have been moved out. | |
} | |
} | |
// move best block pointer to prevout block | |
view.SetBestBlock(pindex->pprev->GetBlockHash()); | |
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN; | |
} | |
void static FlushBlockFile(bool fFinalize = false) | |
{ | |
LOCK(cs_LastBlockFile); | |
FlatFilePos block_pos_old(nLastBlockFile, vinfoBlockFile[nLastBlockFile].nSize); | |
FlatFilePos undo_pos_old(nLastBlockFile, vinfoBlockFile[nLastBlockFile].nUndoSize); | |
bool status = true; | |
status &= BlockFileSeq().Flush(block_pos_old, fFinalize); | |
status &= UndoFileSeq().Flush(undo_pos_old, fFinalize); | |
if (!status) { | |
AbortNode("Flushing block file to disk failed. This is likely the result of an I/O error."); | |
} | |
} | |
static bool FindUndoPos(BlockValidationState &state, int nFile, FlatFilePos &pos, unsigned int nAddSize); | |
static bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams) | |
{ | |
// Write undo information to disk | |
if (pindex->GetUndoPos().IsNull()) { | |
FlatFilePos _pos; | |
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"); | |
// update nUndoPos in block index | |
pindex->nUndoPos = _pos.nPos; | |
pindex->nStatus |= BLOCK_HAVE_UNDO; | |
setDirtyBlockIndex.insert(pindex); | |
} | |
return true; | |
} | |
static CCheckQueue<CScriptCheck> scriptcheckqueue(128); | |
void ThreadScriptCheck(int worker_num) { | |
util::ThreadRename(strprintf("scriptch.%i", worker_num)); | |
scriptcheckqueue.Thread(); | |
} | |
VersionBitsCache versionbitscache GUARDED_BY(cs_main); | |
int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params) | |
{ | |
LOCK(cs_main); | |
int32_t nVersion = VERSIONBITS_TOP_BITS; | |
for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) { | |
ThresholdState state = VersionBitsState(pindexPrev, params, static_cast<Consensus::DeploymentPos>(i), versionbitscache); | |
if (state == ThresholdState::LOCKED_IN || state == ThresholdState::STARTED) { | |
nVersion |= VersionBitsMask(params, static_cast<Consensus::DeploymentPos>(i)); | |
} | |
} | |
return nVersion; | |
} | |
/** | |
* Threshold condition checker that triggers when unknown versionbits are seen on the network. | |
*/ | |
class WarningBitsConditionChecker : public AbstractThresholdConditionChecker | |
{ | |
private: | |
int bit; | |
public: | |
explicit WarningBitsConditionChecker(int bitIn) : bit(bitIn) {} | |
int64_t BeginTime(const Consensus::Params& params) const override { return 0; } | |
int64_t EndTime(const Consensus::Params& params) const override { return std::numeric_limits<int64_t>::max(); } | |
int Period(const Consensus::Params& params) const override { return params.nMinerConfirmationWindow; } | |
int Threshold(const Consensus::Params& params) const override { return params.nRuleChangeActivationThreshold; } | |
bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override | |
{ | |
return pindex->nHeight >= params.MinBIP9WarningHeight && | |
((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && | |
((pindex->nVersion >> bit) & 1) != 0 && | |
((ComputeBlockVersion(pindex->pprev, params) >> bit) & 1) == 0; | |
} | |
}; | |
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 | |
// except for testing purposes, due to limitations of the functional test | |
// environment. See test/functional/p2p-segwit.py. | |
static bool IsScriptWitnessEnabled(const Consensus::Params& params) | |
{ | |
return params.SegwitHeight != std::numeric_limits<int>::max(); | |
} | |
static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& consensusparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | |
AssertLockHeld(cs_main); | |
unsigned int flags = SCRIPT_VERIFY_NONE; | |
// BIP16 didn't become active until Apr 1 2012 (on mainnet, and | |
// retroactively applied to testnet) | |
// However, only one historical block violated the P2SH rules (on both | |
// mainnet and testnet), so for simplicity, always leave P2SH | |
// on except for the one violating block. | |
if (consensusparams.BIP16Exception.IsNull() || // no bip16 exception on this chain | |
pindex->phashBlock == nullptr || // this is a new candidate block, eg from TestBlockValidity() | |
*pindex->phashBlock != consensusparams.BIP16Exception) // this block isn't the historical exception | |
{ | |
flags |= SCRIPT_VERIFY_P2SH; | |
} | |
// Enforce WITNESS rules whenever P2SH is in effect (and the segwit | |
// deployment is defined). | |
if (flags & SCRIPT_VERIFY_P2SH && IsScriptWitnessEnabled(consensusparams)) { | |
flags |= SCRIPT_VERIFY_WITNESS; | |
} | |
// Start enforcing the DERSIG (BIP66) rule | |
if (pindex->nHeight >= consensusparams.BIP66Height) { | |
flags |= SCRIPT_VERIFY_DERSIG; | |
} | |
// Start enforcing CHECKLOCKTIMEVERIFY (BIP65) rule | |
if (pindex->nHeight >= consensusparams.BIP65Height) { | |
flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; | |
} | |
// Start enforcing BIP112 (CHECKSEQUENCEVERIFY) | |
if (pindex->nHeight >= consensusparams.CSVHeight) { | |
flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; | |
} | |
// Start enforcing BIP147 NULLDUMMY (activated simultaneously with segwit) | |
if (IsWitnessEnabled(pindex->pprev, consensusparams)) { | |
flags |= SCRIPT_VERIFY_NULLDUMMY; | |
} | |
return flags; | |
} | |
static int64_t nTimeCheck = 0; | |
static int64_t nTimeForks = 0; | |
static int64_t nTimeVerify = 0; | |
static int64_t nTimeConnect = 0; | |
static int64_t nTimeIndex = 0; | |
static int64_t nTimeCallbacks = 0; | |
static int64_t nTimeTotal = 0; | |
static int64_t nBlocksTotal = 0; | |
/** Apply the effects of this block (with given index) on the UTXO set represented by coins. | |
* Validity checks that depend on the UTXO set are also done; ConnectBlock() | |
* can fail if those validity checks fail (among other reasons). */ | |
bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, CBlockIndex* pindex, | |
CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck) | |
{ | |
AssertLockHeld(cs_main); | |
assert(pindex); | |
assert(*pindex->phashBlock == block.GetHash()); | |
int64_t nTimeStart = GetTimeMicros(); | |
// Check it again in case a previous version let a bad block in | |
// NOTE: We don't currently (re-)invoke ContextualCheckBlock() or | |
// ContextualCheckBlockHeader() here. This means that if we add a new | |
// consensus rule that is enforced in one of those two functions, then we | |
// may have let in a block that violates the rule prior to updating the | |
// software, and we would NOT be enforcing the rule here. Fully solving | |
// upgrade from one software version to the next after a consensus rule | |
// change is potentially tricky and issue-specific (see RewindBlockIndex() | |
// for one general approach that was used for BIP 141 deployment). | |
// Also, currently the rule against blocks more than 2 hours in the future | |
// is enforced in ContextualCheckBlockHeader(); we wouldn't want to | |
// re-enforce that rule here (at least until we make it impossible for | |
// GetAdjustedTime() to go backward). | |
if (!CheckBlock(block, state, chainparams.GetConsensus(), !fJustCheck, !fJustCheck)) { | |
if (state.GetResult() == BlockValidationResult::BLOCK_MUTATED) { | |
// We don't write down blocks to disk if they may have been | |
// corrupted, so this should be impossible unless we're having hardware | |
// problems. | |
return AbortNode(state, "Corrupt block found indicating potential hardware failure; shutting down"); | |
} | |
return error("%s: Consensus::CheckBlock: %s", __func__, state.ToString()); | |
} | |
// verify that the view's current state corresponds to the previous block | |
uint256 hashPrevBlock = pindex->pprev == nullptr ? uint256() : pindex->pprev->GetBlockHash(); | |
assert(hashPrevBlock == view.GetBestBlock()); | |
nBlocksTotal++; | |
// Special case for the genesis block, skipping connection of its transactions | |
// (its coinbase is unspendable) | |
if (block.GetHash() == chainparams.GetConsensus().hashGenesisBlock) { | |
if (!fJustCheck) | |
view.SetBestBlock(pindex->GetBlockHash()); | |
return true; | |
} | |
bool fScriptChecks = true; | |
if (!hashAssumeValid.IsNull()) { | |
// We've been configured with the hash of a block which has been externally verified to have a valid history. | |
// A suitable default value is included with the software and updated from time to time. Because validity | |
// relative to a piece of software is an objective fact these defaults can be easily reviewed. | |
// This setting doesn't force the selection of any particular chain but makes validating some faster by | |
// effectively caching the result of part of the verification. | |
BlockMap::const_iterator it = m_blockman.m_block_index.find(hashAssumeValid); | |
if (it != m_blockman.m_block_index.end()) { | |
if (it->second->GetAncestor(pindex->nHeight) == pindex && | |
pindexBestHeader->GetAncestor(pindex->nHeight) == pindex && | |
pindexBestHeader->nChainWork >= nMinimumChainWork) { | |
// This block is a member of the assumed verified chain and an ancestor of the best header. | |
// Script verification is skipped when connecting blocks under the | |
// assumevalid block. Assuming the assumevalid block is valid this | |
// is safe because block merkle hashes are still computed and checked, | |
// Of course, if an assumed valid block is invalid due to false scriptSigs | |
// this optimization would allow an invalid chain to be accepted. | |
// The equivalent time check discourages hash power from extorting the network via DOS attack | |
// into accepting an invalid block through telling users they must manually set assumevalid. | |
// Requiring a software change or burying the invalid block, regardless of the setting, makes | |
// it hard to hide the implication of the demand. This also avoids having release candidates | |
// that are hardly doing any signature verification at all in testing without having to | |
// artificially set the default assumed verified block further back. | |
// The test against nMinimumChainWork prevents the skipping when denied access to any chain at | |
// least as good as the expected chain. | |
fScriptChecks = (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, chainparams.GetConsensus()) <= 60 * 60 * 24 * 7 * 2); | |
} | |
} | |
} | |
int64_t nTime1 = GetTimeMicros(); nTimeCheck += nTime1 - nTimeStart; | |
LogPrint(BCLog::BENCH, " - Sanity checks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime1 - nTimeStart), nTimeCheck * MICRO, nTimeCheck * MILLI / nBlocksTotal); | |
// Do not allow blocks that contain transactions which 'overwrite' older transactions, | |
// unless those are already completely spent. | |
// If such overwrites are allowed, coinbases and transactions depending upon those | |
// can be duplicated to remove the ability to spend the first instance -- even after | |
// being sent to another address. | |
// See BIP30, CVE-2012-1909, and http://r6.ca/blog/20120206T005236Z.html for more information. | |
// This logic is not necessary for memory pool transactions, as AcceptToMemoryPool | |
// already refuses previously-known transaction ids entirely. | |
// This rule was originally applied to all blocks with a timestamp after March 15, 2012, 0:00 UTC. | |
// Now that the whole chain is irreversibly beyond that time it is applied to all blocks except the | |
// two in the chain that violate it. This prevents exploiting the issue against nodes during their | |
// initial block download. | |
bool fEnforceBIP30 = !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256S("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || | |
(pindex->nHeight==91880 && pindex->GetBlockHash() == uint256S("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"))); | |
// Once BIP34 activated it was not possible to create new duplicate coinbases and thus other than starting | |
// with the 2 existing duplicate coinbase pairs, not possible to create overwriting txs. But by the | |
// time BIP34 activated, in each of the existing pairs the duplicate coinbase had overwritten the first | |
// before the first had been spent. Since those coinbases are sufficiently buried it's no longer possible to create further | |
// duplicate transactions descending from the known pairs either. | |
// If we're on the known chain at height greater than where BIP34 activated, we can save the db accesses needed for the BIP30 check. | |
// BIP34 requires that a block at height X (block X) has its coinbase | |
// scriptSig start with a CScriptNum of X (indicated height X). The above | |
// logic of no longer requiring BIP30 once BIP34 activates is flawed in the | |
// case that there is a block X before the BIP34 height of 227,931 which has | |
// an indicated height Y where Y is greater than X. The coinbase for block | |
// X would also be a valid coinbase for block Y, which could be a BIP30 | |
// violation. An exhaustive search of all mainnet coinbases before the | |
// BIP34 height which have an indicated height greater than the block height | |
// reveals many occurrences. The 3 lowest indicated heights found are | |
// 209,921, 490,897, and 1,983,702 and thus coinbases for blocks at these 3 | |
// heights would be the first opportunity for BIP30 to be violated. | |
// The search reveals a great many blocks which have an indicated height | |
// greater than 1,983,702, so we simply remove the optimization to skip | |
// BIP30 checking for blocks at height 1,983,702 or higher. Before we reach | |
// that block in another 25 years or so, we should take advantage of a | |
// future consensus change to do a new and improved version of BIP34 that | |
// will actually prevent ever creating any duplicate coinbases in the | |
// future. | |
static constexpr int BIP34_IMPLIES_BIP30_LIMIT = 1983702; | |
// There is no potential to create a duplicate coinbase at block 209,921 | |
// because this is still before the BIP34 height and so explicit BIP30 | |
// checking is still active. | |
// The final case is block 176,684 which has an indicated height of | |
// 490,897. Unfortunately, this issue was not discovered until about 2 weeks | |
// before block 490,897 so there was not much opportunity to address this | |
// case other than to carefully analyze it and determine it would not be a | |
// problem. Block 490,897 was, in fact, mined with a different coinbase than | |
// block 176,684, but it is important to note that even if it hadn't been or | |
// is remined on an alternate fork with a duplicate coinbase, we would still | |
// not run into a BIP30 violation. This is because the coinbase for 176,684 | |
// is spent in block 185,956 in transaction | |
// d4f7fbbf92f4a3014a230b2dc70b8058d02eb36ac06b4a0736d9d60eaa9e8781. This | |
// spending transaction can't be duplicated because it also spends coinbase | |
// 0328dd85c331237f18e781d692c92de57649529bd5edf1d01036daea32ffde29. This | |
// coinbase has an indicated height of over 4.2 billion, and wouldn't be | |
// duplicatable until that height, and it's currently impossible to create a | |
// chain that long. Nevertheless we may wish to consider a future soft fork | |
// which retroactively prevents block 490,897 from creating a duplicate | |
// coinbase. The two historical BIP30 violations often provide a confusing | |
// edge case when manipulating the UTXO and it would be simpler not to have | |
// another edge case to deal with. | |
// testnet3 has no blocks before the BIP34 height with indicated heights | |
// post BIP34 before approximately height 486,000,000 and presumably will | |
// be reset before it reaches block 1,983,702 and starts doing unnecessary | |
// BIP30 checking again. | |
assert(pindex->pprev); | |
CBlockIndex *pindexBIP34height = pindex->pprev->GetAncestor(chainparams.GetConsensus().BIP34Height); | |
//Only continue to enforce if we're below BIP34 activation height or the block hash at that height doesn't correspond. | |
fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || !(pindexBIP34height->GetBlockHash() == chainparams.GetConsensus().BIP34Hash)); | |
// TODO: Remove BIP30 checking from block height 1,983,702 on, once we have a | |
// consensus change that ensures coinbases at those heights can not | |
// duplicate earlier coinbases. | |
if (fEnforceBIP30 || pindex->nHeight >= BIP34_IMPLIES_BIP30_LIMIT) { | |
for (const auto& tx : block.vtx) { | |
for (size_t o = 0; o < tx->vout.size(); o++) { | |
if (view.HaveCoin(COutPoint(tx->GetHash(), o))) { | |
LogPrintf("ERROR: ConnectBlock(): tried to overwrite transaction\n"); | |
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-txns-BIP30"); | |
} | |
} | |
} | |
} | |
// Start enforcing BIP68 (sequence locks) | |
int nLockTimeFlags = 0; | |
if (pindex->nHeight >= chainparams.GetConsensus().CSVHeight) { | |
nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE; | |
} | |
// Get the script flags for this block | |
unsigned int flags = GetBlockScriptFlags(pindex, chainparams.GetConsensus()); | |
int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1; | |
LogPrint(BCLog::BENCH, " - Fork checks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime2 - nTime1), nTimeForks * MICRO, nTimeForks * MILLI / nBlocksTotal); | |
CBlockUndo blockundo; | |
// Precomputed transaction data pointers must not be invalidated | |
// until after `control` has run the script checks (potentially | |
// in multiple threads). Preallocate the vector size so a new allocation | |
// doesn't invalidate pointers into the vector, and keep txsdata in scope | |
// for as long as `control`. | |
CCheckQueueControl<CScriptCheck> control(fScriptChecks && g_parallel_script_checks ? &scriptcheckqueue : nullptr); | |
std::vector<PrecomputedTransactionData> txsdata(block.vtx.size()); | |
std::vector<int> prevheights; | |
CAmount nFees = 0; | |
int nInputs = 0; | |
int64_t nSigOpsCost = 0; | |
blockundo.vtxundo.reserve(block.vtx.size() - 1); | |
for (unsigned int i = 0; i < block.vtx.size(); i++) | |
{ | |
const CTransaction &tx = *(block.vtx[i]); | |
nInputs += tx.vin.size(); | |
if (!tx.IsCoinBase()) | |
{ | |
CAmount txfee = 0; | |
TxValidationState tx_state; | |
if (!Consensus::CheckTxInputs(tx, tx_state, view, pindex->nHeight, txfee)) { | |
// Any transaction validation failure in ConnectBlock is a block consensus failure | |
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, | |
tx_state.GetRejectReason(), tx_state.GetDebugMessage()); | |
return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), state.ToString()); | |
} | |
nFees += txfee; | |
if (!MoneyRange(nFees)) { | |
LogPrintf("ERROR: %s: accumulated fee in the block out of range.\n", __func__); | |
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-txns-accumulated-fee-outofrange"); | |
} | |
// Check that transaction is BIP68 final | |
// BIP68 lock checks (as opposed to nLockTime checks) must | |
// be in ConnectBlock because they require the UTXO set | |
prevheights.resize(tx.vin.size()); | |
for (size_t j = 0; j < tx.vin.size(); j++) { | |
prevheights[j] = view.AccessCoin(tx.vin[j].prevout).nHeight; | |
} | |
if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) { | |
LogPrintf("ERROR: %s: contains a non-BIP68-final transaction\n", __func__); | |
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-txns-nonfinal"); | |
} | |
} | |
// GetTransactionSigOpCost counts 3 types of sigops: | |
// * legacy (always) | |
// * p2sh (when P2SH enabled in flags and excludes coinbase) | |
// * witness (when witness enabled in flags and excludes coinbase) | |
nSigOpsCost += GetTransactionSigOpCost(tx, view, flags); | |
if (nSigOpsCost > MAX_BLOCK_SIGOPS_COST) { | |
LogPrintf("ERROR: ConnectBlock(): too many sigops\n"); | |
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-blk-sigops"); | |
} | |
if (!tx.IsCoinBase()) | |
{ | |
std::vector<CScriptCheck> vChecks; | |
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */ | |
TxValidationState tx_state; | |
if (fScriptChecks && !CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txsdata[i], g_parallel_script_checks ? &vChecks : nullptr)) { | |
// Any transaction validation failure in ConnectBlock is a block consensus failure | |
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, | |
tx_state.GetRejectReason(), tx_state.GetDebugMessage()); | |
return error("ConnectBlock(): CheckInputScripts on %s failed with %s", | |
tx.GetHash().ToString(), state.ToString()); | |
} | |
control.Add(vChecks); | |
} | |
CTxUndo undoDummy; | |
if (i > 0) { | |
blockundo.vtxundo.push_back(CTxUndo()); | |
} | |
UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight); | |
} | |
int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2; | |
LogPrint(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), MILLI * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal); | |
CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()); | |
if (block.vtx[0]->GetValueOut() > blockReward) { | |
LogPrintf("ERROR: ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)\n", block.vtx[0]->GetValueOut(), blockReward); | |
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-amount"); | |
} | |
if (!control.Wait()) { | |
LogPrintf("ERROR: %s: CheckQueue failed\n", __func__); | |
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "block-validation-failed"); | |
} | |
int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2; | |
LogPrint(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, MILLI * (nTime4 - nTime2), nInputs <= 1 ? 0 : MILLI * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * MICRO, nTimeVerify * MILLI / nBlocksTotal); | |
if (fJustCheck) | |
return true; | |
if (!WriteUndoDataForBlock(blockundo, state, pindex, chainparams)) | |
return false; | |
if (!pindex->IsValid(BLOCK_VALID_SCRIPTS)) { | |
pindex->RaiseValidity(BLOCK_VALID_SCRIPTS); | |
setDirtyBlockIndex.insert(pindex); | |
} | |
assert(pindex->phashBlock); | |
// add this block to the view's block chain | |
view.SetBestBlock(pindex->GetBlockHash()); | |
int64_t nTime5 = GetTimeMicros(); nTimeIndex += nTime5 - nTime4; | |
LogPrint(BCLog::BENCH, " - Index writing: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime5 - nTime4), nTimeIndex * MICRO, nTimeIndex * MILLI / nBlocksTotal); | |
int64_t nTime6 = GetTimeMicros(); nTimeCallbacks += nTime6 - nTime5; | |
LogPrint(BCLog::BENCH, " - Callbacks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime6 - nTime5), nTimeCallbacks * MICRO, nTimeCallbacks * MILLI / nBlocksTotal); | |
return true; | |
} | |
CoinsCacheSizeState CChainState::GetCoinsCacheSizeState(const CTxMemPool& tx_pool) | |
{ | |
return this->GetCoinsCacheSizeState( | |
tx_pool, | |
nCoinCacheUsage, | |
gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000); | |
} | |
CoinsCacheSizeState CChainState::GetCoinsCacheSizeState( | |
const CTxMemPool& tx_pool, | |
size_t max_coins_cache_size_bytes, | |
size_t max_mempool_size_bytes) | |
{ | |
int64_t nMempoolUsage = tx_pool.DynamicMemoryUsage(); | |
int64_t cacheSize = CoinsTip().DynamicMemoryUsage(); | |
int64_t nTotalSpace = | |
max_coins_cache_size_bytes + std::max<int64_t>(max_mempool_size_bytes - nMempoolUsage, 0); | |
//! No need to periodic flush if at least this much space still available. | |
static constexpr int64_t MAX_BLOCK_COINSDB_USAGE_BYTES = 10 * 1024 * 1024; // 10MB | |
int64_t large_threshold = | |
std::max((9 * nTotalSpace) / 10, nTotalSpace - MAX_BLOCK_COINSDB_USAGE_BYTES); | |
if (cacheSize > nTotalSpace) { | |
LogPrintf("Cache size (%s) exceeds total space (%s)\n", cacheSize, nTotalSpace); | |
return CoinsCacheSizeState::CRITICAL; | |
} else if (cacheSize > large_threshold) { | |
return CoinsCacheSizeState::LARGE; | |
} | |
return CoinsCacheSizeState::OK; | |
} | |
bool CChainState::FlushStateToDisk( | |
const CChainParams& chainparams, | |
BlockValidationState &state, | |
FlushStateMode mode, | |
int nManualPruneHeight) | |
{ | |
LOCK(cs_main); | |
assert(this->CanFlushToDisk()); | |
static int64_t nLastWrite = 0; | |
static int64_t nLastFlush = 0; | |
std::set<int> setFilesToPrune; | |
bool full_flush_completed = false; | |
const size_t coins_count = CoinsTip().GetCacheSize(); | |
const size_t coins_mem_usage = CoinsTip().DynamicMemoryUsage(); | |
try { | |
{ | |
bool fFlushForPrune = false; | |
bool fDoFullFlush = false; | |
CoinsCacheSizeState cache_state = GetCoinsCacheSizeState(::mempool); | |
LOCK(cs_LastBlockFile); | |
if (fPruneMode && (fCheckForPruning || nManualPruneHeight > 0) && !fReindex) { | |
if (nManualPruneHeight > 0) { | |
LOG_TIME_MILLIS("find files to prune (manual)", BCLog::BENCH); | |
FindFilesToPruneManual(setFilesToPrune, nManualPruneHeight); | |
} else { | |
LOG_TIME_MILLIS("find files to prune", BCLog::BENCH); | |
FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight()); | |
fCheckForPruning = false; | |
} | |
if (!setFilesToPrune.empty()) { | |
fFlushForPrune = true; | |
if (!fHavePruned) { | |
pblocktree->WriteFlag("prunedblockfiles", true); | |
fHavePruned = true; | |
} | |
} | |
} | |
int64_t nNow = GetTimeMicros(); | |
// Avoid writing/flushing immediately after startup. | |
if (nLastWrite == 0) { | |
nLastWrite = nNow; | |
} | |
if (nLastFlush == 0) { | |
nLastFlush = nNow; | |
} | |
// The cache is large and we're within 10% and 10 MiB of the limit, but we have time now (not in the middle of a block processing). | |
bool fCacheLarge = mode == FlushStateMode::PERIODIC && cache_state >= CoinsCacheSizeState::LARGE; | |
// The cache is over the limit, we have to write now. | |
bool fCacheCritical = mode == FlushStateMode::IF_NEEDED && cache_state >= CoinsCacheSizeState::CRITICAL; | |
// It's been a while since we wrote the block index to disk. Do this frequently, so we don't need to redownload after a crash. | |
bool fPeriodicWrite = mode == FlushStateMode::PERIODIC && nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000; | |
// It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage. | |
bool fPeriodicFlush = mode == FlushStateMode::PERIODIC && nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000; | |
// Combine all conditions that result in a full cache flush. | |
fDoFullFlush = (mode == FlushStateMode::ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune; | |
// Write blocks and block index to disk. | |
if (fDoFullFlush || fPeriodicWrite) { | |
// Depend on nMinDiskSpace to ensure we can write block index | |
if (!CheckDiskSpace(GetBlocksDir())) { | |
return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!").translated, CClientUIInterface::MSG_NOPREFIX); | |
} | |
{ | |
LOG_TIME_MILLIS("write block and undo data to disk", BCLog::BENCH); | |
// First make sure all block and undo data is flushed to disk. | |
FlushBlockFile(); | |
} | |
// Then update all block file information (which may refer to block and undo files). | |
{ | |
LOG_TIME_MILLIS("write block index to disk", BCLog::BENCH); | |
std::vector<std::pair<int, const CBlockFileInfo*> > vFiles; | |
vFiles.reserve(setDirtyFileInfo.size()); | |
for (std::set<int>::iterator it = setDirtyFileInfo.begin(); it != setDirtyFileInfo.end(); ) { | |
vFiles.push_back(std::make_pair(*it, &vinfoBlockFile[*it])); | |
setDirtyFileInfo.erase(it++); | |
} | |
std::vector<const CBlockIndex*> vBlocks; | |
vBlocks.reserve(setDirtyBlockIndex.size()); | |
for (std::set<CBlockIndex*>::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end(); ) { | |
vBlocks.push_back(*it); | |
setDirtyBlockIndex.erase(it++); | |
} | |
if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) { | |
return AbortNode(state, "Failed to write to block index database"); | |
} | |
} | |
// Finally remove any pruned files | |
if (fFlushForPrune) { | |
LOG_TIME_MILLIS("unlink pruned files", BCLog::BENCH); | |
UnlinkPrunedFiles(setFilesToPrune); | |
} | |
nLastWrite = nNow; | |
} | |
// Flush best chain related state. This can only be done if the blocks / block index write was also done. | |
if (fDoFullFlush && !CoinsTip().GetBestBlock().IsNull()) { | |
LOG_TIME_SECONDS(strprintf("write coins cache to disk (%d coins, %.2fkB)", | |
coins_count, coins_mem_usage / 1000)); | |
// Typical Coin structures on disk are around 48 bytes in size. | |
// Pushing a new one to the database can cause it to be written | |
// twice (once in the log, and once in the tables). This is already | |
// an overestimation, as most will delete an existing entry or | |
// overwrite one. Still, use a conservative safety factor of 2. | |
if (!CheckDiskSpace(GetDataDir(), 48 * 2 * 2 * CoinsTip().GetCacheSize())) { | |
return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!").translated, CClientUIInterface::MSG_NOPREFIX); | |
} | |
// Flush the chainstate (which may refer to block index entries). | |
if (!CoinsTip().Flush()) | |
return AbortNode(state, "Failed to write to coin database"); | |
nLastFlush = nNow; | |
full_flush_completed = true; | |
} | |
} | |
if (full_flush_completed) { | |
// Update best block in wallet (so we can detect restored wallets). | |
GetMainSignals().ChainStateFlushed(m_chain.GetLocator()); | |
} | |
} catch (const std::runtime_error& e) { | |
return AbortNode(state, std::string("System error while flushing: ") + e.what()); | |
} | |
return true; | |
} | |
void CChainState::ForceFlushStateToDisk() { | |
BlockValidationState state; | |
const CChainParams& chainparams = Params(); | |
if (!this->FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS)) { | |
LogPrintf("%s: failed to flush state (%s)\n", __func__, state.ToString()); | |
} | |
} | |
void CChainState::PruneAndFlush() { | |
BlockValidationState state; | |
fCheckForPruning = true; | |
const CChainParams& chainparams = Params(); | |
if (!this->FlushStateToDisk(chainparams, state, FlushStateMode::NONE)) { | |
LogPrintf("%s: failed to flush state (%s)\n", __func__, state.ToString()); | |
} | |
} | |
static void DoWarning(const std::string& strWarning) | |
{ | |
static bool fWarned = false; | |
SetMiscWarning(strWarning); | |
if (!fWarned) { | |
AlertNotify(strWarning); | |
fWarned = true; | |
} | |
} | |
/** Private helper function that concatenates warning messages. */ | |
static void AppendWarning(std::string& res, const std::string& warn) | |
{ | |
if (!res.empty()) res += ", "; | |
res += warn; | |
} | |
/** Check warning conditions and do some notifications on new chain tip set. */ | |
void static UpdateTip(const CBlockIndex* pindexNew, const CChainParams& chainParams) | |
EXCLUSIVE_LOCKS_REQUIRED(::cs_main) | |
{ | |
// New best block | |
mempool.AddTransactionsUpdated(1); | |
{ | |
LOCK(g_best_block_mutex); | |
g_best_block = pindexNew->GetBlockHash(); | |
g_best_block_cv.notify_all(); | |
} | |
std::string warningMessages; | |
if (!::ChainstateActive().IsInitialBlockDownload()) | |
{ | |
int nUpgraded = 0; | |
const CBlockIndex* pindex = pindexNew; | |
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) { | |
WarningBitsConditionChecker checker(bit); | |
ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]); | |
if (state == ThresholdState::ACTIVE || state == ThresholdState::LOCKED_IN) { | |
const std::string strWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)").translated, bit); | |
if (state == ThresholdState::ACTIVE) { | |
DoWarning(strWarning); | |
} else { | |
AppendWarning(warningMessages, strWarning); | |
} | |
} | |
} | |
// Check the version of the last 100 blocks to see if we need to upgrade: | |
for (int i = 0; i < 100 && pindex != nullptr; i++) | |
{ | |
int32_t nExpectedVersion = ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus()); | |
if (pindex->nVersion > VERSIONBITS_LAST_OLD_BLOCK_VERSION && (pindex->nVersion & ~nExpectedVersion) != 0) | |
++nUpgraded; | |
pindex = pindex->pprev; | |
} | |
if (nUpgraded > 0) | |
AppendWarning(warningMessages, strprintf(_("%d of last 100 blocks have unexpected version").translated, nUpgraded)); | |
} | |
LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)%s\n", __func__, | |
pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, pindexNew->nVersion, | |
log(pindexNew->nChainWork.getdouble())/log(2.0), (unsigned long)pindexNew->nChainTx, | |
FormatISO8601DateTime(pindexNew->GetBlockTime()), | |
GuessVerificationProgress(chainParams.TxData(), pindexNew), ::ChainstateActive().CoinsTip().DynamicMemoryUsage() * (1.0 / (1<<20)), ::ChainstateActive().CoinsTip().GetCacheSize(), | |
!warningMessages.empty() ? strprintf(" warning='%s'", warningMessages) : ""); | |
} | |
/** Disconnect m_chain's tip. | |
* After calling, the mempool will be in an inconsistent state, with | |
* transactions from disconnected blocks being added to disconnectpool. You | |
* should make the mempool consistent again by calling UpdateMempoolForReorg. | |
* with cs_main held. | |
* | |
* If disconnectpool is nullptr, then no disconnected transactions are added to | |
* disconnectpool (note that the caller is responsible for mempool consistency | |
* in any case). | |
*/ | |
bool CChainState::DisconnectTip(BlockValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool) | |
{ | |
CBlockIndex *pindexDelete = m_chain.Tip(); | |
assert(pindexDelete); | |
// Read block from disk. | |
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(); | |
CBlock& block = *pblock; | |
if (!ReadBlockFromDisk(block, pindexDelete, chainparams.GetConsensus())) | |
return error("DisconnectTip(): Failed to read block"); | |
// Apply the block atomically to the chain state. | |
int64_t nStart = GetTimeMicros(); | |
{ | |
CCoinsViewCache view(&CoinsTip()); | |
assert(view.GetBestBlock() == pindexDelete->GetBlockHash()); | |
if (DisconnectBlock(block, pindexDelete, view) != DISCONNECT_OK) | |
return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString()); | |
bool flushed = view.Flush(); | |
assert(flushed); | |
} | |
LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * MILLI); | |
// Write the chain state to disk, if necessary. | |
if (!FlushStateToDisk(chainparams, state, FlushStateMode::IF_NEEDED)) | |
return false; | |
if (disconnectpool) { | |
// Save transactions to re-add to mempool at end of reorg | |
for (auto it = block.vtx.rbegin(); it != block.vtx.rend(); ++it) { | |
disconnectpool->addTransaction(*it); | |
} | |
while (disconnectpool->DynamicMemoryUsage() > MAX_DISCONNECTED_TX_POOL_SIZE * 1000) { | |
// Drop the earliest entry, and remove its children from the mempool. | |
auto it = disconnectpool->queuedTx.get<insertion_order>().begin(); | |
mempool.removeRecursive(**it, MemPoolRemovalReason::REORG); | |
disconnectpool->removeEntry(it); | |
} | |
} | |
m_chain.SetTip(pindexDelete->pprev); | |
UpdateTip(pindexDelete->pprev, chainparams); | |
// Let wallets know transactions went from 1-confirmed to | |
// 0-confirmed or conflicted: | |
GetMainSignals().BlockDisconnected(pblock, pindexDelete); | |
return true; | |
} | |
static int64_t nTimeReadFromDisk = 0; | |
static int64_t nTimeConnectTotal = 0; | |
static int64_t nTimeFlush = 0; | |
static int64_t nTimeChainState = 0; | |
static int64_t nTimePostConnect = 0; | |
struct PerBlockConnectTrace { | |
CBlockIndex* pindex = nullptr; | |
std::shared_ptr<const CBlock> pblock; | |
PerBlockConnectTrace() {} | |
}; | |
/** | |
* Used to track blocks whose transactions were applied to the UTXO state as a | |
* part of a single ActivateBestChainStep call. | |
* | |
* This class is single-use, once you call GetBlocksConnected() you have to throw | |
* it away and make a new one. | |
*/ | |
class ConnectTrace { | |
private: | |
std::vector<PerBlockConnectTrace> blocksConnected; | |
public: | |
explicit ConnectTrace() : blocksConnected(1) {} | |
void BlockConnected(CBlockIndex* pindex, std::shared_ptr<const CBlock> pblock) { | |
assert(!blocksConnected.back().pindex); | |
assert(pindex); | |
assert(pblock); | |
blocksConnected.back().pindex = pindex; | |
blocksConnected.back().pblock = std::move(pblock); | |
blocksConnected.emplace_back(); | |
} | |
std::vector<PerBlockConnectTrace>& GetBlocksConnected() { | |
// We always keep one extra block at the end of our list because | |
// blocks are added after all the conflicted transactions have | |
// been filled in. Thus, the last entry should always be an empty | |
// one waiting for the transactions from the next block. We pop | |
// the last entry here to make sure the list we return is sane. | |
assert(!blocksConnected.back().pindex); | |
blocksConnected.pop_back(); | |
return blocksConnected; | |
} | |
}; | |
/** | |
* Connect a new block to m_chain. pblock is either nullptr or a pointer to a CBlock | |
* corresponding to pindexNew, to bypass loading it again from disk. | |
* | |
* The block is added to connectTrace if connection succeeds. | |
*/ | |
bool CChainState::ConnectTip(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool) | |
{ | |
assert(pindexNew->pprev == m_chain.Tip()); | |
// Read block from disk. | |
int64_t nTime1 = GetTimeMicros(); | |
std::shared_ptr<const CBlock> pthisBlock; | |
if (!pblock) { | |
std::shared_ptr<CBlock> pblockNew = std::make_shared<CBlock>(); | |
if (!ReadBlockFromDisk(*pblockNew, pindexNew, chainparams.GetConsensus())) | |
return AbortNode(state, "Failed to read block"); | |
pthisBlock = pblockNew; | |
} else { | |
pthisBlock = pblock; | |
} | |
const CBlock& blockConnecting = *pthisBlock; | |
// Apply the block atomically to the chain state. | |
int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1; | |
int64_t nTime3; | |
LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * MILLI, nTimeReadFromDisk * MICRO); | |
{ | |
CCoinsViewCache view(&CoinsTip()); | |
bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, chainparams); | |
GetMainSignals().BlockChecked(blockConnecting, state); | |
if (!rv) { | |
if (state.IsInvalid()) | |
InvalidBlockFound(pindexNew, state); | |
return error("%s: ConnectBlock %s failed, %s", __func__, pindexNew->GetBlockHash().ToString(), state.ToString()); | |
} | |
nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2; | |
assert(nBlocksTotal > 0); | |
LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime3 - nTime2) * MILLI, nTimeConnectTotal * MICRO, nTimeConnectTotal * MILLI / nBlocksTotal); | |
bool flushed = view.Flush(); | |
assert(flushed); | |
} | |
int64_t nTime4 = GetTimeMicros(); nTimeFlush += nTime4 - nTime3; | |
LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime4 - nTime3) * MILLI, nTimeFlush * MICRO, nTimeFlush * MILLI / nBlocksTotal); | |
// Write the chain state to disk, if necessary. | |
if (!FlushStateToDisk(chainparams, state, FlushStateMode::IF_NEEDED)) | |
return false; | |
int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4; | |
LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime5 - nTime4) * MILLI, nTimeChainState * MICRO, nTimeChainState * MILLI / nBlocksTotal); | |
// Remove conflicting transactions from the mempool.; | |
mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight); | |
disconnectpool.removeForBlock(blockConnecting.vtx); | |
// Update m_chain & related variables. | |
m_chain.SetTip(pindexNew); | |
UpdateTip(pindexNew, chainparams); | |
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; | |
LogPrint(BCLog::BENCH, " - Connect postprocess: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime5) * MILLI, nTimePostConnect * MICRO, nTimePostConnect * MILLI / nBlocksTotal); | |
LogPrint(BCLog::BENCH, "- Connect block: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime6 - nTime1) * MILLI, nTimeTotal * MICRO, nTimeTotal * MILLI / nBlocksTotal); | |
connectTrace.BlockConnected(pindexNew, std::move(pthisBlock)); | |
return true; | |
} | |
/** | |
* Return the tip of the chain with the most work in it, that isn't | |
* known to be invalid (it's however far from certain to be valid). | |
*/ | |
CBlockIndex* CChainState::FindMostWorkChain() { | |
do { | |
CBlockIndex *pindexNew = nullptr; | |
// Find the best candidate header. | |
{ | |
std::set<CBlockIndex*, CBlockIndexWorkComparator>::reverse_iterator it = setBlockIndexCandidates.rbegin(); | |
if (it == setBlockIndexCandidates.rend()) | |
return nullptr; | |
pindexNew = *it; | |
} | |
// Check whether all blocks on the path between the currently active chain and the candidate are valid. | |
// Just going until the active chain is an optimization, as we know all blocks in it are valid already. | |
CBlockIndex *pindexTest = pindexNew; | |
bool fInvalidAncestor = false; | |
while (pindexTest && !m_chain.Contains(pindexTest)) { | |
assert(pindexTest->HaveTxsDownloaded() || pindexTest->nHeight == 0); | |
// Pruned nodes may have entries in setBlockIndexCandidates for | |
// which block files have been deleted. Remove those as candidates | |
// for the most work chain if we come across them; we can't switch | |
// to a chain unless we have all the non-active-chain parent blocks. | |
bool fFailedChain = pindexTest->nStatus & BLOCK_FAILED_MASK; | |
bool fMissingData = !(pindexTest->nStatus & BLOCK_HAVE_DATA); | |
if (fFailedChain || fMissingData) { | |
// Candidate chain is not usable (either invalid or missing data) | |
if (fFailedChain && (pindexBestInvalid == nullptr || pindexNew->nChainWork > pindexBestInvalid->nChainWork)) | |
pindexBestInvalid = pindexNew; | |
CBlockIndex *pindexFailed = pindexNew; | |
// Remove the entire chain from the set. | |
while (pindexTest != pindexFailed) { | |
if (fFailedChain) { | |
pindexFailed->nStatus |= BLOCK_FAILED_CHILD; | |
} else if (fMissingData) { | |
// If we're missing data, then add back to m_blocks_unlinked, | |
// so that if the block arrives in the future we can try adding | |
// to setBlockIndexCandidates again. | |
m_blockman.m_blocks_unlinked.insert( | |
std::make_pair(pindexFailed->pprev, pindexFailed)); | |
} | |
setBlockIndexCandidates.erase(pindexFailed); | |
pindexFailed = pindexFailed->pprev; | |
} | |
setBlockIndexCandidates.erase(pindexTest); | |
fInvalidAncestor = true; | |
break; | |
} | |
pindexTest = pindexTest->pprev; | |
} | |
if (!fInvalidAncestor) | |
return pindexNew; | |
} while(true); | |
} | |
/** Delete all entries in setBlockIndexCandidates that are worse than the current tip. */ | |
void CChainState::PruneBlockIndexCandidates() { | |
// Note that we can't delete the current block itself, as we may need to return to it later in case a | |
// reorganization to a better block fails. | |
std::set<CBlockIndex*, CBlockIndexWorkComparator>::iterator it = setBlockIndexCandidates.begin(); | |
while (it != setBlockIndexCandidates.end() && setBlockIndexCandidates.value_comp()(*it, m_chain.Tip())) { | |
setBlockIndexCandidates.erase(it++); | |
} | |
// Either the current tip or a successor of it we're working towards is left in setBlockIndexCandidates. | |
assert(!setBlockIndexCandidates.empty()); | |
} | |
/** | |
* Try to make some progress towards making pindexMostWork the active block. | |
* pblock is either nullptr or a pointer to a CBlock corresponding to pindexMostWork. | |
* | |
* @returns true unless a system error occurred | |
*/ | |
bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) | |
{ | |
AssertLockHeld(cs_main); | |
const CBlockIndex *pindexOldTip = m_chain.Tip(); | |
const CBlockIndex *pindexFork = m_chain.FindFork(pindexMostWork); | |
// Disconnect active blocks which are no longer in the best chain. | |
bool fBlocksDisconnected = false; | |
DisconnectedBlockTransactions disconnectpool; | |
while (m_chain.Tip() && m_chain.Tip() != pindexFork) { | |
if (!DisconnectTip(state, chainparams, &disconnectpool)) { | |
// This is likely a fatal error, but keep the mempool consistent, | |
// just in case. Only remove from the mempool in this case. | |
UpdateMempoolForReorg(disconnectpool, false); | |
// If we're unable to disconnect a block during normal operation, | |
// then that is a failure of our local system -- we should abort | |
// rather than stay on a less work chain. | |
AbortNode(state, "Failed to disconnect block; see debug.log for details"); | |
return false; | |
} | |
fBlocksDisconnected = true; | |
} | |
// Build list of new blocks to connect. | |
std::vector<CBlockIndex*> vpindexToConnect; | |
bool fContinue = true; | |
int nHeight = pindexFork ? pindexFork->nHeight : -1; | |
while (fContinue && nHeight != pindexMostWork->nHeight) { | |
// Don't iterate the entire list of potential improvements toward the best tip, as we likely only need | |
// a few blocks along the way. | |
int nTargetHeight = std::min(nHeight + 32, pindexMostWork->nHeight); | |
vpindexToConnect.clear(); | |
vpindexToConnect.reserve(nTargetHeight - nHeight); | |
CBlockIndex *pindexIter = pindexMostWork->GetAncestor(nTargetHeight); | |
while (pindexIter && pindexIter->nHeight != nHeight) { | |
vpindexToConnect.push_back(pindexIter); | |
pindexIter = pindexIter->pprev; | |
} | |
nHeight = nTargetHeight; | |
// Connect new blocks. | |
for (CBlockIndex *pindexConnect : reverse_iterate(vpindexToConnect)) { | |
if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr<const CBlock>(), connectTrace, disconnectpool)) { | |
if (state.IsInvalid()) { | |
// The block violates a consensus rule. | |
if (state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { | |
InvalidChainFound(vpindexToConnect.front()); | |
} | |
state = BlockValidationState(); | |
fInvalidFound = true; | |
fContinue = false; | |
break; | |
} else { | |
// A system error occurred (disk space, database error, ...). | |
// Make the mempool consistent with the current tip, just in case | |
// any observers try to use it before shutdown. | |
UpdateMempoolForReorg(disconnectpool, false); | |
return false; | |
} | |
} else { | |
PruneBlockIndexCandidates(); | |
if (!pindexOldTip || m_chain.Tip()->nChainWork > pindexOldTip->nChainWork) { | |
// We're in a better position than we were. Return temporarily to release the lock. | |
fContinue = false; | |
break; | |
} | |
} | |
} | |
} | |
if (fBlocksDisconnected) { | |
// If any blocks were disconnected, disconnectpool may be non empty. Add | |
// any disconnected transactions back to the mempool. | |
UpdateMempoolForReorg(disconnectpool, true); | |
} | |
mempool.check(&CoinsTip()); | |
// Callbacks/notifications for a new best chain. | |
if (fInvalidFound) | |
CheckForkWarningConditionsOnNewFork(vpindexToConnect.back()); | |
else | |
CheckForkWarningConditions(); | |
return true; | |
} | |
static bool NotifyHeaderTip() LOCKS_EXCLUDED(cs_main) { | |
bool fNotify = false; | |
bool fInitialBlockDownload = false; | |
static CBlockIndex* pindexHeaderOld = nullptr; | |
CBlockIndex* pindexHeader = nullptr; | |
{ | |
LOCK(cs_main); | |
pindexHeader = pindexBestHeader; | |
if (pindexHeader != pindexHeaderOld) { | |
fNotify = true; | |
fInitialBlockDownload = ::ChainstateActive().IsInitialBlockDownload(); | |
pindexHeaderOld = pindexHeader; | |
} | |
} | |
// Send block tip changed notifications without cs_main | |
if (fNotify) { | |
uiInterface.NotifyHeaderTip(fInitialBlockDownload, pindexHeader); | |
} | |
return fNotify; | |
} | |
static void LimitValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main) { | |
AssertLockNotHeld(cs_main); | |
if (GetMainSignals().CallbacksPending() > 10) { | |
SyncWithValidationInterfaceQueue(); | |
} | |
} | |
bool CChainState::ActivateBestChain(BlockValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) { | |
// Note that while we're often called here from ProcessNewBlock, this is | |
// far from a guarantee. Things in the P2P/RPC will often end up calling | |
// us in the middle of ProcessNewBlock - do not assume pblock is set | |
// sanely for performance or correctness! | |
AssertLockNotHeld(cs_main); | |
// ABC maintains a fair degree of expensive-to-calculate internal state | |
// because this function periodically releases cs_main so that it does not lock up other threads for too long | |
// during large connects - and to allow for e.g. the callback queue to drain | |
// we use m_cs_chainstate to enforce mutual exclusion so that only one caller may execute this function at a time | |
LOCK(m_cs_chainstate); | |
CBlockIndex *pindexMostWork = nullptr; | |
CBlockIndex *pindexNewTip = nullptr; | |
int nStopAtHeight = gArgs.GetArg("-stopatheight", DEFAULT_STOPATHEIGHT); | |
do { | |
boost::this_thread::interruption_point(); | |
// Block until the validation queue drains. This should largely | |
// never happen in normal operation, however may happen during | |
// reindex, causing memory blowup if we run too far ahead. | |
// Note that if a validationinterface callback ends up calling | |
// ActivateBestChain this may lead to a deadlock! We should | |
// probably have a DEBUG_LOCKORDER test for this in the future. | |
LimitValidationInterfaceQueue(); | |
{ | |
LOCK2(cs_main, ::mempool.cs); // Lock transaction pool for at least as long as it takes for connectTrace to be consumed | |
CBlockIndex* starting_tip = m_chain.Tip(); | |
bool blocks_connected = false; | |
do { | |
// We absolutely may not unlock cs_main until we've made forward progress | |
// (with the exception of shutdown due to hardware issues, low disk space, etc). | |
ConnectTrace connectTrace; // Destructed before cs_main is unlocked | |
if (pindexMostWork == nullptr) { | |
pindexMostWork = FindMostWorkChain(); | |
} | |
// Whether we have anything to do at all. | |
if (pindexMostWork == nullptr || pindexMostWork == m_chain.Tip()) { | |
break; | |
} | |
bool fInvalidFound = false; | |
std::shared_ptr<const CBlock> nullBlockPtr; | |
if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : nullBlockPtr, fInvalidFound, connectTrace)) { | |