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.
0diff --git a/src/validation.cpp b/src/validation.cpp
1index 0986147b7..1657323bd 100644
2--- a/src/validation.cpp
3+++ b/src/validation.cpp
4@@ -323,60 +323,60 @@ void Chainstate::MaybeUpdateMempoolForReorg(
5 // the disconnectpool that were added back and cleans up the mempool state.
6 m_mempool->UpdateTransactionsFromBlock(vHashUpdate);
7
8- // Predicate to use for filtering transactions in removeForReorg.
9- // Checks whether the transaction is still final and, if it spends a coinbase output, mature.
10- // Also updates valid entries' cached LockPoints if needed.
11- // If false, the tx is still valid and its lockpoints are updated.
12- // If true, the tx would be invalid in the next block; remove this entry and all of its descendants.
13- const auto filter_final_and_mature = [this](CTxMemPool::txiter it)
14- EXCLUSIVE_LOCKS_REQUIRED(m_mempool->cs, ::cs_main) {
15- AssertLockHeld(m_mempool->cs);
16- AssertLockHeld(::cs_main);
17- const CTransaction& tx = it->GetTx();
18+ // We also need to remove any now-immature transactions
19+ m_mempool->removeForReorg(m_chain, [this](CTxMemPool::txiter it){ return !this->IsTxFinalAndMature(it); });
20+ // Re-limit mempool size, in case we added any transactions
21+ LimitMempoolSize(*m_mempool, this->CoinsTip());
22+}
23
24- // The transaction must be final.
25- if (!CheckFinalTxAtTip(*Assert(m_chain.Tip()), tx)) return true;
26+// Predicate to use for filtering transactions in removeForReorg.
27+// Checks whether the transaction is still final and, if it spends a coinbase output, mature.
28+// Also updates valid entries' cached LockPoints if needed.
29+// If true, the tx is still valid and its lockpoints are updated.
30+// If false, the tx would be invalid in the next block; remove this entry and all of its descendants.
31+bool Chainstate::IsTxFinalAndMature(CTxMemPool::txiter it) EXCLUSIVE_LOCKS_REQUIRED(m_mempool->cs, ::cs_main)
32+{
33+ AssertLockHeld(m_mempool->cs);
34+ AssertLockHeld(::cs_main);
35+ const CTransaction& tx = it->GetTx();
36
37- const LockPoints& lp = it->GetLockPoints();
38- // CheckSequenceLocksAtTip checks if the transaction will be final in the next block to be
39- // created on top of the new chain.
40- if (TestLockPointValidity(m_chain, lp)) {
41- if (!CheckSequenceLocksAtTip(m_chain.Tip(), lp)) {
42- return true;
43- }
44+ // The transaction must be final.
45+ if (!CheckFinalTxAtTip(*Assert(m_chain.Tip()), tx)) return true;
46+
47+ const LockPoints& lp = it->GetLockPoints();
48+ // CheckSequenceLocksAtTip checks if the transaction will be final in the next block to be
49+ // created on top of the new chain.
50+ if (TestLockPointValidity(m_chain, lp)) {
51+ if (!CheckSequenceLocksAtTip(m_chain.Tip(), lp)) {
52+ return false;
53+ }
54+ } else {
55+ const CCoinsViewMemPool view_mempool{&CoinsTip(), *m_mempool};
56+ const std::optional<LockPoints> new_lock_points{CalculateLockPointsAtTip(m_chain.Tip(), view_mempool, tx)};
57+ if (new_lock_points.has_value() && CheckSequenceLocksAtTip(m_chain.Tip(), *new_lock_points)) {
58+ // Now update the mempool entry lockpoints as well.
59+ m_mempool->mapTx.modify(it, [&new_lock_points](CTxMemPoolEntry& e) { e.UpdateLockPoints(*new_lock_points); });
60 } else {
61- const CCoinsViewMemPool view_mempool{&CoinsTip(), *m_mempool};
62- const std::optional<LockPoints> new_lock_points{CalculateLockPointsAtTip(m_chain.Tip(), view_mempool, tx)};
63- if (new_lock_points.has_value() && CheckSequenceLocksAtTip(m_chain.Tip(), *new_lock_points)) {
64- // Now update the mempool entry lockpoints as well.
65- m_mempool->mapTx.modify(it, [&new_lock_points](CTxMemPoolEntry& e) { e.UpdateLockPoints(*new_lock_points); });
66- } else {
67- return true;
68- }
69+ return false;
70 }
71+ }
72
73- // If the transaction spends any coinbase outputs, it must be mature.
74- if (it->GetSpendsCoinbase()) {
75- for (const CTxIn& txin : tx.vin) {
76- auto it2 = m_mempool->mapTx.find(txin.prevout.hash);
77- if (it2 != m_mempool->mapTx.end())
78- continue;
79- const Coin& coin{CoinsTip().AccessCoin(txin.prevout)};
80- assert(!coin.IsSpent());
81- const auto mempool_spend_height{m_chain.Tip()->nHeight + 1};
82- if (coin.IsCoinBase() && mempool_spend_height - coin.nHeight < COINBASE_MATURITY) {
83- return true;
84- }
85+ // If the transaction spends any coinbase outputs, it must be mature.
86+ if (it->GetSpendsCoinbase()) {
87+ for (const CTxIn& txin : tx.vin) {
88+ auto it2 = m_mempool->mapTx.find(txin.prevout.hash);
89+ if (it2 != m_mempool->mapTx.end())
90+ continue;
91+ const Coin& coin{CoinsTip().AccessCoin(txin.prevout)};
92+ assert(!coin.IsSpent());
93+ const auto mempool_spend_height{m_chain.Tip()->nHeight + 1};
94+ if (coin.IsCoinBase() && mempool_spend_height - coin.nHeight < COINBASE_MATURITY) {
95+ return false;
96 }
97 }
98- // Transaction is still valid and cached LockPoints are updated.
99- return false;
100- };
101-
102- // We also need to remove any now-immature transactions
103- m_mempool->removeForReorg(m_chain, filter_final_and_mature);
104- // Re-limit mempool size, in case we added any transactions
105- LimitMempoolSize(*m_mempool, this->CoinsTip());
106+ }
107+ // Transaction is still valid and cached LockPoints are updated.
108+ return true;
109 }
110
111 /**
112diff --git a/src/validation.h b/src/validation.h
113index bd6f710d1..52f1ee66f 100644
114--- a/src/validation.h
115+++ b/src/validation.h
116@@ -291,6 +291,7 @@ std::optional<LockPoints> CalculateLockPointsAtTip(CBlockIndex* tip,
117 * passed in for evaluation.
118 * The LockPoints should not be considered valid if CheckSequenceLocksAtTip returns false.
119 */
120+
121 bool CheckSequenceLocksAtTip(CBlockIndex* tip,
122 const LockPoints& lp);
123
124@@ -770,6 +771,8 @@ private:
125 DisconnectedBlockTransactions& disconnectpool,
126 bool fAddToMempool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool->cs);
127
128+ bool IsTxFinalAndMature(CTxMemPool::txiter it) EXCLUSIVE_LOCKS_REQUIRED(m_mempool->cs, ::cs_main);
129+
130 /** Check warning conditions and do some notifications on new chain tip set. */
131 void UpdateTip(const CBlockIndex* pindexNew)
132 EXCLUSIVE_LOCKS_REQUIRED(::cs_main);