@aztec/world-state 0.0.1-commit.001888fc → 0.0.1-commit.017a351
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.
- package/dest/native/ipc_world_state_instance.d.ts +45 -0
- package/dest/native/ipc_world_state_instance.d.ts.map +1 -0
- package/dest/native/ipc_world_state_instance.js +750 -0
- package/dest/native/merkle_trees_facade.d.ts +8 -4
- package/dest/native/merkle_trees_facade.d.ts.map +1 -1
- package/dest/native/merkle_trees_facade.js +34 -15
- package/dest/native/message.d.ts +7 -8
- package/dest/native/message.d.ts.map +1 -1
- package/dest/native/native_world_state.d.ts +19 -7
- package/dest/native/native_world_state.d.ts.map +1 -1
- package/dest/native/native_world_state.js +89 -24
- package/dest/native/native_world_state_instance.d.ts +21 -39
- package/dest/native/native_world_state_instance.d.ts.map +1 -1
- package/dest/native/native_world_state_instance.js +8 -202
- package/dest/native/world_state_ops_queue.js +5 -5
- package/dest/synchronizer/config.d.ts +1 -1
- package/dest/synchronizer/config.d.ts.map +1 -1
- package/dest/synchronizer/config.js +9 -10
- package/dest/synchronizer/factory.d.ts +4 -4
- package/dest/synchronizer/factory.d.ts.map +1 -1
- package/dest/synchronizer/factory.js +7 -6
- package/dest/synchronizer/server_world_state_synchronizer.d.ts +1 -1
- package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
- package/dest/synchronizer/server_world_state_synchronizer.js +40 -11
- package/dest/testing.d.ts +4 -3
- package/dest/testing.d.ts.map +1 -1
- package/dest/testing.js +10 -6
- package/package.json +13 -10
- package/src/native/ipc_world_state_instance.ts +863 -0
- package/src/native/merkle_trees_facade.ts +41 -19
- package/src/native/message.ts +6 -7
- package/src/native/native_world_state.ts +98 -35
- package/src/native/native_world_state_instance.ts +28 -276
- package/src/native/world_state_ops_queue.ts +5 -5
- package/src/synchronizer/config.ts +14 -10
- package/src/synchronizer/factory.ts +11 -10
- package/src/synchronizer/server_world_state_synchronizer.ts +35 -13
- package/src/testing.ts +8 -9
|
@@ -4,6 +4,7 @@ import { createLogger } from '@aztec/foundation/log';
|
|
|
4
4
|
import { serializeToBuffer } from '@aztec/foundation/serialize';
|
|
5
5
|
import { sleep } from '@aztec/foundation/sleep';
|
|
6
6
|
import { type IndexedTreeLeafPreimage, SiblingPath } from '@aztec/foundation/trees';
|
|
7
|
+
import { BlockHash } from '@aztec/stdlib/block';
|
|
7
8
|
import type {
|
|
8
9
|
BatchInsertionResult,
|
|
9
10
|
IndexedTreeId,
|
|
@@ -21,7 +22,7 @@ import {
|
|
|
21
22
|
PublicDataTreeLeafPreimage,
|
|
22
23
|
} from '@aztec/stdlib/trees';
|
|
23
24
|
import { type BlockHeader, PartialStateReference, StateReference } from '@aztec/stdlib/tx';
|
|
24
|
-
import {
|
|
25
|
+
import type { WorldStateRevision } from '@aztec/stdlib/world-state';
|
|
25
26
|
|
|
26
27
|
import assert from 'assert';
|
|
27
28
|
|
|
@@ -45,8 +46,12 @@ export class MerkleTreesFacade implements MerkleTreeReadOperations {
|
|
|
45
46
|
return this.initialHeader;
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
getRevision():
|
|
49
|
-
return
|
|
49
|
+
getRevision(): WorldStateRevision {
|
|
50
|
+
return this.revision;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
getSocketPath(): string {
|
|
54
|
+
return this.instance.getSocketPath();
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
findLeafIndices(treeId: MerkleTreeId, values: MerkleTreeLeafType<MerkleTreeId>[]): Promise<(bigint | undefined)[]> {
|
|
@@ -118,7 +123,7 @@ export class MerkleTreesFacade implements MerkleTreeReadOperations {
|
|
|
118
123
|
|
|
119
124
|
const leaf = deserializeLeafValue(resp);
|
|
120
125
|
if (leaf instanceof Fr) {
|
|
121
|
-
return leaf as any;
|
|
126
|
+
return treeId === MerkleTreeId.ARCHIVE ? (new BlockHash(leaf) as any) : (leaf as any);
|
|
122
127
|
} else {
|
|
123
128
|
return leaf.toBuffer() as any;
|
|
124
129
|
}
|
|
@@ -207,6 +212,7 @@ export class MerkleTreesFacade implements MerkleTreeReadOperations {
|
|
|
207
212
|
|
|
208
213
|
export class MerkleTreesForkFacade extends MerkleTreesFacade implements MerkleTreeWriteOperations {
|
|
209
214
|
private log = createLogger('world-state:merkle-trees-fork-facade');
|
|
215
|
+
private closePromise: Promise<void> | undefined;
|
|
210
216
|
|
|
211
217
|
constructor(
|
|
212
218
|
instance: NativeWorldStateInstance,
|
|
@@ -228,7 +234,7 @@ export class MerkleTreesForkFacade extends MerkleTreesFacade implements MerkleTr
|
|
|
228
234
|
|
|
229
235
|
async appendLeaves<ID extends MerkleTreeId>(treeId: ID, leaves: MerkleTreeLeafType<ID>[]): Promise<void> {
|
|
230
236
|
await this.instance.call(WorldStateMessageType.APPEND_LEAVES, {
|
|
231
|
-
leaves: leaves.map(leaf => leaf as any),
|
|
237
|
+
leaves: leaves.map(leaf => serializeLeaf(hydrateLeaf(treeId, leaf as any))),
|
|
232
238
|
forkId: this.revision.forkId,
|
|
233
239
|
treeId,
|
|
234
240
|
});
|
|
@@ -249,15 +255,15 @@ export class MerkleTreesForkFacade extends MerkleTreesFacade implements MerkleTr
|
|
|
249
255
|
|
|
250
256
|
return {
|
|
251
257
|
newSubtreeSiblingPath: new SiblingPath<SubtreeSiblingPathHeight>(
|
|
252
|
-
resp.
|
|
253
|
-
resp.
|
|
258
|
+
resp.subtreePath.length as any,
|
|
259
|
+
resp.subtreePath,
|
|
254
260
|
),
|
|
255
|
-
sortedNewLeaves: resp.
|
|
261
|
+
sortedNewLeaves: resp.sortedLeaves
|
|
256
262
|
.map(([leaf]) => leaf)
|
|
257
263
|
.map(deserializeLeafValue)
|
|
258
264
|
.map(serializeToBuffer),
|
|
259
|
-
sortedNewLeavesIndexes: resp.
|
|
260
|
-
lowLeavesWitnessData: resp.
|
|
265
|
+
sortedNewLeavesIndexes: resp.sortedLeaves.map(([, index]) => index),
|
|
266
|
+
lowLeavesWitnessData: resp.lowLeafWitnessData.map(data => ({
|
|
261
267
|
index: BigInt(data.index),
|
|
262
268
|
leafPreimage: deserializeIndexedLeaf(data.leaf),
|
|
263
269
|
siblingPath: new SiblingPath<TreeHeight>(data.path.length as any, data.path),
|
|
@@ -277,12 +283,12 @@ export class MerkleTreesForkFacade extends MerkleTreesFacade implements MerkleTr
|
|
|
277
283
|
});
|
|
278
284
|
|
|
279
285
|
return {
|
|
280
|
-
lowLeavesWitnessData: resp.
|
|
286
|
+
lowLeavesWitnessData: resp.lowLeafWitnessData.map(data => ({
|
|
281
287
|
index: BigInt(data.index),
|
|
282
288
|
leafPreimage: deserializeIndexedLeaf(data.leaf),
|
|
283
289
|
siblingPath: new SiblingPath<TreeHeight>(data.path.length as any, data.path),
|
|
284
290
|
})),
|
|
285
|
-
insertionWitnessData: resp.
|
|
291
|
+
insertionWitnessData: resp.insertionWitnessData.map(data => ({
|
|
286
292
|
index: BigInt(data.index),
|
|
287
293
|
leafPreimage: deserializeIndexedLeaf(data.leaf),
|
|
288
294
|
siblingPath: new SiblingPath<TreeHeight>(data.path.length as any, data.path),
|
|
@@ -290,8 +296,17 @@ export class MerkleTreesForkFacade extends MerkleTreesFacade implements MerkleTr
|
|
|
290
296
|
};
|
|
291
297
|
}
|
|
292
298
|
|
|
293
|
-
public
|
|
299
|
+
public close(): Promise<void> {
|
|
294
300
|
assert.notEqual(this.revision.forkId, 0, 'Fork ID must be set');
|
|
301
|
+
// Share the in-flight close promise across duplicate dispose calls so DELETE_FORK is sent at most once.
|
|
302
|
+
if (this.closePromise) {
|
|
303
|
+
return this.closePromise;
|
|
304
|
+
}
|
|
305
|
+
this.closePromise = this.doClose();
|
|
306
|
+
return this.closePromise;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
private async doClose(): Promise<void> {
|
|
295
310
|
try {
|
|
296
311
|
await this.instance.call(WorldStateMessageType.DELETE_FORK, { forkId: this.revision.forkId });
|
|
297
312
|
} catch (err: any) {
|
|
@@ -300,6 +315,12 @@ export class MerkleTreesForkFacade extends MerkleTreesFacade implements MerkleTr
|
|
|
300
315
|
if (err?.message === 'Native instance is closed') {
|
|
301
316
|
return;
|
|
302
317
|
}
|
|
318
|
+
// Ignore "Fork not found": the native fork was already destroyed by a pending-chain unwind or a
|
|
319
|
+
// historical prune (both call C++ remove_forks_for_block). Fork IDs are monotonic and never reused,
|
|
320
|
+
// so swallowing this on close cannot mask a deletion of a different fork.
|
|
321
|
+
if (err?.message === 'Fork not found') {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
303
324
|
throw err;
|
|
304
325
|
}
|
|
305
326
|
}
|
|
@@ -309,9 +330,6 @@ export class MerkleTreesForkFacade extends MerkleTreesFacade implements MerkleTr
|
|
|
309
330
|
void sleep(this.opts.closeDelayMs)
|
|
310
331
|
.then(() => this.close())
|
|
311
332
|
.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
333
|
this.log.warn('Error closing MerkleTreesForkFacade after delay', { err });
|
|
316
334
|
});
|
|
317
335
|
} else {
|
|
@@ -352,9 +370,11 @@ export class MerkleTreesForkFacade extends MerkleTreesFacade implements MerkleTr
|
|
|
352
370
|
}
|
|
353
371
|
}
|
|
354
372
|
|
|
355
|
-
function hydrateLeaf
|
|
373
|
+
function hydrateLeaf(treeId: MerkleTreeId, leaf: Fr | BlockHash | Buffer) {
|
|
356
374
|
if (leaf instanceof Fr) {
|
|
357
375
|
return leaf;
|
|
376
|
+
} else if (leaf instanceof BlockHash) {
|
|
377
|
+
return leaf.toFr();
|
|
358
378
|
} else if (treeId === MerkleTreeId.NULLIFIER_TREE) {
|
|
359
379
|
return NullifierLeaf.fromBuffer(leaf);
|
|
360
380
|
} else if (treeId === MerkleTreeId.PUBLIC_DATA_TREE) {
|
|
@@ -364,8 +384,10 @@ function hydrateLeaf<ID extends MerkleTreeId>(treeId: ID, leaf: Fr | Buffer) {
|
|
|
364
384
|
}
|
|
365
385
|
}
|
|
366
386
|
|
|
367
|
-
export function serializeLeaf(leaf: Fr | NullifierLeaf | PublicDataTreeLeaf): SerializedLeafValue {
|
|
368
|
-
if (leaf instanceof
|
|
387
|
+
export function serializeLeaf(leaf: Fr | BlockHash | NullifierLeaf | PublicDataTreeLeaf): SerializedLeafValue {
|
|
388
|
+
if (leaf instanceof BlockHash) {
|
|
389
|
+
return leaf.toBuffer();
|
|
390
|
+
} else if (leaf instanceof Fr) {
|
|
369
391
|
return leaf.toBuffer();
|
|
370
392
|
} else if (leaf instanceof NullifierLeaf) {
|
|
371
393
|
return { nullifier: leaf.nullifier.toBuffer() };
|
package/src/native/message.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
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';
|
|
5
4
|
import { AppendOnlyTreeSnapshot, MerkleTreeId } from '@aztec/stdlib/trees';
|
|
6
5
|
import type { StateReference } from '@aztec/stdlib/tx';
|
|
7
6
|
import type { UInt32 } from '@aztec/stdlib/types';
|
|
@@ -391,24 +390,24 @@ interface BatchInsertRequest extends WithTreeId, WithForkId, WithLeaves {
|
|
|
391
390
|
}
|
|
392
391
|
|
|
393
392
|
interface BatchInsertResponse {
|
|
394
|
-
|
|
393
|
+
lowLeafWitnessData: ReadonlyArray<{
|
|
395
394
|
leaf: SerializedIndexedLeaf;
|
|
396
395
|
index: bigint | number;
|
|
397
396
|
path: Tuple<Buffer, number>;
|
|
398
397
|
}>;
|
|
399
|
-
|
|
400
|
-
|
|
398
|
+
sortedLeaves: ReadonlyArray<[SerializedLeafValue, UInt32]>;
|
|
399
|
+
subtreePath: Tuple<Buffer, number>;
|
|
401
400
|
}
|
|
402
401
|
|
|
403
402
|
interface SequentialInsertRequest extends WithTreeId, WithForkId, WithLeaves {}
|
|
404
403
|
|
|
405
404
|
interface SequentialInsertResponse {
|
|
406
|
-
|
|
405
|
+
lowLeafWitnessData: ReadonlyArray<{
|
|
407
406
|
leaf: SerializedIndexedLeaf;
|
|
408
407
|
index: bigint | number;
|
|
409
408
|
path: Tuple<Buffer, number>;
|
|
410
409
|
}>;
|
|
411
|
-
|
|
410
|
+
insertionWitnessData: ReadonlyArray<{
|
|
412
411
|
leaf: SerializedIndexedLeaf;
|
|
413
412
|
index: bigint | number;
|
|
414
413
|
path: Tuple<Buffer, number>;
|
|
@@ -423,7 +422,7 @@ interface UpdateArchiveRequest extends WithForkId {
|
|
|
423
422
|
interface SyncBlockRequest extends WithCanonicalForkId {
|
|
424
423
|
blockNumber: BlockNumber;
|
|
425
424
|
blockStateRef: BlockStateReference;
|
|
426
|
-
blockHeaderHash:
|
|
425
|
+
blockHeaderHash: Buffer;
|
|
427
426
|
paddedNoteHashes: readonly SerializedLeafValue[];
|
|
428
427
|
paddedL1ToL2Messages: readonly SerializedLeafValue[];
|
|
429
428
|
paddedNullifiers: readonly SerializedLeafValue[];
|
|
@@ -3,7 +3,6 @@ import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
|
3
3
|
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
|
-
import { tryRmDir } from '@aztec/foundation/fs';
|
|
7
6
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
8
7
|
import type { L2Block } from '@aztec/stdlib/block';
|
|
9
8
|
import { DatabaseVersionManager } from '@aztec/stdlib/database-version/manager';
|
|
@@ -14,18 +13,19 @@ import type {
|
|
|
14
13
|
} from '@aztec/stdlib/interfaces/server';
|
|
15
14
|
import type { SnapshotDataKeys } from '@aztec/stdlib/snapshots';
|
|
16
15
|
import { MerkleTreeId, NullifierLeaf, type NullifierLeafPreimage, PublicDataTreeLeaf } from '@aztec/stdlib/trees';
|
|
17
|
-
import { BlockHeader, PartialStateReference, StateReference } from '@aztec/stdlib/tx';
|
|
18
|
-
import { WorldStateRevision } from '@aztec/stdlib/world-state';
|
|
16
|
+
import { BlockHeader, GlobalVariables, PartialStateReference, StateReference } from '@aztec/stdlib/tx';
|
|
17
|
+
import { EMPTY_GENESIS_DATA, type GenesisData, WorldStateRevision } from '@aztec/stdlib/world-state';
|
|
19
18
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
20
19
|
|
|
21
20
|
import assert from 'assert/strict';
|
|
22
|
-
import { mkdtemp, rm } from 'fs/promises';
|
|
21
|
+
import { mkdir, mkdtemp, rm } from 'fs/promises';
|
|
23
22
|
import { tmpdir } from 'os';
|
|
24
23
|
import { join } from 'path';
|
|
25
24
|
|
|
26
25
|
import { WorldStateInstrumentation } from '../instrumentation/instrumentation.js';
|
|
27
26
|
import type { WorldStateTreeMapSizes } from '../synchronizer/factory.js';
|
|
28
27
|
import type { MerkleTreeAdminDatabase as MerkleTreeDatabase } from '../world-state-db/merkle_tree_db.js';
|
|
28
|
+
import { IpcWorldState } from './ipc_world_state_instance.js';
|
|
29
29
|
import { MerkleTreesFacade, MerkleTreesForkFacade, serializeLeaf } from './merkle_trees_facade.js';
|
|
30
30
|
import {
|
|
31
31
|
WorldStateMessageType,
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
sanitizeSummary,
|
|
37
37
|
treeStateReferenceToSnapshot,
|
|
38
38
|
} from './message.js';
|
|
39
|
-
import {
|
|
39
|
+
import type { NativeWorldStateInstance } from './native_world_state_instance.js';
|
|
40
40
|
|
|
41
41
|
// The current version of the world state database schema
|
|
42
42
|
// Increment this when making incompatible changes to the database schema
|
|
@@ -50,37 +50,49 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
50
50
|
private cachedStatusSummary: WorldStateStatusSummary | undefined;
|
|
51
51
|
|
|
52
52
|
protected constructor(
|
|
53
|
-
protected instance:
|
|
53
|
+
protected instance: NativeWorldStateInstance,
|
|
54
54
|
protected readonly worldStateInstrumentation: WorldStateInstrumentation,
|
|
55
55
|
protected readonly log: Logger,
|
|
56
|
+
private readonly genesis: GenesisData = EMPTY_GENESIS_DATA,
|
|
56
57
|
private readonly cleanup = () => Promise.resolve(),
|
|
58
|
+
/** Factory to recreate a fresh IpcWorldState after clear(). */
|
|
59
|
+
private readonly recreateInstance?: () => Promise<NativeWorldStateInstance>,
|
|
57
60
|
) {}
|
|
58
61
|
|
|
59
62
|
static async new(
|
|
60
63
|
rollupAddress: EthAddress,
|
|
61
64
|
dataDir: string,
|
|
62
65
|
wsTreeMapSizes: WorldStateTreeMapSizes,
|
|
63
|
-
|
|
66
|
+
genesis: GenesisData = EMPTY_GENESIS_DATA,
|
|
64
67
|
instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
65
68
|
bindings?: LoggerBindings,
|
|
66
69
|
cleanup = () => Promise.resolve(),
|
|
67
70
|
): Promise<NativeWorldStateService> {
|
|
71
|
+
for (const [key, value] of Object.entries(wsTreeMapSizes)) {
|
|
72
|
+
if (value <= 0) {
|
|
73
|
+
throw new Error(`Map size must be a positive number, got ${value} for ${key}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
68
77
|
const log = createLogger('world-state:database', bindings);
|
|
69
78
|
const worldStateDirectory = join(dataDir, WORLD_STATE_DIR);
|
|
70
|
-
|
|
79
|
+
|
|
71
80
|
const versionManager = new DatabaseVersionManager({
|
|
72
81
|
schemaVersion: WORLD_STATE_DB_VERSION,
|
|
73
82
|
rollupAddress,
|
|
74
83
|
dataDirectory: worldStateDirectory,
|
|
75
|
-
onOpen: (dir
|
|
76
|
-
return Promise.resolve(
|
|
77
|
-
new NativeWorldState(dir, wsTreeMapSizes, prefilledPublicData, instrumentation, bindings),
|
|
78
|
-
);
|
|
79
|
-
},
|
|
84
|
+
onOpen: dir => IpcWorldState.spawn(dir, wsTreeMapSizes, genesis, instrumentation, bindings),
|
|
80
85
|
});
|
|
81
86
|
|
|
82
87
|
const [instance] = await versionManager.open();
|
|
83
|
-
|
|
88
|
+
|
|
89
|
+
const recreateInstance = async () => {
|
|
90
|
+
await rm(worldStateDirectory, { recursive: true, force: true, maxRetries: 3 });
|
|
91
|
+
await mkdir(worldStateDirectory, { recursive: true });
|
|
92
|
+
return IpcWorldState.spawn(worldStateDirectory, wsTreeMapSizes, genesis, instrumentation, bindings);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const worldState = new this(instance, instrumentation, log, genesis, cleanup, recreateInstance);
|
|
84
96
|
try {
|
|
85
97
|
await worldState.init();
|
|
86
98
|
} catch (e) {
|
|
@@ -92,9 +104,8 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
92
104
|
}
|
|
93
105
|
|
|
94
106
|
static async tmp(
|
|
95
|
-
rollupAddress = EthAddress.ZERO,
|
|
96
107
|
cleanupTmpDir = true,
|
|
97
|
-
|
|
108
|
+
genesis: GenesisData = EMPTY_GENESIS_DATA,
|
|
98
109
|
instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
99
110
|
bindings?: LoggerBindings,
|
|
100
111
|
): Promise<NativeWorldStateService> {
|
|
@@ -110,7 +121,8 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
110
121
|
};
|
|
111
122
|
log.debug(`Created temporary world state database at: ${dataDir} with tree map size: ${dbMapSizeKb}`);
|
|
112
123
|
|
|
113
|
-
|
|
124
|
+
const instance = await IpcWorldState.spawn(dataDir, worldStateTreeMapSizes, genesis, instrumentation, bindings);
|
|
125
|
+
|
|
114
126
|
const cleanup = async () => {
|
|
115
127
|
if (cleanupTmpDir) {
|
|
116
128
|
await rm(dataDir, { recursive: true, force: true, maxRetries: 3 });
|
|
@@ -120,15 +132,43 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
120
132
|
}
|
|
121
133
|
};
|
|
122
134
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
dataDir,
|
|
126
|
-
worldStateTreeMapSizes,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
135
|
+
const recreateInstance = async () => {
|
|
136
|
+
await rm(dataDir, { recursive: true, force: true, maxRetries: 3 });
|
|
137
|
+
await mkdir(dataDir, { recursive: true });
|
|
138
|
+
return IpcWorldState.spawn(dataDir, worldStateTreeMapSizes, genesis, instrumentation, bindings);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const worldState = new this(instance, instrumentation, log, genesis, cleanup, recreateInstance);
|
|
142
|
+
try {
|
|
143
|
+
await worldState.init();
|
|
144
|
+
} catch (e) {
|
|
145
|
+
log.error(`Error initializing tmp world state: ${e}`);
|
|
146
|
+
throw e;
|
|
147
|
+
}
|
|
148
|
+
return worldState;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static ephemeral(
|
|
152
|
+
genesis: GenesisData = EMPTY_GENESIS_DATA,
|
|
153
|
+
instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
154
|
+
bindings?: LoggerBindings,
|
|
155
|
+
): Promise<NativeWorldStateService> {
|
|
156
|
+
return this.tmp(/*cleanupTmpDir=*/ true, genesis, instrumentation, bindings);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
static async fromIpc(
|
|
160
|
+
wsdbBackend: ConstructorParameters<typeof IpcWorldState>[0],
|
|
161
|
+
instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
162
|
+
bindings?: LoggerBindings,
|
|
163
|
+
genesis: GenesisData = EMPTY_GENESIS_DATA,
|
|
164
|
+
cleanup = () => Promise.resolve(),
|
|
165
|
+
recreateInstance?: () => Promise<NativeWorldStateInstance>,
|
|
166
|
+
): Promise<NativeWorldStateService> {
|
|
167
|
+
const log = createLogger('world-state:database', bindings);
|
|
168
|
+
const instance = new IpcWorldState(wsdbBackend, instrumentation, bindings);
|
|
169
|
+
const worldState = new this(instance, instrumentation, log, genesis, cleanup, recreateInstance);
|
|
170
|
+
await worldState.init();
|
|
171
|
+
return worldState;
|
|
132
172
|
}
|
|
133
173
|
|
|
134
174
|
protected async init() {
|
|
@@ -147,16 +187,29 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
147
187
|
|
|
148
188
|
// the initial header _must_ be the first element in the archive tree
|
|
149
189
|
// if this assertion fails, check that the hashing done in Header in yarn-project matches the initial header hash done in world_state.cpp
|
|
150
|
-
const indices = await committed.findLeafIndices(MerkleTreeId.ARCHIVE, [
|
|
190
|
+
const indices = await committed.findLeafIndices(MerkleTreeId.ARCHIVE, [await this.initialHeader.hash()]);
|
|
151
191
|
const initialHeaderIndex = indices[0];
|
|
152
192
|
assert.strictEqual(initialHeaderIndex, 0n, 'Invalid initial archive state');
|
|
153
193
|
}
|
|
154
194
|
|
|
155
|
-
public async clear() {
|
|
195
|
+
public async clear(): Promise<void> {
|
|
196
|
+
if (!this.recreateInstance) {
|
|
197
|
+
throw new Error('clear() is not available for externally-managed IPC backends');
|
|
198
|
+
}
|
|
199
|
+
this.log.warn('Clearing world state: shutting down WSDB, deleting data, and recreating');
|
|
156
200
|
await this.instance.close();
|
|
157
201
|
this.cachedStatusSummary = undefined;
|
|
158
|
-
|
|
159
|
-
|
|
202
|
+
this.instance = await this.recreateInstance();
|
|
203
|
+
await this.init();
|
|
204
|
+
this.log.info('World state cleared and reinitialized from genesis');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Returns the socket path of the underlying IPC backend, if available. */
|
|
208
|
+
public getSocketPath(): string {
|
|
209
|
+
if (this.instance instanceof IpcWorldState) {
|
|
210
|
+
return this.instance.getSocketPath();
|
|
211
|
+
}
|
|
212
|
+
throw new Error('getSocketPath() is only available with IPC world state');
|
|
160
213
|
}
|
|
161
214
|
|
|
162
215
|
public getCommitted(): MerkleTreeReadOperations {
|
|
@@ -185,7 +238,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
185
238
|
this.initialHeader!,
|
|
186
239
|
new WorldStateRevision(
|
|
187
240
|
/*forkId=*/ resp.forkId,
|
|
188
|
-
/* blockNumber=*/
|
|
241
|
+
/* blockNumber=*/ WorldStateRevision.LATEST,
|
|
189
242
|
/* includeUncommitted=*/ true,
|
|
190
243
|
),
|
|
191
244
|
opts,
|
|
@@ -232,7 +285,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
232
285
|
WorldStateMessageType.SYNC_BLOCK,
|
|
233
286
|
{
|
|
234
287
|
blockNumber: l2Block.number,
|
|
235
|
-
blockHeaderHash: await l2Block.hash(),
|
|
288
|
+
blockHeaderHash: (await l2Block.hash()).toBuffer(),
|
|
236
289
|
paddedL1ToL2Messages: paddedL1ToL2Messages.map(serializeLeaf),
|
|
237
290
|
paddedNoteHashes: paddedNoteHashes.map(serializeLeaf),
|
|
238
291
|
paddedNullifiers: paddedNullifiers.map(serializeLeaf),
|
|
@@ -250,13 +303,23 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
250
303
|
}
|
|
251
304
|
|
|
252
305
|
public async close(): Promise<void> {
|
|
253
|
-
|
|
254
|
-
|
|
306
|
+
try {
|
|
307
|
+
await this.instance.close();
|
|
308
|
+
} finally {
|
|
309
|
+
await this.cleanup();
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
async [Symbol.asyncDispose](): Promise<void> {
|
|
314
|
+
await this.close();
|
|
255
315
|
}
|
|
256
316
|
|
|
257
317
|
private async buildInitialHeader(): Promise<BlockHeader> {
|
|
258
318
|
const state = await this.getInitialStateReference();
|
|
259
|
-
return BlockHeader.empty({
|
|
319
|
+
return BlockHeader.empty({
|
|
320
|
+
state,
|
|
321
|
+
globalVariables: GlobalVariables.empty({ timestamp: this.genesis.genesisTimestamp }),
|
|
322
|
+
});
|
|
260
323
|
}
|
|
261
324
|
|
|
262
325
|
private sanitizeAndCacheSummaryFromFull(response: WorldStateStatusFull) {
|