@aztec/world-state 0.0.1-commit.d3ec352c → 0.0.1-commit.e6bd8901

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 (40) hide show
  1. package/dest/instrumentation/instrumentation.d.ts +1 -1
  2. package/dest/instrumentation/instrumentation.d.ts.map +1 -1
  3. package/dest/instrumentation/instrumentation.js +11 -42
  4. package/dest/native/merkle_trees_facade.d.ts +8 -3
  5. package/dest/native/merkle_trees_facade.d.ts.map +1 -1
  6. package/dest/native/merkle_trees_facade.js +35 -6
  7. package/dest/native/message.d.ts +2 -2
  8. package/dest/native/message.d.ts.map +1 -1
  9. package/dest/native/message.js +1 -1
  10. package/dest/native/native_world_state.d.ts +7 -5
  11. package/dest/native/native_world_state.d.ts.map +1 -1
  12. package/dest/native/native_world_state.js +5 -4
  13. package/dest/synchronizer/config.d.ts +1 -3
  14. package/dest/synchronizer/config.d.ts.map +1 -1
  15. package/dest/synchronizer/config.js +1 -6
  16. package/dest/synchronizer/server_world_state_synchronizer.d.ts +5 -4
  17. package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
  18. package/dest/synchronizer/server_world_state_synchronizer.js +67 -40
  19. package/dest/test/utils.d.ts +11 -17
  20. package/dest/test/utils.d.ts.map +1 -1
  21. package/dest/test/utils.js +44 -81
  22. package/dest/testing.d.ts +2 -2
  23. package/dest/testing.d.ts.map +1 -1
  24. package/dest/testing.js +1 -1
  25. package/dest/world-state-db/merkle_tree_db.d.ts +7 -9
  26. package/dest/world-state-db/merkle_tree_db.d.ts.map +1 -1
  27. package/package.json +11 -11
  28. package/src/instrumentation/instrumentation.ts +10 -42
  29. package/src/native/merkle_trees_facade.ts +36 -3
  30. package/src/native/message.ts +1 -1
  31. package/src/native/native_world_state.ts +9 -8
  32. package/src/synchronizer/config.ts +1 -14
  33. package/src/synchronizer/server_world_state_synchronizer.ts +71 -56
  34. package/src/test/utils.ts +70 -128
  35. package/src/testing.ts +1 -1
  36. package/src/world-state-db/merkle_tree_db.ts +10 -12
  37. package/dest/synchronizer/utils.d.ts +0 -11
  38. package/dest/synchronizer/utils.d.ts.map +0 -1
  39. package/dest/synchronizer/utils.js +0 -59
  40. package/src/synchronizer/utils.ts +0 -83
@@ -7,7 +7,6 @@ import {
7
7
  Metrics,
8
8
  type TelemetryClient,
9
9
  type UpDownCounter,
10
- ValueType,
11
10
  } from '@aztec/telemetry-client';
12
11
 
13
12
  import {
@@ -46,56 +45,25 @@ export class WorldStateInstrumentation {
46
45
  private log: Logger = createLogger('world-state:instrumentation'),
47
46
  ) {
48
47
  const meter = telemetry.getMeter('World State');
49
- this.dbMapSize = meter.createGauge(Metrics.WORLD_STATE_DB_MAP_SIZE, {
50
- description: `The current configured map size for each merkle tree`,
51
- valueType: ValueType.INT,
52
- });
48
+ this.dbMapSize = meter.createGauge(Metrics.WORLD_STATE_DB_MAP_SIZE);
53
49
 
54
- this.dbPhysicalSize = meter.createGauge(Metrics.WORLD_STATE_DB_PHYSICAL_SIZE, {
55
- description: `The current physical disk space used for each database`,
56
- valueType: ValueType.INT,
57
- });
50
+ this.dbPhysicalSize = meter.createGauge(Metrics.WORLD_STATE_DB_PHYSICAL_SIZE);
58
51
 
59
- this.treeSize = meter.createGauge(Metrics.WORLD_STATE_TREE_SIZE, {
60
- description: `The current number of leaves in each merkle tree`,
61
- valueType: ValueType.INT,
62
- });
52
+ this.treeSize = meter.createGauge(Metrics.WORLD_STATE_TREE_SIZE);
63
53
 
64
- this.unfinalizedHeight = meter.createGauge(Metrics.WORLD_STATE_UNFINALIZED_HEIGHT, {
65
- description: `The unfinalized block height of each merkle tree`,
66
- valueType: ValueType.INT,
67
- });
54
+ this.unfinalizedHeight = meter.createGauge(Metrics.WORLD_STATE_UNFINALIZED_HEIGHT);
68
55
 
69
- this.finalizedHeight = meter.createGauge(Metrics.WORLD_STATE_FINALIZED_HEIGHT, {
70
- description: `The finalized block height of each merkle tree`,
71
- valueType: ValueType.INT,
72
- });
56
+ this.finalizedHeight = meter.createGauge(Metrics.WORLD_STATE_FINALIZED_HEIGHT);
73
57
 
74
- this.oldestBlock = meter.createGauge(Metrics.WORLD_STATE_OLDEST_BLOCK, {
75
- description: `The oldest historical block of each merkle tree`,
76
- valueType: ValueType.INT,
77
- });
58
+ this.oldestBlock = meter.createGauge(Metrics.WORLD_STATE_OLDEST_BLOCK);
78
59
 
79
- this.dbUsedSize = meter.createGauge(Metrics.WORLD_STATE_DB_USED_SIZE, {
80
- description: `The current used database size for each db of each merkle tree`,
81
- valueType: ValueType.INT,
82
- });
60
+ this.dbUsedSize = meter.createGauge(Metrics.WORLD_STATE_DB_USED_SIZE);
83
61
 
84
- this.dbNumItems = meter.createGauge(Metrics.WORLD_STATE_DB_NUM_ITEMS, {
85
- description: `The current number of items in each database of each merkle tree`,
86
- valueType: ValueType.INT,
87
- });
62
+ this.dbNumItems = meter.createGauge(Metrics.WORLD_STATE_DB_NUM_ITEMS);
88
63
 
89
- this.requestHistogram = meter.createHistogram(Metrics.WORLD_STATE_REQUEST_TIME, {
90
- description: 'The round trip time of world state requests',
91
- unit: 'us',
92
- valueType: ValueType.INT,
93
- });
64
+ this.requestHistogram = meter.createHistogram(Metrics.WORLD_STATE_REQUEST_TIME);
94
65
 
95
- this.criticalErrors = meter.createUpDownCounter(Metrics.WORLD_STATE_CRITICAL_ERROR_COUNT, {
96
- description: 'The number of critical errors in the world state',
97
- valueType: ValueType.INT,
98
- });
66
+ this.criticalErrors = meter.createUpDownCounter(Metrics.WORLD_STATE_CRITICAL_ERROR_COUNT);
99
67
  }
100
68
 
101
69
  private updateTreeStats(treeDbStats: TreeDBStats, treeMeta: TreeMeta, tree: MerkleTreeId) {
@@ -1,6 +1,8 @@
1
1
  import { BlockNumber } from '@aztec/foundation/branded-types';
2
- import { Fr } from '@aztec/foundation/fields';
2
+ import { Fr } from '@aztec/foundation/curves/bn254';
3
+ import { createLogger } from '@aztec/foundation/log';
3
4
  import { serializeToBuffer } from '@aztec/foundation/serialize';
5
+ import { sleep } from '@aztec/foundation/sleep';
4
6
  import { type IndexedTreeLeafPreimage, SiblingPath } from '@aztec/foundation/trees';
5
7
  import type {
6
8
  BatchInsertionResult,
@@ -204,7 +206,14 @@ export class MerkleTreesFacade implements MerkleTreeReadOperations {
204
206
  }
205
207
 
206
208
  export class MerkleTreesForkFacade extends MerkleTreesFacade implements MerkleTreeWriteOperations {
207
- constructor(instance: NativeWorldStateInstance, initialHeader: BlockHeader, revision: WorldStateRevision) {
209
+ private log = createLogger('world-state:merkle-trees-fork-facade');
210
+
211
+ constructor(
212
+ instance: NativeWorldStateInstance,
213
+ initialHeader: BlockHeader,
214
+ revision: WorldStateRevision,
215
+ private opts: { closeDelayMs?: number },
216
+ ) {
208
217
  assert.notEqual(revision.forkId, 0, 'Fork ID must be set');
209
218
  assert.equal(revision.includeUncommitted, true, 'Fork must include uncommitted data');
210
219
  super(instance, initialHeader, revision);
@@ -283,7 +292,31 @@ export class MerkleTreesForkFacade extends MerkleTreesFacade implements MerkleTr
283
292
 
284
293
  public async close(): Promise<void> {
285
294
  assert.notEqual(this.revision.forkId, 0, 'Fork ID must be set');
286
- await this.instance.call(WorldStateMessageType.DELETE_FORK, { forkId: this.revision.forkId });
295
+ try {
296
+ await this.instance.call(WorldStateMessageType.DELETE_FORK, { forkId: this.revision.forkId });
297
+ } catch (err: any) {
298
+ // Ignore errors due to native instance being closed during shutdown.
299
+ // This can happen when validators are still processing block proposals while the node is stopping.
300
+ if (err?.message === 'Native instance is closed') {
301
+ return;
302
+ }
303
+ throw err;
304
+ }
305
+ }
306
+
307
+ async [Symbol.dispose](): Promise<void> {
308
+ if (this.opts.closeDelayMs) {
309
+ void sleep(this.opts.closeDelayMs)
310
+ .then(() => this.close())
311
+ .catch(err => {
312
+ if (err && 'message' in err && err.message === 'Native instance is closed') {
313
+ return; // Ignore errors due to native instance being closed
314
+ }
315
+ this.log.warn('Error closing MerkleTreesForkFacade after delay', { err });
316
+ });
317
+ } else {
318
+ await this.close();
319
+ }
287
320
  }
288
321
 
289
322
  public async createCheckpoint(): Promise<void> {
@@ -1,5 +1,5 @@
1
1
  import { BlockNumber } from '@aztec/foundation/branded-types';
2
- import { Fr } from '@aztec/foundation/fields';
2
+ import { Fr } from '@aztec/foundation/curves/bn254';
3
3
  import type { Tuple } from '@aztec/foundation/serialize';
4
4
  import { AppendOnlyTreeSnapshot, MerkleTreeId } from '@aztec/stdlib/trees';
5
5
  import type { StateReference } from '@aztec/stdlib/tx';
@@ -1,11 +1,11 @@
1
1
  import { MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
2
2
  import { BlockNumber } from '@aztec/foundation/branded-types';
3
3
  import { fromEntries, padArrayEnd } from '@aztec/foundation/collection';
4
+ import { Fr } from '@aztec/foundation/curves/bn254';
4
5
  import { EthAddress } from '@aztec/foundation/eth-address';
5
- import { Fr } from '@aztec/foundation/fields';
6
6
  import { tryRmDir } from '@aztec/foundation/fs';
7
7
  import { type Logger, createLogger } from '@aztec/foundation/log';
8
- import type { L2BlockNew } from '@aztec/stdlib/block';
8
+ import type { L2Block } from '@aztec/stdlib/block';
9
9
  import { DatabaseVersionManager } from '@aztec/stdlib/database-version';
10
10
  import type {
11
11
  IndexedTreeId,
@@ -159,7 +159,10 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
159
159
  );
160
160
  }
161
161
 
162
- public async fork(blockNumber?: BlockNumber): Promise<MerkleTreeWriteOperations> {
162
+ public async fork(
163
+ blockNumber?: BlockNumber,
164
+ opts: { closeDelayMs?: number } = {},
165
+ ): Promise<MerkleTreeWriteOperations> {
163
166
  const resp = await this.instance.call(WorldStateMessageType.CREATE_FORK, {
164
167
  latest: blockNumber === undefined,
165
168
  blockNumber: blockNumber ?? BlockNumber.ZERO,
@@ -173,6 +176,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
173
176
  /* blockNumber=*/ BlockNumber.ZERO,
174
177
  /* includeUncommitted=*/ true,
175
178
  ),
179
+ opts,
176
180
  );
177
181
  }
178
182
 
@@ -180,11 +184,8 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
180
184
  return this.initialHeader!;
181
185
  }
182
186
 
183
- public async handleL2BlockAndMessages(
184
- l2Block: L2BlockNew,
185
- l1ToL2Messages: Fr[],
186
- isFirstBlock: boolean,
187
- ): Promise<WorldStateStatusFull> {
187
+ public async handleL2BlockAndMessages(l2Block: L2Block, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull> {
188
+ const isFirstBlock = l2Block.indexWithinCheckpoint === 0;
188
189
  if (!isFirstBlock && l1ToL2Messages.length > 0) {
189
190
  throw new Error(
190
191
  `L1 to L2 messages must be empty for non-first blocks, but got ${l1ToL2Messages.length} messages for block ${l2Block.number}.`,
@@ -1,18 +1,10 @@
1
- import {
2
- type ConfigMappingsType,
3
- booleanConfigHelper,
4
- getConfigFromMappings,
5
- numberConfigHelper,
6
- } from '@aztec/foundation/config';
1
+ import { type ConfigMappingsType, getConfigFromMappings, numberConfigHelper } from '@aztec/foundation/config';
7
2
 
8
3
  /** World State synchronizer configuration values. */
9
4
  export interface WorldStateConfig {
10
5
  /** The frequency in which to check. */
11
6
  worldStateBlockCheckIntervalMS: number;
12
7
 
13
- /** Whether to follow only the proven chain. */
14
- worldStateProvenBlocksOnly: boolean;
15
-
16
8
  /** Size of the batch for each get-blocks request from the synchronizer to the archiver. */
17
9
  worldStateBlockRequestBatchSize?: number;
18
10
 
@@ -48,11 +40,6 @@ export const worldStateConfigMappings: ConfigMappingsType<WorldStateConfig> = {
48
40
  defaultValue: 100,
49
41
  description: 'The frequency in which to check.',
50
42
  },
51
- worldStateProvenBlocksOnly: {
52
- env: 'WS_PROVEN_BLOCKS_ONLY',
53
- description: 'Whether to follow only the proven chain.',
54
- ...booleanConfigHelper(),
55
- },
56
43
  worldStateBlockRequestBatchSize: {
57
44
  env: 'WS_BLOCK_REQUEST_BATCH_SIZE',
58
45
  parseEnv: (val: string | undefined) => (val ? +val : undefined),
@@ -1,17 +1,19 @@
1
+ import { GENESIS_BLOCK_HEADER_HASH, INITIAL_L2_BLOCK_NUM, INITIAL_L2_CHECKPOINT_NUM } from '@aztec/constants';
1
2
  import { BlockNumber } from '@aztec/foundation/branded-types';
2
- import type { Fr } from '@aztec/foundation/fields';
3
+ import type { Fr } from '@aztec/foundation/curves/bn254';
3
4
  import { type Logger, createLogger } from '@aztec/foundation/log';
4
5
  import { promiseWithResolvers } from '@aztec/foundation/promise';
5
6
  import { elapsed } from '@aztec/foundation/timer';
6
- import type {
7
- L2BlockId,
8
- L2BlockNew,
9
- L2BlockSource,
7
+ import {
8
+ GENESIS_CHECKPOINT_HEADER_HASH,
9
+ type L2Block,
10
+ type L2BlockId,
11
+ type L2BlockSource,
10
12
  L2BlockStream,
11
- L2BlockStreamEvent,
12
- L2BlockStreamEventHandler,
13
- L2BlockStreamLocalDataProvider,
14
- L2Tips,
13
+ type L2BlockStreamEvent,
14
+ type L2BlockStreamEventHandler,
15
+ type L2BlockStreamLocalDataProvider,
16
+ type L2Tips,
15
17
  } from '@aztec/stdlib/block';
16
18
  import {
17
19
  WorldStateRunningState,
@@ -23,14 +25,13 @@ import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
23
25
  import type { SnapshotDataKeys } from '@aztec/stdlib/snapshots';
24
26
  import type { L2BlockHandledStats } from '@aztec/stdlib/stats';
25
27
  import { MerkleTreeId, type MerkleTreeReadOperations, type MerkleTreeWriteOperations } from '@aztec/stdlib/trees';
26
- import { TraceableL2BlockStream, getTelemetryClient } from '@aztec/telemetry-client';
28
+ import { getTelemetryClient } from '@aztec/telemetry-client';
27
29
 
28
30
  import { WorldStateInstrumentation } from '../instrumentation/instrumentation.js';
29
31
  import type { WorldStateStatusFull } from '../native/message.js';
30
32
  import type { MerkleTreeAdminDatabase } from '../world-state-db/merkle_tree_db.js';
31
33
  import type { WorldStateConfig } from './config.js';
32
34
  import { WorldStateSynchronizerError } from './errors.js';
33
- import { findFirstBlocksInCheckpoints } from './utils.js';
34
35
 
35
36
  export type { SnapshotDataKeys };
36
37
 
@@ -47,7 +48,6 @@ export class ServerWorldStateSynchronizer
47
48
  private latestBlockNumberAtStart = BlockNumber.ZERO;
48
49
  private historyToKeep: number | undefined;
49
50
  private currentState: WorldStateRunningState = WorldStateRunningState.IDLE;
50
- private latestBlockHashQuery: { blockNumber: BlockNumber; hash: string | undefined } | undefined = undefined;
51
51
 
52
52
  private syncPromise = promiseWithResolvers<void>();
53
53
  protected blockStream: L2BlockStream | undefined;
@@ -80,8 +80,8 @@ export class ServerWorldStateSynchronizer
80
80
  return this.merkleTreeDb.getSnapshot(blockNumber);
81
81
  }
82
82
 
83
- public fork(blockNumber?: BlockNumber): Promise<MerkleTreeWriteOperations> {
84
- return this.merkleTreeDb.fork(blockNumber);
83
+ public fork(blockNumber?: BlockNumber, opts?: { closeDelayMs?: number }): Promise<MerkleTreeWriteOperations> {
84
+ return this.merkleTreeDb.fork(blockNumber, opts);
85
85
  }
86
86
 
87
87
  public backupTo(dstPath: string, compact?: boolean): Promise<Record<Exclude<SnapshotDataKeys, 'archiver'>, string>> {
@@ -101,11 +101,7 @@ export class ServerWorldStateSynchronizer
101
101
  }
102
102
 
103
103
  // Get the current latest block number
104
- this.latestBlockNumberAtStart = BlockNumber(
105
- await (this.config.worldStateProvenBlocksOnly
106
- ? this.l2BlockSource.getProvenBlockNumber()
107
- : this.l2BlockSource.getBlockNumber()),
108
- );
104
+ this.latestBlockNumberAtStart = BlockNumber(await this.l2BlockSource.getBlockNumber());
109
105
 
110
106
  const blockToDownloadFrom = (await this.getLatestBlockNumber()) + 1;
111
107
 
@@ -127,12 +123,11 @@ export class ServerWorldStateSynchronizer
127
123
  }
128
124
 
129
125
  protected createBlockStream(): L2BlockStream {
130
- const tracer = this.instrumentation.telemetry.getTracer('WorldStateL2BlockStream');
131
126
  const logger = createLogger('world-state:block_stream');
132
- return new TraceableL2BlockStream(this.l2BlockSource, this, this, tracer, 'WorldStateL2BlockStream', logger, {
133
- proven: this.config.worldStateProvenBlocksOnly,
127
+ return new L2BlockStream(this.l2BlockSource, this, this, logger, {
134
128
  pollIntervalMS: this.config.worldStateBlockCheckIntervalMS,
135
129
  batchSize: this.config.worldStateBlockRequestBatchSize,
130
+ ignoreCheckpoints: true,
136
131
  });
137
132
  }
138
133
 
@@ -161,7 +156,7 @@ export class ServerWorldStateSynchronizer
161
156
  }
162
157
 
163
158
  public async getLatestBlockNumber() {
164
- return (await this.getL2Tips()).latest.number;
159
+ return (await this.getL2Tips()).proposed.number;
165
160
  }
166
161
 
167
162
  public async stopSync() {
@@ -240,27 +235,44 @@ export class ServerWorldStateSynchronizer
240
235
  if (number === BlockNumber.ZERO) {
241
236
  return (await this.merkleTreeCommitted.getInitialHeader().hash()).toString();
242
237
  }
243
- if (this.latestBlockHashQuery?.hash === undefined || number !== this.latestBlockHashQuery.blockNumber) {
244
- this.latestBlockHashQuery = {
245
- hash: await this.merkleTreeCommitted
246
- .getLeafValue(MerkleTreeId.ARCHIVE, BigInt(number))
247
- .then(leaf => leaf?.toString()),
248
- blockNumber: number,
249
- };
250
- }
251
- return this.latestBlockHashQuery.hash;
238
+ return this.merkleTreeCommitted.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(number)).then(leaf => leaf?.toString());
252
239
  }
253
240
 
254
241
  /** Returns the latest L2 block number for each tip of the chain (latest, proven, finalized). */
255
242
  public async getL2Tips(): Promise<L2Tips> {
256
243
  const status = await this.merkleTreeDb.getStatusSummary();
257
- const unfinalizedBlockHash = await this.getL2BlockHash(status.unfinalizedBlockNumber);
244
+ const unfinalizedBlockHashPromise = this.getL2BlockHash(status.unfinalizedBlockNumber);
245
+ const finalizedBlockHashPromise = this.getL2BlockHash(status.finalizedBlockNumber);
246
+
247
+ const provenBlockNumber = this.provenBlockNumber ?? status.finalizedBlockNumber;
248
+ const provenBlockHashPromise =
249
+ this.provenBlockNumber === undefined ? finalizedBlockHashPromise : this.getL2BlockHash(this.provenBlockNumber);
250
+
251
+ const [unfinalizedBlockHash, finalizedBlockHash, provenBlockHash] = await Promise.all([
252
+ unfinalizedBlockHashPromise,
253
+ finalizedBlockHashPromise,
254
+ provenBlockHashPromise,
255
+ ]);
258
256
  const latestBlockId: L2BlockId = { number: status.unfinalizedBlockNumber, hash: unfinalizedBlockHash! };
259
257
 
258
+ // World state doesn't track checkpointed blocks or checkpoints themselves.
259
+ // but we use a block stream so we need to provide 'local' L2Tips.
260
+ // We configure the block stream to ignore checkpoints and set checkpoint values to genesis here.
261
+ const genesisCheckpointHeaderHash = GENESIS_CHECKPOINT_HEADER_HASH.toString();
260
262
  return {
261
- latest: latestBlockId,
262
- finalized: { number: status.finalizedBlockNumber, hash: '' },
263
- proven: { number: this.provenBlockNumber ?? status.finalizedBlockNumber, hash: '' }, // TODO(palla/reorg): Using finalized as proven for now
263
+ proposed: latestBlockId,
264
+ checkpointed: {
265
+ block: { number: INITIAL_L2_BLOCK_NUM, hash: GENESIS_BLOCK_HEADER_HASH.toString() },
266
+ checkpoint: { number: INITIAL_L2_CHECKPOINT_NUM, hash: genesisCheckpointHeaderHash },
267
+ },
268
+ finalized: {
269
+ block: { number: status.finalizedBlockNumber, hash: finalizedBlockHash ?? '' },
270
+ checkpoint: { number: INITIAL_L2_CHECKPOINT_NUM, hash: genesisCheckpointHeaderHash },
271
+ },
272
+ proven: {
273
+ block: { number: provenBlockNumber, hash: provenBlockHash ?? '' },
274
+ checkpoint: { number: INITIAL_L2_CHECKPOINT_NUM, hash: genesisCheckpointHeaderHash },
275
+ },
264
276
  };
265
277
  }
266
278
 
@@ -268,16 +280,16 @@ export class ServerWorldStateSynchronizer
268
280
  public async handleBlockStreamEvent(event: L2BlockStreamEvent): Promise<void> {
269
281
  switch (event.type) {
270
282
  case 'blocks-added':
271
- await this.handleL2Blocks(event.blocks.map(b => b.block.toL2Block()));
283
+ await this.handleL2Blocks(event.blocks);
272
284
  break;
273
285
  case 'chain-pruned':
274
- await this.handleChainPruned(BlockNumber(event.block.number));
286
+ await this.handleChainPruned(event.block.number);
275
287
  break;
276
288
  case 'chain-proven':
277
- await this.handleChainProven(BlockNumber(event.block.number));
289
+ await this.handleChainProven(event.block.number);
278
290
  break;
279
291
  case 'chain-finalized':
280
- await this.handleChainFinalized(BlockNumber(event.block.number));
292
+ await this.handleChainFinalized(event.block.number);
281
293
  break;
282
294
  }
283
295
  }
@@ -287,16 +299,25 @@ export class ServerWorldStateSynchronizer
287
299
  * @param l2Blocks - The L2 blocks to handle.
288
300
  * @returns Whether the block handled was produced by this same node.
289
301
  */
290
- private async handleL2Blocks(l2Blocks: L2BlockNew[]) {
302
+ private async handleL2Blocks(l2Blocks: L2Block[]) {
291
303
  this.log.trace(`Handling L2 blocks ${l2Blocks[0].number} to ${l2Blocks.at(-1)!.number}`);
292
304
 
293
- const firstBlocksInCheckpoints = await findFirstBlocksInCheckpoints(l2Blocks, this.l2BlockSource);
305
+ // Fetch the L1->L2 messages for the first block in a checkpoint.
306
+ const messagesForBlocks = new Map<BlockNumber, Fr[]>();
307
+ await Promise.all(
308
+ l2Blocks
309
+ .filter(b => b.indexWithinCheckpoint === 0)
310
+ .map(async block => {
311
+ const l1ToL2Messages = await this.l2BlockSource.getL1ToL2Messages(block.checkpointNumber);
312
+ messagesForBlocks.set(block.number, l1ToL2Messages);
313
+ }),
314
+ );
294
315
 
295
316
  let updateStatus: WorldStateStatusFull | undefined = undefined;
296
317
  for (const block of l2Blocks) {
297
- const l1ToL2Messages = firstBlocksInCheckpoints.get(block.number) ?? [];
298
- const isFirstBlock = firstBlocksInCheckpoints.has(block.number);
299
- const [duration, result] = await elapsed(() => this.handleL2Block(block, l1ToL2Messages, isFirstBlock));
318
+ const [duration, result] = await elapsed(() =>
319
+ this.handleL2Block(block, messagesForBlocks.get(block.number) ?? []),
320
+ );
300
321
  this.log.info(`World state updated with L2 block ${block.number}`, {
301
322
  eventName: 'l2-block-handled',
302
323
  duration,
@@ -319,18 +340,13 @@ export class ServerWorldStateSynchronizer
319
340
  * @param l1ToL2Messages - The L1 to L2 messages for the block.
320
341
  * @returns Whether the block handled was produced by this same node.
321
342
  */
322
- private async handleL2Block(
323
- l2Block: L2BlockNew,
324
- l1ToL2Messages: Fr[],
325
- isFirstBlock: boolean,
326
- ): Promise<WorldStateStatusFull> {
327
- // If the above check succeeds, we can proceed to handle the block.
343
+ private async handleL2Block(l2Block: L2Block, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull> {
328
344
  this.log.trace(`Pushing L2 block ${l2Block.number} to merkle tree db `, {
329
345
  blockNumber: l2Block.number,
330
346
  blockHash: await l2Block.hash().then(h => h.toString()),
331
347
  l1ToL2Messages: l1ToL2Messages.map(msg => msg.toString()),
332
348
  });
333
- const result = await this.merkleTreeDb.handleL2BlockAndMessages(l2Block, l1ToL2Messages, isFirstBlock);
349
+ const result = await this.merkleTreeDb.handleL2BlockAndMessages(l2Block, l1ToL2Messages);
334
350
 
335
351
  if (this.currentState === WorldStateRunningState.SYNCHING && l2Block.number >= this.latestBlockNumberAtStart) {
336
352
  this.setCurrentState(WorldStateRunningState.RUNNING);
@@ -346,12 +362,12 @@ export class ServerWorldStateSynchronizer
346
362
  if (this.historyToKeep === undefined) {
347
363
  return;
348
364
  }
349
- const newHistoricBlock = BlockNumber(summary.finalizedBlockNumber - this.historyToKeep + 1);
350
- if (newHistoricBlock <= BlockNumber(1)) {
365
+ const newHistoricBlock = summary.finalizedBlockNumber - this.historyToKeep + 1;
366
+ if (newHistoricBlock <= 1) {
351
367
  return;
352
368
  }
353
369
  this.log.verbose(`Pruning historic blocks to ${newHistoricBlock}`);
354
- const status = await this.merkleTreeDb.removeHistoricalBlocks(newHistoricBlock);
370
+ const status = await this.merkleTreeDb.removeHistoricalBlocks(BlockNumber(newHistoricBlock));
355
371
  this.log.debug(`World state summary `, status.summary);
356
372
  }
357
373
 
@@ -364,7 +380,6 @@ export class ServerWorldStateSynchronizer
364
380
  private async handleChainPruned(blockNumber: BlockNumber) {
365
381
  this.log.warn(`Chain pruned to block ${blockNumber}`);
366
382
  const status = await this.merkleTreeDb.unwindBlocks(blockNumber);
367
- this.latestBlockHashQuery = undefined;
368
383
  this.provenBlockNumber = undefined;
369
384
  this.instrumentation.updateWorldStateMetrics(status);
370
385
  }