You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Stacked on #24771 (A-1377). AZIP-22 Fast Inbox, FI-08.
## What
Implements the AZIP's censorship assert as `ProposeLib.validateInboxConsumption` — a new library function that is **not yet called**: today's `inbox.consume()` / `inHash` check in `propose` is untouched, so this is dead code until the flip wires it in.
Given the checkpoint header's `inboxRollingHash`, an unsigned calldata bucket hint, the proposed slot, and the parent checkpoint's cumulative consumed total (which the flip will source from the temp checkpoint log), the function enforces:
1. **End anchoring**: the header's rolling hash must equal the snapshot in `inbox.getBucket(hint)` (`Rollup__InvalidInboxRollingHash`). The hint is a lookup aid only — a wrong hint reverts, it cannot change what gets accepted — and `getBucket` itself rejects hints beyond the current bucket or already overwritten in the ring. A checkpoint consuming nothing references the same bucket as its parent (the genesis bucket for the first checkpoint), so there is no base case.
2. **Mandatory consumption**: the first unconsumed bucket (`hint + 1`) must be absent, **past the cutoff**, or **cap-escaped** (`Rollup__UnconsumedInboxMessages`). The cutoff is the build-frame start minus `INBOX_LAG_SECONDS`: a checkpoint proposed in slot S is built during slot S-1 (proposer pipelining), and validators are not required to act on buckets younger than one L1 slot at build start, so `cutoff = toTimestamp(S-1) - 12`. Cap escape allows stopping when consuming through the next bucket would exceed `MAX_L1_TO_L2_MSGS_PER_CHECKPOINT` (1024) messages since the parent's total. Both comparisons are exact-boundary tested.
The function performs **no Inbox write**. It is a pure `view` that **returns** the consumed cumulative total (`bucket.totalMsgCount`). The flip (FI-14) stores that consumed position as part of the per-checkpoint temp-log record, extended to `{inboxRollingHash, inboxMsgTotal, inboxConsumedBucket}` and written by `propose`; that record is the authoritative consumed position and is prune-consistent, since temp logs rewind with the pending chain. Two new checks guard the returned value: consumption must **move forward** (`Rollup__InboxConsumptionBehindParent`, equal allowed — a proposal cannot consume behind its parent, and the check precedes the delta subtractions so a backwards proposal reverts descriptively rather than underflowing), and the consumed delta cannot exceed `MAX_L1_TO_L2_MSGS_PER_CHECKPOINT` in one checkpoint (`Rollup__TooManyInboxMessagesConsumed`). The Inbox-side proven-consumed cache that ring overwrite protection needs moved to **FI-20**, anchored to the proven tip rather than the pending chain (decided 2026-07-17): a pointer advanced with the pending chain is not prune-safe, since after a prune it would sit ahead of what the replacement chain consumed.
`INBOX_LAG_SECONDS = 12` and `MAX_L1_TO_L2_MSGS_PER_CHECKPOINT = 1024` are defined at file level in `ProposeLib` for now; they mirror the protocol constants and should move into the generated `Constants` library once the Solidity emitter allow-list includes them.
## Testing
New `ProposeInboxConsumption.t.sol` (15 tests) drives the library function through a harness that owns the Inbox and TimeLib storage, covering the roadmap done-when plus boundaries:
- **empty Inbox** (hint 0 / hash 0 passes and returns 0; non-zero hash rejected),
- **exact-cutoff bucket** (timestamp == cutoff must be consumed; cutoff + 1 need not),
- **cap escape** (1025 messages spill into buckets of 256+1: stopping at bucket 4 = exactly 1024 escapes and returns the full cap; stopping at bucket 3 = 1024-through-next does not; parent total shifts the arithmetic and kills the escape),
- **cap upper bound** (consuming more than 1024 in one checkpoint from a fresh parent reverts `Rollup__TooManyInboxMessagesConsumed`),
- **moves forward** (a proposal whose referenced bucket total sits behind the parent reverts `Rollup__InboxConsumptionBehindParent`; an equal reference consumes nothing and returns the unchanged total),
- **stale hash** (previous bucket's hash against the current bucket) and **unknown hash** rejection, plus out-of-window hints (future bucket, ring-overwritten bucket),
- **return value**: the successful paths assert the consumed cumulative total the flip will record (0, 3, cap).
The three former consumed-pointer tests are removed along with the pointer. Full `forge test` at the current rebased tip: 890 passed, 0 failed, 3 skipped (the previously noted `testGetEpochProofPublicInputsVerifiesHeaders` failure inherited from the base has since been fixed).
Replaces #24773.
0 commit comments