-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Test that we never block on adding a tx to an empty mempool #1226
Comments
A refinement of this issue would be to check that adding a tx to a nearly empty mempool can not block. Otherwise, minted blocks might not actually make much use of the block capacity despite high tx load. See #1225 (comment) for a concrete example. #1175 implicitly has this property as the per-tx limits are significantly smaller than the per-block limits. |
I agree both of those policies are desireable. Which plausible mechanisms are we aware of?
|
Another mechanism is using the Line 187 in 6a8def9
|
Closes #1226 In addition to the previously valid/invalid txs (purely based on the UTxO ledger rules), we add an optional per-tx limit to the mock block. As a second step, we generate very large txs that are larger than an entire mempool, in order to test that we do *not* block when adding them (just like the other txs), which is important as explained in #1226. --- One way to validate this PR is to introduce a bug that would cause us to block on such transactions, and observe that the test now indeed catches that. For example, retrying when the per-tx limited is not satisfied (this is basically what happened in #1168 and was fixed by #1225) via ```diff diff --git a/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Mempool/Update.hs b/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Mempool/Update.hs index 372ea15c29..31abe25fbf 100644 --- a/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Mempool/Update.hs +++ b/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Mempool/Update.hs @@ -170,25 +170,8 @@ pureTryAddTx :: -> TryAddTx blk pureTryAddTx cfg wti tx is = case runExcept $ txMeasure cfg (isLedgerState is) tx of - Left err -> - -- The transaction does not have a valid measure (eg its ExUnits is - -- greater than what this ledger state allows for a single transaction). - -- - -- It might seem simpler to remove the failure case from 'txMeasure' and - -- simply fully validate the tx before determining whether it'd fit in - -- the mempool; that way we could reject invalid txs ASAP. However, for a - -- valid tx, we'd pay that validation cost every time the node's - -- selection changed, even if the tx wouldn't fit. So it'd very much be - -- as if the mempool were effectively over capacity! What's worse, each - -- attempt would not be using 'extendVRPrevApplied'. - TryAddTx - Nothing - (MempoolTxRejected tx err) - (TraceMempoolRejectedTx - tx - err - (isMempoolSize is) - ) + Left _err -> + NotEnoughSpaceLeft Right txsz -- Check for overflow -- ``` or here ```diff diff --git a/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Ledger/Block.hs b/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Ledger/Block.hs index 743e11bc61..e01d8cfe5a 100644 --- a/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Ledger/Block.hs +++ b/ouroboros-consensus/src/unstable-mock-block/Ouroboros/Consensus/Mock/Ledger/Block.hs @@ -452,10 +452,7 @@ instance TxLimits (SimpleBlock c ext) where -- But not 'maxbound'!, since the mempool sometimes holds multiple blocks worth. blockCapacityTxMeasure _cfg _st = IgnoringOverflow simpleBlockCapacity - txMeasure cfg _st = - fmap IgnoringOverflow - . checkTxSize (simpleLedgerMockConfig cfg) - . simpleGenTx + txMeasure _cfg _st = pure . IgnoringOverflow . txSize . simpleGenTx simpleBlockCapacity :: ByteSize32 simpleBlockCapacity = ByteSize32 512 ``` will cause many test failures with `FailureDeadlock [Labelled (ThreadId []) (Just "main")]'` via `io-sim`'s nice deadlock detection. --- Stacked on top of #1175 to avoid boring rebase work
Since #49, adding a tx to the mempool is guarded by a lock
ouroboros-consensus/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Mempool/Update.hs
Line 76 in 6a8def9
Therefore, while a tx is waiting to be added to the mempool, no other tx can enter the mempool. In order to avoid a deadlock, it must be guaranteed that adding a tx can not block forever. Such a deadlock is problematic both for the local node (as a restart is necessary), as well as for the entire network, as only empty blocks might otherwise be minted.
This requirement can be deduced from the following two properties:
As the mempool will eventually become empty, no transaction can block forever.
The goal of this issue is to test the second property.
At the moment (6a8def9), this property is true for the block size capacity due to #21: As the capacity of the mempool is positive, the conditional
mempoolsize < mempoolcapacity
is always true when adding a tx to an empty mempool.See #1225 for a recent change restoring this behavior for the ad-hoc reference scripts size limit (added in #1166) after #1168.
As of #1175, this property will be guaranteed by performing the per-tx size checks as part of the check whether to add the tx to the mempool, as the per-tx limit is smaller than the per-block limit, and the mempool capacity encompasses at least one block.
One strategy to test this would be to enrich the
TestBlock
used inTest.Consensus.Mempool
with a per-tx size limit, and then add a simple test which tries to add overly large txs to an empty mempool.The text was updated successfully, but these errors were encountered: