diff --git a/src/txmempool.cpp b/src/txmempool.cpp --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -698,51 +698,66 @@ AssertLockHeld(cs); AssertLockHeld(::cs_main); + const auto check_final_and_mature = + [this, &active_chainstate, flags, + &config](txiter it) EXCLUSIVE_LOCKS_REQUIRED(cs, ::cs_main) { + bool should_remove = false; + AssertLockHeld(cs); + AssertLockHeld(::cs_main); + const CTransaction &tx = it->GetTx(); + LockPoints lp = it->GetLockPoints(); + const bool validLP{ + TestLockPointValidity(active_chainstate.m_chain, &lp)}; + CCoinsViewMemPool view_mempool(&active_chainstate.CoinsTip(), + *this); + + TxValidationState state; + if (!ContextualCheckTransactionForCurrentBlock( + active_chainstate.m_chain.Tip(), + config.GetChainParams().GetConsensus(), tx, state, flags) || + !CheckSequenceLocks(active_chainstate.m_chain.Tip(), + view_mempool, tx, flags, &lp, validLP)) { + // Note if CheckSequenceLocks fails the LockPoints may still be + // invalid. So it's critical that we remove the tx and not + // depend on the LockPoints. + should_remove = true; + } else if (it->GetSpendsCoinbase()) { + for (const CTxIn &txin : tx.vin) { + indexed_transaction_set::const_iterator it2 = + mapTx.find(txin.prevout.GetTxId()); + if (it2 != mapTx.end()) { + continue; + } + + const Coin &coin = + active_chainstate.CoinsTip().AccessCoin(txin.prevout); + if (m_check_ratio != 0) { + assert(!coin.IsSpent()); + } + const auto mempool_spend_height{ + active_chainstate.m_chain.Tip()->nHeight + 1}; + if (coin.IsSpent() || + (coin.IsCoinBase() && + mempool_spend_height - coin.GetHeight() < + COINBASE_MATURITY)) { + should_remove = true; + break; + } + } + } + // CheckSequenceLocks updates lp. Update the mempool entry + // LockPoints. + if (!validLP) { + mapTx.modify(it, update_lock_points(lp)); + } + return should_remove; + }; + setEntries txToRemove; for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) { - const CTransaction &tx = it->GetTx(); - LockPoints lp = it->GetLockPoints(); - const bool validLP{ - TestLockPointValidity(active_chainstate.m_chain, &lp)}; - CCoinsViewMemPool view_mempool(&active_chainstate.CoinsTip(), *this); - - TxValidationState state; - if (!ContextualCheckTransactionForCurrentBlock( - active_chainstate.m_chain.Tip(), - config.GetChainParams().GetConsensus(), tx, state, flags) || - !CheckSequenceLocks(active_chainstate.m_chain.Tip(), view_mempool, - tx, flags, &lp, validLP)) { - // Note if CheckSequenceLocks fails the LockPoints may still be - // invalid. So it's critical that we remove the tx and not depend on - // the LockPoints. + if (check_final_and_mature(it)) { txToRemove.insert(it); - } else if (it->GetSpendsCoinbase()) { - for (const CTxIn &txin : tx.vin) { - indexed_transaction_set::const_iterator it2 = - mapTx.find(txin.prevout.GetTxId()); - if (it2 != mapTx.end()) { - continue; - } - - const Coin &coin = - active_chainstate.CoinsTip().AccessCoin(txin.prevout); - if (m_check_ratio != 0) { - assert(!coin.IsSpent()); - } - const auto mempool_spend_height{ - active_chainstate.m_chain.Tip()->nHeight + 1}; - if (coin.IsSpent() || (coin.IsCoinBase() && - mempool_spend_height - coin.GetHeight() < - COINBASE_MATURITY)) { - txToRemove.insert(it); - break; - } - } - } - // CheckSequenceLocks updates lp. Update the mempool entry LockPoints. - if (!validLP) { - mapTx.modify(it, update_lock_points(lp)); } } setEntries setAllRemoves;