Skip to content

Commit c273112

Browse files
committed
chore(fast-inbox): emit inbox lag and checkpoint cap from the constants generator (A-1434)
Add INBOX_LAG_SECONDS and MAX_L1_TO_L2_MSGS_PER_CHECKPOINT to the Solidity constants allowlist so the generator emits them into ConstantsGen.sol, matching the values already present in constants.gen.ts. ProposeLib and its consumption test now read the generated Constants library instead of the hand-declared file-scope copies, giving L1 and TS a single source of truth.
1 parent 2d04b54 commit c273112

3 files changed

Lines changed: 17 additions & 23 deletions

File tree

l1-contracts/scripts/constants-codegen/solidity.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
[
22
"MAX_FIELD_VALUE",
33
"L1_TO_L2_MSG_SUBTREE_HEIGHT",
4+
"MAX_L1_TO_L2_MSGS_PER_CHECKPOINT",
5+
"INBOX_LAG_SECONDS",
46
"MAX_L2_TO_L1_MSGS_PER_TX",
57
"INITIAL_CHECKPOINT_NUMBER",
68
"MAX_CHECKPOINTS_PER_EPOCH",

l1-contracts/src/core/libraries/rollup/ProposeLib.sol

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
pragma solidity >=0.8.27;
44

55
import {BlobLib} from "@aztec-blob-lib/BlobLib.sol";
6+
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";
67
import {IEscapeHatch} from "@aztec/core/interfaces/IEscapeHatch.sol";
78
import {RollupStore, IRollupCore, CheckpointHeaderValidationFlags} from "@aztec/core/interfaces/IRollup.sol";
89
import {IInbox, MAX_MSGS_PER_BUCKET} from "@aztec/core/interfaces/messagebridge/IInbox.sol";
@@ -22,14 +23,6 @@ import {SafeCast} from "@oz/utils/math/SafeCast.sol";
2223
import {ProposedHeader, ProposedHeaderLib} from "./ProposedHeaderLib.sol";
2324
import {STFLib} from "./STFLib.sol";
2425

25-
// Streaming-inbox protocol constants (AZIP-22 Fast Inbox). These mirror the protocol circuit constants and
26-
// should move into the generated Constants library once the Solidity emitter includes them.
27-
// Minimum bucket age, in seconds, at the start of a checkpoint's build frame for its consumption to be
28-
// mandatory. One L1 slot: validators cannot be required to act on buckets they may not have seen.
29-
uint256 constant INBOX_LAG_SECONDS = 12;
30-
// Maximum number of L1 to L2 messages a single checkpoint can insert.
31-
uint256 constant MAX_L1_TO_L2_MSGS_PER_CHECKPOINT = 1024;
32-
3326
struct ProposeArgs {
3427
bytes32 archive;
3528
OracleInput oracleInput;
@@ -465,17 +458,17 @@ library ProposeLib {
465458
);
466459

467460
require(
468-
bucket.totalMsgCount - _parentTotalMsgCount <= MAX_L1_TO_L2_MSGS_PER_CHECKPOINT,
461+
bucket.totalMsgCount - _parentTotalMsgCount <= Constants.MAX_L1_TO_L2_MSGS_PER_CHECKPOINT,
469462
Errors.Rollup__TooManyInboxMessagesConsumed(bucket.totalMsgCount - _parentTotalMsgCount)
470463
);
471464

472465
if (_bucketHint < _inbox.getCurrentBucketSeq()) {
473466
IInbox.InboxBucket memory next = _inbox.getBucket(_bucketHint + 1);
474467
Timestamp buildFrameStart = TimeLib.toTimestamp(_slotNumber - Slot.wrap(1));
475-
Timestamp cutoff = buildFrameStart - Timestamp.wrap(INBOX_LAG_SECONDS);
468+
Timestamp cutoff = buildFrameStart - Timestamp.wrap(Constants.INBOX_LAG_SECONDS);
476469
require(
477470
next.timestamp > Timestamp.unwrap(cutoff)
478-
|| next.totalMsgCount - _parentTotalMsgCount > MAX_L1_TO_L2_MSGS_PER_CHECKPOINT,
471+
|| next.totalMsgCount - _parentTotalMsgCount > Constants.MAX_L1_TO_L2_MSGS_PER_CHECKPOINT,
479472
Errors.Rollup__UnconsumedInboxMessages(_bucketHint + 1)
480473
);
481474
}

l1-contracts/test/rollup/ProposeInboxConsumption.t.sol

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,8 @@ import {Test} from "forge-std/Test.sol";
66
import {TestERC20} from "src/mock/TestERC20.sol";
77
import {IERC20} from "@oz/token/ERC20/IERC20.sol";
88
import {IInbox, MAX_MSGS_PER_BUCKET} from "@aztec/core/interfaces/messagebridge/IInbox.sol";
9-
import {
10-
ProposeLib,
11-
INBOX_LAG_SECONDS,
12-
MAX_L1_TO_L2_MSGS_PER_CHECKPOINT
13-
} from "@aztec/core/libraries/rollup/ProposeLib.sol";
9+
import {ProposeLib} from "@aztec/core/libraries/rollup/ProposeLib.sol";
10+
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";
1411
import {TimeLib, Slot, Timestamp} from "@aztec/core/libraries/TimeLib.sol";
1512
import {Errors} from "@aztec/core/libraries/Errors.sol";
1613
import {DataStructures} from "@aztec/core/libraries/DataStructures.sol";
@@ -50,7 +47,7 @@ contract ProposeInboxConsumptionTest is Test {
5047
// Start of the build frame for a checkpoint proposed in SLOT: it is built during the previous slot.
5148
uint256 internal buildFrameStart = GENESIS_TIME + (Slot.unwrap(SLOT) - 1) * SLOT_DURATION;
5249
// Buckets at or before the cutoff must be consumed by the checkpoint.
53-
uint256 internal cutoff = buildFrameStart - INBOX_LAG_SECONDS;
50+
uint256 internal cutoff = buildFrameStart - Constants.INBOX_LAG_SECONDS;
5451

5552
function setUp() public {
5653
vm.warp(GENESIS_TIME);
@@ -125,7 +122,7 @@ contract ProposeInboxConsumptionTest is Test {
125122
// One more message than the checkpoint cap, all before the cutoff. They spill over into buckets
126123
// 1..4 of 256 (the per-bucket cap) plus bucket 5 with the single excess message.
127124
vm.warp(cutoff - 100);
128-
_sendMany(MAX_L1_TO_L2_MSGS_PER_CHECKPOINT + 1);
125+
_sendMany(Constants.MAX_L1_TO_L2_MSGS_PER_CHECKPOINT + 1);
129126
assertEq(inbox.getCurrentBucketSeq(), 5, "expected five buckets");
130127

131128
vm.warp(GENESIS_TIME + Slot.unwrap(SLOT) * SLOT_DURATION);
@@ -134,12 +131,12 @@ contract ProposeInboxConsumptionTest is Test {
134131
// even though it is old.
135132
bytes32 endHash = inbox.getBucket(4).rollingHash;
136133
uint256 consumed = rollup.validateInboxConsumption(inbox, endHash, 4, SLOT, 0);
137-
assertEq(consumed, MAX_L1_TO_L2_MSGS_PER_CHECKPOINT, "consumed the full cap");
134+
assertEq(consumed, Constants.MAX_L1_TO_L2_MSGS_PER_CHECKPOINT, "consumed the full cap");
138135
}
139136

140137
function testNoCapEscapeAtExactCap() public {
141138
vm.warp(cutoff - 100);
142-
_sendMany(MAX_L1_TO_L2_MSGS_PER_CHECKPOINT + 1);
139+
_sendMany(Constants.MAX_L1_TO_L2_MSGS_PER_CHECKPOINT + 1);
143140

144141
vm.warp(GENESIS_TIME + Slot.unwrap(SLOT) * SLOT_DURATION);
145142

@@ -154,7 +151,7 @@ contract ProposeInboxConsumptionTest is Test {
154151
// Same layout as testCapEscape, but the parent checkpoint had already consumed one message:
155152
// buckets 2..5 then hold cap messages total, which fit in one checkpoint, so no escape from bucket 1.
156153
vm.warp(cutoff - 100);
157-
_sendMany(MAX_L1_TO_L2_MSGS_PER_CHECKPOINT + 1);
154+
_sendMany(Constants.MAX_L1_TO_L2_MSGS_PER_CHECKPOINT + 1);
158155

159156
vm.warp(GENESIS_TIME + Slot.unwrap(SLOT) * SLOT_DURATION);
160157

@@ -288,14 +285,16 @@ contract ProposeInboxConsumptionTest is Test {
288285
// One more message than the checkpoint cap, all before the cutoff, referenced in a single proposal from
289286
// a fresh parent: the consumed delta exceeds what the circuits can insert.
290287
vm.warp(cutoff - 100);
291-
_sendMany(MAX_L1_TO_L2_MSGS_PER_CHECKPOINT + 1);
288+
_sendMany(Constants.MAX_L1_TO_L2_MSGS_PER_CHECKPOINT + 1);
292289
assertEq(inbox.getCurrentBucketSeq(), 5, "expected five buckets");
293290

294291
bytes32 endHash = inbox.getBucket(5).rollingHash;
295292

296293
vm.warp(GENESIS_TIME + Slot.unwrap(SLOT) * SLOT_DURATION);
297294
vm.expectRevert(
298-
abi.encodeWithSelector(Errors.Rollup__TooManyInboxMessagesConsumed.selector, MAX_L1_TO_L2_MSGS_PER_CHECKPOINT + 1)
295+
abi.encodeWithSelector(
296+
Errors.Rollup__TooManyInboxMessagesConsumed.selector, Constants.MAX_L1_TO_L2_MSGS_PER_CHECKPOINT + 1
297+
)
299298
);
300299
rollup.validateInboxConsumption(inbox, endHash, 5, SLOT, 0);
301300
}

0 commit comments

Comments
 (0)