Skip to content

Commit 06b6369

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#23976: document and clean up MaybeUpdateMempoolForReorg
e177fca Replace `struct update_lock_points` with lambda (glozow) c7cd98c document and clean up MaybeUpdateMempoolForReorg (glozow) Pull request description: followup to #23683, addressing bitcoin/bitcoin#23683 (comment) ACKs for top commit: hebasto: ACK e177fca, I have reviewed the code and it looks OK, I agree it can be merged. instagibbs: ACK e177fca MarcoFalke: Approach ACK e177fca 😶 Tree-SHA512: 8c2709dd5cab73cde41f3e5655d5f237bacfb341f78eac026169be579528695ca628c8777b7d89760d8677a4e6786913293681cfe16ab702b30c909703e1824c
2 parents 2d7ffce + e177fca commit 06b6369

File tree

2 files changed

+36
-28
lines changed

2 files changed

+36
-28
lines changed

src/txmempool.h

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -312,16 +312,6 @@ class CompareTxMemPoolEntryByAncestorFee
312312
}
313313
};
314314

315-
struct update_lock_points
316-
{
317-
explicit update_lock_points(const LockPoints& _lp) : lp(_lp) { }
318-
319-
void operator() (CTxMemPoolEntry &e) { e.UpdateLockPoints(lp); }
320-
321-
private:
322-
const LockPoints& lp;
323-
};
324-
325315
// Multi_index tag names
326316
struct descendant_score {};
327317
struct entry_time {};
@@ -599,10 +589,14 @@ class CTxMemPool
599589
void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
600590

601591
void removeRecursive(const CTransaction& tx, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs);
602-
/** After reorg, check if mempool entries are now non-final, premature coinbase spends, or have
603-
* invalid lockpoints. Update lockpoints and remove entries (and descendants of entries) that
604-
* are no longer valid. */
605-
void removeForReorg(CChain& chain, std::function<bool(txiter)> check_final_and_mature) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
592+
/** After reorg, filter the entries that would no longer be valid in the next block, and update
593+
* the entries' cached LockPoints if needed. The mempool does not have any knowledge of
594+
* consensus rules. It just appplies the callable function and removes the ones for which it
595+
* returns true.
596+
* @param[in] filter_final_and_mature Predicate that checks the relevant validation rules
597+
* and updates an entry's LockPoints.
598+
* */
599+
void removeForReorg(CChain& chain, std::function<bool(txiter)> filter_final_and_mature) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
606600
void removeConflicts(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(cs);
607601
void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight) EXCLUSIVE_LOCKS_REQUIRED(cs);
608602

src/validation.cpp

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)