@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
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
import { AsyncApi } from '@aztec/bb.js/aztec-wsdb';
|
|
2
|
-
import type {
|
|
3
|
-
WorldStateDBStats as WsdbDBStats,
|
|
4
|
-
DBStats as WsdbDBStatsInner,
|
|
5
|
-
WorldStateMeta as WsdbMeta,
|
|
6
|
-
SiblingPathAndIndex as WsdbSiblingPathAndIndex,
|
|
7
|
-
WorldStateStatusFull as WsdbStatusFull,
|
|
8
|
-
WorldStateStatusSummary as WsdbStatusSummary,
|
|
9
|
-
TreeDBStats as WsdbTreeDBStats,
|
|
10
|
-
TreeMeta as WsdbTreeMeta,
|
|
11
|
-
} from '@aztec/bb.js/aztec-wsdb';
|
|
12
1
|
import {
|
|
13
2
|
ARCHIVE_HEIGHT,
|
|
14
3
|
DomainSeparator,
|
|
@@ -19,62 +8,224 @@ import {
|
|
|
19
8
|
NULLIFIER_TREE_HEIGHT,
|
|
20
9
|
PUBLIC_DATA_TREE_HEIGHT,
|
|
21
10
|
} from '@aztec/constants';
|
|
11
|
+
import type { BlockNumber } from '@aztec/foundation/branded-types';
|
|
12
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
22
13
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
14
|
+
import type { IndexedTreeId, TreeInfo } from '@aztec/stdlib/interfaces/server';
|
|
23
15
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
24
|
-
import type { WorldStateRevision } from '@aztec/stdlib/world-state';
|
|
16
|
+
import type { GenesisData, WorldStateRevision } from '@aztec/stdlib/world-state';
|
|
17
|
+
import { AsyncApi, WsdbService } from '@aztec/wsdb';
|
|
18
|
+
import type {
|
|
19
|
+
WorldStateDBStats as WsdbDBStats,
|
|
20
|
+
DBStats as WsdbDBStatsInner,
|
|
21
|
+
WorldStateMeta as WsdbMeta,
|
|
22
|
+
SiblingPathAndIndex as WsdbSiblingPathAndIndex,
|
|
23
|
+
WorldStateStatusFull as WsdbStatusFull,
|
|
24
|
+
WorldStateStatusSummary as WsdbStatusSummary,
|
|
25
|
+
TreeDBStats as WsdbTreeDBStats,
|
|
26
|
+
TreeMeta as WsdbTreeMeta,
|
|
27
|
+
} from '@aztec/wsdb';
|
|
25
28
|
|
|
26
|
-
import
|
|
27
|
-
import { Decoder, Encoder } from 'msgpackr';
|
|
29
|
+
import { cpus } from 'node:os';
|
|
28
30
|
|
|
29
31
|
import type { WorldStateInstrumentation } from '../instrumentation/instrumentation.js';
|
|
30
32
|
import type { WorldStateTreeMapSizes } from '../synchronizer/factory.js';
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
isWithForkId,
|
|
47
|
-
isWithRevision,
|
|
33
|
+
import type {
|
|
34
|
+
BlockStateReference,
|
|
35
|
+
DBStats,
|
|
36
|
+
SerializedBatchInsertionResult,
|
|
37
|
+
SerializedIndexedLeaf,
|
|
38
|
+
SerializedLeafValue,
|
|
39
|
+
SerializedSequentialInsertionResult,
|
|
40
|
+
SerializedSiblingPathAndIndex,
|
|
41
|
+
TreeDBStats,
|
|
42
|
+
TreeMeta,
|
|
43
|
+
TreeStateReference,
|
|
44
|
+
WorldStateDBStats,
|
|
45
|
+
WorldStateMeta,
|
|
46
|
+
WorldStateStatusFull,
|
|
47
|
+
WorldStateStatusSummary,
|
|
48
48
|
} from './message.js';
|
|
49
49
|
import type { NativeWorldStateInstance } from './native_world_state_instance.js';
|
|
50
|
-
import {
|
|
50
|
+
import type { WorldStateOperationName } from './world_state_operation.js';
|
|
51
|
+
|
|
52
|
+
// ————— Request conversion helpers —————
|
|
53
|
+
|
|
54
|
+
function toWsdbRevision(rev: WorldStateRevision): { forkId: number; blockNumber: number; includeUncommitted: boolean } {
|
|
55
|
+
return {
|
|
56
|
+
forkId: rev.forkId,
|
|
57
|
+
blockNumber: Number(rev.blockNumber),
|
|
58
|
+
includeUncommitted: rev.includeUncommitted,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function blockStateRefToMap(ref: Map<number, readonly [Buffer, number | bigint]>) {
|
|
63
|
+
return [...ref.entries()].map(([treeId, [root, size]]) => ({
|
|
64
|
+
treeId,
|
|
65
|
+
root: new Uint8Array(root),
|
|
66
|
+
size: Number(size),
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function toPublicDataLeaf(leaf: SerializedLeafValue): { slot: Uint8Array; value: Uint8Array } {
|
|
71
|
+
if (leaf instanceof Buffer || !('slot' in leaf)) {
|
|
72
|
+
throw new Error('Expected public data leaf');
|
|
73
|
+
}
|
|
74
|
+
return { slot: new Uint8Array(leaf.slot), value: new Uint8Array(leaf.value) };
|
|
75
|
+
}
|
|
51
76
|
|
|
52
|
-
|
|
77
|
+
function toNullifierLeaf(leaf: SerializedLeafValue): { nullifier: Uint8Array } {
|
|
78
|
+
if (leaf instanceof Buffer || !('nullifier' in leaf)) {
|
|
79
|
+
throw new Error('Expected nullifier leaf');
|
|
80
|
+
}
|
|
81
|
+
return { nullifier: new Uint8Array(leaf.nullifier) };
|
|
82
|
+
}
|
|
53
83
|
|
|
54
|
-
|
|
55
|
-
|
|
84
|
+
function fromPublicDataLeaf(leaf: { slot: Uint8Array; value: Uint8Array }): Exclude<SerializedLeafValue, Buffer> {
|
|
85
|
+
return { slot: Buffer.from(leaf.slot), value: Buffer.from(leaf.value) };
|
|
86
|
+
}
|
|
56
87
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return Buffer.from(msgpackEncoder.pack(leaf));
|
|
88
|
+
function fromNullifierLeaf(leaf: { nullifier: Uint8Array }): Exclude<SerializedLeafValue, Buffer> {
|
|
89
|
+
return { nullifier: Buffer.from(leaf.nullifier) };
|
|
60
90
|
}
|
|
61
91
|
|
|
62
|
-
|
|
92
|
+
type WireIndexedLeaf<TLeaf> = { leaf: TLeaf; nextIndex: number; nextKey: Uint8Array };
|
|
93
|
+
type WireLeafUpdateWitnessData<TLeaf> = { leaf: WireIndexedLeaf<TLeaf>; index: number; path: Uint8Array[] };
|
|
94
|
+
|
|
95
|
+
function fromIndexedLeaf<TLeaf>(
|
|
96
|
+
leaf: WireIndexedLeaf<TLeaf>,
|
|
97
|
+
convertLeaf: (leaf: TLeaf) => Exclude<SerializedLeafValue, Buffer>,
|
|
98
|
+
) {
|
|
99
|
+
return {
|
|
100
|
+
leaf: convertLeaf(leaf.leaf),
|
|
101
|
+
nextIndex: leaf.nextIndex,
|
|
102
|
+
nextKey: Buffer.from(leaf.nextKey),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function fromLeafUpdateWitnessData<TLeaf>(
|
|
107
|
+
data: WireLeafUpdateWitnessData<TLeaf>,
|
|
108
|
+
convertLeaf: (leaf: TLeaf) => Exclude<SerializedLeafValue, Buffer>,
|
|
109
|
+
) {
|
|
110
|
+
return {
|
|
111
|
+
leaf: fromIndexedLeaf(data.leaf, convertLeaf),
|
|
112
|
+
index: data.index,
|
|
113
|
+
path: data.path.map(p => Buffer.from(p)),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function fromBatchInsertionResult<
|
|
118
|
+
TLeaf,
|
|
119
|
+
TResult extends {
|
|
120
|
+
lowLeafWitnessData: Array<WireLeafUpdateWitnessData<TLeaf>>;
|
|
121
|
+
sortedLeaves: Array<{ leaf: TLeaf; index: number }>;
|
|
122
|
+
subtreePath: Uint8Array[];
|
|
123
|
+
},
|
|
124
|
+
>(result: TResult, convertLeaf: (leaf: TLeaf) => Exclude<SerializedLeafValue, Buffer>) {
|
|
125
|
+
return {
|
|
126
|
+
lowLeafWitnessData: result.lowLeafWitnessData.map(data => fromLeafUpdateWitnessData(data, convertLeaf)),
|
|
127
|
+
sortedLeaves: result.sortedLeaves.map(({ leaf, index }) => [convertLeaf(leaf), index] as const),
|
|
128
|
+
subtreePath: result.subtreePath.map(p => Buffer.from(p)),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
63
131
|
|
|
64
|
-
function
|
|
132
|
+
function fromSequentialInsertionResult<
|
|
133
|
+
TLeaf,
|
|
134
|
+
TResult extends {
|
|
135
|
+
lowLeafWitnessData: Array<WireLeafUpdateWitnessData<TLeaf>>;
|
|
136
|
+
insertionWitnessData: Array<WireLeafUpdateWitnessData<TLeaf>>;
|
|
137
|
+
},
|
|
138
|
+
>(result: TResult, convertLeaf: (leaf: TLeaf) => Exclude<SerializedLeafValue, Buffer>) {
|
|
65
139
|
return {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
includeuncommitted: rev.includeUncommitted,
|
|
140
|
+
lowLeafWitnessData: result.lowLeafWitnessData.map(data => fromLeafUpdateWitnessData(data, convertLeaf)),
|
|
141
|
+
insertionWitnessData: result.insertionWitnessData.map(data => fromLeafUpdateWitnessData(data, convertLeaf)),
|
|
69
142
|
};
|
|
70
143
|
}
|
|
71
144
|
|
|
72
|
-
function
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
result.set(treeId, [new Uint8Array(root), Number(size)]);
|
|
145
|
+
function toFrLeaf(leaf: SerializedLeafValue): Uint8Array {
|
|
146
|
+
if (!(leaf instanceof Buffer)) {
|
|
147
|
+
throw new Error('Expected field leaf');
|
|
76
148
|
}
|
|
77
|
-
return
|
|
149
|
+
return new Uint8Array(leaf);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function formatMap(map: Record<number, number> | undefined): string | undefined {
|
|
153
|
+
if (!map || Object.keys(map).length === 0) {
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
return `{${Object.entries(map)
|
|
157
|
+
.map(([key, value]) => `${key}:${value}`)
|
|
158
|
+
.join(',')}}`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** SHM request/response ring size for the spawned aztec-wsdb process (32 MiB). */
|
|
162
|
+
const WSDB_SHM_RING_SIZE = 32 * 1024 * 1024;
|
|
163
|
+
|
|
164
|
+
function getWsdbThreadCount(): number {
|
|
165
|
+
return Math.min(16, cpus().length);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function getWsdbExtraArgs(
|
|
169
|
+
dataDir: string,
|
|
170
|
+
wsTreeMapSizes: WorldStateTreeMapSizes,
|
|
171
|
+
genesis: GenesisData,
|
|
172
|
+
threads: number,
|
|
173
|
+
): string[] {
|
|
174
|
+
const options = getWsdbOptions(dataDir, wsTreeMapSizes);
|
|
175
|
+
const args = ['--data-dir', dataDir, '--threads', threads.toString()];
|
|
176
|
+
|
|
177
|
+
// Size the SHM rings generously. Responses such as batch-insertion witnesses
|
|
178
|
+
// run to a few MB, and an SHM frame is capped at half the ring (the wrap
|
|
179
|
+
// handling needs that headroom), so 32 MiB rings give ~16 MiB per message.
|
|
180
|
+
// Ignored by the UDS transport. Pages are demand-faulted, so unused capacity
|
|
181
|
+
// is cheap.
|
|
182
|
+
args.push('--request-ring-size', WSDB_SHM_RING_SIZE.toString());
|
|
183
|
+
args.push('--response-ring-size', WSDB_SHM_RING_SIZE.toString());
|
|
184
|
+
|
|
185
|
+
const treeHeights = formatMap(options.treeHeights);
|
|
186
|
+
if (treeHeights) {
|
|
187
|
+
args.push('--tree-heights', treeHeights);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const treePrefill = formatMap(options.treePrefill);
|
|
191
|
+
if (treePrefill) {
|
|
192
|
+
args.push('--tree-prefill', treePrefill);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const mapSizes = formatMap(options.mapSizes);
|
|
196
|
+
if (mapSizes) {
|
|
197
|
+
args.push('--map-sizes', mapSizes);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
args.push('--initial-header-generator-point', options.initialHeaderGeneratorPoint.toString());
|
|
201
|
+
|
|
202
|
+
if (genesis.prefilledPublicData.length > 0) {
|
|
203
|
+
const pairs = genesis.prefilledPublicData.map(data => [
|
|
204
|
+
data.slot.toBuffer().toString('hex'),
|
|
205
|
+
data.value.toBuffer().toString('hex'),
|
|
206
|
+
]);
|
|
207
|
+
args.push('--prefilled-public-data', JSON.stringify(pairs));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const prefilledNullifiers = genesis.prefilledNullifiers ?? [];
|
|
211
|
+
for (let i = 1; i < prefilledNullifiers.length; i++) {
|
|
212
|
+
if (prefilledNullifiers[i].toBigInt() <= prefilledNullifiers[i - 1].toBigInt()) {
|
|
213
|
+
throw new Error('Prefilled genesis nullifiers must be unique and strictly increasing');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (prefilledNullifiers.length > 0) {
|
|
217
|
+
args.push(
|
|
218
|
+
'--prefilled-nullifiers',
|
|
219
|
+
JSON.stringify(prefilledNullifiers.map(nullifier => nullifier.toBuffer().toString('hex'))),
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const genesisTimestamp = Number(genesis.genesisTimestamp);
|
|
224
|
+
if (genesisTimestamp !== 0) {
|
|
225
|
+
args.push('--genesis-timestamp', genesisTimestamp.toString());
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return args;
|
|
78
229
|
}
|
|
79
230
|
|
|
80
231
|
// ————— Response conversion helpers —————
|
|
@@ -97,66 +248,54 @@ function convertUint8ArraysToBuffers(obj: unknown): unknown {
|
|
|
97
248
|
return obj;
|
|
98
249
|
}
|
|
99
250
|
|
|
100
|
-
/** Decode a msgpack-encoded leaf value blob and convert Uint8Arrays to Buffers. */
|
|
101
|
-
function decodeLeafValue(encoded: Uint8Array): SerializedLeafValue {
|
|
102
|
-
const decoded = msgpackDecoder.unpack(Buffer.from(encoded));
|
|
103
|
-
return convertUint8ArraysToBuffers(decoded) as SerializedLeafValue;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/** Decode a msgpack-encoded indexed leaf preimage blob. */
|
|
107
|
-
function decodeLeafPreimage(encoded: Uint8Array): SerializedIndexedLeaf {
|
|
108
|
-
const decoded = msgpackDecoder.unpack(Buffer.from(encoded));
|
|
109
|
-
return convertUint8ArraysToBuffers(decoded) as SerializedIndexedLeaf;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
251
|
/** Convert Wsdb state reference (Record<number, [Uint8Array, number]>) to NAPI format. */
|
|
113
252
|
function convertStateRef(
|
|
114
|
-
state:
|
|
253
|
+
state: Array<{ treeId: number; root: Uint8Array; size: number }>,
|
|
115
254
|
): Record<number, readonly [Buffer, number | bigint]> {
|
|
116
255
|
const result: Record<number, readonly [Buffer, number | bigint]> = {};
|
|
117
|
-
for (const
|
|
118
|
-
result[
|
|
256
|
+
for (const { treeId, root, size } of state) {
|
|
257
|
+
result[treeId] = [Buffer.from(root), BigInt(size)] as const;
|
|
119
258
|
}
|
|
120
259
|
return result;
|
|
121
260
|
}
|
|
122
261
|
|
|
123
|
-
/** Convert Wsdb WorldStateStatusSummary
|
|
262
|
+
/** Convert Wsdb WorldStateStatusSummary to the native world-state format. */
|
|
124
263
|
function convertStatusSummary(s: WsdbStatusSummary): WorldStateStatusSummary {
|
|
125
264
|
return {
|
|
126
|
-
unfinalizedBlockNumber: s.
|
|
127
|
-
finalizedBlockNumber: s.
|
|
128
|
-
oldestHistoricalBlock: s.
|
|
129
|
-
treesAreSynched: s.
|
|
265
|
+
unfinalizedBlockNumber: s.unfinalizedBlockNumber,
|
|
266
|
+
finalizedBlockNumber: s.finalizedBlockNumber,
|
|
267
|
+
oldestHistoricalBlock: s.oldestHistoricalBlock,
|
|
268
|
+
treesAreSynched: s.treesAreSynched,
|
|
130
269
|
} as unknown as WorldStateStatusSummary;
|
|
131
270
|
}
|
|
132
271
|
|
|
133
272
|
function convertDBStats(s: WsdbDBStatsInner): DBStats {
|
|
134
273
|
return {
|
|
135
274
|
name: s.name,
|
|
136
|
-
numDataItems: s.
|
|
137
|
-
totalUsedSize: s.
|
|
275
|
+
numDataItems: s.numDataItems,
|
|
276
|
+
totalUsedSize: s.totalUsedSize,
|
|
138
277
|
} as unknown as DBStats;
|
|
139
278
|
}
|
|
140
279
|
|
|
141
280
|
function convertTreeDBStats(s: WsdbTreeDBStats): TreeDBStats {
|
|
142
281
|
return {
|
|
143
|
-
mapSize: s.
|
|
144
|
-
physicalFileSize: s.
|
|
145
|
-
blocksDBStats: convertDBStats(s.
|
|
146
|
-
nodesDBStats: convertDBStats(s.
|
|
147
|
-
leafPreimagesDBStats: convertDBStats(s.
|
|
148
|
-
leafIndicesDBStats: convertDBStats(s.
|
|
149
|
-
blockIndicesDBStats: convertDBStats(s.
|
|
282
|
+
mapSize: s.mapSize,
|
|
283
|
+
physicalFileSize: s.physicalFileSize,
|
|
284
|
+
blocksDBStats: convertDBStats(s.blocksDBStats),
|
|
285
|
+
nodesDBStats: convertDBStats(s.nodesDBStats),
|
|
286
|
+
leafPreimagesDBStats: convertDBStats(s.leafPreimagesDBStats),
|
|
287
|
+
leafIndicesDBStats: convertDBStats(s.leafIndicesDBStats),
|
|
288
|
+
blockIndicesDBStats: convertDBStats(s.blockIndicesDBStats),
|
|
150
289
|
} as unknown as TreeDBStats;
|
|
151
290
|
}
|
|
152
291
|
|
|
153
292
|
function convertWorldStateDBStats(s: WsdbDBStats): WorldStateDBStats {
|
|
154
293
|
return {
|
|
155
|
-
noteHashTreeStats: convertTreeDBStats(s.
|
|
156
|
-
messageTreeStats: convertTreeDBStats(s.
|
|
157
|
-
archiveTreeStats: convertTreeDBStats(s.
|
|
158
|
-
publicDataTreeStats: convertTreeDBStats(s.
|
|
159
|
-
nullifierTreeStats: convertTreeDBStats(s.
|
|
294
|
+
noteHashTreeStats: convertTreeDBStats(s.noteHashTreeStats),
|
|
295
|
+
messageTreeStats: convertTreeDBStats(s.messageTreeStats),
|
|
296
|
+
archiveTreeStats: convertTreeDBStats(s.archiveTreeStats),
|
|
297
|
+
publicDataTreeStats: convertTreeDBStats(s.publicDataTreeStats),
|
|
298
|
+
nullifierTreeStats: convertTreeDBStats(s.nullifierTreeStats),
|
|
160
299
|
} as unknown as WorldStateDBStats;
|
|
161
300
|
}
|
|
162
301
|
|
|
@@ -165,37 +304,37 @@ function convertTreeMeta(m: WsdbTreeMeta): TreeMeta {
|
|
|
165
304
|
name: m.name,
|
|
166
305
|
depth: m.depth,
|
|
167
306
|
size: m.size,
|
|
168
|
-
committedSize: m.
|
|
307
|
+
committedSize: m.committedSize,
|
|
169
308
|
root: m.root,
|
|
170
|
-
initialSize: m.
|
|
171
|
-
initialRoot: m.
|
|
172
|
-
oldestHistoricBlock: m.
|
|
173
|
-
unfinalizedBlockHeight: m.
|
|
174
|
-
finalizedBlockHeight: m.
|
|
309
|
+
initialSize: m.initialSize,
|
|
310
|
+
initialRoot: m.initialRoot,
|
|
311
|
+
oldestHistoricBlock: m.oldestHistoricBlock,
|
|
312
|
+
unfinalizedBlockHeight: m.unfinalizedBlockHeight,
|
|
313
|
+
finalizedBlockHeight: m.finalizedBlockHeight,
|
|
175
314
|
} as unknown as TreeMeta;
|
|
176
315
|
}
|
|
177
316
|
|
|
178
317
|
function convertWorldStateMeta(m: WsdbMeta): WorldStateMeta {
|
|
179
318
|
return {
|
|
180
|
-
noteHashTreeMeta: convertTreeMeta(m.
|
|
181
|
-
messageTreeMeta: convertTreeMeta(m.
|
|
182
|
-
archiveTreeMeta: convertTreeMeta(m.
|
|
183
|
-
publicDataTreeMeta: convertTreeMeta(m.
|
|
184
|
-
nullifierTreeMeta: convertTreeMeta(m.
|
|
319
|
+
noteHashTreeMeta: convertTreeMeta(m.noteHashTreeMeta),
|
|
320
|
+
messageTreeMeta: convertTreeMeta(m.messageTreeMeta),
|
|
321
|
+
archiveTreeMeta: convertTreeMeta(m.archiveTreeMeta),
|
|
322
|
+
publicDataTreeMeta: convertTreeMeta(m.publicDataTreeMeta),
|
|
323
|
+
nullifierTreeMeta: convertTreeMeta(m.nullifierTreeMeta),
|
|
185
324
|
} as unknown as WorldStateMeta;
|
|
186
325
|
}
|
|
187
326
|
|
|
188
327
|
function convertStatusFull(s: WsdbStatusFull): WorldStateStatusFull {
|
|
189
328
|
return {
|
|
190
329
|
summary: convertStatusSummary(s.summary),
|
|
191
|
-
dbStats: convertWorldStateDBStats(s.
|
|
330
|
+
dbStats: convertWorldStateDBStats(s.dbStats),
|
|
192
331
|
meta: convertWorldStateMeta(s.meta),
|
|
193
332
|
} as unknown as WorldStateStatusFull;
|
|
194
333
|
}
|
|
195
334
|
|
|
196
335
|
/** Convert Wsdb SiblingPathAndIndex to NAPI format. */
|
|
197
336
|
function convertSiblingPathAndIndex(
|
|
198
|
-
s: WsdbSiblingPathAndIndex | undefined,
|
|
337
|
+
s: WsdbSiblingPathAndIndex | null | undefined,
|
|
199
338
|
): { index: bigint; path: Buffer[] } | undefined {
|
|
200
339
|
if (!s) {
|
|
201
340
|
return undefined;
|
|
@@ -208,108 +347,50 @@ function convertSiblingPathAndIndex(
|
|
|
208
347
|
|
|
209
348
|
// ————— Public API —————
|
|
210
349
|
|
|
211
|
-
/** Backend interface matching WsdbBackend from bb.js. */
|
|
212
|
-
export interface WsdbIpcBackend {
|
|
213
|
-
call(inputBuffer: Uint8Array): Promise<Uint8Array>;
|
|
214
|
-
getSocketPath(): string;
|
|
215
|
-
destroy?(): Promise<void>;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
350
|
/**
|
|
219
351
|
* IPC-backed world state instance.
|
|
220
|
-
* Uses
|
|
352
|
+
* Uses WsdbService (spawns aztec-wsdb binary) and the generated AsyncApi
|
|
221
353
|
* to communicate via the NamedUnion IPC protocol.
|
|
222
354
|
*/
|
|
223
355
|
export class IpcWorldState implements NativeWorldStateInstance {
|
|
224
356
|
private open = true;
|
|
225
|
-
private queues = new Map<number, WorldStateOpsQueue>();
|
|
226
357
|
private api: AsyncApi;
|
|
227
358
|
/** Tracks checkpoint depth per fork (WSDB IPC doesn't return depth in response). */
|
|
228
359
|
private checkpointDepths = new Map<number, number>();
|
|
229
360
|
|
|
230
361
|
constructor(
|
|
231
|
-
private readonly
|
|
362
|
+
private readonly wsdb: WsdbService,
|
|
232
363
|
private readonly instrumentation: WorldStateInstrumentation,
|
|
233
364
|
bindings?: LoggerBindings,
|
|
234
365
|
private readonly log: Logger = createLogger('world-state:ipc-database', bindings),
|
|
235
366
|
) {
|
|
236
|
-
this.api =
|
|
237
|
-
this.queues.set(0, new WorldStateOpsQueue());
|
|
367
|
+
this.api = wsdb;
|
|
238
368
|
this.log.info('Created IPC-backed world state instance');
|
|
239
369
|
}
|
|
240
370
|
|
|
241
|
-
/** Returns the socket path of the underlying wsdb server. */
|
|
242
|
-
getSocketPath(): string {
|
|
243
|
-
return this.wsdbBackend.getSocketPath();
|
|
244
|
-
}
|
|
245
|
-
|
|
246
371
|
/**
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
* need to reach the WSDB process must use {@link getSocketPath} instead.
|
|
372
|
+
* Spawn an `aztec-wsdb` subprocess and return an IPC-backed world state wrapping it.
|
|
373
|
+
* Encapsulates wsdb binary discovery, service construction, and readiness wait.
|
|
250
374
|
*/
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
forkId = body.forkId;
|
|
268
|
-
} else if (isWithRevision(body)) {
|
|
269
|
-
forkId = body.revision.forkId;
|
|
270
|
-
committedOnly = body.revision.includeUncommitted === false;
|
|
271
|
-
} else {
|
|
272
|
-
const _: never = body;
|
|
273
|
-
throw new Error(`Unable to determine forkId for message=${WorldStateMessageType[messageType]}`);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
let requestQueue = this.queues.get(forkId);
|
|
277
|
-
if (requestQueue === undefined) {
|
|
278
|
-
requestQueue = new WorldStateOpsQueue();
|
|
279
|
-
this.queues.set(forkId, requestQueue);
|
|
280
|
-
}
|
|
375
|
+
static async spawn(
|
|
376
|
+
dataDir: string,
|
|
377
|
+
wsTreeMapSizes: WorldStateTreeMapSizes,
|
|
378
|
+
genesis: GenesisData,
|
|
379
|
+
instrumentation: WorldStateInstrumentation,
|
|
380
|
+
bindings?: LoggerBindings,
|
|
381
|
+
threads: number = getWsdbThreadCount(),
|
|
382
|
+
): Promise<IpcWorldState> {
|
|
383
|
+
const transport = process.env.WSDB_TRANSPORT === 'shm' ? 'shm' : 'uds';
|
|
384
|
+
const wsdb = await WsdbService.spawn({
|
|
385
|
+
transport,
|
|
386
|
+
extraArgs: getWsdbExtraArgs(dataDir, wsTreeMapSizes, genesis, threads),
|
|
387
|
+
env: { HARDWARE_CONCURRENCY: threads.toString() },
|
|
388
|
+
});
|
|
389
|
+
return new IpcWorldState(wsdb, instrumentation, bindings);
|
|
390
|
+
}
|
|
281
391
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
// DELETE_FORK rejects with "Fork not found").
|
|
285
|
-
let shouldDeleteForkQueue = false;
|
|
286
|
-
try {
|
|
287
|
-
const response = await requestQueue.execute(
|
|
288
|
-
async () => {
|
|
289
|
-
assert.notEqual(messageType, WorldStateMessageType.CLOSE, 'Use close() to close the IPC instance');
|
|
290
|
-
assert.equal(this.open, true, 'IPC instance is closed');
|
|
291
|
-
let response: WorldStateResponse[T];
|
|
292
|
-
try {
|
|
293
|
-
response = await this._sendMessage(messageType, body);
|
|
294
|
-
} catch (error: any) {
|
|
295
|
-
errorHandler(error.message);
|
|
296
|
-
throw error;
|
|
297
|
-
}
|
|
298
|
-
return responseHandler(response);
|
|
299
|
-
},
|
|
300
|
-
messageType,
|
|
301
|
-
committedOnly,
|
|
302
|
-
);
|
|
303
|
-
return response;
|
|
304
|
-
} catch (err: any) {
|
|
305
|
-
shouldDeleteForkQueue = forkId !== 0 && err?.message === 'Fork not found';
|
|
306
|
-
throw err;
|
|
307
|
-
} finally {
|
|
308
|
-
if (messageType === WorldStateMessageType.DELETE_FORK || shouldDeleteForkQueue) {
|
|
309
|
-
await requestQueue.stop();
|
|
310
|
-
this.queues.delete(forkId);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
392
|
+
getIpcPath(): string {
|
|
393
|
+
return this.wsdb.getIpcPath();
|
|
313
394
|
}
|
|
314
395
|
|
|
315
396
|
async close(): Promise<void> {
|
|
@@ -317,380 +398,421 @@ export class IpcWorldState implements NativeWorldStateInstance {
|
|
|
317
398
|
return;
|
|
318
399
|
}
|
|
319
400
|
this.open = false;
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
// Send shutdown command. Under normal operation, the WSDB process sends its
|
|
323
|
-
// response before exiting (via ShutdownRequested in ipc_server.hpp). The
|
|
324
|
-
// try/catch is defensive: if the process is killed externally (SIGKILL, OOM)
|
|
325
|
-
// before responding, the pending IPC callback would be rejected by the socket
|
|
326
|
-
// close handler. We proceed to destroy the backend regardless.
|
|
327
|
-
try {
|
|
328
|
-
await queue.execute(
|
|
329
|
-
async () => {
|
|
330
|
-
await this.api.wsdbShutdown({});
|
|
331
|
-
},
|
|
332
|
-
WorldStateMessageType.CLOSE,
|
|
333
|
-
false,
|
|
334
|
-
);
|
|
335
|
-
} catch (err: any) {
|
|
336
|
-
this.log.debug(`wsdbShutdown completed with error: ${err.message}`);
|
|
337
|
-
}
|
|
338
|
-
await queue.stop();
|
|
339
|
-
|
|
340
|
-
if (this.wsdbBackend.destroy) {
|
|
341
|
-
await this.wsdbBackend.destroy();
|
|
342
|
-
}
|
|
401
|
+
await this.wsdb.destroy();
|
|
343
402
|
}
|
|
344
403
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
return response;
|
|
356
|
-
} catch (error) {
|
|
357
|
-
this.log.error(`Call ${WorldStateMessageType[messageType]} failed: ${error}`, error);
|
|
358
|
-
throw error;
|
|
359
|
-
}
|
|
404
|
+
getTreeInfo(treeId: MerkleTreeId, revision: WorldStateRevision): Promise<TreeInfo> {
|
|
405
|
+
return this.execute('getTreeInfo', revision.forkId, revision.includeUncommitted === false, async () => {
|
|
406
|
+
const resp = await this.api.getTreeInfo({ treeId, revision: toWsdbRevision(revision) });
|
|
407
|
+
return {
|
|
408
|
+
treeId: resp.treeId,
|
|
409
|
+
root: Buffer.from(resp.root),
|
|
410
|
+
size: BigInt(resp.size),
|
|
411
|
+
depth: resp.depth,
|
|
412
|
+
};
|
|
413
|
+
});
|
|
360
414
|
}
|
|
361
415
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
case WorldStateMessageType.GET_TREE_INFO: {
|
|
370
|
-
const b = body as WorldStateRequest[WorldStateMessageType.GET_TREE_INFO];
|
|
371
|
-
const resp = await this.api.wsdbGetTreeInfo({
|
|
372
|
-
treeid: b.treeId,
|
|
373
|
-
revision: toWsdbRevision(b.revision),
|
|
374
|
-
});
|
|
375
|
-
return {
|
|
376
|
-
treeId: resp.treeid,
|
|
377
|
-
root: Buffer.from(resp.root),
|
|
378
|
-
size: resp.size,
|
|
379
|
-
depth: resp.depth,
|
|
380
|
-
} as WorldStateResponse[T];
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
case WorldStateMessageType.GET_STATE_REFERENCE: {
|
|
384
|
-
const b = body as WorldStateRequest[WorldStateMessageType.GET_STATE_REFERENCE];
|
|
385
|
-
const resp = await this.api.wsdbGetStateReference({
|
|
386
|
-
revision: toWsdbRevision(b.revision),
|
|
387
|
-
});
|
|
388
|
-
return { state: convertStateRef(resp.state) } as WorldStateResponse[T];
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
case WorldStateMessageType.GET_INITIAL_STATE_REFERENCE: {
|
|
392
|
-
const resp = await this.api.wsdbGetInitialStateReference({});
|
|
393
|
-
return { state: convertStateRef(resp.state) } as WorldStateResponse[T];
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// ——— Leaf queries ———
|
|
397
|
-
|
|
398
|
-
case WorldStateMessageType.GET_LEAF_VALUE: {
|
|
399
|
-
const b = body as WorldStateRequest[WorldStateMessageType.GET_LEAF_VALUE];
|
|
400
|
-
const resp = await this.api.wsdbGetLeafValue({
|
|
401
|
-
treeid: b.treeId,
|
|
402
|
-
revision: toWsdbRevision(b.revision),
|
|
403
|
-
leafindex: Number(b.leafIndex),
|
|
404
|
-
});
|
|
405
|
-
if (!resp.value) {
|
|
406
|
-
return undefined as WorldStateResponse[T];
|
|
407
|
-
}
|
|
408
|
-
return decodeLeafValue(resp.value) as WorldStateResponse[T];
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
case WorldStateMessageType.GET_LEAF_PREIMAGE: {
|
|
412
|
-
const b = body as WorldStateRequest[WorldStateMessageType.GET_LEAF_PREIMAGE];
|
|
413
|
-
const resp = await this.api.wsdbGetLeafPreimage({
|
|
414
|
-
treeid: b.treeId,
|
|
415
|
-
revision: toWsdbRevision(b.revision),
|
|
416
|
-
leafindex: Number(b.leafIndex),
|
|
417
|
-
});
|
|
418
|
-
if (!resp.preimage) {
|
|
419
|
-
return undefined as WorldStateResponse[T];
|
|
420
|
-
}
|
|
421
|
-
return decodeLeafPreimage(resp.preimage) as WorldStateResponse[T];
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
case WorldStateMessageType.GET_SIBLING_PATH: {
|
|
425
|
-
const b = body as WorldStateRequest[WorldStateMessageType.GET_SIBLING_PATH];
|
|
426
|
-
const resp = await this.api.wsdbGetSiblingPath({
|
|
427
|
-
treeid: b.treeId,
|
|
428
|
-
revision: toWsdbRevision(b.revision),
|
|
429
|
-
leafindex: Number(b.leafIndex),
|
|
430
|
-
});
|
|
431
|
-
return resp.path.map(p => Buffer.from(p)) as WorldStateResponse[T];
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
case WorldStateMessageType.GET_BLOCK_NUMBERS_FOR_LEAF_INDICES: {
|
|
435
|
-
const b = body as WorldStateRequest[WorldStateMessageType.GET_BLOCK_NUMBERS_FOR_LEAF_INDICES];
|
|
436
|
-
const resp = await this.api.wsdbGetBlockNumbersForLeafIndices({
|
|
437
|
-
treeid: b.treeId,
|
|
438
|
-
revision: toWsdbRevision(b.revision),
|
|
439
|
-
leafindices: b.leafIndices.map(Number),
|
|
440
|
-
});
|
|
441
|
-
return {
|
|
442
|
-
blockNumbers: resp.blocknumbers.map(n => (n != null ? BigInt(n) : undefined)),
|
|
443
|
-
} as WorldStateResponse[T];
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// ——— Find operations ———
|
|
416
|
+
getStateReference(revision: WorldStateRevision): Promise<Record<number, TreeStateReference>> {
|
|
417
|
+
return this.execute('getStateReference', revision.forkId, revision.includeUncommitted === false, async () => {
|
|
418
|
+
const resp = await this.api.getStateReference({ revision: toWsdbRevision(revision) });
|
|
419
|
+
return convertStateRef(resp.state);
|
|
420
|
+
});
|
|
421
|
+
}
|
|
447
422
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
startindex: Number(b.startIndex),
|
|
455
|
-
});
|
|
456
|
-
return {
|
|
457
|
-
indices: resp.indices.map(n => (n != null ? BigInt(n) : undefined)),
|
|
458
|
-
} as WorldStateResponse[T];
|
|
459
|
-
}
|
|
423
|
+
getInitialStateReference(): Promise<Record<number, TreeStateReference>> {
|
|
424
|
+
return this.execute('getInitialStateReference', 0, false, async () => {
|
|
425
|
+
const resp = await this.api.getInitialStateReference({});
|
|
426
|
+
return convertStateRef(resp.state);
|
|
427
|
+
});
|
|
428
|
+
}
|
|
460
429
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
430
|
+
getLeafValue(
|
|
431
|
+
treeId: MerkleTreeId,
|
|
432
|
+
revision: WorldStateRevision,
|
|
433
|
+
leafIndex: bigint,
|
|
434
|
+
): Promise<SerializedLeafValue | undefined> {
|
|
435
|
+
return this.execute('getLeafValue', revision.forkId, revision.includeUncommitted === false, async () => {
|
|
436
|
+
const wsdbRevision = toWsdbRevision(revision);
|
|
437
|
+
const wsdbLeafIndex = Number(leafIndex);
|
|
438
|
+
|
|
439
|
+
if (treeId === MerkleTreeId.PUBLIC_DATA_TREE) {
|
|
440
|
+
const resp = await this.api.getPublicDataLeafValue({ revision: wsdbRevision, leafIndex: wsdbLeafIndex });
|
|
441
|
+
return resp.value ? fromPublicDataLeaf(resp.value) : undefined;
|
|
472
442
|
}
|
|
473
443
|
|
|
474
|
-
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
treeid: b.treeId,
|
|
478
|
-
revision: toWsdbRevision(b.revision),
|
|
479
|
-
leaves: b.leaves.map(serializeLeafToBytes),
|
|
480
|
-
});
|
|
481
|
-
return {
|
|
482
|
-
paths: resp.paths.map(convertSiblingPathAndIndex),
|
|
483
|
-
} as WorldStateResponse[T];
|
|
444
|
+
if (treeId === MerkleTreeId.NULLIFIER_TREE) {
|
|
445
|
+
const resp = await this.api.getNullifierLeafValue({ revision: wsdbRevision, leafIndex: wsdbLeafIndex });
|
|
446
|
+
return resp.value ? fromNullifierLeaf(resp.value) : undefined;
|
|
484
447
|
}
|
|
485
448
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
await this.api.wsdbAppendLeaves({
|
|
491
|
-
treeid: b.treeId,
|
|
492
|
-
leaves: b.leaves.map(serializeLeafToBytes),
|
|
493
|
-
forkid: b.forkId,
|
|
494
|
-
});
|
|
495
|
-
return undefined as WorldStateResponse[T];
|
|
496
|
-
}
|
|
449
|
+
const resp = await this.api.getLeafValue({ treeId, revision: wsdbRevision, leafIndex: wsdbLeafIndex });
|
|
450
|
+
return resp.value ? Buffer.from(resp.value) : undefined;
|
|
451
|
+
});
|
|
452
|
+
}
|
|
497
453
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
454
|
+
getLeafPreimage(
|
|
455
|
+
treeId: IndexedTreeId,
|
|
456
|
+
revision: WorldStateRevision,
|
|
457
|
+
leafIndex: bigint,
|
|
458
|
+
): Promise<SerializedIndexedLeaf | undefined> {
|
|
459
|
+
return this.execute('getLeafPreimage', revision.forkId, revision.includeUncommitted === false, async () => {
|
|
460
|
+
const resp =
|
|
461
|
+
treeId === MerkleTreeId.PUBLIC_DATA_TREE
|
|
462
|
+
? await this.api.getPublicDataLeafPreimage({
|
|
463
|
+
revision: toWsdbRevision(revision),
|
|
464
|
+
leafIndex: Number(leafIndex),
|
|
465
|
+
})
|
|
466
|
+
: await this.api.getNullifierLeafPreimage({
|
|
467
|
+
revision: toWsdbRevision(revision),
|
|
468
|
+
leafIndex: Number(leafIndex),
|
|
469
|
+
});
|
|
470
|
+
return resp.preimage ? (convertUint8ArraysToBuffers(resp.preimage) as SerializedIndexedLeaf) : undefined;
|
|
471
|
+
});
|
|
472
|
+
}
|
|
509
473
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
474
|
+
getSiblingPath(treeId: MerkleTreeId, revision: WorldStateRevision, leafIndex: bigint): Promise<Buffer[]> {
|
|
475
|
+
return this.execute('getSiblingPath', revision.forkId, revision.includeUncommitted === false, async () => {
|
|
476
|
+
const resp = await this.api.getSiblingPath({
|
|
477
|
+
treeId,
|
|
478
|
+
revision: toWsdbRevision(revision),
|
|
479
|
+
leafIndex: Number(leafIndex),
|
|
480
|
+
});
|
|
481
|
+
return resp.path.map(p => Buffer.from(p));
|
|
482
|
+
});
|
|
483
|
+
}
|
|
520
484
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
485
|
+
getBlockNumbersForLeafIndices(
|
|
486
|
+
treeId: MerkleTreeId,
|
|
487
|
+
revision: WorldStateRevision,
|
|
488
|
+
leafIndices: bigint[],
|
|
489
|
+
): Promise<(bigint | undefined)[]> {
|
|
490
|
+
return this.execute(
|
|
491
|
+
'getBlockNumbersForLeafIndices',
|
|
492
|
+
revision.forkId,
|
|
493
|
+
revision.includeUncommitted === false,
|
|
494
|
+
async () => {
|
|
495
|
+
const resp = await this.api.getBlockNumbersForLeafIndices({
|
|
496
|
+
treeId,
|
|
497
|
+
revision: toWsdbRevision(revision),
|
|
498
|
+
leafIndices: leafIndices.map(Number),
|
|
527
499
|
});
|
|
528
|
-
return
|
|
529
|
-
}
|
|
500
|
+
return resp.blockNumbers.map(n => (n != null ? BigInt(n) : undefined));
|
|
501
|
+
},
|
|
502
|
+
);
|
|
503
|
+
}
|
|
530
504
|
|
|
531
|
-
|
|
505
|
+
findLeafIndices(
|
|
506
|
+
treeId: MerkleTreeId,
|
|
507
|
+
revision: WorldStateRevision,
|
|
508
|
+
leaves: SerializedLeafValue[],
|
|
509
|
+
startIndex: bigint,
|
|
510
|
+
): Promise<(bigint | undefined)[]> {
|
|
511
|
+
return this.execute('findLeafIndices', revision.forkId, revision.includeUncommitted === false, async () => {
|
|
512
|
+
const wsdbRevision = toWsdbRevision(revision);
|
|
513
|
+
const wsdbStartIndex = Number(startIndex);
|
|
514
|
+
const resp =
|
|
515
|
+
treeId === MerkleTreeId.PUBLIC_DATA_TREE
|
|
516
|
+
? await this.api.findPublicDataLeafIndices({
|
|
517
|
+
revision: wsdbRevision,
|
|
518
|
+
leaves: leaves.map(toPublicDataLeaf),
|
|
519
|
+
startIndex: wsdbStartIndex,
|
|
520
|
+
})
|
|
521
|
+
: treeId === MerkleTreeId.NULLIFIER_TREE
|
|
522
|
+
? await this.api.findNullifierLeafIndices({
|
|
523
|
+
revision: wsdbRevision,
|
|
524
|
+
leaves: leaves.map(toNullifierLeaf),
|
|
525
|
+
startIndex: wsdbStartIndex,
|
|
526
|
+
})
|
|
527
|
+
: await this.api.findLeafIndices({
|
|
528
|
+
treeId,
|
|
529
|
+
revision: wsdbRevision,
|
|
530
|
+
leaves: leaves.map(toFrLeaf),
|
|
531
|
+
startIndex: wsdbStartIndex,
|
|
532
|
+
});
|
|
533
|
+
return resp.indices.map(n => (n != null ? BigInt(n) : undefined));
|
|
534
|
+
});
|
|
535
|
+
}
|
|
532
536
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
+
findLowLeaf(
|
|
538
|
+
treeId: IndexedTreeId,
|
|
539
|
+
revision: WorldStateRevision,
|
|
540
|
+
key: Fr,
|
|
541
|
+
): Promise<{ index: bigint; alreadyPresent: boolean }> {
|
|
542
|
+
return this.execute('findLowLeaf', revision.forkId, revision.includeUncommitted === false, async () => {
|
|
543
|
+
const resp = await this.api.findLowLeaf({
|
|
544
|
+
treeId,
|
|
545
|
+
revision: toWsdbRevision(revision),
|
|
546
|
+
key: new Uint8Array(key.toBuffer()),
|
|
547
|
+
});
|
|
548
|
+
return {
|
|
549
|
+
alreadyPresent: resp.alreadyPresent,
|
|
550
|
+
index: BigInt(resp.index),
|
|
551
|
+
};
|
|
552
|
+
});
|
|
553
|
+
}
|
|
537
554
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
555
|
+
findSiblingPaths(
|
|
556
|
+
treeId: MerkleTreeId,
|
|
557
|
+
revision: WorldStateRevision,
|
|
558
|
+
leaves: SerializedLeafValue[],
|
|
559
|
+
): Promise<(SerializedSiblingPathAndIndex | undefined)[]> {
|
|
560
|
+
return this.execute('findSiblingPaths', revision.forkId, revision.includeUncommitted === false, async () => {
|
|
561
|
+
const wsdbRevision = toWsdbRevision(revision);
|
|
562
|
+
const resp =
|
|
563
|
+
treeId === MerkleTreeId.PUBLIC_DATA_TREE
|
|
564
|
+
? await this.api.findPublicDataSiblingPaths({
|
|
565
|
+
revision: wsdbRevision,
|
|
566
|
+
leaves: leaves.map(toPublicDataLeaf),
|
|
567
|
+
})
|
|
568
|
+
: treeId === MerkleTreeId.NULLIFIER_TREE
|
|
569
|
+
? await this.api.findNullifierSiblingPaths({
|
|
570
|
+
revision: wsdbRevision,
|
|
571
|
+
leaves: leaves.map(toNullifierLeaf),
|
|
572
|
+
})
|
|
573
|
+
: await this.api.findSiblingPaths({
|
|
574
|
+
treeId,
|
|
575
|
+
revision: wsdbRevision,
|
|
576
|
+
leaves: leaves.map(toFrLeaf),
|
|
577
|
+
});
|
|
578
|
+
return resp.paths.map(convertSiblingPathAndIndex);
|
|
579
|
+
});
|
|
580
|
+
}
|
|
542
581
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
expectedarchiveroot: new Uint8Array(b.expectedArchiveRoot),
|
|
553
|
-
expectedpreviousarchiveroot: new Uint8Array(b.expectedPreviousArchiveRoot),
|
|
554
|
-
paddednotehashes: b.paddedNoteHashes.map(l => new Uint8Array(l as Buffer)),
|
|
555
|
-
paddedl1tol2messages: b.paddedL1ToL2Messages.map(l => new Uint8Array(l as Buffer)),
|
|
556
|
-
paddednullifiers: b.paddedNullifiers.map(l => ({
|
|
557
|
-
nullifier: new Uint8Array((l as { nullifier: Buffer }).nullifier),
|
|
558
|
-
})),
|
|
559
|
-
publicdatawrites: b.publicDataWrites.map(l => ({
|
|
560
|
-
slot: new Uint8Array((l as { slot: Buffer; value: Buffer }).slot),
|
|
561
|
-
value: new Uint8Array((l as { slot: Buffer; value: Buffer }).value),
|
|
562
|
-
})),
|
|
563
|
-
});
|
|
582
|
+
updateArchive(forkId: number, blockStateRef: BlockStateReference, blockHeaderHash: Buffer): Promise<void> {
|
|
583
|
+
return this.execute('updateArchive', forkId, false, async () => {
|
|
584
|
+
await this.api.updateArchive({
|
|
585
|
+
blockStateRef: blockStateRefToMap(blockStateRef),
|
|
586
|
+
blockHeaderHash: new Uint8Array(blockHeaderHash),
|
|
587
|
+
forkId,
|
|
588
|
+
});
|
|
589
|
+
});
|
|
590
|
+
}
|
|
564
591
|
|
|
565
|
-
|
|
592
|
+
appendLeaves(treeId: MerkleTreeId, forkId: number, leaves: SerializedLeafValue[]): Promise<void> {
|
|
593
|
+
return this.execute('appendLeaves', forkId, false, async () => {
|
|
594
|
+
if (treeId === MerkleTreeId.PUBLIC_DATA_TREE) {
|
|
595
|
+
await this.api.appendPublicDataLeaves({ leaves: leaves.map(toPublicDataLeaf), forkId });
|
|
596
|
+
} else if (treeId === MerkleTreeId.NULLIFIER_TREE) {
|
|
597
|
+
await this.api.appendNullifierLeaves({ leaves: leaves.map(toNullifierLeaf), forkId });
|
|
598
|
+
} else {
|
|
599
|
+
await this.api.appendLeaves({ treeId, leaves: leaves.map(toFrLeaf), forkId });
|
|
566
600
|
}
|
|
601
|
+
});
|
|
602
|
+
}
|
|
567
603
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
604
|
+
batchInsert(
|
|
605
|
+
treeId: IndexedTreeId,
|
|
606
|
+
forkId: number,
|
|
607
|
+
leaves: SerializedLeafValue[],
|
|
608
|
+
subtreeDepth: number,
|
|
609
|
+
): Promise<SerializedBatchInsertionResult> {
|
|
610
|
+
return this.execute('batchInsert', forkId, false, async () => {
|
|
611
|
+
const resp =
|
|
612
|
+
treeId === MerkleTreeId.PUBLIC_DATA_TREE
|
|
613
|
+
? await this.api.batchInsertPublicData({
|
|
614
|
+
leaves: leaves.map(toPublicDataLeaf),
|
|
615
|
+
subtreeDepth,
|
|
616
|
+
forkId,
|
|
617
|
+
})
|
|
618
|
+
: await this.api.batchInsertNullifier({
|
|
619
|
+
leaves: leaves.map(toNullifierLeaf),
|
|
620
|
+
subtreeDepth,
|
|
621
|
+
forkId,
|
|
622
|
+
});
|
|
623
|
+
return treeId === MerkleTreeId.PUBLIC_DATA_TREE
|
|
624
|
+
? fromBatchInsertionResult(resp.result as any, fromPublicDataLeaf)
|
|
625
|
+
: fromBatchInsertionResult(resp.result as any, fromNullifierLeaf);
|
|
626
|
+
});
|
|
627
|
+
}
|
|
578
628
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
629
|
+
sequentialInsert(
|
|
630
|
+
treeId: IndexedTreeId,
|
|
631
|
+
forkId: number,
|
|
632
|
+
leaves: SerializedLeafValue[],
|
|
633
|
+
): Promise<SerializedSequentialInsertionResult> {
|
|
634
|
+
return this.execute('sequentialInsert', forkId, false, async () => {
|
|
635
|
+
const resp =
|
|
636
|
+
treeId === MerkleTreeId.PUBLIC_DATA_TREE
|
|
637
|
+
? await this.api.sequentialInsertPublicData({
|
|
638
|
+
leaves: leaves.map(toPublicDataLeaf),
|
|
639
|
+
forkId,
|
|
640
|
+
})
|
|
641
|
+
: await this.api.sequentialInsertNullifier({
|
|
642
|
+
leaves: leaves.map(toNullifierLeaf),
|
|
643
|
+
forkId,
|
|
644
|
+
});
|
|
645
|
+
return treeId === MerkleTreeId.PUBLIC_DATA_TREE
|
|
646
|
+
? fromSequentialInsertionResult(resp.result as any, fromPublicDataLeaf)
|
|
647
|
+
: fromSequentialInsertionResult(resp.result as any, fromNullifierLeaf);
|
|
648
|
+
});
|
|
649
|
+
}
|
|
584
650
|
|
|
585
|
-
|
|
651
|
+
syncBlock(input: {
|
|
652
|
+
blockNumber: BlockNumber;
|
|
653
|
+
blockStateRef: BlockStateReference;
|
|
654
|
+
blockHeaderHash: Buffer;
|
|
655
|
+
expectedArchiveRoot: Buffer;
|
|
656
|
+
expectedPreviousArchiveRoot: Buffer;
|
|
657
|
+
paddedNoteHashes: readonly SerializedLeafValue[];
|
|
658
|
+
paddedL1ToL2Messages: readonly SerializedLeafValue[];
|
|
659
|
+
paddedNullifiers: readonly SerializedLeafValue[];
|
|
660
|
+
publicDataWrites: readonly SerializedLeafValue[];
|
|
661
|
+
}): Promise<WorldStateStatusFull> {
|
|
662
|
+
return this.execute('syncBlock', 0, false, async () => {
|
|
663
|
+
const resp = await this.api.syncBlock({
|
|
664
|
+
blockNumber: Number(input.blockNumber),
|
|
665
|
+
blockStateRef: blockStateRefToMap(input.blockStateRef),
|
|
666
|
+
blockHeaderHash: new Uint8Array(input.blockHeaderHash),
|
|
667
|
+
expectedArchiveRoot: new Uint8Array(input.expectedArchiveRoot),
|
|
668
|
+
expectedPreviousArchiveRoot: new Uint8Array(input.expectedPreviousArchiveRoot),
|
|
669
|
+
paddedNoteHashes: input.paddedNoteHashes.map(toFrLeaf),
|
|
670
|
+
paddedL1ToL2Messages: input.paddedL1ToL2Messages.map(toFrLeaf),
|
|
671
|
+
paddedNullifiers: input.paddedNullifiers.map(toNullifierLeaf),
|
|
672
|
+
publicDataWrites: input.publicDataWrites.map(toPublicDataLeaf),
|
|
673
|
+
});
|
|
674
|
+
return convertStatusFull(resp.status);
|
|
675
|
+
});
|
|
676
|
+
}
|
|
586
677
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
678
|
+
createFork(input: { latest: boolean; blockNumber: BlockNumber }): Promise<number> {
|
|
679
|
+
return this.execute('createFork', 0, false, async () => {
|
|
680
|
+
const resp = await this.api.createFork({
|
|
681
|
+
latest: input.latest,
|
|
682
|
+
blockNumber: Number(input.blockNumber),
|
|
683
|
+
});
|
|
684
|
+
return resp.forkId;
|
|
685
|
+
});
|
|
686
|
+
}
|
|
592
687
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
688
|
+
deleteFork(forkId: number): Promise<void> {
|
|
689
|
+
return this.execute('deleteFork', forkId, false, async () => {
|
|
690
|
+
await this.api.deleteFork({ forkId });
|
|
691
|
+
});
|
|
692
|
+
}
|
|
598
693
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
694
|
+
finalizeBlocks(toBlockNumber: BlockNumber): Promise<WorldStateStatusSummary> {
|
|
695
|
+
return this.execute('finalizeBlocks', 0, false, async () => {
|
|
696
|
+
const resp = await this.api.finalizeBlocks({ toBlockNumber: Number(toBlockNumber) });
|
|
697
|
+
return convertStatusSummary(resp.status);
|
|
698
|
+
});
|
|
699
|
+
}
|
|
604
700
|
|
|
605
|
-
|
|
701
|
+
unwindBlocks(toBlockNumber: BlockNumber): Promise<WorldStateStatusFull> {
|
|
702
|
+
return this.execute('unwindBlocks', 0, false, async () => {
|
|
703
|
+
const resp = await this.api.unwindBlocks({ toBlockNumber: Number(toBlockNumber) });
|
|
704
|
+
return convertStatusFull(resp.status);
|
|
705
|
+
});
|
|
706
|
+
}
|
|
606
707
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
708
|
+
removeHistoricalBlocks(toBlockNumber: BlockNumber): Promise<WorldStateStatusFull> {
|
|
709
|
+
return this.execute('removeHistoricalBlocks', 0, false, async () => {
|
|
710
|
+
const resp = await this.api.removeHistoricalBlocks({ toBlockNumber: Number(toBlockNumber) });
|
|
711
|
+
return convertStatusFull(resp.status);
|
|
712
|
+
});
|
|
713
|
+
}
|
|
611
714
|
|
|
612
|
-
|
|
715
|
+
getStatus(): Promise<WorldStateStatusSummary> {
|
|
716
|
+
return this.execute('getStatus', 0, false, async () => {
|
|
717
|
+
const resp = await this.api.getStatus({});
|
|
718
|
+
return convertStatusSummary(resp.status);
|
|
719
|
+
});
|
|
720
|
+
}
|
|
613
721
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
722
|
+
createCheckpoint(forkId: number): Promise<number> {
|
|
723
|
+
return this.execute('createCheckpoint', forkId, false, async () => {
|
|
724
|
+
await this.api.createCheckpoint({ forkId });
|
|
725
|
+
const depth = (this.checkpointDepths.get(forkId) ?? 0) + 1;
|
|
726
|
+
this.checkpointDepths.set(forkId, depth);
|
|
727
|
+
return depth;
|
|
728
|
+
});
|
|
729
|
+
}
|
|
621
730
|
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
731
|
+
commitCheckpoint(forkId: number): Promise<void> {
|
|
732
|
+
return this.execute('commitCheckpoint', forkId, false, async () => {
|
|
733
|
+
await this.api.commitCheckpoint({ forkId });
|
|
734
|
+
const depth = Math.max(0, (this.checkpointDepths.get(forkId) ?? 0) - 1);
|
|
735
|
+
this.checkpointDepths.set(forkId, depth);
|
|
736
|
+
});
|
|
737
|
+
}
|
|
629
738
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
739
|
+
revertCheckpoint(forkId: number): Promise<void> {
|
|
740
|
+
return this.execute('revertCheckpoint', forkId, false, async () => {
|
|
741
|
+
await this.api.revertCheckpoint({ forkId });
|
|
742
|
+
const depth = Math.max(0, (this.checkpointDepths.get(forkId) ?? 0) - 1);
|
|
743
|
+
this.checkpointDepths.set(forkId, depth);
|
|
744
|
+
});
|
|
745
|
+
}
|
|
637
746
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
// Commit one level at a time down to target depth
|
|
647
|
-
for (let d = currentDepth; d > targetDepth; d--) {
|
|
648
|
-
await this.api.wsdbCommitCheckpoint({ forkid: b.forkId });
|
|
649
|
-
}
|
|
747
|
+
commitAllCheckpoints(forkId: number, depth: number): Promise<void> {
|
|
748
|
+
return this.execute('commitAllCheckpoints', forkId, false, async () => {
|
|
749
|
+
const currentDepth = this.checkpointDepths.get(forkId) ?? 0;
|
|
750
|
+
if (depth === 0) {
|
|
751
|
+
await this.api.commitAllCheckpoints({ forkId });
|
|
752
|
+
} else {
|
|
753
|
+
for (let d = currentDepth; d > depth; d--) {
|
|
754
|
+
await this.api.commitCheckpoint({ forkId });
|
|
650
755
|
}
|
|
651
|
-
this.checkpointDepths.set(b.forkId, targetDepth);
|
|
652
|
-
return undefined as WorldStateResponse[T];
|
|
653
756
|
}
|
|
757
|
+
this.checkpointDepths.set(forkId, depth);
|
|
758
|
+
});
|
|
759
|
+
}
|
|
654
760
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
// Revert one level at a time down to target depth
|
|
664
|
-
for (let d = currentDepth; d > targetDepth; d--) {
|
|
665
|
-
await this.api.wsdbRevertCheckpoint({ forkid: b.forkId });
|
|
666
|
-
}
|
|
761
|
+
revertAllCheckpoints(forkId: number, depth: number): Promise<void> {
|
|
762
|
+
return this.execute('revertAllCheckpoints', forkId, false, async () => {
|
|
763
|
+
const currentDepth = this.checkpointDepths.get(forkId) ?? 0;
|
|
764
|
+
if (depth === 0) {
|
|
765
|
+
await this.api.revertAllCheckpoints({ forkId });
|
|
766
|
+
} else {
|
|
767
|
+
for (let d = currentDepth; d > depth; d--) {
|
|
768
|
+
await this.api.revertCheckpoint({ forkId });
|
|
667
769
|
}
|
|
668
|
-
this.checkpointDepths.set(b.forkId, targetDepth);
|
|
669
|
-
return undefined as WorldStateResponse[T];
|
|
670
770
|
}
|
|
771
|
+
this.checkpointDepths.set(forkId, depth);
|
|
772
|
+
});
|
|
773
|
+
}
|
|
671
774
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
return undefined as WorldStateResponse[T];
|
|
678
|
-
}
|
|
775
|
+
copyStores(dstPath: string, compact: boolean): Promise<void> {
|
|
776
|
+
return this.execute('copyStores', 0, false, async () => {
|
|
777
|
+
await this.api.copyStores({ dstPath, compact });
|
|
778
|
+
});
|
|
779
|
+
}
|
|
679
780
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
781
|
+
// Read/write ordering is enforced server-side by the wsdb per-fork scheduler,
|
|
782
|
+
// so the client no longer queues: every op is sent immediately and the server
|
|
783
|
+
// serializes writes per fork while running reads concurrently. `_forkId` and
|
|
784
|
+
// `_committedOnly` are retained in the signature (they describe the op) but are
|
|
785
|
+
// no longer needed for client-side ordering.
|
|
786
|
+
private async execute<T>(
|
|
787
|
+
operation: WorldStateOperationName,
|
|
788
|
+
_forkId: number,
|
|
789
|
+
_committedOnly: boolean,
|
|
790
|
+
request: () => Promise<T>,
|
|
791
|
+
): Promise<T> {
|
|
792
|
+
if (!this.open) {
|
|
793
|
+
throw new Error('IPC instance is closed');
|
|
794
|
+
}
|
|
795
|
+
return await this.send(operation, request);
|
|
796
|
+
}
|
|
684
797
|
|
|
685
|
-
|
|
686
|
-
|
|
798
|
+
private async send<T>(operation: WorldStateOperationName, request: () => Promise<T>): Promise<T> {
|
|
799
|
+
const start = performance.now();
|
|
800
|
+
try {
|
|
801
|
+
const response = await request();
|
|
802
|
+
const durationMs = performance.now() - start;
|
|
803
|
+
this.log.trace(`Call ${operation} took (ms)`, { duration: durationMs });
|
|
804
|
+
this.instrumentation.recordRoundTrip(durationMs * 1000, operation);
|
|
805
|
+
return response;
|
|
806
|
+
} catch (error) {
|
|
807
|
+
this.log.error(`Call ${operation} failed: ${error}`, error);
|
|
808
|
+
throw error;
|
|
687
809
|
}
|
|
688
810
|
}
|
|
689
811
|
}
|
|
690
812
|
|
|
691
813
|
/**
|
|
692
814
|
* Helper to create WsdbOptions from standard world state config.
|
|
693
|
-
* Returns the options needed to construct a
|
|
815
|
+
* Returns the options needed to construct a wsdb service command line.
|
|
694
816
|
*/
|
|
695
817
|
export function getWsdbOptions(
|
|
696
818
|
dataDir: string,
|