@aztec/world-state 0.0.1-commit.993d240 → 0.0.1-commit.9a89641
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 -488
- 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 -229
- 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 +108 -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 -210
- 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/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 +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 -495
- package/src/native/merkle_trees_facade.ts +59 -104
- package/src/native/message.ts +13 -296
- package/src/native/native_world_state.ts +136 -153
- package/src/native/native_world_state_instance.ts +94 -291
- package/src/native/world_state_operation.ts +33 -0
- package/src/synchronizer/errors.ts +8 -0
- package/src/synchronizer/factory.ts +0 -1
- 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_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,30 +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
|
-
this.deleteCachedSummary.bind(this),
|
|
306
|
-
);
|
|
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);
|
|
307
311
|
} catch (err) {
|
|
312
|
+
this.deleteCachedSummary();
|
|
308
313
|
this.worldStateInstrumentation.incCriticalErrors('synch_pending_block');
|
|
309
314
|
throw err;
|
|
310
315
|
}
|
|
311
316
|
}
|
|
312
317
|
|
|
313
318
|
public async close(): Promise<void> {
|
|
314
|
-
|
|
315
|
-
|
|
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();
|
|
316
328
|
}
|
|
317
329
|
|
|
318
330
|
private async buildInitialHeader(): Promise<BlockHeader> {
|
|
@@ -335,7 +347,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
335
347
|
return sanitized;
|
|
336
348
|
}
|
|
337
349
|
|
|
338
|
-
private deleteCachedSummary(
|
|
350
|
+
private deleteCachedSummary() {
|
|
339
351
|
this.cachedStatusSummary = undefined;
|
|
340
352
|
}
|
|
341
353
|
|
|
@@ -346,16 +358,9 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
346
358
|
*/
|
|
347
359
|
public async setFinalized(toBlockNumber: BlockNumber) {
|
|
348
360
|
try {
|
|
349
|
-
await this.instance.
|
|
350
|
-
WorldStateMessageType.FINALIZE_BLOCKS,
|
|
351
|
-
{
|
|
352
|
-
toBlockNumber,
|
|
353
|
-
canonical: true,
|
|
354
|
-
},
|
|
355
|
-
this.sanitizeAndCacheSummary.bind(this),
|
|
356
|
-
this.deleteCachedSummary.bind(this),
|
|
357
|
-
);
|
|
361
|
+
this.sanitizeAndCacheSummary(await this.instance.finalizeBlocks(toBlockNumber));
|
|
358
362
|
} catch (err) {
|
|
363
|
+
this.deleteCachedSummary();
|
|
359
364
|
this.worldStateInstrumentation.incCriticalErrors('finalize_block');
|
|
360
365
|
throw err;
|
|
361
366
|
}
|
|
@@ -369,16 +374,9 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
369
374
|
*/
|
|
370
375
|
public async removeHistoricalBlocks(toBlockNumber: BlockNumber) {
|
|
371
376
|
try {
|
|
372
|
-
return await this.instance.
|
|
373
|
-
WorldStateMessageType.REMOVE_HISTORICAL_BLOCKS,
|
|
374
|
-
{
|
|
375
|
-
toBlockNumber,
|
|
376
|
-
canonical: true,
|
|
377
|
-
},
|
|
378
|
-
this.sanitizeAndCacheSummaryFromFull.bind(this),
|
|
379
|
-
this.deleteCachedSummary.bind(this),
|
|
380
|
-
);
|
|
377
|
+
return this.sanitizeAndCacheSummaryFromFull(await this.instance.removeHistoricalBlocks(toBlockNumber));
|
|
381
378
|
} catch (err) {
|
|
379
|
+
this.deleteCachedSummary();
|
|
382
380
|
this.worldStateInstrumentation.incCriticalErrors('prune_historical_block');
|
|
383
381
|
throw err;
|
|
384
382
|
}
|
|
@@ -391,16 +389,9 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
391
389
|
*/
|
|
392
390
|
public async unwindBlocks(toBlockNumber: BlockNumber) {
|
|
393
391
|
try {
|
|
394
|
-
return await this.instance.
|
|
395
|
-
WorldStateMessageType.UNWIND_BLOCKS,
|
|
396
|
-
{
|
|
397
|
-
toBlockNumber,
|
|
398
|
-
canonical: true,
|
|
399
|
-
},
|
|
400
|
-
this.sanitizeAndCacheSummaryFromFull.bind(this),
|
|
401
|
-
this.deleteCachedSummary.bind(this),
|
|
402
|
-
);
|
|
392
|
+
return this.sanitizeAndCacheSummaryFromFull(await this.instance.unwindBlocks(toBlockNumber));
|
|
403
393
|
} catch (err) {
|
|
394
|
+
this.deleteCachedSummary();
|
|
404
395
|
this.worldStateInstrumentation.incCriticalErrors('prune_pending_block');
|
|
405
396
|
throw err;
|
|
406
397
|
}
|
|
@@ -410,11 +401,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
410
401
|
if (this.cachedStatusSummary !== undefined) {
|
|
411
402
|
return { ...this.cachedStatusSummary };
|
|
412
403
|
}
|
|
413
|
-
return await this.instance.
|
|
414
|
-
WorldStateMessageType.GET_STATUS,
|
|
415
|
-
{ canonical: true },
|
|
416
|
-
this.sanitizeAndCacheSummary.bind(this),
|
|
417
|
-
);
|
|
404
|
+
return this.sanitizeAndCacheSummary(await this.instance.getStatus());
|
|
418
405
|
}
|
|
419
406
|
|
|
420
407
|
updateLeaf<ID extends IndexedTreeId>(
|
|
@@ -426,14 +413,14 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
426
413
|
}
|
|
427
414
|
|
|
428
415
|
private async getInitialStateReference(): Promise<StateReference> {
|
|
429
|
-
const
|
|
416
|
+
const state = await this.instance.getInitialStateReference();
|
|
430
417
|
|
|
431
418
|
return new StateReference(
|
|
432
|
-
treeStateReferenceToSnapshot(
|
|
419
|
+
treeStateReferenceToSnapshot(state[MerkleTreeId.L1_TO_L2_MESSAGE_TREE]),
|
|
433
420
|
new PartialStateReference(
|
|
434
|
-
treeStateReferenceToSnapshot(
|
|
435
|
-
treeStateReferenceToSnapshot(
|
|
436
|
-
treeStateReferenceToSnapshot(
|
|
421
|
+
treeStateReferenceToSnapshot(state[MerkleTreeId.NOTE_HASH_TREE]),
|
|
422
|
+
treeStateReferenceToSnapshot(state[MerkleTreeId.NULLIFIER_TREE]),
|
|
423
|
+
treeStateReferenceToSnapshot(state[MerkleTreeId.PUBLIC_DATA_TREE]),
|
|
437
424
|
),
|
|
438
425
|
);
|
|
439
426
|
}
|
|
@@ -442,11 +429,7 @@ export class NativeWorldStateService implements MerkleTreeDatabase {
|
|
|
442
429
|
dstPath: string,
|
|
443
430
|
compact: boolean = true,
|
|
444
431
|
): Promise<Record<Exclude<SnapshotDataKeys, 'archiver'>, string>> {
|
|
445
|
-
await this.instance.
|
|
446
|
-
dstPath,
|
|
447
|
-
compact,
|
|
448
|
-
canonical: true,
|
|
449
|
-
});
|
|
432
|
+
await this.instance.copyStores(dstPath, compact);
|
|
450
433
|
return fromEntries(NATIVE_WORLD_STATE_DBS.map(([name, dir]) => [name, join(dstPath, dir, 'data.mdb')] as const));
|
|
451
434
|
}
|
|
452
435
|
}
|