@aztec/world-state 0.0.1-commit.2f68f620 → 0.0.1-commit.3100065
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/instrumentation/instrumentation.d.ts +3 -4
- package/dest/instrumentation/instrumentation.d.ts.map +1 -1
- package/dest/instrumentation/instrumentation.js +9 -4
- package/dest/native/ipc_world_state_instance.d.ts +22 -59
- package/dest/native/ipc_world_state_instance.d.ts.map +1 -1
- package/dest/native/ipc_world_state_instance.js +495 -520
- package/dest/native/merkle_trees_facade.d.ts +3 -4
- package/dest/native/merkle_trees_facade.d.ts.map +1 -1
- package/dest/native/merkle_trees_facade.js +109 -37
- package/dest/native/message.d.ts +233 -14
- package/dest/native/message.d.ts.map +1 -1
- package/dest/native/message.js +42 -0
- package/dest/native/native_world_state.d.ts +28 -14
- package/dest/native/native_world_state.d.ts.map +1 -1
- package/dest/native/native_world_state.js +102 -101
- package/dest/native/native_world_state_instance.d.ts +42 -58
- package/dest/native/native_world_state_instance.d.ts.map +1 -1
- package/dest/native/native_world_state_instance.js +222 -5
- package/dest/native/world_state_ops_queue.d.ts +19 -0
- package/dest/native/world_state_ops_queue.d.ts.map +1 -0
- package/dest/native/world_state_ops_queue.js +146 -0
- package/dest/synchronizer/errors.d.ts +8 -1
- package/dest/synchronizer/errors.d.ts.map +1 -1
- package/dest/synchronizer/errors.js +8 -1
- package/dest/synchronizer/factory.d.ts +1 -1
- package/dest/synchronizer/factory.d.ts.map +1 -1
- package/dest/synchronizer/factory.js +1 -1
- package/dest/synchronizer/index.d.ts +2 -1
- package/dest/synchronizer/index.d.ts.map +1 -1
- package/dest/synchronizer/index.js +1 -0
- package/dest/synchronizer/server_world_state_synchronizer.d.ts +11 -6
- package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
- package/dest/synchronizer/server_world_state_synchronizer.js +55 -43
- package/dest/test/utils.d.ts +1 -1
- package/dest/test/utils.d.ts.map +1 -1
- package/dest/test/utils.js +6 -1
- package/dest/testing.d.ts +2 -2
- package/dest/testing.d.ts.map +1 -1
- package/dest/testing.js +15 -4
- package/package.json +10 -12
- package/src/instrumentation/instrumentation.ts +18 -6
- package/src/native/ipc_world_state_instance.ts +503 -608
- package/src/native/merkle_trees_facade.ts +104 -59
- package/src/native/message.ts +300 -13
- package/src/native/native_world_state.ts +156 -121
- package/src/native/native_world_state_instance.ts +307 -96
- package/src/native/world_state_ops_queue.ts +190 -0
- package/src/synchronizer/errors.ts +8 -0
- package/src/synchronizer/factory.ts +1 -0
- package/src/synchronizer/index.ts +1 -0
- package/src/synchronizer/server_world_state_synchronizer.ts +63 -30
- package/src/test/utils.ts +10 -1
- package/src/testing.ts +14 -4
- package/dest/native/world_state_operation.d.ts +0 -7
- package/dest/native/world_state_operation.d.ts.map +0 -1
- package/dest/native/world_state_operation.js +0 -5
- package/src/native/world_state_operation.ts +0 -33
|
@@ -3,6 +3,7 @@ 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';
|
|
6
7
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
7
8
|
import type { L2Block } from '@aztec/stdlib/block';
|
|
8
9
|
import { DatabaseVersionManager } from '@aztec/stdlib/database-version/manager';
|
|
@@ -18,16 +19,16 @@ import { EMPTY_GENESIS_DATA, type GenesisData, WorldStateRevision } from '@aztec
|
|
|
18
19
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
19
20
|
|
|
20
21
|
import assert from 'assert/strict';
|
|
21
|
-
import {
|
|
22
|
+
import { mkdtemp, rm } from 'fs/promises';
|
|
22
23
|
import { tmpdir } from 'os';
|
|
23
24
|
import { join } from 'path';
|
|
24
25
|
|
|
25
26
|
import { WorldStateInstrumentation } from '../instrumentation/instrumentation.js';
|
|
26
27
|
import type { WorldStateTreeMapSizes } from '../synchronizer/factory.js';
|
|
27
28
|
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
|
+
WorldStateMessageType,
|
|
31
32
|
type WorldStateStatusFull,
|
|
32
33
|
type WorldStateStatusSummary,
|
|
33
34
|
blockStateReference,
|
|
@@ -35,7 +36,7 @@ import {
|
|
|
35
36
|
sanitizeSummary,
|
|
36
37
|
treeStateReferenceToSnapshot,
|
|
37
38
|
} from './message.js';
|
|
38
|
-
import
|
|
39
|
+
import { NativeWorldState } from './native_world_state_instance.js';
|
|
39
40
|
|
|
40
41
|
// The current version of the world state database schema
|
|
41
42
|
// Increment this when making incompatible changes to the database schema
|
|
@@ -43,21 +44,47 @@ export const WORLD_STATE_DB_VERSION = 2; // The initial version
|
|
|
43
44
|
|
|
44
45
|
export const WORLD_STATE_DIR = 'world_state';
|
|
45
46
|
|
|
47
|
+
const DEFAULT_TMP_TREE_MAP_SIZE_KB = 10 * 1024 * 1024;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Sets up a fresh `mkdtemp` directory + default `WorldStateTreeMapSizes` shared by both
|
|
51
|
+
* the `.tmp` (fsync-on) and `.ephemeral` (fsync-off) factories. Returns the raw tmpdir,
|
|
52
|
+
* the tree map sizes, and the package logger.
|
|
53
|
+
*/
|
|
54
|
+
async function createTmpWorldStateDir(
|
|
55
|
+
bindings?: LoggerBindings,
|
|
56
|
+
): Promise<{ dataDir: string; wsTreeMapSizes: WorldStateTreeMapSizes; log: Logger }> {
|
|
57
|
+
const log = createLogger('world-state:database', bindings);
|
|
58
|
+
const dataDir = await mkdtemp(join(tmpdir(), 'aztec-world-state-'));
|
|
59
|
+
const wsTreeMapSizes: WorldStateTreeMapSizes = {
|
|
60
|
+
archiveTreeMapSizeKb: DEFAULT_TMP_TREE_MAP_SIZE_KB,
|
|
61
|
+
nullifierTreeMapSizeKb: DEFAULT_TMP_TREE_MAP_SIZE_KB,
|
|
62
|
+
noteHashTreeMapSizeKb: DEFAULT_TMP_TREE_MAP_SIZE_KB,
|
|
63
|
+
messageTreeMapSizeKb: DEFAULT_TMP_TREE_MAP_SIZE_KB,
|
|
64
|
+
publicDataTreeMapSizeKb: DEFAULT_TMP_TREE_MAP_SIZE_KB,
|
|
65
|
+
};
|
|
66
|
+
log.debug(`Created temporary world state database at: ${dataDir} (map size ${DEFAULT_TMP_TREE_MAP_SIZE_KB} KB)`);
|
|
67
|
+
return { dataDir, wsTreeMapSizes, log };
|
|
68
|
+
}
|
|
69
|
+
|
|
46
70
|
export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
47
71
|
protected initialHeader: BlockHeader | undefined;
|
|
48
72
|
// This is read heavily and only changes when data is persisted, so we cache it
|
|
49
73
|
private cachedStatusSummary: WorldStateStatusSummary | undefined;
|
|
50
74
|
|
|
51
75
|
protected constructor(
|
|
52
|
-
protected instance:
|
|
76
|
+
protected instance: NativeWorldState,
|
|
53
77
|
protected readonly worldStateInstrumentation: WorldStateInstrumentation,
|
|
54
78
|
protected readonly log: Logger,
|
|
55
79
|
private readonly genesis: GenesisData = EMPTY_GENESIS_DATA,
|
|
56
80
|
private readonly cleanup = () => Promise.resolve(),
|
|
57
|
-
/** Factory to recreate a fresh IpcWorldState after clear(). */
|
|
58
|
-
private readonly recreateInstance?: () => Promise<NativeWorldStateInstance>,
|
|
59
81
|
) {}
|
|
60
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Opens a persistent world state at `dataDir`. Goes through `DatabaseVersionManager` so the
|
|
85
|
+
* caller's rollup address is bound to the on-disk schema and incompatible versions surface
|
|
86
|
+
* loudly. The LMDB envs commit with full fsync.
|
|
87
|
+
*/
|
|
61
88
|
static async new(
|
|
62
89
|
rollupAddress: EthAddress,
|
|
63
90
|
dataDir: string,
|
|
@@ -67,31 +94,28 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
67
94
|
bindings?: LoggerBindings,
|
|
68
95
|
cleanup = () => Promise.resolve(),
|
|
69
96
|
): Promise<NativeWorldStateService> {
|
|
70
|
-
for (const [key, value] of Object.entries(wsTreeMapSizes)) {
|
|
71
|
-
if (value <= 0) {
|
|
72
|
-
throw new Error(`Map size must be a positive number, got ${value} for ${key}`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
97
|
const log = createLogger('world-state:database', bindings);
|
|
77
98
|
const worldStateDirectory = join(dataDir, WORLD_STATE_DIR);
|
|
78
|
-
|
|
79
99
|
const versionManager = new DatabaseVersionManager({
|
|
80
100
|
schemaVersion: WORLD_STATE_DB_VERSION,
|
|
81
101
|
rollupAddress,
|
|
82
102
|
dataDirectory: worldStateDirectory,
|
|
83
|
-
onOpen:
|
|
103
|
+
onOpen: (dir: string) =>
|
|
104
|
+
Promise.resolve(
|
|
105
|
+
new NativeWorldState(
|
|
106
|
+
dir,
|
|
107
|
+
wsTreeMapSizes,
|
|
108
|
+
genesis,
|
|
109
|
+
instrumentation,
|
|
110
|
+
bindings,
|
|
111
|
+
undefined,
|
|
112
|
+
/*ephemeral=*/ false,
|
|
113
|
+
),
|
|
114
|
+
),
|
|
84
115
|
});
|
|
85
116
|
|
|
86
117
|
const [instance] = await versionManager.open();
|
|
87
|
-
|
|
88
|
-
const recreateInstance = async () => {
|
|
89
|
-
await rm(worldStateDirectory, { recursive: true, force: true, maxRetries: 3 });
|
|
90
|
-
await mkdir(worldStateDirectory, { recursive: true });
|
|
91
|
-
return IpcWorldState.spawn(worldStateDirectory, wsTreeMapSizes, genesis, instrumentation, bindings);
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const worldState = new this(instance, instrumentation, log, genesis, cleanup, recreateInstance);
|
|
118
|
+
const worldState = new this(instance, instrumentation, log, genesis, cleanup);
|
|
95
119
|
try {
|
|
96
120
|
await worldState.init();
|
|
97
121
|
} catch (e) {
|
|
@@ -102,30 +126,23 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
102
126
|
return worldState;
|
|
103
127
|
}
|
|
104
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Opens a world state in a fresh tmpdir with full fsync semantics. Use when you need the
|
|
131
|
+
* on-disk file to remain crash-recoverable (e.g. for snapshot/backup tests) but don't
|
|
132
|
+
* want a persistent dataDir. Pass `cleanupTmpDir=false` to keep the directory after
|
|
133
|
+
* close for inspection.
|
|
134
|
+
*
|
|
135
|
+
* If you don't care about crash-recoverability — i.e. you just want a fast scratch
|
|
136
|
+
* database for tests — use {@link ephemeral} instead.
|
|
137
|
+
*/
|
|
105
138
|
static async tmp(
|
|
139
|
+
rollupAddress = EthAddress.ZERO,
|
|
106
140
|
cleanupTmpDir = true,
|
|
107
141
|
genesis: GenesisData = EMPTY_GENESIS_DATA,
|
|
108
142
|
instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
109
143
|
bindings?: LoggerBindings,
|
|
110
144
|
): Promise<NativeWorldStateService> {
|
|
111
|
-
const log =
|
|
112
|
-
const dataDir = await mkdtemp(join(tmpdir(), 'aztec-world-state-'));
|
|
113
|
-
// Temporary (test/dev) world states are small and short-lived. Keep the LMDB
|
|
114
|
-
// map sizes in the MB range: with the IPC backend each tmp() spawns a separate
|
|
115
|
-
// aztec-wsdb that maps these per tree, and oversized maps add real cold-start
|
|
116
|
-
// I/O under parallel CI load. 256 MB/tree is ample for tests.
|
|
117
|
-
const dbMapSizeKb = 256 * 1024;
|
|
118
|
-
const worldStateTreeMapSizes: WorldStateTreeMapSizes = {
|
|
119
|
-
archiveTreeMapSizeKb: dbMapSizeKb,
|
|
120
|
-
nullifierTreeMapSizeKb: dbMapSizeKb,
|
|
121
|
-
noteHashTreeMapSizeKb: dbMapSizeKb,
|
|
122
|
-
messageTreeMapSizeKb: dbMapSizeKb,
|
|
123
|
-
publicDataTreeMapSizeKb: dbMapSizeKb,
|
|
124
|
-
};
|
|
125
|
-
log.debug(`Created temporary world state database at: ${dataDir} with tree map size: ${dbMapSizeKb}`);
|
|
126
|
-
|
|
127
|
-
const instance = await IpcWorldState.spawn(dataDir, worldStateTreeMapSizes, genesis, instrumentation, bindings);
|
|
128
|
-
|
|
145
|
+
const { dataDir, wsTreeMapSizes, log } = await createTmpWorldStateDir(bindings);
|
|
129
146
|
const cleanup = async () => {
|
|
130
147
|
if (cleanupTmpDir) {
|
|
131
148
|
await rm(dataDir, { recursive: true, force: true, maxRetries: 3 });
|
|
@@ -134,46 +151,47 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
134
151
|
log.debug(`Leaving temporary world state database: ${dataDir}`);
|
|
135
152
|
}
|
|
136
153
|
};
|
|
154
|
+
return this.new(rollupAddress, dataDir, wsTreeMapSizes, genesis, instrumentation, bindings, cleanup);
|
|
155
|
+
}
|
|
137
156
|
|
|
138
|
-
|
|
157
|
+
/**
|
|
158
|
+
* Opens a fully-ephemeral world state. The directory is created in `os.tmpdir()`, the LMDB
|
|
159
|
+
* envs open with `MDB_NOSYNC | MDB_NOMETASYNC` so commits never block on fsync, and the
|
|
160
|
+
* directory is removed on dispose. A crash mid-write leaves the env unrecoverable.
|
|
161
|
+
*
|
|
162
|
+
* For unit tests and other isolated runs. Use {@link tmp} when you need fsync semantics in a
|
|
163
|
+
* tmp dir, and {@link new} for a persistent store. Skips {@link DatabaseVersionManager} —
|
|
164
|
+
* there is no on-disk schema to bind to and no rollup address is taken.
|
|
165
|
+
*/
|
|
166
|
+
static async ephemeral(
|
|
167
|
+
genesis: GenesisData = EMPTY_GENESIS_DATA,
|
|
168
|
+
instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
169
|
+
bindings?: LoggerBindings,
|
|
170
|
+
): Promise<NativeWorldStateService> {
|
|
171
|
+
const { dataDir, wsTreeMapSizes, log } = await createTmpWorldStateDir(bindings);
|
|
172
|
+
const cleanup = async () => {
|
|
139
173
|
await rm(dataDir, { recursive: true, force: true, maxRetries: 3 });
|
|
140
|
-
|
|
141
|
-
return IpcWorldState.spawn(dataDir, worldStateTreeMapSizes, genesis, instrumentation, bindings);
|
|
174
|
+
log.debug(`Deleted ephemeral world state database: ${dataDir}`);
|
|
142
175
|
};
|
|
143
|
-
|
|
144
|
-
|
|
176
|
+
const instance = new NativeWorldState(
|
|
177
|
+
join(dataDir, WORLD_STATE_DIR),
|
|
178
|
+
wsTreeMapSizes,
|
|
179
|
+
genesis,
|
|
180
|
+
instrumentation,
|
|
181
|
+
bindings,
|
|
182
|
+
undefined,
|
|
183
|
+
/*ephemeral=*/ true,
|
|
184
|
+
);
|
|
185
|
+
const worldState = new this(instance, instrumentation, log, genesis, cleanup);
|
|
145
186
|
try {
|
|
146
187
|
await worldState.init();
|
|
147
188
|
} catch (e) {
|
|
148
|
-
log.error(`Error initializing
|
|
189
|
+
log.error(`Error initializing ephemeral world state: ${e}`);
|
|
149
190
|
throw e;
|
|
150
191
|
}
|
|
151
192
|
return worldState;
|
|
152
193
|
}
|
|
153
194
|
|
|
154
|
-
static ephemeral(
|
|
155
|
-
genesis: GenesisData = EMPTY_GENESIS_DATA,
|
|
156
|
-
instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
157
|
-
bindings?: LoggerBindings,
|
|
158
|
-
): Promise<NativeWorldStateService> {
|
|
159
|
-
return this.tmp(/*cleanupTmpDir=*/ true, genesis, instrumentation, bindings);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
static async fromIpc(
|
|
163
|
-
wsdbBackend: ConstructorParameters<typeof IpcWorldState>[0],
|
|
164
|
-
instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
165
|
-
bindings?: LoggerBindings,
|
|
166
|
-
genesis: GenesisData = EMPTY_GENESIS_DATA,
|
|
167
|
-
cleanup = () => Promise.resolve(),
|
|
168
|
-
recreateInstance?: () => Promise<NativeWorldStateInstance>,
|
|
169
|
-
): Promise<NativeWorldStateService> {
|
|
170
|
-
const log = createLogger('world-state:database', bindings);
|
|
171
|
-
const instance = new IpcWorldState(wsdbBackend, instrumentation, bindings);
|
|
172
|
-
const worldState = new this(instance, instrumentation, log, genesis, cleanup, recreateInstance);
|
|
173
|
-
await worldState.init();
|
|
174
|
-
return worldState;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
195
|
protected async init() {
|
|
178
196
|
const status = await this.getStatusSummary();
|
|
179
197
|
if (!status.treesAreSynched) {
|
|
@@ -195,24 +213,11 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
195
213
|
assert.strictEqual(initialHeaderIndex, 0n, 'Invalid initial archive state');
|
|
196
214
|
}
|
|
197
215
|
|
|
198
|
-
public async clear()
|
|
199
|
-
if (!this.recreateInstance) {
|
|
200
|
-
throw new Error('clear() is not available for externally-managed IPC backends');
|
|
201
|
-
}
|
|
202
|
-
this.log.warn('Clearing world state: shutting down WSDB, deleting data, and recreating');
|
|
216
|
+
public async clear() {
|
|
203
217
|
await this.instance.close();
|
|
204
218
|
this.cachedStatusSummary = undefined;
|
|
205
|
-
this.instance
|
|
206
|
-
|
|
207
|
-
this.log.info('World state cleared and reinitialized from genesis');
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/** Returns the IPC path of the underlying IPC backend, if available. */
|
|
211
|
-
public getIpcPath(): string {
|
|
212
|
-
if (this.instance instanceof IpcWorldState) {
|
|
213
|
-
return this.instance.getIpcPath();
|
|
214
|
-
}
|
|
215
|
-
throw new Error('getIpcPath() is only available with IPC world state');
|
|
219
|
+
await tryRmDir(this.instance.getDataDir(), this.log);
|
|
220
|
+
this.instance = this.instance.clone();
|
|
216
221
|
}
|
|
217
222
|
|
|
218
223
|
public getCommitted(): MerkleTreeReadOperations {
|
|
@@ -231,15 +236,16 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
231
236
|
blockNumber?: BlockNumber,
|
|
232
237
|
opts: { closeDelayMs?: number } = {},
|
|
233
238
|
): Promise<MerkleTreeWriteOperations> {
|
|
234
|
-
const
|
|
239
|
+
const resp = await this.instance.call(WorldStateMessageType.CREATE_FORK, {
|
|
235
240
|
latest: blockNumber === undefined,
|
|
236
241
|
blockNumber: blockNumber ?? BlockNumber.ZERO,
|
|
242
|
+
canonical: true,
|
|
237
243
|
});
|
|
238
244
|
return new MerkleTreesForkFacade(
|
|
239
245
|
this.instance,
|
|
240
246
|
this.initialHeader!,
|
|
241
247
|
new WorldStateRevision(
|
|
242
|
-
/*forkId=*/ forkId,
|
|
248
|
+
/*forkId=*/ resp.forkId,
|
|
243
249
|
/* blockNumber=*/ WorldStateRevision.LATEST,
|
|
244
250
|
/* includeUncommitted=*/ true,
|
|
245
251
|
),
|
|
@@ -283,33 +289,33 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
283
289
|
});
|
|
284
290
|
|
|
285
291
|
try {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
292
|
+
return await this.instance.call(
|
|
293
|
+
WorldStateMessageType.SYNC_BLOCK,
|
|
294
|
+
{
|
|
295
|
+
blockNumber: l2Block.number,
|
|
296
|
+
blockHeaderHash: (await l2Block.hash()).toBuffer(),
|
|
297
|
+
// Forwarded so the native sync verifies the archive root against canonical and rejects a divergent tree.
|
|
298
|
+
expectedArchiveRoot: l2Block.archive.root.toBuffer(),
|
|
299
|
+
expectedPreviousArchiveRoot: l2Block.header.lastArchive.root.toBuffer(),
|
|
300
|
+
paddedL1ToL2Messages: paddedL1ToL2Messages.map(serializeLeaf),
|
|
301
|
+
paddedNoteHashes: paddedNoteHashes.map(serializeLeaf),
|
|
302
|
+
paddedNullifiers: paddedNullifiers.map(serializeLeaf),
|
|
303
|
+
publicDataWrites: publicDataWrites.map(serializeLeaf),
|
|
304
|
+
blockStateRef: blockStateReference(l2Block.header.state),
|
|
305
|
+
canonical: true,
|
|
306
|
+
},
|
|
307
|
+
this.sanitizeAndCacheSummaryFromFull.bind(this),
|
|
308
|
+
this.deleteCachedSummary.bind(this),
|
|
309
|
+
);
|
|
296
310
|
} catch (err) {
|
|
297
|
-
this.deleteCachedSummary();
|
|
298
311
|
this.worldStateInstrumentation.incCriticalErrors('synch_pending_block');
|
|
299
312
|
throw err;
|
|
300
313
|
}
|
|
301
314
|
}
|
|
302
315
|
|
|
303
316
|
public async close(): Promise<void> {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
} finally {
|
|
307
|
-
await this.cleanup();
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
async [Symbol.asyncDispose](): Promise<void> {
|
|
312
|
-
await this.close();
|
|
317
|
+
await this.instance.close();
|
|
318
|
+
await this.cleanup();
|
|
313
319
|
}
|
|
314
320
|
|
|
315
321
|
private async buildInitialHeader(): Promise<BlockHeader> {
|
|
@@ -332,7 +338,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
332
338
|
return sanitized;
|
|
333
339
|
}
|
|
334
340
|
|
|
335
|
-
private deleteCachedSummary() {
|
|
341
|
+
private deleteCachedSummary(_: string) {
|
|
336
342
|
this.cachedStatusSummary = undefined;
|
|
337
343
|
}
|
|
338
344
|
|
|
@@ -343,9 +349,16 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
343
349
|
*/
|
|
344
350
|
public async setFinalized(toBlockNumber: BlockNumber) {
|
|
345
351
|
try {
|
|
346
|
-
|
|
352
|
+
await this.instance.call(
|
|
353
|
+
WorldStateMessageType.FINALIZE_BLOCKS,
|
|
354
|
+
{
|
|
355
|
+
toBlockNumber,
|
|
356
|
+
canonical: true,
|
|
357
|
+
},
|
|
358
|
+
this.sanitizeAndCacheSummary.bind(this),
|
|
359
|
+
this.deleteCachedSummary.bind(this),
|
|
360
|
+
);
|
|
347
361
|
} catch (err) {
|
|
348
|
-
this.deleteCachedSummary();
|
|
349
362
|
this.worldStateInstrumentation.incCriticalErrors('finalize_block');
|
|
350
363
|
throw err;
|
|
351
364
|
}
|
|
@@ -359,9 +372,16 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
359
372
|
*/
|
|
360
373
|
public async removeHistoricalBlocks(toBlockNumber: BlockNumber) {
|
|
361
374
|
try {
|
|
362
|
-
return
|
|
375
|
+
return await this.instance.call(
|
|
376
|
+
WorldStateMessageType.REMOVE_HISTORICAL_BLOCKS,
|
|
377
|
+
{
|
|
378
|
+
toBlockNumber,
|
|
379
|
+
canonical: true,
|
|
380
|
+
},
|
|
381
|
+
this.sanitizeAndCacheSummaryFromFull.bind(this),
|
|
382
|
+
this.deleteCachedSummary.bind(this),
|
|
383
|
+
);
|
|
363
384
|
} catch (err) {
|
|
364
|
-
this.deleteCachedSummary();
|
|
365
385
|
this.worldStateInstrumentation.incCriticalErrors('prune_historical_block');
|
|
366
386
|
throw err;
|
|
367
387
|
}
|
|
@@ -374,9 +394,16 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
374
394
|
*/
|
|
375
395
|
public async unwindBlocks(toBlockNumber: BlockNumber) {
|
|
376
396
|
try {
|
|
377
|
-
return
|
|
397
|
+
return await this.instance.call(
|
|
398
|
+
WorldStateMessageType.UNWIND_BLOCKS,
|
|
399
|
+
{
|
|
400
|
+
toBlockNumber,
|
|
401
|
+
canonical: true,
|
|
402
|
+
},
|
|
403
|
+
this.sanitizeAndCacheSummaryFromFull.bind(this),
|
|
404
|
+
this.deleteCachedSummary.bind(this),
|
|
405
|
+
);
|
|
378
406
|
} catch (err) {
|
|
379
|
-
this.deleteCachedSummary();
|
|
380
407
|
this.worldStateInstrumentation.incCriticalErrors('prune_pending_block');
|
|
381
408
|
throw err;
|
|
382
409
|
}
|
|
@@ -386,7 +413,11 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
386
413
|
if (this.cachedStatusSummary !== undefined) {
|
|
387
414
|
return { ...this.cachedStatusSummary };
|
|
388
415
|
}
|
|
389
|
-
return
|
|
416
|
+
return await this.instance.call(
|
|
417
|
+
WorldStateMessageType.GET_STATUS,
|
|
418
|
+
{ canonical: true },
|
|
419
|
+
this.sanitizeAndCacheSummary.bind(this),
|
|
420
|
+
);
|
|
390
421
|
}
|
|
391
422
|
|
|
392
423
|
updateLeaf<ID extends IndexedTreeId>(
|
|
@@ -398,14 +429,14 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
398
429
|
}
|
|
399
430
|
|
|
400
431
|
private async getInitialStateReference(): Promise<StateReference> {
|
|
401
|
-
const
|
|
432
|
+
const resp = await this.instance.call(WorldStateMessageType.GET_INITIAL_STATE_REFERENCE, { canonical: true });
|
|
402
433
|
|
|
403
434
|
return new StateReference(
|
|
404
|
-
treeStateReferenceToSnapshot(state[MerkleTreeId.L1_TO_L2_MESSAGE_TREE]),
|
|
435
|
+
treeStateReferenceToSnapshot(resp.state[MerkleTreeId.L1_TO_L2_MESSAGE_TREE]),
|
|
405
436
|
new PartialStateReference(
|
|
406
|
-
treeStateReferenceToSnapshot(state[MerkleTreeId.NOTE_HASH_TREE]),
|
|
407
|
-
treeStateReferenceToSnapshot(state[MerkleTreeId.NULLIFIER_TREE]),
|
|
408
|
-
treeStateReferenceToSnapshot(state[MerkleTreeId.PUBLIC_DATA_TREE]),
|
|
437
|
+
treeStateReferenceToSnapshot(resp.state[MerkleTreeId.NOTE_HASH_TREE]),
|
|
438
|
+
treeStateReferenceToSnapshot(resp.state[MerkleTreeId.NULLIFIER_TREE]),
|
|
439
|
+
treeStateReferenceToSnapshot(resp.state[MerkleTreeId.PUBLIC_DATA_TREE]),
|
|
409
440
|
),
|
|
410
441
|
);
|
|
411
442
|
}
|
|
@@ -414,7 +445,11 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
414
445
|
dstPath: string,
|
|
415
446
|
compact: boolean = true,
|
|
416
447
|
): Promise<Record<Exclude<SnapshotDataKeys, 'archiver'>, string>> {
|
|
417
|
-
await this.instance.
|
|
448
|
+
await this.instance.call(WorldStateMessageType.COPY_STORES, {
|
|
449
|
+
dstPath,
|
|
450
|
+
compact,
|
|
451
|
+
canonical: true,
|
|
452
|
+
});
|
|
418
453
|
return fromEntries(NATIVE_WORLD_STATE_DBS.map(([name, dir]) => [name, join(dstPath, dir, 'data.mdb')] as const));
|
|
419
454
|
}
|
|
420
455
|
}
|