While refactoring this function, would it be appropriate to eliminate this behemoth filter_final_and_mature lambda and turn it into a member function? It's a very straightforward carve-out and I think that massively helps with readability. Example very quick diff below (some lock warnings but compiles otherwise). In addition to carve-out, it also flips the true/false behaviour for an (imo) more intuitive behaviour and naming and thus readability.
<details>
<summary>git diff</summary>
diff --git a/src/validation.cpp b/src/validation.cpp
index 0986147b7..1657323bd 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -323,60 +323,60 @@ void Chainstate::MaybeUpdateMempoolForReorg(
// the disconnectpool that were added back and cleans up the mempool state.
m_mempool->UpdateTransactionsFromBlock(vHashUpdate);
- // Predicate to use for filtering transactions in removeForReorg.
- // Checks whether the transaction is still final and, if it spends a coinbase output, mature.
- // Also updates valid entries' cached LockPoints if needed.
- // If false, the tx is still valid and its lockpoints are updated.
- // If true, the tx would be invalid in the next block; remove this entry and all of its descendants.
- const auto filter_final_and_mature = [this](CTxMemPool::txiter it)
- EXCLUSIVE_LOCKS_REQUIRED(m_mempool->cs, ::cs_main) {
- AssertLockHeld(m_mempool->cs);
- AssertLockHeld(::cs_main);
- const CTransaction& tx = it->GetTx();
+ // We also need to remove any now-immature transactions
+ m_mempool->removeForReorg(m_chain, [this](CTxMemPool::txiter it){ return !this->IsTxFinalAndMature(it); });
+ // Re-limit mempool size, in case we added any transactions
+ LimitMempoolSize(*m_mempool, this->CoinsTip());
+}
- // The transaction must be final.
- if (!CheckFinalTxAtTip(*Assert(m_chain.Tip()), tx)) return true;
+// Predicate to use for filtering transactions in removeForReorg.
+// Checks whether the transaction is still final and, if it spends a coinbase output, mature.
+// Also updates valid entries' cached LockPoints if needed.
+// If true, the tx is still valid and its lockpoints are updated.
+// If false, the tx would be invalid in the next block; remove this entry and all of its descendants.
+bool Chainstate::IsTxFinalAndMature(CTxMemPool::txiter it) EXCLUSIVE_LOCKS_REQUIRED(m_mempool->cs, ::cs_main)
+{
+ AssertLockHeld(m_mempool->cs);
+ AssertLockHeld(::cs_main);
+ const CTransaction& tx = it->GetTx();
- const LockPoints& lp = it->GetLockPoints();
- // CheckSequenceLocksAtTip checks if the transaction will be final in the next block to be
- // created on top of the new chain.
- if (TestLockPointValidity(m_chain, lp)) {
- if (!CheckSequenceLocksAtTip(m_chain.Tip(), lp)) {
- return true;
- }
+ // The transaction must be final.
+ if (!CheckFinalTxAtTip(*Assert(m_chain.Tip()), tx)) return true;
+
+ const LockPoints& lp = it->GetLockPoints();
+ // CheckSequenceLocksAtTip checks if the transaction will be final in the next block to be
+ // created on top of the new chain.
+ if (TestLockPointValidity(m_chain, lp)) {
+ if (!CheckSequenceLocksAtTip(m_chain.Tip(), lp)) {
+ return false;
+ }
+ } else {
+ const CCoinsViewMemPool view_mempool{&CoinsTip(), *m_mempool};
+ const std::optional<LockPoints> new_lock_points{CalculateLockPointsAtTip(m_chain.Tip(), view_mempool, tx)};
+ if (new_lock_points.has_value() && CheckSequenceLocksAtTip(m_chain.Tip(), *new_lock_points)) {
+ // Now update the mempool entry lockpoints as well.
+ m_mempool->mapTx.modify(it, [&new_lock_points](CTxMemPoolEntry& e) { e.UpdateLockPoints(*new_lock_points); });
} else {
- const CCoinsViewMemPool view_mempool{&CoinsTip(), *m_mempool};
- const std::optional<LockPoints> new_lock_points{CalculateLockPointsAtTip(m_chain.Tip(), view_mempool, tx)};
- if (new_lock_points.has_value() && CheckSequenceLocksAtTip(m_chain.Tip(), *new_lock_points)) {
- // Now update the mempool entry lockpoints as well.
- m_mempool->mapTx.modify(it, [&new_lock_points](CTxMemPoolEntry& e) { e.UpdateLockPoints(*new_lock_points); });
- } else {
- return true;
- }
+ return false;
}
+ }
- // If the transaction spends any coinbase outputs, it must be mature.
- if (it->GetSpendsCoinbase()) {
- for (const CTxIn& txin : tx.vin) {
- auto it2 = m_mempool->mapTx.find(txin.prevout.hash);
- if (it2 != m_mempool->mapTx.end())
- continue;
- const Coin& coin{CoinsTip().AccessCoin(txin.prevout)};
- assert(!coin.IsSpent());
- const auto mempool_spend_height{m_chain.Tip()->nHeight + 1};
- if (coin.IsCoinBase() && mempool_spend_height - coin.nHeight < COINBASE_MATURITY) {
- return true;
- }
+ // If the transaction spends any coinbase outputs, it must be mature.
+ if (it->GetSpendsCoinbase()) {
+ for (const CTxIn& txin : tx.vin) {
+ auto it2 = m_mempool->mapTx.find(txin.prevout.hash);
+ if (it2 != m_mempool->mapTx.end())
+ continue;
+ const Coin& coin{CoinsTip().AccessCoin(txin.prevout)};
+ assert(!coin.IsSpent());
+ const auto mempool_spend_height{m_chain.Tip()->nHeight + 1};
+ if (coin.IsCoinBase() && mempool_spend_height - coin.nHeight < COINBASE_MATURITY) {
+ return false;
}
}
- // Transaction is still valid and cached LockPoints are updated.
- return false;
- };
-
- // We also need to remove any now-immature transactions
- m_mempool->removeForReorg(m_chain, filter_final_and_mature);
- // Re-limit mempool size, in case we added any transactions
- LimitMempoolSize(*m_mempool, this->CoinsTip());
+ }
+ // Transaction is still valid and cached LockPoints are updated.
+ return true;
}
/**
diff --git a/src/validation.h b/src/validation.h
index bd6f710d1..52f1ee66f 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -291,6 +291,7 @@ std::optional<LockPoints> CalculateLockPointsAtTip(CBlockIndex* tip,
* passed in for evaluation.
* The LockPoints should not be considered valid if CheckSequenceLocksAtTip returns false.
*/
+
bool CheckSequenceLocksAtTip(CBlockIndex* tip,
const LockPoints& lp);
@@ -770,6 +771,8 @@ private:
DisconnectedBlockTransactions& disconnectpool,
bool fAddToMempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool->cs);
+ bool IsTxFinalAndMature(CTxMemPool::txiter it) EXCLUSIVE_LOCKS_REQUIRED(m_mempool->cs, ::cs_main);
+
/** Check warning conditions and do some notifications on new chain tip set. */
void UpdateTip(const CBlockIndex* pindexNew)
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
</details>