diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 1395fa021f..5969b68e27 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -18,6 +18,7 @@ #include #include #include // removeForBlock paklist transition +#include CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee, int64_t _nTime, unsigned int _entryHeight, @@ -548,7 +549,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx) /** * Called when a block is connected. Removes from mempool and updates the miner fee estimator. */ -void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned int nBlockHeight, bool pak_transition) +void CTxMemPool::removeForBlock(const std::vector& vtx, unsigned int nBlockHeight, const CBlockIndex* p_block_index_new) { LOCK(cs); std::vector entries; @@ -574,6 +575,40 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigne ClearPrioritisation(tx->GetHash()); } + // Eject transactions that are invalid for *following* block due to transition + // We check every epoch_length blocks due to peg-ins expiring an epoch after + // being changed + if (p_block_index_new) { + const CChainParams& chainparams = Params(); + uint32_t epoch_length = chainparams.GetConsensus().dynamic_epoch_length; + if ((p_block_index_new->nHeight+1) % epoch_length == 0) { + CPAKList enforced_paklist = GetActivePAKList(p_block_index_new, chainparams.GetConsensus()); + std::vector tx_to_remove; + for (const auto& entry : mapTx) { + const CTransaction& tx = entry.GetTx(); + if (chainparams.GetEnforcePak() && !IsPAKValidTx(tx, enforced_paklist)) { + tx_to_remove.push_back(MakeTransactionRef(tx)); + continue; + } + + std::vector fedpegscripts = GetValidFedpegScripts(p_block_index_new, chainparams.GetConsensus(), true /* nextblock_validation */); + for (size_t nIn = 0; nIn < tx.vin.size(); nIn++) { + const CTxIn& in = tx.vin[nIn]; + std::string err; + if (in.m_is_pegin && (!tx.HasWitness() || !IsValidPeginWitness(tx.witness.vtxinwit[nIn].m_pegin_witness, fedpegscripts, in.prevout, err, true /* check_depth */))) { + tx_to_remove.push_back(MakeTransactionRef(tx)); + break; + } + } + } + for (auto& tx : tx_to_remove) { + const uint256 tx_id = tx->GetHash(); + removeRecursive(*tx, MemPoolRemovalReason::BLOCK); + ClearPrioritisation(tx_id); + } + } + } + lastRollingFeeUpdate = GetTime(); blockSinceLastRollingFeeBump = true; } diff --git a/src/validation.cpp b/src/validation.cpp index f2fea52fae..c24c2cdafe 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2658,10 +2658,9 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp 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.; - // ELEMENTS: We also eject now-invalid peg-outs based on block transition if not config list set - // If config is set, this means all peg-outs have been filtered for that list already and other - // functionaries aren't matching your list. Operator should restart with no list or new matching list. - mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight, (paklist && !g_paklist_config)); + // ELEMENTS: We also eject peg-outs with now-invalid PAK proofs + // as well as peg-in inputs during transitional periods. + mempool.removeForBlock(blockConnecting.vtx, pindexNew->nHeight, pindexNew); disconnectpool.removeForBlock(blockConnecting.vtx); // Update chainActive & related variables. chainActive.SetTip(pindexNew);