@aztec/pxe 0.0.1-commit.7ac86ea28 → 0.0.1-commit.7b86788
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_function_simulator/contract_function_simulator.d.ts +1 -1
- package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
- package/dest/contract_function_simulator/contract_function_simulator.js +6 -6
- package/dest/contract_function_simulator/execution_tagging_index_cache.d.ts +5 -5
- package/dest/contract_function_simulator/execution_tagging_index_cache.d.ts.map +1 -1
- package/dest/contract_function_simulator/execution_tagging_index_cache.js +3 -3
- package/dest/contract_function_simulator/noir-structs/event_validation_request.js +1 -1
- package/dest/contract_function_simulator/noir-structs/note_validation_request.d.ts +1 -1
- package/dest/contract_function_simulator/noir-structs/note_validation_request.js +1 -1
- package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +1 -1
- package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/private_execution_oracle.js +8 -8
- package/dest/logs/log_service.d.ts +1 -1
- package/dest/logs/log_service.d.ts.map +1 -1
- package/dest/logs/log_service.js +4 -4
- package/dest/private_kernel/hints/private_kernel_reset_private_inputs_builder.d.ts +4 -3
- package/dest/private_kernel/hints/private_kernel_reset_private_inputs_builder.d.ts.map +1 -1
- package/dest/private_kernel/hints/private_kernel_reset_private_inputs_builder.js +125 -64
- package/dest/private_kernel/hints/test_utils.d.ts +122 -0
- package/dest/private_kernel/hints/test_utils.d.ts.map +1 -0
- package/dest/private_kernel/hints/test_utils.js +203 -0
- package/dest/private_kernel/private_kernel_execution_prover.d.ts +1 -1
- package/dest/private_kernel/private_kernel_execution_prover.d.ts.map +1 -1
- package/dest/private_kernel/private_kernel_execution_prover.js +13 -5
- package/dest/pxe.d.ts +1 -1
- package/dest/pxe.d.ts.map +1 -1
- package/dest/pxe.js +2 -1
- package/dest/storage/tagging_store/recipient_tagging_store.d.ts +6 -6
- package/dest/storage/tagging_store/recipient_tagging_store.d.ts.map +1 -1
- package/dest/storage/tagging_store/sender_tagging_store.d.ts +5 -5
- package/dest/storage/tagging_store/sender_tagging_store.d.ts.map +1 -1
- package/dest/storage/tagging_store/sender_tagging_store.js +4 -4
- package/dest/tagging/index.d.ts +2 -2
- package/dest/tagging/index.d.ts.map +1 -1
- package/dest/tagging/index.js +1 -1
- package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts +4 -5
- package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.d.ts.map +1 -1
- package/dest/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.js +3 -3
- package/dest/tagging/recipient_sync/utils/load_logs_for_range.d.ts +6 -7
- package/dest/tagging/recipient_sync/utils/load_logs_for_range.d.ts.map +1 -1
- package/dest/tagging/recipient_sync/utils/load_logs_for_range.js +12 -11
- package/dest/tagging/sender_sync/sync_sender_tagging_indexes.d.ts +4 -8
- package/dest/tagging/sender_sync/sync_sender_tagging_indexes.d.ts.map +1 -1
- package/dest/tagging/sender_sync/sync_sender_tagging_indexes.js +3 -6
- package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.d.ts +4 -7
- package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.d.ts.map +1 -1
- package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.js +14 -15
- package/package.json +16 -16
- package/src/contract_function_simulator/contract_function_simulator.ts +12 -13
- package/src/contract_function_simulator/execution_tagging_index_cache.ts +5 -5
- package/src/contract_function_simulator/noir-structs/event_validation_request.ts +1 -1
- package/src/contract_function_simulator/noir-structs/note_validation_request.ts +1 -1
- package/src/contract_function_simulator/oracle/private_execution_oracle.ts +12 -9
- package/src/logs/log_service.ts +10 -5
- package/src/private_kernel/hints/private_kernel_reset_private_inputs_builder.ts +157 -110
- package/src/private_kernel/hints/test_utils.ts +325 -0
- package/src/private_kernel/private_kernel_execution_prover.ts +13 -6
- package/src/pxe.ts +2 -1
- package/src/storage/tagging_store/recipient_tagging_store.ts +9 -5
- package/src/storage/tagging_store/sender_tagging_store.ts +8 -8
- package/src/tagging/index.ts +1 -1
- package/src/tagging/recipient_sync/load_private_logs_for_sender_recipient_pair.ts +3 -6
- package/src/tagging/recipient_sync/utils/load_logs_for_range.ts +10 -15
- package/src/tagging/sender_sync/sync_sender_tagging_indexes.ts +4 -9
- package/src/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.ts +11 -20
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MAX_KEY_VALIDATION_REQUESTS_PER_CALL,
|
|
3
|
+
MAX_KEY_VALIDATION_REQUESTS_PER_TX,
|
|
4
|
+
MAX_NOTE_HASHES_PER_CALL,
|
|
5
|
+
MAX_NOTE_HASHES_PER_TX,
|
|
6
|
+
MAX_NOTE_HASH_READ_REQUESTS_PER_CALL,
|
|
7
|
+
MAX_NOTE_HASH_READ_REQUESTS_PER_TX,
|
|
8
|
+
MAX_NULLIFIERS_PER_CALL,
|
|
9
|
+
MAX_NULLIFIERS_PER_TX,
|
|
10
|
+
MAX_NULLIFIER_READ_REQUESTS_PER_CALL,
|
|
11
|
+
MAX_NULLIFIER_READ_REQUESTS_PER_TX,
|
|
12
|
+
MAX_PRIVATE_LOGS_PER_CALL,
|
|
13
|
+
MAX_PRIVATE_LOGS_PER_TX,
|
|
14
|
+
} from '@aztec/constants';
|
|
15
|
+
import { makeTuple } from '@aztec/foundation/array';
|
|
16
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
17
|
+
import { Point } from '@aztec/foundation/curves/grumpkin';
|
|
18
|
+
import type { Serializable } from '@aztec/foundation/serialize';
|
|
19
|
+
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
20
|
+
import {
|
|
21
|
+
ClaimedLengthArray,
|
|
22
|
+
KeyValidationRequest,
|
|
23
|
+
KeyValidationRequestAndSeparator,
|
|
24
|
+
NoteHash,
|
|
25
|
+
Nullifier,
|
|
26
|
+
PrivateCircuitPublicInputs,
|
|
27
|
+
PrivateKernelCircuitPublicInputs,
|
|
28
|
+
type PrivateKernelSimulateOutput,
|
|
29
|
+
ReadRequest,
|
|
30
|
+
ScopedKeyValidationRequestAndSeparator,
|
|
31
|
+
ScopedNoteHash,
|
|
32
|
+
ScopedNullifier,
|
|
33
|
+
ScopedReadRequest,
|
|
34
|
+
} from '@aztec/stdlib/kernel';
|
|
35
|
+
import { PrivateLogData, ScopedPrivateLogData } from '@aztec/stdlib/kernel';
|
|
36
|
+
import { PrivateLog } from '@aztec/stdlib/logs';
|
|
37
|
+
import { PrivateCallExecutionResult } from '@aztec/stdlib/tx';
|
|
38
|
+
import { VerificationKeyData } from '@aztec/stdlib/vks';
|
|
39
|
+
|
|
40
|
+
const DEFAULT_CONTRACT_ADDRESS = AztecAddress.fromBigInt(987654n);
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Builds a ClaimedLengthArray from a list of items, padding to the required size.
|
|
44
|
+
*/
|
|
45
|
+
function makeClaimed<T extends Serializable, N extends number>(items: T[], emptyFactory: { empty(): T }, maxSize: N) {
|
|
46
|
+
const padded = makeTuple(maxSize, i => items[i] ?? emptyFactory.empty());
|
|
47
|
+
return new ClaimedLengthArray<T, typeof maxSize>(padded, items.length);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Builder for PrivateKernelCircuitPublicInputs with fluent API for adding side effects. */
|
|
51
|
+
export class PrivateKernelCircuitPublicInputsBuilder {
|
|
52
|
+
private noteHashes: ScopedNoteHash[] = [];
|
|
53
|
+
private nullifiers: ScopedNullifier[] = [];
|
|
54
|
+
private noteHashReadRequests: ScopedReadRequest[] = [];
|
|
55
|
+
private nullifierReadRequests: ScopedReadRequest[] = [];
|
|
56
|
+
private keyValidationRequests: ScopedKeyValidationRequestAndSeparator[] = [];
|
|
57
|
+
private privateLogs: ScopedPrivateLogData[] = [];
|
|
58
|
+
private nextCounter: number;
|
|
59
|
+
|
|
60
|
+
constructor(
|
|
61
|
+
private contractAddress: AztecAddress = DEFAULT_CONTRACT_ADDRESS,
|
|
62
|
+
startCounter = 1,
|
|
63
|
+
) {
|
|
64
|
+
this.nextCounter = startCounter;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private getCounter(sideEffectCounter?: number): number {
|
|
68
|
+
if (sideEffectCounter !== undefined) {
|
|
69
|
+
this.nextCounter = sideEffectCounter + 1;
|
|
70
|
+
return sideEffectCounter;
|
|
71
|
+
}
|
|
72
|
+
return this.nextCounter++;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Adds a note hash to the accumulated data. Defaults are generated randomly. */
|
|
76
|
+
addNoteHash(opts?: { value?: Fr; counter?: number; contractAddress?: AztecAddress }): this {
|
|
77
|
+
const value = opts?.value ?? Fr.random();
|
|
78
|
+
const counter = this.getCounter(opts?.counter);
|
|
79
|
+
const addr = opts?.contractAddress ?? this.contractAddress;
|
|
80
|
+
this.noteHashes.push(new NoteHash(value, counter).scope(addr));
|
|
81
|
+
return this;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Adds a nullifier to the accumulated data. Defaults are generated randomly. */
|
|
85
|
+
addNullifier(opts?: { value?: Fr; noteHash?: Fr; counter?: number; contractAddress?: AztecAddress }): this {
|
|
86
|
+
const value = opts?.value ?? Fr.random();
|
|
87
|
+
const noteHash = opts?.noteHash ?? Fr.ZERO;
|
|
88
|
+
const counter = this.getCounter(opts?.counter);
|
|
89
|
+
const addr = opts?.contractAddress ?? this.contractAddress;
|
|
90
|
+
this.nullifiers.push(new Nullifier(value, noteHash, counter).scope(addr));
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Adds a pending note hash read request (non-empty contract address, can match a pending note hash). */
|
|
95
|
+
addPendingNoteHashReadRequest(opts?: { value?: Fr; counter?: number; contractAddress?: AztecAddress }): this {
|
|
96
|
+
const value = opts?.value ?? Fr.random();
|
|
97
|
+
const counter = this.getCounter(opts?.counter);
|
|
98
|
+
const addr = opts?.contractAddress ?? this.contractAddress;
|
|
99
|
+
this.noteHashReadRequests.push(new ScopedReadRequest(new ReadRequest(value, counter), addr));
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Adds a settled note hash read request (empty contract address, resolved against the note hash tree). */
|
|
104
|
+
addSettledNoteHashReadRequest(opts?: { value?: Fr; counter?: number }): this {
|
|
105
|
+
const value = opts?.value ?? Fr.random();
|
|
106
|
+
const counter = this.getCounter(opts?.counter);
|
|
107
|
+
this.noteHashReadRequests.push(new ScopedReadRequest(new ReadRequest(value, counter), AztecAddress.ZERO));
|
|
108
|
+
return this;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Adds a pending nullifier read request (non-empty contract address, can match a pending nullifier). */
|
|
112
|
+
addPendingNullifierReadRequest(opts?: { value?: Fr; counter?: number; contractAddress?: AztecAddress }): this {
|
|
113
|
+
const value = opts?.value ?? Fr.random();
|
|
114
|
+
const counter = this.getCounter(opts?.counter);
|
|
115
|
+
const addr = opts?.contractAddress ?? this.contractAddress;
|
|
116
|
+
this.nullifierReadRequests.push(new ScopedReadRequest(new ReadRequest(value, counter), addr));
|
|
117
|
+
return this;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Adds a settled nullifier read request (empty contract address, resolved against the nullifier tree). */
|
|
121
|
+
addSettledNullifierReadRequest(opts?: { value?: Fr; counter?: number }): this {
|
|
122
|
+
const value = opts?.value ?? Fr.random();
|
|
123
|
+
const counter = this.getCounter(opts?.counter);
|
|
124
|
+
this.nullifierReadRequests.push(new ScopedReadRequest(new ReadRequest(value, counter), AztecAddress.ZERO));
|
|
125
|
+
return this;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Adds a key validation request to validation requests. */
|
|
129
|
+
addKeyValidationRequest(opts?: { contractAddress?: AztecAddress }): this {
|
|
130
|
+
const addr = opts?.contractAddress ?? this.contractAddress;
|
|
131
|
+
this.keyValidationRequests.push(
|
|
132
|
+
new ScopedKeyValidationRequestAndSeparator(
|
|
133
|
+
new KeyValidationRequestAndSeparator(
|
|
134
|
+
new KeyValidationRequest(new Point(Fr.random(), Fr.random(), false), Fr.random()),
|
|
135
|
+
Fr.random(),
|
|
136
|
+
),
|
|
137
|
+
addr,
|
|
138
|
+
),
|
|
139
|
+
);
|
|
140
|
+
return this;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Adds a private log to the accumulated data. Defaults are generated randomly. */
|
|
144
|
+
addPrivateLog(opts?: { noteHashCounter?: number; counter?: number; contractAddress?: AztecAddress }): this {
|
|
145
|
+
const noteHashCounter = opts?.noteHashCounter ?? 0;
|
|
146
|
+
const counter = this.getCounter(opts?.counter);
|
|
147
|
+
const addr = opts?.contractAddress ?? this.contractAddress;
|
|
148
|
+
this.privateLogs.push(
|
|
149
|
+
new ScopedPrivateLogData(new PrivateLogData(PrivateLog.empty(), noteHashCounter, counter), addr),
|
|
150
|
+
);
|
|
151
|
+
return this;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Builds the PrivateKernelCircuitPublicInputs with all added side effects. */
|
|
155
|
+
build(): PrivateKernelCircuitPublicInputs {
|
|
156
|
+
const publicInputs = PrivateKernelCircuitPublicInputs.empty();
|
|
157
|
+
publicInputs.end.noteHashes = makeClaimed(this.noteHashes, ScopedNoteHash, MAX_NOTE_HASHES_PER_TX);
|
|
158
|
+
publicInputs.end.nullifiers = makeClaimed(this.nullifiers, ScopedNullifier, MAX_NULLIFIERS_PER_TX);
|
|
159
|
+
publicInputs.end.privateLogs = makeClaimed(this.privateLogs, ScopedPrivateLogData, MAX_PRIVATE_LOGS_PER_TX);
|
|
160
|
+
publicInputs.validationRequests.noteHashReadRequests = makeClaimed(
|
|
161
|
+
this.noteHashReadRequests,
|
|
162
|
+
ScopedReadRequest,
|
|
163
|
+
MAX_NOTE_HASH_READ_REQUESTS_PER_TX,
|
|
164
|
+
);
|
|
165
|
+
publicInputs.validationRequests.nullifierReadRequests = makeClaimed(
|
|
166
|
+
this.nullifierReadRequests,
|
|
167
|
+
ScopedReadRequest,
|
|
168
|
+
MAX_NULLIFIER_READ_REQUESTS_PER_TX,
|
|
169
|
+
);
|
|
170
|
+
publicInputs.validationRequests.scopedKeyValidationRequestsAndSeparators = makeClaimed(
|
|
171
|
+
this.keyValidationRequests,
|
|
172
|
+
ScopedKeyValidationRequestAndSeparator,
|
|
173
|
+
MAX_KEY_VALIDATION_REQUESTS_PER_TX,
|
|
174
|
+
);
|
|
175
|
+
return publicInputs;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** Builder for PrivateCircuitPublicInputs (call-level) with fluent API for adding side effects. */
|
|
180
|
+
export class PrivateCircuitPublicInputsBuilder {
|
|
181
|
+
private noteHashes: NoteHash[] = [];
|
|
182
|
+
private nullifiers: Nullifier[] = [];
|
|
183
|
+
private noteHashReadRequests: ScopedReadRequest[] = [];
|
|
184
|
+
private nullifierReadRequests: ScopedReadRequest[] = [];
|
|
185
|
+
private keyValidationRequests: KeyValidationRequestAndSeparator[] = [];
|
|
186
|
+
private privateLogs: PrivateLogData[] = [];
|
|
187
|
+
private nextCounter: number;
|
|
188
|
+
|
|
189
|
+
constructor(
|
|
190
|
+
private contractAddress: AztecAddress = DEFAULT_CONTRACT_ADDRESS,
|
|
191
|
+
startCounter = 1,
|
|
192
|
+
) {
|
|
193
|
+
this.nextCounter = startCounter;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private getCounter(sideEffectCounter?: number): number {
|
|
197
|
+
if (sideEffectCounter !== undefined) {
|
|
198
|
+
this.nextCounter = sideEffectCounter + 1;
|
|
199
|
+
return sideEffectCounter;
|
|
200
|
+
}
|
|
201
|
+
return this.nextCounter++;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Adds a note hash. Defaults are generated randomly. */
|
|
205
|
+
addNoteHash(opts?: { value?: Fr; counter?: number }): this {
|
|
206
|
+
const value = opts?.value ?? Fr.random();
|
|
207
|
+
const counter = this.getCounter(opts?.counter);
|
|
208
|
+
this.noteHashes.push(new NoteHash(value, counter));
|
|
209
|
+
return this;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** Adds a nullifier. Defaults are generated randomly. */
|
|
213
|
+
addNullifier(opts?: { value?: Fr; noteHash?: Fr; counter?: number }): this {
|
|
214
|
+
const value = opts?.value ?? Fr.random();
|
|
215
|
+
const noteHash = opts?.noteHash ?? Fr.ZERO;
|
|
216
|
+
const counter = this.getCounter(opts?.counter);
|
|
217
|
+
this.nullifiers.push(new Nullifier(value, noteHash, counter));
|
|
218
|
+
return this;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Adds a pending note hash read request (non-empty contract address, can match a pending note hash). */
|
|
222
|
+
addPendingNoteHashReadRequest(opts?: { value?: Fr; counter?: number }): this {
|
|
223
|
+
const value = opts?.value ?? Fr.random();
|
|
224
|
+
const counter = this.getCounter(opts?.counter);
|
|
225
|
+
this.noteHashReadRequests.push(new ScopedReadRequest(new ReadRequest(value, counter), this.contractAddress));
|
|
226
|
+
return this;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Adds a settled note hash read request (empty contract address, resolved against the note hash tree). */
|
|
230
|
+
addSettledNoteHashReadRequest(opts?: { value?: Fr; counter?: number }): this {
|
|
231
|
+
const value = opts?.value ?? Fr.random();
|
|
232
|
+
const counter = this.getCounter(opts?.counter);
|
|
233
|
+
this.noteHashReadRequests.push(new ScopedReadRequest(new ReadRequest(value, counter), AztecAddress.ZERO));
|
|
234
|
+
return this;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** Adds a pending nullifier read request (non-empty contract address, can match a pending nullifier). */
|
|
238
|
+
addPendingNullifierReadRequest(opts?: { value?: Fr; counter?: number }): this {
|
|
239
|
+
const value = opts?.value ?? Fr.random();
|
|
240
|
+
const counter = this.getCounter(opts?.counter);
|
|
241
|
+
this.nullifierReadRequests.push(new ScopedReadRequest(new ReadRequest(value, counter), this.contractAddress));
|
|
242
|
+
return this;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** Adds a settled nullifier read request (empty contract address, resolved against the nullifier tree). */
|
|
246
|
+
addSettledNullifierReadRequest(opts?: { value?: Fr; counter?: number }): this {
|
|
247
|
+
const value = opts?.value ?? Fr.random();
|
|
248
|
+
const counter = this.getCounter(opts?.counter);
|
|
249
|
+
this.nullifierReadRequests.push(new ScopedReadRequest(new ReadRequest(value, counter), AztecAddress.ZERO));
|
|
250
|
+
return this;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** Adds a key validation request. */
|
|
254
|
+
addKeyValidationRequest(): this {
|
|
255
|
+
this.keyValidationRequests.push(
|
|
256
|
+
new KeyValidationRequestAndSeparator(
|
|
257
|
+
new KeyValidationRequest(new Point(Fr.random(), Fr.random(), false), Fr.random()),
|
|
258
|
+
Fr.random(),
|
|
259
|
+
),
|
|
260
|
+
);
|
|
261
|
+
return this;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** Adds a private log. Defaults are generated randomly. */
|
|
265
|
+
addPrivateLog(opts?: { noteHashCounter?: number; counter?: number }): this {
|
|
266
|
+
const noteHashCounter = opts?.noteHashCounter ?? 0;
|
|
267
|
+
const counter = this.getCounter(opts?.counter);
|
|
268
|
+
this.privateLogs.push(new PrivateLogData(PrivateLog.empty(), noteHashCounter, counter));
|
|
269
|
+
return this;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** Builds the PrivateCircuitPublicInputs with all added side effects. */
|
|
273
|
+
build(): PrivateCircuitPublicInputs {
|
|
274
|
+
const publicInputs = PrivateCircuitPublicInputs.empty();
|
|
275
|
+
publicInputs.callContext.contractAddress = this.contractAddress;
|
|
276
|
+
publicInputs.noteHashes = makeClaimed(this.noteHashes, NoteHash, MAX_NOTE_HASHES_PER_CALL);
|
|
277
|
+
publicInputs.nullifiers = makeClaimed(this.nullifiers, Nullifier, MAX_NULLIFIERS_PER_CALL);
|
|
278
|
+
publicInputs.privateLogs = makeClaimed(this.privateLogs, PrivateLogData, MAX_PRIVATE_LOGS_PER_CALL);
|
|
279
|
+
publicInputs.noteHashReadRequests = makeClaimed(
|
|
280
|
+
this.noteHashReadRequests,
|
|
281
|
+
ScopedReadRequest,
|
|
282
|
+
MAX_NOTE_HASH_READ_REQUESTS_PER_CALL,
|
|
283
|
+
);
|
|
284
|
+
publicInputs.nullifierReadRequests = makeClaimed(
|
|
285
|
+
this.nullifierReadRequests,
|
|
286
|
+
ScopedReadRequest,
|
|
287
|
+
MAX_NULLIFIER_READ_REQUESTS_PER_CALL,
|
|
288
|
+
);
|
|
289
|
+
publicInputs.keyValidationRequestsAndSeparators = makeClaimed(
|
|
290
|
+
this.keyValidationRequests,
|
|
291
|
+
KeyValidationRequestAndSeparator,
|
|
292
|
+
MAX_KEY_VALIDATION_REQUESTS_PER_CALL,
|
|
293
|
+
);
|
|
294
|
+
return publicInputs;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** Wraps a PrivateKernelCircuitPublicInputs in a PrivateKernelSimulateOutput. */
|
|
299
|
+
export function makeKernelOutput(
|
|
300
|
+
publicInputs?: PrivateKernelCircuitPublicInputs,
|
|
301
|
+
): PrivateKernelSimulateOutput<PrivateKernelCircuitPublicInputs> {
|
|
302
|
+
return {
|
|
303
|
+
publicInputs: publicInputs ?? PrivateKernelCircuitPublicInputs.empty(),
|
|
304
|
+
verificationKey: VerificationKeyData.empty(),
|
|
305
|
+
outputWitness: new Map(),
|
|
306
|
+
bytecode: Buffer.from([]),
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/** Wraps a PrivateCircuitPublicInputs in a PrivateCallExecutionResult. */
|
|
311
|
+
export function makeExecutionResult(publicInputs?: PrivateCircuitPublicInputs): PrivateCallExecutionResult {
|
|
312
|
+
return new PrivateCallExecutionResult(
|
|
313
|
+
Buffer.alloc(0),
|
|
314
|
+
Buffer.alloc(0),
|
|
315
|
+
new Map(),
|
|
316
|
+
publicInputs ?? PrivateCircuitPublicInputs.empty(),
|
|
317
|
+
[],
|
|
318
|
+
new Map(),
|
|
319
|
+
[],
|
|
320
|
+
[],
|
|
321
|
+
[],
|
|
322
|
+
[],
|
|
323
|
+
[],
|
|
324
|
+
);
|
|
325
|
+
}
|
|
@@ -116,6 +116,7 @@ export class PrivateKernelExecutionProver {
|
|
|
116
116
|
splitCounter,
|
|
117
117
|
);
|
|
118
118
|
while (resetBuilder.needsReset()) {
|
|
119
|
+
// Inner reset: without siloing.
|
|
119
120
|
const witgenTimer = new Timer();
|
|
120
121
|
const privateInputs = await resetBuilder.build(this.oracle);
|
|
121
122
|
output = generateWitnesses
|
|
@@ -216,16 +217,24 @@ export class PrivateKernelExecutionProver {
|
|
|
216
217
|
firstIteration = false;
|
|
217
218
|
}
|
|
218
219
|
|
|
219
|
-
//
|
|
220
|
-
|
|
220
|
+
// Final reset: include siloing of note hashes, nullifiers and private logs.
|
|
221
|
+
const finalResetBuilder = new PrivateKernelResetPrivateInputsBuilder(
|
|
221
222
|
output,
|
|
222
223
|
[],
|
|
223
224
|
noteHashNullifierCounterMap,
|
|
224
225
|
splitCounter,
|
|
225
226
|
);
|
|
226
|
-
|
|
227
|
+
if (!finalResetBuilder.needsReset()) {
|
|
228
|
+
// The final reset must be performed exactly once, because each tx has at least one nullifier that requires
|
|
229
|
+
// siloing, and siloing cannot be done multiple times.
|
|
230
|
+
// While, in theory, it might be possible to silo note hashes first and then run another reset to silo nullifiers
|
|
231
|
+
// and/or private logs, we currently don't have standalone dimensions for the arrays that require siloing. As a
|
|
232
|
+
// result, all necessary siloing must be done together in a single reset.
|
|
233
|
+
// Refer to the possible combinations of dimensions in private_kernel_reset_config.json.
|
|
234
|
+
throw new Error('Nothing to reset for the final reset.');
|
|
235
|
+
} else {
|
|
227
236
|
const witgenTimer = new Timer();
|
|
228
|
-
const privateInputs = await
|
|
237
|
+
const privateInputs = await finalResetBuilder.build(this.oracle);
|
|
229
238
|
output = generateWitnesses
|
|
230
239
|
? await this.proofCreator.generateResetOutput(privateInputs)
|
|
231
240
|
: await this.proofCreator.simulateReset(privateInputs);
|
|
@@ -239,8 +248,6 @@ export class PrivateKernelExecutionProver {
|
|
|
239
248
|
witgen: witgenTimer.ms(),
|
|
240
249
|
},
|
|
241
250
|
});
|
|
242
|
-
|
|
243
|
-
resetBuilder = new PrivateKernelResetPrivateInputsBuilder(output, [], noteHashNullifierCounterMap, splitCounter);
|
|
244
251
|
}
|
|
245
252
|
|
|
246
253
|
if (output.publicInputs.feePayer.isZero() && skipFeeEnforcement) {
|
package/src/pxe.ts
CHANGED
|
@@ -958,7 +958,8 @@ export class PXE {
|
|
|
958
958
|
const validationResult = await this.node.isValidTx(simulatedTx, { isSimulation: true, skipFeeEnforcement });
|
|
959
959
|
validationTime = validationTimer.ms();
|
|
960
960
|
if (validationResult.result === 'invalid') {
|
|
961
|
-
|
|
961
|
+
const reason = validationResult.reason.length > 0 ? ` Reason: ${validationResult.reason.join(', ')}` : '';
|
|
962
|
+
throw new Error(`The simulated transaction is unable to be added to state and is invalid.${reason}`);
|
|
962
963
|
}
|
|
963
964
|
}
|
|
964
965
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ExtendedDirectionalAppTaggingSecret } from '@aztec/stdlib/logs';
|
|
3
3
|
|
|
4
4
|
import type { StagedStore } from '../../job_coordinator/job_coordinator.js';
|
|
5
5
|
|
|
@@ -106,11 +106,11 @@ export class RecipientTaggingStore implements StagedStore {
|
|
|
106
106
|
return Promise.resolve();
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
getHighestAgedIndex(secret:
|
|
109
|
+
getHighestAgedIndex(secret: ExtendedDirectionalAppTaggingSecret, jobId: string): Promise<number | undefined> {
|
|
110
110
|
return this.#store.transactionAsync(() => this.#readHighestAgedIndex(jobId, secret.toString()));
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
updateHighestAgedIndex(secret:
|
|
113
|
+
updateHighestAgedIndex(secret: ExtendedDirectionalAppTaggingSecret, index: number, jobId: string): Promise<void> {
|
|
114
114
|
return this.#store.transactionAsync(async () => {
|
|
115
115
|
const currentIndex = await this.#readHighestAgedIndex(jobId, secret.toString());
|
|
116
116
|
if (currentIndex !== undefined && index <= currentIndex) {
|
|
@@ -121,11 +121,15 @@ export class RecipientTaggingStore implements StagedStore {
|
|
|
121
121
|
});
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
getHighestFinalizedIndex(secret:
|
|
124
|
+
getHighestFinalizedIndex(secret: ExtendedDirectionalAppTaggingSecret, jobId: string): Promise<number | undefined> {
|
|
125
125
|
return this.#store.transactionAsync(() => this.#readHighestFinalizedIndex(jobId, secret.toString()));
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
updateHighestFinalizedIndex(
|
|
128
|
+
updateHighestFinalizedIndex(
|
|
129
|
+
secret: ExtendedDirectionalAppTaggingSecret,
|
|
130
|
+
index: number,
|
|
131
|
+
jobId: string,
|
|
132
|
+
): Promise<void> {
|
|
129
133
|
return this.#store.transactionAsync(async () => {
|
|
130
134
|
const currentIndex = await this.#readHighestFinalizedIndex(jobId, secret.toString());
|
|
131
135
|
if (currentIndex !== undefined && index < currentIndex) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AztecAsyncKVStore, AztecAsyncMap } from '@aztec/kv-store';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ExtendedDirectionalAppTaggingSecret, PreTag } from '@aztec/stdlib/logs';
|
|
3
3
|
import { TxHash } from '@aztec/stdlib/tx';
|
|
4
4
|
|
|
5
5
|
import type { StagedStore } from '../../job_coordinator/job_coordinator.js';
|
|
@@ -154,7 +154,7 @@ export class SenderTaggingStore implements StagedStore {
|
|
|
154
154
|
|
|
155
155
|
// The secrets in pre-tags should be unique because we always store just the highest index per given secret-txHash
|
|
156
156
|
// pair. Below we check that this is the case.
|
|
157
|
-
const secretsSet = new Set(preTags.map(preTag => preTag.
|
|
157
|
+
const secretsSet = new Set(preTags.map(preTag => preTag.extendedSecret.toString()));
|
|
158
158
|
if (secretsSet.size !== preTags.length) {
|
|
159
159
|
return Promise.reject(new Error(`Duplicate secrets found when storing pending indexes`));
|
|
160
160
|
}
|
|
@@ -163,10 +163,10 @@ export class SenderTaggingStore implements StagedStore {
|
|
|
163
163
|
|
|
164
164
|
return this.#store.transactionAsync(async () => {
|
|
165
165
|
// Prefetch all data, start reads during iteration to keep IndexedDB transaction alive
|
|
166
|
-
const preTagReadPromises = preTags.map(({
|
|
167
|
-
const secretStr =
|
|
166
|
+
const preTagReadPromises = preTags.map(({ extendedSecret, index }) => {
|
|
167
|
+
const secretStr = extendedSecret.toString();
|
|
168
168
|
return {
|
|
169
|
-
|
|
169
|
+
extendedSecret,
|
|
170
170
|
secretStr,
|
|
171
171
|
index,
|
|
172
172
|
pending: this.#readPendingIndexes(jobId, secretStr),
|
|
@@ -233,7 +233,7 @@ export class SenderTaggingStore implements StagedStore {
|
|
|
233
233
|
* [startIndex, endIndex). Returns an empty array if no pending indexes exist in the range.
|
|
234
234
|
*/
|
|
235
235
|
getTxHashesOfPendingIndexes(
|
|
236
|
-
secret:
|
|
236
|
+
secret: ExtendedDirectionalAppTaggingSecret,
|
|
237
237
|
startIndex: number,
|
|
238
238
|
endIndex: number,
|
|
239
239
|
jobId: string,
|
|
@@ -252,7 +252,7 @@ export class SenderTaggingStore implements StagedStore {
|
|
|
252
252
|
* @param secret - The secret to get the last finalized index for.
|
|
253
253
|
* @returns The last (highest) finalized index for the given secret.
|
|
254
254
|
*/
|
|
255
|
-
getLastFinalizedIndex(secret:
|
|
255
|
+
getLastFinalizedIndex(secret: ExtendedDirectionalAppTaggingSecret, jobId: string): Promise<number | undefined> {
|
|
256
256
|
return this.#store.transactionAsync(() => this.#readLastFinalizedIndex(jobId, secret.toString()));
|
|
257
257
|
}
|
|
258
258
|
|
|
@@ -262,7 +262,7 @@ export class SenderTaggingStore implements StagedStore {
|
|
|
262
262
|
* @param secret - The directional app tagging secret to query the last used index for.
|
|
263
263
|
* @returns The last used index.
|
|
264
264
|
*/
|
|
265
|
-
getLastUsedIndex(secret:
|
|
265
|
+
getLastUsedIndex(secret: ExtendedDirectionalAppTaggingSecret, jobId: string): Promise<number | undefined> {
|
|
266
266
|
const secretStr = secret.toString();
|
|
267
267
|
|
|
268
268
|
return this.#store.transactionAsync(async () => {
|
package/src/tagging/index.ts
CHANGED
|
@@ -15,5 +15,5 @@ export { UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN } from './constants.js';
|
|
|
15
15
|
export { getAllPrivateLogsByTags, getAllPublicLogsByTagsFromContract } from './get_all_logs_by_tags.js';
|
|
16
16
|
|
|
17
17
|
// Re-export tagging-related types from stdlib
|
|
18
|
-
export {
|
|
18
|
+
export { ExtendedDirectionalAppTaggingSecret, Tag, SiloedTag } from '@aztec/stdlib/logs';
|
|
19
19
|
export { type PreTag } from '@aztec/stdlib/logs';
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
-
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
3
2
|
import type { BlockHash } from '@aztec/stdlib/block';
|
|
4
3
|
import type { AztecNode } from '@aztec/stdlib/interfaces/client';
|
|
5
|
-
import type {
|
|
4
|
+
import type { ExtendedDirectionalAppTaggingSecret, TxScopedL2Log } from '@aztec/stdlib/logs';
|
|
6
5
|
|
|
7
6
|
import type { RecipientTaggingStore } from '../../storage/tagging_store/recipient_tagging_store.js';
|
|
8
7
|
import { UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN } from '../constants.js';
|
|
@@ -10,15 +9,14 @@ import { findHighestIndexes } from './utils/find_highest_indexes.js';
|
|
|
10
9
|
import { loadLogsForRange } from './utils/load_logs_for_range.js';
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
|
-
* Loads private logs for
|
|
12
|
+
* Loads private logs for the app-sender-recipient triplet defined by `secret` and updates the highest aged and
|
|
14
13
|
* finalized indexes in the db. At most load logs from blocks up to and including `anchorBlockNumber`.
|
|
15
14
|
*
|
|
16
15
|
* @dev This function can be safely executed "in parallel" for other sender-recipient pairs because the data in
|
|
17
16
|
* in the tagging data provider is indexed by the secret and hence completely disjoint.
|
|
18
17
|
*/
|
|
19
18
|
export async function loadPrivateLogsForSenderRecipientPair(
|
|
20
|
-
secret:
|
|
21
|
-
app: AztecAddress,
|
|
19
|
+
secret: ExtendedDirectionalAppTaggingSecret,
|
|
22
20
|
aztecNode: AztecNode,
|
|
23
21
|
taggingStore: RecipientTaggingStore,
|
|
24
22
|
anchorBlockNumber: BlockNumber,
|
|
@@ -96,7 +94,6 @@ export async function loadPrivateLogsForSenderRecipientPair(
|
|
|
96
94
|
// Get private logs with their block timestamps and corresponding tagging indexes
|
|
97
95
|
const privateLogsWithIndexes = await loadLogsForRange(
|
|
98
96
|
secret,
|
|
99
|
-
app,
|
|
100
97
|
aztecNode,
|
|
101
98
|
start,
|
|
102
99
|
end,
|
|
@@ -1,32 +1,27 @@
|
|
|
1
1
|
import type { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
-
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
3
2
|
import type { BlockHash } from '@aztec/stdlib/block';
|
|
4
3
|
import type { AztecNode } from '@aztec/stdlib/interfaces/client';
|
|
5
|
-
import type {
|
|
6
|
-
import { SiloedTag
|
|
4
|
+
import type { ExtendedDirectionalAppTaggingSecret, TxScopedL2Log } from '@aztec/stdlib/logs';
|
|
5
|
+
import { SiloedTag } from '@aztec/stdlib/logs';
|
|
7
6
|
|
|
8
7
|
import { getAllPrivateLogsByTags } from '../../get_all_logs_by_tags.js';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
|
-
* Gets private logs with their corresponding block timestamps and tagging indexes for the given index range
|
|
12
|
-
* `
|
|
13
|
-
* exclusive.
|
|
10
|
+
* Gets private logs with their corresponding block timestamps and tagging indexes for the given index range and
|
|
11
|
+
* `extendedSecret`. At most load logs from blocks up to and including `anchorBlockNumber`. `start` is inclusive and
|
|
12
|
+
* `end` is exclusive.
|
|
14
13
|
*/
|
|
15
14
|
export async function loadLogsForRange(
|
|
16
|
-
|
|
17
|
-
app: AztecAddress,
|
|
15
|
+
extendedSecret: ExtendedDirectionalAppTaggingSecret,
|
|
18
16
|
aztecNode: AztecNode,
|
|
19
17
|
start: number,
|
|
20
18
|
end: number,
|
|
21
19
|
anchorBlockNumber: BlockNumber,
|
|
22
20
|
anchorBlockHash: BlockHash,
|
|
23
21
|
): Promise<Array<{ log: TxScopedL2Log; taggingIndex: number }>> {
|
|
24
|
-
// Derive tags for the window
|
|
25
|
-
const
|
|
26
|
-
.
|
|
27
|
-
.map((_, i) => ({ secret, index: start + i }));
|
|
28
|
-
const siloedTags = await Promise.all(preTags.map(preTag => Tag.compute(preTag))).then(tags =>
|
|
29
|
-
Promise.all(tags.map(tag => SiloedTag.compute(tag, app))),
|
|
22
|
+
// Derive siloed tags for the window
|
|
23
|
+
const siloedTags = await Promise.all(
|
|
24
|
+
Array.from({ length: end - start }, (_, i) => SiloedTag.compute({ extendedSecret, index: start + i })),
|
|
30
25
|
);
|
|
31
26
|
|
|
32
27
|
// We use the utility function below to retrieve all logs for the tags across all pages, so we don't need to handle
|
|
@@ -37,7 +32,7 @@ export async function loadLogsForRange(
|
|
|
37
32
|
const logsWithIndexes: Array<{ log: TxScopedL2Log; taggingIndex: number }> = [];
|
|
38
33
|
for (let i = 0; i < logs.length; i++) {
|
|
39
34
|
const logsForTag = logs[i];
|
|
40
|
-
const taggingIndex =
|
|
35
|
+
const taggingIndex = start + i;
|
|
41
36
|
for (const log of logsForTag) {
|
|
42
37
|
if (log.blockNumber <= anchorBlockNumber) {
|
|
43
38
|
logsWithIndexes.push({ log, taggingIndex });
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
2
1
|
import type { BlockHash } from '@aztec/stdlib/block';
|
|
3
2
|
import type { AztecNode } from '@aztec/stdlib/interfaces/server';
|
|
4
|
-
import type {
|
|
3
|
+
import type { ExtendedDirectionalAppTaggingSecret } from '@aztec/stdlib/logs';
|
|
5
4
|
|
|
6
5
|
import type { SenderTaggingStore } from '../../storage/tagging_store/sender_tagging_store.js';
|
|
7
6
|
import { UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN } from '../constants.js';
|
|
@@ -11,11 +10,8 @@ import { loadAndStoreNewTaggingIndexes } from './utils/load_and_store_new_taggin
|
|
|
11
10
|
/**
|
|
12
11
|
* Syncs tagging indexes. This function needs to be called whenever a private log is being sent.
|
|
13
12
|
*
|
|
14
|
-
* @param secret - The secret that's unique for (sender, recipient,
|
|
13
|
+
* @param secret - The secret that's unique for (sender, recipient, app) tuple while the direction of
|
|
15
14
|
* sender -> recipient matters.
|
|
16
|
-
* @param app - The address of the contract that the logs are tagged for. Needs to be provided because we perform
|
|
17
|
-
* second round of siloing in this function which is necessary because kernels do it as well (they silo first field
|
|
18
|
-
* of the private log which corresponds to the tag).
|
|
19
15
|
* @remarks When syncing the indexes as sender we don't care about the log contents - we only care about the highest
|
|
20
16
|
* pending and highest finalized indexes as that guides the next index choice when sending a log. The next index choice
|
|
21
17
|
* is simply the highest pending index plus one (or finalized if pending is undefined).
|
|
@@ -23,8 +19,7 @@ import { loadAndStoreNewTaggingIndexes } from './utils/load_and_store_new_taggin
|
|
|
23
19
|
* updates its status accordingly.
|
|
24
20
|
*/
|
|
25
21
|
export async function syncSenderTaggingIndexes(
|
|
26
|
-
secret:
|
|
27
|
-
app: AztecAddress,
|
|
22
|
+
secret: ExtendedDirectionalAppTaggingSecret,
|
|
28
23
|
aztecNode: AztecNode,
|
|
29
24
|
taggingStore: SenderTaggingStore,
|
|
30
25
|
anchorBlockHash: BlockHash,
|
|
@@ -59,7 +54,7 @@ export async function syncSenderTaggingIndexes(
|
|
|
59
54
|
while (true) {
|
|
60
55
|
// Load and store indexes for the current window. These indexes may already exist in the database if txs using
|
|
61
56
|
// them were previously sent from this PXE. Any duplicates are handled by the tagging data provider.
|
|
62
|
-
await loadAndStoreNewTaggingIndexes(secret,
|
|
57
|
+
await loadAndStoreNewTaggingIndexes(secret, start, end, aztecNode, taggingStore, anchorBlockHash, jobId);
|
|
63
58
|
|
|
64
59
|
// Retrieve all indexes within the current window from storage and update their status accordingly.
|
|
65
60
|
const pendingTxHashes = await taggingStore.getTxHashesOfPendingIndexes(secret, start, end, jobId);
|