@aztec/pxe 0.59.0 → 0.61.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/contract_data_oracle/index.d.ts +1 -0
- package/dest/contract_data_oracle/index.d.ts.map +1 -1
- package/dest/contract_data_oracle/private_functions_tree.d.ts +1 -0
- package/dest/contract_data_oracle/private_functions_tree.d.ts.map +1 -1
- package/dest/database/deferred_note_dao.d.ts +7 -19
- package/dest/database/deferred_note_dao.d.ts.map +1 -1
- package/dest/database/deferred_note_dao.js +8 -18
- package/dest/database/incoming_note_dao.d.ts +2 -1
- package/dest/database/incoming_note_dao.d.ts.map +1 -1
- package/dest/database/incoming_note_dao.js +3 -3
- package/dest/database/kv_pxe_database.d.ts +5 -3
- package/dest/database/kv_pxe_database.d.ts.map +1 -1
- package/dest/database/kv_pxe_database.js +22 -8
- package/dest/database/outgoing_note_dao.d.ts +2 -1
- package/dest/database/outgoing_note_dao.d.ts.map +1 -1
- package/dest/database/outgoing_note_dao.js +3 -3
- package/dest/database/pxe_database.d.ts +6 -4
- package/dest/database/pxe_database.d.ts.map +1 -1
- 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 +9 -9
- package/dest/kernel_prover/kernel_prover.js +6 -6
- package/dest/kernel_prover/test/test_circuit_prover.d.ts +1 -0
- package/dest/kernel_prover/test/test_circuit_prover.d.ts.map +1 -1
- package/dest/note_processor/note_processor.d.ts +1 -5
- package/dest/note_processor/note_processor.d.ts.map +1 -1
- package/dest/note_processor/note_processor.js +56 -58
- package/dest/note_processor/utils/add_public_values_to_payload.d.ts +10 -0
- package/dest/note_processor/utils/add_public_values_to_payload.d.ts.map +1 -0
- package/dest/note_processor/utils/add_public_values_to_payload.js +48 -0
- package/dest/note_processor/utils/brute_force_note_info.d.ts +8 -3
- package/dest/note_processor/utils/brute_force_note_info.d.ts.map +1 -1
- package/dest/note_processor/utils/brute_force_note_info.js +6 -3
- package/dest/note_processor/utils/produce_note_daos.d.ts.map +1 -1
- package/dest/note_processor/utils/produce_note_daos.js +2 -4
- package/dest/note_processor/utils/produce_note_daos_for_key.d.ts +3 -3
- package/dest/note_processor/utils/produce_note_daos_for_key.d.ts.map +1 -1
- package/dest/note_processor/utils/produce_note_daos_for_key.js +7 -61
- package/dest/pxe_http/pxe_http_server.js +3 -3
- package/dest/pxe_service/error_enriching.d.ts +11 -0
- package/dest/pxe_service/error_enriching.d.ts.map +1 -0
- package/dest/pxe_service/error_enriching.js +68 -0
- package/dest/pxe_service/index.d.ts +1 -0
- package/dest/pxe_service/index.d.ts.map +1 -1
- package/dest/pxe_service/index.js +2 -1
- package/dest/pxe_service/pxe_service.d.ts +1 -1
- package/dest/pxe_service/pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/pxe_service.js +27 -66
- package/dest/simulator_oracle/index.d.ts +17 -1
- package/dest/simulator_oracle/index.d.ts.map +1 -1
- package/dest/simulator_oracle/index.js +40 -1
- package/dest/synchronizer/synchronizer.d.ts +1 -1
- package/dest/synchronizer/synchronizer.d.ts.map +1 -1
- package/dest/synchronizer/synchronizer.js +3 -3
- package/package.json +14 -14
- package/src/database/deferred_note_dao.ts +6 -19
- package/src/database/incoming_note_dao.ts +2 -1
- package/src/database/kv_pxe_database.ts +26 -6
- package/src/database/outgoing_note_dao.ts +2 -1
- package/src/database/pxe_database.ts +8 -4
- package/src/kernel_prover/hints/build_private_kernel_reset_private_inputs.ts +8 -14
- package/src/kernel_prover/kernel_prover.ts +6 -6
- package/src/note_processor/note_processor.ts +89 -88
- package/src/note_processor/utils/add_public_values_to_payload.ts +63 -0
- package/src/note_processor/utils/brute_force_note_info.ts +11 -3
- package/src/note_processor/utils/produce_note_daos.ts +5 -7
- package/src/note_processor/utils/produce_note_daos_for_key.ts +19 -114
- package/src/pxe_http/pxe_http_server.ts +2 -2
- package/src/pxe_service/error_enriching.ts +91 -0
- package/src/pxe_service/index.ts +1 -0
- package/src/pxe_service/pxe_service.ts +29 -78
- package/src/simulator_oracle/index.ts +51 -0
- package/src/synchronizer/synchronizer.ts +2 -2
- package/dest/note_processor/utils/add_nullable_field_to_payload.d.ts +0 -12
- package/dest/note_processor/utils/add_nullable_field_to_payload.d.ts.map +0 -1
- package/dest/note_processor/utils/add_nullable_field_to_payload.js +0 -46
- package/src/note_processor/utils/add_nullable_field_to_payload.ts +0 -67
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { NoteSelector } from '@aztec/foundation/abi';
|
|
1
|
+
import { L1NotePayload, TxHash, UnencryptedTxL2Logs } from '@aztec/circuit-types';
|
|
2
|
+
import { Fr, Point, type PublicKey, Vector } from '@aztec/circuits.js';
|
|
4
3
|
import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
5
4
|
|
|
6
5
|
/**
|
|
@@ -12,14 +11,8 @@ export class DeferredNoteDao {
|
|
|
12
11
|
constructor(
|
|
13
12
|
/** IvpkM or OvpkM (depending on if incoming or outgoing) the note was encrypted with. */
|
|
14
13
|
public publicKey: PublicKey,
|
|
15
|
-
/** The note
|
|
16
|
-
public
|
|
17
|
-
/** The contract address this note is created in. */
|
|
18
|
-
public contractAddress: AztecAddress,
|
|
19
|
-
/** The specific storage location of the note on the contract. */
|
|
20
|
-
public storageSlot: Fr,
|
|
21
|
-
/** The type ID of the note on the contract. */
|
|
22
|
-
public noteTypeId: NoteSelector,
|
|
14
|
+
/** The note payload delivered via L1. */
|
|
15
|
+
public payload: L1NotePayload,
|
|
23
16
|
/** The hash of the tx the note was created in. Equal to the first nullifier */
|
|
24
17
|
public txHash: TxHash,
|
|
25
18
|
/** New note hashes in this transaction, one of which belongs to this note */
|
|
@@ -33,10 +26,7 @@ export class DeferredNoteDao {
|
|
|
33
26
|
toBuffer(): Buffer {
|
|
34
27
|
return serializeToBuffer(
|
|
35
28
|
this.publicKey,
|
|
36
|
-
this.
|
|
37
|
-
this.contractAddress,
|
|
38
|
-
this.storageSlot,
|
|
39
|
-
this.noteTypeId,
|
|
29
|
+
this.payload,
|
|
40
30
|
this.txHash,
|
|
41
31
|
new Vector(this.noteHashes),
|
|
42
32
|
this.dataStartIndexForTx,
|
|
@@ -47,10 +37,7 @@ export class DeferredNoteDao {
|
|
|
47
37
|
const reader = BufferReader.asReader(buffer);
|
|
48
38
|
return new DeferredNoteDao(
|
|
49
39
|
reader.readObject(Point),
|
|
50
|
-
reader.readObject(
|
|
51
|
-
reader.readObject(AztecAddress),
|
|
52
|
-
reader.readObject(Fr),
|
|
53
|
-
reader.readObject(NoteSelector),
|
|
40
|
+
reader.readObject(L1NotePayload),
|
|
54
41
|
reader.readObject(TxHash),
|
|
55
42
|
reader.readVector(Fr),
|
|
56
43
|
reader.readNumber(),
|
|
@@ -41,6 +41,7 @@ export class IncomingNoteDao implements NoteData {
|
|
|
41
41
|
) {}
|
|
42
42
|
|
|
43
43
|
static fromPayloadAndNoteInfo(
|
|
44
|
+
note: Note,
|
|
44
45
|
payload: L1NotePayload,
|
|
45
46
|
noteInfo: NoteInfo,
|
|
46
47
|
dataStartIndexForTx: number,
|
|
@@ -48,7 +49,7 @@ export class IncomingNoteDao implements NoteData {
|
|
|
48
49
|
) {
|
|
49
50
|
const noteHashIndexInTheWholeTree = BigInt(dataStartIndexForTx + noteInfo.noteHashIndex);
|
|
50
51
|
return new IncomingNoteDao(
|
|
51
|
-
|
|
52
|
+
note,
|
|
52
53
|
payload.contractAddress,
|
|
53
54
|
payload.storageSlot,
|
|
54
55
|
payload.noteTypeId,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
} from '@aztec/circuits.js';
|
|
15
15
|
import { type ContractArtifact } from '@aztec/foundation/abi';
|
|
16
16
|
import { toBufferBE } from '@aztec/foundation/bigint-buffer';
|
|
17
|
-
import { Fr
|
|
17
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
18
18
|
import {
|
|
19
19
|
type AztecArray,
|
|
20
20
|
type AztecKVStore,
|
|
@@ -66,6 +66,8 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
66
66
|
#notesByTxHashAndScope: Map<string, AztecMultiMap<string, string>>;
|
|
67
67
|
#notesByIvpkMAndScope: Map<string, AztecMultiMap<string, string>>;
|
|
68
68
|
|
|
69
|
+
#taggingSecretIndexes: AztecMap<string, number>;
|
|
70
|
+
|
|
69
71
|
constructor(private db: AztecKVStore) {
|
|
70
72
|
this.#db = db;
|
|
71
73
|
|
|
@@ -111,6 +113,8 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
111
113
|
this.#notesByTxHashAndScope.set(scope, db.openMultiMap(`${scope}:notes_by_tx_hash`));
|
|
112
114
|
this.#notesByIvpkMAndScope.set(scope, db.openMultiMap(`${scope}:notes_by_ivpk_m`));
|
|
113
115
|
}
|
|
116
|
+
|
|
117
|
+
this.#taggingSecretIndexes = db.openMap('tagging_secret_indices');
|
|
114
118
|
}
|
|
115
119
|
|
|
116
120
|
public async getContract(
|
|
@@ -215,7 +219,7 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
215
219
|
const newLength = await this.#deferredNotes.push(...deferredNotes.map(note => note.toBuffer()));
|
|
216
220
|
for (const [index, note] of deferredNotes.entries()) {
|
|
217
221
|
const noteId = newLength - deferredNotes.length + index;
|
|
218
|
-
await this.#deferredNotesByContract.set(note.contractAddress.toString(), noteId);
|
|
222
|
+
await this.#deferredNotesByContract.set(note.payload.contractAddress.toString(), noteId);
|
|
219
223
|
}
|
|
220
224
|
}
|
|
221
225
|
|
|
@@ -545,12 +549,12 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
545
549
|
return Promise.resolve(Array.from(this.#addresses).map(v => CompleteAddress.fromBuffer(v)));
|
|
546
550
|
}
|
|
547
551
|
|
|
548
|
-
|
|
549
|
-
return this.#syncedBlockPerPublicKey.get(
|
|
552
|
+
getSynchedBlockNumberForAccount(account: AztecAddress): number | undefined {
|
|
553
|
+
return this.#syncedBlockPerPublicKey.get(account.toString());
|
|
550
554
|
}
|
|
551
555
|
|
|
552
|
-
|
|
553
|
-
return this.#syncedBlockPerPublicKey.set(
|
|
556
|
+
setSynchedBlockNumberForAccount(account: AztecAddress, blockNumber: number): Promise<void> {
|
|
557
|
+
return this.#syncedBlockPerPublicKey.set(account.toString(), blockNumber);
|
|
554
558
|
}
|
|
555
559
|
|
|
556
560
|
async estimateSize(): Promise<number> {
|
|
@@ -572,4 +576,20 @@ export class KVPxeDatabase implements PxeDatabase {
|
|
|
572
576
|
|
|
573
577
|
return incomingNotesSize + outgoingNotesSize + treeRootsSize + authWitsSize + addressesSize;
|
|
574
578
|
}
|
|
579
|
+
|
|
580
|
+
async incrementTaggingSecretsIndexes(appTaggingSecrets: Fr[]): Promise<void> {
|
|
581
|
+
const indexes = await this.getTaggingSecretsIndexes(appTaggingSecrets);
|
|
582
|
+
await this.db.transaction(() => {
|
|
583
|
+
indexes.forEach(index => {
|
|
584
|
+
const nextIndex = index ? index + 1 : 1;
|
|
585
|
+
void this.#taggingSecretIndexes.set(appTaggingSecrets.toString(), nextIndex);
|
|
586
|
+
});
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
getTaggingSecretsIndexes(appTaggingSecrets: Fr[]): Promise<number[]> {
|
|
591
|
+
return this.db.transaction(() =>
|
|
592
|
+
appTaggingSecrets.map(secret => this.#taggingSecretIndexes.get(secret.toString()) ?? 0),
|
|
593
|
+
);
|
|
594
|
+
}
|
|
575
595
|
}
|
|
@@ -35,6 +35,7 @@ export class OutgoingNoteDao {
|
|
|
35
35
|
) {}
|
|
36
36
|
|
|
37
37
|
static fromPayloadAndNoteInfo(
|
|
38
|
+
note: Note,
|
|
38
39
|
payload: L1NotePayload,
|
|
39
40
|
noteInfo: NoteInfo,
|
|
40
41
|
dataStartIndexForTx: number,
|
|
@@ -42,7 +43,7 @@ export class OutgoingNoteDao {
|
|
|
42
43
|
) {
|
|
43
44
|
const noteHashIndexInTheWholeTree = BigInt(dataStartIndexForTx + noteInfo.noteHashIndex);
|
|
44
45
|
return new OutgoingNoteDao(
|
|
45
|
-
|
|
46
|
+
note,
|
|
46
47
|
payload.contractAddress,
|
|
47
48
|
payload.storageSlot,
|
|
48
49
|
payload.noteTypeId,
|
|
@@ -169,20 +169,24 @@ export interface PxeDatabase extends ContractArtifactDatabase, ContractInstanceD
|
|
|
169
169
|
|
|
170
170
|
/**
|
|
171
171
|
* Updates up to which block number we have processed notes for a given public key.
|
|
172
|
-
* @param
|
|
172
|
+
* @param account - The account to set the synched block number for.
|
|
173
173
|
* @param blockNumber - The block number to set.
|
|
174
174
|
*/
|
|
175
|
-
|
|
175
|
+
setSynchedBlockNumberForAccount(account: AztecAddress, blockNumber: number): Promise<void>;
|
|
176
176
|
|
|
177
177
|
/**
|
|
178
178
|
* Get the synched block number for a given public key.
|
|
179
|
-
* @param
|
|
179
|
+
* @param account - The account to get the synched block number for.
|
|
180
180
|
*/
|
|
181
|
-
|
|
181
|
+
getSynchedBlockNumberForAccount(account: AztecAddress): number | undefined;
|
|
182
182
|
|
|
183
183
|
/**
|
|
184
184
|
* Returns the estimated size in bytes of this db.
|
|
185
185
|
* @returns The estimated size in bytes of this db.
|
|
186
186
|
*/
|
|
187
187
|
estimateSize(): Promise<number>;
|
|
188
|
+
|
|
189
|
+
getTaggingSecretsIndexes(appTaggingSecrets: Fr[]): Promise<number[]>;
|
|
190
|
+
|
|
191
|
+
incrementTaggingSecretsIndexes(appTaggingSecrets: Fr[]): Promise<void>;
|
|
188
192
|
}
|
|
@@ -48,11 +48,7 @@ function collectNestedReadRequests(
|
|
|
48
48
|
return collectNested(executionStack, executionResult => {
|
|
49
49
|
const nonEmptyReadRequests = getNonEmptyItems(extractReadRequests(executionResult));
|
|
50
50
|
return nonEmptyReadRequests.map(
|
|
51
|
-
readRequest =>
|
|
52
|
-
new ScopedReadRequest(
|
|
53
|
-
readRequest,
|
|
54
|
-
executionResult.callStackItem.publicInputs.callContext.storageContractAddress,
|
|
55
|
-
),
|
|
51
|
+
readRequest => new ScopedReadRequest(readRequest, executionResult.publicInputs.callContext.contractAddress),
|
|
56
52
|
);
|
|
57
53
|
});
|
|
58
54
|
}
|
|
@@ -117,7 +113,7 @@ export class PrivateKernelResetPrivateInputsBuilder {
|
|
|
117
113
|
MAX_NULLIFIERS_PER_TX,
|
|
118
114
|
() => new TransientDataIndexHint(MAX_NULLIFIERS_PER_TX, MAX_NOTE_HASHES_PER_TX),
|
|
119
115
|
);
|
|
120
|
-
this.nextIteration = executionStack[this.executionStack.length - 1]?.
|
|
116
|
+
this.nextIteration = executionStack[this.executionStack.length - 1]?.publicInputs;
|
|
121
117
|
}
|
|
122
118
|
|
|
123
119
|
needsReset(): boolean {
|
|
@@ -244,10 +240,9 @@ export class PrivateKernelResetPrivateInputsBuilder {
|
|
|
244
240
|
}
|
|
245
241
|
|
|
246
242
|
const futureNoteHashes = collectNested(this.executionStack, executionResult => {
|
|
247
|
-
const nonEmptyNoteHashes = getNonEmptyItems(executionResult.
|
|
243
|
+
const nonEmptyNoteHashes = getNonEmptyItems(executionResult.publicInputs.noteHashes);
|
|
248
244
|
return nonEmptyNoteHashes.map(
|
|
249
|
-
noteHash =>
|
|
250
|
-
new ScopedNoteHash(noteHash, executionResult.callStackItem.publicInputs.callContext.storageContractAddress),
|
|
245
|
+
noteHash => new ScopedNoteHash(noteHash, executionResult.publicInputs.callContext.contractAddress),
|
|
251
246
|
);
|
|
252
247
|
});
|
|
253
248
|
|
|
@@ -297,10 +292,9 @@ export class PrivateKernelResetPrivateInputsBuilder {
|
|
|
297
292
|
}
|
|
298
293
|
|
|
299
294
|
const futureNullifiers = collectNested(this.executionStack, executionResult => {
|
|
300
|
-
const nonEmptyNullifiers = getNonEmptyItems(executionResult.
|
|
295
|
+
const nonEmptyNullifiers = getNonEmptyItems(executionResult.publicInputs.nullifiers);
|
|
301
296
|
return nonEmptyNullifiers.map(
|
|
302
|
-
nullifier =>
|
|
303
|
-
new ScopedNullifier(nullifier, executionResult.callStackItem.publicInputs.callContext.storageContractAddress),
|
|
297
|
+
nullifier => new ScopedNullifier(nullifier, executionResult.publicInputs.callContext.contractAddress),
|
|
304
298
|
);
|
|
305
299
|
});
|
|
306
300
|
|
|
@@ -376,11 +370,11 @@ export class PrivateKernelResetPrivateInputsBuilder {
|
|
|
376
370
|
|
|
377
371
|
const futureNoteHashReads = collectNestedReadRequests(
|
|
378
372
|
this.executionStack,
|
|
379
|
-
executionResult => executionResult.
|
|
373
|
+
executionResult => executionResult.publicInputs.noteHashReadRequests,
|
|
380
374
|
);
|
|
381
375
|
const futureNullifierReads = collectNestedReadRequests(
|
|
382
376
|
this.executionStack,
|
|
383
|
-
executionResult => executionResult.
|
|
377
|
+
executionResult => executionResult.publicInputs.nullifierReadRequests,
|
|
384
378
|
);
|
|
385
379
|
if (this.nextIteration) {
|
|
386
380
|
// If it's not the final reset, only one dimension will be reset at a time.
|
|
@@ -114,8 +114,8 @@ export class KernelProver {
|
|
|
114
114
|
executionStack.push(...[...currentExecution.nestedExecutions].reverse());
|
|
115
115
|
|
|
116
116
|
const functionName = await this.oracle.getDebugFunctionName(
|
|
117
|
-
currentExecution.
|
|
118
|
-
currentExecution.
|
|
117
|
+
currentExecution.publicInputs.callContext.contractAddress,
|
|
118
|
+
currentExecution.publicInputs.callContext.functionSelector,
|
|
119
119
|
);
|
|
120
120
|
|
|
121
121
|
const appVk = await this.proofCreator.computeAppCircuitVerificationKey(currentExecution.acir, functionName);
|
|
@@ -201,12 +201,12 @@ export class KernelProver {
|
|
|
201
201
|
return tailOutput;
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
-
private async createPrivateCallData({
|
|
205
|
-
const { contractAddress,
|
|
204
|
+
private async createPrivateCallData({ publicInputs }: PrivateExecutionResult, vk: VerificationKeyAsFields) {
|
|
205
|
+
const { contractAddress, functionSelector } = publicInputs.callContext;
|
|
206
206
|
|
|
207
207
|
const functionLeafMembershipWitness = await this.oracle.getFunctionMembershipWitness(
|
|
208
208
|
contractAddress,
|
|
209
|
-
|
|
209
|
+
functionSelector,
|
|
210
210
|
);
|
|
211
211
|
const { contractClassId, publicKeys, saltedInitializationHash } = await this.oracle.getContractAddressPreimage(
|
|
212
212
|
contractAddress,
|
|
@@ -223,7 +223,7 @@ export class KernelProver {
|
|
|
223
223
|
: makeTuple(PROTOCOL_CONTRACT_TREE_HEIGHT, Fr.zero);
|
|
224
224
|
|
|
225
225
|
return PrivateCallData.from({
|
|
226
|
-
|
|
226
|
+
publicInputs,
|
|
227
227
|
vk,
|
|
228
228
|
publicKeys,
|
|
229
229
|
contractClassArtifactHash,
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { type AztecNode, L1NotePayload, type L2Block } from '@aztec/circuit-types';
|
|
2
2
|
import { type NoteProcessorStats } from '@aztec/circuit-types/stats';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
type CompleteAddress,
|
|
5
|
+
INITIAL_L2_BLOCK_NUM,
|
|
6
|
+
MAX_NOTE_HASHES_PER_TX,
|
|
7
|
+
computeAddressSecret,
|
|
8
|
+
} from '@aztec/circuits.js';
|
|
4
9
|
import { type Fr } from '@aztec/foundation/fields';
|
|
5
10
|
import { type Logger, createDebugLogger } from '@aztec/foundation/log';
|
|
6
11
|
import { Timer } from '@aztec/foundation/timer';
|
|
@@ -48,10 +53,6 @@ export class NoteProcessor {
|
|
|
48
53
|
|
|
49
54
|
private constructor(
|
|
50
55
|
public readonly account: CompleteAddress,
|
|
51
|
-
/** The public counterpart to the secret key to be used in the decryption of incoming note logs. */
|
|
52
|
-
private readonly ivpkM: PublicKey,
|
|
53
|
-
/** The public counterpart to the secret key to be used in the decryption of outgoing note logs. */
|
|
54
|
-
private readonly ovpkM: PublicKey,
|
|
55
56
|
private keyStore: KeyStore,
|
|
56
57
|
private db: PxeDatabase,
|
|
57
58
|
private node: AztecNode,
|
|
@@ -60,7 +61,7 @@ export class NoteProcessor {
|
|
|
60
61
|
private log: Logger,
|
|
61
62
|
) {}
|
|
62
63
|
|
|
63
|
-
public static
|
|
64
|
+
public static create(
|
|
64
65
|
account: CompleteAddress,
|
|
65
66
|
keyStore: KeyStore,
|
|
66
67
|
db: PxeDatabase,
|
|
@@ -69,10 +70,7 @@ export class NoteProcessor {
|
|
|
69
70
|
simulator = getAcirSimulator(db, node, keyStore),
|
|
70
71
|
log = createDebugLogger('aztec:note_processor'),
|
|
71
72
|
) {
|
|
72
|
-
|
|
73
|
-
const ovpkM = await keyStore.getMasterOutgoingViewingPublicKey(account.address);
|
|
74
|
-
|
|
75
|
-
return new NoteProcessor(account, ivpkM, ovpkM, keyStore, db, node, startingBlock, simulator, log);
|
|
73
|
+
return new NoteProcessor(account, keyStore, db, node, startingBlock, simulator, log);
|
|
76
74
|
}
|
|
77
75
|
|
|
78
76
|
/**
|
|
@@ -95,7 +93,7 @@ export class NoteProcessor {
|
|
|
95
93
|
}
|
|
96
94
|
|
|
97
95
|
private getSyncedToBlock(): number {
|
|
98
|
-
return this.db.
|
|
96
|
+
return this.db.getSynchedBlockNumberForAccount(this.account.address) ?? this.startingBlock - 1;
|
|
99
97
|
}
|
|
100
98
|
|
|
101
99
|
/**
|
|
@@ -114,13 +112,17 @@ export class NoteProcessor {
|
|
|
114
112
|
const deferredIncomingNotes: DeferredNoteDao[] = [];
|
|
115
113
|
const deferredOutgoingNotes: DeferredNoteDao[] = [];
|
|
116
114
|
|
|
117
|
-
const ivskM = await this.keyStore.getMasterSecretKey(this.
|
|
118
|
-
const
|
|
115
|
+
const ivskM = await this.keyStore.getMasterSecretKey(this.account.publicKeys.masterIncomingViewingPublicKey);
|
|
116
|
+
const addressSecret = computeAddressSecret(this.account.getPreaddress(), ivskM);
|
|
117
|
+
|
|
118
|
+
const ovskM = await this.keyStore.getMasterSecretKey(this.account.publicKeys.masterOutgoingViewingPublicKey);
|
|
119
119
|
|
|
120
120
|
// Iterate over both blocks and encrypted logs.
|
|
121
121
|
for (const block of blocks) {
|
|
122
122
|
this.stats.blocks++;
|
|
123
|
-
const { txLogs } = block.body.noteEncryptedLogs;
|
|
123
|
+
const { txLogs: encryptedTxLogs } = block.body.noteEncryptedLogs;
|
|
124
|
+
const { txLogs: unencryptedTxLogs } = block.body.unencryptedLogs;
|
|
125
|
+
|
|
124
126
|
const dataStartIndexForBlock =
|
|
125
127
|
block.header.state.partial.noteHashTree.nextAvailableLeafIndex -
|
|
126
128
|
block.body.numberOfTxsIncludingPadded * MAX_NOTE_HASHES_PER_TX;
|
|
@@ -131,65 +133,72 @@ export class NoteProcessor {
|
|
|
131
133
|
const outgoingNotes: OutgoingNoteDao[] = [];
|
|
132
134
|
|
|
133
135
|
// Iterate over all the encrypted logs and try decrypting them. If successful, store the note.
|
|
134
|
-
for (let indexOfTxInABlock = 0; indexOfTxInABlock <
|
|
136
|
+
for (let indexOfTxInABlock = 0; indexOfTxInABlock < encryptedTxLogs.length; ++indexOfTxInABlock) {
|
|
135
137
|
this.stats.txs++;
|
|
136
138
|
const dataStartIndexForTx = dataStartIndexForBlock + indexOfTxInABlock * MAX_NOTE_HASHES_PER_TX;
|
|
137
139
|
const noteHashes = block.body.txEffects[indexOfTxInABlock].noteHashes;
|
|
138
140
|
// Note: Each tx generates a `TxL2Logs` object and for this reason we can rely on its index corresponding
|
|
139
141
|
// to the index of a tx in a block.
|
|
140
|
-
const
|
|
142
|
+
const encryptedTxFunctionLogs = encryptedTxLogs[indexOfTxInABlock].functionLogs;
|
|
143
|
+
const unencryptedTxFunctionLogs = unencryptedTxLogs[indexOfTxInABlock].functionLogs;
|
|
141
144
|
const excludedIndices: Set<number> = new Set();
|
|
142
|
-
for (const functionLogs of txFunctionLogs) {
|
|
143
|
-
for (const log of functionLogs.logs) {
|
|
144
|
-
this.stats.seen++;
|
|
145
|
-
const incomingNotePayload = L1NotePayload.decryptAsIncoming(log, ivskM);
|
|
146
|
-
const outgoingNotePayload = L1NotePayload.decryptAsOutgoing(log, ovskM);
|
|
147
|
-
|
|
148
|
-
if (incomingNotePayload || outgoingNotePayload) {
|
|
149
|
-
if (incomingNotePayload && outgoingNotePayload && !incomingNotePayload.equals(outgoingNotePayload)) {
|
|
150
|
-
throw new Error(
|
|
151
|
-
`Incoming and outgoing note payloads do not match. Incoming: ${JSON.stringify(
|
|
152
|
-
incomingNotePayload,
|
|
153
|
-
)}, Outgoing: ${JSON.stringify(outgoingNotePayload)}`,
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const payload = incomingNotePayload || outgoingNotePayload;
|
|
158
|
-
|
|
159
|
-
const txEffect = block.body.txEffects[indexOfTxInABlock];
|
|
160
|
-
const { incomingNote, outgoingNote, incomingDeferredNote, outgoingDeferredNote } = await produceNoteDaos(
|
|
161
|
-
this.simulator,
|
|
162
|
-
this.db,
|
|
163
|
-
incomingNotePayload ? this.ivpkM : undefined,
|
|
164
|
-
outgoingNotePayload ? this.ovpkM : undefined,
|
|
165
|
-
payload!,
|
|
166
|
-
txEffect.txHash,
|
|
167
|
-
noteHashes,
|
|
168
|
-
dataStartIndexForTx,
|
|
169
|
-
excludedIndices,
|
|
170
|
-
this.log,
|
|
171
|
-
txEffect.unencryptedLogs,
|
|
172
|
-
);
|
|
173
|
-
|
|
174
|
-
if (incomingNote) {
|
|
175
|
-
incomingNotes.push(incomingNote);
|
|
176
|
-
this.stats.decryptedIncoming++;
|
|
177
|
-
}
|
|
178
|
-
if (outgoingNote) {
|
|
179
|
-
outgoingNotes.push(outgoingNote);
|
|
180
|
-
this.stats.decryptedOutgoing++;
|
|
181
|
-
}
|
|
182
|
-
if (incomingDeferredNote) {
|
|
183
|
-
deferredIncomingNotes.push(incomingDeferredNote);
|
|
184
|
-
this.stats.deferredIncoming++;
|
|
185
|
-
}
|
|
186
|
-
if (outgoingDeferredNote) {
|
|
187
|
-
deferredOutgoingNotes.push(outgoingDeferredNote);
|
|
188
|
-
this.stats.deferredOutgoing++;
|
|
189
|
-
}
|
|
190
145
|
|
|
191
|
-
|
|
192
|
-
|
|
146
|
+
// We iterate over both encrypted and unencrypted logs to decrypt the notes since partial notes are passed
|
|
147
|
+
// via the unencrypted logs stream.
|
|
148
|
+
for (const txFunctionLogs of [encryptedTxFunctionLogs, unencryptedTxFunctionLogs]) {
|
|
149
|
+
for (const functionLogs of txFunctionLogs) {
|
|
150
|
+
for (const unprocessedLog of functionLogs.logs) {
|
|
151
|
+
this.stats.seen++;
|
|
152
|
+
const incomingNotePayload = L1NotePayload.decryptAsIncoming(unprocessedLog.data, addressSecret);
|
|
153
|
+
const outgoingNotePayload = L1NotePayload.decryptAsOutgoing(unprocessedLog.data, ovskM);
|
|
154
|
+
|
|
155
|
+
if (incomingNotePayload || outgoingNotePayload) {
|
|
156
|
+
if (incomingNotePayload && outgoingNotePayload && !incomingNotePayload.equals(outgoingNotePayload)) {
|
|
157
|
+
throw new Error(
|
|
158
|
+
`Incoming and outgoing note payloads do not match. Incoming: ${JSON.stringify(
|
|
159
|
+
incomingNotePayload,
|
|
160
|
+
)}, Outgoing: ${JSON.stringify(outgoingNotePayload)}`,
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const payload = incomingNotePayload || outgoingNotePayload;
|
|
165
|
+
|
|
166
|
+
const txEffect = block.body.txEffects[indexOfTxInABlock];
|
|
167
|
+
const { incomingNote, outgoingNote, incomingDeferredNote, outgoingDeferredNote } =
|
|
168
|
+
await produceNoteDaos(
|
|
169
|
+
this.simulator,
|
|
170
|
+
this.db,
|
|
171
|
+
incomingNotePayload ? this.account.publicKeys.masterIncomingViewingPublicKey : undefined,
|
|
172
|
+
outgoingNotePayload ? this.account.publicKeys.masterOutgoingViewingPublicKey : undefined,
|
|
173
|
+
payload!,
|
|
174
|
+
txEffect.txHash,
|
|
175
|
+
noteHashes,
|
|
176
|
+
dataStartIndexForTx,
|
|
177
|
+
excludedIndices,
|
|
178
|
+
this.log,
|
|
179
|
+
txEffect.unencryptedLogs,
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
if (incomingNote) {
|
|
183
|
+
incomingNotes.push(incomingNote);
|
|
184
|
+
this.stats.decryptedIncoming++;
|
|
185
|
+
}
|
|
186
|
+
if (outgoingNote) {
|
|
187
|
+
outgoingNotes.push(outgoingNote);
|
|
188
|
+
this.stats.decryptedOutgoing++;
|
|
189
|
+
}
|
|
190
|
+
if (incomingDeferredNote) {
|
|
191
|
+
deferredIncomingNotes.push(incomingDeferredNote);
|
|
192
|
+
this.stats.deferredIncoming++;
|
|
193
|
+
}
|
|
194
|
+
if (outgoingDeferredNote) {
|
|
195
|
+
deferredOutgoingNotes.push(outgoingDeferredNote);
|
|
196
|
+
this.stats.deferredOutgoing++;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (incomingNote == undefined && outgoingNote == undefined && incomingDeferredNote == undefined) {
|
|
200
|
+
this.stats.failed++;
|
|
201
|
+
}
|
|
193
202
|
}
|
|
194
203
|
}
|
|
195
204
|
}
|
|
@@ -207,7 +216,7 @@ export class NoteProcessor {
|
|
|
207
216
|
await this.processDeferredNotes(deferredIncomingNotes, deferredOutgoingNotes);
|
|
208
217
|
|
|
209
218
|
const syncedToBlock = blocks[blocks.length - 1].number;
|
|
210
|
-
await this.db.
|
|
219
|
+
await this.db.setSynchedBlockNumberForAccount(this.account.address, syncedToBlock);
|
|
211
220
|
|
|
212
221
|
this.log.debug(`Synched block ${syncedToBlock}`);
|
|
213
222
|
}
|
|
@@ -241,7 +250,10 @@ export class NoteProcessor {
|
|
|
241
250
|
const nullifiers: Fr[] = blocksAndNotes.flatMap(b =>
|
|
242
251
|
b.block.body.txEffects.flatMap(txEffect => txEffect.nullifiers),
|
|
243
252
|
);
|
|
244
|
-
const removedNotes = await this.db.removeNullifiedNotes(
|
|
253
|
+
const removedNotes = await this.db.removeNullifiedNotes(
|
|
254
|
+
nullifiers,
|
|
255
|
+
this.account.publicKeys.masterIncomingViewingPublicKey,
|
|
256
|
+
);
|
|
245
257
|
removedNotes.forEach(noteDao => {
|
|
246
258
|
this.log.verbose(
|
|
247
259
|
`Removed note for contract ${noteDao.contractAddress} at slot ${
|
|
@@ -265,15 +277,15 @@ export class NoteProcessor {
|
|
|
265
277
|
await this.db.addDeferredNotes([...deferredIncomingNotes, ...deferredOutgoingNotes]);
|
|
266
278
|
deferredIncomingNotes.forEach(noteDao => {
|
|
267
279
|
this.log.verbose(
|
|
268
|
-
`Deferred incoming note for contract ${noteDao.contractAddress} at slot ${
|
|
269
|
-
noteDao.storageSlot
|
|
280
|
+
`Deferred incoming note for contract ${noteDao.payload.contractAddress} at slot ${
|
|
281
|
+
noteDao.payload.storageSlot
|
|
270
282
|
} in tx ${noteDao.txHash.toString()}`,
|
|
271
283
|
);
|
|
272
284
|
});
|
|
273
285
|
deferredOutgoingNotes.forEach(noteDao => {
|
|
274
286
|
this.log.verbose(
|
|
275
|
-
`Deferred outgoing note for contract ${noteDao.contractAddress} at slot ${
|
|
276
|
-
noteDao.storageSlot
|
|
287
|
+
`Deferred outgoing note for contract ${noteDao.payload.contractAddress} at slot ${
|
|
288
|
+
noteDao.payload.storageSlot
|
|
277
289
|
} in tx ${noteDao.txHash.toString()}`,
|
|
278
290
|
);
|
|
279
291
|
});
|
|
@@ -298,21 +310,10 @@ export class NoteProcessor {
|
|
|
298
310
|
const outgoingNotes: OutgoingNoteDao[] = [];
|
|
299
311
|
|
|
300
312
|
for (const deferredNote of deferredNoteDaos) {
|
|
301
|
-
const {
|
|
302
|
-
publicKey,
|
|
303
|
-
note,
|
|
304
|
-
contractAddress,
|
|
305
|
-
storageSlot,
|
|
306
|
-
noteTypeId,
|
|
307
|
-
txHash,
|
|
308
|
-
noteHashes,
|
|
309
|
-
dataStartIndexForTx,
|
|
310
|
-
unencryptedLogs,
|
|
311
|
-
} = deferredNote;
|
|
312
|
-
const payload = new L1NotePayload(note, contractAddress, storageSlot, noteTypeId);
|
|
313
|
+
const { publicKey, payload, txHash, noteHashes, dataStartIndexForTx, unencryptedLogs } = deferredNote;
|
|
313
314
|
|
|
314
|
-
const isIncoming = publicKey.equals(this.
|
|
315
|
-
const isOutgoing = publicKey.equals(this.
|
|
315
|
+
const isIncoming = publicKey.equals(this.account.publicKeys.masterIncomingViewingPublicKey);
|
|
316
|
+
const isOutgoing = publicKey.equals(this.account.publicKeys.masterOutgoingViewingPublicKey);
|
|
316
317
|
|
|
317
318
|
if (!isIncoming && !isOutgoing) {
|
|
318
319
|
// The note does not belong to this note processor
|
|
@@ -322,8 +323,8 @@ export class NoteProcessor {
|
|
|
322
323
|
const { incomingNote, outgoingNote } = await produceNoteDaos(
|
|
323
324
|
this.simulator,
|
|
324
325
|
this.db,
|
|
325
|
-
isIncoming ? this.
|
|
326
|
-
isOutgoing ? this.
|
|
326
|
+
isIncoming ? this.account.publicKeys.masterIncomingViewingPublicKey : undefined,
|
|
327
|
+
isOutgoing ? this.account.publicKeys.masterOutgoingViewingPublicKey : undefined,
|
|
327
328
|
payload,
|
|
328
329
|
txHash,
|
|
329
330
|
noteHashes,
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type L1NotePayload, Note } from '@aztec/circuit-types';
|
|
2
|
+
import { ContractNotFoundError } from '@aztec/simulator';
|
|
3
|
+
|
|
4
|
+
import { type PxeDatabase } from '../../database/pxe_database.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Merges privately and publicly delivered note values.
|
|
8
|
+
* @param db - PXE database used to fetch contract instance and artifact.
|
|
9
|
+
* @param payload - Payload corresponding to the note.
|
|
10
|
+
* @returns Note payload with public fields added.
|
|
11
|
+
*/
|
|
12
|
+
export async function getOrderedNoteItems(
|
|
13
|
+
db: PxeDatabase,
|
|
14
|
+
{ contractAddress, noteTypeId, privateNoteValues, publicNoteValues }: L1NotePayload,
|
|
15
|
+
): Promise<Note> {
|
|
16
|
+
if (publicNoteValues.length === 0) {
|
|
17
|
+
return new Note(privateNoteValues);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const instance = await db.getContractInstance(contractAddress);
|
|
21
|
+
if (!instance) {
|
|
22
|
+
throw new ContractNotFoundError(
|
|
23
|
+
`Could not find instance for ${contractAddress.toString()}. This should never happen here as the partial notes flow should be triggered only for non-deferred notes.`,
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const artifact = await db.getContractArtifact(instance.contractClassId);
|
|
28
|
+
if (!artifact) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
`Could not find artifact for contract class ${instance.contractClassId.toString()}. This should never happen here as the partial notes flow should be triggered only for non-deferred notes.`,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const noteFields = Object.values(artifact.notes).find(note => note.id.equals(noteTypeId))?.fields;
|
|
35
|
+
|
|
36
|
+
if (!noteFields) {
|
|
37
|
+
throw new Error(`Could not find note fields for note type ${noteTypeId.toString()}.`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// We sort note fields by index so that we can iterate over them in order.
|
|
41
|
+
noteFields.sort((a, b) => a.index - b.index);
|
|
42
|
+
|
|
43
|
+
// Now we insert the public fields into the note based on its indices defined in the ABI.
|
|
44
|
+
const modifiedNoteItems = privateNoteValues;
|
|
45
|
+
let indexInPublicValues = 0;
|
|
46
|
+
for (let i = 0; i < noteFields.length; i++) {
|
|
47
|
+
const noteField = noteFields[i];
|
|
48
|
+
if (noteField.nullable) {
|
|
49
|
+
if (i == noteFields.length - 1) {
|
|
50
|
+
// We are processing the last field so we simply insert the rest of the public fields at the end
|
|
51
|
+
modifiedNoteItems.push(...publicNoteValues.slice(indexInPublicValues));
|
|
52
|
+
} else {
|
|
53
|
+
const noteFieldLength = noteFields[i + 1].index - noteField.index;
|
|
54
|
+
const publicValuesToInsert = publicNoteValues.slice(indexInPublicValues, indexInPublicValues + noteFieldLength);
|
|
55
|
+
indexInPublicValues += noteFieldLength;
|
|
56
|
+
// Now we insert the public fields at the note field index
|
|
57
|
+
modifiedNoteItems.splice(noteField.index, 0, ...publicValuesToInsert);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return new Note(modifiedNoteItems);
|
|
63
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type Note, type TxHash } from '@aztec/circuit-types';
|
|
2
|
+
import { type AztecAddress } from '@aztec/circuits.js';
|
|
2
3
|
import { computeNoteHashNonce, siloNullifier } from '@aztec/circuits.js/hash';
|
|
4
|
+
import { type NoteSelector } from '@aztec/foundation/abi';
|
|
3
5
|
import { Fr } from '@aztec/foundation/fields';
|
|
4
6
|
import { type AcirSimulator } from '@aztec/simulator';
|
|
5
7
|
|
|
@@ -18,7 +20,10 @@ export interface NoteInfo {
|
|
|
18
20
|
* @remarks This method assists in identifying spent notes in the note hash tree.
|
|
19
21
|
* @param siloedNoteHashes - Note hashes in the tx. One of them should correspond to the note we are looking for
|
|
20
22
|
* @param txHash - Hash of a tx the note was emitted in.
|
|
21
|
-
* @param
|
|
23
|
+
* @param contractAddress - Address of the contract the note was emitted in.
|
|
24
|
+
* @param storageSlot - Storage slot of the note.
|
|
25
|
+
* @param noteTypeId - Type of the note.
|
|
26
|
+
* @param note - Note items.
|
|
22
27
|
* @param excludedIndices - Indices that have been assigned a note in the same tx. Notes in a tx can have the same
|
|
23
28
|
* l1NotePayload. We need to find a different index for each replicate.
|
|
24
29
|
* @param computeNullifier - A flag indicating whether to compute the nullifier or just return 0.
|
|
@@ -29,7 +34,10 @@ export async function bruteForceNoteInfo(
|
|
|
29
34
|
simulator: AcirSimulator,
|
|
30
35
|
siloedNoteHashes: Fr[],
|
|
31
36
|
txHash: TxHash,
|
|
32
|
-
|
|
37
|
+
contractAddress: AztecAddress,
|
|
38
|
+
storageSlot: Fr,
|
|
39
|
+
noteTypeId: NoteSelector,
|
|
40
|
+
note: Note,
|
|
33
41
|
excludedIndices: Set<number>,
|
|
34
42
|
computeNullifier: boolean,
|
|
35
43
|
): Promise<NoteInfo> {
|