@aztec/pxe 0.55.1 → 0.57.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/bin/index.js +0 -0
- package/dest/database/deferred_note_dao.d.ts +6 -2
- package/dest/database/deferred_note_dao.d.ts.map +1 -1
- package/dest/database/deferred_note_dao.js +8 -5
- package/dest/database/incoming_note_dao.d.ts +3 -1
- package/dest/database/incoming_note_dao.d.ts.map +1 -1
- package/dest/database/incoming_note_dao.js +5 -1
- package/dest/database/kv_pxe_database.d.ts.map +1 -1
- package/dest/database/kv_pxe_database.js +3 -2
- package/dest/database/outgoing_note_dao.d.ts +3 -1
- package/dest/database/outgoing_note_dao.d.ts.map +1 -1
- package/dest/database/outgoing_note_dao.js +5 -1
- package/dest/kernel_oracle/index.d.ts +1 -1
- package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.d.ts +28 -0
- package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.d.ts.map +1 -0
- package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.js +260 -0
- package/dest/kernel_prover/hints/index.d.ts +1 -2
- package/dest/kernel_prover/hints/index.d.ts.map +1 -1
- package/dest/kernel_prover/hints/index.js +2 -3
- package/dest/kernel_prover/kernel_prover.d.ts +2 -4
- package/dest/kernel_prover/kernel_prover.d.ts.map +1 -1
- package/dest/kernel_prover/kernel_prover.js +26 -25
- package/dest/kernel_prover/test/test_circuit_prover.d.ts +2 -3
- package/dest/kernel_prover/test/test_circuit_prover.d.ts.map +1 -1
- package/dest/kernel_prover/test/test_circuit_prover.js +8 -11
- package/dest/note_processor/note_processor.d.ts.map +1 -1
- package/dest/note_processor/note_processor.js +13 -15
- package/dest/note_processor/utils/add_nullable_field_to_payload.d.ts +12 -0
- package/dest/note_processor/utils/add_nullable_field_to_payload.d.ts.map +1 -0
- package/dest/note_processor/utils/add_nullable_field_to_payload.js +46 -0
- package/dest/note_processor/utils/brute_force_note_info.d.ts +26 -0
- package/dest/note_processor/utils/brute_force_note_info.d.ts.map +1 -0
- package/dest/note_processor/utils/brute_force_note_info.js +52 -0
- package/dest/note_processor/utils/index.d.ts +3 -0
- package/dest/note_processor/utils/index.d.ts.map +1 -0
- package/dest/note_processor/utils/index.js +2 -0
- package/dest/note_processor/{produce_note_dao.d.ts → utils/produce_note_daos.d.ts} +12 -8
- package/dest/note_processor/utils/produce_note_daos.d.ts.map +1 -0
- package/dest/note_processor/utils/produce_note_daos.js +53 -0
- package/dest/note_processor/utils/produce_note_daos_for_key.d.ts +9 -0
- package/dest/note_processor/utils/produce_note_daos_for_key.d.ts.map +1 -0
- package/dest/note_processor/utils/produce_note_daos_for_key.js +80 -0
- package/dest/pxe_http/pxe_http_server.d.ts.map +1 -1
- package/dest/pxe_http/pxe_http_server.js +12 -4
- package/dest/pxe_service/create_pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/create_pxe_service.js +1 -3
- package/dest/pxe_service/pxe_service.d.ts +8 -8
- package/dest/pxe_service/pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/pxe_service.js +39 -56
- package/package.json +17 -14
- package/src/database/deferred_note_dao.ts +5 -1
- package/src/database/incoming_note_dao.ts +24 -1
- package/src/database/kv_pxe_database.ts +3 -1
- package/src/database/outgoing_note_dao.ts +23 -1
- package/src/kernel_prover/hints/build_private_kernel_reset_private_inputs.ts +467 -0
- package/src/kernel_prover/hints/index.ts +1 -2
- package/src/kernel_prover/kernel_prover.ts +53 -76
- package/src/kernel_prover/test/test_circuit_prover.ts +11 -15
- package/src/note_processor/note_processor.ts +30 -21
- package/src/note_processor/utils/add_nullable_field_to_payload.ts +67 -0
- package/src/note_processor/utils/brute_force_note_info.ts +82 -0
- package/src/note_processor/utils/index.ts +2 -0
- package/src/note_processor/utils/produce_note_daos.ts +114 -0
- package/src/note_processor/utils/produce_note_daos_for_key.ts +157 -0
- package/src/pxe_http/pxe_http_server.ts +18 -3
- package/src/pxe_service/create_pxe_service.ts +0 -2
- package/src/pxe_service/pxe_service.ts +61 -100
- package/dest/kernel_prover/hints/build_private_kernel_reset_hints.d.ts +0 -5
- package/dest/kernel_prover/hints/build_private_kernel_reset_hints.d.ts.map +0 -1
- package/dest/kernel_prover/hints/build_private_kernel_reset_hints.js +0 -90
- package/dest/kernel_prover/hints/needs_reset.d.ts +0 -5
- package/dest/kernel_prover/hints/needs_reset.d.ts.map +0 -1
- package/dest/kernel_prover/hints/needs_reset.js +0 -38
- package/dest/note_processor/produce_note_dao.d.ts.map +0 -1
- package/dest/note_processor/produce_note_dao.js +0 -131
- package/src/kernel_prover/hints/build_private_kernel_reset_hints.ts +0 -249
- package/src/kernel_prover/hints/needs_reset.ts +0 -54
- package/src/note_processor/produce_note_dao.ts +0 -235
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type PrivateExecutionResult,
|
|
3
|
+
type PrivateKernelProver,
|
|
4
|
+
type PrivateKernelSimulateOutput,
|
|
5
|
+
collectEnqueuedPublicFunctionCalls,
|
|
6
|
+
collectNoteHashLeafIndexMap,
|
|
7
|
+
collectNoteHashNullifierCounterMap,
|
|
8
|
+
collectPublicTeardownFunctionCall,
|
|
9
|
+
getFinalMinRevertibleSideEffectCounter,
|
|
10
|
+
} from '@aztec/circuit-types';
|
|
2
11
|
import {
|
|
3
12
|
Fr,
|
|
4
13
|
PrivateCallData,
|
|
@@ -15,29 +24,18 @@ import {
|
|
|
15
24
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
16
25
|
import { assertLength } from '@aztec/foundation/serialize';
|
|
17
26
|
import { pushTestData } from '@aztec/foundation/testing';
|
|
18
|
-
import {
|
|
19
|
-
ClientCircuitArtifacts,
|
|
20
|
-
PrivateResetTagToArtifactName,
|
|
21
|
-
getVKTreeRoot,
|
|
22
|
-
} from '@aztec/noir-protocol-circuits-types';
|
|
23
|
-
import {
|
|
24
|
-
type ExecutionResult,
|
|
25
|
-
collectEnqueuedPublicFunctionCalls,
|
|
26
|
-
collectNoteHashLeafIndexMap,
|
|
27
|
-
collectNoteHashNullifierCounterMap,
|
|
28
|
-
collectPublicTeardownFunctionCall,
|
|
29
|
-
getFinalMinRevertibleSideEffectCounter,
|
|
30
|
-
} from '@aztec/simulator';
|
|
27
|
+
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types';
|
|
31
28
|
|
|
32
29
|
import { type WitnessMap } from '@noir-lang/types';
|
|
33
30
|
|
|
34
|
-
import {
|
|
31
|
+
import { PrivateKernelResetPrivateInputsBuilder } from './hints/build_private_kernel_reset_private_inputs.js';
|
|
35
32
|
import { type ProvingDataOracle } from './proving_data_oracle.js';
|
|
36
33
|
|
|
37
34
|
const NULL_PROVE_OUTPUT: PrivateKernelSimulateOutput<PrivateKernelCircuitPublicInputs> = {
|
|
38
35
|
publicInputs: PrivateKernelCircuitPublicInputs.empty(),
|
|
39
36
|
verificationKey: VerificationKeyAsFields.makeEmpty(),
|
|
40
37
|
outputWitness: new Map(),
|
|
38
|
+
bytecode: Buffer.from([]),
|
|
41
39
|
};
|
|
42
40
|
/**
|
|
43
41
|
* The KernelProver class is responsible for generating kernel proofs.
|
|
@@ -63,7 +61,7 @@ export class KernelProver {
|
|
|
63
61
|
*/
|
|
64
62
|
async prove(
|
|
65
63
|
txRequest: TxRequest,
|
|
66
|
-
executionResult:
|
|
64
|
+
executionResult: PrivateExecutionResult,
|
|
67
65
|
): Promise<PrivateKernelSimulateOutput<PrivateKernelTailCircuitPublicInputs>> {
|
|
68
66
|
const executionStack = [executionResult];
|
|
69
67
|
let firstIteration = true;
|
|
@@ -81,22 +79,29 @@ export class KernelProver {
|
|
|
81
79
|
const witnessStack: WitnessMap[] = [];
|
|
82
80
|
|
|
83
81
|
while (executionStack.length) {
|
|
84
|
-
if (!firstIteration
|
|
85
|
-
|
|
86
|
-
executionStack,
|
|
82
|
+
if (!firstIteration) {
|
|
83
|
+
let resetBuilder = new PrivateKernelResetPrivateInputsBuilder(
|
|
87
84
|
output,
|
|
88
|
-
|
|
85
|
+
executionStack,
|
|
89
86
|
noteHashNullifierCounterMap,
|
|
90
87
|
validationRequestsSplitCounter,
|
|
91
|
-
false,
|
|
92
88
|
);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
89
|
+
while (resetBuilder.needsReset()) {
|
|
90
|
+
const privateInputs = await resetBuilder.build(this.oracle, noteHashLeafIndexMap);
|
|
91
|
+
output = await this.proofCreator.simulateProofReset(privateInputs);
|
|
92
|
+
// TODO(#7368) consider refactoring this redundant bytecode pushing
|
|
93
|
+
acirs.push(output.bytecode);
|
|
94
|
+
witnessStack.push(output.outputWitness);
|
|
95
|
+
|
|
96
|
+
resetBuilder = new PrivateKernelResetPrivateInputsBuilder(
|
|
97
|
+
output,
|
|
98
|
+
executionStack,
|
|
99
|
+
noteHashNullifierCounterMap,
|
|
100
|
+
validationRequestsSplitCounter,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
99
103
|
}
|
|
104
|
+
|
|
100
105
|
const currentExecution = executionStack.pop()!;
|
|
101
106
|
executionStack.push(...[...currentExecution.nestedExecutions].reverse());
|
|
102
107
|
|
|
@@ -117,7 +122,7 @@ export class KernelProver {
|
|
|
117
122
|
const proofInput = new PrivateKernelInitCircuitPrivateInputs(txRequest, getVKTreeRoot(), privateCallData);
|
|
118
123
|
pushTestData('private-kernel-inputs-init', proofInput);
|
|
119
124
|
output = await this.proofCreator.simulateProofInit(proofInput);
|
|
120
|
-
acirs.push(
|
|
125
|
+
acirs.push(output.bytecode);
|
|
121
126
|
witnessStack.push(output.outputWitness);
|
|
122
127
|
} else {
|
|
123
128
|
const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(output.verificationKey);
|
|
@@ -130,28 +135,34 @@ export class KernelProver {
|
|
|
130
135
|
const proofInput = new PrivateKernelInnerCircuitPrivateInputs(previousKernelData, privateCallData);
|
|
131
136
|
pushTestData('private-kernel-inputs-inner', proofInput);
|
|
132
137
|
output = await this.proofCreator.simulateProofInner(proofInput);
|
|
133
|
-
acirs.push(
|
|
138
|
+
acirs.push(output.bytecode);
|
|
134
139
|
witnessStack.push(output.outputWitness);
|
|
135
140
|
}
|
|
136
141
|
firstIteration = false;
|
|
137
142
|
}
|
|
138
143
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
// Reset.
|
|
145
|
+
let resetBuilder = new PrivateKernelResetPrivateInputsBuilder(
|
|
146
|
+
output,
|
|
147
|
+
[],
|
|
148
|
+
noteHashNullifierCounterMap,
|
|
149
|
+
validationRequestsSplitCounter,
|
|
150
|
+
);
|
|
151
|
+
while (resetBuilder.needsReset()) {
|
|
152
|
+
const privateInputs = await resetBuilder.build(this.oracle, noteHashLeafIndexMap);
|
|
153
|
+
output = await this.proofCreator.simulateProofReset(privateInputs);
|
|
154
|
+
acirs.push(output.bytecode);
|
|
155
|
+
witnessStack.push(output.outputWitness);
|
|
156
|
+
|
|
157
|
+
resetBuilder = new PrivateKernelResetPrivateInputsBuilder(
|
|
142
158
|
output,
|
|
143
|
-
|
|
159
|
+
[],
|
|
144
160
|
noteHashNullifierCounterMap,
|
|
145
161
|
validationRequestsSplitCounter,
|
|
146
|
-
true,
|
|
147
162
|
);
|
|
148
|
-
output = await this.proofCreator.simulateProofReset(resetInputs);
|
|
149
|
-
// TODO(#7368) consider refactoring this redundant bytecode pushing
|
|
150
|
-
acirs.push(
|
|
151
|
-
Buffer.from(ClientCircuitArtifacts[PrivateResetTagToArtifactName[resetInputs.sizeTag]].bytecode, 'base64'),
|
|
152
|
-
);
|
|
153
|
-
witnessStack.push(output.outputWitness);
|
|
154
163
|
}
|
|
164
|
+
|
|
165
|
+
// Private tail.
|
|
155
166
|
const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(output.verificationKey);
|
|
156
167
|
const previousKernelData = new PrivateKernelData(
|
|
157
168
|
output.publicInputs,
|
|
@@ -168,14 +179,7 @@ export class KernelProver {
|
|
|
168
179
|
|
|
169
180
|
pushTestData('private-kernel-inputs-ordering', privateInputs);
|
|
170
181
|
const tailOutput = await this.proofCreator.simulateProofTail(privateInputs);
|
|
171
|
-
acirs.push(
|
|
172
|
-
Buffer.from(
|
|
173
|
-
privateInputs.isForPublic()
|
|
174
|
-
? ClientCircuitArtifacts.PrivateKernelTailToPublicArtifact.bytecode
|
|
175
|
-
: ClientCircuitArtifacts.PrivateKernelTailArtifact.bytecode,
|
|
176
|
-
'base64',
|
|
177
|
-
),
|
|
178
|
-
);
|
|
182
|
+
acirs.push(tailOutput.bytecode);
|
|
179
183
|
witnessStack.push(tailOutput.outputWitness);
|
|
180
184
|
|
|
181
185
|
// TODO(#7368) how do we 'bincode' encode these inputs?
|
|
@@ -184,34 +188,7 @@ export class KernelProver {
|
|
|
184
188
|
return tailOutput;
|
|
185
189
|
}
|
|
186
190
|
|
|
187
|
-
private async
|
|
188
|
-
executionStack: ExecutionResult[],
|
|
189
|
-
output: PrivateKernelSimulateOutput<PrivateKernelCircuitPublicInputs>,
|
|
190
|
-
noteHashLeafIndexMap: Map<bigint, bigint>,
|
|
191
|
-
noteHashNullifierCounterMap: Map<number, number>,
|
|
192
|
-
validationRequestsSplitCounter: number,
|
|
193
|
-
shouldSilo: boolean,
|
|
194
|
-
) {
|
|
195
|
-
const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(output.verificationKey);
|
|
196
|
-
const previousKernelData = new PrivateKernelData(
|
|
197
|
-
output.publicInputs,
|
|
198
|
-
output.verificationKey,
|
|
199
|
-
Number(previousVkMembershipWitness.leafIndex),
|
|
200
|
-
assertLength<Fr, typeof VK_TREE_HEIGHT>(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT),
|
|
201
|
-
);
|
|
202
|
-
|
|
203
|
-
return await buildPrivateKernelResetInputs(
|
|
204
|
-
executionStack,
|
|
205
|
-
previousKernelData,
|
|
206
|
-
noteHashLeafIndexMap,
|
|
207
|
-
noteHashNullifierCounterMap,
|
|
208
|
-
validationRequestsSplitCounter,
|
|
209
|
-
shouldSilo,
|
|
210
|
-
this.oracle,
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
private async createPrivateCallData({ callStackItem }: ExecutionResult, vk: VerificationKeyAsFields) {
|
|
191
|
+
private async createPrivateCallData({ callStackItem }: PrivateExecutionResult, vk: VerificationKeyAsFields) {
|
|
215
192
|
const { contractAddress, functionData } = callStackItem;
|
|
216
193
|
|
|
217
194
|
const functionLeafMembershipWitness = await this.oracle.getFunctionMembershipWitness(
|
|
@@ -3,19 +3,17 @@ import {
|
|
|
3
3
|
type PrivateKernelProver,
|
|
4
4
|
type PrivateKernelSimulateOutput,
|
|
5
5
|
} from '@aztec/circuit-types';
|
|
6
|
-
import type {
|
|
6
|
+
import type { CircuitSimulationStats } from '@aztec/circuit-types/stats';
|
|
7
7
|
import {
|
|
8
8
|
ClientIvcProof,
|
|
9
|
-
type PrivateCircuitPublicInputs,
|
|
10
9
|
type PrivateKernelCircuitPublicInputs,
|
|
11
10
|
type PrivateKernelInitCircuitPrivateInputs,
|
|
12
11
|
type PrivateKernelInnerCircuitPrivateInputs,
|
|
13
|
-
type
|
|
12
|
+
type PrivateKernelResetCircuitPrivateInputs,
|
|
14
13
|
type PrivateKernelTailCircuitPrivateInputs,
|
|
15
14
|
type PrivateKernelTailCircuitPublicInputs,
|
|
16
15
|
VerificationKeyAsFields,
|
|
17
16
|
} from '@aztec/circuits.js';
|
|
18
|
-
import { siloNoteHash } from '@aztec/circuits.js/hash';
|
|
19
17
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
20
18
|
import { elapsed } from '@aztec/foundation/timer';
|
|
21
19
|
import {
|
|
@@ -26,6 +24,8 @@ import {
|
|
|
26
24
|
executeReset,
|
|
27
25
|
executeTail,
|
|
28
26
|
executeTailForPublic,
|
|
27
|
+
getPrivateKernelResetArtifactName,
|
|
28
|
+
maxPrivateKernelResetDimensions,
|
|
29
29
|
} from '@aztec/noir-protocol-circuits-types';
|
|
30
30
|
|
|
31
31
|
import { type WitnessMap } from '@noir-lang/types';
|
|
@@ -40,12 +40,6 @@ export class TestPrivateKernelProver implements PrivateKernelProver {
|
|
|
40
40
|
return Promise.resolve(ClientIvcProof.empty());
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
public getSiloedCommitments(publicInputs: PrivateCircuitPublicInputs) {
|
|
44
|
-
const contractAddress = publicInputs.callContext.storageContractAddress;
|
|
45
|
-
|
|
46
|
-
return Promise.resolve(publicInputs.noteHashes.map(commitment => siloNoteHash(contractAddress, commitment.value)));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
43
|
public async simulateProofInit(
|
|
50
44
|
privateInputs: PrivateKernelInitCircuitPrivateInputs,
|
|
51
45
|
): Promise<PrivateKernelSimulateOutput<PrivateKernelCircuitPublicInputs>> {
|
|
@@ -75,19 +69,20 @@ export class TestPrivateKernelProver implements PrivateKernelProver {
|
|
|
75
69
|
}
|
|
76
70
|
|
|
77
71
|
public async simulateProofReset(
|
|
78
|
-
privateInputs:
|
|
72
|
+
privateInputs: PrivateKernelResetCircuitPrivateInputs,
|
|
79
73
|
): Promise<PrivateKernelSimulateOutput<PrivateKernelCircuitPublicInputs>> {
|
|
80
|
-
const
|
|
74
|
+
const variantPrivateInputs = privateInputs.trimToSizes();
|
|
75
|
+
const [duration, result] = await elapsed(() => executeReset(variantPrivateInputs, privateInputs.dimensions));
|
|
81
76
|
this.log.debug(`Simulated private kernel reset`, {
|
|
82
77
|
eventName: 'circuit-simulation',
|
|
83
|
-
circuitName:
|
|
78
|
+
circuitName: 'private-kernel-reset',
|
|
84
79
|
duration,
|
|
85
|
-
inputSize:
|
|
80
|
+
inputSize: variantPrivateInputs.toBuffer().length,
|
|
86
81
|
outputSize: result.toBuffer().length,
|
|
87
82
|
} satisfies CircuitSimulationStats);
|
|
88
83
|
return this.makeEmptyKernelSimulateOutput<PrivateKernelCircuitPublicInputs>(
|
|
89
84
|
result,
|
|
90
|
-
|
|
85
|
+
getPrivateKernelResetArtifactName(maxPrivateKernelResetDimensions),
|
|
91
86
|
);
|
|
92
87
|
}
|
|
93
88
|
|
|
@@ -129,6 +124,7 @@ export class TestPrivateKernelProver implements PrivateKernelProver {
|
|
|
129
124
|
publicInputs,
|
|
130
125
|
verificationKey: ProtocolCircuitVks[circuitType].keyAsFields,
|
|
131
126
|
outputWitness: new Map(),
|
|
127
|
+
bytecode: Buffer.from([]),
|
|
132
128
|
};
|
|
133
129
|
return kernelProofOutput;
|
|
134
130
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AztecNode, L1NotePayload, type L2Block
|
|
1
|
+
import { type AztecNode, L1NotePayload, type L2Block } from '@aztec/circuit-types';
|
|
2
2
|
import { type NoteProcessorStats } from '@aztec/circuit-types/stats';
|
|
3
3
|
import { type AztecAddress, INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX, type PublicKey } from '@aztec/circuits.js';
|
|
4
4
|
import { type Fr } from '@aztec/foundation/fields';
|
|
@@ -12,7 +12,7 @@ import { type IncomingNoteDao } from '../database/incoming_note_dao.js';
|
|
|
12
12
|
import { type PxeDatabase } from '../database/index.js';
|
|
13
13
|
import { type OutgoingNoteDao } from '../database/outgoing_note_dao.js';
|
|
14
14
|
import { getAcirSimulator } from '../simulator/index.js';
|
|
15
|
-
import { produceNoteDaos } from './
|
|
15
|
+
import { produceNoteDaos } from './utils/produce_note_daos.js';
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Contains all the decrypted data in this array so that we can later batch insert it all into the database.
|
|
@@ -142,35 +142,33 @@ export class NoteProcessor {
|
|
|
142
142
|
for (const functionLogs of txFunctionLogs) {
|
|
143
143
|
for (const log of functionLogs.logs) {
|
|
144
144
|
this.stats.seen++;
|
|
145
|
-
const
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
if (
|
|
149
|
-
if (
|
|
150
|
-
incomingTaggedNote &&
|
|
151
|
-
outgoingTaggedNote &&
|
|
152
|
-
!incomingTaggedNote.payload.equals(outgoingTaggedNote.payload)
|
|
153
|
-
) {
|
|
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)) {
|
|
154
150
|
throw new Error(
|
|
155
151
|
`Incoming and outgoing note payloads do not match. Incoming: ${JSON.stringify(
|
|
156
|
-
|
|
157
|
-
)}, Outgoing: ${JSON.stringify(
|
|
152
|
+
incomingNotePayload,
|
|
153
|
+
)}, Outgoing: ${JSON.stringify(outgoingNotePayload)}`,
|
|
158
154
|
);
|
|
159
155
|
}
|
|
160
156
|
|
|
161
|
-
const payload =
|
|
157
|
+
const payload = incomingNotePayload || outgoingNotePayload;
|
|
162
158
|
|
|
163
|
-
const
|
|
159
|
+
const txEffect = block.body.txEffects[indexOfTxInABlock];
|
|
164
160
|
const { incomingNote, outgoingNote, incomingDeferredNote, outgoingDeferredNote } = await produceNoteDaos(
|
|
165
161
|
this.simulator,
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
162
|
+
this.db,
|
|
163
|
+
incomingNotePayload ? this.ivpkM : undefined,
|
|
164
|
+
outgoingNotePayload ? this.ovpkM : undefined,
|
|
165
|
+
payload!,
|
|
166
|
+
txEffect.txHash,
|
|
170
167
|
noteHashes,
|
|
171
168
|
dataStartIndexForTx,
|
|
172
169
|
excludedIndices,
|
|
173
170
|
this.log,
|
|
171
|
+
txEffect.unencryptedLogs,
|
|
174
172
|
);
|
|
175
173
|
|
|
176
174
|
if (incomingNote) {
|
|
@@ -300,8 +298,17 @@ export class NoteProcessor {
|
|
|
300
298
|
const outgoingNotes: OutgoingNoteDao[] = [];
|
|
301
299
|
|
|
302
300
|
for (const deferredNote of deferredNoteDaos) {
|
|
303
|
-
const {
|
|
304
|
-
|
|
301
|
+
const {
|
|
302
|
+
publicKey,
|
|
303
|
+
note,
|
|
304
|
+
contractAddress,
|
|
305
|
+
storageSlot,
|
|
306
|
+
noteTypeId,
|
|
307
|
+
txHash,
|
|
308
|
+
noteHashes,
|
|
309
|
+
dataStartIndexForTx,
|
|
310
|
+
unencryptedLogs,
|
|
311
|
+
} = deferredNote;
|
|
305
312
|
const payload = new L1NotePayload(note, contractAddress, storageSlot, noteTypeId);
|
|
306
313
|
|
|
307
314
|
const isIncoming = publicKey.equals(this.ivpkM);
|
|
@@ -314,6 +321,7 @@ export class NoteProcessor {
|
|
|
314
321
|
|
|
315
322
|
const { incomingNote, outgoingNote } = await produceNoteDaos(
|
|
316
323
|
this.simulator,
|
|
324
|
+
this.db,
|
|
317
325
|
isIncoming ? this.ivpkM : undefined,
|
|
318
326
|
isOutgoing ? this.ovpkM : undefined,
|
|
319
327
|
payload,
|
|
@@ -322,6 +330,7 @@ export class NoteProcessor {
|
|
|
322
330
|
dataStartIndexForTx,
|
|
323
331
|
excludedIndices,
|
|
324
332
|
this.log,
|
|
333
|
+
unencryptedLogs,
|
|
325
334
|
);
|
|
326
335
|
|
|
327
336
|
if (isIncoming) {
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { L1NotePayload, Note } from '@aztec/circuit-types';
|
|
2
|
+
import { type Fr } from '@aztec/foundation/fields';
|
|
3
|
+
import { ContractNotFoundError } from '@aztec/simulator';
|
|
4
|
+
|
|
5
|
+
import { type PxeDatabase } from '../../database/pxe_database.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Inserts publicly delivered nullable fields into the note payload.
|
|
9
|
+
* @param db - PXE database used to fetch contract instance and artifact.
|
|
10
|
+
* @param payload - Note payload to which nullable fields should be added.
|
|
11
|
+
* @param nullableFields - List of nullable fields to be added to the note payload.
|
|
12
|
+
* @returns Note payload with nullable fields added.
|
|
13
|
+
*/
|
|
14
|
+
export async function addNullableFieldsToPayload(
|
|
15
|
+
db: PxeDatabase,
|
|
16
|
+
payload: L1NotePayload,
|
|
17
|
+
nullableFields: Fr[],
|
|
18
|
+
): Promise<L1NotePayload> {
|
|
19
|
+
const instance = await db.getContractInstance(payload.contractAddress);
|
|
20
|
+
if (!instance) {
|
|
21
|
+
throw new ContractNotFoundError(
|
|
22
|
+
`Could not find instance for ${payload.contractAddress.toString()}. This should never happen here as the partial notes flow should be triggered only for non-deferred notes.`,
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const artifact = await db.getContractArtifact(instance.contractClassId);
|
|
27
|
+
if (!artifact) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`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.`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const noteFields = Object.values(artifact.notes).find(note => note.id.equals(payload.noteTypeId))?.fields;
|
|
34
|
+
|
|
35
|
+
if (!noteFields) {
|
|
36
|
+
throw new Error(`Could not find note fields for note type ${payload.noteTypeId.toString()}.`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// We sort note fields by index so that we can iterate over them in order.
|
|
40
|
+
noteFields.sort((a, b) => a.index - b.index);
|
|
41
|
+
|
|
42
|
+
// Now we insert the nullable fields into the note based on its indices defined in the ABI.
|
|
43
|
+
const modifiedNoteItems = [...payload.note.items];
|
|
44
|
+
let indexInNullable = 0;
|
|
45
|
+
for (let i = 0; i < noteFields.length; i++) {
|
|
46
|
+
const noteField = noteFields[i];
|
|
47
|
+
if (noteField.nullable) {
|
|
48
|
+
if (i == noteFields.length - 1) {
|
|
49
|
+
// We are processing the last field so we simply insert the rest of the nullable fields at the end
|
|
50
|
+
modifiedNoteItems.push(...nullableFields.slice(indexInNullable));
|
|
51
|
+
} else {
|
|
52
|
+
const noteFieldLength = noteFields[i + 1].index - noteField.index;
|
|
53
|
+
const nullableFieldsToInsert = nullableFields.slice(indexInNullable, indexInNullable + noteFieldLength);
|
|
54
|
+
indexInNullable += noteFieldLength;
|
|
55
|
+
// Now we insert the nullable fields at the note field index
|
|
56
|
+
modifiedNoteItems.splice(noteField.index, 0, ...nullableFieldsToInsert);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return new L1NotePayload(
|
|
62
|
+
new Note(modifiedNoteItems),
|
|
63
|
+
payload.contractAddress,
|
|
64
|
+
payload.storageSlot,
|
|
65
|
+
payload.noteTypeId,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { type L1NotePayload, type TxHash } from '@aztec/circuit-types';
|
|
2
|
+
import { computeNoteHashNonce, siloNullifier } from '@aztec/circuits.js/hash';
|
|
3
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
4
|
+
import { type AcirSimulator } from '@aztec/simulator';
|
|
5
|
+
|
|
6
|
+
export interface NoteInfo {
|
|
7
|
+
noteHashIndex: number;
|
|
8
|
+
nonce: Fr;
|
|
9
|
+
noteHash: Fr;
|
|
10
|
+
siloedNullifier: Fr;
|
|
11
|
+
txHash: TxHash;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Finds nonce, index, inner hash and siloed nullifier for a given note.
|
|
16
|
+
* @dev Finds the index in the note hash tree by computing the note hash with different nonce and see which hash for
|
|
17
|
+
* the current tx matches this value.
|
|
18
|
+
* @remarks This method assists in identifying spent notes in the note hash tree.
|
|
19
|
+
* @param siloedNoteHashes - Note hashes in the tx. One of them should correspond to the note we are looking for
|
|
20
|
+
* @param txHash - Hash of a tx the note was emitted in.
|
|
21
|
+
* @param l1NotePayload - The note payload.
|
|
22
|
+
* @param excludedIndices - Indices that have been assigned a note in the same tx. Notes in a tx can have the same
|
|
23
|
+
* l1NotePayload. We need to find a different index for each replicate.
|
|
24
|
+
* @param computeNullifier - A flag indicating whether to compute the nullifier or just return 0.
|
|
25
|
+
* @returns Nonce, index, inner hash and siloed nullifier for a given note.
|
|
26
|
+
* @throws If cannot find the nonce for the note.
|
|
27
|
+
*/
|
|
28
|
+
export async function bruteForceNoteInfo(
|
|
29
|
+
simulator: AcirSimulator,
|
|
30
|
+
siloedNoteHashes: Fr[],
|
|
31
|
+
txHash: TxHash,
|
|
32
|
+
{ contractAddress, storageSlot, noteTypeId, note }: L1NotePayload,
|
|
33
|
+
excludedIndices: Set<number>,
|
|
34
|
+
computeNullifier: boolean,
|
|
35
|
+
): Promise<NoteInfo> {
|
|
36
|
+
let noteHashIndex = 0;
|
|
37
|
+
let nonce: Fr | undefined;
|
|
38
|
+
let noteHash: Fr | undefined;
|
|
39
|
+
let siloedNoteHash: Fr | undefined;
|
|
40
|
+
let innerNullifier: Fr | undefined;
|
|
41
|
+
const firstNullifier = Fr.fromBuffer(txHash.toBuffer());
|
|
42
|
+
|
|
43
|
+
for (; noteHashIndex < siloedNoteHashes.length; ++noteHashIndex) {
|
|
44
|
+
if (excludedIndices.has(noteHashIndex)) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const siloedNoteHashFromTxEffect = siloedNoteHashes[noteHashIndex];
|
|
49
|
+
if (siloedNoteHashFromTxEffect.equals(Fr.ZERO)) {
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const expectedNonce = computeNoteHashNonce(firstNullifier, noteHashIndex);
|
|
54
|
+
({ noteHash, siloedNoteHash, innerNullifier } = await simulator.computeNoteHashAndOptionallyANullifier(
|
|
55
|
+
contractAddress,
|
|
56
|
+
expectedNonce,
|
|
57
|
+
storageSlot,
|
|
58
|
+
noteTypeId,
|
|
59
|
+
computeNullifier,
|
|
60
|
+
note,
|
|
61
|
+
));
|
|
62
|
+
|
|
63
|
+
if (siloedNoteHashFromTxEffect.equals(siloedNoteHash)) {
|
|
64
|
+
nonce = expectedNonce;
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!nonce) {
|
|
70
|
+
// NB: this used to warn the user that a decrypted log didn't match any notes.
|
|
71
|
+
// This was previously fine as we didn't chop transient note logs, but now we do (#1641 complete).
|
|
72
|
+
throw new Error('Cannot find a matching note hash for the note.');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
noteHashIndex,
|
|
77
|
+
nonce,
|
|
78
|
+
noteHash: noteHash!,
|
|
79
|
+
siloedNullifier: siloNullifier(contractAddress, innerNullifier!),
|
|
80
|
+
txHash,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { type L1NotePayload, type PublicKey, type TxHash, type UnencryptedTxL2Logs } from '@aztec/circuit-types';
|
|
2
|
+
import { type Fr } from '@aztec/foundation/fields';
|
|
3
|
+
import { type Logger } from '@aztec/foundation/log';
|
|
4
|
+
import { type AcirSimulator } from '@aztec/simulator';
|
|
5
|
+
|
|
6
|
+
import { type DeferredNoteDao } from '../../database/deferred_note_dao.js';
|
|
7
|
+
import { IncomingNoteDao } from '../../database/incoming_note_dao.js';
|
|
8
|
+
import { OutgoingNoteDao } from '../../database/outgoing_note_dao.js';
|
|
9
|
+
import { type PxeDatabase } from '../../database/pxe_database.js';
|
|
10
|
+
import { produceNoteDaosForKey } from './produce_note_daos_for_key.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Decodes a note from a transaction that we know was intended for us.
|
|
14
|
+
* Throws if we do not yet have the contract corresponding to the note in our database.
|
|
15
|
+
* Accepts a set of excluded indices, which are indices that have been assigned a note in the same tx.
|
|
16
|
+
* Inserts the index of the note into the excludedIndices set if the note is successfully decoded.
|
|
17
|
+
*
|
|
18
|
+
* @param simulator - An instance of AcirSimulator.
|
|
19
|
+
* @param db - An instance of PxeDatabase.
|
|
20
|
+
* @param ivpkM - The public counterpart to the secret key to be used in the decryption of incoming note logs.
|
|
21
|
+
* @param ovpkM - The public counterpart to the secret key to be used in the decryption of outgoing note logs.
|
|
22
|
+
* @param payload - An instance of l1NotePayload.
|
|
23
|
+
* @param txHash - The hash of the transaction that created the note. Equivalent to the first nullifier of the transaction.
|
|
24
|
+
* @param noteHashes - New note hashes in this transaction, one of which belongs to this note.
|
|
25
|
+
* @param dataStartIndexForTx - The next available leaf index for the note hash tree for this transaction.
|
|
26
|
+
* @param excludedIndices - Indices that have been assigned a note in the same tx. Notes in a tx can have the same l1NotePayload, we need to find a different index for each replicate.
|
|
27
|
+
* @param logger - An instance of Logger.
|
|
28
|
+
* @param unencryptedLogs - Unencrypted logs for the transaction (used to complete partial notes).
|
|
29
|
+
* @returns An object containing the incoming, outgoing, and deferred notes.
|
|
30
|
+
*/
|
|
31
|
+
export async function produceNoteDaos(
|
|
32
|
+
simulator: AcirSimulator,
|
|
33
|
+
db: PxeDatabase,
|
|
34
|
+
ivpkM: PublicKey | undefined,
|
|
35
|
+
ovpkM: PublicKey | undefined,
|
|
36
|
+
payload: L1NotePayload,
|
|
37
|
+
txHash: TxHash,
|
|
38
|
+
noteHashes: Fr[],
|
|
39
|
+
dataStartIndexForTx: number,
|
|
40
|
+
excludedIndices: Set<number>,
|
|
41
|
+
logger: Logger,
|
|
42
|
+
unencryptedLogs: UnencryptedTxL2Logs,
|
|
43
|
+
): Promise<{
|
|
44
|
+
incomingNote: IncomingNoteDao | undefined;
|
|
45
|
+
outgoingNote: OutgoingNoteDao | undefined;
|
|
46
|
+
incomingDeferredNote: DeferredNoteDao | undefined;
|
|
47
|
+
outgoingDeferredNote: DeferredNoteDao | undefined;
|
|
48
|
+
}> {
|
|
49
|
+
// WARNING: This code is full of tech debt and will be refactored once we have final design of partial notes
|
|
50
|
+
// delivery.
|
|
51
|
+
if (!ivpkM && !ovpkM) {
|
|
52
|
+
throw new Error('Both ivpkM and ovpkM are undefined. Cannot create note.');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let incomingNote: IncomingNoteDao | undefined;
|
|
56
|
+
let outgoingNote: OutgoingNoteDao | undefined;
|
|
57
|
+
let incomingDeferredNote: DeferredNoteDao | undefined;
|
|
58
|
+
let outgoingDeferredNote: DeferredNoteDao | undefined;
|
|
59
|
+
|
|
60
|
+
if (ivpkM) {
|
|
61
|
+
[incomingNote, incomingDeferredNote] = await produceNoteDaosForKey(
|
|
62
|
+
simulator,
|
|
63
|
+
db,
|
|
64
|
+
ivpkM,
|
|
65
|
+
payload,
|
|
66
|
+
txHash,
|
|
67
|
+
noteHashes,
|
|
68
|
+
dataStartIndexForTx,
|
|
69
|
+
excludedIndices,
|
|
70
|
+
logger,
|
|
71
|
+
unencryptedLogs,
|
|
72
|
+
IncomingNoteDao.fromPayloadAndNoteInfo,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (ovpkM) {
|
|
77
|
+
if (incomingNote) {
|
|
78
|
+
// Incoming note is defined meaning that this PXE has both the incoming and outgoing keys. We can skip computing
|
|
79
|
+
// note hash and note index since we already have them in the incoming note.
|
|
80
|
+
outgoingNote = new OutgoingNoteDao(
|
|
81
|
+
payload.note,
|
|
82
|
+
payload.contractAddress,
|
|
83
|
+
payload.storageSlot,
|
|
84
|
+
payload.noteTypeId,
|
|
85
|
+
txHash,
|
|
86
|
+
incomingNote.nonce,
|
|
87
|
+
incomingNote.noteHash,
|
|
88
|
+
incomingNote.index,
|
|
89
|
+
ovpkM,
|
|
90
|
+
);
|
|
91
|
+
} else {
|
|
92
|
+
[outgoingNote, outgoingDeferredNote] = await produceNoteDaosForKey(
|
|
93
|
+
simulator,
|
|
94
|
+
db,
|
|
95
|
+
ovpkM,
|
|
96
|
+
payload,
|
|
97
|
+
txHash,
|
|
98
|
+
noteHashes,
|
|
99
|
+
dataStartIndexForTx,
|
|
100
|
+
excludedIndices,
|
|
101
|
+
logger,
|
|
102
|
+
unencryptedLogs,
|
|
103
|
+
OutgoingNoteDao.fromPayloadAndNoteInfo,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
incomingNote,
|
|
110
|
+
outgoingNote,
|
|
111
|
+
incomingDeferredNote,
|
|
112
|
+
outgoingDeferredNote,
|
|
113
|
+
};
|
|
114
|
+
}
|