@aztec/world-state 0.0.1-commit.3100065 → 0.0.1-commit.330febf
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 +2 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -0
- package/dest/instrumentation/instrumentation.d.ts +4 -3
- package/dest/instrumentation/instrumentation.d.ts.map +1 -1
- package/dest/instrumentation/instrumentation.js +4 -9
- package/dest/native/index.d.ts +2 -1
- package/dest/native/index.d.ts.map +1 -1
- package/dest/native/index.js +1 -0
- package/dest/native/ipc_world_state_instance.d.ts +61 -22
- package/dest/native/ipc_world_state_instance.d.ts.map +1 -1
- package/dest/native/ipc_world_state_instance.js +530 -495
- package/dest/native/merkle_trees_facade.d.ts +4 -3
- package/dest/native/merkle_trees_facade.d.ts.map +1 -1
- package/dest/native/merkle_trees_facade.js +37 -109
- package/dest/native/message.d.ts +14 -233
- package/dest/native/message.d.ts.map +1 -1
- package/dest/native/message.js +0 -42
- package/dest/native/native_world_state.d.ts +14 -28
- package/dest/native/native_world_state.d.ts.map +1 -1
- package/dest/native/native_world_state.js +105 -99
- package/dest/native/native_world_state_instance.d.ts +56 -43
- package/dest/native/native_world_state_instance.d.ts.map +1 -1
- package/dest/native/native_world_state_instance.js +1 -223
- package/dest/native/world_state_operation.d.ts +7 -0
- package/dest/native/world_state_operation.d.ts.map +1 -0
- package/dest/native/world_state_operation.js +5 -0
- 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/package.json +11 -10
- package/src/index.ts +1 -0
- package/src/instrumentation/instrumentation.ts +6 -18
- package/src/native/index.ts +1 -0
- package/src/native/ipc_world_state_instance.ts +625 -503
- package/src/native/merkle_trees_facade.ts +59 -104
- package/src/native/message.ts +13 -300
- package/src/native/native_world_state.ts +136 -156
- package/src/native/native_world_state_instance.ts +94 -308
- package/src/native/world_state_operation.ts +33 -0
- package/src/synchronizer/factory.ts +0 -1
- package/dest/native/world_state_ops_queue.d.ts +0 -19
- package/dest/native/world_state_ops_queue.d.ts.map +0 -1
- package/dest/native/world_state_ops_queue.js +0 -146
- package/src/native/world_state_ops_queue.ts +0 -190
|
@@ -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';
|
|
@@ -19,16 +18,16 @@ import { EMPTY_GENESIS_DATA, type GenesisData, WorldStateRevision } from '@aztec
|
|
|
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
|
-
WorldStateMessageType,
|
|
32
31
|
type WorldStateStatusFull,
|
|
33
32
|
type WorldStateStatusSummary,
|
|
34
33
|
blockStateReference,
|
|
@@ -36,7 +35,7 @@ import {
|
|
|
36
35
|
sanitizeSummary,
|
|
37
36
|
treeStateReferenceToSnapshot,
|
|
38
37
|
} from './message.js';
|
|
39
|
-
import {
|
|
38
|
+
import type { NativeWorldStateInstance } from './native_world_state_instance.js';
|
|
40
39
|
|
|
41
40
|
// The current version of the world state database schema
|
|
42
41
|
// Increment this when making incompatible changes to the database schema
|
|
@@ -44,47 +43,21 @@ export const WORLD_STATE_DB_VERSION = 2; // The initial version
|
|
|
44
43
|
|
|
45
44
|
export const WORLD_STATE_DIR = 'world_state';
|
|
46
45
|
|
|
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
|
-
|
|
70
46
|
export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
71
47
|
protected initialHeader: BlockHeader | undefined;
|
|
72
48
|
// This is read heavily and only changes when data is persisted, so we cache it
|
|
73
49
|
private cachedStatusSummary: WorldStateStatusSummary | undefined;
|
|
74
50
|
|
|
75
51
|
protected constructor(
|
|
76
|
-
protected instance:
|
|
52
|
+
protected instance: NativeWorldStateInstance,
|
|
77
53
|
protected readonly worldStateInstrumentation: WorldStateInstrumentation,
|
|
78
54
|
protected readonly log: Logger,
|
|
79
55
|
private readonly genesis: GenesisData = EMPTY_GENESIS_DATA,
|
|
80
56
|
private readonly cleanup = () => Promise.resolve(),
|
|
57
|
+
/** Factory to recreate a fresh IpcWorldState after clear(). */
|
|
58
|
+
private readonly recreateInstance?: () => Promise<NativeWorldStateInstance>,
|
|
81
59
|
) {}
|
|
82
60
|
|
|
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
|
-
*/
|
|
88
61
|
static async new(
|
|
89
62
|
rollupAddress: EthAddress,
|
|
90
63
|
dataDir: string,
|
|
@@ -94,28 +67,31 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
94
67
|
bindings?: LoggerBindings,
|
|
95
68
|
cleanup = () => Promise.resolve(),
|
|
96
69
|
): 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
|
+
|
|
97
76
|
const log = createLogger('world-state:database', bindings);
|
|
98
77
|
const worldStateDirectory = join(dataDir, WORLD_STATE_DIR);
|
|
78
|
+
|
|
99
79
|
const versionManager = new DatabaseVersionManager({
|
|
100
80
|
schemaVersion: WORLD_STATE_DB_VERSION,
|
|
101
81
|
rollupAddress,
|
|
102
82
|
dataDirectory: worldStateDirectory,
|
|
103
|
-
onOpen: (dir
|
|
104
|
-
Promise.resolve(
|
|
105
|
-
new NativeWorldState(
|
|
106
|
-
dir,
|
|
107
|
-
wsTreeMapSizes,
|
|
108
|
-
genesis,
|
|
109
|
-
instrumentation,
|
|
110
|
-
bindings,
|
|
111
|
-
undefined,
|
|
112
|
-
/*ephemeral=*/ false,
|
|
113
|
-
),
|
|
114
|
-
),
|
|
83
|
+
onOpen: dir => IpcWorldState.spawn(dir, wsTreeMapSizes, genesis, instrumentation, bindings),
|
|
115
84
|
});
|
|
116
85
|
|
|
117
86
|
const [instance] = await versionManager.open();
|
|
118
|
-
|
|
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);
|
|
119
95
|
try {
|
|
120
96
|
await worldState.init();
|
|
121
97
|
} catch (e) {
|
|
@@ -126,23 +102,38 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
126
102
|
return worldState;
|
|
127
103
|
}
|
|
128
104
|
|
|
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
|
-
*/
|
|
138
105
|
static async tmp(
|
|
139
|
-
rollupAddress = EthAddress.ZERO,
|
|
140
106
|
cleanupTmpDir = true,
|
|
141
107
|
genesis: GenesisData = EMPTY_GENESIS_DATA,
|
|
142
108
|
instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
143
109
|
bindings?: LoggerBindings,
|
|
110
|
+
threads?: number,
|
|
144
111
|
): Promise<NativeWorldStateService> {
|
|
145
|
-
const
|
|
112
|
+
const log = createLogger('world-state:database', bindings);
|
|
113
|
+
const dataDir = await mkdtemp(join(tmpdir(), 'aztec-world-state-'));
|
|
114
|
+
// Temporary (test/dev) world states are small and short-lived. Keep the LMDB
|
|
115
|
+
// map sizes in the MB range: with the IPC backend each tmp() spawns a separate
|
|
116
|
+
// aztec-wsdb that maps these per tree, and oversized maps add real cold-start
|
|
117
|
+
// I/O under parallel CI load. 256 MB/tree is ample for tests.
|
|
118
|
+
const dbMapSizeKb = 256 * 1024;
|
|
119
|
+
const worldStateTreeMapSizes: WorldStateTreeMapSizes = {
|
|
120
|
+
archiveTreeMapSizeKb: dbMapSizeKb,
|
|
121
|
+
nullifierTreeMapSizeKb: dbMapSizeKb,
|
|
122
|
+
noteHashTreeMapSizeKb: dbMapSizeKb,
|
|
123
|
+
messageTreeMapSizeKb: dbMapSizeKb,
|
|
124
|
+
publicDataTreeMapSizeKb: dbMapSizeKb,
|
|
125
|
+
};
|
|
126
|
+
log.debug(`Created temporary world state database at: ${dataDir} with tree map size: ${dbMapSizeKb}`);
|
|
127
|
+
|
|
128
|
+
const instance = await IpcWorldState.spawn(
|
|
129
|
+
dataDir,
|
|
130
|
+
worldStateTreeMapSizes,
|
|
131
|
+
genesis,
|
|
132
|
+
instrumentation,
|
|
133
|
+
bindings,
|
|
134
|
+
threads,
|
|
135
|
+
);
|
|
136
|
+
|
|
146
137
|
const cleanup = async () => {
|
|
147
138
|
if (cleanupTmpDir) {
|
|
148
139
|
await rm(dataDir, { recursive: true, force: true, maxRetries: 3 });
|
|
@@ -151,47 +142,50 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
151
142
|
log.debug(`Leaving temporary world state database: ${dataDir}`);
|
|
152
143
|
}
|
|
153
144
|
};
|
|
154
|
-
return this.new(rollupAddress, dataDir, wsTreeMapSizes, genesis, instrumentation, bindings, cleanup);
|
|
155
|
-
}
|
|
156
145
|
|
|
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 () => {
|
|
146
|
+
const recreateInstance = async () => {
|
|
173
147
|
await rm(dataDir, { recursive: true, force: true, maxRetries: 3 });
|
|
174
|
-
|
|
148
|
+
await mkdir(dataDir, { recursive: true });
|
|
149
|
+
return IpcWorldState.spawn(dataDir, worldStateTreeMapSizes, genesis, instrumentation, bindings, threads);
|
|
175
150
|
};
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
wsTreeMapSizes,
|
|
179
|
-
genesis,
|
|
180
|
-
instrumentation,
|
|
181
|
-
bindings,
|
|
182
|
-
undefined,
|
|
183
|
-
/*ephemeral=*/ true,
|
|
184
|
-
);
|
|
185
|
-
const worldState = new this(instance, instrumentation, log, genesis, cleanup);
|
|
151
|
+
|
|
152
|
+
const worldState = new this(instance, instrumentation, log, genesis, cleanup, recreateInstance);
|
|
186
153
|
try {
|
|
187
154
|
await worldState.init();
|
|
188
155
|
} catch (e) {
|
|
189
|
-
log.error(`Error initializing
|
|
156
|
+
log.error(`Error initializing tmp world state: ${e}`);
|
|
190
157
|
throw e;
|
|
191
158
|
}
|
|
192
159
|
return worldState;
|
|
193
160
|
}
|
|
194
161
|
|
|
162
|
+
static ephemeral(
|
|
163
|
+
genesis: GenesisData = EMPTY_GENESIS_DATA,
|
|
164
|
+
instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
165
|
+
bindings?: LoggerBindings,
|
|
166
|
+
): Promise<NativeWorldStateService> {
|
|
167
|
+
// The TXE spins up one tiny, short-lived world state per test, many concurrently. Cap the wsdb thread
|
|
168
|
+
// usage to the minimum: a single tree-op thread instead of one per core (the C++ IPC dispatcher pool
|
|
169
|
+
// still floors at 2). This avoids ~32 threads per wsdb multiplied across dozens of concurrent test
|
|
170
|
+
// world states — the trees are cache-sized (see tmp's map-size note), so extra threads buy nothing.
|
|
171
|
+
return this.tmp(/*cleanupTmpDir=*/ true, genesis, instrumentation, bindings, /*threads=*/ 1);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
static async fromIpc(
|
|
175
|
+
wsdbBackend: ConstructorParameters<typeof IpcWorldState>[0],
|
|
176
|
+
instrumentation = new WorldStateInstrumentation(getTelemetryClient()),
|
|
177
|
+
bindings?: LoggerBindings,
|
|
178
|
+
genesis: GenesisData = EMPTY_GENESIS_DATA,
|
|
179
|
+
cleanup = () => Promise.resolve(),
|
|
180
|
+
recreateInstance?: () => Promise<NativeWorldStateInstance>,
|
|
181
|
+
): Promise<NativeWorldStateService> {
|
|
182
|
+
const log = createLogger('world-state:database', bindings);
|
|
183
|
+
const instance = new IpcWorldState(wsdbBackend, instrumentation, bindings);
|
|
184
|
+
const worldState = new this(instance, instrumentation, log, genesis, cleanup, recreateInstance);
|
|
185
|
+
await worldState.init();
|
|
186
|
+
return worldState;
|
|
187
|
+
}
|
|
188
|
+
|
|
195
189
|
protected async init() {
|
|
196
190
|
const status = await this.getStatusSummary();
|
|
197
191
|
if (!status.treesAreSynched) {
|
|
@@ -213,11 +207,24 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
213
207
|
assert.strictEqual(initialHeaderIndex, 0n, 'Invalid initial archive state');
|
|
214
208
|
}
|
|
215
209
|
|
|
216
|
-
public async clear() {
|
|
210
|
+
public async clear(): Promise<void> {
|
|
211
|
+
if (!this.recreateInstance) {
|
|
212
|
+
throw new Error('clear() is not available for externally-managed IPC backends');
|
|
213
|
+
}
|
|
214
|
+
this.log.warn('Clearing world state: shutting down WSDB, deleting data, and recreating');
|
|
217
215
|
await this.instance.close();
|
|
218
216
|
this.cachedStatusSummary = undefined;
|
|
219
|
-
|
|
220
|
-
|
|
217
|
+
this.instance = await this.recreateInstance();
|
|
218
|
+
await this.init();
|
|
219
|
+
this.log.info('World state cleared and reinitialized from genesis');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Returns the IPC path of the underlying IPC backend, if available. */
|
|
223
|
+
public getIpcPath(): string {
|
|
224
|
+
if (this.instance instanceof IpcWorldState) {
|
|
225
|
+
return this.instance.getIpcPath();
|
|
226
|
+
}
|
|
227
|
+
throw new Error('getIpcPath() is only available with IPC world state');
|
|
221
228
|
}
|
|
222
229
|
|
|
223
230
|
public getCommitted(): MerkleTreeReadOperations {
|
|
@@ -236,16 +243,15 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
236
243
|
blockNumber?: BlockNumber,
|
|
237
244
|
opts: { closeDelayMs?: number } = {},
|
|
238
245
|
): Promise<MerkleTreeWriteOperations> {
|
|
239
|
-
const
|
|
246
|
+
const forkId = await this.instance.createFork({
|
|
240
247
|
latest: blockNumber === undefined,
|
|
241
248
|
blockNumber: blockNumber ?? BlockNumber.ZERO,
|
|
242
|
-
canonical: true,
|
|
243
249
|
});
|
|
244
250
|
return new MerkleTreesForkFacade(
|
|
245
251
|
this.instance,
|
|
246
252
|
this.initialHeader!,
|
|
247
253
|
new WorldStateRevision(
|
|
248
|
-
/*forkId=*/
|
|
254
|
+
/*forkId=*/ forkId,
|
|
249
255
|
/* blockNumber=*/ WorldStateRevision.LATEST,
|
|
250
256
|
/* includeUncommitted=*/ true,
|
|
251
257
|
),
|
|
@@ -289,33 +295,36 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
289
295
|
});
|
|
290
296
|
|
|
291
297
|
try {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
canonical: true,
|
|
306
|
-
},
|
|
307
|
-
this.sanitizeAndCacheSummaryFromFull.bind(this),
|
|
308
|
-
this.deleteCachedSummary.bind(this),
|
|
309
|
-
);
|
|
298
|
+
const status = await this.instance.syncBlock({
|
|
299
|
+
blockNumber: l2Block.number,
|
|
300
|
+
blockHeaderHash: (await l2Block.hash()).toBuffer(),
|
|
301
|
+
// Forwarded so the native sync verifies the archive root against canonical and rejects a divergent tree.
|
|
302
|
+
expectedArchiveRoot: l2Block.archive.root.toBuffer(),
|
|
303
|
+
expectedPreviousArchiveRoot: l2Block.header.lastArchive.root.toBuffer(),
|
|
304
|
+
paddedL1ToL2Messages: paddedL1ToL2Messages.map(serializeLeaf),
|
|
305
|
+
paddedNoteHashes: paddedNoteHashes.map(serializeLeaf),
|
|
306
|
+
paddedNullifiers: paddedNullifiers.map(serializeLeaf),
|
|
307
|
+
publicDataWrites: publicDataWrites.map(serializeLeaf),
|
|
308
|
+
blockStateRef: blockStateReference(l2Block.header.state),
|
|
309
|
+
});
|
|
310
|
+
return this.sanitizeAndCacheSummaryFromFull(status);
|
|
310
311
|
} catch (err) {
|
|
312
|
+
this.deleteCachedSummary();
|
|
311
313
|
this.worldStateInstrumentation.incCriticalErrors('synch_pending_block');
|
|
312
314
|
throw err;
|
|
313
315
|
}
|
|
314
316
|
}
|
|
315
317
|
|
|
316
318
|
public async close(): Promise<void> {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
+
try {
|
|
320
|
+
await this.instance.close();
|
|
321
|
+
} finally {
|
|
322
|
+
await this.cleanup();
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
async [Symbol.asyncDispose](): Promise<void> {
|
|
327
|
+
await this.close();
|
|
319
328
|
}
|
|
320
329
|
|
|
321
330
|
private async buildInitialHeader(): Promise<BlockHeader> {
|
|
@@ -338,7 +347,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
338
347
|
return sanitized;
|
|
339
348
|
}
|
|
340
349
|
|
|
341
|
-
private deleteCachedSummary(
|
|
350
|
+
private deleteCachedSummary() {
|
|
342
351
|
this.cachedStatusSummary = undefined;
|
|
343
352
|
}
|
|
344
353
|
|
|
@@ -349,16 +358,9 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
349
358
|
*/
|
|
350
359
|
public async setFinalized(toBlockNumber: BlockNumber) {
|
|
351
360
|
try {
|
|
352
|
-
await this.instance.
|
|
353
|
-
WorldStateMessageType.FINALIZE_BLOCKS,
|
|
354
|
-
{
|
|
355
|
-
toBlockNumber,
|
|
356
|
-
canonical: true,
|
|
357
|
-
},
|
|
358
|
-
this.sanitizeAndCacheSummary.bind(this),
|
|
359
|
-
this.deleteCachedSummary.bind(this),
|
|
360
|
-
);
|
|
361
|
+
this.sanitizeAndCacheSummary(await this.instance.finalizeBlocks(toBlockNumber));
|
|
361
362
|
} catch (err) {
|
|
363
|
+
this.deleteCachedSummary();
|
|
362
364
|
this.worldStateInstrumentation.incCriticalErrors('finalize_block');
|
|
363
365
|
throw err;
|
|
364
366
|
}
|
|
@@ -372,16 +374,9 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
372
374
|
*/
|
|
373
375
|
public async removeHistoricalBlocks(toBlockNumber: BlockNumber) {
|
|
374
376
|
try {
|
|
375
|
-
return await this.instance.
|
|
376
|
-
WorldStateMessageType.REMOVE_HISTORICAL_BLOCKS,
|
|
377
|
-
{
|
|
378
|
-
toBlockNumber,
|
|
379
|
-
canonical: true,
|
|
380
|
-
},
|
|
381
|
-
this.sanitizeAndCacheSummaryFromFull.bind(this),
|
|
382
|
-
this.deleteCachedSummary.bind(this),
|
|
383
|
-
);
|
|
377
|
+
return this.sanitizeAndCacheSummaryFromFull(await this.instance.removeHistoricalBlocks(toBlockNumber));
|
|
384
378
|
} catch (err) {
|
|
379
|
+
this.deleteCachedSummary();
|
|
385
380
|
this.worldStateInstrumentation.incCriticalErrors('prune_historical_block');
|
|
386
381
|
throw err;
|
|
387
382
|
}
|
|
@@ -394,16 +389,9 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
394
389
|
*/
|
|
395
390
|
public async unwindBlocks(toBlockNumber: BlockNumber) {
|
|
396
391
|
try {
|
|
397
|
-
return await this.instance.
|
|
398
|
-
WorldStateMessageType.UNWIND_BLOCKS,
|
|
399
|
-
{
|
|
400
|
-
toBlockNumber,
|
|
401
|
-
canonical: true,
|
|
402
|
-
},
|
|
403
|
-
this.sanitizeAndCacheSummaryFromFull.bind(this),
|
|
404
|
-
this.deleteCachedSummary.bind(this),
|
|
405
|
-
);
|
|
392
|
+
return this.sanitizeAndCacheSummaryFromFull(await this.instance.unwindBlocks(toBlockNumber));
|
|
406
393
|
} catch (err) {
|
|
394
|
+
this.deleteCachedSummary();
|
|
407
395
|
this.worldStateInstrumentation.incCriticalErrors('prune_pending_block');
|
|
408
396
|
throw err;
|
|
409
397
|
}
|
|
@@ -413,11 +401,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
413
401
|
if (this.cachedStatusSummary !== undefined) {
|
|
414
402
|
return { ...this.cachedStatusSummary };
|
|
415
403
|
}
|
|
416
|
-
return await this.instance.
|
|
417
|
-
WorldStateMessageType.GET_STATUS,
|
|
418
|
-
{ canonical: true },
|
|
419
|
-
this.sanitizeAndCacheSummary.bind(this),
|
|
420
|
-
);
|
|
404
|
+
return this.sanitizeAndCacheSummary(await this.instance.getStatus());
|
|
421
405
|
}
|
|
422
406
|
|
|
423
407
|
updateLeaf<ID extends IndexedTreeId>(
|
|
@@ -429,14 +413,14 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
429
413
|
}
|
|
430
414
|
|
|
431
415
|
private async getInitialStateReference(): Promise<StateReference> {
|
|
432
|
-
const
|
|
416
|
+
const state = await this.instance.getInitialStateReference();
|
|
433
417
|
|
|
434
418
|
return new StateReference(
|
|
435
|
-
treeStateReferenceToSnapshot(
|
|
419
|
+
treeStateReferenceToSnapshot(state[MerkleTreeId.L1_TO_L2_MESSAGE_TREE]),
|
|
436
420
|
new PartialStateReference(
|
|
437
|
-
treeStateReferenceToSnapshot(
|
|
438
|
-
treeStateReferenceToSnapshot(
|
|
439
|
-
treeStateReferenceToSnapshot(
|
|
421
|
+
treeStateReferenceToSnapshot(state[MerkleTreeId.NOTE_HASH_TREE]),
|
|
422
|
+
treeStateReferenceToSnapshot(state[MerkleTreeId.NULLIFIER_TREE]),
|
|
423
|
+
treeStateReferenceToSnapshot(state[MerkleTreeId.PUBLIC_DATA_TREE]),
|
|
440
424
|
),
|
|
441
425
|
);
|
|
442
426
|
}
|
|
@@ -445,11 +429,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
445
429
|
dstPath: string,
|
|
446
430
|
compact: boolean = true,
|
|
447
431
|
): Promise<Record<Exclude<SnapshotDataKeys, 'archiver'>, string>> {
|
|
448
|
-
await this.instance.
|
|
449
|
-
dstPath,
|
|
450
|
-
compact,
|
|
451
|
-
canonical: true,
|
|
452
|
-
});
|
|
432
|
+
await this.instance.copyStores(dstPath, compact);
|
|
453
433
|
return fromEntries(NATIVE_WORLD_STATE_DBS.map(([name, dir]) => [name, join(dstPath, dir, 'data.mdb')] as const));
|
|
454
434
|
}
|
|
455
435
|
}
|