@aztec/world-state 0.0.1-commit.7d4e6cd → 0.0.1-commit.8227e42

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 (39) 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/merkle_trees_facade.d.ts +2 -2
  5. package/dest/native/merkle_trees_facade.d.ts.map +1 -1
  6. package/dest/native/merkle_trees_facade.js +13 -4
  7. package/dest/native/message.d.ts +3 -2
  8. package/dest/native/message.d.ts.map +1 -1
  9. package/dest/native/native_world_state.d.ts +7 -7
  10. package/dest/native/native_world_state.d.ts.map +1 -1
  11. package/dest/native/native_world_state.js +9 -8
  12. package/dest/native/native_world_state_instance.d.ts +3 -3
  13. package/dest/native/native_world_state_instance.d.ts.map +1 -1
  14. package/dest/native/native_world_state_instance.js +4 -4
  15. package/dest/synchronizer/config.d.ts +3 -5
  16. package/dest/synchronizer/config.d.ts.map +1 -1
  17. package/dest/synchronizer/config.js +7 -9
  18. package/dest/synchronizer/factory.d.ts +4 -3
  19. package/dest/synchronizer/factory.d.ts.map +1 -1
  20. package/dest/synchronizer/factory.js +5 -5
  21. package/dest/synchronizer/server_world_state_synchronizer.d.ts +1 -2
  22. package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
  23. package/dest/synchronizer/server_world_state_synchronizer.js +45 -25
  24. package/dest/test/utils.d.ts +7 -7
  25. package/dest/test/utils.d.ts.map +1 -1
  26. package/dest/test/utils.js +5 -5
  27. package/dest/world-state-db/merkle_tree_db.d.ts +3 -3
  28. package/dest/world-state-db/merkle_tree_db.d.ts.map +1 -1
  29. package/package.json +11 -11
  30. package/src/instrumentation/instrumentation.ts +9 -1
  31. package/src/native/merkle_trees_facade.ts +11 -2
  32. package/src/native/message.ts +2 -1
  33. package/src/native/native_world_state.ts +22 -10
  34. package/src/native/native_world_state_instance.ts +6 -4
  35. package/src/synchronizer/config.ts +8 -19
  36. package/src/synchronizer/factory.ts +7 -1
  37. package/src/synchronizer/server_world_state_synchronizer.ts +55 -32
  38. package/src/test/utils.ts +6 -6
  39. package/src/world-state-db/merkle_tree_db.ts +2 -2
@@ -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
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';
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,
@@ -48,7 +48,6 @@ export class ServerWorldStateSynchronizer
48
48
  private latestBlockNumberAtStart = BlockNumber.ZERO;
49
49
  private historyToKeep: number | undefined;
50
50
  private currentState: WorldStateRunningState = WorldStateRunningState.IDLE;
51
- private latestBlockHashQuery: { blockNumber: BlockNumber; hash: string | undefined } | undefined = undefined;
52
51
 
53
52
  private syncPromise = promiseWithResolvers<void>();
54
53
  protected blockStream: L2BlockStream | undefined;
@@ -65,7 +64,7 @@ export class ServerWorldStateSynchronizer
65
64
  private readonly log: Logger = createLogger('world_state'),
66
65
  ) {
67
66
  this.merkleTreeCommitted = this.merkleTreeDb.getCommitted();
68
- this.historyToKeep = config.worldStateBlockHistory < 1 ? undefined : config.worldStateBlockHistory;
67
+ this.historyToKeep = config.worldStateCheckpointHistory < 1 ? undefined : config.worldStateCheckpointHistory;
69
68
  this.log.info(
70
69
  `Created world state synchroniser with block history of ${
71
70
  this.historyToKeep === undefined ? 'infinity' : this.historyToKeep
@@ -102,11 +101,7 @@ export class ServerWorldStateSynchronizer
102
101
  }
103
102
 
104
103
  // Get the current latest block number
105
- this.latestBlockNumberAtStart = BlockNumber(
106
- await (this.config.worldStateProvenBlocksOnly
107
- ? this.l2BlockSource.getProvenBlockNumber()
108
- : this.l2BlockSource.getBlockNumber()),
109
- );
104
+ this.latestBlockNumberAtStart = BlockNumber(await this.l2BlockSource.getBlockNumber());
110
105
 
111
106
  const blockToDownloadFrom = (await this.getLatestBlockNumber()) + 1;
112
107
 
@@ -130,7 +125,6 @@ export class ServerWorldStateSynchronizer
130
125
  protected createBlockStream(): L2BlockStream {
131
126
  const logger = createLogger('world-state:block_stream');
132
127
  return new L2BlockStream(this.l2BlockSource, this, this, logger, {
133
- proven: this.config.worldStateProvenBlocksOnly,
134
128
  pollIntervalMS: this.config.worldStateBlockCheckIntervalMS,
135
129
  batchSize: this.config.worldStateBlockRequestBatchSize,
136
130
  ignoreCheckpoints: true,
@@ -241,21 +235,24 @@ export class ServerWorldStateSynchronizer
241
235
  if (number === BlockNumber.ZERO) {
242
236
  return (await this.merkleTreeCommitted.getInitialHeader().hash()).toString();
243
237
  }
244
- if (this.latestBlockHashQuery?.hash === undefined || number !== this.latestBlockHashQuery.blockNumber) {
245
- this.latestBlockHashQuery = {
246
- hash: await this.merkleTreeCommitted
247
- .getLeafValue(MerkleTreeId.ARCHIVE, BigInt(number))
248
- .then(leaf => leaf?.toString()),
249
- blockNumber: number,
250
- };
251
- }
252
- return this.latestBlockHashQuery.hash;
238
+ return this.merkleTreeCommitted.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(number)).then(leaf => leaf?.toString());
253
239
  }
254
240
 
255
241
  /** Returns the latest L2 block number for each tip of the chain (latest, proven, finalized). */
256
242
  public async getL2Tips(): Promise<L2Tips> {
257
243
  const status = await this.merkleTreeDb.getStatusSummary();
258
- 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
+ ]);
259
256
  const latestBlockId: L2BlockId = { number: status.unfinalizedBlockNumber, hash: unfinalizedBlockHash! };
260
257
 
261
258
  // World state doesn't track checkpointed blocks or checkpoints themselves.
@@ -269,13 +266,13 @@ export class ServerWorldStateSynchronizer
269
266
  checkpoint: { number: INITIAL_L2_CHECKPOINT_NUM, hash: genesisCheckpointHeaderHash },
270
267
  },
271
268
  finalized: {
272
- block: { number: status.finalizedBlockNumber, hash: '' },
269
+ block: { number: status.finalizedBlockNumber, hash: finalizedBlockHash ?? '' },
273
270
  checkpoint: { number: INITIAL_L2_CHECKPOINT_NUM, hash: genesisCheckpointHeaderHash },
274
271
  },
275
272
  proven: {
276
- block: { number: this.provenBlockNumber ?? status.finalizedBlockNumber, hash: '' },
273
+ block: { number: provenBlockNumber, hash: provenBlockHash ?? '' },
277
274
  checkpoint: { number: INITIAL_L2_CHECKPOINT_NUM, hash: genesisCheckpointHeaderHash },
278
- }, // TODO(palla/reorg): Using finalized as proven for now
275
+ },
279
276
  };
280
277
  }
281
278
 
@@ -302,8 +299,8 @@ export class ServerWorldStateSynchronizer
302
299
  * @param l2Blocks - The L2 blocks to handle.
303
300
  * @returns Whether the block handled was produced by this same node.
304
301
  */
305
- private async handleL2Blocks(l2Blocks: L2BlockNew[]) {
306
- 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}`);
307
304
 
308
305
  // Fetch the L1->L2 messages for the first block in a checkpoint.
309
306
  const messagesForBlocks = new Map<BlockNumber, Fr[]>();
@@ -343,11 +340,13 @@ export class ServerWorldStateSynchronizer
343
340
  * @param l1ToL2Messages - The L1 to L2 messages for the block.
344
341
  * @returns Whether the block handled was produced by this same node.
345
342
  */
346
- private async handleL2Block(l2Block: L2BlockNew, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull> {
347
- 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 `, {
348
345
  blockNumber: l2Block.number,
349
346
  blockHash: await l2Block.hash().then(h => h.toString()),
350
347
  l1ToL2Messages: l1ToL2Messages.map(msg => msg.toString()),
348
+ blockHeader: l2Block.header.toInspect(),
349
+ blockStats: l2Block.getStats(),
351
350
  });
352
351
  const result = await this.merkleTreeDb.handleL2BlockAndMessages(l2Block, l1ToL2Messages);
353
352
 
@@ -365,12 +364,37 @@ export class ServerWorldStateSynchronizer
365
364
  if (this.historyToKeep === undefined) {
366
365
  return;
367
366
  }
368
- const newHistoricBlock = summary.finalizedBlockNumber - this.historyToKeep + 1;
369
- if (newHistoricBlock <= 1) {
367
+ // Get the checkpointed block for the finalized block number
368
+ const finalisedCheckpoint = await this.l2BlockSource.getCheckpointedBlock(summary.finalizedBlockNumber);
369
+ if (finalisedCheckpoint === undefined) {
370
+ this.log.warn(
371
+ `Failed to retrieve checkpointed block for finalized block number: ${summary.finalizedBlockNumber}`,
372
+ );
373
+ return;
374
+ }
375
+ // Compute the required historic checkpoint number
376
+ const newHistoricCheckpointNumber = finalisedCheckpoint.checkpointNumber - this.historyToKeep + 1;
377
+ if (newHistoricCheckpointNumber <= 1) {
378
+ return;
379
+ }
380
+ // Retrieve the historic checkpoint
381
+ const historicCheckpoints = await this.l2BlockSource.getCheckpoints(
382
+ CheckpointNumber(newHistoricCheckpointNumber),
383
+ 1,
384
+ );
385
+ if (historicCheckpoints.length === 0 || historicCheckpoints[0] === undefined) {
386
+ this.log.warn(`Failed to retrieve checkpoint number ${newHistoricCheckpointNumber} from Archiver`);
387
+ return;
388
+ }
389
+ const historicCheckpoint = historicCheckpoints[0];
390
+ if (historicCheckpoint.checkpoint.blocks.length === 0 || historicCheckpoint.checkpoint.blocks[0] === undefined) {
391
+ this.log.warn(`Retrieved checkpoint number ${newHistoricCheckpointNumber} has no blocks!`);
370
392
  return;
371
393
  }
372
- this.log.verbose(`Pruning historic blocks to ${newHistoricBlock}`);
373
- const status = await this.merkleTreeDb.removeHistoricalBlocks(BlockNumber(newHistoricBlock));
394
+ // Find the block at the start of the checkpoint and remove blocks up to this one
395
+ const newHistoricBlock = historicCheckpoint.checkpoint.blocks[0];
396
+ this.log.verbose(`Pruning historic blocks to ${newHistoricBlock.number}`);
397
+ const status = await this.merkleTreeDb.removeHistoricalBlocks(BlockNumber(newHistoricBlock.number));
374
398
  this.log.debug(`World state summary `, status.summary);
375
399
  }
376
400
 
@@ -383,7 +407,6 @@ export class ServerWorldStateSynchronizer
383
407
  private async handleChainPruned(blockNumber: BlockNumber) {
384
408
  this.log.warn(`Chain pruned to block ${blockNumber}`);
385
409
  const status = await this.merkleTreeDb.unwindBlocks(blockNumber);
386
- this.latestBlockHashQuery = undefined;
387
410
  this.provenBlockNumber = undefined;
388
411
  this.instrumentation.updateWorldStateMetrics(status);
389
412
  }
package/src/test/utils.ts CHANGED
@@ -5,10 +5,10 @@ import {
5
5
  NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
6
6
  } from '@aztec/constants';
7
7
  import { asyncMap } from '@aztec/foundation/async-map';
8
- import { BlockNumber, type CheckpointNumber } from '@aztec/foundation/branded-types';
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,8 +76,8 @@ 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, {
80
- indexWithinCheckpoint: isFirstBlockInCheckpoint ? 0 : 1,
79
+ const block = await L2Block.random(blockNum, {
80
+ indexWithinCheckpoint: isFirstBlockInCheckpoint ? IndexWithinCheckpoint(0) : IndexWithinCheckpoint(1),
81
81
  txsPerBlock: size,
82
82
  txOptions: { maxEffects },
83
83
  });
@@ -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