Skip to content

Commit f9e61da

Browse files
committed
chore(fast-inbox): emit inbox lag and checkpoint cap from the constants generator (A-1434)
Moves `INBOX_LAG_SECONDS` (12) and `MAX_L1_TO_L2_MSGS_PER_CHECKPOINT` (1024) out of the hand-declared file-scope constants in `ProposeLib.sol` and into the generated `Constants` library, giving L1 Solidity and the TS node a single source of truth (A-1434, Fast Inbox cleanup). Both values already lived in `constants.nr` (the Noir source of truth) and were already emitted to `constants.gen.ts`; the only gap was the Solidity side, which gates emission behind an allowlist. - Add both names to the `SOLIDITY_CONSTANTS` allowlist in `constants/src/scripts/constants.in.ts`, so `yarn remake-constants` emits them into `ConstantsGen.sol`. `constants.gen.ts` is unchanged (already present). - Regenerate `ConstantsGen.sol` (generator output; not hand-edited). - `ProposeLib.sol` imports `Constants` and references the generated values; the hand-declared file-scope copies are deleted. - Update `ProposeInboxConsumption.t.sol` to import the constants from `ConstantsGen.sol` instead of `ProposeLib.sol`. TS node code that validates inbox consumption (`stdlib` cutoff predicate, `validator-client` streaming checks, `sequencer-client` bucket selector) already reads these from `@aztec/constants`, so no TS source change is needed. Testing: - `forge build` and `forge test test/rollup/ProposeInboxConsumption.t.sol` (15 tests) pass. - The three TS regression suites pass: `stdlib` inbox_consumption (10), `validator-client` streaming_inbox_checks (14), `sequencer-client` inbox_bucket_selector (9). - `@aztec/constants`, `@aztec/l1-artifacts`, and `@aztec/ethereum` build. Part of the Fast Inbox stack, on top of #24784..#24793. Replaces #24794.
1 parent 4da410d commit f9e61da

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
@@ -9,6 +9,7 @@ import {IInbox, MAX_MSGS_PER_BUCKET} from "@aztec/core/interfaces/messagebridge/
99
import {TempCheckpointLog} from "@aztec/core/libraries/compressed-data/CheckpointLog.sol";
1010
import {FeeHeader} from "@aztec/core/libraries/compressed-data/fees/FeeStructs.sol";
1111
import {ChainTipsLib, CompressedChainTips} from "@aztec/core/libraries/compressed-data/Tips.sol";
12+
import {Constants} from "@aztec/core/libraries/ConstantsGen.sol";
1213
import {Errors} from "@aztec/core/libraries/Errors.sol";
1314
import {CommitteeAttestations} from "@aztec/core/libraries/rollup/AttestationLib.sol";
1415
import {CoordinationSignatureLib} from "@aztec/core/libraries/rollup/CoordinationSignatureLib.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)