mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-19 13:27:35 +02:00
Merge 828bb776d2 into merged_master (Bitcoin PR #20750)
This commit is contained in:
commit
4268df69bc
14 changed files with 115 additions and 75 deletions
|
|
@ -213,9 +213,10 @@ static FILE* OpenUndoFile(const FlatFilePos &pos, bool fReadOnly = false);
|
|||
static FlatFileSeq BlockFileSeq();
|
||||
static FlatFileSeq UndoFileSeq();
|
||||
|
||||
bool CheckFinalTx(const CTransaction &tx, int flags)
|
||||
bool CheckFinalTx(const CBlockIndex* active_chain_tip, const CTransaction &tx, int flags)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
assert(std::addressof(*::ChainActive().Tip()) == std::addressof(*active_chain_tip));
|
||||
|
||||
// By convention a negative value for flags indicates that the
|
||||
// current network-enforced consensus rules should be used. In
|
||||
|
|
@ -231,7 +232,7 @@ bool CheckFinalTx(const CTransaction &tx, int flags)
|
|||
// 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;
|
||||
const int nBlockHeight = active_chain_tip->nHeight + 1;
|
||||
|
||||
// BIP113 requires that time-locked transactions have nLockTime set to
|
||||
// less than the median time of the previous block they're contained in.
|
||||
|
|
@ -239,13 +240,13 @@ bool CheckFinalTx(const CTransaction &tx, int flags)
|
|||
// 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()
|
||||
? active_chain_tip->GetMedianTimePast()
|
||||
: GetAdjustedTime();
|
||||
|
||||
return IsFinalTx(tx, nBlockHeight, nBlockTime);
|
||||
}
|
||||
|
||||
bool TestLockPointValidity(const LockPoints* lp)
|
||||
bool TestLockPointValidity(CChain& active_chain, const LockPoints* lp)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
assert(lp);
|
||||
|
|
@ -254,7 +255,8 @@ bool TestLockPointValidity(const LockPoints* lp)
|
|||
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)) {
|
||||
assert(std::addressof(::ChainActive()) == std::addressof(active_chain));
|
||||
if (!active_chain.Contains(lp->maxInputBlock)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -263,22 +265,28 @@ bool TestLockPointValidity(const LockPoints* lp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flags, LockPoints* lp, bool useExistingLockPoints)
|
||||
bool CheckSequenceLocks(CChainState& active_chainstate,
|
||||
const CTxMemPool& pool,
|
||||
const CTransaction& tx,
|
||||
int flags,
|
||||
LockPoints* lp,
|
||||
bool useExistingLockPoints)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
AssertLockHeld(pool.cs);
|
||||
assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate));
|
||||
|
||||
CBlockIndex* tip = ::ChainActive().Tip();
|
||||
CBlockIndex* tip = active_chainstate.m_chain.Tip();
|
||||
assert(tip != nullptr);
|
||||
|
||||
CBlockIndex index;
|
||||
index.pprev = tip;
|
||||
// CheckSequenceLocks() uses ::ChainActive().Height()+1 to evaluate
|
||||
// CheckSequenceLocks() uses active_chainstate.m_chain.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()
|
||||
// *next* block, we need to use one more than active_chainstate.m_chain.Height()
|
||||
index.nHeight = tip->nHeight + 1;
|
||||
|
||||
std::pair<int, int64_t> lockPair;
|
||||
|
|
@ -288,8 +296,8 @@ bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flag
|
|||
lockPair.second = lp->time;
|
||||
}
|
||||
else {
|
||||
// CoinsTip() contains the UTXO set for ::ChainActive().Tip()
|
||||
CCoinsViewMemPool viewMemPool(&::ChainstateActive().CoinsTip(), pool);
|
||||
// CoinsTip() contains the UTXO set for active_chainstate.m_chain.Tip()
|
||||
CCoinsViewMemPool viewMemPool(&active_chainstate.CoinsTip(), pool);
|
||||
std::vector<int> prevheights;
|
||||
prevheights.resize(tx.vin.size());
|
||||
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
|
||||
|
|
@ -344,7 +352,7 @@ bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flag
|
|||
// 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)
|
||||
static void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache, size_t limit, std::chrono::seconds age)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(pool.cs, ::cs_main)
|
||||
{
|
||||
int expired = pool.Expire(GetTime<std::chrono::seconds>() - age);
|
||||
|
|
@ -354,18 +362,20 @@ static void LimitMempoolSize(CTxMemPool& pool, size_t limit, std::chrono::second
|
|||
|
||||
std::vector<COutPoint> vNoSpendsRemaining;
|
||||
pool.TrimToSize(limit, &vNoSpendsRemaining);
|
||||
assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(coins_cache));
|
||||
for (const COutPoint& removed : vNoSpendsRemaining)
|
||||
::ChainstateActive().CoinsTip().Uncache(removed);
|
||||
coins_cache.Uncache(removed);
|
||||
}
|
||||
|
||||
static bool IsCurrentForFeeEstimation() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||
static bool IsCurrentForFeeEstimation(CChainState& active_chainstate) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
if (::ChainstateActive().IsInitialBlockDownload())
|
||||
assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate));
|
||||
if (active_chainstate.IsInitialBlockDownload())
|
||||
return false;
|
||||
if (::ChainActive().Tip()->GetBlockTime() < count_seconds(GetTime<std::chrono::seconds>() - MAX_FEE_ESTIMATION_TIP_AGE))
|
||||
if (active_chainstate.m_chain.Tip()->GetBlockTime() < count_seconds(GetTime<std::chrono::seconds>() - MAX_FEE_ESTIMATION_TIP_AGE))
|
||||
return false;
|
||||
if (::ChainActive().Height() < pindexBestHeader->nHeight - 1)
|
||||
if (active_chainstate.m_chain.Height() < pindexBestHeader->nHeight - 1)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -383,10 +393,11 @@ static bool IsCurrentForFeeEstimation() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
|||
* and instead just erase from the mempool as needed.
|
||||
*/
|
||||
|
||||
static void UpdateMempoolForReorg(CTxMemPool& mempool, DisconnectedBlockTransactions& disconnectpool, bool fAddToMempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, mempool.cs)
|
||||
static void UpdateMempoolForReorg(CChainState& active_chainstate, CTxMemPool& mempool, DisconnectedBlockTransactions& disconnectpool, bool fAddToMempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, mempool.cs)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
AssertLockHeld(mempool.cs);
|
||||
assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate));
|
||||
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
|
||||
|
|
@ -398,7 +409,7 @@ static void UpdateMempoolForReorg(CTxMemPool& mempool, DisconnectedBlockTransact
|
|||
while (it != disconnectpool.queuedTx.get<insertion_order>().rend()) {
|
||||
// ignore validation errors in resurrected transactions
|
||||
if (!fAddToMempool || (*it)->IsCoinBase() ||
|
||||
AcceptToMemoryPool(mempool, *it, true /* bypass_limits */).m_result_type != MempoolAcceptResult::ResultType::VALID) {
|
||||
AcceptToMemoryPool(active_chainstate, mempool, *it, true /* bypass_limits */).m_result_type != MempoolAcceptResult::ResultType::VALID) {
|
||||
// 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);
|
||||
|
|
@ -416,9 +427,9 @@ static void UpdateMempoolForReorg(CTxMemPool& mempool, DisconnectedBlockTransact
|
|||
mempool.UpdateTransactionsFromBlock(vHashUpdate);
|
||||
|
||||
// We also need to remove any now-immature transactions
|
||||
mempool.removeForReorg(&::ChainstateActive().CoinsTip(), ::ChainActive().Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
|
||||
mempool.removeForReorg(active_chainstate, 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)});
|
||||
LimitMempoolSize(mempool, active_chainstate.CoinsTip(), gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -428,7 +439,7 @@ static void UpdateMempoolForReorg(CTxMemPool& mempool, DisconnectedBlockTransact
|
|||
* */
|
||||
static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationState& state,
|
||||
const CCoinsViewCache& view, const CTxMemPool& pool,
|
||||
unsigned int flags, PrecomputedTransactionData& txdata)
|
||||
unsigned int flags, PrecomputedTransactionData& txdata, CCoinsViewCache& coins_tip)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
|
|
@ -457,7 +468,8 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationS
|
|||
assert(txFrom->vout.size() > txin.prevout.n);
|
||||
assert(txFrom->vout[txin.prevout.n] == coin.out);
|
||||
} else {
|
||||
const Coin& coinFromUTXOSet = ::ChainstateActive().CoinsTip().AccessCoin(txin.prevout);
|
||||
assert(std::addressof(::ChainstateActive().CoinsTip()) == std::addressof(coins_tip));
|
||||
const Coin& coinFromUTXOSet = coins_tip.AccessCoin(txin.prevout);
|
||||
assert(!coinFromUTXOSet.IsSpent());
|
||||
assert(coinFromUTXOSet.out == coin.out);
|
||||
}
|
||||
|
|
@ -472,11 +484,13 @@ namespace {
|
|||
class MemPoolAccept
|
||||
{
|
||||
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_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) {}
|
||||
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
|
||||
// around easier.
|
||||
|
|
@ -562,6 +576,8 @@ private:
|
|||
CCoinsViewMemPool m_viewmempool;
|
||||
CCoinsView m_dummy;
|
||||
|
||||
CChainState& m_active_chainstate;
|
||||
|
||||
// The package limits in effect at the time of invocation.
|
||||
const size_t m_limit_ancestors;
|
||||
const size_t m_limit_ancestor_size;
|
||||
|
|
@ -625,7 +641,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||
// 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))
|
||||
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");
|
||||
|
||||
// is it already in the memory pool?
|
||||
|
|
@ -688,7 +705,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||
// Used when checking peg-ins
|
||||
std::vector<std::pair<CScript, CScript>> fedpegscripts = GetValidFedpegScripts(::ChainActive().Tip(), chainparams.GetConsensus(), true /* nextblock_validation */);
|
||||
|
||||
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?
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
||||
const CTxIn& txin = tx.vin[i];
|
||||
|
|
@ -746,17 +764,20 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||
// 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))
|
||||
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");
|
||||
|
||||
assert(std::addressof(g_chainman.m_blockman) == std::addressof(m_active_chainstate.m_blockman));
|
||||
CAmountMap fee_map;
|
||||
if (!Consensus::CheckTxInputs(tx, state, m_view, g_chainman.m_blockman.GetSpendHeight(m_view), fee_map, setPeginsSpent, NULL, true, true, fedpegscripts)) {
|
||||
if (!Consensus::CheckTxInputs(tx, state, m_view, m_active_chainstate.m_blockman.GetSpendHeight(m_view), fee_map, setPeginsSpent, NULL, true, true, fedpegscripts)) {
|
||||
return false; // state filled in by CheckTxInputs
|
||||
}
|
||||
|
||||
// Check for non-standard pay-to-script-hash in inputs
|
||||
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)) {
|
||||
return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs");
|
||||
}
|
||||
|
|
@ -789,7 +810,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, setPeginsSpent));
|
||||
unsigned int nSize = entry->GetTxSize();
|
||||
|
||||
|
|
@ -1048,8 +1070,10 @@ bool MemPoolAccept::ConsensusScriptChecks(const ATMPArgs& args, Workspace& ws, P
|
|||
// 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)) {
|
||||
assert(std::addressof(::ChainActive()) == std::addressof(m_active_chainstate.m_chain));
|
||||
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",
|
||||
__func__, hash.ToString(), state.ToString());
|
||||
}
|
||||
|
|
@ -1089,14 +1113,16 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
|
|||
// - 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);
|
||||
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
|
||||
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)});
|
||||
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))
|
||||
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool full");
|
||||
}
|
||||
|
|
@ -1138,6 +1164,7 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
|
|||
|
||||
/** (try to) add transaction to memory pool with a specified acceptance time **/
|
||||
static MempoolAcceptResult AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool,
|
||||
CChainState& active_chainstate,
|
||||
const CTransactionRef &tx, int64_t nAcceptTime,
|
||||
bool bypass_limits, bool test_accept)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||
|
|
@ -1145,7 +1172,8 @@ static MempoolAcceptResult AcceptToMemoryPoolWithTime(const CChainParams& chainp
|
|||
std::vector<COutPoint> coins_to_uncache;
|
||||
MemPoolAccept::ATMPArgs args { chainparams, nAcceptTime, bypass_limits, coins_to_uncache, test_accept };
|
||||
|
||||
const MempoolAcceptResult result = MemPoolAccept(pool).AcceptSingleTransaction(tx, args);
|
||||
assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate));
|
||||
const MempoolAcceptResult result = MemPoolAccept(pool, active_chainstate).AcceptSingleTransaction(tx, args);
|
||||
if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
|
||||
// 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
|
||||
|
|
@ -1153,17 +1181,19 @@ static MempoolAcceptResult AcceptToMemoryPoolWithTime(const CChainParams& chainp
|
|||
// (`CCoinsViewCache::cacheCoins`).
|
||||
|
||||
for (const COutPoint& hashTx : coins_to_uncache)
|
||||
::ChainstateActive().CoinsTip().Uncache(hashTx);
|
||||
active_chainstate.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);
|
||||
active_chainstate.FlushStateToDisk(chainparams, state_dummy, FlushStateMode::PERIODIC);
|
||||
return result;
|
||||
}
|
||||
|
||||
MempoolAcceptResult AcceptToMemoryPool(CTxMemPool& pool, const CTransactionRef &tx, bool bypass_limits, bool test_accept)
|
||||
MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, CTxMemPool& pool, const CTransactionRef& tx,
|
||||
bool bypass_limits, bool test_accept)
|
||||
{
|
||||
return AcceptToMemoryPoolWithTime(Params(), pool, tx, GetTime(), bypass_limits, test_accept);
|
||||
assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate));
|
||||
return AcceptToMemoryPoolWithTime(Params(), pool, active_chainstate, tx, GetTime(), bypass_limits, test_accept);
|
||||
}
|
||||
|
||||
CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, const Consensus::Params& consensusParams, uint256& hashBlock)
|
||||
|
|
@ -2917,7 +2947,7 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChai
|
|||
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(m_mempool, disconnectpool, false);
|
||||
UpdateMempoolForReorg(::ChainstateActive(), m_mempool, 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
|
||||
|
|
@ -2961,7 +2991,7 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChai
|
|||
// 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(m_mempool, disconnectpool, false);
|
||||
UpdateMempoolForReorg(::ChainstateActive(), m_mempool, disconnectpool, false);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -2978,7 +3008,7 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChai
|
|||
if (fBlocksDisconnected) {
|
||||
// If any blocks were disconnected, disconnectpool may be non empty. Add
|
||||
// any disconnected transactions back to the mempool.
|
||||
UpdateMempoolForReorg(m_mempool, disconnectpool, true);
|
||||
UpdateMempoolForReorg(::ChainstateActive(), m_mempool, disconnectpool, true);
|
||||
}
|
||||
m_mempool.check(&CoinsTip());
|
||||
|
||||
|
|
@ -3215,7 +3245,7 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, const CChainParam
|
|||
// transactions back to the mempool if disconnecting was successful,
|
||||
// and we're not doing a very deep invalidation (in which case
|
||||
// keeping the mempool up to date is probably futile anyway).
|
||||
UpdateMempoolForReorg(m_mempool, disconnectpool, /* fAddToMempool = */ (++disconnected <= 10) && ret);
|
||||
UpdateMempoolForReorg(::ChainstateActive(), m_mempool, disconnectpool, /* fAddToMempool = */ (++disconnected <= 10) && ret);
|
||||
if (!ret) return false;
|
||||
assert(invalid_walk_tip->pprev == m_chain.Tip());
|
||||
|
||||
|
|
@ -4515,7 +4545,8 @@ bool static LoadBlockIndexDB(ChainstateManager& chainman, const CChainParams& ch
|
|||
void CChainState::LoadMempool(const ArgsManager& args)
|
||||
{
|
||||
if (args.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
|
||||
::LoadMempool(m_mempool);
|
||||
assert(std::addressof(::ChainstateActive()) == std::addressof(*this));
|
||||
::LoadMempool(m_mempool, *this);
|
||||
}
|
||||
m_mempool.SetIsLoaded(!ShutdownRequested());
|
||||
}
|
||||
|
|
@ -5345,7 +5376,7 @@ int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::D
|
|||
|
||||
static const uint64_t MEMPOOL_DUMP_VERSION = 1;
|
||||
|
||||
bool LoadMempool(CTxMemPool& pool)
|
||||
bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate)
|
||||
{
|
||||
const CChainParams& chainparams = Params();
|
||||
int64_t nExpiryTimeout = gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60;
|
||||
|
|
@ -5385,7 +5416,8 @@ bool LoadMempool(CTxMemPool& pool)
|
|||
}
|
||||
if (nTime > nNow - nExpiryTimeout) {
|
||||
LOCK(cs_main);
|
||||
if (AcceptToMemoryPoolWithTime(chainparams, pool, tx, nTime, false /* bypass_limits */,
|
||||
assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate));
|
||||
if (AcceptToMemoryPoolWithTime(chainparams, pool, active_chainstate, tx, nTime, false /* bypass_limits */,
|
||||
false /* test_accept */).m_result_type == MempoolAcceptResult::ResultType::VALID) {
|
||||
++count;
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue