Skip to content

Commit 62dcb67

Browse files
committed
fix(fast-inbox): guard between-buckets lower bound and bound timestamp fetch (A-1379)
1 parent 72bc282 commit 62dcb67

3 files changed

Lines changed: 24 additions & 9 deletions

File tree

yarn-project/archiver/src/store/message_store.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,8 @@ describe('MessageStore', () => {
439439
expect(await messageStore.getL1ToL2MessagesBetweenBuckets(3n, 3n)).toEqual([]);
440440
// Unknown upper bucket yields no messages.
441441
expect(await messageStore.getL1ToL2MessagesBetweenBuckets(0n, 9n)).toEqual([]);
442+
// An unknown nonzero lower bucket is treated as unavailable, not as genesis.
443+
expect(await messageStore.getL1ToL2MessagesBetweenBuckets(4n, 3n)).toEqual([]);
442444
});
443445

444446
it('rewinds buckets when messages are removed', async () => {

yarn-project/archiver/src/store/message_store.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -433,8 +433,17 @@ export class MessageStore {
433433
if (toBucket === undefined) {
434434
return [];
435435
}
436-
const fromBucket = fromExclusive > 0n ? await this.getBucketSnapshotBySeq(fromExclusive) : undefined;
437-
const startIndex = fromBucket ? fromBucket.lastMessageIndex + 1n : 0n;
436+
// A nonzero lower bound must reference a synced bucket; otherwise the range is unavailable (rather than
437+
// defaulting to genesis, which would silently over-return). Sequence 0 is the genesis base case: start from
438+
// the beginning of the Inbox.
439+
let startIndex = 0n;
440+
if (fromExclusive > 0n) {
441+
const fromBucket = await this.getBucketSnapshotBySeq(fromExclusive);
442+
if (fromBucket === undefined) {
443+
return [];
444+
}
445+
startIndex = fromBucket.lastMessageIndex + 1n;
446+
}
438447
const endIndexExclusive = toBucket.lastMessageIndex + 1n;
439448

440449
const leaves: Fr[] = [];

yarn-project/ethereum/src/contracts/inbox.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { asyncPool } from '@aztec/foundation/async-pool';
12
import { maxBigint } from '@aztec/foundation/bigint';
23
import { CheckpointNumber } from '@aztec/foundation/branded-types';
34
import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
@@ -108,16 +109,19 @@ export class InboxContract {
108109
return this.mapMessageSentLog(log, timestamp);
109110
}
110111

111-
/** Fetches the timestamp of each distinct L1 block number, so each MessageSent log can carry its bucket key. */
112+
/**
113+
* Fetches the timestamp of each distinct L1 block number, so each MessageSent log can carry its bucket key.
114+
* Fetched with bounded concurrency to keep a large sync batch from fanning out unbounded RPC requests. Blocks
115+
* are resolved by number rather than hash so a concurrent L1 reorg does not throw; a resulting cross-fork
116+
* timestamp is transient and re-corrected by the archiver's rolling-hash reorg detection on the next sync.
117+
*/
112118
private async getBlockTimestamps(blockNumbers: bigint[]): Promise<Map<bigint, bigint>> {
113119
const uniqueBlockNumbers = [...new Set(blockNumbers)];
114120
const timestamps = new Map<bigint, bigint>();
115-
await Promise.all(
116-
uniqueBlockNumbers.map(async blockNumber => {
117-
const block = await this.client.getBlock({ blockNumber, includeTransactions: false });
118-
timestamps.set(blockNumber, block.timestamp);
119-
}),
120-
);
121+
await asyncPool(10, uniqueBlockNumbers, async blockNumber => {
122+
const block = await this.client.getBlock({ blockNumber, includeTransactions: false });
123+
timestamps.set(blockNumber, block.timestamp);
124+
});
121125
return timestamps;
122126
}
123127

0 commit comments

Comments
 (0)