@@ -168,47 +168,6 @@ contract Inbox is IInbox {
168168 return (leaf, index);
169169 }
170170
171- /**
172- * @notice Absorbs a message leaf into the consensus rolling hash and snapshots it into the bucket ring
173- *
174- * @dev A bucket only holds messages from a single L1 block, up to MAX_MSGS_PER_BUCKET; the first message
175- * of a new L1 block — or the message after a full bucket, spilling over within the same block — opens the
176- * next bucket, inheriting the rolling hash and cumulative count. Bucket 0 is the pristine genesis base
177- * case and never absorbs. Opening a bucket overwrites the ring entry from BUCKET_RING_SIZE buckets ago;
178- * protection against overwriting unconsumed buckets is not enforced yet.
179- *
180- * @param _leaf - The message leaf to absorb
181- *
182- * @return The sequence number of the bucket the leaf was absorbed into and the updated rolling hash
183- */
184- function _absorbIntoBucket (bytes32 _leaf ) internal returns (uint64 , bytes32 ) {
185- uint64 bucketSeq = currentBucketSeq;
186- InboxBucket memory bucket = buckets[bucketSeq % BUCKET_RING_SIZE];
187-
188- // Buckets are keyed by L1 block timestamp: a strictly larger timestamp opens a new bucket (a full bucket
189- // also rolls over within the same block). Post-merge Ethereum increases block.timestamp strictly per block,
190- // so messages from different L1 blocks always land in different buckets. Under anvil with manual mining two
191- // blocks can share a timestamp and therefore a bucket; this is harmless because the consumption cutoff is
192- // computed over timestamps, so co-timestamped blocks are indistinguishable to it.
193- if (bucketSeq == 0 || bucket.timestamp < block .timestamp || bucket.msgCount == MAX_MSGS_PER_BUCKET) {
194- bucketSeq += 1 ;
195- currentBucketSeq = bucketSeq;
196- bucket = InboxBucket ({
197- rollingHash: bucket.rollingHash,
198- totalMsgCount: bucket.totalMsgCount,
199- timestamp: SafeCast.toUint64 (block .timestamp ),
200- msgCount: 0
201- });
202- }
203-
204- bucket.rollingHash = Hash.accumulateInboxRollingHash (bucket.rollingHash, _leaf);
205- bucket.totalMsgCount += 1 ;
206- bucket.msgCount += 1 ;
207- buckets[bucketSeq % BUCKET_RING_SIZE] = bucket;
208-
209- return (bucketSeq, bucket.rollingHash);
210- }
211-
212171 /**
213172 * @notice Consumes the current tree, and starts a new one if needed
214173 *
@@ -269,4 +228,45 @@ contract Inbox is IInbox {
269228 require (_seq <= current && current - _seq < BUCKET_RING_SIZE, Errors.Inbox__BucketOutOfWindow (_seq, current));
270229 return buckets[_seq % BUCKET_RING_SIZE];
271230 }
231+
232+ /**
233+ * @notice Absorbs a message leaf into the consensus rolling hash and snapshots it into the bucket ring
234+ *
235+ * @dev A bucket only holds messages from a single L1 block, up to MAX_MSGS_PER_BUCKET; the first message
236+ * of a new L1 block — or the message after a full bucket, spilling over within the same block — opens the
237+ * next bucket, inheriting the rolling hash and cumulative count. Bucket 0 is the pristine genesis base
238+ * case and never absorbs. Opening a bucket overwrites the ring entry from BUCKET_RING_SIZE buckets ago;
239+ * protection against overwriting unconsumed buckets is not enforced yet.
240+ *
241+ * @param _leaf - The message leaf to absorb
242+ *
243+ * @return The sequence number of the bucket the leaf was absorbed into and the updated rolling hash
244+ */
245+ function _absorbIntoBucket (bytes32 _leaf ) internal returns (uint64 , bytes32 ) {
246+ uint64 bucketSeq = currentBucketSeq;
247+ InboxBucket memory bucket = buckets[bucketSeq % BUCKET_RING_SIZE];
248+
249+ // Buckets are keyed by L1 block timestamp: a strictly larger timestamp opens a new bucket (a full bucket
250+ // also rolls over within the same block). Post-merge Ethereum increases block.timestamp strictly per block,
251+ // so messages from different L1 blocks always land in different buckets. Under anvil with manual mining two
252+ // blocks can share a timestamp and therefore a bucket; this is harmless because the consumption cutoff is
253+ // computed over timestamps, so co-timestamped blocks are indistinguishable to it.
254+ if (bucketSeq == 0 || bucket.timestamp < block .timestamp || bucket.msgCount == MAX_MSGS_PER_BUCKET) {
255+ bucketSeq += 1 ;
256+ currentBucketSeq = bucketSeq;
257+ bucket = InboxBucket ({
258+ rollingHash: bucket.rollingHash,
259+ totalMsgCount: bucket.totalMsgCount,
260+ timestamp: SafeCast.toUint64 (block .timestamp ),
261+ msgCount: 0
262+ });
263+ }
264+
265+ bucket.rollingHash = Hash.accumulateInboxRollingHash (bucket.rollingHash, _leaf);
266+ bucket.totalMsgCount += 1 ;
267+ bucket.msgCount += 1 ;
268+ buckets[bucketSeq % BUCKET_RING_SIZE] = bucket;
269+
270+ return (bucketSeq, bucket.rollingHash);
271+ }
272272}
0 commit comments