@aztec/stdlib 6.0.0-nightly.20260810 → 6.0.0-nightly.20260821

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) hide show
  1. package/dest/abi/abi.d.ts +4 -3
  2. package/dest/abi/abi.d.ts.map +1 -1
  3. package/dest/abi/abi.js +5 -1
  4. package/dest/abi/contract_artifact.d.ts +7 -2
  5. package/dest/abi/contract_artifact.d.ts.map +1 -1
  6. package/dest/abi/contract_artifact.js +18 -19
  7. package/dest/avm/avm.d.ts +3 -2
  8. package/dest/avm/avm.d.ts.map +1 -1
  9. package/dest/avm/avm.js +9 -3
  10. package/dest/avm/avm_proving_request.d.ts +70 -70
  11. package/dest/block/l2_block.d.ts +1 -2
  12. package/dest/block/l2_block.d.ts.map +1 -1
  13. package/dest/block/l2_block.js +2 -3
  14. package/dest/block/l2_block_source.d.ts +3 -6
  15. package/dest/block/l2_block_source.d.ts.map +1 -1
  16. package/dest/block/l2_block_stream/event_driven_l2_block_stream.d.ts +11 -20
  17. package/dest/block/l2_block_stream/event_driven_l2_block_stream.d.ts.map +1 -1
  18. package/dest/block/l2_block_stream/event_driven_l2_block_stream.js +12 -116
  19. package/dest/checkpoint/checkpoint_data.d.ts +14 -2
  20. package/dest/checkpoint/checkpoint_data.d.ts.map +1 -1
  21. package/dest/checkpoint/checkpoint_data.js +2 -1
  22. package/dest/checkpoint/index.d.ts +2 -1
  23. package/dest/checkpoint/index.d.ts.map +1 -1
  24. package/dest/checkpoint/index.js +1 -0
  25. package/dest/checkpoint/previous_checkpoint_inbox_rolling_hash.d.ts +21 -0
  26. package/dest/checkpoint/previous_checkpoint_inbox_rolling_hash.d.ts.map +1 -0
  27. package/dest/checkpoint/previous_checkpoint_inbox_rolling_hash.js +34 -0
  28. package/dest/checkpoint/simulation_overrides.d.ts +2 -2
  29. package/dest/checkpoint/simulation_overrides.d.ts.map +1 -1
  30. package/dest/checkpoint/simulation_overrides.js +11 -8
  31. package/dest/config/network-consensus-config.d.ts +4 -3
  32. package/dest/config/network-consensus-config.d.ts.map +1 -1
  33. package/dest/config/network-consensus-config.js +9 -4
  34. package/dest/config/node-rpc-config.d.ts +13 -1
  35. package/dest/config/node-rpc-config.d.ts.map +1 -1
  36. package/dest/config/node-rpc-config.js +34 -1
  37. package/dest/deserialization/index.d.ts +17 -17
  38. package/dest/deserialization/index.d.ts.map +1 -1
  39. package/dest/deserialization/index.js +18 -18
  40. package/dest/gas/gas_settings.d.ts +17 -5
  41. package/dest/gas/gas_settings.d.ts.map +1 -1
  42. package/dest/gas/gas_settings.js +4 -4
  43. package/dest/gas/tx_gas_limits.d.ts +3 -4
  44. package/dest/gas/tx_gas_limits.d.ts.map +1 -1
  45. package/dest/gas/tx_gas_limits.js +4 -5
  46. package/dest/interfaces/archiver.d.ts +2 -2
  47. package/dest/interfaces/archiver.d.ts.map +1 -1
  48. package/dest/interfaces/archiver.js +32 -5
  49. package/dest/interfaces/aztec-node-admin.d.ts +2 -1
  50. package/dest/interfaces/aztec-node-admin.d.ts.map +1 -1
  51. package/dest/interfaces/aztec-node.d.ts +22 -4
  52. package/dest/interfaces/aztec-node.d.ts.map +1 -1
  53. package/dest/interfaces/aztec-node.js +11 -9
  54. package/dest/interfaces/block-builder.d.ts +11 -2
  55. package/dest/interfaces/block-builder.d.ts.map +1 -1
  56. package/dest/interfaces/configs.d.ts +7 -1
  57. package/dest/interfaces/configs.d.ts.map +1 -1
  58. package/dest/interfaces/configs.js +2 -1
  59. package/dest/interfaces/p2p.d.ts +18 -1
  60. package/dest/interfaces/p2p.d.ts.map +1 -1
  61. package/dest/interfaces/p2p.js +8 -0
  62. package/dest/interfaces/proving-job.d.ts +17 -42
  63. package/dest/interfaces/proving-job.d.ts.map +1 -1
  64. package/dest/interfaces/proving-job.js +16 -47
  65. package/dest/interfaces/server_circuit_prover.d.ts +8 -15
  66. package/dest/interfaces/server_circuit_prover.d.ts.map +1 -1
  67. package/dest/interfaces/validator.d.ts +7 -7
  68. package/dest/interfaces/validator.d.ts.map +1 -1
  69. package/dest/messaging/append_l1_to_l2_messages.d.ts +5 -5
  70. package/dest/messaging/append_l1_to_l2_messages.d.ts.map +1 -1
  71. package/dest/messaging/append_l1_to_l2_messages.js +4 -8
  72. package/dest/messaging/inbox_bucket.d.ts +77 -0
  73. package/dest/messaging/inbox_bucket.d.ts.map +1 -0
  74. package/dest/messaging/inbox_bucket.js +73 -0
  75. package/dest/messaging/inbox_consumption.d.ts +55 -0
  76. package/dest/messaging/inbox_consumption.d.ts.map +1 -0
  77. package/dest/messaging/inbox_consumption.js +53 -0
  78. package/dest/messaging/inbox_rolling_hash.d.ts +16 -0
  79. package/dest/messaging/inbox_rolling_hash.d.ts.map +1 -0
  80. package/dest/messaging/inbox_rolling_hash.js +23 -0
  81. package/dest/messaging/index.d.ts +6 -3
  82. package/dest/messaging/index.d.ts.map +1 -1
  83. package/dest/messaging/index.js +5 -2
  84. package/dest/messaging/l1_to_l2_message_bundle.d.ts +31 -0
  85. package/dest/messaging/l1_to_l2_message_bundle.d.ts.map +1 -0
  86. package/dest/messaging/l1_to_l2_message_bundle.js +51 -0
  87. package/dest/messaging/l1_to_l2_message_source.d.ts +44 -10
  88. package/dest/messaging/l1_to_l2_message_source.d.ts.map +1 -1
  89. package/dest/messaging/l1_to_l2_message_sponge.d.ts +40 -0
  90. package/dest/messaging/l1_to_l2_message_sponge.d.ts.map +1 -0
  91. package/dest/messaging/l1_to_l2_message_sponge.js +56 -0
  92. package/dest/noir/index.d.ts +3 -3
  93. package/dest/noir/index.d.ts.map +1 -1
  94. package/dest/p2p/block_proposal.d.ts +24 -9
  95. package/dest/p2p/block_proposal.d.ts.map +1 -1
  96. package/dest/p2p/block_proposal.js +42 -20
  97. package/dest/p2p/checkpoint_attestation.d.ts +1 -1
  98. package/dest/p2p/checkpoint_proposal.d.ts +13 -3
  99. package/dest/p2p/checkpoint_proposal.d.ts.map +1 -1
  100. package/dest/p2p/checkpoint_proposal.js +26 -8
  101. package/dest/p2p/consensus_payload.d.ts +1 -1
  102. package/dest/p2p/index.d.ts +2 -1
  103. package/dest/p2p/index.d.ts.map +1 -1
  104. package/dest/p2p/index.js +1 -0
  105. package/dest/p2p/validated_proposal.d.ts +35 -0
  106. package/dest/p2p/validated_proposal.d.ts.map +1 -0
  107. package/dest/p2p/validated_proposal.js +17 -0
  108. package/dest/p2p/wire_compat_fixtures.d.ts +7 -0
  109. package/dest/p2p/wire_compat_fixtures.d.ts.map +1 -0
  110. package/dest/p2p/wire_compat_fixtures.js +14 -0
  111. package/dest/parity/inbox_parity_private_inputs.d.ts +61 -0
  112. package/dest/parity/inbox_parity_private_inputs.d.ts.map +1 -0
  113. package/dest/parity/inbox_parity_private_inputs.js +79 -0
  114. package/dest/parity/index.d.ts +2 -3
  115. package/dest/parity/index.d.ts.map +1 -1
  116. package/dest/parity/index.js +1 -2
  117. package/dest/parity/parity_public_inputs.d.ts +15 -14
  118. package/dest/parity/parity_public_inputs.d.ts.map +1 -1
  119. package/dest/parity/parity_public_inputs.js +13 -15
  120. package/dest/proofs/proving_request_type.d.ts +11 -14
  121. package/dest/proofs/proving_request_type.d.ts.map +1 -1
  122. package/dest/proofs/proving_request_type.js +10 -13
  123. package/dest/rollup/block_constant_data.d.ts +8 -8
  124. package/dest/rollup/block_constant_data.js +4 -4
  125. package/dest/rollup/block_rollup_public_inputs.d.ts +18 -6
  126. package/dest/rollup/block_rollup_public_inputs.d.ts.map +1 -1
  127. package/dest/rollup/block_rollup_public_inputs.js +14 -7
  128. package/dest/rollup/block_root_rollup_private_inputs.d.ts +109 -113
  129. package/dest/rollup/block_root_rollup_private_inputs.d.ts.map +1 -1
  130. package/dest/rollup/block_root_rollup_private_inputs.js +79 -130
  131. package/dest/rollup/checkpoint_header.d.ts +14 -6
  132. package/dest/rollup/checkpoint_header.d.ts.map +1 -1
  133. package/dest/rollup/checkpoint_header.js +18 -14
  134. package/dest/rollup/checkpoint_rollup_public_inputs.d.ts +22 -2
  135. package/dest/rollup/checkpoint_rollup_public_inputs.d.ts.map +1 -1
  136. package/dest/rollup/checkpoint_rollup_public_inputs.js +14 -3
  137. package/dest/rollup/checkpoint_root_rollup_private_inputs.d.ts +27 -6
  138. package/dest/rollup/checkpoint_root_rollup_private_inputs.d.ts.map +1 -1
  139. package/dest/rollup/checkpoint_root_rollup_private_inputs.js +17 -4
  140. package/dest/rollup/root_rollup_public_inputs.d.ts +10 -2
  141. package/dest/rollup/root_rollup_public_inputs.d.ts.map +1 -1
  142. package/dest/rollup/root_rollup_public_inputs.js +9 -3
  143. package/dest/stats/stats.d.ts +2 -2
  144. package/dest/stats/stats.d.ts.map +1 -1
  145. package/dest/tests/factories.d.ts +7 -7
  146. package/dest/tests/factories.d.ts.map +1 -1
  147. package/dest/tests/factories.js +26 -22
  148. package/dest/tests/fixtures.d.ts +1 -1
  149. package/dest/tests/fixtures.d.ts.map +1 -1
  150. package/dest/tests/fixtures.js +2 -0
  151. package/dest/tests/mocks.d.ts +4 -2
  152. package/dest/tests/mocks.d.ts.map +1 -1
  153. package/dest/tests/mocks.js +4 -7
  154. package/dest/tx/state_reference.d.ts +5 -2
  155. package/dest/tx/state_reference.d.ts.map +1 -1
  156. package/dest/tx/state_reference.js +5 -5
  157. package/package.json +8 -8
  158. package/src/abi/abi.ts +7 -2
  159. package/src/abi/contract_artifact.ts +20 -23
  160. package/src/avm/avm.ts +11 -1
  161. package/src/block/l2_block.ts +2 -3
  162. package/src/block/l2_block_source.ts +2 -5
  163. package/src/block/l2_block_stream/event_driven_l2_block_stream.ts +17 -143
  164. package/src/checkpoint/checkpoint_data.ts +14 -1
  165. package/src/checkpoint/index.ts +1 -0
  166. package/src/checkpoint/previous_checkpoint_inbox_rolling_hash.ts +46 -0
  167. package/src/checkpoint/simulation_overrides.ts +11 -8
  168. package/src/config/network-consensus-config.ts +17 -4
  169. package/src/config/node-rpc-config.ts +51 -1
  170. package/src/deserialization/index.ts +18 -18
  171. package/src/gas/README.md +4 -3
  172. package/src/gas/gas_settings.ts +7 -3
  173. package/src/gas/tx_gas_limits.ts +4 -12
  174. package/src/interfaces/archiver.ts +19 -2
  175. package/src/interfaces/aztec-node.ts +33 -12
  176. package/src/interfaces/block-builder.ts +10 -1
  177. package/src/interfaces/configs.ts +6 -0
  178. package/src/interfaces/p2p.ts +21 -0
  179. package/src/interfaces/proving-job.ts +19 -70
  180. package/src/interfaces/server_circuit_prover.ts +13 -37
  181. package/src/interfaces/validator.ts +6 -5
  182. package/src/kernel/private_kernel_reset_dimensions.ts +1 -1
  183. package/src/messaging/append_l1_to_l2_messages.ts +5 -13
  184. package/src/messaging/inbox_bucket.ts +125 -0
  185. package/src/messaging/inbox_consumption.ts +74 -0
  186. package/src/messaging/inbox_rolling_hash.ts +24 -0
  187. package/src/messaging/index.ts +5 -2
  188. package/src/messaging/l1_to_l2_message_bundle.ts +65 -0
  189. package/src/messaging/l1_to_l2_message_source.ts +48 -10
  190. package/src/messaging/l1_to_l2_message_sponge.ts +69 -0
  191. package/src/noir/index.ts +1 -2
  192. package/src/p2p/block_proposal.ts +41 -28
  193. package/src/p2p/checkpoint_proposal.ts +31 -6
  194. package/src/p2p/index.ts +1 -0
  195. package/src/p2p/validated_proposal.ts +43 -0
  196. package/src/p2p/wire_compat_fixtures.ts +23 -0
  197. package/src/parity/inbox_parity_private_inputs.ts +116 -0
  198. package/src/parity/index.ts +1 -2
  199. package/src/parity/parity_public_inputs.ts +12 -14
  200. package/src/proofs/proving_request_type.ts +2 -5
  201. package/src/rollup/block_constant_data.ts +4 -4
  202. package/src/rollup/block_rollup_public_inputs.ts +14 -5
  203. package/src/rollup/block_root_rollup_private_inputs.ts +117 -153
  204. package/src/rollup/checkpoint_header.ts +17 -13
  205. package/src/rollup/checkpoint_rollup_public_inputs.ts +15 -0
  206. package/src/rollup/checkpoint_root_rollup_private_inputs.ts +16 -3
  207. package/src/rollup/root_rollup_public_inputs.ts +10 -0
  208. package/src/stats/stats.ts +4 -5
  209. package/src/tests/factories.ts +38 -32
  210. package/src/tests/fixtures.ts +3 -0
  211. package/src/tests/mocks.ts +6 -7
  212. package/src/tx/state_reference.ts +5 -12
  213. package/dest/messaging/in_hash.d.ts +0 -6
  214. package/dest/messaging/in_hash.d.ts.map +0 -1
  215. package/dest/messaging/in_hash.js +0 -10
  216. package/dest/messaging/inbox_leaf.d.ts +0 -25
  217. package/dest/messaging/inbox_leaf.d.ts.map +0 -1
  218. package/dest/messaging/inbox_leaf.js +0 -42
  219. package/dest/parity/parity_base_private_inputs.d.ts +0 -39
  220. package/dest/parity/parity_base_private_inputs.d.ts.map +0 -1
  221. package/dest/parity/parity_base_private_inputs.js +0 -51
  222. package/dest/parity/parity_root_private_inputs.d.ts +0 -39
  223. package/dest/parity/parity_root_private_inputs.d.ts.map +0 -1
  224. package/dest/parity/parity_root_private_inputs.js +0 -46
  225. package/src/messaging/in_hash.ts +0 -12
  226. package/src/messaging/inbox_leaf.ts +0 -44
  227. package/src/parity/parity_base_private_inputs.ts +0 -71
  228. package/src/parity/parity_root_private_inputs.ts +0 -64
@@ -0,0 +1,125 @@
1
+ import { Fr } from '@aztec/foundation/curves/bn254';
2
+ import { type ZodFor, schemas } from '@aztec/foundation/schemas';
3
+ import { BufferReader, bigintToUInt64BE, serializeToBuffer } from '@aztec/foundation/serialize';
4
+ import type { FieldsOf } from '@aztec/foundation/types';
5
+
6
+ import { z } from 'zod';
7
+
8
+ /**
9
+ * Snapshot of an Inbox rolling-hash bucket as tracked by the archiver.
10
+ *
11
+ * A bucket accumulates the message leaves inserted into the Inbox within a single L1 block (up to a per-bucket
12
+ * maximum, after which further messages in the same block spill into the next bucket). Buckets are identified by
13
+ * a dense, monotonically increasing sequence number and keyed for recency lookups by the L1 block timestamp at
14
+ * which they were opened. Mirrors the on-chain `InboxBucket` struct plus the fields the archiver derives while
15
+ * syncing.
16
+ */
17
+ export type InboxBucket = {
18
+ /** Dense, monotonically increasing sequence number of this bucket in the Inbox ring. */
19
+ seq: bigint;
20
+ /** Consensus rolling hash (truncated sha256 chain) after the last message absorbed into this bucket. */
21
+ inboxRollingHash: Fr;
22
+ /** Cumulative number of messages inserted into the Inbox up to and including this bucket. */
23
+ totalMsgCount: bigint;
24
+ /** L1 block timestamp at which this bucket was opened; the recency key for lag/cutoff comparisons, in seconds. */
25
+ timestamp: bigint;
26
+ /** Number of messages absorbed into this bucket. */
27
+ msgCount: number;
28
+ /** Global leaf index of the last message absorbed into this bucket. */
29
+ lastMessageIndex: bigint;
30
+ };
31
+
32
+ export const InboxBucketSchema = z.object({
33
+ seq: schemas.BigInt,
34
+ inboxRollingHash: Fr.schema,
35
+ totalMsgCount: schemas.BigInt,
36
+ timestamp: schemas.BigInt,
37
+ msgCount: schemas.Integer,
38
+ lastMessageIndex: schemas.BigInt,
39
+ }) satisfies z.ZodType<InboxBucket>;
40
+
41
+ /**
42
+ * Reference to a settled Inbox rolling-hash bucket, carried alongside a block proposal so a
43
+ * validator can look the bucket up in its own Inbox view and derive the consumed-message bundle itself, rather than
44
+ * trusting a proposer-supplied message list. Pins the bucket by its dense sequence number and recency-key timestamp
45
+ * and asserts the expected consensus rolling hash. A wrong reference can only cause a lookup miss or hash mismatch; it
46
+ * can never change what a validator accepts, because the checkpoint header's `inboxRollingHash` remains the signed
47
+ * consensus commitment (mirrors the unsigned bucket hint on L1's `Rollup.propose`).
48
+ */
49
+ export class InboxBucketRef {
50
+ constructor(
51
+ /** Dense, monotonically increasing sequence number of the referenced bucket in the Inbox ring. */
52
+ public readonly bucketSeq: bigint,
53
+ /** L1 block timestamp (in seconds) at which the referenced bucket was opened; its recency key. */
54
+ public readonly bucketTimestamp: bigint,
55
+ /** Consensus rolling hash (truncated sha256 chain) after the last message absorbed into the referenced bucket. */
56
+ public readonly inboxRollingHash: Fr,
57
+ ) {}
58
+
59
+ /** Serialized size in bytes: two uint64 fields plus one field element. */
60
+ static readonly SIZE = 8 + 8 + Fr.SIZE_IN_BYTES;
61
+
62
+ static get schema(): ZodFor<InboxBucketRef> {
63
+ return z
64
+ .object({
65
+ bucketSeq: schemas.BigInt,
66
+ bucketTimestamp: schemas.BigInt,
67
+ inboxRollingHash: Fr.schema,
68
+ })
69
+ .transform(InboxBucketRef.from);
70
+ }
71
+
72
+ static from(fields: FieldsOf<InboxBucketRef>): InboxBucketRef {
73
+ return new InboxBucketRef(fields.bucketSeq, fields.bucketTimestamp, fields.inboxRollingHash);
74
+ }
75
+
76
+ /** Derives a wire reference from a bucket snapshot as tracked by the archiver. */
77
+ static fromBucket(bucket: InboxBucket): InboxBucketRef {
78
+ return new InboxBucketRef(bucket.seq, bucket.timestamp, bucket.inboxRollingHash);
79
+ }
80
+
81
+ toBuffer(): Buffer {
82
+ return serializeToBuffer([
83
+ bigintToUInt64BE(this.bucketSeq),
84
+ bigintToUInt64BE(this.bucketTimestamp),
85
+ this.inboxRollingHash,
86
+ ]);
87
+ }
88
+
89
+ static fromBuffer(buffer: Buffer | BufferReader): InboxBucketRef {
90
+ const reader = BufferReader.asReader(buffer);
91
+ return new InboxBucketRef(reader.readUInt64(), reader.readUInt64(), reader.readObject(Fr));
92
+ }
93
+
94
+ getSize(): number {
95
+ return InboxBucketRef.SIZE;
96
+ }
97
+
98
+ equals(other: InboxBucketRef): boolean {
99
+ return (
100
+ this.bucketSeq === other.bucketSeq &&
101
+ this.bucketTimestamp === other.bucketTimestamp &&
102
+ this.inboxRollingHash.equals(other.inboxRollingHash)
103
+ );
104
+ }
105
+
106
+ static empty(): InboxBucketRef {
107
+ return new InboxBucketRef(0n, 0n, Fr.ZERO);
108
+ }
109
+
110
+ static random(): InboxBucketRef {
111
+ return new InboxBucketRef(
112
+ BigInt(Math.floor(Math.random() * 1000)),
113
+ BigInt(Math.floor(Math.random() * 1_000_000)),
114
+ Fr.random(),
115
+ );
116
+ }
117
+
118
+ toInspect() {
119
+ return {
120
+ bucketSeq: this.bucketSeq.toString(),
121
+ bucketTimestamp: this.bucketTimestamp.toString(),
122
+ inboxRollingHash: this.inboxRollingHash.toString(),
123
+ };
124
+ }
125
+ }
@@ -0,0 +1,74 @@
1
+ import { MAX_L1_TO_L2_MSGS_PER_BLOCK, MAX_L1_TO_L2_MSGS_PER_CHECKPOINT } from '@aztec/constants';
2
+ import { SlotNumber } from '@aztec/foundation/branded-types';
3
+
4
+ import { type L1RollupConstants, getTimestampForSlot } from '../epoch-helpers/index.js';
5
+ import type { InboxBucket } from './inbox_bucket.js';
6
+
7
+ /**
8
+ * Censorship cutoff timestamp for a checkpoint proposed in `slot`, mirroring the cutoff in
9
+ * `ProposeLib.validateInboxConsumption`, which is `TimeLib.getBuildFrameStart(slot)`. A checkpoint proposed in slot
10
+ * `S` is built during slot `S - 1`, and the build frame opens one Ethereum slot before that slot starts, since the
11
+ * builder works from the L1 state as of the preceding L1 block: `cutoff(S) = toTimestamp(S - 1) - E`. Buckets opened
12
+ * at or before the cutoff were visible to every node for the whole build frame and are mandatory to consume by the
13
+ * checkpoint's last block; the strict `>` on the L1 "past cutoff" test (see {@link isInboxConsumptionSufficient})
14
+ * makes a bucket opened exactly at the cutoff mandatory.
15
+ *
16
+ * This is the single source of truth for the cutoff formula shared by the sequencer's streaming bucket selection and
17
+ * the validator's last-block censorship check.
18
+ */
19
+ export function getInboxCutoffTimestamp(
20
+ slot: SlotNumber,
21
+ l1Constants: Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration' | 'ethereumSlotDuration'>,
22
+ ): bigint {
23
+ return getTimestampForSlot(SlotNumber(slot - 1), l1Constants) - BigInt(l1Constants.ethereumSlotDuration);
24
+ }
25
+
26
+ /**
27
+ * Smallest number of blocks a checkpoint must be able to build for the streaming Inbox to be guaranteed to clear any
28
+ * mandatory backlog, and therefore the floor on a network's `maxBlocksPerCheckpoint`.
29
+ *
30
+ * Blocks consume whole buckets — a bucket is never split — so a block can only consume a bucket prefix whose message
31
+ * count fits `MAX_L1_TO_L2_MSGS_PER_BLOCK`. The worst case alternates a one-message bucket with a full
32
+ * `MAX_L1_TO_L2_MSGS_PER_BLOCK`-message bucket: each such pair needs two blocks (the pair's `cap + 1` messages
33
+ * overflow one block), and the backlog only stops being mandatory once consuming the next bucket would exceed
34
+ * `MAX_L1_TO_L2_MSGS_PER_CHECKPOINT` (the cap-escape). That bounds the backlog at `cap + 1` messages per block-pair
35
+ * and yields `2 * ceil((MAX_L1_TO_L2_MSGS_PER_CHECKPOINT + 1) / (MAX_L1_TO_L2_MSGS_PER_BLOCK + 1)) - 1` blocks (the
36
+ * final pair needs only its first block).
37
+ *
38
+ * A network configured below this floor can be halted permanently: an adversary posts that bucket pattern, no
39
+ * checkpoint can reach the censorship floor within its block budget, every checkpoint is rejected, and because a
40
+ * rejected checkpoint never advances the consumed position the next checkpoint faces the identical backlog.
41
+ */
42
+ export const MIN_BLOCKS_FOR_INBOX_CATCHUP =
43
+ 2 * Math.ceil((MAX_L1_TO_L2_MSGS_PER_CHECKPOINT + 1) / (MAX_L1_TO_L2_MSGS_PER_BLOCK + 1)) - 1;
44
+
45
+ /**
46
+ * Whether a checkpoint whose last-consumed bucket is immediately followed by `nextBucket` meets the censorship floor,
47
+ * mirroring the mandatory-consumption assert in `ProposeLib.validateInboxConsumption`.
48
+ * Consumption is sufficient when the first unconsumed bucket:
49
+ * - does not exist (the checkpoint consumed everything the Inbox has), or
50
+ * - was opened strictly after the cutoff (`timestamp > cutoffTimestamp`), or
51
+ * - consuming through it would exceed the per-checkpoint cap (the cap-escape).
52
+ *
53
+ * The strict `>` matches L1: a bucket opened exactly at the cutoff must be consumed. This is the single source of
54
+ * truth for the minimum-consumption / cap-escape rule shared by the sequencer's selection floor and the validator.
55
+ */
56
+ export function isInboxConsumptionSufficient(input: {
57
+ /** The first unconsumed bucket (the one after the checkpoint's last-consumed bucket), or undefined if none exists. */
58
+ nextBucket: Pick<InboxBucket, 'timestamp' | 'totalMsgCount'> | undefined;
59
+ /** Censorship cutoff timestamp from {@link getInboxCutoffTimestamp}. */
60
+ cutoffTimestamp: bigint;
61
+ /** Cumulative Inbox message count consumed as of the parent checkpoint; the per-checkpoint cap origin. */
62
+ checkpointStartTotalMsgCount: bigint;
63
+ /** Maximum number of messages the checkpoint may consume in total (`MAX_L1_TO_L2_MSGS_PER_CHECKPOINT`). */
64
+ perCheckpointCap: number;
65
+ }): boolean {
66
+ const { nextBucket, cutoffTimestamp, checkpointStartTotalMsgCount, perCheckpointCap } = input;
67
+ if (nextBucket === undefined) {
68
+ return true;
69
+ }
70
+ if (nextBucket.timestamp > cutoffTimestamp) {
71
+ return true;
72
+ }
73
+ return nextBucket.totalMsgCount - checkpointStartTotalMsgCount > BigInt(perCheckpointCap);
74
+ }
@@ -0,0 +1,24 @@
1
+ import { DomainSeparator } from '@aztec/constants';
2
+ import { sha256ToField } from '@aztec/foundation/crypto/sha256';
3
+ import { Fr } from '@aztec/foundation/curves/bn254';
4
+ import { numToUInt32BE } from '@aztec/foundation/serialize';
5
+
6
+ /**
7
+ * Extends the Inbox rolling-hash chain by a single message leaf, returning the new rolling hash.
8
+ *
9
+ * Each link is `sha256ToField(DOM_SEP__INBOX_ROLLING_HASH || prev || leaf)` over the 4-byte big-endian domain
10
+ * separator followed by the two 32-byte big-endian values, matching the truncated-to-field sha256 the L1 Inbox
11
+ * accumulates and the noir `accumulate_inbox_rolling_hash` helper. The separator distinguishes a chain link from the
12
+ * untagged `outHash` merkle node hash, which absorbs the same two-field preimage shape.
13
+ */
14
+ export function updateInboxRollingHash(prev: Fr, leaf: Fr): Fr {
15
+ return sha256ToField([numToUInt32BE(DomainSeparator.INBOX_ROLLING_HASH), prev.toBuffer(), leaf.toBuffer()]);
16
+ }
17
+
18
+ /**
19
+ * Extends the Inbox rolling-hash chain by a list of message leaves, in order, returning the new rolling hash.
20
+ * The genesis rolling hash is `Fr.ZERO`, and an empty list returns `start` unchanged.
21
+ */
22
+ export function accumulateInboxRollingHash(start: Fr, leaves: Fr[]): Fr {
23
+ return leaves.reduce(updateInboxRollingHash, start);
24
+ }
@@ -1,6 +1,9 @@
1
1
  export * from './append_l1_to_l2_messages.js';
2
- export * from './in_hash.js';
3
- export * from './inbox_leaf.js';
2
+ export * from './inbox_bucket.js';
3
+ export * from './inbox_consumption.js';
4
+ export * from './inbox_rolling_hash.js';
5
+ export * from './l1_to_l2_message_bundle.js';
6
+ export * from './l1_to_l2_message_sponge.js';
4
7
  export * from './l1_to_l2_message.js';
5
8
  export * from './l1_to_l2_message_source.js';
6
9
  export * from './l1_actor.js';
@@ -0,0 +1,65 @@
1
+ import { MAX_L1_TO_L2_MSGS_PER_BLOCK } from '@aztec/constants';
2
+ import { padArrayEnd } from '@aztec/foundation/collection';
3
+ import { Fr } from '@aztec/foundation/curves/bn254';
4
+ import { bufferSchemaFor } from '@aztec/foundation/schemas';
5
+ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
6
+ import { bufferToHex, hexToBuffer } from '@aztec/foundation/string';
7
+
8
+ /**
9
+ * A block's L1-to-L2 message bundle: the real message leaves it inserts into the L1-to-L2 message tree and the count
10
+ * that drives both the compact (unpadded) tree append and the message-sponge absorb. See the Noir
11
+ * `L1ToL2MessageBundle`.
12
+ */
13
+ export class L1ToL2MessageBundle {
14
+ constructor(
15
+ /** The real message leaves in the leading lanes, padded with zeros to `MAX_L1_TO_L2_MSGS_PER_BLOCK`. Kept as a
16
+ * plain array (not a tuple) to avoid TS's deep-instantiation limit on the wide type. */
17
+ public readonly messages: Fr[],
18
+ /** Number of real messages: drives both the compact tree append and the sponge absorb. */
19
+ public readonly numMsgs: number,
20
+ ) {}
21
+
22
+ /** An empty bundle: no leaves inserted, nothing absorbed. */
23
+ static empty(): L1ToL2MessageBundle {
24
+ return new L1ToL2MessageBundle(
25
+ Array.from({ length: MAX_L1_TO_L2_MSGS_PER_BLOCK }, () => Fr.ZERO),
26
+ 0,
27
+ );
28
+ }
29
+
30
+ toBuffer() {
31
+ return serializeToBuffer(this.messages, this.numMsgs);
32
+ }
33
+
34
+ toString() {
35
+ return bufferToHex(this.toBuffer());
36
+ }
37
+
38
+ static fromBuffer(buffer: Buffer | BufferReader) {
39
+ const reader = BufferReader.asReader(buffer);
40
+ // Array.from (not readArray with the literal cap) keeps the type `Fr[]` and avoids TS's deep-tuple instantiation.
41
+ const messages = Array.from({ length: MAX_L1_TO_L2_MSGS_PER_BLOCK }, () => Fr.fromBuffer(reader));
42
+ return new L1ToL2MessageBundle(messages, reader.readNumber());
43
+ }
44
+
45
+ static fromString(str: string) {
46
+ return L1ToL2MessageBundle.fromBuffer(hexToBuffer(str));
47
+ }
48
+
49
+ toJSON() {
50
+ return this.toBuffer();
51
+ }
52
+
53
+ static get schema() {
54
+ return bufferSchemaFor(L1ToL2MessageBundle);
55
+ }
56
+ }
57
+
58
+ /** Wraps `messages` (the real leaves) into a bundle: the leaves fill the leading lanes, the count is the real count. */
59
+ export function makeL1ToL2MessageBundle(messages: Fr[]): L1ToL2MessageBundle {
60
+ // Explicit `<Fr, number>` keeps the result `Fr[]`; padding to the literal cap would otherwise infer a deep tuple.
61
+ return new L1ToL2MessageBundle(
62
+ padArrayEnd<Fr, number>(messages, Fr.ZERO, MAX_L1_TO_L2_MSGS_PER_BLOCK),
63
+ messages.length,
64
+ );
65
+ }
@@ -1,21 +1,12 @@
1
- import type { CheckpointNumber } from '@aztec/foundation/branded-types';
2
1
  import type { Fr } from '@aztec/foundation/curves/bn254';
3
2
 
4
3
  import type { L2Tips } from '../block/l2_block_source.js';
4
+ import type { InboxBucket } from './inbox_bucket.js';
5
5
 
6
6
  /**
7
7
  * Interface of classes allowing for the retrieval of L1 to L2 messages.
8
8
  */
9
9
  export interface L1ToL2MessageSource {
10
- /**
11
- * Gets new L1 to L2 message (to be) included in a given checkpoint.
12
- * @param checkpointNumber - Checkpoint number to get messages for.
13
- * @returns The L1 to L2 messages/leaves of the messages subtree.
14
- * @throws If the message tree for the given checkpoint has not yet been sealed on L1
15
- * (i.e., checkpointNumber >= inbox treeInProgress).
16
- */
17
- getL1ToL2Messages(checkpointNumber: CheckpointNumber): Promise<Fr[]>;
18
-
19
10
  /**
20
11
  * Gets the L1 to L2 message index in the L1 to L2 message tree.
21
12
  * @param l1ToL2Message - The L1 to L2 message.
@@ -23,6 +14,53 @@ export interface L1ToL2MessageSource {
23
14
  */
24
15
  getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise<bigint | undefined>;
25
16
 
17
+ /**
18
+ * Returns the latest Inbox bucket opened at or before the given L1 timestamp, or undefined if no such bucket
19
+ * exists (i.e., every synced bucket was opened strictly after the timestamp). Used by the sequencer/validator
20
+ * to resolve the censorship cutoff and message-lag boundaries.
21
+ * @param timestamp - The L1 timestamp (in seconds) to look up at-or-before.
22
+ */
23
+ getLatestInboxBucketAtOrBefore(timestamp: bigint): Promise<InboxBucket | undefined>;
24
+
25
+ /**
26
+ * Returns the Inbox bucket with the given sequence number, or undefined if it has not been synced. Validators use
27
+ * this to resolve the bucket a proposal references and check its rolling hash.
28
+ * @param seq - The bucket sequence number.
29
+ */
30
+ getInboxBucket(seq: bigint): Promise<InboxBucket | undefined>;
31
+
32
+ /**
33
+ * Returns the Inbox bucket whose cumulative message total equals `totalMsgCount`, or undefined if no synced bucket
34
+ * sits on that boundary. A block's or checkpoint's L1-to-L2 tree leaf count equals the cumulative total of the last
35
+ * bucket it consumed (messages are indexed compactly, with no padding), so validators use this to resolve the
36
+ * bucket a block consumed through from the block's leaf count, without trusting a wire hint. `totalMsgCount === 0`
37
+ * resolves the genesis sentinel bucket (sequence 0); a total that does not land on a bucket boundary returns
38
+ * undefined.
39
+ * @param totalMsgCount - The cumulative Inbox message count (leaf count) to resolve to a bucket boundary.
40
+ */
41
+ getInboxBucketByTotalMsgCount(totalMsgCount: bigint): Promise<InboxBucket | undefined>;
42
+
43
+ /**
44
+ * Returns the message leaves absorbed into buckets in the range `(fromExclusive, toInclusive]`, in insertion
45
+ * order, for streaming message-bundle derivation. Both bounds must name buckets the source
46
+ * has synced; it throws otherwise, so that an empty result means the range holds no messages instead of hiding an
47
+ * unsynced bound. Callers that can tolerate an unsynced source resolve both bounds first, or map the failure to
48
+ * their own catch-up handling.
49
+ * @param fromExclusive - The lower bucket sequence bound, exclusive (0 means from the start of the Inbox).
50
+ * @param toInclusive - The upper bucket sequence bound, inclusive.
51
+ */
52
+ getL1ToL2MessagesBetweenBuckets(fromExclusive: bigint, toInclusive: bigint): Promise<Fr[]>;
53
+
54
+ /**
55
+ * Returns the message leaves in the cumulative Inbox message-count range `[startLeafCount, endLeafCount)`, in
56
+ * insertion order. The bounds are compact L1-to-L2 tree leaf counts, which every block header
57
+ * carries, so a consumer can ask for the messages a block or checkpoint consumed without resolving Inbox buckets
58
+ * itself. Both bounds must land on a bucket boundary the source has synced; it throws otherwise.
59
+ * @param startLeafCount - The cumulative Inbox message count the range starts at, inclusive.
60
+ * @param endLeafCount - The cumulative Inbox message count the range ends at, exclusive.
61
+ */
62
+ getL1ToL2MessagesBetweenLeafCounts(startLeafCount: bigint, endLeafCount: bigint): Promise<Fr[]>;
63
+
26
64
  /**
27
65
  * Returns the tips of the L2 chain.
28
66
  */
@@ -0,0 +1,69 @@
1
+ import { Poseidon2Sponge } from '@aztec/blob-lib/types';
2
+ import { Fr } from '@aztec/foundation/curves/bn254';
3
+ import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize';
4
+ import type { FieldsOf } from '@aztec/foundation/types';
5
+
6
+ /**
7
+ * An absorb-only Poseidon2 sponge over L1-to-L2 message leaves.
8
+ *
9
+ * Mirrors `L1ToL2MessageSponge` in
10
+ * `noir-projects/fnd/noir-protocol-circuits/crates/rollup-lib/src/abis/l1_to_l2_message_sponge.nr`. Each block of a
11
+ * checkpoint absorbs its message bundle into the sponge it inherited from the previous block; the checkpoint root
12
+ * recomputes the sponge over the checkpoint's whole message list and asserts the accumulated states are equal.
13
+ */
14
+ export class L1ToL2MessageSponge {
15
+ constructor(
16
+ /** Sponge accumulating the absorbed message leaves. */
17
+ public readonly sponge: Poseidon2Sponge,
18
+ /** Number of message leaves absorbed so far. */
19
+ public numAbsorbed: number,
20
+ ) {}
21
+
22
+ /** A fresh, empty sponge (matching noir's `L1ToL2MessageSponge::new()` / `empty()`, i.e. `Poseidon2Sponge::new(0)`). */
23
+ static empty(): L1ToL2MessageSponge {
24
+ return new L1ToL2MessageSponge(Poseidon2Sponge.empty(), 0);
25
+ }
26
+
27
+ /** Absorb the given message leaves in order. */
28
+ async absorb(leaves: Fr[]) {
29
+ await this.sponge.absorb(leaves);
30
+ this.numAbsorbed += leaves.length;
31
+ }
32
+
33
+ clone() {
34
+ return L1ToL2MessageSponge.fromBuffer(this.toBuffer());
35
+ }
36
+
37
+ static getFields(fields: FieldsOf<L1ToL2MessageSponge>) {
38
+ return [fields.sponge, fields.numAbsorbed] as const;
39
+ }
40
+
41
+ toBuffer() {
42
+ return serializeToBuffer(...L1ToL2MessageSponge.getFields(this));
43
+ }
44
+
45
+ static fromBuffer(buffer: Buffer | BufferReader): L1ToL2MessageSponge {
46
+ const reader = BufferReader.asReader(buffer);
47
+ return new L1ToL2MessageSponge(reader.readObject(Poseidon2Sponge), reader.readNumber());
48
+ }
49
+
50
+ toFields(): Fr[] {
51
+ return serializeToFields(...L1ToL2MessageSponge.getFields(this));
52
+ }
53
+
54
+ static fromFields(fields: Fr[] | FieldReader): L1ToL2MessageSponge {
55
+ const reader = FieldReader.asReader(fields);
56
+ return new L1ToL2MessageSponge(reader.readObject(Poseidon2Sponge), reader.readField().toNumber());
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Accumulates a fresh message sponge over `leaves`, in order. This is the value the inbox parity proof commits to and
62
+ * the checkpoint's block roots reach, starting from the empty sponge. Every leaf passed in is absorbed, so any padding
63
+ * the caller includes is part of the accumulated state.
64
+ */
65
+ export async function accumulateL1ToL2MessageSponge(leaves: Fr[]): Promise<L1ToL2MessageSponge> {
66
+ const sponge = L1ToL2MessageSponge.empty();
67
+ await sponge.absorb(leaves);
68
+ return sponge;
69
+ }
package/src/noir/index.ts CHANGED
@@ -4,7 +4,6 @@ import type {
4
4
  AbiErrorType,
5
5
  AbiNamedValue,
6
6
  AbiType,
7
- AbiValue,
8
7
  DebugFileMap,
9
8
  DebugInfo,
10
9
  } from '../abi/abi.js';
@@ -74,7 +73,7 @@ export interface NoirCompiledContract {
74
73
  /** The events of the contract */
75
74
  outputs: {
76
75
  structs: Record<string, AbiType[]>;
77
- globals: Record<string, (AbiNamedValue | AbiValue)[]>;
76
+ globals: Record<string, AbiNamedValue[]>;
78
77
  };
79
78
  /** The map of file ID to the source code and path of the file. */
80
79
  file_map: DebugFileMap;