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:
parent
4c15942b79
commit
d8a816329c
1 changed files with 27 additions and 13 deletions
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue