@aztec/world-state 0.0.1-commit.3469e52 → 0.0.1-commit.381b1a9

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 (43) 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 +9 -2
  4. package/dest/native/fork_checkpoint.d.ts +7 -1
  5. package/dest/native/fork_checkpoint.d.ts.map +1 -1
  6. package/dest/native/fork_checkpoint.js +15 -3
  7. package/dest/native/merkle_trees_facade.d.ts +5 -5
  8. package/dest/native/merkle_trees_facade.d.ts.map +1 -1
  9. package/dest/native/merkle_trees_facade.js +9 -6
  10. package/dest/native/message.d.ts +14 -5
  11. package/dest/native/message.d.ts.map +1 -1
  12. package/dest/native/native_world_state.d.ts +7 -7
  13. package/dest/native/native_world_state.d.ts.map +1 -1
  14. package/dest/native/native_world_state.js +9 -8
  15. package/dest/native/native_world_state_instance.d.ts +3 -3
  16. package/dest/native/native_world_state_instance.d.ts.map +1 -1
  17. package/dest/native/native_world_state_instance.js +4 -4
  18. package/dest/synchronizer/config.d.ts +3 -5
  19. package/dest/synchronizer/config.d.ts.map +1 -1
  20. package/dest/synchronizer/config.js +7 -9
  21. package/dest/synchronizer/factory.d.ts +4 -3
  22. package/dest/synchronizer/factory.d.ts.map +1 -1
  23. package/dest/synchronizer/factory.js +5 -5
  24. package/dest/synchronizer/server_world_state_synchronizer.d.ts +1 -1
  25. package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
  26. package/dest/synchronizer/server_world_state_synchronizer.js +57 -17
  27. package/dest/test/utils.d.ts +6 -6
  28. package/dest/test/utils.d.ts.map +1 -1
  29. package/dest/test/utils.js +3 -3
  30. package/dest/world-state-db/merkle_tree_db.d.ts +3 -3
  31. package/dest/world-state-db/merkle_tree_db.d.ts.map +1 -1
  32. package/package.json +10 -10
  33. package/src/instrumentation/instrumentation.ts +9 -1
  34. package/src/native/fork_checkpoint.ts +19 -3
  35. package/src/native/merkle_trees_facade.ts +14 -7
  36. package/src/native/message.ts +15 -4
  37. package/src/native/native_world_state.ts +22 -10
  38. package/src/native/native_world_state_instance.ts +6 -4
  39. package/src/synchronizer/config.ts +8 -19
  40. package/src/synchronizer/factory.ts +7 -1
  41. package/src/synchronizer/server_world_state_synchronizer.ts +68 -23
  42. package/src/test/utils.ts +4 -4
  43. package/src/world-state-db/merkle_tree_db.ts +2 -2
@@ -1,6 +1,7 @@
1
1
  import { BlockNumber } from '@aztec/foundation/branded-types';
2
2
  import { Fr } from '@aztec/foundation/curves/bn254';
3
3
  import type { Tuple } from '@aztec/foundation/serialize';
4
+ import type { BlockHash } from '@aztec/stdlib/block';
4
5
  import { AppendOnlyTreeSnapshot, MerkleTreeId } from '@aztec/stdlib/trees';
5
6
  import type { StateReference } from '@aztec/stdlib/tx';
6
7
  import type { UInt32 } from '@aztec/stdlib/types';
@@ -283,6 +284,16 @@ interface WithForkId {
283
284
  forkId: number;
284
285
  }
285
286
 
287
+ interface CreateCheckpointResponse {
288
+ depth: number;
289
+ }
290
+
291
+ /** Request to commit/revert all checkpoints down to a target depth. The resulting depth after the operation equals the given depth. */
292
+ interface CheckpointDepthRequest extends WithForkId {
293
+ /** The target depth after the operation. All checkpoints above this depth are committed/reverted. */
294
+ depth: number;
295
+ }
296
+
286
297
  interface WithWorldStateRevision {
287
298
  revision: WorldStateRevision;
288
299
  }
@@ -412,7 +423,7 @@ interface UpdateArchiveRequest extends WithForkId {
412
423
  interface SyncBlockRequest extends WithCanonicalForkId {
413
424
  blockNumber: BlockNumber;
414
425
  blockStateRef: BlockStateReference;
415
- blockHeaderHash: Fr;
426
+ blockHeaderHash: BlockHash;
416
427
  paddedNoteHashes: readonly SerializedLeafValue[];
417
428
  paddedL1ToL2Messages: readonly SerializedLeafValue[];
418
429
  paddedNullifiers: readonly SerializedLeafValue[];
@@ -486,8 +497,8 @@ export type WorldStateRequest = {
486
497
  [WorldStateMessageType.CREATE_CHECKPOINT]: WithForkId;
487
498
  [WorldStateMessageType.COMMIT_CHECKPOINT]: WithForkId;
488
499
  [WorldStateMessageType.REVERT_CHECKPOINT]: WithForkId;
489
- [WorldStateMessageType.COMMIT_ALL_CHECKPOINTS]: WithForkId;
490
- [WorldStateMessageType.REVERT_ALL_CHECKPOINTS]: WithForkId;
500
+ [WorldStateMessageType.COMMIT_ALL_CHECKPOINTS]: CheckpointDepthRequest;
501
+ [WorldStateMessageType.REVERT_ALL_CHECKPOINTS]: CheckpointDepthRequest;
491
502
 
492
503
  [WorldStateMessageType.COPY_STORES]: CopyStoresRequest;
493
504
 
@@ -528,7 +539,7 @@ export type WorldStateResponse = {
528
539
 
529
540
  [WorldStateMessageType.GET_STATUS]: WorldStateStatusSummary;
530
541
 
531
- [WorldStateMessageType.CREATE_CHECKPOINT]: void;
542
+ [WorldStateMessageType.CREATE_CHECKPOINT]: CreateCheckpointResponse;
532
543
  [WorldStateMessageType.COMMIT_CHECKPOINT]: void;
533
544
  [WorldStateMessageType.REVERT_CHECKPOINT]: void;
534
545
  [WorldStateMessageType.COMMIT_ALL_CHECKPOINTS]: void;
@@ -4,9 +4,9 @@ import { fromEntries, padArrayEnd } from '@aztec/foundation/collection';
4
4
  import { Fr } from '@aztec/foundation/curves/bn254';
5
5
  import { EthAddress } from '@aztec/foundation/eth-address';
6
6
  import { tryRmDir } from '@aztec/foundation/fs';
7
- import { type Logger, createLogger } from '@aztec/foundation/log';
8
- import type { L2BlockNew } from '@aztec/stdlib/block';
9
- import { DatabaseVersionManager } from '@aztec/stdlib/database-version';
7
+ import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
8
+ import type { L2Block } from '@aztec/stdlib/block';
9
+ import { DatabaseVersionManager } from '@aztec/stdlib/database-version/manager';
10
10
  import type {
11
11
  IndexedTreeId,
12
12
  MerkleTreeReadOperations,
@@ -52,7 +52,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
52
52
  protected constructor(
53
53
  protected instance: NativeWorldState,
54
54
  protected readonly worldStateInstrumentation: WorldStateInstrumentation,
55
- protected readonly log: Logger = createLogger('world-state:database'),
55
+ protected readonly log: Logger,
56
56
  private readonly cleanup = () => Promise.resolve(),
57
57
  ) {}
58
58
 
@@ -62,9 +62,10 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
62
62
  wsTreeMapSizes: WorldStateTreeMapSizes,
63
63
  prefilledPublicData: PublicDataTreeLeaf[] = [],
64
64
  instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
65
- log = createLogger('world-state:database'),
65
+ bindings?: LoggerBindings,
66
66
  cleanup = () => Promise.resolve(),
67
67
  ): Promise<NativeWorldStateService> {
68
+ const log = createLogger('world-state:database', bindings);
68
69
  const worldStateDirectory = join(dataDir, WORLD_STATE_DIR);
69
70
  // Create a version manager to handle versioning
70
71
  const versionManager = new DatabaseVersionManager({
@@ -72,7 +73,9 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
72
73
  rollupAddress,
73
74
  dataDirectory: worldStateDirectory,
74
75
  onOpen: (dir: string) => {
75
- return Promise.resolve(new NativeWorldState(dir, wsTreeMapSizes, prefilledPublicData, instrumentation));
76
+ return Promise.resolve(
77
+ new NativeWorldState(dir, wsTreeMapSizes, prefilledPublicData, instrumentation, bindings),
78
+ );
76
79
  },
77
80
  });
78
81
 
@@ -93,8 +96,9 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
93
96
  cleanupTmpDir = true,
94
97
  prefilledPublicData: PublicDataTreeLeaf[] = [],
95
98
  instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
99
+ bindings?: LoggerBindings,
96
100
  ): Promise<NativeWorldStateService> {
97
- const log = createLogger('world-state:database');
101
+ const log = createLogger('world-state:database', bindings);
98
102
  const dataDir = await mkdtemp(join(tmpdir(), 'aztec-world-state-'));
99
103
  const dbMapSizeKb = 10 * 1024 * 1024;
100
104
  const worldStateTreeMapSizes: WorldStateTreeMapSizes = {
@@ -116,7 +120,15 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
116
120
  }
117
121
  };
118
122
 
119
- return this.new(rollupAddress, dataDir, worldStateTreeMapSizes, prefilledPublicData, instrumentation, log, cleanup);
123
+ return this.new(
124
+ rollupAddress,
125
+ dataDir,
126
+ worldStateTreeMapSizes,
127
+ prefilledPublicData,
128
+ instrumentation,
129
+ bindings,
130
+ cleanup,
131
+ );
120
132
  }
121
133
 
122
134
  protected async init() {
@@ -135,7 +147,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
135
147
 
136
148
  // the initial header _must_ be the first element in the archive tree
137
149
  // if this assertion fails, check that the hashing done in Header in yarn-project matches the initial header hash done in world_state.cpp
138
- const indices = await committed.findLeafIndices(MerkleTreeId.ARCHIVE, [await this.initialHeader.hash()]);
150
+ const indices = await committed.findLeafIndices(MerkleTreeId.ARCHIVE, [(await this.initialHeader.hash()).toFr()]);
139
151
  const initialHeaderIndex = indices[0];
140
152
  assert.strictEqual(initialHeaderIndex, 0n, 'Invalid initial archive state');
141
153
  }
@@ -184,7 +196,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
184
196
  return this.initialHeader!;
185
197
  }
186
198
 
187
- public async handleL2BlockAndMessages(l2Block: L2BlockNew, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull> {
199
+ public async handleL2BlockAndMessages(l2Block: L2Block, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull> {
188
200
  const isFirstBlock = l2Block.indexWithinCheckpoint === 0;
189
201
  if (!isFirstBlock && l1ToL2Messages.length > 0) {
190
202
  throw new Error(
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ARCHIVE_HEIGHT,
3
- GeneratorIndex,
3
+ DomainSeparator,
4
4
  L1_TO_L2_MSG_TREE_HEIGHT,
5
5
  MAX_NULLIFIERS_PER_TX,
6
6
  MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
@@ -8,7 +8,7 @@ import {
8
8
  NULLIFIER_TREE_HEIGHT,
9
9
  PUBLIC_DATA_TREE_HEIGHT,
10
10
  } from '@aztec/constants';
11
- import { type Logger, createLogger } from '@aztec/foundation/log';
11
+ import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
12
12
  import { NativeWorldState as BaseNativeWorldState, MsgpackChannel } from '@aztec/native';
13
13
  import { MerkleTreeId } from '@aztec/stdlib/trees';
14
14
  import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
@@ -57,7 +57,8 @@ export class NativeWorldState implements NativeWorldStateInstance {
57
57
  private readonly wsTreeMapSizes: WorldStateTreeMapSizes,
58
58
  private readonly prefilledPublicData: PublicDataTreeLeaf[] = [],
59
59
  private readonly instrumentation: WorldStateInstrumentation,
60
- private readonly log: Logger = createLogger('world-state:database'),
60
+ bindings?: LoggerBindings,
61
+ private readonly log: Logger = createLogger('world-state:database', bindings),
61
62
  ) {
62
63
  const threads = Math.min(cpus().length, MAX_WORLD_STATE_THREADS);
63
64
  log.info(
@@ -80,7 +81,7 @@ export class NativeWorldState implements NativeWorldStateInstance {
80
81
  [MerkleTreeId.PUBLIC_DATA_TREE]: 2 * MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
81
82
  },
82
83
  prefilledPublicDataBufferArray,
83
- GeneratorIndex.BLOCK_HASH,
84
+ DomainSeparator.BLOCK_HEADER_HASH,
84
85
  {
85
86
  [MerkleTreeId.NULLIFIER_TREE]: wsTreeMapSizes.nullifierTreeMapSizeKb,
86
87
  [MerkleTreeId.NOTE_HASH_TREE]: wsTreeMapSizes.noteHashTreeMapSizeKb,
@@ -105,6 +106,7 @@ export class NativeWorldState implements NativeWorldStateInstance {
105
106
  this.wsTreeMapSizes,
106
107
  this.prefilledPublicData,
107
108
  this.instrumentation,
109
+ this.log.getBindings(),
108
110
  this.log,
109
111
  );
110
112
  }
@@ -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
 
@@ -37,8 +29,8 @@ export interface WorldStateConfig {
37
29
  /** Optional directory for the world state DB, if unspecified will default to the general data directory */
38
30
  worldStateDataDirectory?: string;
39
31
 
40
- /** The number of historic blocks to maintain */
41
- worldStateBlockHistory: number;
32
+ /** The number of historic checkpoints worth of blocks to maintain */
33
+ worldStateCheckpointHistory: number;
42
34
  }
43
35
 
44
36
  export const worldStateConfigMappings: ConfigMappingsType<WorldStateConfig> = {
@@ -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),
@@ -97,9 +84,11 @@ export const worldStateConfigMappings: ConfigMappingsType<WorldStateConfig> = {
97
84
  env: 'WS_DATA_DIRECTORY',
98
85
  description: 'Optional directory for the world state database',
99
86
  },
100
- worldStateBlockHistory: {
101
- env: 'WS_NUM_HISTORIC_BLOCKS',
102
- description: 'The number of historic blocks to maintain. Values less than 1 mean all history is maintained',
87
+ worldStateCheckpointHistory: {
88
+ env: 'WS_NUM_HISTORIC_CHECKPOINTS',
89
+ description:
90
+ 'The number of historic checkpoints worth of blocks to maintain. Values less than 1 mean all history is maintained',
91
+ fallback: ['WS_NUM_HISTORIC_BLOCKS'],
103
92
  ...numberConfigHelper(64),
104
93
  },
105
94
  };
@@ -1,3 +1,4 @@
1
+ import type { LoggerBindings } from '@aztec/foundation/log';
1
2
  import type { DataStoreConfig } from '@aztec/kv-store/config';
2
3
  import type { L2BlockSource } from '@aztec/stdlib/block';
3
4
  import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
@@ -22,9 +23,10 @@ export async function createWorldStateSynchronizer(
22
23
  l2BlockSource: L2BlockSource & L1ToL2MessageSource,
23
24
  prefilledPublicData: PublicDataTreeLeaf[] = [],
24
25
  client: TelemetryClient = getTelemetryClient(),
26
+ bindings?: LoggerBindings,
25
27
  ) {
26
28
  const instrumentation = new WorldStateInstrumentation(client);
27
- const merkleTrees = await createWorldState(config, prefilledPublicData, instrumentation);
29
+ const merkleTrees = await createWorldState(config, prefilledPublicData, instrumentation, bindings);
28
30
  return new ServerWorldStateSynchronizer(merkleTrees, l2BlockSource, config, instrumentation);
29
31
  }
30
32
 
@@ -42,6 +44,7 @@ export async function createWorldState(
42
44
  Pick<DataStoreConfig, 'dataDirectory' | 'dataStoreMapSizeKb' | 'l1Contracts'>,
43
45
  prefilledPublicData: PublicDataTreeLeaf[] = [],
44
46
  instrumentation: WorldStateInstrumentation = new WorldStateInstrumentation(getTelemetryClient()),
47
+ bindings?: LoggerBindings,
45
48
  ) {
46
49
  const dataDirectory = config.worldStateDataDirectory ?? config.dataDirectory;
47
50
  const dataStoreMapSizeKb = config.worldStateDbMapSizeKb ?? config.dataStoreMapSizeKb;
@@ -65,11 +68,14 @@ export async function createWorldState(
65
68
  wsTreeMapSizes,
66
69
  prefilledPublicData,
67
70
  instrumentation,
71
+ bindings,
68
72
  )
69
73
  : await NativeWorldStateService.tmp(
70
74
  config.l1Contracts.rollupAddress,
71
75
  !['true', '1'].includes(process.env.DEBUG_WORLD_STATE!),
72
76
  prefilledPublicData,
77
+ instrumentation,
78
+ bindings,
73
79
  );
74
80
 
75
81
  return merkleTrees;
@@ -1,13 +1,13 @@
1
- import { GENESIS_BLOCK_HEADER_HASH, INITIAL_L2_BLOCK_NUM, INITIAL_L2_CHECKPOINT_NUM } from '@aztec/constants';
2
- import { BlockNumber } from '@aztec/foundation/branded-types';
1
+ import { GENESIS_BLOCK_HEADER_HASH, INITIAL_CHECKPOINT_NUMBER, INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
2
+ import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
3
3
  import type { Fr } from '@aztec/foundation/curves/bn254';
4
4
  import { type Logger, createLogger } from '@aztec/foundation/log';
5
5
  import { promiseWithResolvers } from '@aztec/foundation/promise';
6
6
  import { elapsed } from '@aztec/foundation/timer';
7
7
  import {
8
8
  GENESIS_CHECKPOINT_HEADER_HASH,
9
+ type L2Block,
9
10
  type L2BlockId,
10
- type L2BlockNew,
11
11
  type L2BlockSource,
12
12
  L2BlockStream,
13
13
  type L2BlockStreamEvent,
@@ -64,7 +64,7 @@ export class ServerWorldStateSynchronizer
64
64
  private readonly log: Logger = createLogger('world_state'),
65
65
  ) {
66
66
  this.merkleTreeCommitted = this.merkleTreeDb.getCommitted();
67
- this.historyToKeep = config.worldStateBlockHistory < 1 ? undefined : config.worldStateBlockHistory;
67
+ this.historyToKeep = config.worldStateCheckpointHistory < 1 ? undefined : config.worldStateCheckpointHistory;
68
68
  this.log.info(
69
69
  `Created world state synchroniser with block history of ${
70
70
  this.historyToKeep === undefined ? 'infinity' : this.historyToKeep
@@ -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
 
@@ -129,7 +125,6 @@ export class ServerWorldStateSynchronizer
129
125
  protected createBlockStream(): L2BlockStream {
130
126
  const logger = createLogger('world-state:block_stream');
131
127
  return new L2BlockStream(this.l2BlockSource, this, this, logger, {
132
- proven: this.config.worldStateProvenBlocksOnly,
133
128
  pollIntervalMS: this.config.worldStateBlockCheckIntervalMS,
134
129
  batchSize: this.config.worldStateBlockRequestBatchSize,
135
130
  ignoreCheckpoints: true,
@@ -268,15 +263,15 @@ export class ServerWorldStateSynchronizer
268
263
  proposed: latestBlockId,
269
264
  checkpointed: {
270
265
  block: { number: INITIAL_L2_BLOCK_NUM, hash: GENESIS_BLOCK_HEADER_HASH.toString() },
271
- checkpoint: { number: INITIAL_L2_CHECKPOINT_NUM, hash: genesisCheckpointHeaderHash },
266
+ checkpoint: { number: INITIAL_CHECKPOINT_NUMBER, hash: genesisCheckpointHeaderHash },
272
267
  },
273
268
  finalized: {
274
269
  block: { number: status.finalizedBlockNumber, hash: finalizedBlockHash ?? '' },
275
- checkpoint: { number: INITIAL_L2_CHECKPOINT_NUM, hash: genesisCheckpointHeaderHash },
270
+ checkpoint: { number: INITIAL_CHECKPOINT_NUMBER, hash: genesisCheckpointHeaderHash },
276
271
  },
277
272
  proven: {
278
273
  block: { number: provenBlockNumber, hash: provenBlockHash ?? '' },
279
- checkpoint: { number: INITIAL_L2_CHECKPOINT_NUM, hash: genesisCheckpointHeaderHash },
274
+ checkpoint: { number: INITIAL_CHECKPOINT_NUMBER, hash: genesisCheckpointHeaderHash },
280
275
  },
281
276
  };
282
277
  }
@@ -304,8 +299,8 @@ export class ServerWorldStateSynchronizer
304
299
  * @param l2Blocks - The L2 blocks to handle.
305
300
  * @returns Whether the block handled was produced by this same node.
306
301
  */
307
- private async handleL2Blocks(l2Blocks: L2BlockNew[]) {
308
- this.log.trace(`Handling L2 blocks ${l2Blocks[0].number} to ${l2Blocks.at(-1)!.number}`);
302
+ private async handleL2Blocks(l2Blocks: L2Block[]) {
303
+ this.log.debug(`Handling L2 blocks ${l2Blocks[0].number} to ${l2Blocks.at(-1)!.number}`);
309
304
 
310
305
  // Fetch the L1->L2 messages for the first block in a checkpoint.
311
306
  const messagesForBlocks = new Map<BlockNumber, Fr[]>();
@@ -345,11 +340,13 @@ export class ServerWorldStateSynchronizer
345
340
  * @param l1ToL2Messages - The L1 to L2 messages for the block.
346
341
  * @returns Whether the block handled was produced by this same node.
347
342
  */
348
- private async handleL2Block(l2Block: L2BlockNew, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull> {
349
- this.log.trace(`Pushing L2 block ${l2Block.number} to merkle tree db `, {
343
+ private async handleL2Block(l2Block: L2Block, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull> {
344
+ this.log.debug(`Pushing L2 block ${l2Block.number} to merkle tree db `, {
350
345
  blockNumber: l2Block.number,
351
346
  blockHash: await l2Block.hash().then(h => h.toString()),
352
347
  l1ToL2Messages: l1ToL2Messages.map(msg => msg.toString()),
348
+ blockHeader: l2Block.header.toInspect(),
349
+ blockStats: l2Block.getStats(),
353
350
  });
354
351
  const result = await this.merkleTreeDb.handleL2BlockAndMessages(l2Block, l1ToL2Messages);
355
352
 
@@ -362,17 +359,65 @@ export class ServerWorldStateSynchronizer
362
359
  }
363
360
 
364
361
  private async handleChainFinalized(blockNumber: BlockNumber) {
365
- this.log.verbose(`Finalized chain is now at block ${blockNumber}`);
362
+ this.log.info(`Updating world state finalized chain to block ${blockNumber}`);
363
+ // If the finalized block number is older than the oldest available block in world state,
364
+ // skip entirely. The finalized block number can jump backwards (e.g. when the finalization
365
+ // heuristic changes) and try to read block data that has already been pruned. When this
366
+ // happens, there is nothing useful to do — the native world state is already finalized
367
+ // past this point and pruning has already happened.
368
+ const currentSummary = await this.merkleTreeDb.getStatusSummary();
369
+ if (blockNumber < currentSummary.oldestHistoricalBlock || blockNumber < 1) {
370
+ this.log.trace(
371
+ `Finalized block ${blockNumber} is older than the oldest available block ${currentSummary.oldestHistoricalBlock}. Skipping.`,
372
+ );
373
+ return;
374
+ }
366
375
  const summary = await this.merkleTreeDb.setFinalized(blockNumber);
376
+ this.log.info(`World state finalized chain updated`, {
377
+ finalizedBlockNumber: summary.finalizedBlockNumber,
378
+ unfinalizedBlockNumber: summary.unfinalizedBlockNumber,
379
+ oldestHistoricalBlock: summary.oldestHistoricalBlock,
380
+ });
367
381
  if (this.historyToKeep === undefined) {
368
382
  return;
369
383
  }
370
- const newHistoricBlock = summary.finalizedBlockNumber - this.historyToKeep + 1;
371
- if (newHistoricBlock <= 1) {
384
+ // Get the checkpointed block for the finalized block number
385
+ const finalisedCheckpoint = await this.l2BlockSource.getCheckpointedBlock(summary.finalizedBlockNumber);
386
+ if (finalisedCheckpoint === undefined) {
387
+ this.log.warn(
388
+ `Failed to retrieve checkpointed block for finalized block number: ${summary.finalizedBlockNumber}`,
389
+ );
390
+ return;
391
+ }
392
+ // Compute the required historic checkpoint number
393
+ const newHistoricCheckpointNumber = finalisedCheckpoint.checkpointNumber - this.historyToKeep + 1;
394
+ if (newHistoricCheckpointNumber <= 1) {
395
+ return;
396
+ }
397
+ // Retrieve the historic checkpoint
398
+ const historicCheckpoints = await this.l2BlockSource.getCheckpoints(
399
+ CheckpointNumber(newHistoricCheckpointNumber),
400
+ 1,
401
+ );
402
+ if (historicCheckpoints.length === 0 || historicCheckpoints[0] === undefined) {
403
+ this.log.warn(`Failed to retrieve checkpoint number ${newHistoricCheckpointNumber} from Archiver`);
404
+ return;
405
+ }
406
+ const historicCheckpoint = historicCheckpoints[0];
407
+ if (historicCheckpoint.checkpoint.blocks.length === 0 || historicCheckpoint.checkpoint.blocks[0] === undefined) {
408
+ this.log.warn(`Retrieved checkpoint number ${newHistoricCheckpointNumber} has no blocks!`);
409
+ return;
410
+ }
411
+ // Find the block at the start of the checkpoint and remove blocks up to this one
412
+ const newHistoricBlock = historicCheckpoint.checkpoint.blocks[0];
413
+ if (newHistoricBlock.number <= currentSummary.oldestHistoricalBlock) {
414
+ this.log.debug(
415
+ `Historic block ${newHistoricBlock.number} is not newer than oldest available ${currentSummary.oldestHistoricalBlock}. Skipping prune.`,
416
+ );
372
417
  return;
373
418
  }
374
- this.log.verbose(`Pruning historic blocks to ${newHistoricBlock}`);
375
- const status = await this.merkleTreeDb.removeHistoricalBlocks(BlockNumber(newHistoricBlock));
419
+ this.log.verbose(`Pruning historic blocks to ${newHistoricBlock.number}`);
420
+ const status = await this.merkleTreeDb.removeHistoricalBlocks(BlockNumber(newHistoricBlock.number));
376
421
  this.log.debug(`World state summary `, status.summary);
377
422
  }
378
423
 
@@ -383,7 +428,7 @@ export class ServerWorldStateSynchronizer
383
428
  }
384
429
 
385
430
  private async handleChainPruned(blockNumber: BlockNumber) {
386
- this.log.warn(`Chain pruned to block ${blockNumber}`);
431
+ this.log.info(`Chain pruned to block ${blockNumber}`);
387
432
  const status = await this.merkleTreeDb.unwindBlocks(blockNumber);
388
433
  this.provenBlockNumber = undefined;
389
434
  this.instrumentation.updateWorldStateMetrics(status);
package/src/test/utils.ts CHANGED
@@ -8,7 +8,7 @@ import { asyncMap } from '@aztec/foundation/async-map';
8
8
  import { BlockNumber, type CheckpointNumber, IndexWithinCheckpoint } from '@aztec/foundation/branded-types';
9
9
  import { padArrayEnd } from '@aztec/foundation/collection';
10
10
  import { Fr } from '@aztec/foundation/curves/bn254';
11
- import { L2BlockNew } from '@aztec/stdlib/block';
11
+ import { L2Block } from '@aztec/stdlib/block';
12
12
  import type {
13
13
  IndexedTreeId,
14
14
  MerkleTreeReadOperations,
@@ -20,7 +20,7 @@ import { BlockHeader } from '@aztec/stdlib/tx';
20
20
 
21
21
  import type { NativeWorldStateService } from '../native/native_world_state.js';
22
22
 
23
- export async function updateBlockState(block: L2BlockNew, l1ToL2Messages: Fr[], fork: MerkleTreeWriteOperations) {
23
+ export async function updateBlockState(block: L2Block, l1ToL2Messages: Fr[], fork: MerkleTreeWriteOperations) {
24
24
  const insertData = async (
25
25
  treeId: IndexedTreeId,
26
26
  data: Buffer[][],
@@ -76,7 +76,7 @@ export async function mockBlock(
76
76
  numL1ToL2Messages: number = NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
77
77
  isFirstBlockInCheckpoint: boolean = true,
78
78
  ) {
79
- const block = await L2BlockNew.random(blockNum, {
79
+ const block = await L2Block.random(blockNum, {
80
80
  indexWithinCheckpoint: isFirstBlockInCheckpoint ? IndexWithinCheckpoint(0) : IndexWithinCheckpoint(1),
81
81
  txsPerBlock: size,
82
82
  txOptions: { maxEffects },
@@ -92,7 +92,7 @@ export async function mockBlock(
92
92
  }
93
93
 
94
94
  export async function mockEmptyBlock(blockNum: BlockNumber, fork: MerkleTreeWriteOperations) {
95
- const l2Block = L2BlockNew.empty();
95
+ const l2Block = L2Block.empty();
96
96
  const l1ToL2Messages = Array(16).fill(0).map(Fr.zero);
97
97
 
98
98
  l2Block.header.globalVariables.blockNumber = blockNum;
@@ -2,7 +2,7 @@ import { MAX_NULLIFIERS_PER_TX, MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX } f
2
2
  import type { BlockNumber } from '@aztec/foundation/branded-types';
3
3
  import type { Fr } from '@aztec/foundation/curves/bn254';
4
4
  import type { IndexedTreeSnapshot, TreeSnapshot } from '@aztec/merkle-tree';
5
- import type { L2BlockNew } from '@aztec/stdlib/block';
5
+ import type { L2Block } from '@aztec/stdlib/block';
6
6
  import type {
7
7
  ForkMerkleTreeOperations,
8
8
  MerkleTreeReadOperations,
@@ -45,7 +45,7 @@ export interface MerkleTreeAdminDatabase extends ForkMerkleTreeOperations, Reado
45
45
  * @param block - The L2 block to handle.
46
46
  * @param l1ToL2Messages - The L1 to L2 messages for the block.
47
47
  */
48
- handleL2BlockAndMessages(block: L2BlockNew, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull>;
48
+ handleL2BlockAndMessages(block: L2Block, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull>;
49
49
 
50
50
  /**
51
51
  * Gets a handle that allows reading the latest committed state