@aztec/world-state 0.0.1-commit.a5db02d → 0.0.1-commit.aa0c64f
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,38 +1,148 @@
|
|
|
1
|
-
import { AsyncApi } from '@aztec/bb.js/aztec-wsdb';
|
|
2
1
|
import { ARCHIVE_HEIGHT, DomainSeparator, L1_TO_L2_MSG_TREE_HEIGHT, MAX_NULLIFIERS_PER_TX, MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, NOTE_HASH_TREE_HEIGHT, NULLIFIER_TREE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT } from '@aztec/constants';
|
|
3
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
3
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import { WorldStateMessageType, isWithCanonical, isWithForkId, isWithRevision } from './message.js';
|
|
8
|
-
import { WorldStateOpsQueue } from './world_state_ops_queue.js';
|
|
9
|
-
// ————— Msgpack helpers —————
|
|
10
|
-
const msgpackEncoder = new Encoder({
|
|
11
|
-
useRecords: false
|
|
12
|
-
});
|
|
13
|
-
const msgpackDecoder = new Decoder({
|
|
14
|
-
useRecords: false
|
|
15
|
-
});
|
|
16
|
-
/** Msgpack-encode a SerializedLeafValue into bytes for IPC transport. */ function serializeLeafToBytes(leaf) {
|
|
17
|
-
return Buffer.from(msgpackEncoder.pack(leaf));
|
|
18
|
-
}
|
|
4
|
+
import { WsdbService } from '@aztec/wsdb';
|
|
5
|
+
import { cpus } from 'node:os';
|
|
19
6
|
// ————— Request conversion helpers —————
|
|
20
7
|
function toWsdbRevision(rev) {
|
|
21
8
|
return {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
9
|
+
forkId: rev.forkId,
|
|
10
|
+
blockNumber: Number(rev.blockNumber),
|
|
11
|
+
includeUncommitted: rev.includeUncommitted
|
|
25
12
|
};
|
|
26
13
|
}
|
|
27
14
|
function blockStateRefToMap(ref) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
15
|
+
return [
|
|
16
|
+
...ref.entries()
|
|
17
|
+
].map(([treeId, [root, size]])=>({
|
|
18
|
+
treeId,
|
|
19
|
+
root: new Uint8Array(root),
|
|
20
|
+
size: Number(size)
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
function toPublicDataLeaf(leaf) {
|
|
24
|
+
if (leaf instanceof Buffer || !('slot' in leaf)) {
|
|
25
|
+
throw new Error('Expected public data leaf');
|
|
34
26
|
}
|
|
35
|
-
return
|
|
27
|
+
return {
|
|
28
|
+
slot: new Uint8Array(leaf.slot),
|
|
29
|
+
value: new Uint8Array(leaf.value)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function toNullifierLeaf(leaf) {
|
|
33
|
+
if (leaf instanceof Buffer || !('nullifier' in leaf)) {
|
|
34
|
+
throw new Error('Expected nullifier leaf');
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
nullifier: new Uint8Array(leaf.nullifier)
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function fromPublicDataLeaf(leaf) {
|
|
41
|
+
return {
|
|
42
|
+
slot: Buffer.from(leaf.slot),
|
|
43
|
+
value: Buffer.from(leaf.value)
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function fromNullifierLeaf(leaf) {
|
|
47
|
+
return {
|
|
48
|
+
nullifier: Buffer.from(leaf.nullifier)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function fromIndexedLeaf(leaf, convertLeaf) {
|
|
52
|
+
return {
|
|
53
|
+
leaf: convertLeaf(leaf.leaf),
|
|
54
|
+
nextIndex: leaf.nextIndex,
|
|
55
|
+
nextKey: Buffer.from(leaf.nextKey)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function fromLeafUpdateWitnessData(data, convertLeaf) {
|
|
59
|
+
return {
|
|
60
|
+
leaf: fromIndexedLeaf(data.leaf, convertLeaf),
|
|
61
|
+
index: data.index,
|
|
62
|
+
path: data.path.map((p)=>Buffer.from(p))
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function fromBatchInsertionResult(result, convertLeaf) {
|
|
66
|
+
return {
|
|
67
|
+
lowLeafWitnessData: result.lowLeafWitnessData.map((data)=>fromLeafUpdateWitnessData(data, convertLeaf)),
|
|
68
|
+
sortedLeaves: result.sortedLeaves.map(({ leaf, index })=>[
|
|
69
|
+
convertLeaf(leaf),
|
|
70
|
+
index
|
|
71
|
+
]),
|
|
72
|
+
subtreePath: result.subtreePath.map((p)=>Buffer.from(p))
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function fromSequentialInsertionResult(result, convertLeaf) {
|
|
76
|
+
return {
|
|
77
|
+
lowLeafWitnessData: result.lowLeafWitnessData.map((data)=>fromLeafUpdateWitnessData(data, convertLeaf)),
|
|
78
|
+
insertionWitnessData: result.insertionWitnessData.map((data)=>fromLeafUpdateWitnessData(data, convertLeaf))
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function toFrLeaf(leaf) {
|
|
82
|
+
if (!(leaf instanceof Buffer)) {
|
|
83
|
+
throw new Error('Expected field leaf');
|
|
84
|
+
}
|
|
85
|
+
return new Uint8Array(leaf);
|
|
86
|
+
}
|
|
87
|
+
function formatMap(map) {
|
|
88
|
+
if (!map || Object.keys(map).length === 0) {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
return `{${Object.entries(map).map(([key, value])=>`${key}:${value}`).join(',')}}`;
|
|
92
|
+
}
|
|
93
|
+
/** SHM request/response ring size for the spawned aztec-wsdb process (32 MiB). */ const WSDB_SHM_RING_SIZE = 32 * 1024 * 1024;
|
|
94
|
+
function getWsdbThreadCount() {
|
|
95
|
+
return Math.min(16, cpus().length);
|
|
96
|
+
}
|
|
97
|
+
function getWsdbExtraArgs(dataDir, wsTreeMapSizes, genesis, threads) {
|
|
98
|
+
const options = getWsdbOptions(dataDir, wsTreeMapSizes);
|
|
99
|
+
const args = [
|
|
100
|
+
'--data-dir',
|
|
101
|
+
dataDir,
|
|
102
|
+
'--threads',
|
|
103
|
+
threads.toString()
|
|
104
|
+
];
|
|
105
|
+
// Size the SHM rings generously. Responses such as batch-insertion witnesses
|
|
106
|
+
// run to a few MB, and an SHM frame is capped at half the ring (the wrap
|
|
107
|
+
// handling needs that headroom), so 32 MiB rings give ~16 MiB per message.
|
|
108
|
+
// Ignored by the UDS transport. Pages are demand-faulted, so unused capacity
|
|
109
|
+
// is cheap.
|
|
110
|
+
args.push('--request-ring-size', WSDB_SHM_RING_SIZE.toString());
|
|
111
|
+
args.push('--response-ring-size', WSDB_SHM_RING_SIZE.toString());
|
|
112
|
+
const treeHeights = formatMap(options.treeHeights);
|
|
113
|
+
if (treeHeights) {
|
|
114
|
+
args.push('--tree-heights', treeHeights);
|
|
115
|
+
}
|
|
116
|
+
const treePrefill = formatMap(options.treePrefill);
|
|
117
|
+
if (treePrefill) {
|
|
118
|
+
args.push('--tree-prefill', treePrefill);
|
|
119
|
+
}
|
|
120
|
+
const mapSizes = formatMap(options.mapSizes);
|
|
121
|
+
if (mapSizes) {
|
|
122
|
+
args.push('--map-sizes', mapSizes);
|
|
123
|
+
}
|
|
124
|
+
args.push('--initial-header-generator-point', options.initialHeaderGeneratorPoint.toString());
|
|
125
|
+
if (genesis.prefilledPublicData.length > 0) {
|
|
126
|
+
const pairs = genesis.prefilledPublicData.map((data)=>[
|
|
127
|
+
data.slot.toBuffer().toString('hex'),
|
|
128
|
+
data.value.toBuffer().toString('hex')
|
|
129
|
+
]);
|
|
130
|
+
args.push('--prefilled-public-data', JSON.stringify(pairs));
|
|
131
|
+
}
|
|
132
|
+
const prefilledNullifiers = genesis.prefilledNullifiers ?? [];
|
|
133
|
+
for(let i = 1; i < prefilledNullifiers.length; i++){
|
|
134
|
+
if (prefilledNullifiers[i].toBigInt() <= prefilledNullifiers[i - 1].toBigInt()) {
|
|
135
|
+
throw new Error('Prefilled genesis nullifiers must be unique and strictly increasing');
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (prefilledNullifiers.length > 0) {
|
|
139
|
+
args.push('--prefilled-nullifiers', JSON.stringify(prefilledNullifiers.map((nullifier)=>nullifier.toBuffer().toString('hex'))));
|
|
140
|
+
}
|
|
141
|
+
const genesisTimestamp = Number(genesis.genesisTimestamp);
|
|
142
|
+
if (genesisTimestamp !== 0) {
|
|
143
|
+
args.push('--genesis-timestamp', genesisTimestamp.toString());
|
|
144
|
+
}
|
|
145
|
+
return args;
|
|
36
146
|
}
|
|
37
147
|
// ————— Response conversion helpers —————
|
|
38
148
|
/** Convert Uint8Array fields to Buffer recursively (for opaque blob responses). */ function convertUint8ArraysToBuffers(obj) {
|
|
@@ -51,57 +161,49 @@ function blockStateRefToMap(ref) {
|
|
|
51
161
|
}
|
|
52
162
|
return obj;
|
|
53
163
|
}
|
|
54
|
-
/** Decode a msgpack-encoded leaf value blob and convert Uint8Arrays to Buffers. */ function decodeLeafValue(encoded) {
|
|
55
|
-
const decoded = msgpackDecoder.unpack(Buffer.from(encoded));
|
|
56
|
-
return convertUint8ArraysToBuffers(decoded);
|
|
57
|
-
}
|
|
58
|
-
/** Decode a msgpack-encoded indexed leaf preimage blob. */ function decodeLeafPreimage(encoded) {
|
|
59
|
-
const decoded = msgpackDecoder.unpack(Buffer.from(encoded));
|
|
60
|
-
return convertUint8ArraysToBuffers(decoded);
|
|
61
|
-
}
|
|
62
164
|
/** Convert Wsdb state reference (Record<number, [Uint8Array, number]>) to NAPI format. */ function convertStateRef(state) {
|
|
63
165
|
const result = {};
|
|
64
|
-
for (const
|
|
65
|
-
result[
|
|
166
|
+
for (const { treeId, root, size } of state){
|
|
167
|
+
result[treeId] = [
|
|
66
168
|
Buffer.from(root),
|
|
67
169
|
BigInt(size)
|
|
68
170
|
];
|
|
69
171
|
}
|
|
70
172
|
return result;
|
|
71
173
|
}
|
|
72
|
-
/** Convert Wsdb WorldStateStatusSummary
|
|
174
|
+
/** Convert Wsdb WorldStateStatusSummary to the native world-state format. */ function convertStatusSummary(s) {
|
|
73
175
|
return {
|
|
74
|
-
unfinalizedBlockNumber: s.
|
|
75
|
-
finalizedBlockNumber: s.
|
|
76
|
-
oldestHistoricalBlock: s.
|
|
77
|
-
treesAreSynched: s.
|
|
176
|
+
unfinalizedBlockNumber: s.unfinalizedBlockNumber,
|
|
177
|
+
finalizedBlockNumber: s.finalizedBlockNumber,
|
|
178
|
+
oldestHistoricalBlock: s.oldestHistoricalBlock,
|
|
179
|
+
treesAreSynched: s.treesAreSynched
|
|
78
180
|
};
|
|
79
181
|
}
|
|
80
182
|
function convertDBStats(s) {
|
|
81
183
|
return {
|
|
82
184
|
name: s.name,
|
|
83
|
-
numDataItems: s.
|
|
84
|
-
totalUsedSize: s.
|
|
185
|
+
numDataItems: s.numDataItems,
|
|
186
|
+
totalUsedSize: s.totalUsedSize
|
|
85
187
|
};
|
|
86
188
|
}
|
|
87
189
|
function convertTreeDBStats(s) {
|
|
88
190
|
return {
|
|
89
|
-
mapSize: s.
|
|
90
|
-
physicalFileSize: s.
|
|
91
|
-
blocksDBStats: convertDBStats(s.
|
|
92
|
-
nodesDBStats: convertDBStats(s.
|
|
93
|
-
leafPreimagesDBStats: convertDBStats(s.
|
|
94
|
-
leafIndicesDBStats: convertDBStats(s.
|
|
95
|
-
blockIndicesDBStats: convertDBStats(s.
|
|
191
|
+
mapSize: s.mapSize,
|
|
192
|
+
physicalFileSize: s.physicalFileSize,
|
|
193
|
+
blocksDBStats: convertDBStats(s.blocksDBStats),
|
|
194
|
+
nodesDBStats: convertDBStats(s.nodesDBStats),
|
|
195
|
+
leafPreimagesDBStats: convertDBStats(s.leafPreimagesDBStats),
|
|
196
|
+
leafIndicesDBStats: convertDBStats(s.leafIndicesDBStats),
|
|
197
|
+
blockIndicesDBStats: convertDBStats(s.blockIndicesDBStats)
|
|
96
198
|
};
|
|
97
199
|
}
|
|
98
200
|
function convertWorldStateDBStats(s) {
|
|
99
201
|
return {
|
|
100
|
-
noteHashTreeStats: convertTreeDBStats(s.
|
|
101
|
-
messageTreeStats: convertTreeDBStats(s.
|
|
102
|
-
archiveTreeStats: convertTreeDBStats(s.
|
|
103
|
-
publicDataTreeStats: convertTreeDBStats(s.
|
|
104
|
-
nullifierTreeStats: convertTreeDBStats(s.
|
|
202
|
+
noteHashTreeStats: convertTreeDBStats(s.noteHashTreeStats),
|
|
203
|
+
messageTreeStats: convertTreeDBStats(s.messageTreeStats),
|
|
204
|
+
archiveTreeStats: convertTreeDBStats(s.archiveTreeStats),
|
|
205
|
+
publicDataTreeStats: convertTreeDBStats(s.publicDataTreeStats),
|
|
206
|
+
nullifierTreeStats: convertTreeDBStats(s.nullifierTreeStats)
|
|
105
207
|
};
|
|
106
208
|
}
|
|
107
209
|
function convertTreeMeta(m) {
|
|
@@ -109,28 +211,28 @@ function convertTreeMeta(m) {
|
|
|
109
211
|
name: m.name,
|
|
110
212
|
depth: m.depth,
|
|
111
213
|
size: m.size,
|
|
112
|
-
committedSize: m.
|
|
214
|
+
committedSize: m.committedSize,
|
|
113
215
|
root: m.root,
|
|
114
|
-
initialSize: m.
|
|
115
|
-
initialRoot: m.
|
|
116
|
-
oldestHistoricBlock: m.
|
|
117
|
-
unfinalizedBlockHeight: m.
|
|
118
|
-
finalizedBlockHeight: m.
|
|
216
|
+
initialSize: m.initialSize,
|
|
217
|
+
initialRoot: m.initialRoot,
|
|
218
|
+
oldestHistoricBlock: m.oldestHistoricBlock,
|
|
219
|
+
unfinalizedBlockHeight: m.unfinalizedBlockHeight,
|
|
220
|
+
finalizedBlockHeight: m.finalizedBlockHeight
|
|
119
221
|
};
|
|
120
222
|
}
|
|
121
223
|
function convertWorldStateMeta(m) {
|
|
122
224
|
return {
|
|
123
|
-
noteHashTreeMeta: convertTreeMeta(m.
|
|
124
|
-
messageTreeMeta: convertTreeMeta(m.
|
|
125
|
-
archiveTreeMeta: convertTreeMeta(m.
|
|
126
|
-
publicDataTreeMeta: convertTreeMeta(m.
|
|
127
|
-
nullifierTreeMeta: convertTreeMeta(m.
|
|
225
|
+
noteHashTreeMeta: convertTreeMeta(m.noteHashTreeMeta),
|
|
226
|
+
messageTreeMeta: convertTreeMeta(m.messageTreeMeta),
|
|
227
|
+
archiveTreeMeta: convertTreeMeta(m.archiveTreeMeta),
|
|
228
|
+
publicDataTreeMeta: convertTreeMeta(m.publicDataTreeMeta),
|
|
229
|
+
nullifierTreeMeta: convertTreeMeta(m.nullifierTreeMeta)
|
|
128
230
|
};
|
|
129
231
|
}
|
|
130
232
|
function convertStatusFull(s) {
|
|
131
233
|
return {
|
|
132
234
|
summary: convertStatusSummary(s.summary),
|
|
133
|
-
dbStats: convertWorldStateDBStats(s.
|
|
235
|
+
dbStats: convertWorldStateDBStats(s.dbStats),
|
|
134
236
|
meta: convertWorldStateMeta(s.meta)
|
|
135
237
|
};
|
|
136
238
|
}
|
|
@@ -143,473 +245,406 @@ function convertStatusFull(s) {
|
|
|
143
245
|
path: s.path.map((p)=>Buffer.from(p))
|
|
144
246
|
};
|
|
145
247
|
}
|
|
248
|
+
// ————— Public API —————
|
|
146
249
|
/**
|
|
147
250
|
* IPC-backed world state instance.
|
|
148
|
-
* Uses
|
|
251
|
+
* Uses WsdbService (spawns aztec-wsdb binary) and the generated AsyncApi
|
|
149
252
|
* to communicate via the NamedUnion IPC protocol.
|
|
150
253
|
*/ export class IpcWorldState {
|
|
151
|
-
|
|
254
|
+
wsdb;
|
|
152
255
|
instrumentation;
|
|
153
256
|
log;
|
|
154
257
|
open;
|
|
155
|
-
queues;
|
|
156
258
|
api;
|
|
157
259
|
/** Tracks checkpoint depth per fork (WSDB IPC doesn't return depth in response). */ checkpointDepths;
|
|
158
|
-
constructor(
|
|
159
|
-
this.
|
|
260
|
+
constructor(wsdb, instrumentation, bindings, log = createLogger('world-state:ipc-database', bindings)){
|
|
261
|
+
this.wsdb = wsdb;
|
|
160
262
|
this.instrumentation = instrumentation;
|
|
161
263
|
this.log = log;
|
|
162
264
|
this.open = true;
|
|
163
|
-
this.queues = new Map();
|
|
164
265
|
this.checkpointDepths = new Map();
|
|
165
|
-
this.api =
|
|
166
|
-
this.queues.set(0, new WorldStateOpsQueue());
|
|
266
|
+
this.api = wsdb;
|
|
167
267
|
this.log.info('Created IPC-backed world state instance');
|
|
168
268
|
}
|
|
169
|
-
/** Returns the socket path of the underlying wsdb server. */ getSocketPath() {
|
|
170
|
-
return this.wsdbBackend.getSocketPath();
|
|
171
|
-
}
|
|
172
269
|
/**
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
if (isWithCanonical(body)) {
|
|
183
|
-
forkId = 0;
|
|
184
|
-
} else if (isWithForkId(body)) {
|
|
185
|
-
forkId = body.forkId;
|
|
186
|
-
} else if (isWithRevision(body)) {
|
|
187
|
-
forkId = body.revision.forkId;
|
|
188
|
-
committedOnly = body.revision.includeUncommitted === false;
|
|
189
|
-
} else {
|
|
190
|
-
const _ = body;
|
|
191
|
-
throw new Error(`Unable to determine forkId for message=${WorldStateMessageType[messageType]}`);
|
|
192
|
-
}
|
|
193
|
-
let requestQueue = this.queues.get(forkId);
|
|
194
|
-
if (requestQueue === undefined) {
|
|
195
|
-
requestQueue = new WorldStateOpsQueue();
|
|
196
|
-
this.queues.set(forkId, requestQueue);
|
|
197
|
-
}
|
|
198
|
-
// The per-fork queue is cleaned up in `finally` even on error, so the JS-side queues map cannot outlive
|
|
199
|
-
// the native fork (e.g. when the native fork was already destroyed by an unwind/historical-prune and
|
|
200
|
-
// DELETE_FORK rejects with "Fork not found").
|
|
201
|
-
let shouldDeleteForkQueue = false;
|
|
202
|
-
try {
|
|
203
|
-
const response = await requestQueue.execute(async ()=>{
|
|
204
|
-
assert.notEqual(messageType, WorldStateMessageType.CLOSE, 'Use close() to close the IPC instance');
|
|
205
|
-
assert.equal(this.open, true, 'IPC instance is closed');
|
|
206
|
-
let response;
|
|
207
|
-
try {
|
|
208
|
-
response = await this._sendMessage(messageType, body);
|
|
209
|
-
} catch (error) {
|
|
210
|
-
errorHandler(error.message);
|
|
211
|
-
throw error;
|
|
212
|
-
}
|
|
213
|
-
return responseHandler(response);
|
|
214
|
-
}, messageType, committedOnly);
|
|
215
|
-
return response;
|
|
216
|
-
} catch (err) {
|
|
217
|
-
shouldDeleteForkQueue = forkId !== 0 && err?.message === 'Fork not found';
|
|
218
|
-
throw err;
|
|
219
|
-
} finally{
|
|
220
|
-
if (messageType === WorldStateMessageType.DELETE_FORK || shouldDeleteForkQueue) {
|
|
221
|
-
await requestQueue.stop();
|
|
222
|
-
this.queues.delete(forkId);
|
|
270
|
+
* Spawn an `aztec-wsdb` subprocess and return an IPC-backed world state wrapping it.
|
|
271
|
+
* Encapsulates wsdb binary discovery, service construction, and readiness wait.
|
|
272
|
+
*/ static async spawn(dataDir, wsTreeMapSizes, genesis, instrumentation, bindings, threads = getWsdbThreadCount()) {
|
|
273
|
+
const transport = process.env.WSDB_TRANSPORT === 'shm' ? 'shm' : 'uds';
|
|
274
|
+
const wsdb = await WsdbService.spawn({
|
|
275
|
+
transport,
|
|
276
|
+
extraArgs: getWsdbExtraArgs(dataDir, wsTreeMapSizes, genesis, threads),
|
|
277
|
+
env: {
|
|
278
|
+
HARDWARE_CONCURRENCY: threads.toString()
|
|
223
279
|
}
|
|
224
|
-
}
|
|
280
|
+
});
|
|
281
|
+
return new IpcWorldState(wsdb, instrumentation, bindings);
|
|
282
|
+
}
|
|
283
|
+
getIpcPath() {
|
|
284
|
+
return this.wsdb.getIpcPath();
|
|
225
285
|
}
|
|
226
286
|
async close() {
|
|
227
287
|
if (!this.open) {
|
|
228
288
|
return;
|
|
229
289
|
}
|
|
230
290
|
this.open = false;
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
291
|
+
await this.wsdb.destroy();
|
|
292
|
+
}
|
|
293
|
+
getTreeInfo(treeId, revision) {
|
|
294
|
+
return this.execute('getTreeInfo', revision.forkId, revision.includeUncommitted === false, async ()=>{
|
|
295
|
+
const resp = await this.api.getTreeInfo({
|
|
296
|
+
treeId,
|
|
297
|
+
revision: toWsdbRevision(revision)
|
|
298
|
+
});
|
|
299
|
+
return {
|
|
300
|
+
treeId: resp.treeId,
|
|
301
|
+
root: Buffer.from(resp.root),
|
|
302
|
+
size: BigInt(resp.size),
|
|
303
|
+
depth: resp.depth
|
|
304
|
+
};
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
getStateReference(revision) {
|
|
308
|
+
return this.execute('getStateReference', revision.forkId, revision.includeUncommitted === false, async ()=>{
|
|
309
|
+
const resp = await this.api.getStateReference({
|
|
310
|
+
revision: toWsdbRevision(revision)
|
|
311
|
+
});
|
|
312
|
+
return convertStateRef(resp.state);
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
getInitialStateReference() {
|
|
316
|
+
return this.execute('getInitialStateReference', 0, false, async ()=>{
|
|
317
|
+
const resp = await this.api.getInitialStateReference({});
|
|
318
|
+
return convertStateRef(resp.state);
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
getLeafValue(treeId, revision, leafIndex) {
|
|
322
|
+
return this.execute('getLeafValue', revision.forkId, revision.includeUncommitted === false, async ()=>{
|
|
323
|
+
const wsdbRevision = toWsdbRevision(revision);
|
|
324
|
+
const wsdbLeafIndex = Number(leafIndex);
|
|
325
|
+
if (treeId === MerkleTreeId.PUBLIC_DATA_TREE) {
|
|
326
|
+
const resp = await this.api.getPublicDataLeafValue({
|
|
327
|
+
revision: wsdbRevision,
|
|
328
|
+
leafIndex: wsdbLeafIndex
|
|
329
|
+
});
|
|
330
|
+
return resp.value ? fromPublicDataLeaf(resp.value) : undefined;
|
|
331
|
+
}
|
|
332
|
+
if (treeId === MerkleTreeId.NULLIFIER_TREE) {
|
|
333
|
+
const resp = await this.api.getNullifierLeafValue({
|
|
334
|
+
revision: wsdbRevision,
|
|
335
|
+
leafIndex: wsdbLeafIndex
|
|
336
|
+
});
|
|
337
|
+
return resp.value ? fromNullifierLeaf(resp.value) : undefined;
|
|
338
|
+
}
|
|
339
|
+
const resp = await this.api.getLeafValue({
|
|
340
|
+
treeId,
|
|
341
|
+
revision: wsdbRevision,
|
|
342
|
+
leafIndex: wsdbLeafIndex
|
|
343
|
+
});
|
|
344
|
+
return resp.value ? Buffer.from(resp.value) : undefined;
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
getLeafPreimage(treeId, revision, leafIndex) {
|
|
348
|
+
return this.execute('getLeafPreimage', revision.forkId, revision.includeUncommitted === false, async ()=>{
|
|
349
|
+
const resp = treeId === MerkleTreeId.PUBLIC_DATA_TREE ? await this.api.getPublicDataLeafPreimage({
|
|
350
|
+
revision: toWsdbRevision(revision),
|
|
351
|
+
leafIndex: Number(leafIndex)
|
|
352
|
+
}) : await this.api.getNullifierLeafPreimage({
|
|
353
|
+
revision: toWsdbRevision(revision),
|
|
354
|
+
leafIndex: Number(leafIndex)
|
|
355
|
+
});
|
|
356
|
+
return resp.preimage ? convertUint8ArraysToBuffers(resp.preimage) : undefined;
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
getSiblingPath(treeId, revision, leafIndex) {
|
|
360
|
+
return this.execute('getSiblingPath', revision.forkId, revision.includeUncommitted === false, async ()=>{
|
|
361
|
+
const resp = await this.api.getSiblingPath({
|
|
362
|
+
treeId,
|
|
363
|
+
revision: toWsdbRevision(revision),
|
|
364
|
+
leafIndex: Number(leafIndex)
|
|
365
|
+
});
|
|
366
|
+
return resp.path.map((p)=>Buffer.from(p));
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
getBlockNumbersForLeafIndices(treeId, revision, leafIndices) {
|
|
370
|
+
return this.execute('getBlockNumbersForLeafIndices', revision.forkId, revision.includeUncommitted === false, async ()=>{
|
|
371
|
+
const resp = await this.api.getBlockNumbersForLeafIndices({
|
|
372
|
+
treeId,
|
|
373
|
+
revision: toWsdbRevision(revision),
|
|
374
|
+
leafIndices: leafIndices.map(Number)
|
|
375
|
+
});
|
|
376
|
+
return resp.blockNumbers.map((n)=>n != null ? BigInt(n) : undefined);
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
findLeafIndices(treeId, revision, leaves, startIndex) {
|
|
380
|
+
return this.execute('findLeafIndices', revision.forkId, revision.includeUncommitted === false, async ()=>{
|
|
381
|
+
const wsdbRevision = toWsdbRevision(revision);
|
|
382
|
+
const wsdbStartIndex = Number(startIndex);
|
|
383
|
+
const resp = treeId === MerkleTreeId.PUBLIC_DATA_TREE ? await this.api.findPublicDataLeafIndices({
|
|
384
|
+
revision: wsdbRevision,
|
|
385
|
+
leaves: leaves.map(toPublicDataLeaf),
|
|
386
|
+
startIndex: wsdbStartIndex
|
|
387
|
+
}) : treeId === MerkleTreeId.NULLIFIER_TREE ? await this.api.findNullifierLeafIndices({
|
|
388
|
+
revision: wsdbRevision,
|
|
389
|
+
leaves: leaves.map(toNullifierLeaf),
|
|
390
|
+
startIndex: wsdbStartIndex
|
|
391
|
+
}) : await this.api.findLeafIndices({
|
|
392
|
+
treeId,
|
|
393
|
+
revision: wsdbRevision,
|
|
394
|
+
leaves: leaves.map(toFrLeaf),
|
|
395
|
+
startIndex: wsdbStartIndex
|
|
396
|
+
});
|
|
397
|
+
return resp.indices.map((n)=>n != null ? BigInt(n) : undefined);
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
findLowLeaf(treeId, revision, key) {
|
|
401
|
+
return this.execute('findLowLeaf', revision.forkId, revision.includeUncommitted === false, async ()=>{
|
|
402
|
+
const resp = await this.api.findLowLeaf({
|
|
403
|
+
treeId,
|
|
404
|
+
revision: toWsdbRevision(revision),
|
|
405
|
+
key: new Uint8Array(key.toBuffer())
|
|
406
|
+
});
|
|
407
|
+
return {
|
|
408
|
+
alreadyPresent: resp.alreadyPresent,
|
|
409
|
+
index: BigInt(resp.index)
|
|
410
|
+
};
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
findSiblingPaths(treeId, revision, leaves) {
|
|
414
|
+
return this.execute('findSiblingPaths', revision.forkId, revision.includeUncommitted === false, async ()=>{
|
|
415
|
+
const wsdbRevision = toWsdbRevision(revision);
|
|
416
|
+
const resp = treeId === MerkleTreeId.PUBLIC_DATA_TREE ? await this.api.findPublicDataSiblingPaths({
|
|
417
|
+
revision: wsdbRevision,
|
|
418
|
+
leaves: leaves.map(toPublicDataLeaf)
|
|
419
|
+
}) : treeId === MerkleTreeId.NULLIFIER_TREE ? await this.api.findNullifierSiblingPaths({
|
|
420
|
+
revision: wsdbRevision,
|
|
421
|
+
leaves: leaves.map(toNullifierLeaf)
|
|
422
|
+
}) : await this.api.findSiblingPaths({
|
|
423
|
+
treeId,
|
|
424
|
+
revision: wsdbRevision,
|
|
425
|
+
leaves: leaves.map(toFrLeaf)
|
|
426
|
+
});
|
|
427
|
+
return resp.paths.map(convertSiblingPathAndIndex);
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
updateArchive(forkId, blockStateRef, blockHeaderHash) {
|
|
431
|
+
return this.execute('updateArchive', forkId, false, async ()=>{
|
|
432
|
+
await this.api.updateArchive({
|
|
433
|
+
blockStateRef: blockStateRefToMap(blockStateRef),
|
|
434
|
+
blockHeaderHash: new Uint8Array(blockHeaderHash),
|
|
435
|
+
forkId
|
|
436
|
+
});
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
appendLeaves(treeId, forkId, leaves) {
|
|
440
|
+
return this.execute('appendLeaves', forkId, false, async ()=>{
|
|
441
|
+
if (treeId === MerkleTreeId.PUBLIC_DATA_TREE) {
|
|
442
|
+
await this.api.appendPublicDataLeaves({
|
|
443
|
+
leaves: leaves.map(toPublicDataLeaf),
|
|
444
|
+
forkId
|
|
445
|
+
});
|
|
446
|
+
} else if (treeId === MerkleTreeId.NULLIFIER_TREE) {
|
|
447
|
+
await this.api.appendNullifierLeaves({
|
|
448
|
+
leaves: leaves.map(toNullifierLeaf),
|
|
449
|
+
forkId
|
|
450
|
+
});
|
|
451
|
+
} else {
|
|
452
|
+
await this.api.appendLeaves({
|
|
453
|
+
treeId,
|
|
454
|
+
leaves: leaves.map(toFrLeaf),
|
|
455
|
+
forkId
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
batchInsert(treeId, forkId, leaves, subtreeDepth) {
|
|
461
|
+
return this.execute('batchInsert', forkId, false, async ()=>{
|
|
462
|
+
const resp = treeId === MerkleTreeId.PUBLIC_DATA_TREE ? await this.api.batchInsertPublicData({
|
|
463
|
+
leaves: leaves.map(toPublicDataLeaf),
|
|
464
|
+
subtreeDepth,
|
|
465
|
+
forkId
|
|
466
|
+
}) : await this.api.batchInsertNullifier({
|
|
467
|
+
leaves: leaves.map(toNullifierLeaf),
|
|
468
|
+
subtreeDepth,
|
|
469
|
+
forkId
|
|
470
|
+
});
|
|
471
|
+
return treeId === MerkleTreeId.PUBLIC_DATA_TREE ? fromBatchInsertionResult(resp.result, fromPublicDataLeaf) : fromBatchInsertionResult(resp.result, fromNullifierLeaf);
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
sequentialInsert(treeId, forkId, leaves) {
|
|
475
|
+
return this.execute('sequentialInsert', forkId, false, async ()=>{
|
|
476
|
+
const resp = treeId === MerkleTreeId.PUBLIC_DATA_TREE ? await this.api.sequentialInsertPublicData({
|
|
477
|
+
leaves: leaves.map(toPublicDataLeaf),
|
|
478
|
+
forkId
|
|
479
|
+
}) : await this.api.sequentialInsertNullifier({
|
|
480
|
+
leaves: leaves.map(toNullifierLeaf),
|
|
481
|
+
forkId
|
|
482
|
+
});
|
|
483
|
+
return treeId === MerkleTreeId.PUBLIC_DATA_TREE ? fromSequentialInsertionResult(resp.result, fromPublicDataLeaf) : fromSequentialInsertionResult(resp.result, fromNullifierLeaf);
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
syncBlock(input) {
|
|
487
|
+
return this.execute('syncBlock', 0, false, async ()=>{
|
|
488
|
+
const resp = await this.api.syncBlock({
|
|
489
|
+
blockNumber: Number(input.blockNumber),
|
|
490
|
+
blockStateRef: blockStateRefToMap(input.blockStateRef),
|
|
491
|
+
blockHeaderHash: new Uint8Array(input.blockHeaderHash),
|
|
492
|
+
expectedArchiveRoot: new Uint8Array(input.expectedArchiveRoot),
|
|
493
|
+
expectedPreviousArchiveRoot: new Uint8Array(input.expectedPreviousArchiveRoot),
|
|
494
|
+
paddedNoteHashes: input.paddedNoteHashes.map(toFrLeaf),
|
|
495
|
+
paddedL1ToL2Messages: input.paddedL1ToL2Messages.map(toFrLeaf),
|
|
496
|
+
paddedNullifiers: input.paddedNullifiers.map(toNullifierLeaf),
|
|
497
|
+
publicDataWrites: input.publicDataWrites.map(toPublicDataLeaf)
|
|
498
|
+
});
|
|
499
|
+
return convertStatusFull(resp.status);
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
createFork(input) {
|
|
503
|
+
return this.execute('createFork', 0, false, async ()=>{
|
|
504
|
+
const resp = await this.api.createFork({
|
|
505
|
+
latest: input.latest,
|
|
506
|
+
blockNumber: Number(input.blockNumber)
|
|
507
|
+
});
|
|
508
|
+
return resp.forkId;
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
deleteFork(forkId) {
|
|
512
|
+
return this.execute('deleteFork', forkId, false, async ()=>{
|
|
513
|
+
await this.api.deleteFork({
|
|
514
|
+
forkId
|
|
515
|
+
});
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
finalizeBlocks(toBlockNumber) {
|
|
519
|
+
return this.execute('finalizeBlocks', 0, false, async ()=>{
|
|
520
|
+
const resp = await this.api.finalizeBlocks({
|
|
521
|
+
toBlockNumber: Number(toBlockNumber)
|
|
522
|
+
});
|
|
523
|
+
return convertStatusSummary(resp.status);
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
unwindBlocks(toBlockNumber) {
|
|
527
|
+
return this.execute('unwindBlocks', 0, false, async ()=>{
|
|
528
|
+
const resp = await this.api.unwindBlocks({
|
|
529
|
+
toBlockNumber: Number(toBlockNumber)
|
|
530
|
+
});
|
|
531
|
+
return convertStatusFull(resp.status);
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
removeHistoricalBlocks(toBlockNumber) {
|
|
535
|
+
return this.execute('removeHistoricalBlocks', 0, false, async ()=>{
|
|
536
|
+
const resp = await this.api.removeHistoricalBlocks({
|
|
537
|
+
toBlockNumber: Number(toBlockNumber)
|
|
538
|
+
});
|
|
539
|
+
return convertStatusFull(resp.status);
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
getStatus() {
|
|
543
|
+
return this.execute('getStatus', 0, false, async ()=>{
|
|
544
|
+
const resp = await this.api.getStatus({});
|
|
545
|
+
return convertStatusSummary(resp.status);
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
createCheckpoint(forkId) {
|
|
549
|
+
return this.execute('createCheckpoint', forkId, false, async ()=>{
|
|
550
|
+
await this.api.createCheckpoint({
|
|
551
|
+
forkId
|
|
552
|
+
});
|
|
553
|
+
const depth = (this.checkpointDepths.get(forkId) ?? 0) + 1;
|
|
554
|
+
this.checkpointDepths.set(forkId, depth);
|
|
555
|
+
return depth;
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
commitCheckpoint(forkId) {
|
|
559
|
+
return this.execute('commitCheckpoint', forkId, false, async ()=>{
|
|
560
|
+
await this.api.commitCheckpoint({
|
|
561
|
+
forkId
|
|
562
|
+
});
|
|
563
|
+
const depth = Math.max(0, (this.checkpointDepths.get(forkId) ?? 0) - 1);
|
|
564
|
+
this.checkpointDepths.set(forkId, depth);
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
revertCheckpoint(forkId) {
|
|
568
|
+
return this.execute('revertCheckpoint', forkId, false, async ()=>{
|
|
569
|
+
await this.api.revertCheckpoint({
|
|
570
|
+
forkId
|
|
571
|
+
});
|
|
572
|
+
const depth = Math.max(0, (this.checkpointDepths.get(forkId) ?? 0) - 1);
|
|
573
|
+
this.checkpointDepths.set(forkId, depth);
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
commitAllCheckpoints(forkId, depth) {
|
|
577
|
+
return this.execute('commitAllCheckpoints', forkId, false, async ()=>{
|
|
578
|
+
const currentDepth = this.checkpointDepths.get(forkId) ?? 0;
|
|
579
|
+
if (depth === 0) {
|
|
580
|
+
await this.api.commitAllCheckpoints({
|
|
581
|
+
forkId
|
|
582
|
+
});
|
|
583
|
+
} else {
|
|
584
|
+
for(let d = currentDepth; d > depth; d--){
|
|
585
|
+
await this.api.commitCheckpoint({
|
|
586
|
+
forkId
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
this.checkpointDepths.set(forkId, depth);
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
revertAllCheckpoints(forkId, depth) {
|
|
594
|
+
return this.execute('revertAllCheckpoints', forkId, false, async ()=>{
|
|
595
|
+
const currentDepth = this.checkpointDepths.get(forkId) ?? 0;
|
|
596
|
+
if (depth === 0) {
|
|
597
|
+
await this.api.revertAllCheckpoints({
|
|
598
|
+
forkId
|
|
599
|
+
});
|
|
600
|
+
} else {
|
|
601
|
+
for(let d = currentDepth; d > depth; d--){
|
|
602
|
+
await this.api.revertCheckpoint({
|
|
603
|
+
forkId
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
this.checkpointDepths.set(forkId, depth);
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
copyStores(dstPath, compact) {
|
|
611
|
+
return this.execute('copyStores', 0, false, async ()=>{
|
|
612
|
+
await this.api.copyStores({
|
|
613
|
+
dstPath,
|
|
614
|
+
compact
|
|
615
|
+
});
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
// Read/write ordering is enforced server-side by the wsdb per-fork scheduler,
|
|
619
|
+
// so the client no longer queues: every op is sent immediately and the server
|
|
620
|
+
// serializes writes per fork while running reads concurrently. `_forkId` and
|
|
621
|
+
// `_committedOnly` are retained in the signature (they describe the op) but are
|
|
622
|
+
// no longer needed for client-side ordering.
|
|
623
|
+
async execute(operation, _forkId, _committedOnly, request) {
|
|
624
|
+
if (!this.open) {
|
|
625
|
+
throw new Error('IPC instance is closed');
|
|
247
626
|
}
|
|
627
|
+
return await this.send(operation, request);
|
|
248
628
|
}
|
|
249
|
-
async
|
|
629
|
+
async send(operation, request) {
|
|
250
630
|
const start = performance.now();
|
|
251
631
|
try {
|
|
252
|
-
const response = await
|
|
632
|
+
const response = await request();
|
|
253
633
|
const durationMs = performance.now() - start;
|
|
254
|
-
this.log.trace(`Call ${
|
|
634
|
+
this.log.trace(`Call ${operation} took (ms)`, {
|
|
255
635
|
duration: durationMs
|
|
256
636
|
});
|
|
257
|
-
this.instrumentation.recordRoundTrip(durationMs * 1000,
|
|
637
|
+
this.instrumentation.recordRoundTrip(durationMs * 1000, operation);
|
|
258
638
|
return response;
|
|
259
639
|
} catch (error) {
|
|
260
|
-
this.log.error(`Call ${
|
|
640
|
+
this.log.error(`Call ${operation} failed: ${error}`, error);
|
|
261
641
|
throw error;
|
|
262
642
|
}
|
|
263
643
|
}
|
|
264
|
-
async dispatch(messageType, body) {
|
|
265
|
-
switch(messageType){
|
|
266
|
-
// ——— Tree info & state reference ———
|
|
267
|
-
case WorldStateMessageType.GET_TREE_INFO:
|
|
268
|
-
{
|
|
269
|
-
const b = body;
|
|
270
|
-
const resp = await this.api.wsdbGetTreeInfo({
|
|
271
|
-
treeid: b.treeId,
|
|
272
|
-
revision: toWsdbRevision(b.revision)
|
|
273
|
-
});
|
|
274
|
-
return {
|
|
275
|
-
treeId: resp.treeid,
|
|
276
|
-
root: Buffer.from(resp.root),
|
|
277
|
-
size: resp.size,
|
|
278
|
-
depth: resp.depth
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
case WorldStateMessageType.GET_STATE_REFERENCE:
|
|
282
|
-
{
|
|
283
|
-
const b = body;
|
|
284
|
-
const resp = await this.api.wsdbGetStateReference({
|
|
285
|
-
revision: toWsdbRevision(b.revision)
|
|
286
|
-
});
|
|
287
|
-
return {
|
|
288
|
-
state: convertStateRef(resp.state)
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
case WorldStateMessageType.GET_INITIAL_STATE_REFERENCE:
|
|
292
|
-
{
|
|
293
|
-
const resp = await this.api.wsdbGetInitialStateReference({});
|
|
294
|
-
return {
|
|
295
|
-
state: convertStateRef(resp.state)
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
// ——— Leaf queries ———
|
|
299
|
-
case WorldStateMessageType.GET_LEAF_VALUE:
|
|
300
|
-
{
|
|
301
|
-
const b = body;
|
|
302
|
-
const resp = await this.api.wsdbGetLeafValue({
|
|
303
|
-
treeid: b.treeId,
|
|
304
|
-
revision: toWsdbRevision(b.revision),
|
|
305
|
-
leafindex: Number(b.leafIndex)
|
|
306
|
-
});
|
|
307
|
-
if (!resp.value) {
|
|
308
|
-
return undefined;
|
|
309
|
-
}
|
|
310
|
-
return decodeLeafValue(resp.value);
|
|
311
|
-
}
|
|
312
|
-
case WorldStateMessageType.GET_LEAF_PREIMAGE:
|
|
313
|
-
{
|
|
314
|
-
const b = body;
|
|
315
|
-
const resp = await this.api.wsdbGetLeafPreimage({
|
|
316
|
-
treeid: b.treeId,
|
|
317
|
-
revision: toWsdbRevision(b.revision),
|
|
318
|
-
leafindex: Number(b.leafIndex)
|
|
319
|
-
});
|
|
320
|
-
if (!resp.preimage) {
|
|
321
|
-
return undefined;
|
|
322
|
-
}
|
|
323
|
-
return decodeLeafPreimage(resp.preimage);
|
|
324
|
-
}
|
|
325
|
-
case WorldStateMessageType.GET_SIBLING_PATH:
|
|
326
|
-
{
|
|
327
|
-
const b = body;
|
|
328
|
-
const resp = await this.api.wsdbGetSiblingPath({
|
|
329
|
-
treeid: b.treeId,
|
|
330
|
-
revision: toWsdbRevision(b.revision),
|
|
331
|
-
leafindex: Number(b.leafIndex)
|
|
332
|
-
});
|
|
333
|
-
return resp.path.map((p)=>Buffer.from(p));
|
|
334
|
-
}
|
|
335
|
-
case WorldStateMessageType.GET_BLOCK_NUMBERS_FOR_LEAF_INDICES:
|
|
336
|
-
{
|
|
337
|
-
const b = body;
|
|
338
|
-
const resp = await this.api.wsdbGetBlockNumbersForLeafIndices({
|
|
339
|
-
treeid: b.treeId,
|
|
340
|
-
revision: toWsdbRevision(b.revision),
|
|
341
|
-
leafindices: b.leafIndices.map(Number)
|
|
342
|
-
});
|
|
343
|
-
return {
|
|
344
|
-
blockNumbers: resp.blocknumbers.map((n)=>n != null ? BigInt(n) : undefined)
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
// ——— Find operations ———
|
|
348
|
-
case WorldStateMessageType.FIND_LEAF_INDICES:
|
|
349
|
-
{
|
|
350
|
-
const b = body;
|
|
351
|
-
const resp = await this.api.wsdbFindLeafIndices({
|
|
352
|
-
treeid: b.treeId,
|
|
353
|
-
revision: toWsdbRevision(b.revision),
|
|
354
|
-
leaves: b.leaves.map(serializeLeafToBytes),
|
|
355
|
-
startindex: Number(b.startIndex)
|
|
356
|
-
});
|
|
357
|
-
return {
|
|
358
|
-
indices: resp.indices.map((n)=>n != null ? BigInt(n) : undefined)
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
case WorldStateMessageType.FIND_LOW_LEAF:
|
|
362
|
-
{
|
|
363
|
-
const b = body;
|
|
364
|
-
const resp = await this.api.wsdbFindLowLeaf({
|
|
365
|
-
treeid: b.treeId,
|
|
366
|
-
revision: toWsdbRevision(b.revision),
|
|
367
|
-
key: new Uint8Array(b.key.toBuffer())
|
|
368
|
-
});
|
|
369
|
-
return {
|
|
370
|
-
alreadyPresent: resp.alreadypresent,
|
|
371
|
-
index: BigInt(resp.index)
|
|
372
|
-
};
|
|
373
|
-
}
|
|
374
|
-
case WorldStateMessageType.FIND_SIBLING_PATHS:
|
|
375
|
-
{
|
|
376
|
-
const b = body;
|
|
377
|
-
const resp = await this.api.wsdbFindSiblingPaths({
|
|
378
|
-
treeid: b.treeId,
|
|
379
|
-
revision: toWsdbRevision(b.revision),
|
|
380
|
-
leaves: b.leaves.map(serializeLeafToBytes)
|
|
381
|
-
});
|
|
382
|
-
return {
|
|
383
|
-
paths: resp.paths.map(convertSiblingPathAndIndex)
|
|
384
|
-
};
|
|
385
|
-
}
|
|
386
|
-
// ——— Mutations ———
|
|
387
|
-
case WorldStateMessageType.APPEND_LEAVES:
|
|
388
|
-
{
|
|
389
|
-
const b = body;
|
|
390
|
-
await this.api.wsdbAppendLeaves({
|
|
391
|
-
treeid: b.treeId,
|
|
392
|
-
leaves: b.leaves.map(serializeLeafToBytes),
|
|
393
|
-
forkid: b.forkId
|
|
394
|
-
});
|
|
395
|
-
return undefined;
|
|
396
|
-
}
|
|
397
|
-
case WorldStateMessageType.BATCH_INSERT:
|
|
398
|
-
{
|
|
399
|
-
const b = body;
|
|
400
|
-
const resp = await this.api.wsdbBatchInsert({
|
|
401
|
-
treeid: b.treeId,
|
|
402
|
-
leaves: b.leaves.map(serializeLeafToBytes),
|
|
403
|
-
subtreedepth: b.subtreeDepth,
|
|
404
|
-
forkid: b.forkId
|
|
405
|
-
});
|
|
406
|
-
const decoded = msgpackDecoder.unpack(Buffer.from(resp.result));
|
|
407
|
-
return convertUint8ArraysToBuffers(decoded);
|
|
408
|
-
}
|
|
409
|
-
case WorldStateMessageType.SEQUENTIAL_INSERT:
|
|
410
|
-
{
|
|
411
|
-
const b = body;
|
|
412
|
-
const resp = await this.api.wsdbSequentialInsert({
|
|
413
|
-
treeid: b.treeId,
|
|
414
|
-
leaves: b.leaves.map(serializeLeafToBytes),
|
|
415
|
-
forkid: b.forkId
|
|
416
|
-
});
|
|
417
|
-
const decoded = msgpackDecoder.unpack(Buffer.from(resp.result));
|
|
418
|
-
return convertUint8ArraysToBuffers(decoded);
|
|
419
|
-
}
|
|
420
|
-
case WorldStateMessageType.UPDATE_ARCHIVE:
|
|
421
|
-
{
|
|
422
|
-
const b = body;
|
|
423
|
-
await this.api.wsdbUpdateArchive({
|
|
424
|
-
blockstateref: blockStateRefToMap(b.blockStateRef),
|
|
425
|
-
blockheaderhash: new Uint8Array(b.blockHeaderHash),
|
|
426
|
-
forkid: b.forkId
|
|
427
|
-
});
|
|
428
|
-
return undefined;
|
|
429
|
-
}
|
|
430
|
-
// ——— Commit / Rollback ———
|
|
431
|
-
case WorldStateMessageType.COMMIT:
|
|
432
|
-
{
|
|
433
|
-
await this.api.wsdbCommit({});
|
|
434
|
-
return undefined;
|
|
435
|
-
}
|
|
436
|
-
case WorldStateMessageType.ROLLBACK:
|
|
437
|
-
{
|
|
438
|
-
await this.api.wsdbRollback({});
|
|
439
|
-
return undefined;
|
|
440
|
-
}
|
|
441
|
-
// ——— Block sync ———
|
|
442
|
-
case WorldStateMessageType.SYNC_BLOCK:
|
|
443
|
-
{
|
|
444
|
-
const b = body;
|
|
445
|
-
const resp = await this.api.wsdbSyncBlock({
|
|
446
|
-
blocknumber: Number(b.blockNumber),
|
|
447
|
-
blockstateref: blockStateRefToMap(b.blockStateRef),
|
|
448
|
-
blockheaderhash: new Uint8Array(b.blockHeaderHash),
|
|
449
|
-
// Forwarded so the wsdb (IPC) sync path enforces the same archive-root divergence check as the napi path.
|
|
450
|
-
expectedarchiveroot: new Uint8Array(b.expectedArchiveRoot),
|
|
451
|
-
expectedpreviousarchiveroot: new Uint8Array(b.expectedPreviousArchiveRoot),
|
|
452
|
-
paddednotehashes: b.paddedNoteHashes.map((l)=>new Uint8Array(l)),
|
|
453
|
-
paddedl1tol2messages: b.paddedL1ToL2Messages.map((l)=>new Uint8Array(l)),
|
|
454
|
-
paddednullifiers: b.paddedNullifiers.map((l)=>({
|
|
455
|
-
nullifier: new Uint8Array(l.nullifier)
|
|
456
|
-
})),
|
|
457
|
-
publicdatawrites: b.publicDataWrites.map((l)=>({
|
|
458
|
-
slot: new Uint8Array(l.slot),
|
|
459
|
-
value: new Uint8Array(l.value)
|
|
460
|
-
}))
|
|
461
|
-
});
|
|
462
|
-
return convertStatusFull(resp.status);
|
|
463
|
-
}
|
|
464
|
-
// ——— Fork management ———
|
|
465
|
-
case WorldStateMessageType.CREATE_FORK:
|
|
466
|
-
{
|
|
467
|
-
const b = body;
|
|
468
|
-
const resp = await this.api.wsdbCreateFork({
|
|
469
|
-
latest: b.latest,
|
|
470
|
-
blocknumber: Number(b.blockNumber)
|
|
471
|
-
});
|
|
472
|
-
return {
|
|
473
|
-
forkId: resp.forkid
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
case WorldStateMessageType.DELETE_FORK:
|
|
477
|
-
{
|
|
478
|
-
const b = body;
|
|
479
|
-
await this.api.wsdbDeleteFork({
|
|
480
|
-
forkid: b.forkId
|
|
481
|
-
});
|
|
482
|
-
return undefined;
|
|
483
|
-
}
|
|
484
|
-
// ——— Block finalization ———
|
|
485
|
-
case WorldStateMessageType.FINALIZE_BLOCKS:
|
|
486
|
-
{
|
|
487
|
-
const b = body;
|
|
488
|
-
const resp = await this.api.wsdbFinalizeBlocks({
|
|
489
|
-
toblocknumber: Number(b.toBlockNumber)
|
|
490
|
-
});
|
|
491
|
-
return convertStatusSummary(resp.status);
|
|
492
|
-
}
|
|
493
|
-
case WorldStateMessageType.UNWIND_BLOCKS:
|
|
494
|
-
{
|
|
495
|
-
const b = body;
|
|
496
|
-
const resp = await this.api.wsdbUnwindBlocks({
|
|
497
|
-
toblocknumber: Number(b.toBlockNumber)
|
|
498
|
-
});
|
|
499
|
-
return convertStatusFull(resp.status);
|
|
500
|
-
}
|
|
501
|
-
case WorldStateMessageType.REMOVE_HISTORICAL_BLOCKS:
|
|
502
|
-
{
|
|
503
|
-
const b = body;
|
|
504
|
-
const resp = await this.api.wsdbRemoveHistoricalBlocks({
|
|
505
|
-
toblocknumber: Number(b.toBlockNumber)
|
|
506
|
-
});
|
|
507
|
-
return convertStatusFull(resp.status);
|
|
508
|
-
}
|
|
509
|
-
// ——— Status ———
|
|
510
|
-
case WorldStateMessageType.GET_STATUS:
|
|
511
|
-
{
|
|
512
|
-
const resp = await this.api.wsdbGetStatus({});
|
|
513
|
-
return convertStatusSummary(resp.status);
|
|
514
|
-
}
|
|
515
|
-
// ——— Checkpoints ———
|
|
516
|
-
case WorldStateMessageType.CREATE_CHECKPOINT:
|
|
517
|
-
{
|
|
518
|
-
const b = body;
|
|
519
|
-
await this.api.wsdbCreateCheckpoint({
|
|
520
|
-
forkid: b.forkId
|
|
521
|
-
});
|
|
522
|
-
const depth = (this.checkpointDepths.get(b.forkId) ?? 0) + 1;
|
|
523
|
-
this.checkpointDepths.set(b.forkId, depth);
|
|
524
|
-
return {
|
|
525
|
-
depth
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
case WorldStateMessageType.COMMIT_CHECKPOINT:
|
|
529
|
-
{
|
|
530
|
-
const b = body;
|
|
531
|
-
await this.api.wsdbCommitCheckpoint({
|
|
532
|
-
forkid: b.forkId
|
|
533
|
-
});
|
|
534
|
-
const depth = Math.max(0, (this.checkpointDepths.get(b.forkId) ?? 0) - 1);
|
|
535
|
-
this.checkpointDepths.set(b.forkId, depth);
|
|
536
|
-
return undefined;
|
|
537
|
-
}
|
|
538
|
-
case WorldStateMessageType.REVERT_CHECKPOINT:
|
|
539
|
-
{
|
|
540
|
-
const b = body;
|
|
541
|
-
await this.api.wsdbRevertCheckpoint({
|
|
542
|
-
forkid: b.forkId
|
|
543
|
-
});
|
|
544
|
-
const depth = Math.max(0, (this.checkpointDepths.get(b.forkId) ?? 0) - 1);
|
|
545
|
-
this.checkpointDepths.set(b.forkId, depth);
|
|
546
|
-
return undefined;
|
|
547
|
-
}
|
|
548
|
-
case WorldStateMessageType.COMMIT_ALL_CHECKPOINTS:
|
|
549
|
-
{
|
|
550
|
-
const b = body;
|
|
551
|
-
const targetDepth = b.depth ?? 0;
|
|
552
|
-
const currentDepth = this.checkpointDepths.get(b.forkId) ?? 0;
|
|
553
|
-
if (targetDepth === 0) {
|
|
554
|
-
// Commit everything — use the bulk operation
|
|
555
|
-
await this.api.wsdbCommitAllCheckpoints({
|
|
556
|
-
forkid: b.forkId
|
|
557
|
-
});
|
|
558
|
-
} else {
|
|
559
|
-
// Commit one level at a time down to target depth
|
|
560
|
-
for(let d = currentDepth; d > targetDepth; d--){
|
|
561
|
-
await this.api.wsdbCommitCheckpoint({
|
|
562
|
-
forkid: b.forkId
|
|
563
|
-
});
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
this.checkpointDepths.set(b.forkId, targetDepth);
|
|
567
|
-
return undefined;
|
|
568
|
-
}
|
|
569
|
-
case WorldStateMessageType.REVERT_ALL_CHECKPOINTS:
|
|
570
|
-
{
|
|
571
|
-
const b = body;
|
|
572
|
-
const targetDepth = b.depth ?? 0;
|
|
573
|
-
const currentDepth = this.checkpointDepths.get(b.forkId) ?? 0;
|
|
574
|
-
if (targetDepth === 0) {
|
|
575
|
-
// Revert everything — use the bulk operation
|
|
576
|
-
await this.api.wsdbRevertAllCheckpoints({
|
|
577
|
-
forkid: b.forkId
|
|
578
|
-
});
|
|
579
|
-
} else {
|
|
580
|
-
// Revert one level at a time down to target depth
|
|
581
|
-
for(let d = currentDepth; d > targetDepth; d--){
|
|
582
|
-
await this.api.wsdbRevertCheckpoint({
|
|
583
|
-
forkid: b.forkId
|
|
584
|
-
});
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
this.checkpointDepths.set(b.forkId, targetDepth);
|
|
588
|
-
return undefined;
|
|
589
|
-
}
|
|
590
|
-
// ——— Misc ———
|
|
591
|
-
case WorldStateMessageType.COPY_STORES:
|
|
592
|
-
{
|
|
593
|
-
const b = body;
|
|
594
|
-
await this.api.wsdbCopyStores({
|
|
595
|
-
dstpath: b.dstPath,
|
|
596
|
-
compact: b.compact
|
|
597
|
-
});
|
|
598
|
-
return undefined;
|
|
599
|
-
}
|
|
600
|
-
case WorldStateMessageType.CLOSE:
|
|
601
|
-
{
|
|
602
|
-
await this.api.wsdbShutdown({});
|
|
603
|
-
return undefined;
|
|
604
|
-
}
|
|
605
|
-
default:
|
|
606
|
-
throw new Error(`Unknown message type: ${messageType}`);
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
644
|
}
|
|
610
645
|
/**
|
|
611
646
|
* Helper to create WsdbOptions from standard world state config.
|
|
612
|
-
* Returns the options needed to construct a
|
|
647
|
+
* Returns the options needed to construct a wsdb service command line.
|
|
613
648
|
*/ export function getWsdbOptions(dataDir, wsTreeMapSizes) {
|
|
614
649
|
return {
|
|
615
650
|
treeHeights: {
|