@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
|
@@ -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,104 +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
|
-
try {
|
|
286
|
-
const response = await requestQueue.execute(
|
|
287
|
-
async () => {
|
|
288
|
-
assert.notEqual(messageType, WorldStateMessageType.CLOSE, 'Use close() to close the IPC instance');
|
|
289
|
-
assert.equal(this.open, true, 'IPC instance is closed');
|
|
290
|
-
let response: WorldStateResponse[T];
|
|
291
|
-
try {
|
|
292
|
-
response = await this._sendMessage(messageType, body);
|
|
293
|
-
} catch (error: any) {
|
|
294
|
-
errorHandler(error.message);
|
|
295
|
-
throw error;
|
|
296
|
-
}
|
|
297
|
-
return responseHandler(response);
|
|
298
|
-
},
|
|
299
|
-
messageType,
|
|
300
|
-
committedOnly,
|
|
301
|
-
);
|
|
302
|
-
return response;
|
|
303
|
-
} finally {
|
|
304
|
-
if (messageType === WorldStateMessageType.DELETE_FORK) {
|
|
305
|
-
await requestQueue.stop();
|
|
306
|
-
this.queues.delete(forkId);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
392
|
+
getIpcPath(): string {
|
|
393
|
+
return this.wsdb.getIpcPath();
|
|
309
394
|
}
|
|
310
395
|
|
|
311
396
|
async close(): Promise<void> {
|
|
@@ -313,376 +398,421 @@ export class IpcWorldState implements NativeWorldStateInstance {
|
|
|
313
398
|
return;
|
|
314
399
|
}
|
|
315
400
|
this.open = false;
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
// Send shutdown command. Under normal operation, the WSDB process sends its
|
|
319
|
-
// response before exiting (via ShutdownRequested in ipc_server.hpp). The
|
|
320
|
-
// try/catch is defensive: if the process is killed externally (SIGKILL, OOM)
|
|
321
|
-
// before responding, the pending IPC callback would be rejected by the socket
|
|
322
|
-
// close handler. We proceed to destroy the backend regardless.
|
|
323
|
-
try {
|
|
324
|
-
await queue.execute(
|
|
325
|
-
async () => {
|
|
326
|
-
await this.api.wsdbShutdown({});
|
|
327
|
-
},
|
|
328
|
-
WorldStateMessageType.CLOSE,
|
|
329
|
-
false,
|
|
330
|
-
);
|
|
331
|
-
} catch (err: any) {
|
|
332
|
-
this.log.debug(`wsdbShutdown completed with error: ${err.message}`);
|
|
333
|
-
}
|
|
334
|
-
await queue.stop();
|
|
335
|
-
|
|
336
|
-
if (this.wsdbBackend.destroy) {
|
|
337
|
-
await this.wsdbBackend.destroy();
|
|
338
|
-
}
|
|
401
|
+
await this.wsdb.destroy();
|
|
339
402
|
}
|
|
340
403
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
return response;
|
|
352
|
-
} catch (error) {
|
|
353
|
-
this.log.error(`Call ${WorldStateMessageType[messageType]} failed: ${error}`, error);
|
|
354
|
-
throw error;
|
|
355
|
-
}
|
|
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
|
+
});
|
|
356
414
|
}
|
|
357
415
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
case WorldStateMessageType.GET_TREE_INFO: {
|
|
366
|
-
const b = body as WorldStateRequest[WorldStateMessageType.GET_TREE_INFO];
|
|
367
|
-
const resp = await this.api.wsdbGetTreeInfo({
|
|
368
|
-
treeid: b.treeId,
|
|
369
|
-
revision: toWsdbRevision(b.revision),
|
|
370
|
-
});
|
|
371
|
-
return {
|
|
372
|
-
treeId: resp.treeid,
|
|
373
|
-
root: Buffer.from(resp.root),
|
|
374
|
-
size: resp.size,
|
|
375
|
-
depth: resp.depth,
|
|
376
|
-
} as WorldStateResponse[T];
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
case WorldStateMessageType.GET_STATE_REFERENCE: {
|
|
380
|
-
const b = body as WorldStateRequest[WorldStateMessageType.GET_STATE_REFERENCE];
|
|
381
|
-
const resp = await this.api.wsdbGetStateReference({
|
|
382
|
-
revision: toWsdbRevision(b.revision),
|
|
383
|
-
});
|
|
384
|
-
return { state: convertStateRef(resp.state) } as WorldStateResponse[T];
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
case WorldStateMessageType.GET_INITIAL_STATE_REFERENCE: {
|
|
388
|
-
const resp = await this.api.wsdbGetInitialStateReference({});
|
|
389
|
-
return { state: convertStateRef(resp.state) } as WorldStateResponse[T];
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// ——— Leaf queries ———
|
|
393
|
-
|
|
394
|
-
case WorldStateMessageType.GET_LEAF_VALUE: {
|
|
395
|
-
const b = body as WorldStateRequest[WorldStateMessageType.GET_LEAF_VALUE];
|
|
396
|
-
const resp = await this.api.wsdbGetLeafValue({
|
|
397
|
-
treeid: b.treeId,
|
|
398
|
-
revision: toWsdbRevision(b.revision),
|
|
399
|
-
leafindex: Number(b.leafIndex),
|
|
400
|
-
});
|
|
401
|
-
if (!resp.value) {
|
|
402
|
-
return undefined as WorldStateResponse[T];
|
|
403
|
-
}
|
|
404
|
-
return decodeLeafValue(resp.value) as WorldStateResponse[T];
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
case WorldStateMessageType.GET_LEAF_PREIMAGE: {
|
|
408
|
-
const b = body as WorldStateRequest[WorldStateMessageType.GET_LEAF_PREIMAGE];
|
|
409
|
-
const resp = await this.api.wsdbGetLeafPreimage({
|
|
410
|
-
treeid: b.treeId,
|
|
411
|
-
revision: toWsdbRevision(b.revision),
|
|
412
|
-
leafindex: Number(b.leafIndex),
|
|
413
|
-
});
|
|
414
|
-
if (!resp.preimage) {
|
|
415
|
-
return undefined as WorldStateResponse[T];
|
|
416
|
-
}
|
|
417
|
-
return decodeLeafPreimage(resp.preimage) as WorldStateResponse[T];
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
case WorldStateMessageType.GET_SIBLING_PATH: {
|
|
421
|
-
const b = body as WorldStateRequest[WorldStateMessageType.GET_SIBLING_PATH];
|
|
422
|
-
const resp = await this.api.wsdbGetSiblingPath({
|
|
423
|
-
treeid: b.treeId,
|
|
424
|
-
revision: toWsdbRevision(b.revision),
|
|
425
|
-
leafindex: Number(b.leafIndex),
|
|
426
|
-
});
|
|
427
|
-
return resp.path.map(p => Buffer.from(p)) as WorldStateResponse[T];
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
case WorldStateMessageType.GET_BLOCK_NUMBERS_FOR_LEAF_INDICES: {
|
|
431
|
-
const b = body as WorldStateRequest[WorldStateMessageType.GET_BLOCK_NUMBERS_FOR_LEAF_INDICES];
|
|
432
|
-
const resp = await this.api.wsdbGetBlockNumbersForLeafIndices({
|
|
433
|
-
treeid: b.treeId,
|
|
434
|
-
revision: toWsdbRevision(b.revision),
|
|
435
|
-
leafindices: b.leafIndices.map(Number),
|
|
436
|
-
});
|
|
437
|
-
return {
|
|
438
|
-
blockNumbers: resp.blocknumbers.map(n => (n != null ? BigInt(n) : undefined)),
|
|
439
|
-
} as WorldStateResponse[T];
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
// ——— 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
|
+
}
|
|
443
422
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
startindex: Number(b.startIndex),
|
|
451
|
-
});
|
|
452
|
-
return {
|
|
453
|
-
indices: resp.indices.map(n => (n != null ? BigInt(n) : undefined)),
|
|
454
|
-
} as WorldStateResponse[T];
|
|
455
|
-
}
|
|
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
|
+
}
|
|
456
429
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
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;
|
|
468
442
|
}
|
|
469
443
|
|
|
470
|
-
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
treeid: b.treeId,
|
|
474
|
-
revision: toWsdbRevision(b.revision),
|
|
475
|
-
leaves: b.leaves.map(serializeLeafToBytes),
|
|
476
|
-
});
|
|
477
|
-
return {
|
|
478
|
-
paths: resp.paths.map(convertSiblingPathAndIndex),
|
|
479
|
-
} 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;
|
|
480
447
|
}
|
|
481
448
|
|
|
482
|
-
|
|
449
|
+
const resp = await this.api.getLeafValue({ treeId, revision: wsdbRevision, leafIndex: wsdbLeafIndex });
|
|
450
|
+
return resp.value ? Buffer.from(resp.value) : undefined;
|
|
451
|
+
});
|
|
452
|
+
}
|
|
483
453
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
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
|
+
}
|
|
493
473
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
}
|
|
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
|
+
}
|
|
505
484
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
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),
|
|
512
499
|
});
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
500
|
+
return resp.blockNumbers.map(n => (n != null ? BigInt(n) : undefined));
|
|
501
|
+
},
|
|
502
|
+
);
|
|
503
|
+
}
|
|
516
504
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
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
|
+
}
|
|
526
536
|
|
|
527
|
-
|
|
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
|
+
}
|
|
528
554
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
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
|
+
}
|
|
533
581
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
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
|
+
}
|
|
538
591
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
paddednotehashes: b.paddedNoteHashes.map(l => new Uint8Array(l as Buffer)),
|
|
548
|
-
paddedl1tol2messages: b.paddedL1ToL2Messages.map(l => new Uint8Array(l as Buffer)),
|
|
549
|
-
paddednullifiers: b.paddedNullifiers.map(l => ({
|
|
550
|
-
nullifier: new Uint8Array((l as { nullifier: Buffer }).nullifier),
|
|
551
|
-
})),
|
|
552
|
-
publicdatawrites: b.publicDataWrites.map(l => ({
|
|
553
|
-
slot: new Uint8Array((l as { slot: Buffer; value: Buffer }).slot),
|
|
554
|
-
value: new Uint8Array((l as { slot: Buffer; value: Buffer }).value),
|
|
555
|
-
})),
|
|
556
|
-
});
|
|
557
|
-
return convertStatusFull(resp.status) as WorldStateResponse[T];
|
|
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 });
|
|
558
600
|
}
|
|
601
|
+
});
|
|
602
|
+
}
|
|
559
603
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
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
|
+
}
|
|
570
628
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
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
|
+
}
|
|
576
650
|
|
|
577
|
-
|
|
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
|
+
}
|
|
578
677
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
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
|
+
}
|
|
584
687
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
688
|
+
deleteFork(forkId: number): Promise<void> {
|
|
689
|
+
return this.execute('deleteFork', forkId, false, async () => {
|
|
690
|
+
await this.api.deleteFork({ forkId });
|
|
691
|
+
});
|
|
692
|
+
}
|
|
590
693
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
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
|
+
}
|
|
596
700
|
|
|
597
|
-
|
|
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
|
+
}
|
|
598
707
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
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
|
+
}
|
|
603
714
|
|
|
604
|
-
|
|
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
|
+
}
|
|
605
721
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
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
|
+
}
|
|
613
730
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
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
|
+
}
|
|
621
738
|
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
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
|
+
}
|
|
629
746
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
// Commit one level at a time down to target depth
|
|
639
|
-
for (let d = currentDepth; d > targetDepth; d--) {
|
|
640
|
-
await this.api.wsdbCommitCheckpoint({ forkid: b.forkId });
|
|
641
|
-
}
|
|
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 });
|
|
642
755
|
}
|
|
643
|
-
this.checkpointDepths.set(b.forkId, targetDepth);
|
|
644
|
-
return undefined as WorldStateResponse[T];
|
|
645
756
|
}
|
|
757
|
+
this.checkpointDepths.set(forkId, depth);
|
|
758
|
+
});
|
|
759
|
+
}
|
|
646
760
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
// Revert one level at a time down to target depth
|
|
656
|
-
for (let d = currentDepth; d > targetDepth; d--) {
|
|
657
|
-
await this.api.wsdbRevertCheckpoint({ forkid: b.forkId });
|
|
658
|
-
}
|
|
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 });
|
|
659
769
|
}
|
|
660
|
-
this.checkpointDepths.set(b.forkId, targetDepth);
|
|
661
|
-
return undefined as WorldStateResponse[T];
|
|
662
770
|
}
|
|
771
|
+
this.checkpointDepths.set(forkId, depth);
|
|
772
|
+
});
|
|
773
|
+
}
|
|
663
774
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
return undefined as WorldStateResponse[T];
|
|
670
|
-
}
|
|
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
|
+
}
|
|
671
780
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
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
|
+
}
|
|
676
797
|
|
|
677
|
-
|
|
678
|
-
|
|
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;
|
|
679
809
|
}
|
|
680
810
|
}
|
|
681
811
|
}
|
|
682
812
|
|
|
683
813
|
/**
|
|
684
814
|
* Helper to create WsdbOptions from standard world state config.
|
|
685
|
-
* Returns the options needed to construct a
|
|
815
|
+
* Returns the options needed to construct a wsdb service command line.
|
|
686
816
|
*/
|
|
687
817
|
export function getWsdbOptions(
|
|
688
818
|
dataDir: string,
|