0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-12 11:19:08 -05:00

validation: Add chainstate member to MemPoolAccept

This commit is contained in:
Carl Dong 2020-09-16 16:53:57 -04:00
parent 4c15942b79
commit d8a816329c

View file

@ -458,11 +458,13 @@ namespace {
class MemPoolAccept class MemPoolAccept
{ {
public: public:
explicit MemPoolAccept(CTxMemPool& mempool) : m_pool(mempool), m_view(&m_dummy), m_viewmempool(&::ChainstateActive().CoinsTip(), m_pool), explicit MemPoolAccept(CTxMemPool& mempool, CChainState& active_chainstate) : m_pool(mempool), m_view(&m_dummy), m_viewmempool(&active_chainstate.CoinsTip(), m_pool), m_active_chainstate(active_chainstate),
m_limit_ancestors(gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT)), m_limit_ancestors(gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT)),
m_limit_ancestor_size(gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000), m_limit_ancestor_size(gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000),
m_limit_descendants(gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT)), m_limit_descendants(gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT)),
m_limit_descendant_size(gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000) {} m_limit_descendant_size(gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000) {
assert(std::addressof(::ChainstateActive()) == std::addressof(m_active_chainstate));
}
// We put the arguments we're handed into a struct, so we can pass them // We put the arguments we're handed into a struct, so we can pass them
// around easier. // around easier.
@ -547,6 +549,8 @@ private:
CCoinsViewMemPool m_viewmempool; CCoinsViewMemPool m_viewmempool;
CCoinsView m_dummy; CCoinsView m_dummy;
CChainState& m_active_chainstate;
// The package limits in effect at the time of invocation. // The package limits in effect at the time of invocation.
const size_t m_limit_ancestors; const size_t m_limit_ancestors;
const size_t m_limit_ancestor_size; const size_t m_limit_ancestor_size;
@ -601,7 +605,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// Only accept nLockTime-using transactions that can be mined in the next // 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 // block; we don't want our mempool filled up with transactions that can't
// be mined yet. // be mined yet.
if (!CheckFinalTx(::ChainActive().Tip(), tx, STANDARD_LOCKTIME_VERIFY_FLAGS)) assert(std::addressof(::ChainActive()) == std::addressof(m_active_chainstate.m_chain));
if (!CheckFinalTx(m_active_chainstate.m_chain.Tip(), tx, STANDARD_LOCKTIME_VERIFY_FLAGS))
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-final"); return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-final");
// is it already in the memory pool? // is it already in the memory pool?
@ -649,7 +654,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
LockPoints lp; LockPoints lp;
m_view.SetBackend(m_viewmempool); m_view.SetBackend(m_viewmempool);
const CCoinsViewCache& coins_cache = ::ChainstateActive().CoinsTip(); assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(m_active_chainstate.CoinsTip()));
const CCoinsViewCache& coins_cache = m_active_chainstate.CoinsTip();
// do all inputs exist? // do all inputs exist?
for (const CTxIn& txin : tx.vin) { for (const CTxIn& txin : tx.vin) {
if (!coins_cache.HaveCoinInCache(txin.prevout)) { if (!coins_cache.HaveCoinInCache(txin.prevout)) {
@ -685,16 +691,19 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// be mined yet. // be mined yet.
// Must keep pool.cs for this unless we change CheckSequenceLocks to take a // Must keep pool.cs for this unless we change CheckSequenceLocks to take a
// CoinsViewCache instead of create its own // CoinsViewCache instead of create its own
if (!CheckSequenceLocks(::ChainstateActive(), m_pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) assert(std::addressof(::ChainstateActive()) == std::addressof(m_active_chainstate));
if (!CheckSequenceLocks(m_active_chainstate, m_pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-BIP68-final"); return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-BIP68-final");
if (!Consensus::CheckTxInputs(tx, state, m_view, g_chainman.m_blockman.GetSpendHeight(m_view), ws.m_base_fees)) { assert(std::addressof(g_chainman.m_blockman) == std::addressof(m_active_chainstate.m_blockman));
if (!Consensus::CheckTxInputs(tx, state, m_view, m_active_chainstate.m_blockman.GetSpendHeight(m_view), ws.m_base_fees)) {
return false; // state filled in by CheckTxInputs return false; // state filled in by CheckTxInputs
} }
// Check for non-standard pay-to-script-hash in inputs // Check for non-standard pay-to-script-hash in inputs
const auto& params = args.m_chainparams.GetConsensus(); const auto& params = args.m_chainparams.GetConsensus();
auto taproot_state = VersionBitsState(::ChainActive().Tip(), params, Consensus::DEPLOYMENT_TAPROOT, versionbitscache); assert(std::addressof(::ChainActive()) == std::addressof(m_active_chainstate.m_chain));
auto taproot_state = VersionBitsState(m_active_chainstate.m_chain.Tip(), params, Consensus::DEPLOYMENT_TAPROOT, versionbitscache);
if (fRequireStandard && !AreInputsStandard(tx, m_view, taproot_state == ThresholdState::ACTIVE)) { if (fRequireStandard && !AreInputsStandard(tx, m_view, taproot_state == ThresholdState::ACTIVE)) {
return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs"); return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs");
} }
@ -720,7 +729,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
} }
} }
entry.reset(new CTxMemPoolEntry(ptx, ws.m_base_fees, nAcceptTime, ::ChainActive().Height(), assert(std::addressof(::ChainActive()) == std::addressof(m_active_chainstate.m_chain));
entry.reset(new CTxMemPoolEntry(ptx, ws.m_base_fees, nAcceptTime, m_active_chainstate.m_chain.Height(),
fSpendsCoinbase, nSigOpsCost, lp)); fSpendsCoinbase, nSigOpsCost, lp));
unsigned int nSize = entry->GetTxSize(); unsigned int nSize = entry->GetTxSize();
@ -972,8 +982,10 @@ bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws, P
// There is a similar check in CreateNewBlock() to prevent creating // There is a similar check in CreateNewBlock() to prevent creating
// invalid blocks (using TestBlockValidity), however allowing such // invalid blocks (using TestBlockValidity), however allowing such
// transactions into the mempool can be exploited as a DoS attack. // transactions into the mempool can be exploited as a DoS attack.
unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(::ChainActive().Tip(), chainparams.GetConsensus()); assert(std::addressof(::ChainActive()) == std::addressof(m_active_chainstate.m_chain));
if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags, txdata, ::ChainstateActive().CoinsTip())) { unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(m_active_chainstate.m_chain.Tip(), chainparams.GetConsensus());
assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(m_active_chainstate.CoinsTip()));
if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags, txdata, m_active_chainstate.CoinsTip())) {
return error("%s: BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s", return error("%s: BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s",
__func__, hash.ToString(), state.ToString()); __func__, hash.ToString(), state.ToString());
} }
@ -1013,14 +1025,16 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
// - it's not being re-added during a reorg which bypasses typical mempool fee limits // - it's not being re-added during a reorg which bypasses typical mempool fee limits
// - the node is not behind // - the node is not behind
// - the transaction is not dependent on any other transactions in the mempool // - the transaction is not dependent on any other transactions in the mempool
bool validForFeeEstimation = !fReplacementTransaction && !bypass_limits && IsCurrentForFeeEstimation(::ChainstateActive()) && m_pool.HasNoInputsOf(tx); assert(std::addressof(::ChainstateActive()) == std::addressof(m_active_chainstate));
bool validForFeeEstimation = !fReplacementTransaction && !bypass_limits && IsCurrentForFeeEstimation(m_active_chainstate) && m_pool.HasNoInputsOf(tx);
// Store transaction in memory // Store transaction in memory
m_pool.addUnchecked(*entry, setAncestors, validForFeeEstimation); m_pool.addUnchecked(*entry, setAncestors, validForFeeEstimation);
// trim mempool and check if tx was trimmed // trim mempool and check if tx was trimmed
if (!bypass_limits) { if (!bypass_limits) {
LimitMempoolSize(m_pool, ::ChainstateActive().CoinsTip(), gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(m_active_chainstate.CoinsTip()));
LimitMempoolSize(m_pool, m_active_chainstate.CoinsTip(), gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)});
if (!m_pool.exists(hash)) if (!m_pool.exists(hash))
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool full"); return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool full");
} }
@ -1069,7 +1083,7 @@ static MempoolAcceptResult AcceptToMemoryPoolWithTime(const CChainParams& chainp
std::vector<COutPoint> coins_to_uncache; std::vector<COutPoint> coins_to_uncache;
MemPoolAccept::ATMPArgs args { chainparams, nAcceptTime, bypass_limits, coins_to_uncache, test_accept }; MemPoolAccept::ATMPArgs args { chainparams, nAcceptTime, bypass_limits, coins_to_uncache, test_accept };
const MempoolAcceptResult result = MemPoolAccept(pool).AcceptSingleTransaction(tx, args); const MempoolAcceptResult result = MemPoolAccept(pool, ::ChainstateActive()).AcceptSingleTransaction(tx, args);
if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
// Remove coins that were not present in the coins cache before calling ATMPW; // 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 // this is to prevent memory DoS in case we receive a large number of