@@ -349,21 +349,37 @@ void CChainState::MaybeUpdateMempoolForReorg(
349349 // the disconnectpool that were added back and cleans up the mempool state.
350350 m_mempool->UpdateTransactionsFromBlock (vHashUpdate);
351351
352- const auto check_final_and_mature = [this , flags=STANDARD_LOCKTIME_VERIFY_FLAGS](CTxMemPool::txiter it)
352+ // Predicate to use for filtering transactions in removeForReorg.
353+ // Checks whether the transaction is still final and, if it spends a coinbase output, mature.
354+ // Also updates valid entries' cached LockPoints if needed.
355+ // If false, the tx is still valid and its lockpoints are updated.
356+ // If true, the tx would be invalid in the next block; remove this entry and all of its descendants.
357+ const auto filter_final_and_mature = [this , flags=STANDARD_LOCKTIME_VERIFY_FLAGS](CTxMemPool::txiter it)
353358 EXCLUSIVE_LOCKS_REQUIRED (m_mempool->cs , ::cs_main) {
354- bool should_remove = false ;
355359 AssertLockHeld (m_mempool->cs );
356360 AssertLockHeld (::cs_main);
357361 const CTransaction& tx = it->GetTx ();
362+
363+ // The transaction must be final.
364+ if (!CheckFinalTx (m_chain.Tip (), tx, flags)) return true ;
358365 LockPoints lp = it->GetLockPoints ();
359366 const bool validLP{TestLockPointValidity (m_chain, lp)};
360367 CCoinsViewMemPool view_mempool (&CoinsTip (), *m_mempool);
361- if (!CheckFinalTx (m_chain.Tip (), tx, flags)
362- || !CheckSequenceLocks (m_chain.Tip (), view_mempool, tx, flags, &lp, validLP)) {
363- // Note if CheckSequenceLocks fails the LockPoints may still be invalid
364- // So it's critical that we remove the tx and not depend on the LockPoints.
365- should_remove = true ;
366- } else if (it->GetSpendsCoinbase ()) {
368+ // CheckSequenceLocks checks if the transaction will be final in the next block to be
369+ // created on top of the new chain. We use useExistingLockPoints=false so that, instead of
370+ // using the information in lp (which might now refer to a block that no longer exists in
371+ // the chain), it will update lp to contain LockPoints relevant to the new chain.
372+ if (!CheckSequenceLocks (m_chain.Tip (), view_mempool, tx, flags, &lp, validLP)) {
373+ // If CheckSequenceLocks fails, remove the tx and don't depend on the LockPoints.
374+ return true ;
375+ } else if (!validLP) {
376+ // If CheckSequenceLocks succeeded, it also updated the LockPoints.
377+ // Now update the mempool entry lockpoints as well.
378+ m_mempool->mapTx .modify (it, [&lp](CTxMemPoolEntry& e) { e.UpdateLockPoints (lp); });
379+ }
380+
381+ // If the transaction spends any coinbase outputs, it must be mature.
382+ if (it->GetSpendsCoinbase ()) {
367383 for (const CTxIn& txin : tx.vin ) {
368384 auto it2 = m_mempool->mapTx .find (txin.prevout .hash );
369385 if (it2 != m_mempool->mapTx .end ())
@@ -372,18 +388,16 @@ void CChainState::MaybeUpdateMempoolForReorg(
372388 assert (!coin.IsSpent ());
373389 const auto mempool_spend_height{m_chain.Tip ()->nHeight + 1 };
374390 if (coin.IsSpent () || (coin.IsCoinBase () && mempool_spend_height - coin.nHeight < COINBASE_MATURITY)) {
375- should_remove = true ;
376- break ;
391+ return true ;
377392 }
378393 }
379394 }
380- // CheckSequenceLocks updates lp. Update the mempool entry LockPoints.
381- if (!validLP) m_mempool->mapTx .modify (it, update_lock_points (lp));
382- return should_remove;
395+ // Transaction is still valid and cached LockPoints are updated.
396+ return false ;
383397 };
384398
385399 // We also need to remove any now-immature transactions
386- m_mempool->removeForReorg (m_chain, check_final_and_mature );
400+ m_mempool->removeForReorg (m_chain, filter_final_and_mature );
387401 // Re-limit mempool size, in case we added any transactions
388402 LimitMempoolSize (
389403 *m_mempool,
0 commit comments