@aztec/pxe 0.69.1 → 0.71.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/config/index.d.ts.map +1 -1
- package/dest/config/index.js +3 -3
- package/dest/database/kv_pxe_database.d.ts +6 -0
- package/dest/database/kv_pxe_database.d.ts.map +1 -1
- package/dest/database/kv_pxe_database.js +48 -3
- package/dest/database/note_dao.d.ts +2 -4
- package/dest/database/note_dao.d.ts.map +1 -1
- package/dest/database/note_dao.js +1 -5
- package/dest/database/outgoing_note_dao.d.ts +1 -3
- package/dest/database/outgoing_note_dao.d.ts.map +1 -1
- package/dest/database/outgoing_note_dao.js +1 -5
- package/dest/database/pxe_database.d.ts +33 -0
- package/dest/database/pxe_database.d.ts.map +1 -1
- package/dest/database/pxe_database_test_suite.d.ts.map +1 -1
- package/dest/database/pxe_database_test_suite.js +121 -1
- package/dest/kernel_oracle/index.js +2 -2
- package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.d.ts +2 -2
- package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.d.ts.map +1 -1
- package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.js +1 -1
- package/dest/kernel_prover/index.d.ts +0 -1
- package/dest/kernel_prover/index.d.ts.map +1 -1
- package/dest/kernel_prover/index.js +1 -2
- package/dest/kernel_prover/kernel_prover.d.ts +8 -2
- package/dest/kernel_prover/kernel_prover.d.ts.map +1 -1
- package/dest/kernel_prover/kernel_prover.js +42 -18
- package/dest/note_decryption_utils/add_public_values_to_payload.js +2 -2
- package/dest/pxe_service/error_enriching.js +1 -1
- package/dest/pxe_service/pxe_service.d.ts +5 -1
- package/dest/pxe_service/pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/pxe_service.js +30 -31
- package/dest/simulator/index.d.ts +2 -2
- package/dest/simulator/index.d.ts.map +1 -1
- package/dest/simulator/index.js +4 -4
- package/dest/simulator_oracle/index.d.ts +16 -9
- package/dest/simulator_oracle/index.d.ts.map +1 -1
- package/dest/simulator_oracle/index.js +131 -63
- package/dest/utils/create_pxe_service.d.ts.map +1 -1
- package/dest/utils/create_pxe_service.js +9 -12
- package/package.json +14 -15
- package/src/config/index.ts +2 -1
- package/src/database/kv_pxe_database.ts +62 -0
- package/src/database/note_dao.ts +2 -30
- package/src/database/outgoing_note_dao.ts +1 -28
- package/src/database/pxe_database.ts +37 -0
- package/src/database/pxe_database_test_suite.ts +160 -0
- package/src/kernel_oracle/index.ts +1 -1
- package/src/kernel_prover/hints/build_private_kernel_reset_private_inputs.ts +4 -4
- package/src/kernel_prover/index.ts +0 -2
- package/src/kernel_prover/kernel_prover.ts +58 -20
- package/src/note_decryption_utils/add_public_values_to_payload.ts +1 -1
- package/src/pxe_service/error_enriching.ts +1 -1
- package/src/pxe_service/pxe_service.ts +32 -44
- package/src/simulator/index.ts +4 -2
- package/src/simulator_oracle/index.ts +224 -67
- package/src/utils/create_pxe_service.ts +8 -13
- package/dest/kernel_prover/test/test_circuit_prover.d.ts +0 -20
- package/dest/kernel_prover/test/test_circuit_prover.d.ts.map +0 -1
- package/dest/kernel_prover/test/test_circuit_prover.js +0 -75
- package/dest/note_decryption_utils/brute_force_note_info.d.ts +0 -31
- package/dest/note_decryption_utils/brute_force_note_info.d.ts.map +0 -1
- package/dest/note_decryption_utils/brute_force_note_info.js +0 -55
- package/dest/note_decryption_utils/index.d.ts +0 -3
- package/dest/note_decryption_utils/index.d.ts.map +0 -1
- package/dest/note_decryption_utils/index.js +0 -2
- package/dest/note_decryption_utils/produce_note_daos.d.ts +0 -28
- package/dest/note_decryption_utils/produce_note_daos.d.ts.map +0 -1
- package/dest/note_decryption_utils/produce_note_daos.js +0 -33
- package/dest/note_decryption_utils/produce_note_daos_for_key.d.ts +0 -8
- package/dest/note_decryption_utils/produce_note_daos_for_key.d.ts.map +0 -1
- package/dest/note_decryption_utils/produce_note_daos_for_key.js +0 -17
- package/src/kernel_prover/test/test_circuit_prover.ts +0 -122
- package/src/note_decryption_utils/brute_force_note_info.ts +0 -90
- package/src/note_decryption_utils/index.ts +0 -2
- package/src/note_decryption_utils/produce_note_daos.ts +0 -67
- package/src/note_decryption_utils/produce_note_daos_for_key.ts +0 -57
|
@@ -12,6 +12,7 @@ import { type ContractArtifact, FunctionSelector, FunctionType } from '@aztec/fo
|
|
|
12
12
|
import { toBufferBE } from '@aztec/foundation/bigint-buffer';
|
|
13
13
|
import { Fr } from '@aztec/foundation/fields';
|
|
14
14
|
import { toArray } from '@aztec/foundation/iterable';
|
|
15
|
+
import { type LogFn, createDebugOnlyLogger } from '@aztec/foundation/log';
|
|
15
16
|
import {
|
|
16
17
|
type AztecAsyncArray,
|
|
17
18
|
type AztecAsyncKVStore,
|
|
@@ -63,6 +64,11 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
63
64
|
#taggingSecretIndexesForSenders: AztecAsyncMap<string, number>;
|
|
64
65
|
#taggingSecretIndexesForRecipients: AztecAsyncMap<string, number>;
|
|
65
66
|
|
|
67
|
+
// Arbitrary data stored by contracts. Key is computed as `${contractAddress}:${key}`
|
|
68
|
+
#contractStore: AztecAsyncMap<string, Buffer>;
|
|
69
|
+
|
|
70
|
+
debug: LogFn;
|
|
71
|
+
|
|
66
72
|
protected constructor(private db: AztecAsyncKVStore) {
|
|
67
73
|
this.#db = db;
|
|
68
74
|
|
|
@@ -100,6 +106,10 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
100
106
|
|
|
101
107
|
this.#taggingSecretIndexesForSenders = db.openMap('tagging_secret_indexes_for_senders');
|
|
102
108
|
this.#taggingSecretIndexesForRecipients = db.openMap('tagging_secret_indexes_for_recipients');
|
|
109
|
+
|
|
110
|
+
this.#contractStore = db.openMap('contract_store');
|
|
111
|
+
|
|
112
|
+
this.debug = createDebugOnlyLogger('aztec:kv-pxe-database');
|
|
103
113
|
}
|
|
104
114
|
|
|
105
115
|
public static async create(db: AztecAsyncKVStore): Promise<KVPxeDatabase> {
|
|
@@ -611,4 +621,56 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
611
621
|
await Promise.all(senders.map(sender => this.#taggingSecretIndexesForSenders.delete(sender)));
|
|
612
622
|
});
|
|
613
623
|
}
|
|
624
|
+
|
|
625
|
+
async dbStore(contractAddress: AztecAddress, slot: Fr, values: Fr[]): Promise<void> {
|
|
626
|
+
await this.#contractStore.set(
|
|
627
|
+
dbSlotToKey(contractAddress, slot),
|
|
628
|
+
Buffer.concat(values.map(value => value.toBuffer())),
|
|
629
|
+
);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
async dbLoad(contractAddress: AztecAddress, slot: Fr): Promise<Fr[] | null> {
|
|
633
|
+
const dataBuffer = await this.#contractStore.getAsync(dbSlotToKey(contractAddress, slot));
|
|
634
|
+
if (!dataBuffer) {
|
|
635
|
+
this.debug(`Data not found for contract ${contractAddress.toString()} and slot ${slot.toString()}`);
|
|
636
|
+
return null;
|
|
637
|
+
}
|
|
638
|
+
const values: Fr[] = [];
|
|
639
|
+
for (let i = 0; i < dataBuffer.length; i += Fr.SIZE_IN_BYTES) {
|
|
640
|
+
values.push(Fr.fromBuffer(dataBuffer.subarray(i, i + Fr.SIZE_IN_BYTES)));
|
|
641
|
+
}
|
|
642
|
+
return values;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
async dbDelete(contractAddress: AztecAddress, slot: Fr): Promise<void> {
|
|
646
|
+
await this.#contractStore.delete(dbSlotToKey(contractAddress, slot));
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
async dbCopy(contractAddress: AztecAddress, srcSlot: Fr, dstSlot: Fr, numEntries: number): Promise<void> {
|
|
650
|
+
// In order to support overlaping source and destination regions we need to check the relative positions of source
|
|
651
|
+
// and destination. If destination is ahead of source, then by the time we overwrite source elements using forward
|
|
652
|
+
// indexes we'll have already read those. On the contrary, if source is ahead of destination we need to use backward
|
|
653
|
+
// indexes to avoid reading elements that've been overwritten.
|
|
654
|
+
|
|
655
|
+
const indexes = Array.from(Array(numEntries).keys());
|
|
656
|
+
if (srcSlot.lt(dstSlot)) {
|
|
657
|
+
indexes.reverse();
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
for (const i of indexes) {
|
|
661
|
+
const currentSrcSlot = dbSlotToKey(contractAddress, srcSlot.add(new Fr(i)));
|
|
662
|
+
const currentDstSlot = dbSlotToKey(contractAddress, dstSlot.add(new Fr(i)));
|
|
663
|
+
|
|
664
|
+
const toCopy = await this.#contractStore.getAsync(currentSrcSlot);
|
|
665
|
+
if (!toCopy) {
|
|
666
|
+
throw new Error(`Attempted to copy empty slot ${currentSrcSlot} for contract ${contractAddress.toString()}`);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
await this.#contractStore.set(currentDstSlot, toCopy);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
function dbSlotToKey(contractAddress: AztecAddress, slot: Fr): string {
|
|
675
|
+
return `${contractAddress.toString()}:${slot.toString()}`;
|
|
614
676
|
}
|
package/src/database/note_dao.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Note, TxHash, randomTxHash } from '@aztec/circuit-types';
|
|
2
2
|
import { AztecAddress, Fr, Point, type PublicKey } from '@aztec/circuits.js';
|
|
3
3
|
import { NoteSelector } from '@aztec/foundation/abi';
|
|
4
4
|
import { toBigIntBE } from '@aztec/foundation/bigint-buffer';
|
|
5
5
|
import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
6
|
-
import { type NoteData } from '@aztec/simulator/
|
|
7
|
-
|
|
8
|
-
import { type NoteInfo } from '../note_decryption_utils/index.js';
|
|
6
|
+
import { type NoteData } from '@aztec/simulator/client';
|
|
9
7
|
|
|
10
8
|
/**
|
|
11
9
|
* A Note Data Access Object, representing a note that was comitted to the note hash tree, holding all of the
|
|
@@ -61,32 +59,6 @@ export class NoteDao implements NoteData {
|
|
|
61
59
|
public noteTypeId: NoteSelector,
|
|
62
60
|
) {}
|
|
63
61
|
|
|
64
|
-
static fromPayloadAndNoteInfo(
|
|
65
|
-
note: Note,
|
|
66
|
-
payload: L1NotePayload,
|
|
67
|
-
noteInfo: NoteInfo,
|
|
68
|
-
l2BlockNumber: number,
|
|
69
|
-
l2BlockHash: string,
|
|
70
|
-
dataStartIndexForTx: number,
|
|
71
|
-
addressPoint: PublicKey,
|
|
72
|
-
) {
|
|
73
|
-
const noteHashIndexInTheWholeTree = BigInt(dataStartIndexForTx + noteInfo.noteHashIndex);
|
|
74
|
-
return new NoteDao(
|
|
75
|
-
note,
|
|
76
|
-
payload.contractAddress,
|
|
77
|
-
payload.storageSlot,
|
|
78
|
-
noteInfo.nonce,
|
|
79
|
-
noteInfo.noteHash,
|
|
80
|
-
noteInfo.siloedNullifier,
|
|
81
|
-
noteInfo.txHash,
|
|
82
|
-
l2BlockNumber,
|
|
83
|
-
l2BlockHash,
|
|
84
|
-
noteHashIndexInTheWholeTree,
|
|
85
|
-
addressPoint,
|
|
86
|
-
payload.noteTypeId,
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
62
|
toBuffer(): Buffer {
|
|
91
63
|
return serializeToBuffer([
|
|
92
64
|
this.note,
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Note, TxHash, randomTxHash } from '@aztec/circuit-types';
|
|
2
2
|
import { AztecAddress, Fr, Point, type PublicKey } from '@aztec/circuits.js';
|
|
3
3
|
import { NoteSelector } from '@aztec/foundation/abi';
|
|
4
4
|
import { toBigIntBE } from '@aztec/foundation/bigint-buffer';
|
|
5
5
|
import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
6
6
|
|
|
7
|
-
import { type NoteInfo } from '../note_decryption_utils/index.js';
|
|
8
|
-
|
|
9
7
|
/**
|
|
10
8
|
* A note with contextual data which was decrypted as outgoing.
|
|
11
9
|
*/
|
|
@@ -38,31 +36,6 @@ export class OutgoingNoteDao {
|
|
|
38
36
|
public ovpkM: PublicKey,
|
|
39
37
|
) {}
|
|
40
38
|
|
|
41
|
-
static fromPayloadAndNoteInfo(
|
|
42
|
-
note: Note,
|
|
43
|
-
payload: L1NotePayload,
|
|
44
|
-
noteInfo: NoteInfo,
|
|
45
|
-
l2BlockNumber: number,
|
|
46
|
-
l2BlockHash: string,
|
|
47
|
-
dataStartIndexForTx: number,
|
|
48
|
-
ovpkM: PublicKey,
|
|
49
|
-
) {
|
|
50
|
-
const noteHashIndexInTheWholeTree = BigInt(dataStartIndexForTx + noteInfo.noteHashIndex);
|
|
51
|
-
return new OutgoingNoteDao(
|
|
52
|
-
note,
|
|
53
|
-
payload.contractAddress,
|
|
54
|
-
payload.storageSlot,
|
|
55
|
-
payload.noteTypeId,
|
|
56
|
-
noteInfo.txHash,
|
|
57
|
-
l2BlockNumber,
|
|
58
|
-
l2BlockHash,
|
|
59
|
-
noteInfo.nonce,
|
|
60
|
-
noteInfo.noteHash,
|
|
61
|
-
noteHashIndexInTheWholeTree,
|
|
62
|
-
ovpkM,
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
39
|
toBuffer(): Buffer {
|
|
67
40
|
return serializeToBuffer([
|
|
68
41
|
this.note,
|
|
@@ -213,4 +213,41 @@ export interface PxeDatabase extends ContractArtifactDatabase, ContractInstanceD
|
|
|
213
213
|
* is also required to deal with chain reorgs.
|
|
214
214
|
*/
|
|
215
215
|
resetNoteSyncData(): Promise<void>;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Stores arbitrary information in a per-contract non-volatile database, which can later be retrieved with `dbLoad`.
|
|
219
|
+
* If data was already stored at this slot, it is overwrriten.
|
|
220
|
+
* @param contractAddress - The contract address to scope the data under.
|
|
221
|
+
* @param slot - The slot in the database in which to store the value. Slots need not be contiguous.
|
|
222
|
+
* @param values - The data to store.
|
|
223
|
+
*/
|
|
224
|
+
dbStore(contractAddress: AztecAddress, slot: Fr, values: Fr[]): Promise<void>;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Returns data previously stored via `dbStore` in the per-contract non-volatile database.
|
|
228
|
+
* @param contractAddress - The contract address under which the data is scoped.
|
|
229
|
+
* @param slot - The slot in the database to read.
|
|
230
|
+
* @returns The stored data or `null` if no data is stored under the slot.
|
|
231
|
+
*/
|
|
232
|
+
dbLoad(contractAddress: AztecAddress, slot: Fr): Promise<Fr[] | null>;
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Deletes data in the per-contract non-volatile database. Does nothing if no data was present.
|
|
236
|
+
* @param contractAddress - The contract address under which the data is scoped.
|
|
237
|
+
* @param slot - The slot in the database to delete.
|
|
238
|
+
*/
|
|
239
|
+
dbDelete(contractAddress: AztecAddress, slot: Fr): Promise<void>;
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Copies a number of contiguous entries in the per-contract non-volatile database. This allows for efficient data
|
|
243
|
+
* structures by avoiding repeated calls to `dbLoad` and `dbStore`.
|
|
244
|
+
* Supports overlapping source and destination regions (which will result in the overlapped source values being
|
|
245
|
+
* overwritten). All copied slots must exist in the database (i.e. have been stored and not deleted)
|
|
246
|
+
*
|
|
247
|
+
* @param contractAddress - The contract address under which the data is scoped.
|
|
248
|
+
* @param srcSlot - The first slot to copy from.
|
|
249
|
+
* @param dstSlot - The first slot to copy to.
|
|
250
|
+
* @param numEntries - The number of entries to copy.
|
|
251
|
+
*/
|
|
252
|
+
dbCopy(contractAddress: AztecAddress, srcSlot: Fr, dstSlot: Fr, numEntries: number): Promise<void>;
|
|
216
253
|
}
|
|
@@ -405,5 +405,165 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) {
|
|
|
405
405
|
await expect(database.getContractInstance(address)).resolves.toEqual(instance);
|
|
406
406
|
});
|
|
407
407
|
});
|
|
408
|
+
|
|
409
|
+
describe('contract non-volatile database', () => {
|
|
410
|
+
let contract: AztecAddress;
|
|
411
|
+
|
|
412
|
+
beforeEach(() => {
|
|
413
|
+
// Setup mock contract address
|
|
414
|
+
contract = AztecAddress.random();
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it('stores and loads a single value', async () => {
|
|
418
|
+
const slot = new Fr(1);
|
|
419
|
+
const values = [new Fr(42)];
|
|
420
|
+
|
|
421
|
+
await database.dbStore(contract, slot, values);
|
|
422
|
+
const result = await database.dbLoad(contract, slot);
|
|
423
|
+
expect(result).toEqual(values);
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
it('stores and loads multiple values', async () => {
|
|
427
|
+
const slot = new Fr(1);
|
|
428
|
+
const values = [new Fr(42), new Fr(43), new Fr(44)];
|
|
429
|
+
|
|
430
|
+
await database.dbStore(contract, slot, values);
|
|
431
|
+
const result = await database.dbLoad(contract, slot);
|
|
432
|
+
expect(result).toEqual(values);
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it('overwrites existing values', async () => {
|
|
436
|
+
const slot = new Fr(1);
|
|
437
|
+
const initialValues = [new Fr(42)];
|
|
438
|
+
const newValues = [new Fr(100)];
|
|
439
|
+
|
|
440
|
+
await database.dbStore(contract, slot, initialValues);
|
|
441
|
+
await database.dbStore(contract, slot, newValues);
|
|
442
|
+
|
|
443
|
+
const result = await database.dbLoad(contract, slot);
|
|
444
|
+
expect(result).toEqual(newValues);
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
it('stores values for different contracts independently', async () => {
|
|
448
|
+
const anotherContract = AztecAddress.random();
|
|
449
|
+
const slot = new Fr(1);
|
|
450
|
+
const values1 = [new Fr(42)];
|
|
451
|
+
const values2 = [new Fr(100)];
|
|
452
|
+
|
|
453
|
+
await database.dbStore(contract, slot, values1);
|
|
454
|
+
await database.dbStore(anotherContract, slot, values2);
|
|
455
|
+
|
|
456
|
+
const result1 = await database.dbLoad(contract, slot);
|
|
457
|
+
const result2 = await database.dbLoad(anotherContract, slot);
|
|
458
|
+
|
|
459
|
+
expect(result1).toEqual(values1);
|
|
460
|
+
expect(result2).toEqual(values2);
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
it('returns null for non-existent slots', async () => {
|
|
464
|
+
const slot = Fr.random();
|
|
465
|
+
const result = await database.dbLoad(contract, slot);
|
|
466
|
+
expect(result).toBeNull();
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
it('deletes a slot', async () => {
|
|
470
|
+
const slot = new Fr(1);
|
|
471
|
+
const values = [new Fr(42)];
|
|
472
|
+
|
|
473
|
+
await database.dbStore(contract, slot, values);
|
|
474
|
+
await database.dbDelete(contract, slot);
|
|
475
|
+
|
|
476
|
+
expect(await database.dbLoad(contract, slot)).toBeNull();
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
it('deletes an empty slot', async () => {
|
|
480
|
+
const slot = new Fr(1);
|
|
481
|
+
await database.dbDelete(contract, slot);
|
|
482
|
+
|
|
483
|
+
expect(await database.dbLoad(contract, slot)).toBeNull();
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
it('copies a single value', async () => {
|
|
487
|
+
const slot = new Fr(1);
|
|
488
|
+
const values = [new Fr(42)];
|
|
489
|
+
|
|
490
|
+
await database.dbStore(contract, slot, values);
|
|
491
|
+
|
|
492
|
+
const dstSlot = new Fr(5);
|
|
493
|
+
await database.dbCopy(contract, slot, dstSlot, 1);
|
|
494
|
+
|
|
495
|
+
expect(await database.dbLoad(contract, dstSlot)).toEqual(values);
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
it('copies multiple non-overlapping values', async () => {
|
|
499
|
+
const src = new Fr(1);
|
|
500
|
+
const valuesArray = [[new Fr(42)], [new Fr(1337)], [new Fr(13)]];
|
|
501
|
+
|
|
502
|
+
await database.dbStore(contract, src, valuesArray[0]);
|
|
503
|
+
await database.dbStore(contract, src.add(new Fr(1)), valuesArray[1]);
|
|
504
|
+
await database.dbStore(contract, src.add(new Fr(2)), valuesArray[2]);
|
|
505
|
+
|
|
506
|
+
const dst = new Fr(5);
|
|
507
|
+
await database.dbCopy(contract, src, dst, 3);
|
|
508
|
+
|
|
509
|
+
expect(await database.dbLoad(contract, dst)).toEqual(valuesArray[0]);
|
|
510
|
+
expect(await database.dbLoad(contract, dst.add(new Fr(1)))).toEqual(valuesArray[1]);
|
|
511
|
+
expect(await database.dbLoad(contract, dst.add(new Fr(2)))).toEqual(valuesArray[2]);
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
it('copies overlapping values with src ahead', async () => {
|
|
515
|
+
const src = new Fr(1);
|
|
516
|
+
const valuesArray = [[new Fr(42)], [new Fr(1337)], [new Fr(13)]];
|
|
517
|
+
|
|
518
|
+
await database.dbStore(contract, src, valuesArray[0]);
|
|
519
|
+
await database.dbStore(contract, src.add(new Fr(1)), valuesArray[1]);
|
|
520
|
+
await database.dbStore(contract, src.add(new Fr(2)), valuesArray[2]);
|
|
521
|
+
|
|
522
|
+
const dst = new Fr(2);
|
|
523
|
+
await database.dbCopy(contract, src, dst, 3);
|
|
524
|
+
|
|
525
|
+
expect(await database.dbLoad(contract, dst)).toEqual(valuesArray[0]);
|
|
526
|
+
expect(await database.dbLoad(contract, dst.add(new Fr(1)))).toEqual(valuesArray[1]);
|
|
527
|
+
expect(await database.dbLoad(contract, dst.add(new Fr(2)))).toEqual(valuesArray[2]);
|
|
528
|
+
|
|
529
|
+
// Slots 2 and 3 (src[1] and src[2]) should have been overwritten since they are also dst[0] and dst[1]
|
|
530
|
+
expect(await database.dbLoad(contract, src)).toEqual(valuesArray[0]); // src[0] (unchanged)
|
|
531
|
+
expect(await database.dbLoad(contract, src.add(new Fr(1)))).toEqual(valuesArray[0]); // dst[0]
|
|
532
|
+
expect(await database.dbLoad(contract, src.add(new Fr(2)))).toEqual(valuesArray[1]); // dst[1]
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
it('copies overlapping values with dst ahead', async () => {
|
|
536
|
+
const src = new Fr(5);
|
|
537
|
+
const valuesArray = [[new Fr(42)], [new Fr(1337)], [new Fr(13)]];
|
|
538
|
+
|
|
539
|
+
await database.dbStore(contract, src, valuesArray[0]);
|
|
540
|
+
await database.dbStore(contract, src.add(new Fr(1)), valuesArray[1]);
|
|
541
|
+
await database.dbStore(contract, src.add(new Fr(2)), valuesArray[2]);
|
|
542
|
+
|
|
543
|
+
const dst = new Fr(4);
|
|
544
|
+
await database.dbCopy(contract, src, dst, 3);
|
|
545
|
+
|
|
546
|
+
expect(await database.dbLoad(contract, dst)).toEqual(valuesArray[0]);
|
|
547
|
+
expect(await database.dbLoad(contract, dst.add(new Fr(1)))).toEqual(valuesArray[1]);
|
|
548
|
+
expect(await database.dbLoad(contract, dst.add(new Fr(2)))).toEqual(valuesArray[2]);
|
|
549
|
+
|
|
550
|
+
// Slots 5 and 6 (src[0] and src[1]) should have been overwritten since they are also dst[1] and dst[2]
|
|
551
|
+
expect(await database.dbLoad(contract, src)).toEqual(valuesArray[1]); // dst[1]
|
|
552
|
+
expect(await database.dbLoad(contract, src.add(new Fr(1)))).toEqual(valuesArray[2]); // dst[2]
|
|
553
|
+
expect(await database.dbLoad(contract, src.add(new Fr(2)))).toEqual(valuesArray[2]); // src[2] (unchanged)
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
it('copying fails if any value is empty', async () => {
|
|
557
|
+
const src = new Fr(1);
|
|
558
|
+
const valuesArray = [[new Fr(42)], [new Fr(1337)], [new Fr(13)]];
|
|
559
|
+
|
|
560
|
+
await database.dbStore(contract, src, valuesArray[0]);
|
|
561
|
+
// We skip src[1]
|
|
562
|
+
await database.dbStore(contract, src.add(new Fr(2)), valuesArray[2]);
|
|
563
|
+
|
|
564
|
+
const dst = new Fr(5);
|
|
565
|
+
await expect(database.dbCopy(contract, src, dst, 3)).rejects.toThrow('Attempted to copy empty slot');
|
|
566
|
+
});
|
|
567
|
+
});
|
|
408
568
|
});
|
|
409
569
|
}
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
import { createLogger } from '@aztec/foundation/log';
|
|
16
16
|
import { type Tuple } from '@aztec/foundation/serialize';
|
|
17
17
|
import { type KeyStore } from '@aztec/key-store';
|
|
18
|
-
import { getVKIndex, getVKSiblingPath } from '@aztec/noir-protocol-circuits-types/
|
|
18
|
+
import { getVKIndex, getVKSiblingPath } from '@aztec/noir-protocol-circuits-types/vks';
|
|
19
19
|
|
|
20
20
|
import { type ContractDataOracle } from '../contract_data_oracle/index.js';
|
|
21
21
|
import { type ProvingDataOracle } from './../kernel_prover/proving_data_oracle.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type PrivateCallExecutionResult, type PrivateKernelSimulateOutput, collectNested } from '@aztec/circuit-types';
|
|
2
2
|
import {
|
|
3
3
|
type Fr,
|
|
4
4
|
KeyValidationHint,
|
|
@@ -42,8 +42,8 @@ import { privateKernelResetDimensionsConfig } from '@aztec/noir-protocol-circuit
|
|
|
42
42
|
import { type ProvingDataOracle } from '../proving_data_oracle.js';
|
|
43
43
|
|
|
44
44
|
function collectNestedReadRequests(
|
|
45
|
-
executionStack:
|
|
46
|
-
extractReadRequests: (execution:
|
|
45
|
+
executionStack: PrivateCallExecutionResult[],
|
|
46
|
+
extractReadRequests: (execution: PrivateCallExecutionResult) => ReadRequest[],
|
|
47
47
|
): ScopedReadRequest[] {
|
|
48
48
|
return collectNested(executionStack, executionResult => {
|
|
49
49
|
const nonEmptyReadRequests = getNonEmptyItems(extractReadRequests(executionResult));
|
|
@@ -101,7 +101,7 @@ export class PrivateKernelResetPrivateInputsBuilder {
|
|
|
101
101
|
|
|
102
102
|
constructor(
|
|
103
103
|
private previousKernelOutput: PrivateKernelSimulateOutput<PrivateKernelCircuitPublicInputs>,
|
|
104
|
-
private executionStack:
|
|
104
|
+
private executionStack: PrivateCallExecutionResult[],
|
|
105
105
|
private noteHashNullifierCounterMap: Map<number, number>,
|
|
106
106
|
private validationRequestsSplitCounter: number,
|
|
107
107
|
) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
type PrivateCallExecutionResult,
|
|
2
3
|
type PrivateExecutionResult,
|
|
3
4
|
type PrivateKernelProver,
|
|
4
5
|
type PrivateKernelSimulateOutput,
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
} from '@aztec/circuit-types';
|
|
11
12
|
import {
|
|
12
13
|
CLIENT_IVC_VERIFICATION_KEY_LENGTH_IN_FIELDS,
|
|
14
|
+
ClientIvcProof,
|
|
13
15
|
Fr,
|
|
14
16
|
PROTOCOL_CONTRACT_TREE_HEIGHT,
|
|
15
17
|
PrivateCallData,
|
|
@@ -32,7 +34,7 @@ import { createLogger } from '@aztec/foundation/log';
|
|
|
32
34
|
import { assertLength } from '@aztec/foundation/serialize';
|
|
33
35
|
import { pushTestData } from '@aztec/foundation/testing';
|
|
34
36
|
import { Timer } from '@aztec/foundation/timer';
|
|
35
|
-
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/
|
|
37
|
+
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vks';
|
|
36
38
|
import {
|
|
37
39
|
getProtocolContractSiblingPath,
|
|
38
40
|
isProtocolContract,
|
|
@@ -89,6 +91,12 @@ const NULL_PROVE_OUTPUT: PrivateKernelSimulateOutput<PrivateKernelCircuitPublicI
|
|
|
89
91
|
bytecode: Buffer.from([]),
|
|
90
92
|
};
|
|
91
93
|
|
|
94
|
+
export type ProvingConfig = {
|
|
95
|
+
simulate: boolean;
|
|
96
|
+
profile: boolean;
|
|
97
|
+
dryRun: boolean;
|
|
98
|
+
};
|
|
99
|
+
|
|
92
100
|
/**
|
|
93
101
|
* The KernelProver class is responsible for generating kernel proofs.
|
|
94
102
|
* It takes a transaction request, its signature, and the simulation result as inputs, and outputs a proof
|
|
@@ -98,7 +106,11 @@ const NULL_PROVE_OUTPUT: PrivateKernelSimulateOutput<PrivateKernelCircuitPublicI
|
|
|
98
106
|
export class KernelProver {
|
|
99
107
|
private log = createLogger('pxe:kernel-prover');
|
|
100
108
|
|
|
101
|
-
constructor(
|
|
109
|
+
constructor(
|
|
110
|
+
private oracle: ProvingDataOracle,
|
|
111
|
+
private proofCreator: PrivateKernelProver,
|
|
112
|
+
private fakeProofs = false,
|
|
113
|
+
) {}
|
|
102
114
|
|
|
103
115
|
/**
|
|
104
116
|
* Generate a proof for a given transaction request and execution result.
|
|
@@ -116,14 +128,19 @@ export class KernelProver {
|
|
|
116
128
|
async prove(
|
|
117
129
|
txRequest: TxRequest,
|
|
118
130
|
executionResult: PrivateExecutionResult,
|
|
119
|
-
profile:
|
|
120
|
-
dryRun: boolean = false,
|
|
131
|
+
{ simulate, profile, dryRun }: ProvingConfig = { simulate: false, profile: false, dryRun: false },
|
|
121
132
|
): Promise<PrivateKernelSimulateOutput<PrivateKernelTailCircuitPublicInputs>> {
|
|
133
|
+
if (simulate && profile) {
|
|
134
|
+
throw new Error('Cannot simulate and profile at the same time');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
simulate = simulate || this.fakeProofs;
|
|
138
|
+
|
|
122
139
|
const timer = new Timer();
|
|
123
140
|
|
|
124
141
|
const isPrivateOnlyTx = this.isPrivateOnly(executionResult);
|
|
125
142
|
|
|
126
|
-
const executionStack = [executionResult];
|
|
143
|
+
const executionStack = [executionResult.entrypoint];
|
|
127
144
|
let firstIteration = true;
|
|
128
145
|
|
|
129
146
|
let output = NULL_PROVE_OUTPUT;
|
|
@@ -156,7 +173,9 @@ export class KernelProver {
|
|
|
156
173
|
);
|
|
157
174
|
while (resetBuilder.needsReset()) {
|
|
158
175
|
const privateInputs = await resetBuilder.build(this.oracle, noteHashLeafIndexMap);
|
|
159
|
-
output =
|
|
176
|
+
output = simulate
|
|
177
|
+
? await this.proofCreator.simulateReset(privateInputs)
|
|
178
|
+
: await this.proofCreator.generateResetOutput(privateInputs);
|
|
160
179
|
// TODO(#7368) consider refactoring this redundant bytecode pushing
|
|
161
180
|
acirs.push(output.bytecode);
|
|
162
181
|
witnessStack.push(output.outputWitness);
|
|
@@ -199,11 +218,17 @@ export class KernelProver {
|
|
|
199
218
|
protocolContractTreeRoot,
|
|
200
219
|
privateCallData,
|
|
201
220
|
isPrivateOnlyTx,
|
|
221
|
+
executionResult.firstNullifier,
|
|
222
|
+
);
|
|
223
|
+
this.log.debug(
|
|
224
|
+
`Calling private kernel init with isPrivateOnly ${isPrivateOnlyTx} and firstNullifierHint ${proofInput.firstNullifierHint}`,
|
|
202
225
|
);
|
|
203
226
|
|
|
204
227
|
pushTestData('private-kernel-inputs-init', proofInput);
|
|
205
228
|
|
|
206
|
-
output =
|
|
229
|
+
output = simulate
|
|
230
|
+
? await this.proofCreator.simulateInit(proofInput)
|
|
231
|
+
: await this.proofCreator.generateInitOutput(proofInput);
|
|
207
232
|
|
|
208
233
|
acirs.push(output.bytecode);
|
|
209
234
|
witnessStack.push(output.outputWitness);
|
|
@@ -222,7 +247,9 @@ export class KernelProver {
|
|
|
222
247
|
|
|
223
248
|
pushTestData('private-kernel-inputs-inner', proofInput);
|
|
224
249
|
|
|
225
|
-
output =
|
|
250
|
+
output = simulate
|
|
251
|
+
? await this.proofCreator.simulateInner(proofInput)
|
|
252
|
+
: await this.proofCreator.generateInnerOutput(proofInput);
|
|
226
253
|
|
|
227
254
|
acirs.push(output.bytecode);
|
|
228
255
|
witnessStack.push(output.outputWitness);
|
|
@@ -242,7 +269,9 @@ export class KernelProver {
|
|
|
242
269
|
);
|
|
243
270
|
while (resetBuilder.needsReset()) {
|
|
244
271
|
const privateInputs = await resetBuilder.build(this.oracle, noteHashLeafIndexMap);
|
|
245
|
-
output =
|
|
272
|
+
output = simulate
|
|
273
|
+
? await this.proofCreator.simulateReset(privateInputs)
|
|
274
|
+
: await this.proofCreator.generateResetOutput(privateInputs);
|
|
246
275
|
|
|
247
276
|
acirs.push(output.bytecode);
|
|
248
277
|
witnessStack.push(output.outputWitness);
|
|
@@ -275,7 +304,9 @@ export class KernelProver {
|
|
|
275
304
|
|
|
276
305
|
pushTestData('private-kernel-inputs-ordering', privateInputs);
|
|
277
306
|
|
|
278
|
-
const tailOutput =
|
|
307
|
+
const tailOutput = simulate
|
|
308
|
+
? await this.proofCreator.simulateTail(privateInputs)
|
|
309
|
+
: await this.proofCreator.generateTailOutput(privateInputs);
|
|
279
310
|
if (tailOutput.publicInputs.forPublic) {
|
|
280
311
|
const privateLogs = privateInputs.previousKernel.publicInputs.end.privateLogs;
|
|
281
312
|
const nonRevertiblePrivateLogs = tailOutput.publicInputs.forPublic.nonRevertibleAccumulatedData.privateLogs;
|
|
@@ -290,18 +321,22 @@ export class KernelProver {
|
|
|
290
321
|
tailOutput.profileResult = { gateCounts };
|
|
291
322
|
}
|
|
292
323
|
|
|
293
|
-
|
|
324
|
+
if (!simulate) {
|
|
325
|
+
this.log.info(`Private kernel witness generation took ${timer.ms()}ms`);
|
|
326
|
+
}
|
|
294
327
|
|
|
295
328
|
// TODO(#7368) how do we 'bincode' encode these inputs?
|
|
296
|
-
if (!dryRun) {
|
|
329
|
+
if (!dryRun && !simulate) {
|
|
297
330
|
const ivcProof = await this.proofCreator.createClientIvcProof(acirs, witnessStack);
|
|
298
331
|
tailOutput.clientIvcProof = ivcProof;
|
|
332
|
+
} else {
|
|
333
|
+
tailOutput.clientIvcProof = ClientIvcProof.empty();
|
|
299
334
|
}
|
|
300
335
|
|
|
301
336
|
return tailOutput;
|
|
302
337
|
}
|
|
303
338
|
|
|
304
|
-
private async createPrivateCallData({ publicInputs, vk: vkAsBuffer }:
|
|
339
|
+
private async createPrivateCallData({ publicInputs, vk: vkAsBuffer }: PrivateCallExecutionResult) {
|
|
305
340
|
const { contractAddress, functionSelector } = publicInputs.callContext;
|
|
306
341
|
|
|
307
342
|
const vkAsFields = vkAsFieldsMegaHonk(vkAsBuffer);
|
|
@@ -339,12 +374,15 @@ export class KernelProver {
|
|
|
339
374
|
}
|
|
340
375
|
|
|
341
376
|
private isPrivateOnly(executionResult: PrivateExecutionResult): boolean {
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
377
|
+
const isPrivateOnlyRecursive = (callResult: PrivateCallExecutionResult): boolean => {
|
|
378
|
+
const makesPublicCalls =
|
|
379
|
+
callResult.enqueuedPublicFunctionCalls.some(enqueuedCall => !enqueuedCall.isEmpty()) ||
|
|
380
|
+
!callResult.publicTeardownFunctionCall.isEmpty();
|
|
381
|
+
return (
|
|
382
|
+
!makesPublicCalls &&
|
|
383
|
+
callResult.nestedExecutions.every(nestedExecution => isPrivateOnlyRecursive(nestedExecution))
|
|
384
|
+
);
|
|
385
|
+
};
|
|
386
|
+
return isPrivateOnlyRecursive(executionResult.entrypoint);
|
|
349
387
|
}
|
|
350
388
|
}
|
|
@@ -41,7 +41,7 @@ export async function getOrderedNoteItems(
|
|
|
41
41
|
noteFields.sort((a, b) => a.index - b.index);
|
|
42
42
|
|
|
43
43
|
// Now we insert the public fields into the note based on its indices defined in the ABI.
|
|
44
|
-
const modifiedNoteItems = privateNoteValues;
|
|
44
|
+
const modifiedNoteItems = [...privateNoteValues];
|
|
45
45
|
let indexInPublicValues = 0;
|
|
46
46
|
for (let i = 0; i < noteFields.length; i++) {
|
|
47
47
|
const noteField = noteFields[i];
|
|
@@ -4,7 +4,7 @@ import { FunctionSelector } from '@aztec/foundation/abi';
|
|
|
4
4
|
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
5
5
|
import { Fr } from '@aztec/foundation/fields';
|
|
6
6
|
import { type Logger } from '@aztec/foundation/log';
|
|
7
|
-
import { resolveAssertionMessageFromRevertData, resolveOpcodeLocations } from '@aztec/simulator/
|
|
7
|
+
import { resolveAssertionMessageFromRevertData, resolveOpcodeLocations } from '@aztec/simulator/client';
|
|
8
8
|
|
|
9
9
|
import { type ContractDataOracle, type PxeDatabase } from '../index.js';
|
|
10
10
|
|