@aztec/world-state 0.56.0 → 0.58.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 (57) hide show
  1. package/README.md +1 -1
  2. package/dest/index.d.ts +1 -0
  3. package/dest/index.d.ts.map +1 -1
  4. package/dest/index.js +2 -1
  5. package/dest/native/merkle_trees_facade.d.ts +34 -0
  6. package/dest/native/merkle_trees_facade.d.ts.map +1 -0
  7. package/dest/native/merkle_trees_facade.js +193 -0
  8. package/dest/native/message.d.ts +78 -19
  9. package/dest/native/message.d.ts.map +1 -1
  10. package/dest/native/message.js +27 -26
  11. package/dest/native/native_world_state.d.ts +39 -38
  12. package/dest/native/native_world_state.d.ts.map +1 -1
  13. package/dest/native/native_world_state.js +108 -254
  14. package/dest/native/native_world_state_instance.d.ts +40 -0
  15. package/dest/native/native_world_state_instance.d.ts.map +1 -0
  16. package/dest/native/native_world_state_instance.js +183 -0
  17. package/dest/synchronizer/config.d.ts +2 -2
  18. package/dest/synchronizer/config.d.ts.map +1 -1
  19. package/dest/synchronizer/config.js +6 -7
  20. package/dest/synchronizer/factory.d.ts +3 -0
  21. package/dest/synchronizer/factory.d.ts.map +1 -1
  22. package/dest/synchronizer/factory.js +13 -4
  23. package/dest/synchronizer/server_world_state_synchronizer.d.ts +41 -41
  24. package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
  25. package/dest/synchronizer/server_world_state_synchronizer.js +128 -163
  26. package/dest/test/utils.d.ts +14 -0
  27. package/dest/test/utils.d.ts.map +1 -0
  28. package/dest/test/utils.js +67 -0
  29. package/dest/world-state-db/index.d.ts +1 -1
  30. package/dest/world-state-db/index.d.ts.map +1 -1
  31. package/dest/world-state-db/merkle_tree_db.d.ts +42 -32
  32. package/dest/world-state-db/merkle_tree_db.d.ts.map +1 -1
  33. package/dest/world-state-db/merkle_tree_db.js +1 -1
  34. package/dest/world-state-db/merkle_tree_operations_facade.d.ts +8 -37
  35. package/dest/world-state-db/merkle_tree_operations_facade.d.ts.map +1 -1
  36. package/dest/world-state-db/merkle_tree_operations_facade.js +6 -45
  37. package/dest/world-state-db/merkle_tree_snapshot_operations_facade.d.ts +4 -13
  38. package/dest/world-state-db/merkle_tree_snapshot_operations_facade.d.ts.map +1 -1
  39. package/dest/world-state-db/merkle_tree_snapshot_operations_facade.js +2 -29
  40. package/dest/world-state-db/merkle_trees.d.ts +17 -19
  41. package/dest/world-state-db/merkle_trees.d.ts.map +1 -1
  42. package/dest/world-state-db/merkle_trees.js +39 -36
  43. package/package.json +18 -12
  44. package/src/index.ts +1 -0
  45. package/src/native/merkle_trees_facade.ts +279 -0
  46. package/src/native/message.ts +97 -20
  47. package/src/native/native_world_state.ts +125 -346
  48. package/src/native/native_world_state_instance.ts +262 -0
  49. package/src/synchronizer/config.ts +8 -9
  50. package/src/synchronizer/factory.ts +20 -3
  51. package/src/synchronizer/server_world_state_synchronizer.ts +160 -186
  52. package/src/test/utils.ts +123 -0
  53. package/src/world-state-db/index.ts +1 -1
  54. package/src/world-state-db/merkle_tree_db.ts +55 -49
  55. package/src/world-state-db/merkle_tree_operations_facade.ts +10 -55
  56. package/src/world-state-db/merkle_tree_snapshot_operations_facade.ts +7 -46
  57. package/src/world-state-db/merkle_trees.ts +50 -45
@@ -1,16 +1,13 @@
1
1
  import {
2
- type BatchInsertionResult,
3
- type HandleL2BlockAndMessagesResult,
4
2
  type IndexedTreeId,
5
3
  type L2Block,
6
- type MerkleTreeAdminOperations,
7
4
  MerkleTreeId,
8
- type MerkleTreeLeafType,
9
- SiblingPath,
10
- type TreeInfo,
5
+ type MerkleTreeReadOperations,
6
+ type MerkleTreeWriteOperations,
11
7
  TxEffect,
12
8
  } from '@aztec/circuit-types';
13
9
  import {
10
+ EthAddress,
14
11
  Fr,
15
12
  Header,
16
13
  MAX_NOTE_HASHES_PER_TX,
@@ -18,279 +15,120 @@ import {
18
15
  MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
19
16
  NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
20
17
  NullifierLeaf,
21
- NullifierLeafPreimage,
18
+ type NullifierLeafPreimage,
22
19
  PartialStateReference,
23
20
  PublicDataTreeLeaf,
24
- PublicDataTreeLeafPreimage,
25
21
  StateReference,
26
22
  } from '@aztec/circuits.js';
27
23
  import { padArrayEnd } from '@aztec/foundation/collection';
28
- import { SerialQueue } from '@aztec/foundation/queue';
29
- import { serializeToBuffer } from '@aztec/foundation/serialize';
30
- import type { IndexedTreeLeafPreimage } from '@aztec/foundation/trees';
24
+ import { createDebugLogger } from '@aztec/foundation/log';
31
25
 
32
- import bindings from 'bindings';
33
- import { Decoder, Encoder, addExtension } from 'msgpackr';
34
- import { isAnyArrayBuffer } from 'util/types';
26
+ import assert from 'assert/strict';
27
+ import { mkdir, mkdtemp, readFile, rm, writeFile } from 'fs/promises';
28
+ import { tmpdir } from 'os';
29
+ import { join } from 'path';
35
30
 
36
- import { type MerkleTreeDb, type TreeSnapshots } from '../world-state-db/merkle_tree_db.js';
37
- import { MerkleTreeAdminOperationsFacade } from '../world-state-db/merkle_tree_operations_facade.js';
31
+ import { type MerkleTreeAdminDatabase as MerkleTreeDatabase } from '../world-state-db/merkle_tree_db.js';
32
+ import { MerkleTreesFacade, MerkleTreesForkFacade, serializeLeaf } from './merkle_trees_facade.js';
38
33
  import {
39
- MessageHeader,
40
- type SerializedIndexedLeaf,
41
- type SerializedLeafValue,
42
- TypedMessage,
43
34
  WorldStateMessageType,
44
- type WorldStateRequest,
45
- type WorldStateResponse,
35
+ type WorldStateStatus,
46
36
  blockStateReference,
47
37
  treeStateReferenceToSnapshot,
48
38
  worldStateRevision,
49
39
  } from './message.js';
40
+ import { NativeWorldState } from './native_world_state_instance.js';
50
41
 
51
- // small extension to pack an NodeJS Fr instance to a representation that the C++ code can understand
52
- // this only works for writes. Unpacking from C++ can't create Fr instances because the data is passed
53
- // as raw, untagged, buffers. On the NodeJS side we don't know what the buffer represents
54
- // Adding a tag would be a solution, but it would have to be done on both sides and it's unclear where else
55
- // C++ fr instances are sent/received/stored.
56
- addExtension({
57
- Class: Fr,
58
- write: fr => fr.toBuffer(),
59
- });
60
-
61
- export interface NativeInstance {
62
- call(msg: Buffer | Uint8Array): Promise<any>;
63
- }
64
-
65
- export class NativeWorldStateService implements MerkleTreeDb {
66
- private nextMessageId = 1;
67
-
68
- private encoder = new Encoder({
69
- // always encode JS objects as MessagePack maps
70
- // this makes it compatible with other MessagePack decoders
71
- useRecords: false,
72
- int64AsType: 'bigint',
73
- });
42
+ const ROLLUP_ADDRESS_FILE = 'rollup_address';
74
43
 
75
- private decoder = new Decoder({
76
- useRecords: false,
77
- int64AsType: 'bigint',
78
- });
44
+ export class NativeWorldStateService implements MerkleTreeDatabase {
45
+ protected initialHeader: Header | undefined;
79
46
 
80
- private queue = new SerialQueue();
47
+ protected constructor(
48
+ protected readonly instance: NativeWorldState,
49
+ protected readonly log = createDebugLogger('aztec:world-state:database'),
50
+ private readonly cleanup = () => Promise.resolve(),
51
+ ) {}
81
52
 
82
- protected constructor(private instance: NativeInstance) {
83
- this.queue.start();
84
- }
85
-
86
- static async create(
53
+ static async new(
54
+ rollupAddress: EthAddress,
87
55
  dataDir: string,
88
- libraryName = 'world_state_napi',
89
- className = 'WorldState',
56
+ log = createDebugLogger('aztec:world-state:database'),
57
+ cleanup = () => Promise.resolve(),
90
58
  ): Promise<NativeWorldStateService> {
91
- const library = bindings(libraryName);
92
- const instance = new library[className](dataDir);
93
- const worldState = new NativeWorldStateService(instance);
94
- await worldState.init();
95
- return worldState;
96
- }
59
+ const rollupAddressFile = join(dataDir, ROLLUP_ADDRESS_FILE);
60
+ const currentRollupStr = await readFile(rollupAddressFile, 'utf8').catch(() => undefined);
61
+ const currentRollupAddress = currentRollupStr ? EthAddress.fromString(currentRollupStr.trim()) : undefined;
97
62
 
98
- protected async init() {
99
- const archive = await this.getTreeInfo(MerkleTreeId.ARCHIVE, false);
100
- if (archive.size === 0n) {
101
- // TODO (alexg) move this to the native module
102
- // const header = await this.buildInitialHeader(true);
103
- // await this.appendLeaves(MerkleTreeId.ARCHIVE, [header.hash()]);
104
- // await this.commit();
63
+ if (currentRollupAddress && !rollupAddress.equals(currentRollupAddress)) {
64
+ log.warn('Rollup address changed, deleting database');
65
+ await rm(dataDir, { recursive: true, force: true });
105
66
  }
106
- }
107
-
108
- public asLatest(): MerkleTreeAdminOperations {
109
- return new MerkleTreeAdminOperationsFacade(this, true);
110
- }
111
67
 
112
- // async buildInitialHeader(ic: boolean = false): Promise<Header> {
113
- // const state = await this.getStateReference(ic);
114
- // return new Header(
115
- // AppendOnlyTreeSnapshot.zero(),
116
- // ContentCommitment.empty(),
117
- // state,
118
- // GlobalVariables.empty(),
119
- // Fr.ZERO,
120
- // );
121
- // }
68
+ await mkdir(dataDir, { recursive: true });
69
+ await writeFile(rollupAddressFile, rollupAddress.toString(), 'utf8');
122
70
 
123
- public getInitialHeader(): Header {
124
- // TODO (alexg) implement this
125
- return Header.empty();
71
+ const instance = new NativeWorldState(dataDir);
72
+ const worldState = new this(instance, log, cleanup);
73
+ await worldState.init();
74
+ return worldState;
126
75
  }
127
76
 
128
- async appendLeaves<ID extends MerkleTreeId>(treeId: ID, leaves: MerkleTreeLeafType<ID>[]): Promise<void> {
129
- await this.call(WorldStateMessageType.APPEND_LEAVES, {
130
- leaves: leaves.map(leaf => leaf as any),
131
- treeId,
132
- });
133
- }
77
+ static async tmp(rollupAddress = EthAddress.ZERO, cleanupTmpDir = true): Promise<NativeWorldStateService> {
78
+ const log = createDebugLogger('aztec:world-state:database');
79
+ const dataDir = await mkdtemp(join(tmpdir(), 'aztec-world-state-'));
80
+ log.debug(`Created temporary world state database: ${dataDir}`);
134
81
 
135
- async batchInsert<TreeHeight extends number, SubtreeSiblingPathHeight extends number, ID extends IndexedTreeId>(
136
- treeId: ID,
137
- rawLeaves: Buffer[],
138
- subtreeHeight: number,
139
- ): Promise<BatchInsertionResult<TreeHeight, SubtreeSiblingPathHeight>> {
140
- const leaves = rawLeaves.map((leaf: Buffer) => hydrateLeaf(treeId, leaf)).map(serializeLeaf);
141
- const resp = await this.call(WorldStateMessageType.BATCH_INSERT, { leaves, treeId, subtreeDepth: subtreeHeight });
142
-
143
- return {
144
- newSubtreeSiblingPath: new SiblingPath<SubtreeSiblingPathHeight>(
145
- resp.subtree_path.length as any,
146
- resp.subtree_path,
147
- ),
148
- sortedNewLeaves: resp.sorted_leaves
149
- .map(([leaf]) => leaf)
150
- .map(deserializeLeafValue)
151
- .map(serializeToBuffer),
152
- sortedNewLeavesIndexes: resp.sorted_leaves.map(([, index]) => index),
153
- lowLeavesWitnessData: resp.low_leaf_witness_data.map(data => ({
154
- index: BigInt(data.index),
155
- leafPreimage: deserializeIndexedLeaf(data.leaf),
156
- siblingPath: new SiblingPath<TreeHeight>(data.path.length as any, data.path),
157
- })),
82
+ // pass a cleanup callback because process.on('beforeExit', cleanup) does not work under Jest
83
+ const cleanup = async () => {
84
+ if (cleanupTmpDir) {
85
+ await rm(dataDir, { recursive: true, force: true });
86
+ log.debug(`Deleted temporary world state database: ${dataDir}`);
87
+ } else {
88
+ log.debug(`Leaving temporary world state database: ${dataDir}`);
89
+ }
158
90
  };
159
- }
160
-
161
- async commit(): Promise<void> {
162
- await this.call(WorldStateMessageType.COMMIT, void 0);
163
- }
164
-
165
- findLeafIndex(
166
- treeId: MerkleTreeId,
167
- value: MerkleTreeLeafType<MerkleTreeId>,
168
- includeUncommitted: boolean,
169
- ): Promise<bigint | undefined> {
170
- return this.findLeafIndexAfter(treeId, value, 0n, includeUncommitted);
171
- }
172
-
173
- async findLeafIndexAfter(
174
- treeId: MerkleTreeId,
175
- leaf: MerkleTreeLeafType<MerkleTreeId>,
176
- startIndex: bigint,
177
- includeUncommitted: boolean,
178
- ): Promise<bigint | undefined> {
179
- const index = await this.call(WorldStateMessageType.FIND_LEAF_INDEX, {
180
- leaf: serializeLeaf(hydrateLeaf(treeId, leaf)),
181
- revision: worldStateRevision(includeUncommitted),
182
- treeId,
183
- startIndex,
184
- });
185
-
186
- if (typeof index === 'number' || typeof index === 'bigint') {
187
- return BigInt(index);
188
- } else {
189
- return undefined;
190
- }
191
- }
192
91
 
193
- async getLeafPreimage(
194
- treeId: IndexedTreeId,
195
- leafIndex: bigint,
196
- args: boolean,
197
- ): Promise<IndexedTreeLeafPreimage | undefined> {
198
- const resp = await this.call(WorldStateMessageType.GET_LEAF_PREIMAGE, {
199
- leafIndex,
200
- revision: worldStateRevision(args),
201
- treeId,
202
- });
203
-
204
- return resp ? deserializeIndexedLeaf(resp) : undefined;
92
+ return this.new(rollupAddress, dataDir, log, cleanup);
205
93
  }
206
94
 
207
- async getLeafValue(
208
- treeId: MerkleTreeId,
209
- leafIndex: bigint,
210
- includeUncommitted: boolean,
211
- ): Promise<MerkleTreeLeafType<MerkleTreeId> | undefined> {
212
- const resp = await this.call(WorldStateMessageType.GET_LEAF_VALUE, {
213
- leafIndex,
214
- revision: worldStateRevision(includeUncommitted),
215
- treeId,
216
- });
217
-
218
- if (!resp) {
219
- return undefined;
220
- }
95
+ protected async init() {
96
+ this.initialHeader = await this.buildInitialHeader();
97
+ const committed = this.getCommitted();
221
98
 
222
- const leaf = deserializeLeafValue(resp);
223
- if (leaf instanceof Fr) {
224
- return leaf;
225
- } else {
226
- return leaf.toBuffer();
99
+ // validate the initial state
100
+ const archive = await committed.getTreeInfo(MerkleTreeId.ARCHIVE);
101
+ if (archive.size === 0n) {
102
+ throw new Error("Archive tree can't be empty");
227
103
  }
228
- }
229
104
 
230
- async getPreviousValueIndex(
231
- treeId: IndexedTreeId,
232
- value: bigint,
233
- includeUncommitted: boolean,
234
- ): Promise<{ index: bigint; alreadyPresent: boolean } | undefined> {
235
- const resp = await this.call(WorldStateMessageType.FIND_LOW_LEAF, {
236
- key: new Fr(value),
237
- revision: worldStateRevision(includeUncommitted),
238
- treeId,
239
- });
240
- return {
241
- alreadyPresent: resp.alreadyPresent,
242
- index: BigInt(resp.index),
243
- };
105
+ // the initial header _must_ be the first element in the archive tree
106
+ // if this assertion fails, check that the hashing done in Header in yarn-project matches the initial header hash done in world_state.cpp
107
+ const initialHeaderIndex = await committed.findLeafIndex(MerkleTreeId.ARCHIVE, this.initialHeader.hash());
108
+ assert.strictEqual(initialHeaderIndex, 0n, 'Invalid initial archive state');
244
109
  }
245
110
 
246
- async getSiblingPath(
247
- treeId: MerkleTreeId,
248
- leafIndex: bigint,
249
- includeUncommitted: boolean,
250
- ): Promise<SiblingPath<number>> {
251
- const siblingPath = await this.call(WorldStateMessageType.GET_SIBLING_PATH, {
252
- leafIndex,
253
- revision: worldStateRevision(includeUncommitted),
254
- treeId,
255
- });
256
-
257
- return new SiblingPath(siblingPath.length, siblingPath);
111
+ public getCommitted(): MerkleTreeReadOperations {
112
+ return new MerkleTreesFacade(this.instance, this.initialHeader!, worldStateRevision(false, 0, 0));
258
113
  }
259
114
 
260
- getSnapshot(_block: number): Promise<TreeSnapshots> {
261
- return Promise.reject(new Error('getSnapshot not implemented'));
115
+ public getSnapshot(blockNumber: number): MerkleTreeReadOperations {
116
+ return new MerkleTreesFacade(this.instance, this.initialHeader!, worldStateRevision(false, 0, blockNumber));
262
117
  }
263
118
 
264
- async getStateReference(includeUncommitted: boolean): Promise<StateReference> {
265
- const resp = await this.call(WorldStateMessageType.GET_STATE_REFERENCE, {
266
- revision: worldStateRevision(includeUncommitted),
119
+ public async fork(blockNumber?: number): Promise<MerkleTreeWriteOperations> {
120
+ const resp = await this.instance.call(WorldStateMessageType.CREATE_FORK, {
121
+ latest: blockNumber === undefined,
122
+ blockNumber: blockNumber ?? 0,
267
123
  });
268
-
269
- return new StateReference(
270
- treeStateReferenceToSnapshot(resp.state[MerkleTreeId.L1_TO_L2_MESSAGE_TREE]),
271
- new PartialStateReference(
272
- treeStateReferenceToSnapshot(resp.state[MerkleTreeId.NOTE_HASH_TREE]),
273
- treeStateReferenceToSnapshot(resp.state[MerkleTreeId.NULLIFIER_TREE]),
274
- treeStateReferenceToSnapshot(resp.state[MerkleTreeId.PUBLIC_DATA_TREE]),
275
- ),
276
- );
124
+ return new MerkleTreesForkFacade(this.instance, this.initialHeader!, worldStateRevision(true, resp.forkId, 0));
277
125
  }
278
126
 
279
- async getTreeInfo(treeId: MerkleTreeId, includeUncommitted: boolean): Promise<TreeInfo> {
280
- const resp = await this.call(WorldStateMessageType.GET_TREE_INFO, {
281
- treeId: treeId,
282
- revision: worldStateRevision(includeUncommitted),
283
- });
284
-
285
- return {
286
- depth: resp.depth,
287
- root: resp.root,
288
- size: BigInt(resp.size),
289
- treeId,
290
- };
127
+ public getInitialHeader(): Header {
128
+ return this.initialHeader!;
291
129
  }
292
130
 
293
- async handleL2BlockAndMessages(l2Block: L2Block, l1ToL2Messages: Fr[]): Promise<HandleL2BlockAndMessagesResult> {
131
+ public async handleL2BlockAndMessages(l2Block: L2Block, l1ToL2Messages: Fr[]): Promise<WorldStateStatus> {
294
132
  // We have to pad both the tx effects and the values within tx effects because that's how the trees are built
295
133
  // by circuits.
296
134
  const paddedTxEffects = padArrayEnd(
@@ -321,142 +159,83 @@ export class NativeWorldStateService implements MerkleTreeDb {
321
159
  batchesOfPaddedPublicDataWrites.push(batch);
322
160
  }
323
161
 
324
- return await this.call(WorldStateMessageType.SYNC_BLOCK, {
325
- blockHash: l2Block.hash(),
162
+ const response = await this.instance.call(WorldStateMessageType.SYNC_BLOCK, {
163
+ blockNumber: l2Block.number,
164
+ blockHeaderHash: l2Block.header.hash(),
326
165
  paddedL1ToL2Messages: paddedL1ToL2Messages.map(serializeLeaf),
327
166
  paddedNoteHashes: paddedNoteHashes.map(serializeLeaf),
328
167
  paddedNullifiers: paddedNullifiers.map(serializeLeaf),
329
168
  batchesOfPaddedPublicDataWrites: batchesOfPaddedPublicDataWrites.map(batch => batch.map(serializeLeaf)),
330
169
  blockStateRef: blockStateReference(l2Block.header.state),
331
170
  });
171
+ return response.status;
332
172
  }
333
173
 
334
- async rollback(): Promise<void> {
335
- await this.call(WorldStateMessageType.ROLLBACK, void 0);
174
+ public async close(): Promise<void> {
175
+ await this.instance.close();
176
+ await this.cleanup();
336
177
  }
337
178
 
338
- async updateArchive(header: Header, _includeUncommitted: boolean): Promise<void> {
339
- await this.call(WorldStateMessageType.UPDATE_ARCHIVE, {
340
- blockHash: header.hash().toBuffer(),
341
- blockStateRef: blockStateReference(header.state),
342
- });
179
+ private async buildInitialHeader(): Promise<Header> {
180
+ const state = await this.getInitialStateReference();
181
+ return Header.empty({ state });
343
182
  }
344
183
 
345
- updateLeaf<ID extends IndexedTreeId>(
346
- _treeId: ID,
347
- _leaf: NullifierLeafPreimage | Buffer,
348
- _index: bigint,
349
- ): Promise<void> {
350
- return Promise.reject(new Error('Method not implemented'));
184
+ /**
185
+ * Advances the finalised block number to be the number provided
186
+ * @param toBlockNumber The block number that is now the tip of the finalised chain
187
+ * @returns The new WorldStateStatus
188
+ */
189
+ public async setFinalised(toBlockNumber: bigint) {
190
+ return await this.instance.call(WorldStateMessageType.FINALISE_BLOCKS, {
191
+ toBlockNumber,
192
+ });
351
193
  }
352
194
 
353
- private call<T extends WorldStateMessageType>(
354
- messageType: T,
355
- body: WorldStateRequest[T],
356
- ): Promise<WorldStateResponse[T]> {
357
- return this.queue.put(async () => {
358
- const request = new TypedMessage(messageType, new MessageHeader({ messageId: this.nextMessageId++ }), body);
359
-
360
- const encodedRequest = this.encoder.encode(request);
361
- const encodedResponse = await this.instance.call(encodedRequest);
362
-
363
- const buf = Buffer.isBuffer(encodedResponse)
364
- ? encodedResponse
365
- : isAnyArrayBuffer(encodedResponse)
366
- ? Buffer.from(encodedResponse)
367
- : encodedResponse;
368
-
369
- if (!Buffer.isBuffer(buf)) {
370
- throw new TypeError(
371
- 'Invalid encoded response: expected Buffer or ArrayBuffer, got ' +
372
- (encodedResponse === null ? 'null' : typeof encodedResponse),
373
- );
374
- }
375
-
376
- const decodedResponse = this.decoder.unpack(buf);
377
- if (!TypedMessage.isTypedMessageLike(decodedResponse)) {
378
- throw new TypeError(
379
- 'Invalid response: expected TypedMessageLike, got ' +
380
- (decodedResponse === null ? 'null' : typeof decodedResponse),
381
- );
382
- }
383
-
384
- const response = TypedMessage.fromMessagePack<T, WorldStateResponse[T]>(decodedResponse);
385
-
386
- if (response.header.requestId !== request.header.messageId) {
387
- throw new Error(
388
- 'Response ID does not match request: ' + response.header.requestId + ' != ' + request.header.messageId,
389
- );
390
- }
391
-
392
- if (response.msgType !== messageType) {
393
- throw new Error('Invalid response message type: ' + response.msgType + ' != ' + messageType);
394
- }
395
-
396
- return response.value;
195
+ /**
196
+ * Removes all historical snapshots up to but not including the given block number
197
+ * @param toBlockNumber The block number of the new oldest historical block
198
+ * @returns The new WorldStateStatus
199
+ */
200
+ public async removeHistoricalBlocks(toBlockNumber: bigint) {
201
+ return await this.instance.call(WorldStateMessageType.REMOVE_HISTORICAL_BLOCKS, {
202
+ toBlockNumber,
397
203
  });
398
204
  }
399
205
 
400
- public async stop(): Promise<void> {
401
- await this.queue.end();
206
+ /**
207
+ * Removes all pending blocks down to but not including the given block number
208
+ * @param toBlockNumber The block number of the new tip of the pending chain,
209
+ * @returns The new WorldStateStatus
210
+ */
211
+ public async unwindBlocks(toBlockNumber: bigint) {
212
+ return await this.instance.call(WorldStateMessageType.UNWIND_BLOCKS, {
213
+ toBlockNumber,
214
+ });
402
215
  }
403
216
 
404
- public delete(): Promise<void> {
405
- return Promise.reject(new Error('Method not implemented'));
217
+ public async getStatus() {
218
+ return await this.instance.call(WorldStateMessageType.GET_STATUS, void 0);
406
219
  }
407
220
 
408
- public fork(): Promise<MerkleTreeDb> {
221
+ updateLeaf<ID extends IndexedTreeId>(
222
+ _treeId: ID,
223
+ _leaf: NullifierLeafPreimage | Buffer,
224
+ _index: bigint,
225
+ ): Promise<void> {
409
226
  return Promise.reject(new Error('Method not implemented'));
410
227
  }
411
- }
412
-
413
- function hydrateLeaf<ID extends MerkleTreeId>(treeId: ID, leaf: Fr | Buffer) {
414
- if (leaf instanceof Fr) {
415
- return leaf;
416
- } else if (treeId === MerkleTreeId.NULLIFIER_TREE) {
417
- return NullifierLeaf.fromBuffer(leaf);
418
- } else if (treeId === MerkleTreeId.PUBLIC_DATA_TREE) {
419
- return PublicDataTreeLeaf.fromBuffer(leaf);
420
- } else {
421
- return Fr.fromBuffer(leaf);
422
- }
423
- }
424
-
425
- function serializeLeaf(leaf: Fr | NullifierLeaf | PublicDataTreeLeaf): SerializedLeafValue {
426
- if (leaf instanceof Fr) {
427
- return leaf.toBuffer();
428
- } else if (leaf instanceof NullifierLeaf) {
429
- return { value: leaf.nullifier.toBuffer() };
430
- } else {
431
- return { value: leaf.value.toBuffer(), slot: leaf.slot.toBuffer() };
432
- }
433
- }
434
228
 
435
- function deserializeLeafValue(leaf: SerializedLeafValue): Fr | NullifierLeaf | PublicDataTreeLeaf {
436
- if (Buffer.isBuffer(leaf)) {
437
- return Fr.fromBuffer(leaf);
438
- } else if ('slot' in leaf) {
439
- return new PublicDataTreeLeaf(Fr.fromBuffer(leaf.slot), Fr.fromBuffer(leaf.value));
440
- } else {
441
- return new NullifierLeaf(Fr.fromBuffer(leaf.value));
442
- }
443
- }
229
+ private async getInitialStateReference(): Promise<StateReference> {
230
+ const resp = await this.instance.call(WorldStateMessageType.GET_INITIAL_STATE_REFERENCE, void 0);
444
231
 
445
- function deserializeIndexedLeaf(leaf: SerializedIndexedLeaf): IndexedTreeLeafPreimage {
446
- if ('slot' in leaf.value) {
447
- return new PublicDataTreeLeafPreimage(
448
- Fr.fromBuffer(leaf.value.slot),
449
- Fr.fromBuffer(leaf.value.value),
450
- Fr.fromBuffer(leaf.nextValue),
451
- BigInt(leaf.nextIndex),
452
- );
453
- } else if ('value' in leaf.value) {
454
- return new NullifierLeafPreimage(
455
- Fr.fromBuffer(leaf.value.value),
456
- Fr.fromBuffer(leaf.nextValue),
457
- BigInt(leaf.nextIndex),
232
+ return new StateReference(
233
+ treeStateReferenceToSnapshot(resp.state[MerkleTreeId.L1_TO_L2_MESSAGE_TREE]),
234
+ new PartialStateReference(
235
+ treeStateReferenceToSnapshot(resp.state[MerkleTreeId.NOTE_HASH_TREE]),
236
+ treeStateReferenceToSnapshot(resp.state[MerkleTreeId.NULLIFIER_TREE]),
237
+ treeStateReferenceToSnapshot(resp.state[MerkleTreeId.PUBLIC_DATA_TREE]),
238
+ ),
458
239
  );
459
- } else {
460
- throw new Error('Invalid leaf type');
461
240
  }
462
241
  }