@aztec/simulator 0.65.1 → 0.66.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/acvm/oracle/oracle.d.ts +0 -3
- package/dest/acvm/oracle/oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/oracle.js +1 -17
- package/dest/acvm/oracle/typed_oracle.d.ts +0 -5
- package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/typed_oracle.js +1 -10
- package/dest/avm/avm_memory_types.js +4 -4
- package/dest/avm/avm_simulator.d.ts.map +1 -1
- package/dest/avm/avm_simulator.js +5 -4
- package/dest/avm/avm_tree.d.ts +31 -14
- package/dest/avm/avm_tree.d.ts.map +1 -1
- package/dest/avm/avm_tree.js +34 -40
- package/dest/avm/journal/journal.d.ts.map +1 -1
- package/dest/avm/journal/journal.js +16 -10
- package/dest/avm/opcodes/environment_getters.d.ts +10 -11
- package/dest/avm/opcodes/environment_getters.d.ts.map +1 -1
- package/dest/avm/opcodes/environment_getters.js +12 -15
- package/dest/client/client_execution_context.d.ts +3 -30
- package/dest/client/client_execution_context.d.ts.map +1 -1
- package/dest/client/client_execution_context.js +5 -47
- package/dest/client/private_execution.d.ts.map +1 -1
- package/dest/client/private_execution.js +2 -4
- package/dest/public/enqueued_call_side_effect_trace.d.ts.map +1 -1
- package/dest/public/enqueued_call_side_effect_trace.js +15 -15
- package/dest/public/fixtures/index.d.ts +1 -6
- package/dest/public/fixtures/index.d.ts.map +1 -1
- package/dest/public/fixtures/index.js +24 -11
- package/dest/public/public_db_sources.d.ts.map +1 -1
- package/dest/public/public_db_sources.js +27 -13
- package/dest/public/public_processor.d.ts.map +1 -1
- package/dest/public/public_processor.js +8 -5
- package/dest/public/public_processor_metrics.d.ts +1 -1
- package/dest/public/public_processor_metrics.d.ts.map +1 -1
- package/dest/public/public_tx_context.d.ts +2 -6
- package/dest/public/public_tx_context.d.ts.map +1 -1
- package/dest/public/public_tx_context.js +23 -29
- package/dest/public/public_tx_simulator.d.ts.map +1 -1
- package/dest/public/public_tx_simulator.js +18 -5
- package/dest/public/side_effect_trace.js +8 -8
- package/dest/public/transitional_adapters.d.ts +2 -6
- package/dest/public/transitional_adapters.d.ts.map +1 -1
- package/dest/public/transitional_adapters.js +4 -67
- package/package.json +9 -9
- package/src/acvm/oracle/oracle.ts +0 -30
- package/src/acvm/oracle/typed_oracle.ts +0 -17
- package/src/avm/avm_memory_types.ts +4 -4
- package/src/avm/avm_simulator.ts +4 -3
- package/src/avm/avm_tree.ts +67 -53
- package/src/avm/journal/journal.ts +21 -9
- package/src/avm/opcodes/environment_getters.ts +1 -4
- package/src/client/client_execution_context.ts +5 -59
- package/src/client/private_execution.ts +0 -4
- package/src/public/enqueued_call_side_effect_trace.ts +14 -16
- package/src/public/fixtures/index.ts +30 -10
- package/src/public/public_db_sources.ts +29 -16
- package/src/public/public_processor.ts +6 -8
- package/src/public/public_processor_metrics.ts +1 -1
- package/src/public/public_tx_context.ts +37 -44
- package/src/public/public_tx_simulator.ts +19 -13
- package/src/public/side_effect_trace.ts +7 -7
- package/src/public/transitional_adapters.ts +6 -193
package/src/avm/avm_tree.ts
CHANGED
|
@@ -17,7 +17,14 @@ import cloneDeep from 'lodash.clonedeep';
|
|
|
17
17
|
type PreimageWitness<T extends IndexedTreeLeafPreimage> = {
|
|
18
18
|
preimage: T;
|
|
19
19
|
index: bigint;
|
|
20
|
-
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The result of fetching a leaf from an indexed tree. Contains the preimage and wether the leaf was already present
|
|
24
|
+
* or it's a low leaf.
|
|
25
|
+
*/
|
|
26
|
+
type GetLeafResult<T extends IndexedTreeLeafPreimage> = PreimageWitness<T> & {
|
|
27
|
+
alreadyPresent: boolean;
|
|
21
28
|
};
|
|
22
29
|
|
|
23
30
|
/**
|
|
@@ -29,16 +36,30 @@ type LeafWitness<T extends IndexedTreeLeafPreimage> = PreimageWitness<T> & {
|
|
|
29
36
|
};
|
|
30
37
|
|
|
31
38
|
/**
|
|
32
|
-
* The result of an
|
|
39
|
+
* The result of an update in an indexed merkle tree (no new leaf inserted)
|
|
40
|
+
*/
|
|
41
|
+
type IndexedUpdateResult<T extends IndexedTreeLeafPreimage> = {
|
|
42
|
+
element: T;
|
|
43
|
+
lowWitness: LeafWitness<T>;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The result of an insertion in an indexed merkle tree.
|
|
33
48
|
* This will be used to hint the circuit
|
|
34
49
|
*/
|
|
35
|
-
export type
|
|
50
|
+
export type IndexedInsertResult<T extends IndexedTreeLeafPreimage> = IndexedUpdateResult<T> & {
|
|
36
51
|
leafIndex: bigint;
|
|
37
52
|
insertionPath: Fr[];
|
|
38
|
-
newOrElementToUpdate: { update: boolean; element: T };
|
|
39
|
-
lowWitness: LeafWitness<T>;
|
|
40
53
|
};
|
|
41
54
|
|
|
55
|
+
/**
|
|
56
|
+
* The result of an indexed upsert in an indexed merkle tree.
|
|
57
|
+
* This will be used to hint the circuit
|
|
58
|
+
*/
|
|
59
|
+
export type IndexedUpsertResult<T extends IndexedTreeLeafPreimage> =
|
|
60
|
+
| (IndexedUpdateResult<T> & { update: true })
|
|
61
|
+
| (IndexedInsertResult<T> & { update: false });
|
|
62
|
+
|
|
42
63
|
/****************************************************/
|
|
43
64
|
/****** The AvmEphemeralForest Class ****************/
|
|
44
65
|
/****************************************************/
|
|
@@ -144,7 +165,7 @@ export class AvmEphemeralForest {
|
|
|
144
165
|
* @param newValue - The value to be written or updated to
|
|
145
166
|
* @returns The insertion result which contains the insertion path, low leaf and the new leaf index
|
|
146
167
|
*/
|
|
147
|
-
async writePublicStorage(slot: Fr, newValue: Fr): Promise<
|
|
168
|
+
async writePublicStorage(slot: Fr, newValue: Fr): Promise<IndexedUpsertResult<PublicDataTreeLeafPreimage>> {
|
|
148
169
|
// This only works for the public data tree
|
|
149
170
|
const treeId = MerkleTreeId.PUBLIC_DATA_TREE;
|
|
150
171
|
const tree = this.treeMap.get(treeId)!;
|
|
@@ -152,12 +173,12 @@ export class AvmEphemeralForest {
|
|
|
152
173
|
typeof treeId,
|
|
153
174
|
PublicDataTreeLeafPreimage
|
|
154
175
|
>(treeId, slot);
|
|
155
|
-
const { preimage, index, update } = leafOrLowLeafInfo;
|
|
156
|
-
const siblingPath = await this.getSiblingPath(treeId,
|
|
176
|
+
const { preimage, index: lowLeafIndex, alreadyPresent: update } = leafOrLowLeafInfo;
|
|
177
|
+
const siblingPath = await this.getSiblingPath(treeId, lowLeafIndex);
|
|
157
178
|
|
|
158
179
|
if (pathAbsentInEphemeralTree) {
|
|
159
180
|
// Since we have never seen this before - we should insert it into our tree as it is about to be updated.
|
|
160
|
-
this.treeMap.get(treeId)!.insertSiblingPath(
|
|
181
|
+
this.treeMap.get(treeId)!.insertSiblingPath(lowLeafIndex, siblingPath);
|
|
161
182
|
}
|
|
162
183
|
|
|
163
184
|
if (update) {
|
|
@@ -165,29 +186,18 @@ export class AvmEphemeralForest {
|
|
|
165
186
|
const existingPublicDataSiblingPath = siblingPath;
|
|
166
187
|
updatedPreimage.value = newValue;
|
|
167
188
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const insertionIndex = tree.leafCount;
|
|
172
|
-
tree.updateLeaf(this.hashPreimage(updatedPreimage), index);
|
|
173
|
-
tree.appendLeaf(Fr.ZERO);
|
|
174
|
-
this.setIndexedUpdates(treeId, index, updatedPreimage);
|
|
175
|
-
this.setIndexedUpdates(treeId, insertionIndex, emptyLeaf);
|
|
176
|
-
const insertionPath = tree.getSiblingPath(insertionIndex)!;
|
|
177
|
-
|
|
178
|
-
// Even though we append an empty leaf into the tree as a part of update - it doesnt seem to impact future inserts...
|
|
179
|
-
this._updateSortedKeys(treeId, [updatedPreimage.slot], [index]);
|
|
189
|
+
tree.updateLeaf(this.hashPreimage(updatedPreimage), lowLeafIndex);
|
|
190
|
+
this.setIndexedUpdates(treeId, lowLeafIndex, updatedPreimage);
|
|
191
|
+
this._updateSortedKeys(treeId, [updatedPreimage.slot], [lowLeafIndex]);
|
|
180
192
|
|
|
181
193
|
return {
|
|
182
|
-
|
|
183
|
-
insertionPath,
|
|
184
|
-
newOrElementToUpdate: { update: true, element: updatedPreimage },
|
|
194
|
+
element: updatedPreimage,
|
|
185
195
|
lowWitness: {
|
|
186
196
|
preimage: preimage,
|
|
187
|
-
index:
|
|
188
|
-
update: true,
|
|
197
|
+
index: lowLeafIndex,
|
|
189
198
|
siblingPath: existingPublicDataSiblingPath,
|
|
190
199
|
},
|
|
200
|
+
update: true,
|
|
191
201
|
};
|
|
192
202
|
}
|
|
193
203
|
// We are writing to a new slot, so our preimage is a lowNullifier
|
|
@@ -202,22 +212,22 @@ export class AvmEphemeralForest {
|
|
|
202
212
|
new Fr(preimage.getNextKey()),
|
|
203
213
|
preimage.getNextIndex(),
|
|
204
214
|
);
|
|
205
|
-
const insertionPath = this.appendIndexedTree(treeId,
|
|
215
|
+
const insertionPath = this.appendIndexedTree(treeId, lowLeafIndex, updatedLowLeaf, newPublicDataLeaf);
|
|
206
216
|
|
|
207
217
|
// Even though the low leaf key is not updated, we still need to update the sorted keys in case we have
|
|
208
218
|
// not seen the low leaf before
|
|
209
|
-
this._updateSortedKeys(treeId, [newPublicDataLeaf.slot, updatedLowLeaf.slot], [insertionIndex,
|
|
219
|
+
this._updateSortedKeys(treeId, [newPublicDataLeaf.slot, updatedLowLeaf.slot], [insertionIndex, lowLeafIndex]);
|
|
210
220
|
|
|
211
221
|
return {
|
|
212
|
-
|
|
213
|
-
insertionPath: insertionPath,
|
|
214
|
-
newOrElementToUpdate: { update: false, element: newPublicDataLeaf },
|
|
222
|
+
element: newPublicDataLeaf,
|
|
215
223
|
lowWitness: {
|
|
216
224
|
preimage,
|
|
217
|
-
index:
|
|
218
|
-
update: false,
|
|
225
|
+
index: lowLeafIndex,
|
|
219
226
|
siblingPath,
|
|
220
227
|
},
|
|
228
|
+
update: false,
|
|
229
|
+
leafIndex: insertionIndex,
|
|
230
|
+
insertionPath: insertionPath,
|
|
221
231
|
};
|
|
222
232
|
}
|
|
223
233
|
|
|
@@ -247,14 +257,14 @@ export class AvmEphemeralForest {
|
|
|
247
257
|
* @param value - The nullifier to be appended
|
|
248
258
|
* @returns The insertion result which contains the insertion path, low leaf and the new leaf index
|
|
249
259
|
*/
|
|
250
|
-
async appendNullifier(nullifier: Fr): Promise<
|
|
260
|
+
async appendNullifier(nullifier: Fr): Promise<IndexedInsertResult<NullifierLeafPreimage>> {
|
|
251
261
|
const treeId = MerkleTreeId.NULLIFIER_TREE;
|
|
252
262
|
const tree = this.treeMap.get(treeId)!;
|
|
253
263
|
const [leafOrLowLeafInfo, pathAbsentInEphemeralTree] = await this._getLeafOrLowLeafInfo<
|
|
254
264
|
typeof treeId,
|
|
255
265
|
NullifierLeafPreimage
|
|
256
266
|
>(treeId, nullifier);
|
|
257
|
-
const { preimage, index,
|
|
267
|
+
const { preimage, index, alreadyPresent } = leafOrLowLeafInfo;
|
|
258
268
|
const siblingPath = await this.getSiblingPath(treeId, index);
|
|
259
269
|
|
|
260
270
|
if (pathAbsentInEphemeralTree) {
|
|
@@ -262,7 +272,7 @@ export class AvmEphemeralForest {
|
|
|
262
272
|
this.treeMap.get(treeId)!.insertSiblingPath(index, siblingPath);
|
|
263
273
|
}
|
|
264
274
|
|
|
265
|
-
assert(!
|
|
275
|
+
assert(!alreadyPresent, 'Nullifier already exists in the tree. Cannot update a nullifier!');
|
|
266
276
|
|
|
267
277
|
// We are writing a new entry
|
|
268
278
|
const insertionIndex = tree.leafCount;
|
|
@@ -282,15 +292,14 @@ export class AvmEphemeralForest {
|
|
|
282
292
|
);
|
|
283
293
|
|
|
284
294
|
return {
|
|
285
|
-
|
|
286
|
-
insertionPath: insertionPath,
|
|
287
|
-
newOrElementToUpdate: { update: false, element: newNullifierLeaf },
|
|
295
|
+
element: newNullifierLeaf,
|
|
288
296
|
lowWitness: {
|
|
289
297
|
preimage,
|
|
290
298
|
index,
|
|
291
|
-
update,
|
|
292
299
|
siblingPath,
|
|
293
300
|
},
|
|
301
|
+
leafIndex: insertionIndex,
|
|
302
|
+
insertionPath: insertionPath,
|
|
294
303
|
};
|
|
295
304
|
}
|
|
296
305
|
|
|
@@ -360,7 +369,7 @@ export class AvmEphemeralForest {
|
|
|
360
369
|
async getLeafOrLowLeafInfo<ID extends IndexedTreeId, T extends IndexedTreeLeafPreimage>(
|
|
361
370
|
treeId: ID,
|
|
362
371
|
key: Fr,
|
|
363
|
-
): Promise<
|
|
372
|
+
): Promise<GetLeafResult<T>> {
|
|
364
373
|
const [leafOrLowLeafInfo, _] = await this._getLeafOrLowLeafInfo<ID, T>(treeId, key);
|
|
365
374
|
return leafOrLowLeafInfo;
|
|
366
375
|
}
|
|
@@ -373,14 +382,14 @@ export class AvmEphemeralForest {
|
|
|
373
382
|
* @param key - The key for which we are look up the leaf or low leaf for.
|
|
374
383
|
* @param T - The type of the preimage (PublicData or Nullifier)
|
|
375
384
|
* @returns [
|
|
376
|
-
*
|
|
385
|
+
* getLeafResult - The leaf or low leaf info (preimage & leaf index),
|
|
377
386
|
* pathAbsentInEphemeralTree - whether its sibling path is absent in the ephemeral tree (useful during insertions)
|
|
378
387
|
* ]
|
|
379
388
|
*/
|
|
380
389
|
async _getLeafOrLowLeafInfo<ID extends IndexedTreeId, T extends IndexedTreeLeafPreimage>(
|
|
381
390
|
treeId: ID,
|
|
382
391
|
key: Fr,
|
|
383
|
-
): Promise<[
|
|
392
|
+
): Promise<[GetLeafResult<T>, /*pathAbsentInEphemeralTree=*/ boolean]> {
|
|
384
393
|
const bigIntKey = key.toBigInt();
|
|
385
394
|
// In this function, "min" refers to the leaf with the
|
|
386
395
|
// largest key <= the specified key in the indexedUpdates.
|
|
@@ -392,7 +401,7 @@ export class AvmEphemeralForest {
|
|
|
392
401
|
if (minIndexedLeafIndex === -1n) {
|
|
393
402
|
// No leaf is present in the indexed updates that is <= the key,
|
|
394
403
|
// so retrieve the leaf or low leaf from the underlying DB.
|
|
395
|
-
const leafOrLowLeafPreimage:
|
|
404
|
+
const leafOrLowLeafPreimage: GetLeafResult<T> = await this._getLeafOrLowLeafWitnessInExternalDb(
|
|
396
405
|
treeId,
|
|
397
406
|
bigIntKey,
|
|
398
407
|
);
|
|
@@ -402,7 +411,7 @@ export class AvmEphemeralForest {
|
|
|
402
411
|
const minPreimage: T = this.getIndexedUpdate(treeId, minIndexedLeafIndex);
|
|
403
412
|
if (minPreimage.getKey() === bigIntKey) {
|
|
404
413
|
// the index found is an exact match, no need to search further
|
|
405
|
-
const leafInfo = { preimage: minPreimage, index: minIndexedLeafIndex,
|
|
414
|
+
const leafInfo = { preimage: minPreimage, index: minIndexedLeafIndex, alreadyPresent: true };
|
|
406
415
|
return [leafInfo, /*pathAbsentInEphemeralTree=*/ false];
|
|
407
416
|
} else {
|
|
408
417
|
// We are starting with the leaf with largest key <= the specified key
|
|
@@ -453,7 +462,7 @@ export class AvmEphemeralForest {
|
|
|
453
462
|
private async _getLeafOrLowLeafWitnessInExternalDb<ID extends IndexedTreeId, T extends IndexedTreeLeafPreimage>(
|
|
454
463
|
treeId: ID,
|
|
455
464
|
key: bigint,
|
|
456
|
-
): Promise<
|
|
465
|
+
): Promise<GetLeafResult<T>> {
|
|
457
466
|
// "key" is siloed slot (leafSlot) or siloed nullifier
|
|
458
467
|
const previousValueIndex = await this.treeDb.getPreviousValueIndex(treeId, key);
|
|
459
468
|
assert(
|
|
@@ -468,7 +477,7 @@ export class AvmEphemeralForest {
|
|
|
468
477
|
`${MerkleTreeId[treeId]} low leaf preimage should never be undefined (even if target leaf does not exist)`,
|
|
469
478
|
);
|
|
470
479
|
|
|
471
|
-
return { preimage: leafPreimage as T, index: leafIndex,
|
|
480
|
+
return { preimage: leafPreimage as T, index: leafIndex, alreadyPresent };
|
|
472
481
|
}
|
|
473
482
|
|
|
474
483
|
/**
|
|
@@ -481,7 +490,7 @@ export class AvmEphemeralForest {
|
|
|
481
490
|
* @param minIndex - The index of the leaf with the largest key <= the specified key.
|
|
482
491
|
* @param T - The type of the preimage (PublicData or Nullifier)
|
|
483
492
|
* @returns [
|
|
484
|
-
*
|
|
493
|
+
* GetLeafResult | undefined - The leaf or low leaf info (preimage & leaf index),
|
|
485
494
|
* pathAbsentInEphemeralTree - whether its sibling path is absent in the ephemeral tree (useful during insertions)
|
|
486
495
|
* ]
|
|
487
496
|
*
|
|
@@ -497,10 +506,10 @@ export class AvmEphemeralForest {
|
|
|
497
506
|
key: bigint,
|
|
498
507
|
minPreimage: T,
|
|
499
508
|
minIndex: bigint,
|
|
500
|
-
): Promise<[
|
|
509
|
+
): Promise<[GetLeafResult<T> | undefined, /*pathAbsentInEphemeralTree=*/ boolean]> {
|
|
501
510
|
let found = false;
|
|
502
511
|
let curr = minPreimage as T;
|
|
503
|
-
let result:
|
|
512
|
+
let result: GetLeafResult<T> | undefined = undefined;
|
|
504
513
|
// Temp to avoid infinite loops - the limit is the number of leaves we may have to read
|
|
505
514
|
const LIMIT = 2n ** BigInt(getTreeHeight(treeId)) - 1n;
|
|
506
515
|
let counter = 0n;
|
|
@@ -511,11 +520,11 @@ export class AvmEphemeralForest {
|
|
|
511
520
|
if (curr.getKey() === bigIntKey) {
|
|
512
521
|
// We found an exact match - therefore this is an update
|
|
513
522
|
found = true;
|
|
514
|
-
result = { preimage: curr, index: lowPublicDataIndex,
|
|
523
|
+
result = { preimage: curr, index: lowPublicDataIndex, alreadyPresent: true };
|
|
515
524
|
} else if (curr.getKey() < bigIntKey && (curr.getNextIndex() === 0n || curr.getNextKey() > bigIntKey)) {
|
|
516
525
|
// We found it via sandwich or max condition, this is a low nullifier
|
|
517
526
|
found = true;
|
|
518
|
-
result = { preimage: curr, index: lowPublicDataIndex,
|
|
527
|
+
result = { preimage: curr, index: lowPublicDataIndex, alreadyPresent: false };
|
|
519
528
|
}
|
|
520
529
|
// Update the the values for the next iteration
|
|
521
530
|
else {
|
|
@@ -671,7 +680,12 @@ export class EphemeralAvmTree {
|
|
|
671
680
|
for (let i = 0; i < siblingPath.length; i++) {
|
|
672
681
|
// Flip(XOR) the last bit because we are inserting siblings of the leaf
|
|
673
682
|
const sibIndex = index ^ 1n;
|
|
674
|
-
this.
|
|
683
|
+
const node = this.getNode(sibIndex, this.depth - i);
|
|
684
|
+
// If we are inserting a sibling path and we already have a branch at that index in our
|
|
685
|
+
// ephemeral tree, we should not overwrite it
|
|
686
|
+
if (node === undefined || node.tag === TreeType.LEAF) {
|
|
687
|
+
this.updateLeaf(siblingPath[i], sibIndex, this.depth - i);
|
|
688
|
+
}
|
|
675
689
|
index >>= 1n;
|
|
676
690
|
}
|
|
677
691
|
}
|
|
@@ -163,8 +163,12 @@ export class AvmPersistableStateManager {
|
|
|
163
163
|
const lowLeafIndex = lowLeafInfo.index;
|
|
164
164
|
const lowLeafPath = lowLeafInfo.siblingPath;
|
|
165
165
|
|
|
166
|
-
const
|
|
167
|
-
|
|
166
|
+
const newLeafPreimage = result.element as PublicDataTreeLeafPreimage;
|
|
167
|
+
let insertionPath;
|
|
168
|
+
|
|
169
|
+
if (!result.update) {
|
|
170
|
+
insertionPath = result.insertionPath;
|
|
171
|
+
}
|
|
168
172
|
|
|
169
173
|
this.trace.tracePublicStorageWrite(
|
|
170
174
|
contractAddress,
|
|
@@ -200,7 +204,7 @@ export class AvmPersistableStateManager {
|
|
|
200
204
|
const {
|
|
201
205
|
preimage,
|
|
202
206
|
index: leafIndex,
|
|
203
|
-
|
|
207
|
+
alreadyPresent,
|
|
204
208
|
} = await this.merkleTrees.getLeafOrLowLeafInfo(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot);
|
|
205
209
|
// The index and preimage here is either the low leaf or the leaf itself (depending on the value of update flag)
|
|
206
210
|
// In either case, we just want the sibling path to this leaf - it's up to the avm to distinguish if it's a low leaf or not
|
|
@@ -212,7 +216,7 @@ export class AvmPersistableStateManager {
|
|
|
212
216
|
);
|
|
213
217
|
this.log.debug(`leafPreimage.slot: ${leafPreimage.slot}, leafPreimage.value: ${leafPreimage.value}`);
|
|
214
218
|
|
|
215
|
-
if (!
|
|
219
|
+
if (!alreadyPresent) {
|
|
216
220
|
// Sanity check that the leaf slot is skipped by low leaf when it doesn't exist
|
|
217
221
|
assert(
|
|
218
222
|
leafPreimage.slot.toBigInt() < leafSlot.toBigInt() &&
|
|
@@ -308,12 +312,15 @@ export class AvmPersistableStateManager {
|
|
|
308
312
|
const {
|
|
309
313
|
preimage,
|
|
310
314
|
index: leafIndex,
|
|
311
|
-
|
|
315
|
+
alreadyPresent,
|
|
312
316
|
} = await this.merkleTrees.getLeafOrLowLeafInfo(MerkleTreeId.NULLIFIER_TREE, siloedNullifier);
|
|
313
317
|
const leafPreimage = preimage as NullifierLeafPreimage;
|
|
314
318
|
const leafPath = await this.merkleTrees.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, leafIndex);
|
|
315
319
|
|
|
316
|
-
assert(
|
|
320
|
+
assert(
|
|
321
|
+
alreadyPresent == exists,
|
|
322
|
+
'WorldStateDB contains nullifier leaf, but merkle tree does not.... This is a bug!',
|
|
323
|
+
);
|
|
317
324
|
|
|
318
325
|
if (exists) {
|
|
319
326
|
this.log.debug(`Siloed nullifier ${siloedNullifier} exists at leafIndex=${leafIndex}`);
|
|
@@ -355,11 +362,11 @@ export class AvmPersistableStateManager {
|
|
|
355
362
|
// Maybe overkill, but we should check if the nullifier is already present in the tree before attempting to insert
|
|
356
363
|
// It might be better to catch the error from the insert operation
|
|
357
364
|
// Trace all nullifier creations, even duplicate insertions that fail
|
|
358
|
-
const { preimage, index,
|
|
365
|
+
const { preimage, index, alreadyPresent } = await this.merkleTrees.getLeafOrLowLeafInfo(
|
|
359
366
|
MerkleTreeId.NULLIFIER_TREE,
|
|
360
367
|
siloedNullifier,
|
|
361
368
|
);
|
|
362
|
-
if (
|
|
369
|
+
if (alreadyPresent) {
|
|
363
370
|
this.log.verbose(`Siloed nullifier ${siloedNullifier} already present in tree at index ${index}!`);
|
|
364
371
|
// If the nullifier is already present, we should not insert it again
|
|
365
372
|
// instead we provide the direct membership path
|
|
@@ -367,7 +374,7 @@ export class AvmPersistableStateManager {
|
|
|
367
374
|
// This just becomes a nullifier read hint
|
|
368
375
|
this.trace.traceNullifierCheck(
|
|
369
376
|
siloedNullifier,
|
|
370
|
-
/*exists=*/
|
|
377
|
+
/*exists=*/ alreadyPresent,
|
|
371
378
|
preimage as NullifierLeafPreimage,
|
|
372
379
|
new Fr(index),
|
|
373
380
|
path,
|
|
@@ -379,6 +386,11 @@ export class AvmPersistableStateManager {
|
|
|
379
386
|
// Cache pending nullifiers for later access
|
|
380
387
|
await this.nullifiers.append(siloedNullifier);
|
|
381
388
|
// We append the new nullifier
|
|
389
|
+
this.log.debug(
|
|
390
|
+
`Nullifier tree root before insertion ${this.merkleTrees.treeMap
|
|
391
|
+
.get(MerkleTreeId.NULLIFIER_TREE)!
|
|
392
|
+
.getRoot()}`,
|
|
393
|
+
);
|
|
382
394
|
const appendResult = await this.merkleTrees.appendNullifier(siloedNullifier);
|
|
383
395
|
this.log.debug(
|
|
384
396
|
`Nullifier tree root after insertion ${this.merkleTrees.treeMap.get(MerkleTreeId.NULLIFIER_TREE)!.getRoot()}`,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AvmContext } from '../avm_context.js';
|
|
2
|
-
import { Field,
|
|
2
|
+
import { Field, Uint64 } from '../avm_memory_types.js';
|
|
3
3
|
import { InstructionExecutionError } from '../errors.js';
|
|
4
4
|
import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
|
|
5
5
|
import { Addressing } from './addressing_mode.js';
|
|
@@ -8,7 +8,6 @@ import { Instruction } from './instruction.js';
|
|
|
8
8
|
export enum EnvironmentVariable {
|
|
9
9
|
ADDRESS,
|
|
10
10
|
SENDER,
|
|
11
|
-
FUNCTIONSELECTOR,
|
|
12
11
|
TRANSACTIONFEE,
|
|
13
12
|
CHAINID,
|
|
14
13
|
VERSION,
|
|
@@ -27,8 +26,6 @@ function getValue(e: EnvironmentVariable, ctx: AvmContext) {
|
|
|
27
26
|
return new Field(ctx.environment.address.toField());
|
|
28
27
|
case EnvironmentVariable.SENDER:
|
|
29
28
|
return new Field(ctx.environment.sender.toField());
|
|
30
|
-
case EnvironmentVariable.FUNCTIONSELECTOR:
|
|
31
|
-
return new Uint32(ctx.environment.functionSelector.value);
|
|
32
29
|
case EnvironmentVariable.TRANSACTIONFEE:
|
|
33
30
|
return new Field(ctx.environment.transactionFee);
|
|
34
31
|
case EnvironmentVariable.CHAINID:
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type AuthWitness,
|
|
3
3
|
type AztecNode,
|
|
4
|
-
|
|
5
|
-
CountedNoteLog,
|
|
4
|
+
CountedContractClassLog,
|
|
6
5
|
CountedPublicExecutionRequest,
|
|
7
|
-
EncryptedL2Log,
|
|
8
|
-
EncryptedL2NoteLog,
|
|
9
6
|
Note,
|
|
10
7
|
NoteAndSlot,
|
|
11
8
|
type NoteStatus,
|
|
@@ -25,7 +22,6 @@ import {
|
|
|
25
22
|
import { computeUniqueNoteHash, siloNoteHash } from '@aztec/circuits.js/hash';
|
|
26
23
|
import { type FunctionAbi, type FunctionArtifact, type NoteSelector, countArgumentsSize } from '@aztec/foundation/abi';
|
|
27
24
|
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
28
|
-
import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto';
|
|
29
25
|
import { Fr } from '@aztec/foundation/fields';
|
|
30
26
|
import { applyStringFormatting, createDebugLogger } from '@aztec/foundation/log';
|
|
31
27
|
|
|
@@ -60,9 +56,7 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
60
56
|
*/
|
|
61
57
|
private noteHashLeafIndexMap: Map<bigint, bigint> = new Map();
|
|
62
58
|
private noteHashNullifierCounterMap: Map<number, number> = new Map();
|
|
63
|
-
private
|
|
64
|
-
private encryptedLogs: CountedLog<EncryptedL2Log>[] = [];
|
|
65
|
-
private contractClassLogs: CountedLog<UnencryptedL2Log>[] = [];
|
|
59
|
+
private contractClassLogs: CountedContractClassLog[] = [];
|
|
66
60
|
private nestedExecutions: PrivateExecutionResult[] = [];
|
|
67
61
|
private enqueuedPublicFunctionCalls: CountedPublicExecutionRequest[] = [];
|
|
68
62
|
private publicTeardownFunctionCall: PublicExecutionRequest = PublicExecutionRequest.empty();
|
|
@@ -136,20 +130,6 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
136
130
|
return this.noteHashNullifierCounterMap;
|
|
137
131
|
}
|
|
138
132
|
|
|
139
|
-
/**
|
|
140
|
-
* Return the note encrypted logs emitted during this execution.
|
|
141
|
-
*/
|
|
142
|
-
public getNoteEncryptedLogs() {
|
|
143
|
-
return this.noteEncryptedLogs;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Return the encrypted logs emitted during this execution.
|
|
148
|
-
*/
|
|
149
|
-
public getEncryptedLogs() {
|
|
150
|
-
return this.encryptedLogs;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
133
|
/**
|
|
154
134
|
* Return the contract class logs emitted during this execution.
|
|
155
135
|
*/
|
|
@@ -326,49 +306,15 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
326
306
|
return Promise.resolve();
|
|
327
307
|
}
|
|
328
308
|
|
|
329
|
-
/**
|
|
330
|
-
* Emit encrypted data
|
|
331
|
-
* @param contractAddress - The contract emitting the encrypted event.
|
|
332
|
-
* @param randomness - A value used to mask the contract address we are siloing with.
|
|
333
|
-
* @param encryptedEvent - The encrypted event data.
|
|
334
|
-
* @param counter - The effects counter.
|
|
335
|
-
*/
|
|
336
|
-
public override emitEncryptedEventLog(
|
|
337
|
-
contractAddress: AztecAddress,
|
|
338
|
-
randomness: Fr,
|
|
339
|
-
encryptedEvent: Buffer,
|
|
340
|
-
counter: number,
|
|
341
|
-
) {
|
|
342
|
-
// In some cases, we actually want to reveal the contract address we are siloing with:
|
|
343
|
-
// e.g. 'handshaking' contract w/ known address
|
|
344
|
-
// An app providing randomness = 0 signals to not mask the address.
|
|
345
|
-
const maskedContractAddress = randomness.isZero()
|
|
346
|
-
? contractAddress.toField()
|
|
347
|
-
: poseidon2HashWithSeparator([contractAddress, randomness], 0);
|
|
348
|
-
const encryptedLog = new CountedLog(new EncryptedL2Log(encryptedEvent, maskedContractAddress), counter);
|
|
349
|
-
this.encryptedLogs.push(encryptedLog);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Emit encrypted note data
|
|
354
|
-
* @param noteHashCounter - The note hash counter.
|
|
355
|
-
* @param encryptedNote - The encrypted note data.
|
|
356
|
-
* @param counter - The log counter.
|
|
357
|
-
*/
|
|
358
|
-
public override emitEncryptedNoteLog(noteHashCounter: number, encryptedNote: Buffer, counter: number) {
|
|
359
|
-
const encryptedLog = new CountedNoteLog(new EncryptedL2NoteLog(encryptedNote), counter, noteHashCounter);
|
|
360
|
-
this.noteEncryptedLogs.push(encryptedLog);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
309
|
/**
|
|
364
310
|
* Emit a contract class unencrypted log.
|
|
365
|
-
* This fn exists
|
|
311
|
+
* This fn exists because sha hashing the preimage
|
|
366
312
|
* is too large to compile (16,200 fields, 518,400 bytes) => the oracle hashes it.
|
|
367
313
|
* See private_context.nr
|
|
368
314
|
* @param log - The unencrypted log to be emitted.
|
|
369
315
|
*/
|
|
370
316
|
public override emitContractClassLog(log: UnencryptedL2Log, counter: number) {
|
|
371
|
-
this.contractClassLogs.push(new
|
|
317
|
+
this.contractClassLogs.push(new CountedContractClassLog(log, counter));
|
|
372
318
|
const text = log.toHumanReadable();
|
|
373
319
|
this.log.verbose(
|
|
374
320
|
`Emitted log from ContractClassRegisterer: "${text.length > 100 ? text.slice(0, 100) + '...' : text}"`,
|
|
@@ -381,7 +327,7 @@ export class ClientExecutionContext extends ViewDataOracle {
|
|
|
381
327
|
childExecutionResult.publicInputs.noteHashes.some(item => !item.isEmpty()) ||
|
|
382
328
|
childExecutionResult.publicInputs.nullifiers.some(item => !item.isEmpty()) ||
|
|
383
329
|
childExecutionResult.publicInputs.l2ToL1Msgs.some(item => !item.isEmpty()) ||
|
|
384
|
-
childExecutionResult.publicInputs.
|
|
330
|
+
childExecutionResult.publicInputs.privateLogs.some(item => !item.isEmpty()) ||
|
|
385
331
|
childExecutionResult.publicInputs.contractClassLogsHashes.some(item => !item.isEmpty())
|
|
386
332
|
) {
|
|
387
333
|
throw new Error(`Static call cannot update the state, emit L2->L1 messages or generate logs`);
|
|
@@ -59,8 +59,6 @@ export async function executePrivateFunction(
|
|
|
59
59
|
appCircuitName: functionName,
|
|
60
60
|
} satisfies CircuitWitnessGenerationStats);
|
|
61
61
|
|
|
62
|
-
const noteEncryptedLogs = context.getNoteEncryptedLogs();
|
|
63
|
-
const encryptedLogs = context.getEncryptedLogs();
|
|
64
62
|
const contractClassLogs = context.getContractClassLogs();
|
|
65
63
|
|
|
66
64
|
const rawReturnValues = await context.unpackReturns(publicInputs.returnsHash);
|
|
@@ -86,8 +84,6 @@ export async function executePrivateFunction(
|
|
|
86
84
|
nestedExecutions,
|
|
87
85
|
enqueuedPublicFunctionCalls,
|
|
88
86
|
publicTeardownFunctionCall,
|
|
89
|
-
noteEncryptedLogs,
|
|
90
|
-
encryptedLogs,
|
|
91
87
|
contractClassLogs,
|
|
92
88
|
);
|
|
93
89
|
}
|
|
@@ -179,15 +179,13 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
|
|
|
179
179
|
this.avmCircuitHints.contractInstances.items.push(...forkedTrace.avmCircuitHints.contractInstances.items);
|
|
180
180
|
this.avmCircuitHints.contractBytecodeHints.items.push(...forkedTrace.avmCircuitHints.contractBytecodeHints.items);
|
|
181
181
|
|
|
182
|
-
this.avmCircuitHints.
|
|
183
|
-
this.avmCircuitHints.
|
|
184
|
-
this.avmCircuitHints.
|
|
185
|
-
this.avmCircuitHints.
|
|
186
|
-
this.avmCircuitHints.
|
|
187
|
-
this.avmCircuitHints.
|
|
188
|
-
this.avmCircuitHints.
|
|
189
|
-
...forkedTrace.avmCircuitHints.l1ToL2MessageReadRequest.items,
|
|
190
|
-
);
|
|
182
|
+
this.avmCircuitHints.publicDataReads.items.push(...forkedTrace.avmCircuitHints.publicDataReads.items);
|
|
183
|
+
this.avmCircuitHints.publicDataWrites.items.push(...forkedTrace.avmCircuitHints.publicDataWrites.items);
|
|
184
|
+
this.avmCircuitHints.nullifierReads.items.push(...forkedTrace.avmCircuitHints.nullifierReads.items);
|
|
185
|
+
this.avmCircuitHints.nullifierWrites.items.push(...forkedTrace.avmCircuitHints.nullifierWrites.items);
|
|
186
|
+
this.avmCircuitHints.noteHashReads.items.push(...forkedTrace.avmCircuitHints.noteHashReads.items);
|
|
187
|
+
this.avmCircuitHints.noteHashWrites.items.push(...forkedTrace.avmCircuitHints.noteHashWrites.items);
|
|
188
|
+
this.avmCircuitHints.l1ToL2MessageReads.items.push(...forkedTrace.avmCircuitHints.l1ToL2MessageReads.items);
|
|
191
189
|
}
|
|
192
190
|
|
|
193
191
|
public getCounter() {
|
|
@@ -211,7 +209,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
|
|
|
211
209
|
assert(leafPreimage.value.equals(value), 'Value mismatch when tracing in public data write');
|
|
212
210
|
}
|
|
213
211
|
|
|
214
|
-
this.avmCircuitHints.
|
|
212
|
+
this.avmCircuitHints.publicDataReads.items.push(new AvmPublicDataReadTreeHint(leafPreimage, leafIndex, path));
|
|
215
213
|
this.log.debug(`SLOAD cnt: ${this.sideEffectCounter} val: ${value} slot: ${slot}`);
|
|
216
214
|
this.incrementSideEffectCounter();
|
|
217
215
|
}
|
|
@@ -245,7 +243,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
|
|
|
245
243
|
|
|
246
244
|
// New hinting
|
|
247
245
|
const readHint = new AvmPublicDataReadTreeHint(lowLeafPreimage, lowLeafIndex, lowLeafPath);
|
|
248
|
-
this.avmCircuitHints.
|
|
246
|
+
this.avmCircuitHints.publicDataWrites.items.push(
|
|
249
247
|
new AvmPublicDataWriteTreeHint(readHint, newLeafPreimage, insertionPath),
|
|
250
248
|
);
|
|
251
249
|
|
|
@@ -264,7 +262,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
|
|
|
264
262
|
path: Fr[] = emptyNoteHashPath(),
|
|
265
263
|
) {
|
|
266
264
|
// New Hinting
|
|
267
|
-
this.avmCircuitHints.
|
|
265
|
+
this.avmCircuitHints.noteHashReads.items.push(new AvmAppendTreeHint(leafIndex, noteHash, path));
|
|
268
266
|
// NOTE: counter does not increment for note hash checks (because it doesn't rely on pending note hashes)
|
|
269
267
|
}
|
|
270
268
|
|
|
@@ -282,7 +280,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
|
|
|
282
280
|
//const siloedNoteHash = siloNoteHash(contractAddress, noteHash);
|
|
283
281
|
this.noteHashes.push(new NoteHash(noteHash, this.sideEffectCounter).scope(contractAddress));
|
|
284
282
|
this.log.debug(`NEW_NOTE_HASH cnt: ${this.sideEffectCounter}`);
|
|
285
|
-
this.avmCircuitHints.
|
|
283
|
+
this.avmCircuitHints.noteHashWrites.items.push(new AvmAppendTreeHint(leafIndex, noteHash, path));
|
|
286
284
|
this.incrementSideEffectCounter();
|
|
287
285
|
}
|
|
288
286
|
|
|
@@ -293,7 +291,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
|
|
|
293
291
|
lowLeafIndex: Fr = Fr.zero(),
|
|
294
292
|
lowLeafPath: Fr[] = emptyNullifierPath(),
|
|
295
293
|
) {
|
|
296
|
-
this.avmCircuitHints.
|
|
294
|
+
this.avmCircuitHints.nullifierReads.items.push(
|
|
297
295
|
new AvmNullifierReadTreeHint(lowLeafPreimage, lowLeafIndex, lowLeafPath),
|
|
298
296
|
);
|
|
299
297
|
this.log.debug(`NULLIFIER_EXISTS cnt: ${this.sideEffectCounter}`);
|
|
@@ -314,7 +312,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
|
|
|
314
312
|
this.nullifiers.push(new Nullifier(siloedNullifier, this.sideEffectCounter, /*noteHash=*/ Fr.ZERO));
|
|
315
313
|
|
|
316
314
|
const lowLeafReadHint = new AvmNullifierReadTreeHint(lowLeafPreimage, lowLeafIndex, lowLeafPath);
|
|
317
|
-
this.avmCircuitHints.
|
|
315
|
+
this.avmCircuitHints.nullifierWrites.items.push(new AvmNullifierWriteTreeHint(lowLeafReadHint, insertionPath));
|
|
318
316
|
this.log.debug(`NEW_NULLIFIER cnt: ${this.sideEffectCounter}`);
|
|
319
317
|
this.incrementSideEffectCounter();
|
|
320
318
|
}
|
|
@@ -327,7 +325,7 @@ export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceI
|
|
|
327
325
|
_exists: boolean,
|
|
328
326
|
path: Fr[] = emptyL1ToL2MessagePath(),
|
|
329
327
|
) {
|
|
330
|
-
this.avmCircuitHints.
|
|
328
|
+
this.avmCircuitHints.l1ToL2MessageReads.items.push(new AvmAppendTreeHint(msgLeafIndex, msgHash, path));
|
|
331
329
|
}
|
|
332
330
|
|
|
333
331
|
public traceNewL2ToL1Message(contractAddress: AztecAddress, recipient: Fr, content: Fr) {
|