@aztec/world-state 3.0.3 → 4.0.0-devnet.1-patch.0

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 +17 -41
  4. package/dest/native/merkle_trees_facade.d.ts +7 -2
  5. package/dest/native/merkle_trees_facade.d.ts.map +1 -1
  6. package/dest/native/merkle_trees_facade.js +34 -5
  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 +10 -8
  10. package/dest/native/native_world_state.d.ts.map +1 -1
  11. package/dest/native/native_world_state.js +11 -10
  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 +3 -3
  15. package/dest/synchronizer/config.d.ts +1 -3
  16. package/dest/synchronizer/config.d.ts.map +1 -1
  17. package/dest/synchronizer/config.js +1 -6
  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 +5 -4
  22. package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
  23. package/dest/synchronizer/server_world_state_synchronizer.js +57 -29
  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 +10 -6
  27. package/dest/world-state-db/merkle_tree_db.d.ts +5 -5
  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 +17 -41
  31. package/src/native/merkle_trees_facade.ts +35 -2
  32. package/src/native/message.ts +2 -1
  33. package/src/native/native_world_state.ts +27 -11
  34. package/src/native/native_world_state_instance.ts +5 -3
  35. package/src/synchronizer/config.ts +1 -14
  36. package/src/synchronizer/factory.ts +7 -1
  37. package/src/synchronizer/server_world_state_synchronizer.ts +54 -40
  38. package/src/test/utils.ts +8 -7
  39. package/src/world-state-db/merkle_tree_db.ts +8 -4
@@ -1,6 +1,8 @@
1
1
  import { BlockNumber } from '@aztec/foundation/branded-types';
2
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,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';
@@ -412,7 +413,7 @@ interface UpdateArchiveRequest extends WithForkId {
412
413
  interface SyncBlockRequest extends WithCanonicalForkId {
413
414
  blockNumber: BlockNumber;
414
415
  blockStateRef: BlockStateReference;
415
- blockHeaderHash: Fr;
416
+ blockHeaderHash: BlockHash;
416
417
  paddedNoteHashes: readonly SerializedLeafValue[];
417
418
  paddedL1ToL2Messages: readonly SerializedLeafValue[];
418
419
  paddedNullifiers: readonly SerializedLeafValue[];
@@ -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
  }
@@ -159,7 +171,10 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
159
171
  );
160
172
  }
161
173
 
162
- public async fork(blockNumber?: BlockNumber): Promise<MerkleTreeWriteOperations> {
174
+ public async fork(
175
+ blockNumber?: BlockNumber,
176
+ opts: { closeDelayMs?: number } = {},
177
+ ): Promise<MerkleTreeWriteOperations> {
163
178
  const resp = await this.instance.call(WorldStateMessageType.CREATE_FORK, {
164
179
  latest: blockNumber === undefined,
165
180
  blockNumber: blockNumber ?? BlockNumber.ZERO,
@@ -173,6 +188,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
173
188
  /* blockNumber=*/ BlockNumber.ZERO,
174
189
  /* includeUncommitted=*/ true,
175
190
  ),
191
+ opts,
176
192
  );
177
193
  }
178
194
 
@@ -180,7 +196,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
180
196
  return this.initialHeader!;
181
197
  }
182
198
 
183
- public async handleL2BlockAndMessages(l2Block: L2BlockNew, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull> {
199
+ public async handleL2BlockAndMessages(l2Block: L2Block, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull> {
184
200
  const isFirstBlock = l2Block.indexWithinCheckpoint === 0;
185
201
  if (!isFirstBlock && l1ToL2Messages.length > 0) {
186
202
  throw new Error(
@@ -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
+ GeneratorIndex.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
 
@@ -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,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,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
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,7 +25,7 @@ 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';
@@ -46,7 +48,6 @@ export class ServerWorldStateSynchronizer
46
48
  private latestBlockNumberAtStart = BlockNumber.ZERO;
47
49
  private historyToKeep: number | undefined;
48
50
  private currentState: WorldStateRunningState = WorldStateRunningState.IDLE;
49
- private latestBlockHashQuery: { blockNumber: BlockNumber; hash: string | undefined } | undefined = undefined;
50
51
 
51
52
  private syncPromise = promiseWithResolvers<void>();
52
53
  protected blockStream: L2BlockStream | undefined;
@@ -79,8 +80,8 @@ export class ServerWorldStateSynchronizer
79
80
  return this.merkleTreeDb.getSnapshot(blockNumber);
80
81
  }
81
82
 
82
- public fork(blockNumber?: BlockNumber): Promise<MerkleTreeWriteOperations> {
83
- return this.merkleTreeDb.fork(blockNumber);
83
+ public fork(blockNumber?: BlockNumber, opts?: { closeDelayMs?: number }): Promise<MerkleTreeWriteOperations> {
84
+ return this.merkleTreeDb.fork(blockNumber, opts);
84
85
  }
85
86
 
86
87
  public backupTo(dstPath: string, compact?: boolean): Promise<Record<Exclude<SnapshotDataKeys, 'archiver'>, string>> {
@@ -100,11 +101,7 @@ export class ServerWorldStateSynchronizer
100
101
  }
101
102
 
102
103
  // Get the current latest block number
103
- this.latestBlockNumberAtStart = BlockNumber(
104
- await (this.config.worldStateProvenBlocksOnly
105
- ? this.l2BlockSource.getProvenBlockNumber()
106
- : this.l2BlockSource.getBlockNumber()),
107
- );
104
+ this.latestBlockNumberAtStart = BlockNumber(await this.l2BlockSource.getBlockNumber());
108
105
 
109
106
  const blockToDownloadFrom = (await this.getLatestBlockNumber()) + 1;
110
107
 
@@ -126,12 +123,11 @@ export class ServerWorldStateSynchronizer
126
123
  }
127
124
 
128
125
  protected createBlockStream(): L2BlockStream {
129
- const tracer = this.instrumentation.telemetry.getTracer('WorldStateL2BlockStream');
130
126
  const logger = createLogger('world-state:block_stream');
131
- return new TraceableL2BlockStream(this.l2BlockSource, this, this, tracer, 'WorldStateL2BlockStream', logger, {
132
- proven: this.config.worldStateProvenBlocksOnly,
127
+ return new L2BlockStream(this.l2BlockSource, this, this, logger, {
133
128
  pollIntervalMS: this.config.worldStateBlockCheckIntervalMS,
134
129
  batchSize: this.config.worldStateBlockRequestBatchSize,
130
+ ignoreCheckpoints: true,
135
131
  });
136
132
  }
137
133
 
@@ -160,7 +156,7 @@ export class ServerWorldStateSynchronizer
160
156
  }
161
157
 
162
158
  public async getLatestBlockNumber() {
163
- return (await this.getL2Tips()).latest.number;
159
+ return (await this.getL2Tips()).proposed.number;
164
160
  }
165
161
 
166
162
  public async stopSync() {
@@ -239,27 +235,44 @@ export class ServerWorldStateSynchronizer
239
235
  if (number === BlockNumber.ZERO) {
240
236
  return (await this.merkleTreeCommitted.getInitialHeader().hash()).toString();
241
237
  }
242
- if (this.latestBlockHashQuery?.hash === undefined || number !== this.latestBlockHashQuery.blockNumber) {
243
- this.latestBlockHashQuery = {
244
- hash: await this.merkleTreeCommitted
245
- .getLeafValue(MerkleTreeId.ARCHIVE, BigInt(number))
246
- .then(leaf => leaf?.toString()),
247
- blockNumber: number,
248
- };
249
- }
250
- return this.latestBlockHashQuery.hash;
238
+ return this.merkleTreeCommitted.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(number)).then(leaf => leaf?.toString());
251
239
  }
252
240
 
253
241
  /** Returns the latest L2 block number for each tip of the chain (latest, proven, finalized). */
254
242
  public async getL2Tips(): Promise<L2Tips> {
255
243
  const status = await this.merkleTreeDb.getStatusSummary();
256
- 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
+ ]);
257
256
  const latestBlockId: L2BlockId = { number: status.unfinalizedBlockNumber, hash: unfinalizedBlockHash! };
258
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();
259
262
  return {
260
- latest: latestBlockId,
261
- finalized: { number: status.finalizedBlockNumber, hash: '' },
262
- 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
+ },
263
276
  };
264
277
  }
265
278
 
@@ -267,7 +280,7 @@ export class ServerWorldStateSynchronizer
267
280
  public async handleBlockStreamEvent(event: L2BlockStreamEvent): Promise<void> {
268
281
  switch (event.type) {
269
282
  case 'blocks-added':
270
- await this.handleL2Blocks(event.blocks.map(b => b.block.toL2Block()));
283
+ await this.handleL2Blocks(event.blocks);
271
284
  break;
272
285
  case 'chain-pruned':
273
286
  await this.handleChainPruned(event.block.number);
@@ -286,8 +299,8 @@ export class ServerWorldStateSynchronizer
286
299
  * @param l2Blocks - The L2 blocks to handle.
287
300
  * @returns Whether the block handled was produced by this same node.
288
301
  */
289
- private async handleL2Blocks(l2Blocks: L2BlockNew[]) {
290
- 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}`);
291
304
 
292
305
  // Fetch the L1->L2 messages for the first block in a checkpoint.
293
306
  const messagesForBlocks = new Map<BlockNumber, Fr[]>();
@@ -327,11 +340,13 @@ export class ServerWorldStateSynchronizer
327
340
  * @param l1ToL2Messages - The L1 to L2 messages for the block.
328
341
  * @returns Whether the block handled was produced by this same node.
329
342
  */
330
- private async handleL2Block(l2Block: L2BlockNew, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull> {
331
- 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 `, {
332
345
  blockNumber: l2Block.number,
333
346
  blockHash: await l2Block.hash().then(h => h.toString()),
334
347
  l1ToL2Messages: l1ToL2Messages.map(msg => msg.toString()),
348
+ blockHeader: l2Block.header.toInspect(),
349
+ blockStats: l2Block.getStats(),
335
350
  });
336
351
  const result = await this.merkleTreeDb.handleL2BlockAndMessages(l2Block, l1ToL2Messages);
337
352
 
@@ -367,7 +382,6 @@ export class ServerWorldStateSynchronizer
367
382
  private async handleChainPruned(blockNumber: BlockNumber) {
368
383
  this.log.warn(`Chain pruned to block ${blockNumber}`);
369
384
  const status = await this.merkleTreeDb.unwindBlocks(blockNumber);
370
- this.latestBlockHashQuery = undefined;
371
385
  this.provenBlockNumber = undefined;
372
386
  this.instrumentation.updateWorldStateMetrics(status);
373
387
  }
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,
@@ -16,10 +16,11 @@ import type {
16
16
  } from '@aztec/stdlib/interfaces/server';
17
17
  import { mockCheckpointAndMessages, mockL1ToL2Messages } from '@aztec/stdlib/testing';
18
18
  import { AppendOnlyTreeSnapshot, MerkleTreeId } from '@aztec/stdlib/trees';
19
+ import { BlockHeader } from '@aztec/stdlib/tx';
19
20
 
20
21
  import type { NativeWorldStateService } from '../native/native_world_state.js';
21
22
 
22
- export async function updateBlockState(block: L2BlockNew, l1ToL2Messages: Fr[], fork: MerkleTreeWriteOperations) {
23
+ export async function updateBlockState(block: L2Block, l1ToL2Messages: Fr[], fork: MerkleTreeWriteOperations) {
23
24
  const insertData = async (
24
25
  treeId: IndexedTreeId,
25
26
  data: Buffer[][],
@@ -59,7 +60,7 @@ export async function updateBlockState(block: L2BlockNew, l1ToL2Messages: Fr[],
59
60
  await Promise.all([publicDataInsert, nullifierInsert, noteHashInsert, messageInsert]);
60
61
 
61
62
  const state = await fork.getStateReference();
62
- block.header.state = state;
63
+ block.header = BlockHeader.from({ ...block.header, state });
63
64
  await fork.updateArchive(block.header);
64
65
 
65
66
  const archiveState = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
@@ -75,8 +76,8 @@ export async function mockBlock(
75
76
  numL1ToL2Messages: number = NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
76
77
  isFirstBlockInCheckpoint: boolean = true,
77
78
  ) {
78
- const block = await L2BlockNew.random(blockNum, {
79
- indexWithinCheckpoint: isFirstBlockInCheckpoint ? 0 : 1,
79
+ const block = await L2Block.random(blockNum, {
80
+ indexWithinCheckpoint: isFirstBlockInCheckpoint ? IndexWithinCheckpoint(0) : IndexWithinCheckpoint(1),
80
81
  txsPerBlock: size,
81
82
  txOptions: { maxEffects },
82
83
  });
@@ -91,7 +92,7 @@ export async function mockBlock(
91
92
  }
92
93
 
93
94
  export async function mockEmptyBlock(blockNum: BlockNumber, fork: MerkleTreeWriteOperations) {
94
- const l2Block = L2BlockNew.empty();
95
+ const l2Block = L2Block.empty();
95
96
  const l1ToL2Messages = Array(16).fill(0).map(Fr.zero);
96
97
 
97
98
  l2Block.header.globalVariables.blockNumber = blockNum;
@@ -2,8 +2,12 @@ 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';
6
- import type { ForkMerkleTreeOperations, MerkleTreeReadOperations } from '@aztec/stdlib/interfaces/server';
5
+ import type { L2Block } from '@aztec/stdlib/block';
6
+ import type {
7
+ ForkMerkleTreeOperations,
8
+ MerkleTreeReadOperations,
9
+ ReadonlyWorldStateAccess,
10
+ } from '@aztec/stdlib/interfaces/server';
7
11
  import type { MerkleTreeId } from '@aztec/stdlib/trees';
8
12
 
9
13
  import type { WorldStateStatusFull, WorldStateStatusSummary } from '../native/message.js';
@@ -35,13 +39,13 @@ export type TreeSnapshots = {
35
39
  [MerkleTreeId.ARCHIVE]: TreeSnapshot<Fr>;
36
40
  };
37
41
 
38
- export interface MerkleTreeAdminDatabase extends ForkMerkleTreeOperations {
42
+ export interface MerkleTreeAdminDatabase extends ForkMerkleTreeOperations, ReadonlyWorldStateAccess {
39
43
  /**
40
44
  * Handles a single L2 block (i.e. Inserts the new note hashes into the merkle tree).
41
45
  * @param block - The L2 block to handle.
42
46
  * @param l1ToL2Messages - The L1 to L2 messages for the block.
43
47
  */
44
- handleL2BlockAndMessages(block: L2BlockNew, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull>;
48
+ handleL2BlockAndMessages(block: L2Block, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull>;
45
49
 
46
50
  /**
47
51
  * Gets a handle that allows reading the latest committed state