IntersectMBO / IntersectMBO/ouroboros-consensus

Leios: a zero EB reference limit lets the EB grow without bound

Open
#2,291 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Haskell
Stars
67
Forks
43
Avg merge
5d 13h
Merged PRs (30d)
43

Description

A ranking block sets [`referencesSize = maxBound`](https://github.com/IntersectMBO/ouroboros-consensus/blob/6423a842504c2b4148d76313bb8708b633ef7907/ouroboros-consensus-cardano/src/shelley/Ouroboros/Consensus/Shelley/Ledger/Mempool.hs#L740-L742) to mean "this axis does not limit a ranking block". To read the real limit back, the code depends on `Word32` overflow.

Write `L` for the [endorser block limit on that axis](https://github.com/IntersectMBO/ouroboros-consensus/blob/6423a842504c2b4148d76313bb8708b633ef7907/ouroboros-consensus-cardano/src/shelley/Ouroboros/Consensus/Shelley/Ledger/Mempool.hs#L801-L807). The forge takes transactions twice:

- [Without a certificate](https://github.com/IntersectMBO/ouroboros-consensus/blob/6423a842504c2b4148d76313bb8708b633ef7907/ouroboros-consensus-diffusion/src/ouroboros-consensus-diffusion/Ouroboros/Consensus/NodeKernel/Forge.hs#L751-L754): the limit is `plus rbCap ebCap`. [`plus` is `(+) @Word32`](https://github.com/IntersectMBO/ouroboros-consensus/blob/6423a842504c2b4148d76313bb8708b633ef7907/ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Ledger/SupportsMempool.hs#L443-L445), so the axis becomes `maxBound + L`, which overflows to `L - 1`.
- [With a certificate](https://github.com/IntersectMBO/ouroboros-consensus/blob/6423a842504c2b4148d76313bb8708b633ef7907/ouroboros-consensus-diffusion/src/ouroboros-consensus-diffusion/Ouroboros/Consensus/NodeKernel/Forge.hs#L797): the limit is `ebCap` alone, so the axis is `L`.

Two results follow.

The two paths differ by one byte. One gets `L - 1` and the other gets `L`.

`L = 0` reverses the meaning, because `maxBound + 0` does not overflow. Every transaction costs at [least 35 bytes on that axis](https://github.com/IntersectMBO/ouroboros-consensus/blob/6423a842504c2b4148d76313bb8708b633ef7907/ouroboros-consensus-cardano/src/shelley/Ouroboros/Consensus/Shelley/Ledger/Mempool.hs#L773-L776), so:

- `L = 1` gives the take a bound of 0. The first transaction costs 35, so nothing fits.
- `L = 0` gives the take a bound of `maxBound`, which is 4294967295. Filling it needs about 123 million transactions, so the axis never binds and the closure axis limits the endorser block instead.

The smaller limit gives the larger endorser block.

`L = 0` is reachable. #2280 sets `L` to `referencesLimit - min referencesLimit 5`, which is 0 for every `maxEndorserBlockReferencesSize` from 0 to 5.

The fix is to represent "no limit" directly, instead of as a value that must overflow. Then `L = 0` means "nothing fits", and both forge paths read the same limit.

Contributor guide

Open the contributing guide

Research direction

Start in ouroboros-consensus-cardano/src/shelley/Ouroboros/Consensus/Shelley/Ledger/Mempool.hs, then trace the capacity handling in Ouroboros/Consensus/NodeKernel/Forge.hs and SupportsMempool.hs. Replace the overflow-based no-limit representation so an endorser reference limit of zero makes nothing fit, and verify that both forge paths use the same effective limit.

Written by the indexing model from the issue text.

Assessment

Tech stack
haskell
Domain
blockchain, distributed-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.