@aztec/world-state 0.53.0 → 0.55.0
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/native/index.d.ts +2 -0
- package/dest/native/index.d.ts.map +1 -0
- package/dest/native/index.js +2 -0
- package/dest/native/message.d.ts +176 -0
- package/dest/native/message.d.ts.map +1 -0
- package/dest/native/message.js +69 -0
- package/dest/native/native_world_state.d.ts +44 -0
- package/dest/native/native_world_state.d.ts.map +1 -0
- package/dest/native/native_world_state.js +303 -0
- package/dest/synchronizer/server_world_state_synchronizer.d.ts +1 -1
- package/dest/synchronizer/server_world_state_synchronizer.d.ts.map +1 -1
- package/dest/synchronizer/server_world_state_synchronizer.js +1 -1
- package/dest/world-state-db/merkle_tree_db.d.ts +2 -0
- package/dest/world-state-db/merkle_tree_db.d.ts.map +1 -1
- package/package.json +16 -9
- package/src/native/index.ts +1 -0
- package/src/native/message.ts +247 -0
- package/src/native/native_world_state.ts +462 -0
- package/src/synchronizer/server_world_state_synchronizer.ts +1 -1
- package/src/world-state-db/merkle_tree_db.ts +3 -0
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type BatchInsertionResult,
|
|
3
|
+
type HandleL2BlockAndMessagesResult,
|
|
4
|
+
type IndexedTreeId,
|
|
5
|
+
type L2Block,
|
|
6
|
+
type MerkleTreeAdminOperations,
|
|
7
|
+
MerkleTreeId,
|
|
8
|
+
type MerkleTreeLeafType,
|
|
9
|
+
SiblingPath,
|
|
10
|
+
type TreeInfo,
|
|
11
|
+
TxEffect,
|
|
12
|
+
} from '@aztec/circuit-types';
|
|
13
|
+
import {
|
|
14
|
+
Fr,
|
|
15
|
+
Header,
|
|
16
|
+
MAX_NOTE_HASHES_PER_TX,
|
|
17
|
+
MAX_NULLIFIERS_PER_TX,
|
|
18
|
+
MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
19
|
+
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
20
|
+
NullifierLeaf,
|
|
21
|
+
NullifierLeafPreimage,
|
|
22
|
+
PartialStateReference,
|
|
23
|
+
PublicDataTreeLeaf,
|
|
24
|
+
PublicDataTreeLeafPreimage,
|
|
25
|
+
StateReference,
|
|
26
|
+
} from '@aztec/circuits.js';
|
|
27
|
+
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
28
|
+
import { SerialQueue } from '@aztec/foundation/queue';
|
|
29
|
+
import { serializeToBuffer } from '@aztec/foundation/serialize';
|
|
30
|
+
import type { IndexedTreeLeafPreimage } from '@aztec/foundation/trees';
|
|
31
|
+
|
|
32
|
+
import bindings from 'bindings';
|
|
33
|
+
import { Decoder, Encoder, addExtension } from 'msgpackr';
|
|
34
|
+
import { isAnyArrayBuffer } from 'util/types';
|
|
35
|
+
|
|
36
|
+
import { type MerkleTreeDb, type TreeSnapshots } from '../world-state-db/merkle_tree_db.js';
|
|
37
|
+
import { MerkleTreeAdminOperationsFacade } from '../world-state-db/merkle_tree_operations_facade.js';
|
|
38
|
+
import {
|
|
39
|
+
MessageHeader,
|
|
40
|
+
type SerializedIndexedLeaf,
|
|
41
|
+
type SerializedLeafValue,
|
|
42
|
+
TypedMessage,
|
|
43
|
+
WorldStateMessageType,
|
|
44
|
+
type WorldStateRequest,
|
|
45
|
+
type WorldStateResponse,
|
|
46
|
+
blockStateReference,
|
|
47
|
+
treeStateReferenceToSnapshot,
|
|
48
|
+
worldStateRevision,
|
|
49
|
+
} from './message.js';
|
|
50
|
+
|
|
51
|
+
// small extension to pack an NodeJS Fr instance to a representation that the C++ code can understand
|
|
52
|
+
// this only works for writes. Unpacking from C++ can't create Fr instances because the data is passed
|
|
53
|
+
// as raw, untagged, buffers. On the NodeJS side we don't know what the buffer represents
|
|
54
|
+
// Adding a tag would be a solution, but it would have to be done on both sides and it's unclear where else
|
|
55
|
+
// C++ fr instances are sent/received/stored.
|
|
56
|
+
addExtension({
|
|
57
|
+
Class: Fr,
|
|
58
|
+
write: fr => fr.toBuffer(),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
export interface NativeInstance {
|
|
62
|
+
call(msg: Buffer | Uint8Array): Promise<any>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export class NativeWorldStateService implements MerkleTreeDb {
|
|
66
|
+
private nextMessageId = 1;
|
|
67
|
+
|
|
68
|
+
private encoder = new Encoder({
|
|
69
|
+
// always encode JS objects as MessagePack maps
|
|
70
|
+
// this makes it compatible with other MessagePack decoders
|
|
71
|
+
useRecords: false,
|
|
72
|
+
int64AsType: 'bigint',
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
private decoder = new Decoder({
|
|
76
|
+
useRecords: false,
|
|
77
|
+
int64AsType: 'bigint',
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
private queue = new SerialQueue();
|
|
81
|
+
|
|
82
|
+
protected constructor(private instance: NativeInstance) {
|
|
83
|
+
this.queue.start();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
static async create(
|
|
87
|
+
dataDir: string,
|
|
88
|
+
libraryName = 'world_state_napi',
|
|
89
|
+
className = 'WorldState',
|
|
90
|
+
): Promise<NativeWorldStateService> {
|
|
91
|
+
const library = bindings(libraryName);
|
|
92
|
+
const instance = new library[className](dataDir);
|
|
93
|
+
const worldState = new NativeWorldStateService(instance);
|
|
94
|
+
await worldState.init();
|
|
95
|
+
return worldState;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
protected async init() {
|
|
99
|
+
const archive = await this.getTreeInfo(MerkleTreeId.ARCHIVE, false);
|
|
100
|
+
if (archive.size === 0n) {
|
|
101
|
+
// TODO (alexg) move this to the native module
|
|
102
|
+
// const header = await this.buildInitialHeader(true);
|
|
103
|
+
// await this.appendLeaves(MerkleTreeId.ARCHIVE, [header.hash()]);
|
|
104
|
+
// await this.commit();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public asLatest(): MerkleTreeAdminOperations {
|
|
109
|
+
return new MerkleTreeAdminOperationsFacade(this, true);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// async buildInitialHeader(ic: boolean = false): Promise<Header> {
|
|
113
|
+
// const state = await this.getStateReference(ic);
|
|
114
|
+
// return new Header(
|
|
115
|
+
// AppendOnlyTreeSnapshot.zero(),
|
|
116
|
+
// ContentCommitment.empty(),
|
|
117
|
+
// state,
|
|
118
|
+
// GlobalVariables.empty(),
|
|
119
|
+
// Fr.ZERO,
|
|
120
|
+
// );
|
|
121
|
+
// }
|
|
122
|
+
|
|
123
|
+
public getInitialHeader(): Header {
|
|
124
|
+
// TODO (alexg) implement this
|
|
125
|
+
return Header.empty();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async appendLeaves<ID extends MerkleTreeId>(treeId: ID, leaves: MerkleTreeLeafType<ID>[]): Promise<void> {
|
|
129
|
+
await this.call(WorldStateMessageType.APPEND_LEAVES, {
|
|
130
|
+
leaves: leaves.map(leaf => leaf as any),
|
|
131
|
+
treeId,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async batchInsert<TreeHeight extends number, SubtreeSiblingPathHeight extends number, ID extends IndexedTreeId>(
|
|
136
|
+
treeId: ID,
|
|
137
|
+
rawLeaves: Buffer[],
|
|
138
|
+
subtreeHeight: number,
|
|
139
|
+
): Promise<BatchInsertionResult<TreeHeight, SubtreeSiblingPathHeight>> {
|
|
140
|
+
const leaves = rawLeaves.map((leaf: Buffer) => hydrateLeaf(treeId, leaf)).map(serializeLeaf);
|
|
141
|
+
const resp = await this.call(WorldStateMessageType.BATCH_INSERT, { leaves, treeId, subtreeDepth: subtreeHeight });
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
newSubtreeSiblingPath: new SiblingPath<SubtreeSiblingPathHeight>(
|
|
145
|
+
resp.subtree_path.length as any,
|
|
146
|
+
resp.subtree_path,
|
|
147
|
+
),
|
|
148
|
+
sortedNewLeaves: resp.sorted_leaves
|
|
149
|
+
.map(([leaf]) => leaf)
|
|
150
|
+
.map(deserializeLeafValue)
|
|
151
|
+
.map(serializeToBuffer),
|
|
152
|
+
sortedNewLeavesIndexes: resp.sorted_leaves.map(([, index]) => index),
|
|
153
|
+
lowLeavesWitnessData: resp.low_leaf_witness_data.map(data => ({
|
|
154
|
+
index: BigInt(data.index),
|
|
155
|
+
leafPreimage: deserializeIndexedLeaf(data.leaf),
|
|
156
|
+
siblingPath: new SiblingPath<TreeHeight>(data.path.length as any, data.path),
|
|
157
|
+
})),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async commit(): Promise<void> {
|
|
162
|
+
await this.call(WorldStateMessageType.COMMIT, void 0);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
findLeafIndex(
|
|
166
|
+
treeId: MerkleTreeId,
|
|
167
|
+
value: MerkleTreeLeafType<MerkleTreeId>,
|
|
168
|
+
includeUncommitted: boolean,
|
|
169
|
+
): Promise<bigint | undefined> {
|
|
170
|
+
return this.findLeafIndexAfter(treeId, value, 0n, includeUncommitted);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async findLeafIndexAfter(
|
|
174
|
+
treeId: MerkleTreeId,
|
|
175
|
+
leaf: MerkleTreeLeafType<MerkleTreeId>,
|
|
176
|
+
startIndex: bigint,
|
|
177
|
+
includeUncommitted: boolean,
|
|
178
|
+
): Promise<bigint | undefined> {
|
|
179
|
+
const index = await this.call(WorldStateMessageType.FIND_LEAF_INDEX, {
|
|
180
|
+
leaf: serializeLeaf(hydrateLeaf(treeId, leaf)),
|
|
181
|
+
revision: worldStateRevision(includeUncommitted),
|
|
182
|
+
treeId,
|
|
183
|
+
startIndex,
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
if (typeof index === 'number' || typeof index === 'bigint') {
|
|
187
|
+
return BigInt(index);
|
|
188
|
+
} else {
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async getLeafPreimage(
|
|
194
|
+
treeId: IndexedTreeId,
|
|
195
|
+
leafIndex: bigint,
|
|
196
|
+
args: boolean,
|
|
197
|
+
): Promise<IndexedTreeLeafPreimage | undefined> {
|
|
198
|
+
const resp = await this.call(WorldStateMessageType.GET_LEAF_PREIMAGE, {
|
|
199
|
+
leafIndex,
|
|
200
|
+
revision: worldStateRevision(args),
|
|
201
|
+
treeId,
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
return resp ? deserializeIndexedLeaf(resp) : undefined;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async getLeafValue(
|
|
208
|
+
treeId: MerkleTreeId,
|
|
209
|
+
leafIndex: bigint,
|
|
210
|
+
includeUncommitted: boolean,
|
|
211
|
+
): Promise<MerkleTreeLeafType<MerkleTreeId> | undefined> {
|
|
212
|
+
const resp = await this.call(WorldStateMessageType.GET_LEAF_VALUE, {
|
|
213
|
+
leafIndex,
|
|
214
|
+
revision: worldStateRevision(includeUncommitted),
|
|
215
|
+
treeId,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
if (!resp) {
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const leaf = deserializeLeafValue(resp);
|
|
223
|
+
if (leaf instanceof Fr) {
|
|
224
|
+
return leaf;
|
|
225
|
+
} else {
|
|
226
|
+
return leaf.toBuffer();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async getPreviousValueIndex(
|
|
231
|
+
treeId: IndexedTreeId,
|
|
232
|
+
value: bigint,
|
|
233
|
+
includeUncommitted: boolean,
|
|
234
|
+
): Promise<{ index: bigint; alreadyPresent: boolean } | undefined> {
|
|
235
|
+
const resp = await this.call(WorldStateMessageType.FIND_LOW_LEAF, {
|
|
236
|
+
key: new Fr(value),
|
|
237
|
+
revision: worldStateRevision(includeUncommitted),
|
|
238
|
+
treeId,
|
|
239
|
+
});
|
|
240
|
+
return {
|
|
241
|
+
alreadyPresent: resp.alreadyPresent,
|
|
242
|
+
index: BigInt(resp.index),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async getSiblingPath(
|
|
247
|
+
treeId: MerkleTreeId,
|
|
248
|
+
leafIndex: bigint,
|
|
249
|
+
includeUncommitted: boolean,
|
|
250
|
+
): Promise<SiblingPath<number>> {
|
|
251
|
+
const siblingPath = await this.call(WorldStateMessageType.GET_SIBLING_PATH, {
|
|
252
|
+
leafIndex,
|
|
253
|
+
revision: worldStateRevision(includeUncommitted),
|
|
254
|
+
treeId,
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
return new SiblingPath(siblingPath.length, siblingPath);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
getSnapshot(_block: number): Promise<TreeSnapshots> {
|
|
261
|
+
return Promise.reject(new Error('getSnapshot not implemented'));
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async getStateReference(includeUncommitted: boolean): Promise<StateReference> {
|
|
265
|
+
const resp = await this.call(WorldStateMessageType.GET_STATE_REFERENCE, {
|
|
266
|
+
revision: worldStateRevision(includeUncommitted),
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
return new StateReference(
|
|
270
|
+
treeStateReferenceToSnapshot(resp.state[MerkleTreeId.L1_TO_L2_MESSAGE_TREE]),
|
|
271
|
+
new PartialStateReference(
|
|
272
|
+
treeStateReferenceToSnapshot(resp.state[MerkleTreeId.NOTE_HASH_TREE]),
|
|
273
|
+
treeStateReferenceToSnapshot(resp.state[MerkleTreeId.NULLIFIER_TREE]),
|
|
274
|
+
treeStateReferenceToSnapshot(resp.state[MerkleTreeId.PUBLIC_DATA_TREE]),
|
|
275
|
+
),
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async getTreeInfo(treeId: MerkleTreeId, includeUncommitted: boolean): Promise<TreeInfo> {
|
|
280
|
+
const resp = await this.call(WorldStateMessageType.GET_TREE_INFO, {
|
|
281
|
+
treeId: treeId,
|
|
282
|
+
revision: worldStateRevision(includeUncommitted),
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
depth: resp.depth,
|
|
287
|
+
root: resp.root,
|
|
288
|
+
size: BigInt(resp.size),
|
|
289
|
+
treeId,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
async handleL2BlockAndMessages(l2Block: L2Block, l1ToL2Messages: Fr[]): Promise<HandleL2BlockAndMessagesResult> {
|
|
294
|
+
// We have to pad both the tx effects and the values within tx effects because that's how the trees are built
|
|
295
|
+
// by circuits.
|
|
296
|
+
const paddedTxEffects = padArrayEnd(
|
|
297
|
+
l2Block.body.txEffects,
|
|
298
|
+
TxEffect.empty(),
|
|
299
|
+
l2Block.body.numberOfTxsIncludingPadded,
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
const paddedNoteHashes = paddedTxEffects.flatMap(txEffect =>
|
|
303
|
+
padArrayEnd(txEffect.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
|
|
304
|
+
);
|
|
305
|
+
const paddedL1ToL2Messages = padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
306
|
+
|
|
307
|
+
const paddedNullifiers = paddedTxEffects
|
|
308
|
+
.flatMap(txEffect => padArrayEnd(txEffect.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX))
|
|
309
|
+
.map(nullifier => new NullifierLeaf(nullifier));
|
|
310
|
+
|
|
311
|
+
// We insert the public data tree leaves with one batch per tx to avoid updating the same key twice
|
|
312
|
+
const batchesOfPaddedPublicDataWrites: PublicDataTreeLeaf[][] = [];
|
|
313
|
+
for (const txEffect of paddedTxEffects) {
|
|
314
|
+
const batch: PublicDataTreeLeaf[] = Array(MAX_TOTAL_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX).fill(
|
|
315
|
+
PublicDataTreeLeaf.empty(),
|
|
316
|
+
);
|
|
317
|
+
for (const [i, write] of txEffect.publicDataWrites.entries()) {
|
|
318
|
+
batch[i] = new PublicDataTreeLeaf(write.leafIndex, write.newValue);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
batchesOfPaddedPublicDataWrites.push(batch);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return await this.call(WorldStateMessageType.SYNC_BLOCK, {
|
|
325
|
+
blockHash: l2Block.hash(),
|
|
326
|
+
paddedL1ToL2Messages: paddedL1ToL2Messages.map(serializeLeaf),
|
|
327
|
+
paddedNoteHashes: paddedNoteHashes.map(serializeLeaf),
|
|
328
|
+
paddedNullifiers: paddedNullifiers.map(serializeLeaf),
|
|
329
|
+
batchesOfPaddedPublicDataWrites: batchesOfPaddedPublicDataWrites.map(batch => batch.map(serializeLeaf)),
|
|
330
|
+
blockStateRef: blockStateReference(l2Block.header.state),
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
async rollback(): Promise<void> {
|
|
335
|
+
await this.call(WorldStateMessageType.ROLLBACK, void 0);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
async updateArchive(header: Header, _includeUncommitted: boolean): Promise<void> {
|
|
339
|
+
await this.call(WorldStateMessageType.UPDATE_ARCHIVE, {
|
|
340
|
+
blockHash: header.hash().toBuffer(),
|
|
341
|
+
blockStateRef: blockStateReference(header.state),
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
updateLeaf<ID extends IndexedTreeId>(
|
|
346
|
+
_treeId: ID,
|
|
347
|
+
_leaf: NullifierLeafPreimage | Buffer,
|
|
348
|
+
_index: bigint,
|
|
349
|
+
): Promise<void> {
|
|
350
|
+
return Promise.reject(new Error('Method not implemented'));
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
private call<T extends WorldStateMessageType>(
|
|
354
|
+
messageType: T,
|
|
355
|
+
body: WorldStateRequest[T],
|
|
356
|
+
): Promise<WorldStateResponse[T]> {
|
|
357
|
+
return this.queue.put(async () => {
|
|
358
|
+
const request = new TypedMessage(messageType, new MessageHeader({ messageId: this.nextMessageId++ }), body);
|
|
359
|
+
|
|
360
|
+
const encodedRequest = this.encoder.encode(request);
|
|
361
|
+
const encodedResponse = await this.instance.call(encodedRequest);
|
|
362
|
+
|
|
363
|
+
const buf = Buffer.isBuffer(encodedResponse)
|
|
364
|
+
? encodedResponse
|
|
365
|
+
: isAnyArrayBuffer(encodedResponse)
|
|
366
|
+
? Buffer.from(encodedResponse)
|
|
367
|
+
: encodedResponse;
|
|
368
|
+
|
|
369
|
+
if (!Buffer.isBuffer(buf)) {
|
|
370
|
+
throw new TypeError(
|
|
371
|
+
'Invalid encoded response: expected Buffer or ArrayBuffer, got ' +
|
|
372
|
+
(encodedResponse === null ? 'null' : typeof encodedResponse),
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const decodedResponse = this.decoder.unpack(buf);
|
|
377
|
+
if (!TypedMessage.isTypedMessageLike(decodedResponse)) {
|
|
378
|
+
throw new TypeError(
|
|
379
|
+
'Invalid response: expected TypedMessageLike, got ' +
|
|
380
|
+
(decodedResponse === null ? 'null' : typeof decodedResponse),
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const response = TypedMessage.fromMessagePack<T, WorldStateResponse[T]>(decodedResponse);
|
|
385
|
+
|
|
386
|
+
if (response.header.requestId !== request.header.messageId) {
|
|
387
|
+
throw new Error(
|
|
388
|
+
'Response ID does not match request: ' + response.header.requestId + ' != ' + request.header.messageId,
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (response.msgType !== messageType) {
|
|
393
|
+
throw new Error('Invalid response message type: ' + response.msgType + ' != ' + messageType);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return response.value;
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
public async stop(): Promise<void> {
|
|
401
|
+
await this.queue.end();
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
public delete(): Promise<void> {
|
|
405
|
+
return Promise.reject(new Error('Method not implemented'));
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
public fork(): Promise<MerkleTreeDb> {
|
|
409
|
+
return Promise.reject(new Error('Method not implemented'));
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function hydrateLeaf<ID extends MerkleTreeId>(treeId: ID, leaf: Fr | Buffer) {
|
|
414
|
+
if (leaf instanceof Fr) {
|
|
415
|
+
return leaf;
|
|
416
|
+
} else if (treeId === MerkleTreeId.NULLIFIER_TREE) {
|
|
417
|
+
return NullifierLeaf.fromBuffer(leaf);
|
|
418
|
+
} else if (treeId === MerkleTreeId.PUBLIC_DATA_TREE) {
|
|
419
|
+
return PublicDataTreeLeaf.fromBuffer(leaf);
|
|
420
|
+
} else {
|
|
421
|
+
return Fr.fromBuffer(leaf);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function serializeLeaf(leaf: Fr | NullifierLeaf | PublicDataTreeLeaf): SerializedLeafValue {
|
|
426
|
+
if (leaf instanceof Fr) {
|
|
427
|
+
return leaf.toBuffer();
|
|
428
|
+
} else if (leaf instanceof NullifierLeaf) {
|
|
429
|
+
return { value: leaf.nullifier.toBuffer() };
|
|
430
|
+
} else {
|
|
431
|
+
return { value: leaf.value.toBuffer(), slot: leaf.slot.toBuffer() };
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function deserializeLeafValue(leaf: SerializedLeafValue): Fr | NullifierLeaf | PublicDataTreeLeaf {
|
|
436
|
+
if (Buffer.isBuffer(leaf)) {
|
|
437
|
+
return Fr.fromBuffer(leaf);
|
|
438
|
+
} else if ('slot' in leaf) {
|
|
439
|
+
return new PublicDataTreeLeaf(Fr.fromBuffer(leaf.slot), Fr.fromBuffer(leaf.value));
|
|
440
|
+
} else {
|
|
441
|
+
return new NullifierLeaf(Fr.fromBuffer(leaf.value));
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function deserializeIndexedLeaf(leaf: SerializedIndexedLeaf): IndexedTreeLeafPreimage {
|
|
446
|
+
if ('slot' in leaf.value) {
|
|
447
|
+
return new PublicDataTreeLeafPreimage(
|
|
448
|
+
Fr.fromBuffer(leaf.value.slot),
|
|
449
|
+
Fr.fromBuffer(leaf.value.value),
|
|
450
|
+
Fr.fromBuffer(leaf.nextValue),
|
|
451
|
+
BigInt(leaf.nextIndex),
|
|
452
|
+
);
|
|
453
|
+
} else if ('value' in leaf.value) {
|
|
454
|
+
return new NullifierLeafPreimage(
|
|
455
|
+
Fr.fromBuffer(leaf.value.value),
|
|
456
|
+
Fr.fromBuffer(leaf.nextValue),
|
|
457
|
+
BigInt(leaf.nextIndex),
|
|
458
|
+
);
|
|
459
|
+
} else {
|
|
460
|
+
throw new Error('Invalid leaf type');
|
|
461
|
+
}
|
|
462
|
+
}
|
|
@@ -17,12 +17,12 @@ import { type AztecKVStore, type AztecSingleton } from '@aztec/kv-store';
|
|
|
17
17
|
import { openTmpStore } from '@aztec/kv-store/utils';
|
|
18
18
|
import { SHA256Trunc, StandardTree } from '@aztec/merkle-tree';
|
|
19
19
|
|
|
20
|
-
import { type MerkleTrees } from '../world-state-db/index.js';
|
|
21
20
|
import {
|
|
22
21
|
MerkleTreeAdminOperationsFacade,
|
|
23
22
|
MerkleTreeOperationsFacade,
|
|
24
23
|
} from '../world-state-db/merkle_tree_operations_facade.js';
|
|
25
24
|
import { MerkleTreeSnapshotOperationsFacade } from '../world-state-db/merkle_tree_snapshot_operations_facade.js';
|
|
25
|
+
import { type MerkleTrees } from '../world-state-db/merkle_trees.js';
|
|
26
26
|
import { type WorldStateConfig } from './config.js';
|
|
27
27
|
import {
|
|
28
28
|
WorldStateRunningState,
|