@aztec/sequencer-client 0.32.1 → 0.34.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/global_variable_builder/global_builder.js +2 -2
- package/dest/publisher/l1-publisher.js +10 -10
- package/dest/publisher/viem-tx-sender.js +2 -2
- package/dest/sequencer/abstract_phase_manager.d.ts +16 -4
- package/dest/sequencer/abstract_phase_manager.d.ts.map +1 -1
- package/dest/sequencer/abstract_phase_manager.js +38 -39
- package/dest/sequencer/app_logic_phase_manager.d.ts +1 -0
- package/dest/sequencer/app_logic_phase_manager.d.ts.map +1 -1
- package/dest/sequencer/app_logic_phase_manager.js +4 -4
- package/dest/sequencer/hints_builder.d.ts +7 -3
- package/dest/sequencer/hints_builder.d.ts.map +1 -1
- package/dest/sequencer/hints_builder.js +24 -4
- package/dest/sequencer/phase_manager_factory.d.ts.map +1 -1
- package/dest/sequencer/phase_manager_factory.js +5 -4
- package/dest/sequencer/public_processor.d.ts +6 -3
- package/dest/sequencer/public_processor.d.ts.map +1 -1
- package/dest/sequencer/public_processor.js +65 -27
- package/dest/sequencer/sequencer.d.ts +2 -12
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +43 -49
- package/dest/sequencer/setup_phase_manager.d.ts +1 -0
- package/dest/sequencer/setup_phase_manager.d.ts.map +1 -1
- package/dest/sequencer/setup_phase_manager.js +3 -3
- package/dest/sequencer/tail_phase_manager.d.ts +6 -1
- package/dest/sequencer/tail_phase_manager.d.ts.map +1 -1
- package/dest/sequencer/tail_phase_manager.js +29 -4
- package/dest/sequencer/teardown_phase_manager.d.ts +1 -0
- package/dest/sequencer/teardown_phase_manager.d.ts.map +1 -1
- package/dest/sequencer/teardown_phase_manager.js +3 -3
- package/dest/sequencer/tx_validator.d.ts +2 -1
- package/dest/sequencer/tx_validator.d.ts.map +1 -1
- package/dest/sequencer/tx_validator.js +8 -7
- package/dest/sequencer/utils.d.ts.map +1 -1
- package/dest/sequencer/utils.js +8 -7
- package/dest/simulator/index.d.ts +2 -2
- package/dest/simulator/index.d.ts.map +1 -1
- package/dest/simulator/public_executor.js +3 -3
- package/dest/simulator/public_kernel.d.ts +2 -2
- package/dest/simulator/public_kernel.d.ts.map +1 -1
- package/dest/simulator/public_kernel.js +5 -5
- package/package.json +32 -15
- package/src/global_variable_builder/global_builder.ts +1 -1
- package/src/publisher/l1-publisher.ts +9 -9
- package/src/publisher/viem-tx-sender.ts +1 -1
- package/src/sequencer/abstract_phase_manager.ts +74 -63
- package/src/sequencer/app_logic_phase_manager.ts +3 -3
- package/src/sequencer/hints_builder.ts +42 -9
- package/src/sequencer/phase_manager_factory.ts +4 -3
- package/src/sequencer/public_processor.ts +97 -51
- package/src/sequencer/sequencer.ts +51 -61
- package/src/sequencer/setup_phase_manager.ts +2 -2
- package/src/sequencer/tail_phase_manager.ts +67 -3
- package/src/sequencer/teardown_phase_manager.ts +2 -2
- package/src/sequencer/tx_validator.ts +8 -6
- package/src/sequencer/utils.ts +7 -6
- package/src/simulator/index.ts +2 -1
- package/src/simulator/public_executor.ts +2 -2
- package/src/simulator/public_kernel.ts +6 -5
- package/dest/utils.d.ts +0 -12
- package/dest/utils.d.ts.map +0 -1
- package/dest/utils.js +0 -16
- package/src/utils.ts +0 -16
|
@@ -7,18 +7,18 @@ import {
|
|
|
7
7
|
Fr,
|
|
8
8
|
type GlobalVariables,
|
|
9
9
|
type Header,
|
|
10
|
+
type KernelCircuitPublicInputs,
|
|
10
11
|
L2ToL1Message,
|
|
11
12
|
MAX_NEW_L2_TO_L1_MSGS_PER_CALL,
|
|
12
13
|
MAX_NEW_NOTE_HASHES_PER_CALL,
|
|
13
14
|
MAX_NEW_NULLIFIERS_PER_CALL,
|
|
14
|
-
MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
15
15
|
MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL,
|
|
16
16
|
MAX_NULLIFIER_READ_REQUESTS_PER_CALL,
|
|
17
17
|
MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL,
|
|
18
18
|
MAX_PUBLIC_DATA_READS_PER_CALL,
|
|
19
19
|
MAX_PUBLIC_DATA_READS_PER_TX,
|
|
20
20
|
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL,
|
|
21
|
-
|
|
21
|
+
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
22
22
|
MembershipWitness,
|
|
23
23
|
type PrivateKernelTailCircuitPublicInputs,
|
|
24
24
|
type Proof,
|
|
@@ -31,7 +31,6 @@ import {
|
|
|
31
31
|
PublicKernelCircuitPrivateInputs,
|
|
32
32
|
type PublicKernelCircuitPublicInputs,
|
|
33
33
|
PublicKernelData,
|
|
34
|
-
PublicKernelTailCircuitPrivateInputs,
|
|
35
34
|
RETURN_VALUES_LENGTH,
|
|
36
35
|
ReadRequest,
|
|
37
36
|
RevertCode,
|
|
@@ -42,6 +41,13 @@ import {
|
|
|
42
41
|
makeEmptyProof,
|
|
43
42
|
} from '@aztec/circuits.js';
|
|
44
43
|
import { computeVarArgsHash } from '@aztec/circuits.js/hash';
|
|
44
|
+
import {
|
|
45
|
+
type AbiType,
|
|
46
|
+
type DecodedReturn,
|
|
47
|
+
type FunctionArtifact,
|
|
48
|
+
type ProcessReturnValues,
|
|
49
|
+
decodeReturnValues,
|
|
50
|
+
} from '@aztec/foundation/abi';
|
|
45
51
|
import { arrayNonEmptyLength, padArrayEnd } from '@aztec/foundation/collection';
|
|
46
52
|
import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';
|
|
47
53
|
import { type Tuple } from '@aztec/foundation/serialize';
|
|
@@ -102,6 +108,10 @@ export abstract class AbstractPhaseManager {
|
|
|
102
108
|
* the output of the public kernel circuit for this phase
|
|
103
109
|
*/
|
|
104
110
|
publicKernelOutput: PublicKernelCircuitPublicInputs;
|
|
111
|
+
/**
|
|
112
|
+
* the final output of the public kernel circuit for this phase
|
|
113
|
+
*/
|
|
114
|
+
finalKernelOutput?: KernelCircuitPublicInputs;
|
|
105
115
|
/**
|
|
106
116
|
* the proof of the public kernel circuit for this phase
|
|
107
117
|
*/
|
|
@@ -110,6 +120,7 @@ export abstract class AbstractPhaseManager {
|
|
|
110
120
|
* revert reason, if any
|
|
111
121
|
*/
|
|
112
122
|
revertReason: SimulationError | undefined;
|
|
123
|
+
returnValues: ProcessReturnValues;
|
|
113
124
|
}>;
|
|
114
125
|
|
|
115
126
|
public static extractEnqueuedPublicCallsByPhase(
|
|
@@ -117,8 +128,10 @@ export abstract class AbstractPhaseManager {
|
|
|
117
128
|
enqueuedPublicFunctionCalls: PublicCallRequest[],
|
|
118
129
|
): Record<PublicKernelPhase, PublicCallRequest[]> {
|
|
119
130
|
const publicCallsStack = enqueuedPublicFunctionCalls.slice().reverse();
|
|
120
|
-
const nonRevertibleCallStack = publicInputs.endNonRevertibleData.publicCallStack.filter(
|
|
121
|
-
|
|
131
|
+
const nonRevertibleCallStack = publicInputs.forPublic!.endNonRevertibleData.publicCallStack.filter(
|
|
132
|
+
i => !i.isEmpty(),
|
|
133
|
+
);
|
|
134
|
+
const revertibleCallStack = publicInputs.forPublic!.end.publicCallStack.filter(i => !i.isEmpty());
|
|
122
135
|
|
|
123
136
|
const callRequestsStack = publicCallsStack
|
|
124
137
|
.map(call => call.toCallRequest())
|
|
@@ -180,14 +193,22 @@ export abstract class AbstractPhaseManager {
|
|
|
180
193
|
tx: Tx,
|
|
181
194
|
previousPublicKernelOutput: PublicKernelCircuitPublicInputs,
|
|
182
195
|
previousPublicKernelProof: Proof,
|
|
183
|
-
): Promise<
|
|
196
|
+
): Promise<
|
|
197
|
+
[
|
|
198
|
+
PublicKernelCircuitPublicInputs,
|
|
199
|
+
Proof,
|
|
200
|
+
UnencryptedFunctionL2Logs[],
|
|
201
|
+
SimulationError | undefined,
|
|
202
|
+
ProcessReturnValues,
|
|
203
|
+
]
|
|
204
|
+
> {
|
|
184
205
|
let kernelOutput = previousPublicKernelOutput;
|
|
185
206
|
let kernelProof = previousPublicKernelProof;
|
|
186
207
|
|
|
187
208
|
const enqueuedCalls = this.extractEnqueuedPublicCalls(tx);
|
|
188
209
|
|
|
189
210
|
if (!enqueuedCalls || !enqueuedCalls.length) {
|
|
190
|
-
return [kernelOutput, kernelProof, [], undefined];
|
|
211
|
+
return [kernelOutput, kernelProof, [], undefined, undefined];
|
|
191
212
|
}
|
|
192
213
|
|
|
193
214
|
const newUnencryptedFunctionLogs: UnencryptedFunctionL2Logs[] = [];
|
|
@@ -196,24 +217,24 @@ export abstract class AbstractPhaseManager {
|
|
|
196
217
|
// separate public callstacks to be proven by separate public kernel sequences
|
|
197
218
|
// and submitted separately to the base rollup?
|
|
198
219
|
|
|
220
|
+
const returns = [];
|
|
221
|
+
|
|
199
222
|
for (const enqueuedCall of enqueuedCalls) {
|
|
200
223
|
const executionStack: (PublicExecution | PublicExecutionResult)[] = [enqueuedCall];
|
|
201
224
|
|
|
225
|
+
let currentReturn: DecodedReturn | undefined = undefined;
|
|
226
|
+
|
|
202
227
|
// Keep track of which result is for the top/enqueued call
|
|
203
228
|
let enqueuedExecutionResult: PublicExecutionResult | undefined;
|
|
204
229
|
|
|
205
230
|
while (executionStack.length) {
|
|
206
231
|
const current = executionStack.pop()!;
|
|
207
232
|
const isExecutionRequest = !isPublicExecutionResult(current);
|
|
208
|
-
|
|
209
233
|
const sideEffectCounter = lastSideEffectCounter(tx) + 1;
|
|
210
|
-
// NOTE: temporary glue to incorporate avm execution calls.
|
|
211
|
-
const simulator = (execution: PublicExecution, globalVariables: GlobalVariables) =>
|
|
212
|
-
execution.functionData.isTranspiled
|
|
213
|
-
? this.publicExecutor.simulateAvm(execution, globalVariables, sideEffectCounter)
|
|
214
|
-
: this.publicExecutor.simulate(execution, globalVariables, sideEffectCounter);
|
|
215
234
|
|
|
216
|
-
const result = isExecutionRequest
|
|
235
|
+
const result = isExecutionRequest
|
|
236
|
+
? await this.publicExecutor.simulate(current, this.globalVariables, sideEffectCounter)
|
|
237
|
+
: current;
|
|
217
238
|
|
|
218
239
|
const functionSelector = result.execution.functionData.selector.toString();
|
|
219
240
|
if (result.reverted && !PhaseIsRevertible[this.phase]) {
|
|
@@ -238,7 +259,7 @@ export abstract class AbstractPhaseManager {
|
|
|
238
259
|
// sanity check. Note we can't expect them to just be equal, because e.g.
|
|
239
260
|
// if the simulator reverts in app logic, it "resets" and result.reverted will be false when we run teardown,
|
|
240
261
|
// but the kernel carries the reverted flag forward. But if the simulator reverts, so should the kernel.
|
|
241
|
-
if (result.reverted && kernelOutput.
|
|
262
|
+
if (result.reverted && kernelOutput.revertCode.isOK()) {
|
|
242
263
|
throw new Error(
|
|
243
264
|
`Public kernel circuit did not revert on ${result.execution.contractAddress.toString()}:${functionSelector}, but simulator did.`,
|
|
244
265
|
);
|
|
@@ -252,64 +273,52 @@ export abstract class AbstractPhaseManager {
|
|
|
252
273
|
result.revertReason
|
|
253
274
|
}`,
|
|
254
275
|
);
|
|
255
|
-
return [kernelOutput, kernelProof, [], result.revertReason];
|
|
276
|
+
return [kernelOutput, kernelProof, [], result.revertReason, undefined];
|
|
256
277
|
}
|
|
257
278
|
|
|
258
279
|
if (!enqueuedExecutionResult) {
|
|
259
280
|
enqueuedExecutionResult = result;
|
|
281
|
+
|
|
282
|
+
// Padding as the AVM is not always returning the expected return size (4)
|
|
283
|
+
// which is expected by the kernel.
|
|
284
|
+
const paddedReturn = padArrayEnd(result.returnValues, Fr.ZERO, RETURN_VALUES_LENGTH);
|
|
285
|
+
|
|
286
|
+
// TODO(#5450) Need to use the proper return values here
|
|
287
|
+
const returnTypes: AbiType[] = [{ kind: 'array', length: 4, type: { kind: 'field' } }];
|
|
288
|
+
const mockArtifact = { returnTypes } as any as FunctionArtifact;
|
|
289
|
+
|
|
290
|
+
currentReturn = decodeReturnValues(mockArtifact, paddedReturn);
|
|
260
291
|
}
|
|
261
292
|
}
|
|
262
293
|
// HACK(#1622): Manually patches the ordering of public state actions
|
|
263
294
|
// TODO(#757): Enforce proper ordering of public state actions
|
|
264
295
|
patchPublicStorageActionOrdering(kernelOutput, enqueuedExecutionResult!, this.phase);
|
|
296
|
+
|
|
297
|
+
returns.push(currentReturn);
|
|
265
298
|
}
|
|
266
299
|
|
|
267
300
|
// TODO(#3675): This should be done in a public kernel circuit
|
|
268
|
-
removeRedundantPublicDataWrites(kernelOutput);
|
|
301
|
+
removeRedundantPublicDataWrites(kernelOutput, this.phase);
|
|
269
302
|
|
|
270
|
-
return [kernelOutput, kernelProof, newUnencryptedFunctionLogs, undefined];
|
|
303
|
+
return [kernelOutput, kernelProof, newUnencryptedFunctionLogs, undefined, returns];
|
|
271
304
|
}
|
|
272
305
|
|
|
273
306
|
protected async runKernelCircuit(
|
|
274
307
|
previousOutput: PublicKernelCircuitPublicInputs,
|
|
275
308
|
previousProof: Proof,
|
|
276
|
-
callData
|
|
309
|
+
callData: PublicCallData,
|
|
277
310
|
): Promise<[PublicKernelCircuitPublicInputs, Proof]> {
|
|
278
311
|
const output = await this.getKernelCircuitOutput(previousOutput, previousProof, callData);
|
|
279
312
|
return [output, makeEmptyProof()];
|
|
280
313
|
}
|
|
281
314
|
|
|
282
|
-
protected
|
|
315
|
+
protected getKernelCircuitOutput(
|
|
283
316
|
previousOutput: PublicKernelCircuitPublicInputs,
|
|
284
317
|
previousProof: Proof,
|
|
285
|
-
callData
|
|
318
|
+
callData: PublicCallData,
|
|
286
319
|
): Promise<PublicKernelCircuitPublicInputs> {
|
|
287
320
|
const previousKernel = this.getPreviousKernelData(previousOutput, previousProof);
|
|
288
321
|
|
|
289
|
-
if (this.phase === PublicKernelPhase.TAIL) {
|
|
290
|
-
const { validationRequests, endNonRevertibleData, end } = previousOutput;
|
|
291
|
-
const nullifierReadRequestHints = await this.hintsBuilder.getNullifierReadRequestHints(
|
|
292
|
-
validationRequests.nullifierReadRequests,
|
|
293
|
-
endNonRevertibleData.newNullifiers,
|
|
294
|
-
end.newNullifiers,
|
|
295
|
-
);
|
|
296
|
-
const nullifierNonExistentReadRequestHints = await this.hintsBuilder.getNullifierNonExistentReadRequestHints(
|
|
297
|
-
validationRequests.nullifierNonExistentReadRequests,
|
|
298
|
-
endNonRevertibleData.newNullifiers,
|
|
299
|
-
end.newNullifiers,
|
|
300
|
-
);
|
|
301
|
-
const inputs = new PublicKernelTailCircuitPrivateInputs(
|
|
302
|
-
previousKernel,
|
|
303
|
-
nullifierReadRequestHints,
|
|
304
|
-
nullifierNonExistentReadRequestHints,
|
|
305
|
-
);
|
|
306
|
-
return this.publicKernel.publicKernelCircuitTail(inputs);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
if (!callData) {
|
|
310
|
-
throw new Error(`Cannot run public kernel circuit without call data for phase '${this.phase}'.`);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
322
|
const inputs = new PublicKernelCircuitPrivateInputs(previousKernel, callData);
|
|
314
323
|
switch (this.phase) {
|
|
315
324
|
case PublicKernelPhase.SETUP:
|
|
@@ -435,26 +444,30 @@ export abstract class AbstractPhaseManager {
|
|
|
435
444
|
}
|
|
436
445
|
}
|
|
437
446
|
|
|
438
|
-
function removeRedundantPublicDataWrites(publicInputs: PublicKernelCircuitPublicInputs) {
|
|
439
|
-
const
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
const
|
|
443
|
-
lastWritesMap.
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
+
function removeRedundantPublicDataWrites(publicInputs: PublicKernelCircuitPublicInputs, phase: PublicKernelPhase) {
|
|
448
|
+
const lastWritesMap = new Map<string, boolean>();
|
|
449
|
+
const patch = <N extends number>(requests: Tuple<PublicDataUpdateRequest, N>) =>
|
|
450
|
+
requests.filter(write => {
|
|
451
|
+
const leafSlot = write.leafSlot.toString();
|
|
452
|
+
const exists = lastWritesMap.get(leafSlot);
|
|
453
|
+
lastWritesMap.set(leafSlot, true);
|
|
454
|
+
return !exists;
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
const [prev, curr] = PhaseIsRevertible[phase]
|
|
458
|
+
? [publicInputs.endNonRevertibleData, publicInputs.end]
|
|
459
|
+
: [publicInputs.end, publicInputs.endNonRevertibleData];
|
|
447
460
|
|
|
448
|
-
|
|
449
|
-
patch(
|
|
461
|
+
curr.publicDataUpdateRequests = padArrayEnd(
|
|
462
|
+
patch(curr.publicDataUpdateRequests.reverse()).reverse(),
|
|
450
463
|
PublicDataUpdateRequest.empty(),
|
|
451
|
-
|
|
464
|
+
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
452
465
|
);
|
|
453
466
|
|
|
454
|
-
|
|
455
|
-
patch(
|
|
467
|
+
prev.publicDataUpdateRequests = padArrayEnd(
|
|
468
|
+
patch(prev.publicDataUpdateRequests.reverse()),
|
|
456
469
|
PublicDataUpdateRequest.empty(),
|
|
457
|
-
|
|
470
|
+
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
458
471
|
);
|
|
459
472
|
}
|
|
460
473
|
|
|
@@ -531,8 +544,6 @@ function patchPublicStorageActionOrdering(
|
|
|
531
544
|
...simPublicDataUpdateRequests,
|
|
532
545
|
],
|
|
533
546
|
PublicDataUpdateRequest.empty(),
|
|
534
|
-
|
|
535
|
-
? MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX
|
|
536
|
-
: MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
547
|
+
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
537
548
|
);
|
|
538
549
|
}
|
|
@@ -38,9 +38,9 @@ export class AppLogicPhaseManager extends AbstractPhaseManager {
|
|
|
38
38
|
// TODO(#4073): This is catching only private deployments, when we add public ones, we'll
|
|
39
39
|
// have to capture contracts emitted in that phase as well.
|
|
40
40
|
// TODO(@spalladino): Should we allow emitting contracts in the fee preparation phase?
|
|
41
|
-
this.log(`Processing tx ${tx.getTxHash()}`);
|
|
41
|
+
this.log.verbose(`Processing tx ${tx.getTxHash()}`);
|
|
42
42
|
await this.publicContractsDB.addNewContracts(tx);
|
|
43
|
-
const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs, revertReason] =
|
|
43
|
+
const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs, revertReason, returnValues] =
|
|
44
44
|
await this.processEnqueuedPublicCalls(tx, previousPublicKernelOutput, previousPublicKernelProof).catch(
|
|
45
45
|
// if we throw for any reason other than simulation, we need to rollback and drop the TX
|
|
46
46
|
async err => {
|
|
@@ -57,6 +57,6 @@ export class AppLogicPhaseManager extends AbstractPhaseManager {
|
|
|
57
57
|
await this.publicStateDB.checkpoint();
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
return { publicKernelOutput, publicKernelProof, revertReason };
|
|
60
|
+
return { publicKernelOutput, publicKernelProof, revertReason, returnValues };
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -2,18 +2,21 @@ import { MerkleTreeId } from '@aztec/circuit-types';
|
|
|
2
2
|
import {
|
|
3
3
|
type Fr,
|
|
4
4
|
MAX_NEW_NULLIFIERS_PER_TX,
|
|
5
|
-
type MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX,
|
|
6
5
|
type MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX,
|
|
7
6
|
type MAX_NULLIFIER_READ_REQUESTS_PER_TX,
|
|
8
|
-
|
|
7
|
+
MAX_PUBLIC_DATA_READS_PER_TX,
|
|
9
8
|
MembershipWitness,
|
|
10
9
|
NULLIFIER_TREE_HEIGHT,
|
|
10
|
+
PUBLIC_DATA_TREE_HEIGHT,
|
|
11
|
+
type PublicDataRead,
|
|
12
|
+
PublicDataTreeLeafPreimage,
|
|
11
13
|
type ReadRequestContext,
|
|
12
14
|
type SideEffectLinkedToNoteHash,
|
|
13
15
|
buildNullifierNonExistentReadRequestHints,
|
|
14
16
|
buildNullifierReadRequestHints,
|
|
15
|
-
|
|
17
|
+
mergeAccumulatedData,
|
|
16
18
|
} from '@aztec/circuits.js';
|
|
19
|
+
import { makeTuple } from '@aztec/foundation/array';
|
|
17
20
|
import { type Tuple } from '@aztec/foundation/serialize';
|
|
18
21
|
import { type MerkleTreeOperations } from '@aztec/world-state';
|
|
19
22
|
|
|
@@ -22,22 +25,22 @@ export class HintsBuilder {
|
|
|
22
25
|
|
|
23
26
|
getNullifierReadRequestHints(
|
|
24
27
|
nullifierReadRequests: Tuple<ReadRequestContext, typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX>,
|
|
25
|
-
nullifiersNonRevertible: Tuple<SideEffectLinkedToNoteHash, typeof
|
|
26
|
-
nullifiersRevertible: Tuple<SideEffectLinkedToNoteHash, typeof
|
|
28
|
+
nullifiersNonRevertible: Tuple<SideEffectLinkedToNoteHash, typeof MAX_NEW_NULLIFIERS_PER_TX>,
|
|
29
|
+
nullifiersRevertible: Tuple<SideEffectLinkedToNoteHash, typeof MAX_NEW_NULLIFIERS_PER_TX>,
|
|
27
30
|
) {
|
|
28
31
|
return buildNullifierReadRequestHints(
|
|
29
32
|
this,
|
|
30
33
|
nullifierReadRequests,
|
|
31
|
-
|
|
34
|
+
mergeAccumulatedData(MAX_NEW_NULLIFIERS_PER_TX, nullifiersNonRevertible, nullifiersRevertible),
|
|
32
35
|
);
|
|
33
36
|
}
|
|
34
37
|
|
|
35
38
|
getNullifierNonExistentReadRequestHints(
|
|
36
39
|
nullifierNonExistentReadRequests: Tuple<ReadRequestContext, typeof MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX>,
|
|
37
|
-
nullifiersNonRevertible: Tuple<SideEffectLinkedToNoteHash, typeof
|
|
38
|
-
nullifiersRevertible: Tuple<SideEffectLinkedToNoteHash, typeof
|
|
40
|
+
nullifiersNonRevertible: Tuple<SideEffectLinkedToNoteHash, typeof MAX_NEW_NULLIFIERS_PER_TX>,
|
|
41
|
+
nullifiersRevertible: Tuple<SideEffectLinkedToNoteHash, typeof MAX_NEW_NULLIFIERS_PER_TX>,
|
|
39
42
|
) {
|
|
40
|
-
const pendingNullifiers =
|
|
43
|
+
const pendingNullifiers = mergeAccumulatedData(
|
|
41
44
|
MAX_NEW_NULLIFIERS_PER_TX,
|
|
42
45
|
nullifiersNonRevertible,
|
|
43
46
|
nullifiersRevertible,
|
|
@@ -83,4 +86,34 @@ export class HintsBuilder {
|
|
|
83
86
|
|
|
84
87
|
return { membershipWitness, leafPreimage };
|
|
85
88
|
}
|
|
89
|
+
|
|
90
|
+
async getPublicDataReadsInfo(publicDataReads: PublicDataRead[]) {
|
|
91
|
+
const newPublicDataReadsWitnesses: Tuple<
|
|
92
|
+
MembershipWitness<typeof PUBLIC_DATA_TREE_HEIGHT>,
|
|
93
|
+
typeof MAX_PUBLIC_DATA_READS_PER_TX
|
|
94
|
+
> = makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => MembershipWitness.empty(PUBLIC_DATA_TREE_HEIGHT, 0n));
|
|
95
|
+
|
|
96
|
+
const newPublicDataReadsPreimages: Tuple<PublicDataTreeLeafPreimage, typeof MAX_PUBLIC_DATA_READS_PER_TX> =
|
|
97
|
+
makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => PublicDataTreeLeafPreimage.empty());
|
|
98
|
+
|
|
99
|
+
for (const i in publicDataReads) {
|
|
100
|
+
const leafSlot = publicDataReads[i].leafSlot.value;
|
|
101
|
+
const lowLeafResult = await this.db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot);
|
|
102
|
+
if (!lowLeafResult) {
|
|
103
|
+
throw new Error(`Public data tree should have one initial leaf`);
|
|
104
|
+
}
|
|
105
|
+
const preimage = await this.db.getLeafPreimage(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
|
|
106
|
+
const path = await this.db.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
|
|
107
|
+
newPublicDataReadsWitnesses[i] = new MembershipWitness(
|
|
108
|
+
PUBLIC_DATA_TREE_HEIGHT,
|
|
109
|
+
BigInt(lowLeafResult.index),
|
|
110
|
+
path.toTuple<typeof PUBLIC_DATA_TREE_HEIGHT>(),
|
|
111
|
+
);
|
|
112
|
+
newPublicDataReadsPreimages[i] = preimage! as PublicDataTreeLeafPreimage;
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
newPublicDataReadsWitnesses,
|
|
116
|
+
newPublicDataReadsPreimages,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
86
119
|
}
|
|
@@ -34,7 +34,8 @@ export class PhaseManagerFactory {
|
|
|
34
34
|
publicContractsDB: ContractsDataSourcePublicDB,
|
|
35
35
|
publicStateDB: PublicStateDB,
|
|
36
36
|
): AbstractPhaseManager | undefined {
|
|
37
|
-
|
|
37
|
+
const data = tx.data.forPublic!;
|
|
38
|
+
if (data.needsSetup) {
|
|
38
39
|
return new SetupPhaseManager(
|
|
39
40
|
db,
|
|
40
41
|
publicExecutor,
|
|
@@ -44,7 +45,7 @@ export class PhaseManagerFactory {
|
|
|
44
45
|
publicContractsDB,
|
|
45
46
|
publicStateDB,
|
|
46
47
|
);
|
|
47
|
-
} else if (
|
|
48
|
+
} else if (data.needsAppLogic) {
|
|
48
49
|
return new AppLogicPhaseManager(
|
|
49
50
|
db,
|
|
50
51
|
publicExecutor,
|
|
@@ -54,7 +55,7 @@ export class PhaseManagerFactory {
|
|
|
54
55
|
publicContractsDB,
|
|
55
56
|
publicStateDB,
|
|
56
57
|
);
|
|
57
|
-
} else if (
|
|
58
|
+
} else if (data.needsTeardown) {
|
|
58
59
|
return new TeardownPhaseManager(
|
|
59
60
|
db,
|
|
60
61
|
publicExecutor,
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
|
+
type BlockProver,
|
|
2
3
|
type FailedTx,
|
|
3
4
|
type ProcessedTx,
|
|
4
5
|
type SimulationError,
|
|
5
6
|
Tx,
|
|
6
|
-
getPreviousOutputAndProof,
|
|
7
7
|
makeEmptyProcessedTx,
|
|
8
8
|
makeProcessedTx,
|
|
9
9
|
toTxEffect,
|
|
10
10
|
validateProcessedTx,
|
|
11
11
|
} from '@aztec/circuit-types';
|
|
12
12
|
import { type TxSequencerProcessingStats } from '@aztec/circuit-types/stats';
|
|
13
|
-
import { type GlobalVariables, type Header } from '@aztec/circuits.js';
|
|
13
|
+
import { type GlobalVariables, type Header, type KernelCircuitPublicInputs } from '@aztec/circuits.js';
|
|
14
|
+
import { type ProcessReturnValues } from '@aztec/foundation/abi';
|
|
14
15
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
15
16
|
import { Timer } from '@aztec/foundation/timer';
|
|
16
17
|
import { PublicExecutor, type PublicStateDB, type SimulationProvider } from '@aztec/simulator';
|
|
@@ -20,8 +21,9 @@ import { type MerkleTreeOperations } from '@aztec/world-state';
|
|
|
20
21
|
import { type PublicKernelCircuitSimulator } from '../simulator/index.js';
|
|
21
22
|
import { ContractsDataSourcePublicDB, WorldStateDB, WorldStatePublicDB } from '../simulator/public_executor.js';
|
|
22
23
|
import { RealPublicKernelCircuitSimulator } from '../simulator/public_kernel.js';
|
|
23
|
-
import { type AbstractPhaseManager } from './abstract_phase_manager.js';
|
|
24
|
+
import { type AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js';
|
|
24
25
|
import { PhaseManagerFactory } from './phase_manager_factory.js';
|
|
26
|
+
import { type TxValidator } from './tx_validator.js';
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* Creates new instances of PublicProcessor given the provided merkle tree db and contract data source.
|
|
@@ -84,60 +86,45 @@ export class PublicProcessor {
|
|
|
84
86
|
* @param txs - Txs to process.
|
|
85
87
|
* @returns The list of processed txs with their circuit simulation outputs.
|
|
86
88
|
*/
|
|
87
|
-
public async process(
|
|
89
|
+
public async process(
|
|
90
|
+
txs: Tx[],
|
|
91
|
+
maxTransactions = txs.length,
|
|
92
|
+
blockProver?: BlockProver,
|
|
93
|
+
txValidator?: TxValidator,
|
|
94
|
+
): Promise<[ProcessedTx[], FailedTx[], ProcessReturnValues[]]> {
|
|
88
95
|
// The processor modifies the tx objects in place, so we need to clone them.
|
|
89
96
|
txs = txs.map(tx => Tx.clone(tx));
|
|
90
97
|
const result: ProcessedTx[] = [];
|
|
91
98
|
const failed: FailedTx[] = [];
|
|
99
|
+
const returns: ProcessReturnValues[] = [];
|
|
92
100
|
|
|
93
101
|
for (const tx of txs) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
this.publicKernel,
|
|
99
|
-
this.globalVariables,
|
|
100
|
-
this.historicalHeader,
|
|
101
|
-
this.publicContractsDB,
|
|
102
|
-
this.publicStateDB,
|
|
103
|
-
);
|
|
104
|
-
this.log(`Beginning processing in phase ${phase?.phase} for tx ${tx.getTxHash()}`);
|
|
105
|
-
let { publicKernelPublicInput, previousProof: proof } = getPreviousOutputAndProof(tx, undefined, undefined);
|
|
106
|
-
let revertReason: SimulationError | undefined;
|
|
107
|
-
const timer = new Timer();
|
|
102
|
+
// only process up to the limit of the block
|
|
103
|
+
if (result.length >= maxTransactions) {
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
108
106
|
try {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
this.publicStateDB,
|
|
124
|
-
);
|
|
107
|
+
const [processedTx, returnValues] = !tx.hasPublicCalls()
|
|
108
|
+
? [makeProcessedTx(tx, tx.data.toKernelCircuitPublicInputs(), tx.proof)]
|
|
109
|
+
: await this.processTxWithPublicCalls(tx);
|
|
110
|
+
validateProcessedTx(processedTx);
|
|
111
|
+
// Re-validate the transaction
|
|
112
|
+
if (txValidator) {
|
|
113
|
+
// Only accept processed transactions that are not double-spends,
|
|
114
|
+
// public functions emitting nullifiers would pass earlier check but fail here.
|
|
115
|
+
// Note that we're checking all nullifiers generated in the private execution twice,
|
|
116
|
+
// we could store the ones already checked and skip them here as an optimization.
|
|
117
|
+
const [_, invalid] = await txValidator.validateTxs([processedTx]);
|
|
118
|
+
if (invalid.length) {
|
|
119
|
+
throw new Error(`Transaction ${invalid[0].hash} invalid after processing public functions`);
|
|
120
|
+
}
|
|
125
121
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
result.push(
|
|
131
|
-
|
|
132
|
-
this.log(`Processed public part of ${tx.data.endNonRevertibleData.newNullifiers[0].value}`, {
|
|
133
|
-
eventName: 'tx-sequencer-processing',
|
|
134
|
-
duration: timer.ms(),
|
|
135
|
-
effectsSize: toTxEffect(processedTransaction).toBuffer().length,
|
|
136
|
-
publicDataUpdateRequests:
|
|
137
|
-
processedTransaction.data.combinedData.publicDataUpdateRequests.filter(x => !x.leafSlot.isZero()).length ??
|
|
138
|
-
0,
|
|
139
|
-
...tx.getStats(),
|
|
140
|
-
} satisfies TxSequencerProcessingStats);
|
|
122
|
+
// if we were given a prover then send the transaction to it for proving
|
|
123
|
+
if (blockProver) {
|
|
124
|
+
await blockProver.addNewTx(processedTx);
|
|
125
|
+
}
|
|
126
|
+
result.push(processedTx);
|
|
127
|
+
returns.push(returnValues);
|
|
141
128
|
} catch (err: any) {
|
|
142
129
|
const errorMessage = err instanceof Error ? err.message : 'Unknown error';
|
|
143
130
|
this.log.warn(`Failed to process tx ${tx.getTxHash()}: ${errorMessage}`);
|
|
@@ -146,10 +133,11 @@ export class PublicProcessor {
|
|
|
146
133
|
tx,
|
|
147
134
|
error: err instanceof Error ? err : new Error(errorMessage),
|
|
148
135
|
});
|
|
136
|
+
returns.push([]);
|
|
149
137
|
}
|
|
150
138
|
}
|
|
151
139
|
|
|
152
|
-
return [result, failed];
|
|
140
|
+
return [result, failed, returns];
|
|
153
141
|
}
|
|
154
142
|
|
|
155
143
|
/**
|
|
@@ -158,6 +146,64 @@ export class PublicProcessor {
|
|
|
158
146
|
*/
|
|
159
147
|
public makeEmptyProcessedTx(): ProcessedTx {
|
|
160
148
|
const { chainId, version } = this.globalVariables;
|
|
161
|
-
return makeEmptyProcessedTx(this.historicalHeader, chainId, version);
|
|
149
|
+
return makeEmptyProcessedTx(this.historicalHeader.clone(), chainId, version);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private async processTxWithPublicCalls(tx: Tx): Promise<[ProcessedTx, ProcessReturnValues | undefined]> {
|
|
153
|
+
let returnValues: ProcessReturnValues = undefined;
|
|
154
|
+
let phase: AbstractPhaseManager | undefined = PhaseManagerFactory.phaseFromTx(
|
|
155
|
+
tx,
|
|
156
|
+
this.db,
|
|
157
|
+
this.publicExecutor,
|
|
158
|
+
this.publicKernel,
|
|
159
|
+
this.globalVariables,
|
|
160
|
+
this.historicalHeader,
|
|
161
|
+
this.publicContractsDB,
|
|
162
|
+
this.publicStateDB,
|
|
163
|
+
);
|
|
164
|
+
this.log.debug(`Beginning processing in phase ${phase?.phase} for tx ${tx.getTxHash()}`);
|
|
165
|
+
let proof = tx.proof;
|
|
166
|
+
let publicKernelPublicInput = tx.data.toPublicKernelCircuitPublicInputs();
|
|
167
|
+
let finalKernelOutput: KernelCircuitPublicInputs | undefined;
|
|
168
|
+
let revertReason: SimulationError | undefined;
|
|
169
|
+
const timer = new Timer();
|
|
170
|
+
while (phase) {
|
|
171
|
+
const output = await phase.handle(tx, publicKernelPublicInput, proof);
|
|
172
|
+
if (phase.phase === PublicKernelPhase.APP_LOGIC) {
|
|
173
|
+
returnValues = output.returnValues;
|
|
174
|
+
}
|
|
175
|
+
publicKernelPublicInput = output.publicKernelOutput;
|
|
176
|
+
finalKernelOutput = output.finalKernelOutput;
|
|
177
|
+
proof = output.publicKernelProof;
|
|
178
|
+
revertReason ??= output.revertReason;
|
|
179
|
+
phase = PhaseManagerFactory.phaseFromOutput(
|
|
180
|
+
publicKernelPublicInput,
|
|
181
|
+
phase,
|
|
182
|
+
this.db,
|
|
183
|
+
this.publicExecutor,
|
|
184
|
+
this.publicKernel,
|
|
185
|
+
this.globalVariables,
|
|
186
|
+
this.historicalHeader,
|
|
187
|
+
this.publicContractsDB,
|
|
188
|
+
this.publicStateDB,
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (!finalKernelOutput) {
|
|
193
|
+
throw new Error('Final public kernel was not executed.');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const processedTx = makeProcessedTx(tx, finalKernelOutput, proof, revertReason);
|
|
197
|
+
|
|
198
|
+
this.log.debug(`Processed public part of ${tx.getTxHash()}`, {
|
|
199
|
+
eventName: 'tx-sequencer-processing',
|
|
200
|
+
duration: timer.ms(),
|
|
201
|
+
effectsSize: toTxEffect(processedTx).toBuffer().length,
|
|
202
|
+
publicDataUpdateRequests:
|
|
203
|
+
processedTx.data.end.publicDataUpdateRequests.filter(x => !x.leafSlot.isZero()).length ?? 0,
|
|
204
|
+
...tx.getStats(),
|
|
205
|
+
} satisfies TxSequencerProcessingStats);
|
|
206
|
+
|
|
207
|
+
return [processedTx, returnValues];
|
|
162
208
|
}
|
|
163
209
|
}
|