One of the circular dependencies in the codebase is validation <-> txmempool. These two modules
are each heavily depended on by other modules, so their interdependency creates a “domino effect”
into the rest of the codebase. To experience this for yourself, compile (with ccache), make a small
edit to protocol.h (where P2P protocol messages are defined), then run make again and watch it
rebuild txmempool and everything mempool-related.
PR#22677 removes this dependency by removing
txmempool’s dependency on validation. It creates a GetFiltered() function that allows
validation and other clients to pass in an arbitrary predicate, iterates through all of its entries,
applies the predicate function to each of them, and returns the set of filtered iterators to mempool
entries. This allows validation to apply consensus rules to all of the mempool entries without
access to the mempool’s internals.
What is a circular dependency? Why should we avoid circular dependencies?
What functionality lives in validation? What functionality lives in txmempool?
Why should/shouldn’t validation depend on txmempool? Why should/shouldn’t txmempool depend on
One of the functions that causes txmempool to rely on validation is the check() function. What
checks does it perform, and how does this PR split the checks into two categories?
Another function that causes txmempool to rely on validation is the removeForReorg() function,
which calls CheckSequenceLocks() and CheckFinalTx(). Why do we need to re-check sequence
locks in a reorg? How is it possible for a coinbase spend to become premature in a reorg?
<_aj_> glozow: "neither depending on the other" -- isn't validation the *action* of accepting a block (which means the txs in the block should no longer be in the mempool since they're no longer valid on top of the new tip) ; the consensus rules themselves are in consensus/ and script/ and the like?
<glozow> OK next question. One of the functions that causes txmempool to rely on validation is the `check()` function. What checks does it perform, and how does this PR split the checks into two categories?
<glozow> so I've (arbitrarily) split the `check()` assertions into 2 categories: contextual checks and internal consistency checks. Contextual is what pg2 already mentioned - we go through and make sure all the transactions' inputs refer to something available in our mempool or UTXO set.
<glozow> Internal consistency checks are things like making sure the ancestor/descendant counts of each entry add up correctly, checking that our total fee accounting and dynamic memory usage are accurate, etc.
<glozow> Moving on to next question: Another function that causes txmempool to rely on validation is the `removeForReorg()` function, which calls `CheckSequenceLocks()` and `CheckFinalTx()`. Why do we need to re-check sequence locks in a reorg?