@aztec/world-state 0.0.0-test.1 → 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/index.d.ts +1 -1
- package/dest/instrumentation/instrumentation.d.ts +6 -4
- package/dest/instrumentation/instrumentation.d.ts.map +1 -1
- package/dest/instrumentation/instrumentation.js +25 -41
- package/dest/native/bench_metrics.d.ts +23 -0
- package/dest/native/bench_metrics.d.ts.map +1 -0
- package/dest/native/bench_metrics.js +81 -0
- package/dest/native/fork_checkpoint.d.ts +7 -1
- package/dest/native/fork_checkpoint.d.ts.map +1 -1
- package/dest/native/fork_checkpoint.js +15 -3
- package/dest/native/index.d.ts +1 -1
- 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 +25 -9
- package/dest/native/merkle_trees_facade.d.ts.map +1 -1
- package/dest/native/merkle_trees_facade.js +109 -25
- package/dest/native/message.d.ts +87 -58
- package/dest/native/message.d.ts.map +1 -1
- package/dest/native/message.js +61 -61
- package/dest/native/native_world_state.d.ts +41 -21
- package/dest/native/native_world_state.d.ts.map +1 -1
- package/dest/native/native_world_state.js +177 -50
- package/dest/native/native_world_state_instance.d.ts +23 -25
- package/dest/native/native_world_state_instance.d.ts.map +1 -1
- package/dest/native/native_world_state_instance.js +8 -163
- package/dest/native/world_state_ops_queue.d.ts +1 -1
- package/dest/native/world_state_ops_queue.d.ts.map +1 -1
- package/dest/native/world_state_ops_queue.js +6 -6
- package/dest/synchronizer/config.d.ts +14 -6
- package/dest/synchronizer/config.d.ts.map +1 -1
- package/dest/synchronizer/config.js +36 -14
- package/dest/synchronizer/errors.d.ts +4 -0
- package/dest/synchronizer/errors.d.ts.map +1 -0
- package/dest/synchronizer/errors.js +5 -0
- package/dest/synchronizer/factory.d.ts +13 -5
- package/dest/synchronizer/factory.d.ts.map +1 -1
- package/dest/synchronizer/factory.js +15 -9
- package/dest/synchronizer/index.d.ts +1 -1
- package/dest/synchronizer/server_world_state_synchronizer.d.ts +21 -31
- package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
- package/dest/synchronizer/server_world_state_synchronizer.js +220 -96
- package/dest/test/index.d.ts +1 -1
- package/dest/test/utils.d.ts +12 -5
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +54 -47
- package/dest/testing.d.ts +6 -5
- package/dest/testing.d.ts.map +1 -1
- package/dest/testing.js +15 -15
- package/dest/world-state-db/index.d.ts +1 -1
- package/dest/world-state-db/merkle_tree_db.d.ts +12 -18
- package/dest/world-state-db/merkle_tree_db.d.ts.map +1 -1
- package/package.json +27 -25
- package/src/instrumentation/instrumentation.ts +31 -43
- package/src/native/bench_metrics.ts +91 -0
- package/src/native/fork_checkpoint.ts +19 -3
- package/src/native/ipc_world_state_instance.ts +863 -0
- package/src/native/merkle_trees_facade.ts +127 -33
- package/src/native/message.ts +109 -80
- package/src/native/native_world_state.ts +207 -64
- package/src/native/native_world_state_instance.ts +28 -223
- package/src/native/world_state_ops_queue.ts +6 -6
- package/src/synchronizer/config.ts +58 -20
- package/src/synchronizer/errors.ts +5 -0
- package/src/synchronizer/factory.ts +48 -18
- package/src/synchronizer/server_world_state_synchronizer.ts +249 -121
- package/src/test/utils.ts +92 -82
- package/src/testing.ts +11 -16
- package/src/world-state-db/merkle_tree_db.ts +16 -18
|
@@ -1,42 +1,48 @@
|
|
|
1
1
|
import { MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
|
|
2
|
-
import {
|
|
2
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { fromEntries, padArrayEnd } from '@aztec/foundation/collection';
|
|
4
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
|
-
import {
|
|
5
|
-
import { createLogger } from '@aztec/foundation/log';
|
|
6
|
+
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
6
7
|
import type { L2Block } from '@aztec/stdlib/block';
|
|
7
|
-
import { DatabaseVersionManager } from '@aztec/stdlib/database-version';
|
|
8
|
+
import { DatabaseVersionManager } from '@aztec/stdlib/database-version/manager';
|
|
8
9
|
import type {
|
|
9
10
|
IndexedTreeId,
|
|
10
11
|
MerkleTreeReadOperations,
|
|
11
12
|
MerkleTreeWriteOperations,
|
|
12
13
|
} from '@aztec/stdlib/interfaces/server';
|
|
14
|
+
import type { SnapshotDataKeys } from '@aztec/stdlib/snapshots';
|
|
13
15
|
import { MerkleTreeId, NullifierLeaf, type NullifierLeafPreimage, PublicDataTreeLeaf } from '@aztec/stdlib/trees';
|
|
14
|
-
import { BlockHeader, PartialStateReference, StateReference } from '@aztec/stdlib/tx';
|
|
16
|
+
import { BlockHeader, GlobalVariables, PartialStateReference, StateReference } from '@aztec/stdlib/tx';
|
|
17
|
+
import { EMPTY_GENESIS_DATA, type GenesisData, WorldStateRevision } from '@aztec/stdlib/world-state';
|
|
15
18
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
16
19
|
|
|
17
20
|
import assert from 'assert/strict';
|
|
18
|
-
import { mkdtemp, rm } from 'fs/promises';
|
|
21
|
+
import { mkdir, mkdtemp, rm } from 'fs/promises';
|
|
19
22
|
import { tmpdir } from 'os';
|
|
20
23
|
import { join } from 'path';
|
|
21
24
|
|
|
22
25
|
import { WorldStateInstrumentation } from '../instrumentation/instrumentation.js';
|
|
26
|
+
import type { WorldStateTreeMapSizes } from '../synchronizer/factory.js';
|
|
23
27
|
import type { MerkleTreeAdminDatabase as MerkleTreeDatabase } from '../world-state-db/merkle_tree_db.js';
|
|
28
|
+
import { IpcWorldState } from './ipc_world_state_instance.js';
|
|
24
29
|
import { MerkleTreesFacade, MerkleTreesForkFacade, serializeLeaf } from './merkle_trees_facade.js';
|
|
25
30
|
import {
|
|
26
31
|
WorldStateMessageType,
|
|
27
32
|
type WorldStateStatusFull,
|
|
28
33
|
type WorldStateStatusSummary,
|
|
29
34
|
blockStateReference,
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
sanitizeFullStatus,
|
|
36
|
+
sanitizeSummary,
|
|
32
37
|
treeStateReferenceToSnapshot,
|
|
33
|
-
worldStateRevision,
|
|
34
38
|
} from './message.js';
|
|
35
|
-
import {
|
|
39
|
+
import type { NativeWorldStateInstance } from './native_world_state_instance.js';
|
|
36
40
|
|
|
37
41
|
// The current version of the world state database schema
|
|
38
42
|
// Increment this when making incompatible changes to the database schema
|
|
39
|
-
export const WORLD_STATE_DB_VERSION =
|
|
43
|
+
export const WORLD_STATE_DB_VERSION = 2; // The initial version
|
|
44
|
+
|
|
45
|
+
export const WORLD_STATE_DIR = 'world_state';
|
|
40
46
|
|
|
41
47
|
export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
42
48
|
protected initialHeader: BlockHeader | undefined;
|
|
@@ -44,38 +50,53 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
44
50
|
private cachedStatusSummary: WorldStateStatusSummary | undefined;
|
|
45
51
|
|
|
46
52
|
protected constructor(
|
|
47
|
-
protected
|
|
53
|
+
protected instance: NativeWorldStateInstance,
|
|
48
54
|
protected readonly worldStateInstrumentation: WorldStateInstrumentation,
|
|
49
|
-
protected readonly log
|
|
55
|
+
protected readonly log: Logger,
|
|
56
|
+
private readonly genesis: GenesisData = EMPTY_GENESIS_DATA,
|
|
50
57
|
private readonly cleanup = () => Promise.resolve(),
|
|
58
|
+
/** Factory to recreate a fresh IpcWorldState after clear(). */
|
|
59
|
+
private readonly recreateInstance?: () => Promise<NativeWorldStateInstance>,
|
|
51
60
|
) {}
|
|
52
61
|
|
|
53
62
|
static async new(
|
|
54
63
|
rollupAddress: EthAddress,
|
|
55
64
|
dataDir: string,
|
|
56
|
-
|
|
57
|
-
|
|
65
|
+
wsTreeMapSizes: WorldStateTreeMapSizes,
|
|
66
|
+
genesis: GenesisData = EMPTY_GENESIS_DATA,
|
|
58
67
|
instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
59
|
-
|
|
68
|
+
bindings?: LoggerBindings,
|
|
60
69
|
cleanup = () => Promise.resolve(),
|
|
61
70
|
): Promise<NativeWorldStateService> {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
+
|
|
77
|
+
const log = createLogger('world-state:database', bindings);
|
|
78
|
+
const worldStateDirectory = join(dataDir, WORLD_STATE_DIR);
|
|
79
|
+
|
|
80
|
+
const versionManager = new DatabaseVersionManager({
|
|
81
|
+
schemaVersion: WORLD_STATE_DB_VERSION,
|
|
66
82
|
rollupAddress,
|
|
67
|
-
worldStateDirectory,
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
},
|
|
71
|
-
);
|
|
83
|
+
dataDirectory: worldStateDirectory,
|
|
84
|
+
onOpen: dir => IpcWorldState.spawn(dir, wsTreeMapSizes, genesis, instrumentation, bindings),
|
|
85
|
+
});
|
|
72
86
|
|
|
73
87
|
const [instance] = await versionManager.open();
|
|
74
|
-
|
|
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);
|
|
75
96
|
try {
|
|
76
97
|
await worldState.init();
|
|
77
98
|
} catch (e) {
|
|
78
|
-
log.error(`Error
|
|
99
|
+
log.error(`Error initializing world state: ${e}`);
|
|
79
100
|
throw e;
|
|
80
101
|
}
|
|
81
102
|
|
|
@@ -83,17 +104,25 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
83
104
|
}
|
|
84
105
|
|
|
85
106
|
static async tmp(
|
|
86
|
-
rollupAddress = EthAddress.ZERO,
|
|
87
107
|
cleanupTmpDir = true,
|
|
88
|
-
|
|
108
|
+
genesis: GenesisData = EMPTY_GENESIS_DATA,
|
|
89
109
|
instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
110
|
+
bindings?: LoggerBindings,
|
|
90
111
|
): Promise<NativeWorldStateService> {
|
|
91
|
-
const log = createLogger('world-state:database');
|
|
112
|
+
const log = createLogger('world-state:database', bindings);
|
|
92
113
|
const dataDir = await mkdtemp(join(tmpdir(), 'aztec-world-state-'));
|
|
93
114
|
const dbMapSizeKb = 10 * 1024 * 1024;
|
|
94
|
-
|
|
115
|
+
const worldStateTreeMapSizes: WorldStateTreeMapSizes = {
|
|
116
|
+
archiveTreeMapSizeKb: dbMapSizeKb,
|
|
117
|
+
nullifierTreeMapSizeKb: dbMapSizeKb,
|
|
118
|
+
noteHashTreeMapSizeKb: dbMapSizeKb,
|
|
119
|
+
messageTreeMapSizeKb: dbMapSizeKb,
|
|
120
|
+
publicDataTreeMapSizeKb: dbMapSizeKb,
|
|
121
|
+
};
|
|
122
|
+
log.debug(`Created temporary world state database at: ${dataDir} with tree map size: ${dbMapSizeKb}`);
|
|
123
|
+
|
|
124
|
+
const instance = await IpcWorldState.spawn(dataDir, worldStateTreeMapSizes, genesis, instrumentation, bindings);
|
|
95
125
|
|
|
96
|
-
// pass a cleanup callback because process.on('beforeExit', cleanup) does not work under Jest
|
|
97
126
|
const cleanup = async () => {
|
|
98
127
|
if (cleanupTmpDir) {
|
|
99
128
|
await rm(dataDir, { recursive: true, force: true, maxRetries: 3 });
|
|
@@ -103,7 +132,43 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
103
132
|
}
|
|
104
133
|
};
|
|
105
134
|
|
|
106
|
-
|
|
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;
|
|
107
172
|
}
|
|
108
173
|
|
|
109
174
|
protected async init() {
|
|
@@ -127,21 +192,57 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
127
192
|
assert.strictEqual(initialHeaderIndex, 0n, 'Invalid initial archive state');
|
|
128
193
|
}
|
|
129
194
|
|
|
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');
|
|
200
|
+
await this.instance.close();
|
|
201
|
+
this.cachedStatusSummary = undefined;
|
|
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');
|
|
213
|
+
}
|
|
214
|
+
|
|
130
215
|
public getCommitted(): MerkleTreeReadOperations {
|
|
131
|
-
return new MerkleTreesFacade(this.instance, this.initialHeader!,
|
|
216
|
+
return new MerkleTreesFacade(this.instance, this.initialHeader!, WorldStateRevision.empty());
|
|
132
217
|
}
|
|
133
218
|
|
|
134
|
-
public getSnapshot(blockNumber:
|
|
135
|
-
return new MerkleTreesFacade(
|
|
219
|
+
public getSnapshot(blockNumber: BlockNumber): MerkleTreeReadOperations {
|
|
220
|
+
return new MerkleTreesFacade(
|
|
221
|
+
this.instance,
|
|
222
|
+
this.initialHeader!,
|
|
223
|
+
new WorldStateRevision(/*forkId=*/ 0, /* blockNumber=*/ blockNumber, /* includeUncommitted=*/ false),
|
|
224
|
+
);
|
|
136
225
|
}
|
|
137
226
|
|
|
138
|
-
public async fork(
|
|
227
|
+
public async fork(
|
|
228
|
+
blockNumber?: BlockNumber,
|
|
229
|
+
opts: { closeDelayMs?: number } = {},
|
|
230
|
+
): Promise<MerkleTreeWriteOperations> {
|
|
139
231
|
const resp = await this.instance.call(WorldStateMessageType.CREATE_FORK, {
|
|
140
232
|
latest: blockNumber === undefined,
|
|
141
|
-
blockNumber: blockNumber ??
|
|
233
|
+
blockNumber: blockNumber ?? BlockNumber.ZERO,
|
|
142
234
|
canonical: true,
|
|
143
235
|
});
|
|
144
|
-
return new MerkleTreesForkFacade(
|
|
236
|
+
return new MerkleTreesForkFacade(
|
|
237
|
+
this.instance,
|
|
238
|
+
this.initialHeader!,
|
|
239
|
+
new WorldStateRevision(
|
|
240
|
+
/*forkId=*/ resp.forkId,
|
|
241
|
+
/* blockNumber=*/ WorldStateRevision.LATEST,
|
|
242
|
+
/* includeUncommitted=*/ true,
|
|
243
|
+
),
|
|
244
|
+
opts,
|
|
245
|
+
);
|
|
145
246
|
}
|
|
146
247
|
|
|
147
248
|
public getInitialHeader(): BlockHeader {
|
|
@@ -149,11 +250,22 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
149
250
|
}
|
|
150
251
|
|
|
151
252
|
public async handleL2BlockAndMessages(l2Block: L2Block, l1ToL2Messages: Fr[]): Promise<WorldStateStatusFull> {
|
|
152
|
-
|
|
253
|
+
const isFirstBlock = l2Block.indexWithinCheckpoint === 0;
|
|
254
|
+
if (!isFirstBlock && l1ToL2Messages.length > 0) {
|
|
255
|
+
throw new Error(
|
|
256
|
+
`L1 to L2 messages must be empty for non-first blocks, but got ${l1ToL2Messages.length} messages for block ${l2Block.number}.`,
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// We have to pad the given l1 to l2 messages, and the note hashes and nullifiers within tx effects, because that's
|
|
261
|
+
// how the trees are built by circuits.
|
|
262
|
+
const paddedL1ToL2Messages = isFirstBlock
|
|
263
|
+
? padArrayEnd<Fr, number>(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP)
|
|
264
|
+
: [];
|
|
265
|
+
|
|
153
266
|
const paddedNoteHashes = l2Block.body.txEffects.flatMap(txEffect =>
|
|
154
267
|
padArrayEnd(txEffect.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
|
|
155
268
|
);
|
|
156
|
-
const paddedL1ToL2Messages = padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
157
269
|
|
|
158
270
|
const paddedNullifiers = l2Block.body.txEffects
|
|
159
271
|
.flatMap(txEffect => padArrayEnd(txEffect.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX))
|
|
@@ -173,7 +285,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
173
285
|
WorldStateMessageType.SYNC_BLOCK,
|
|
174
286
|
{
|
|
175
287
|
blockNumber: l2Block.number,
|
|
176
|
-
blockHeaderHash: await l2Block.
|
|
288
|
+
blockHeaderHash: (await l2Block.hash()).toBuffer(),
|
|
177
289
|
paddedL1ToL2Messages: paddedL1ToL2Messages.map(serializeLeaf),
|
|
178
290
|
paddedNoteHashes: paddedNoteHashes.map(serializeLeaf),
|
|
179
291
|
paddedNullifiers: paddedNullifiers.map(serializeLeaf),
|
|
@@ -181,7 +293,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
181
293
|
blockStateRef: blockStateReference(l2Block.header.state),
|
|
182
294
|
canonical: true,
|
|
183
295
|
},
|
|
184
|
-
this.
|
|
296
|
+
this.sanitizeAndCacheSummaryFromFull.bind(this),
|
|
185
297
|
this.deleteCachedSummary.bind(this),
|
|
186
298
|
);
|
|
187
299
|
} catch (err) {
|
|
@@ -191,25 +303,35 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
191
303
|
}
|
|
192
304
|
|
|
193
305
|
public async close(): Promise<void> {
|
|
194
|
-
|
|
195
|
-
|
|
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();
|
|
196
315
|
}
|
|
197
316
|
|
|
198
317
|
private async buildInitialHeader(): Promise<BlockHeader> {
|
|
199
318
|
const state = await this.getInitialStateReference();
|
|
200
|
-
return BlockHeader.empty({
|
|
319
|
+
return BlockHeader.empty({
|
|
320
|
+
state,
|
|
321
|
+
globalVariables: GlobalVariables.empty({ timestamp: this.genesis.genesisTimestamp }),
|
|
322
|
+
});
|
|
201
323
|
}
|
|
202
324
|
|
|
203
|
-
private
|
|
204
|
-
const
|
|
205
|
-
this.cachedStatusSummary = { ...
|
|
206
|
-
return
|
|
325
|
+
private sanitizeAndCacheSummaryFromFull(response: WorldStateStatusFull) {
|
|
326
|
+
const sanitized = sanitizeFullStatus(response);
|
|
327
|
+
this.cachedStatusSummary = { ...sanitized.summary };
|
|
328
|
+
return sanitized;
|
|
207
329
|
}
|
|
208
330
|
|
|
209
|
-
private
|
|
210
|
-
const
|
|
211
|
-
this.cachedStatusSummary = { ...
|
|
212
|
-
return
|
|
331
|
+
private sanitizeAndCacheSummary(response: WorldStateStatusSummary) {
|
|
332
|
+
const sanitized = sanitizeSummary(response);
|
|
333
|
+
this.cachedStatusSummary = { ...sanitized };
|
|
334
|
+
return sanitized;
|
|
213
335
|
}
|
|
214
336
|
|
|
215
337
|
private deleteCachedSummary(_: string) {
|
|
@@ -217,19 +339,19 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
217
339
|
}
|
|
218
340
|
|
|
219
341
|
/**
|
|
220
|
-
* Advances the
|
|
221
|
-
* @param toBlockNumber The block number that is now the tip of the
|
|
342
|
+
* Advances the finalized block number to be the number provided
|
|
343
|
+
* @param toBlockNumber The block number that is now the tip of the finalized chain
|
|
222
344
|
* @returns The new WorldStateStatus
|
|
223
345
|
*/
|
|
224
|
-
public async
|
|
346
|
+
public async setFinalized(toBlockNumber: BlockNumber) {
|
|
225
347
|
try {
|
|
226
348
|
await this.instance.call(
|
|
227
|
-
WorldStateMessageType.
|
|
349
|
+
WorldStateMessageType.FINALIZE_BLOCKS,
|
|
228
350
|
{
|
|
229
351
|
toBlockNumber,
|
|
230
352
|
canonical: true,
|
|
231
353
|
},
|
|
232
|
-
this.
|
|
354
|
+
this.sanitizeAndCacheSummary.bind(this),
|
|
233
355
|
this.deleteCachedSummary.bind(this),
|
|
234
356
|
);
|
|
235
357
|
} catch (err) {
|
|
@@ -244,7 +366,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
244
366
|
* @param toBlockNumber The block number of the new oldest historical block
|
|
245
367
|
* @returns The new WorldStateStatus
|
|
246
368
|
*/
|
|
247
|
-
public async removeHistoricalBlocks(toBlockNumber:
|
|
369
|
+
public async removeHistoricalBlocks(toBlockNumber: BlockNumber) {
|
|
248
370
|
try {
|
|
249
371
|
return await this.instance.call(
|
|
250
372
|
WorldStateMessageType.REMOVE_HISTORICAL_BLOCKS,
|
|
@@ -252,7 +374,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
252
374
|
toBlockNumber,
|
|
253
375
|
canonical: true,
|
|
254
376
|
},
|
|
255
|
-
this.
|
|
377
|
+
this.sanitizeAndCacheSummaryFromFull.bind(this),
|
|
256
378
|
this.deleteCachedSummary.bind(this),
|
|
257
379
|
);
|
|
258
380
|
} catch (err) {
|
|
@@ -266,7 +388,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
266
388
|
* @param toBlockNumber The block number of the new tip of the pending chain,
|
|
267
389
|
* @returns The new WorldStateStatus
|
|
268
390
|
*/
|
|
269
|
-
public async unwindBlocks(toBlockNumber:
|
|
391
|
+
public async unwindBlocks(toBlockNumber: BlockNumber) {
|
|
270
392
|
try {
|
|
271
393
|
return await this.instance.call(
|
|
272
394
|
WorldStateMessageType.UNWIND_BLOCKS,
|
|
@@ -274,7 +396,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
274
396
|
toBlockNumber,
|
|
275
397
|
canonical: true,
|
|
276
398
|
},
|
|
277
|
-
this.
|
|
399
|
+
this.sanitizeAndCacheSummaryFromFull.bind(this),
|
|
278
400
|
this.deleteCachedSummary.bind(this),
|
|
279
401
|
);
|
|
280
402
|
} catch (err) {
|
|
@@ -290,7 +412,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
290
412
|
return await this.instance.call(
|
|
291
413
|
WorldStateMessageType.GET_STATUS,
|
|
292
414
|
{ canonical: true },
|
|
293
|
-
this.
|
|
415
|
+
this.sanitizeAndCacheSummary.bind(this),
|
|
294
416
|
);
|
|
295
417
|
}
|
|
296
418
|
|
|
@@ -314,4 +436,25 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
314
436
|
),
|
|
315
437
|
);
|
|
316
438
|
}
|
|
439
|
+
|
|
440
|
+
public async backupTo(
|
|
441
|
+
dstPath: string,
|
|
442
|
+
compact: boolean = true,
|
|
443
|
+
): Promise<Record<Exclude<SnapshotDataKeys, 'archiver'>, string>> {
|
|
444
|
+
await this.instance.call(WorldStateMessageType.COPY_STORES, {
|
|
445
|
+
dstPath,
|
|
446
|
+
compact,
|
|
447
|
+
canonical: true,
|
|
448
|
+
});
|
|
449
|
+
return fromEntries(NATIVE_WORLD_STATE_DBS.map(([name, dir]) => [name, join(dstPath, dir, 'data.mdb')] as const));
|
|
450
|
+
}
|
|
317
451
|
}
|
|
452
|
+
|
|
453
|
+
// The following paths are defined in cpp-land
|
|
454
|
+
export const NATIVE_WORLD_STATE_DBS = [
|
|
455
|
+
['l1-to-l2-message-tree', 'L1ToL2MessageTree'],
|
|
456
|
+
['archive-tree', 'ArchiveTree'],
|
|
457
|
+
['public-data-tree', 'PublicDataTree'],
|
|
458
|
+
['note-hash-tree', 'NoteHashTree'],
|
|
459
|
+
['nullifier-tree', 'NullifierTree'],
|
|
460
|
+
] as const;
|