@@ -349,21 +349,37 @@ void CChainState::MaybeUpdateMempoolForReorg(
349
349
// the disconnectpool that were added back and cleans up the mempool state.
350
350
m_mempool->UpdateTransactionsFromBlock (vHashUpdate);
351
351
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)
353
358
EXCLUSIVE_LOCKS_REQUIRED (m_mempool->cs , ::cs_main) {
354
- bool should_remove = false ;
355
359
AssertLockHeld (m_mempool->cs );
356
360
AssertLockHeld (::cs_main);
357
361
const CTransaction& tx = it->GetTx ();
362
+
363
+ // The transaction must be final.
364
+ if (!CheckFinalTx (m_chain.Tip (), tx, flags)) return true ;
358
365
LockPoints lp = it->GetLockPoints ();
359
366
const bool validLP{TestLockPointValidity (m_chain, lp)};
360
367
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 ()) {
367
383
for (const CTxIn& txin : tx.vin ) {
368
384
auto it2 = m_mempool->mapTx .find (txin.prevout .hash );
369
385
if (it2 != m_mempool->mapTx .end ())
@@ -372,18 +388,16 @@ void CChainState::MaybeUpdateMempoolForReorg(
372
388
assert (!coin.IsSpent ());
373
389
const auto mempool_spend_height{m_chain.Tip ()->nHeight + 1 };
374
390
if (coin.IsSpent () || (coin.IsCoinBase () && mempool_spend_height - coin.nHeight < COINBASE_MATURITY)) {
375
- should_remove = true ;
376
- break ;
391
+ return true ;
377
392
}
378
393
}
379
394
}
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 ;
383
397
};
384
398
385
399
// 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 );
387
401
// Re-limit mempool size, in case we added any transactions
388
402
LimitMempoolSize (
389
403
*m_mempool,
0 commit comments