IntersectMBO / IntersectMBO/ouroboros-consensus
Leios: a zero EB reference limit lets the EB grow without bound
- 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
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