@aztec/sequencer-client 0.23.0 → 0.26.1

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.
Files changed (88) hide show
  1. package/dest/block_builder/solo_block_builder.d.ts +9 -9
  2. package/dest/block_builder/solo_block_builder.d.ts.map +1 -1
  3. package/dest/block_builder/solo_block_builder.js +26 -48
  4. package/dest/global_variable_builder/viem-reader.js +2 -2
  5. package/dest/prover/empty.d.ts +2 -2
  6. package/dest/prover/empty.d.ts.map +1 -1
  7. package/dest/prover/empty.js +1 -1
  8. package/dest/prover/index.d.ts +2 -2
  9. package/dest/prover/index.d.ts.map +1 -1
  10. package/dest/publisher/l1-publisher.d.ts +0 -2
  11. package/dest/publisher/l1-publisher.d.ts.map +1 -1
  12. package/dest/publisher/l1-publisher.js +2 -3
  13. package/dest/publisher/viem-tx-sender.d.ts.map +1 -1
  14. package/dest/publisher/viem-tx-sender.js +6 -10
  15. package/dest/sequencer/abstract_phase_manager.d.ts +23 -30
  16. package/dest/sequencer/abstract_phase_manager.d.ts.map +1 -1
  17. package/dest/sequencer/abstract_phase_manager.js +151 -98
  18. package/dest/sequencer/{fee_distribution_phase_manager.d.ts → app_logic_phase_manager.d.ts} +9 -11
  19. package/dest/sequencer/app_logic_phase_manager.d.ts.map +1 -0
  20. package/dest/sequencer/app_logic_phase_manager.js +44 -0
  21. package/dest/sequencer/phase_manager_factory.d.ts +19 -0
  22. package/dest/sequencer/phase_manager_factory.d.ts.map +1 -0
  23. package/dest/sequencer/phase_manager_factory.js +51 -0
  24. package/dest/sequencer/processed_tx.d.ts +4 -4
  25. package/dest/sequencer/processed_tx.d.ts.map +1 -1
  26. package/dest/sequencer/processed_tx.js +8 -8
  27. package/dest/sequencer/public_processor.d.ts +1 -1
  28. package/dest/sequencer/public_processor.d.ts.map +1 -1
  29. package/dest/sequencer/public_processor.js +13 -11
  30. package/dest/sequencer/sequencer.d.ts +3 -3
  31. package/dest/sequencer/sequencer.d.ts.map +1 -1
  32. package/dest/sequencer/sequencer.js +23 -16
  33. package/dest/sequencer/{fee_preparation_phase_manager.d.ts → setup_phase_manager.d.ts} +9 -11
  34. package/dest/sequencer/setup_phase_manager.d.ts.map +1 -0
  35. package/dest/sequencer/setup_phase_manager.js +37 -0
  36. package/dest/sequencer/{application_logic_phase_manager.d.ts → teardown_phase_manager.d.ts} +9 -12
  37. package/dest/sequencer/teardown_phase_manager.d.ts.map +1 -0
  38. package/dest/sequencer/teardown_phase_manager.js +36 -0
  39. package/dest/simulator/index.d.ts +11 -5
  40. package/dest/simulator/index.d.ts.map +1 -1
  41. package/dest/simulator/public_executor.d.ts +8 -3
  42. package/dest/simulator/public_executor.d.ts.map +1 -1
  43. package/dest/simulator/public_executor.js +64 -11
  44. package/dest/simulator/public_kernel.d.ts +11 -5
  45. package/dest/simulator/public_kernel.d.ts.map +1 -1
  46. package/dest/simulator/public_kernel.js +35 -16
  47. package/dest/simulator/rollup.js +2 -2
  48. package/package.json +14 -24
  49. package/src/block_builder/index.ts +24 -0
  50. package/src/block_builder/solo_block_builder.ts +726 -0
  51. package/src/block_builder/types.ts +8 -0
  52. package/src/client/index.ts +1 -0
  53. package/src/client/sequencer-client.ts +97 -0
  54. package/src/config.ts +86 -0
  55. package/src/global_variable_builder/config.ts +20 -0
  56. package/src/global_variable_builder/global_builder.ts +95 -0
  57. package/src/global_variable_builder/index.ts +16 -0
  58. package/src/global_variable_builder/viem-reader.ts +61 -0
  59. package/src/index.ts +15 -0
  60. package/src/mocks/verification_keys.ts +36 -0
  61. package/src/prover/empty.ts +74 -0
  62. package/src/prover/index.ts +53 -0
  63. package/src/publisher/config.ts +41 -0
  64. package/src/publisher/index.ts +14 -0
  65. package/src/publisher/l1-publisher.ts +362 -0
  66. package/src/publisher/viem-tx-sender.ts +235 -0
  67. package/src/receiver.ts +13 -0
  68. package/src/sequencer/abstract_phase_manager.ts +489 -0
  69. package/src/sequencer/app_logic_phase_manager.ts +75 -0
  70. package/src/sequencer/config.ts +1 -0
  71. package/src/sequencer/index.ts +2 -0
  72. package/src/sequencer/phase_manager_factory.ts +122 -0
  73. package/src/sequencer/processed_tx.ts +94 -0
  74. package/src/sequencer/public_processor.ts +153 -0
  75. package/src/sequencer/sequencer.ts +469 -0
  76. package/src/sequencer/setup_phase_manager.ts +68 -0
  77. package/src/sequencer/teardown_phase_manager.ts +67 -0
  78. package/src/simulator/index.ts +57 -0
  79. package/src/simulator/public_executor.ts +267 -0
  80. package/src/simulator/public_kernel.ts +84 -0
  81. package/src/simulator/rollup.ts +76 -0
  82. package/src/utils.ts +16 -0
  83. package/dest/sequencer/application_logic_phase_manager.d.ts.map +0 -1
  84. package/dest/sequencer/application_logic_phase_manager.js +0 -64
  85. package/dest/sequencer/fee_distribution_phase_manager.d.ts.map +0 -1
  86. package/dest/sequencer/fee_distribution_phase_manager.js +0 -42
  87. package/dest/sequencer/fee_preparation_phase_manager.d.ts.map +0 -1
  88. package/dest/sequencer/fee_preparation_phase_manager.js +0 -43
@@ -0,0 +1,489 @@
1
+ import { FunctionL2Logs, MerkleTreeId, Tx } from '@aztec/circuit-types';
2
+ import {
3
+ AztecAddress,
4
+ CallRequest,
5
+ ContractStorageRead,
6
+ ContractStorageUpdateRequest,
7
+ Fr,
8
+ GlobalVariables,
9
+ Header,
10
+ L2ToL1Message,
11
+ MAX_NEW_L2_TO_L1_MSGS_PER_CALL,
12
+ MAX_NEW_NOTE_HASHES_PER_CALL,
13
+ MAX_NEW_NULLIFIERS_PER_CALL,
14
+ MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX,
15
+ MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
16
+ MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL,
17
+ MAX_PUBLIC_DATA_READS_PER_CALL,
18
+ MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL,
19
+ MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX,
20
+ MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
21
+ MembershipWitness,
22
+ PrivateKernelTailCircuitPublicInputs,
23
+ Proof,
24
+ PublicAccumulatedNonRevertibleData,
25
+ PublicAccumulatedRevertibleData,
26
+ PublicCallData,
27
+ PublicCallRequest,
28
+ PublicCallStackItem,
29
+ PublicCircuitPublicInputs,
30
+ PublicDataRead,
31
+ PublicDataUpdateRequest,
32
+ PublicKernelCircuitPrivateInputs,
33
+ PublicKernelCircuitPublicInputs,
34
+ PublicKernelData,
35
+ RETURN_VALUES_LENGTH,
36
+ SideEffect,
37
+ SideEffectLinkedToNoteHash,
38
+ VK_TREE_HEIGHT,
39
+ } from '@aztec/circuits.js';
40
+ import { computeVarArgsHash } from '@aztec/circuits.js/hash';
41
+ import { arrayNonEmptyLength, padArrayEnd } from '@aztec/foundation/collection';
42
+ import { DebugLogger, createDebugLogger } from '@aztec/foundation/log';
43
+ import { Tuple, to2Fields } from '@aztec/foundation/serialize';
44
+ import {
45
+ PublicExecution,
46
+ PublicExecutionResult,
47
+ PublicExecutor,
48
+ collectPublicDataReads,
49
+ collectPublicDataUpdateRequests,
50
+ isPublicExecutionResult,
51
+ } from '@aztec/simulator';
52
+ import { MerkleTreeOperations } from '@aztec/world-state';
53
+
54
+ import { env } from 'process';
55
+
56
+ import { getVerificationKeys } from '../mocks/verification_keys.js';
57
+ import { PublicProver } from '../prover/index.js';
58
+ import { PublicKernelCircuitSimulator } from '../simulator/index.js';
59
+ import { FailedTx } from './processed_tx.js';
60
+
61
+ export enum PublicKernelPhase {
62
+ SETUP = 'setup',
63
+ APP_LOGIC = 'app-logic',
64
+ TEARDOWN = 'teardown',
65
+ }
66
+
67
+ export const PhaseIsRevertible: Record<PublicKernelPhase, boolean> = {
68
+ [PublicKernelPhase.SETUP]: false,
69
+ [PublicKernelPhase.APP_LOGIC]: true,
70
+ [PublicKernelPhase.TEARDOWN]: false,
71
+ };
72
+
73
+ export abstract class AbstractPhaseManager {
74
+ protected log: DebugLogger;
75
+ constructor(
76
+ protected db: MerkleTreeOperations,
77
+ protected publicExecutor: PublicExecutor,
78
+ protected publicKernel: PublicKernelCircuitSimulator,
79
+ protected publicProver: PublicProver,
80
+ protected globalVariables: GlobalVariables,
81
+ protected historicalHeader: Header,
82
+ public phase: PublicKernelPhase,
83
+ ) {
84
+ this.log = createDebugLogger(`aztec:sequencer:${phase}`);
85
+ }
86
+ /**
87
+ *
88
+ * @param tx - the tx to be processed
89
+ * @param publicKernelPublicInputs - the output of the public kernel circuit for the previous phase
90
+ * @param previousPublicKernelProof - the proof of the public kernel circuit for the previous phase
91
+ */
92
+ abstract handle(
93
+ tx: Tx,
94
+ publicKernelPublicInputs: PublicKernelCircuitPublicInputs,
95
+ previousPublicKernelProof: Proof,
96
+ ): Promise<{
97
+ /**
98
+ * the output of the public kernel circuit for this phase
99
+ */
100
+ publicKernelOutput: PublicKernelCircuitPublicInputs;
101
+ /**
102
+ * the proof of the public kernel circuit for this phase
103
+ */
104
+ publicKernelProof: Proof;
105
+ }>;
106
+ abstract rollback(tx: Tx, err: unknown): Promise<FailedTx>;
107
+
108
+ public static extractEnqueuedPublicCallsByPhase(
109
+ publicInputs: PrivateKernelTailCircuitPublicInputs,
110
+ enqueuedPublicFunctionCalls: PublicCallRequest[],
111
+ ): Record<PublicKernelPhase, PublicCallRequest[]> {
112
+ const publicCallsStack = enqueuedPublicFunctionCalls.slice().reverse();
113
+ const nonRevertibleCallStack = publicInputs.endNonRevertibleData.publicCallStack.filter(i => !i.isEmpty());
114
+ const revertibleCallStack = publicInputs.end.publicCallStack.filter(i => !i.isEmpty());
115
+
116
+ const callRequestsStack = publicCallsStack
117
+ .map(call => call.toCallRequest())
118
+ .filter(
119
+ // filter out enqueued calls that are not in the public call stack
120
+ // TODO mitch left a question about whether this is only needed when unit testing
121
+ // with mock data
122
+ call => revertibleCallStack.find(p => p.equals(call)) || nonRevertibleCallStack.find(p => p.equals(call)),
123
+ );
124
+
125
+ if (callRequestsStack.length === 0) {
126
+ return {
127
+ [PublicKernelPhase.SETUP]: [],
128
+ [PublicKernelPhase.APP_LOGIC]: [],
129
+ [PublicKernelPhase.TEARDOWN]: [],
130
+ };
131
+ }
132
+
133
+ // find the first call that is revertible
134
+ const firstRevertibleCallIndex = callRequestsStack.findIndex(
135
+ c => revertibleCallStack.findIndex(p => p.equals(c)) !== -1,
136
+ );
137
+
138
+ if (firstRevertibleCallIndex === 0) {
139
+ return {
140
+ [PublicKernelPhase.SETUP]: [],
141
+ [PublicKernelPhase.APP_LOGIC]: publicCallsStack,
142
+ [PublicKernelPhase.TEARDOWN]: [],
143
+ };
144
+ } else {
145
+ return {
146
+ [PublicKernelPhase.SETUP]: publicCallsStack.slice(0, firstRevertibleCallIndex - 1),
147
+ [PublicKernelPhase.APP_LOGIC]: publicCallsStack.slice(firstRevertibleCallIndex),
148
+ [PublicKernelPhase.TEARDOWN]: [publicCallsStack[firstRevertibleCallIndex - 1]],
149
+ };
150
+ }
151
+ }
152
+
153
+ protected extractEnqueuedPublicCalls(tx: Tx): PublicCallRequest[] {
154
+ const calls = AbstractPhaseManager.extractEnqueuedPublicCallsByPhase(tx.data, tx.enqueuedPublicFunctionCalls)[
155
+ this.phase
156
+ ];
157
+
158
+ return calls;
159
+ }
160
+
161
+ public static getKernelOutputAndProof(
162
+ tx: Tx,
163
+ publicKernelPublicInput?: PublicKernelCircuitPublicInputs,
164
+ previousPublicKernelProof?: Proof,
165
+ ): {
166
+ /**
167
+ * the output of the public kernel circuit for this phase
168
+ */
169
+ publicKernelPublicInput: PublicKernelCircuitPublicInputs;
170
+ /**
171
+ * the proof of the public kernel circuit for this phase
172
+ */
173
+ publicKernelProof: Proof;
174
+ } {
175
+ if (publicKernelPublicInput && previousPublicKernelProof) {
176
+ return {
177
+ publicKernelPublicInput: publicKernelPublicInput,
178
+ publicKernelProof: previousPublicKernelProof,
179
+ };
180
+ } else {
181
+ const publicKernelPublicInput = new PublicKernelCircuitPublicInputs(
182
+ tx.data.aggregationObject,
183
+ PublicAccumulatedNonRevertibleData.fromPrivateAccumulatedNonRevertibleData(tx.data.endNonRevertibleData),
184
+ PublicAccumulatedRevertibleData.fromPrivateAccumulatedRevertibleData(tx.data.end),
185
+ tx.data.constants,
186
+ tx.data.needsSetup,
187
+ tx.data.needsAppLogic,
188
+ tx.data.needsTeardown,
189
+ );
190
+ const publicKernelProof = previousPublicKernelProof || tx.proof;
191
+ return {
192
+ publicKernelPublicInput,
193
+ publicKernelProof,
194
+ };
195
+ }
196
+ }
197
+
198
+ protected async processEnqueuedPublicCalls(
199
+ tx: Tx,
200
+ previousPublicKernelOutput: PublicKernelCircuitPublicInputs,
201
+ previousPublicKernelProof: Proof,
202
+ ): Promise<[PublicKernelCircuitPublicInputs, Proof, FunctionL2Logs[]]> {
203
+ let kernelOutput = previousPublicKernelOutput;
204
+ let kernelProof = previousPublicKernelProof;
205
+
206
+ const enqueuedCalls = this.extractEnqueuedPublicCalls(tx);
207
+
208
+ if (!enqueuedCalls || !enqueuedCalls.length) {
209
+ return [kernelOutput, kernelProof, []];
210
+ }
211
+
212
+ const newUnencryptedFunctionLogs: FunctionL2Logs[] = [];
213
+
214
+ // TODO(#1684): Should multiple separately enqueued public calls be treated as
215
+ // separate public callstacks to be proven by separate public kernel sequences
216
+ // and submitted separately to the base rollup?
217
+
218
+ for (const enqueuedCall of enqueuedCalls) {
219
+ const executionStack: (PublicExecution | PublicExecutionResult)[] = [enqueuedCall];
220
+
221
+ // Keep track of which result is for the top/enqueued call
222
+ let enqueuedExecutionResult: PublicExecutionResult | undefined;
223
+
224
+ while (executionStack.length) {
225
+ const current = executionStack.pop()!;
226
+ const isExecutionRequest = !isPublicExecutionResult(current);
227
+
228
+ // NOTE: temporary glue to incorporate avm execution calls
229
+ const simulator = (execution: PublicExecution, globalVariables: GlobalVariables) =>
230
+ env.AVM_ENABLED
231
+ ? this.publicExecutor.simulateAvm(execution, globalVariables)
232
+ : this.publicExecutor.simulate(execution, globalVariables);
233
+
234
+ const result = isExecutionRequest ? await simulator(current, this.globalVariables) : current;
235
+
236
+ newUnencryptedFunctionLogs.push(result.unencryptedLogs);
237
+ const functionSelector = result.execution.functionData.selector.toString();
238
+ this.log.debug(
239
+ `Running public kernel circuit for ${result.execution.contractAddress.toString()}:${functionSelector}`,
240
+ );
241
+ executionStack.push(...result.nestedExecutions);
242
+ const callData = await this.getPublicCallData(result, isExecutionRequest);
243
+
244
+ [kernelOutput, kernelProof] = await this.runKernelCircuit(callData, kernelOutput, kernelProof);
245
+
246
+ if (!enqueuedExecutionResult) {
247
+ enqueuedExecutionResult = result;
248
+ }
249
+ }
250
+ // HACK(#1622): Manually patches the ordering of public state actions
251
+ // TODO(#757): Enforce proper ordering of public state actions
252
+ patchPublicStorageActionOrdering(kernelOutput, enqueuedExecutionResult!, this.phase);
253
+ }
254
+
255
+ // TODO(#3675): This should be done in a public kernel circuit
256
+ removeRedundantPublicDataWrites(kernelOutput);
257
+
258
+ return [kernelOutput, kernelProof, newUnencryptedFunctionLogs];
259
+ }
260
+
261
+ protected async runKernelCircuit(
262
+ callData: PublicCallData,
263
+ previousOutput: PublicKernelCircuitPublicInputs,
264
+ previousProof: Proof,
265
+ ): Promise<[PublicKernelCircuitPublicInputs, Proof]> {
266
+ const output = await this.getKernelCircuitOutput(callData, previousOutput, previousProof);
267
+ const proof = await this.publicProver.getPublicKernelCircuitProof(output);
268
+ return [output, proof];
269
+ }
270
+
271
+ protected getKernelCircuitOutput(
272
+ callData: PublicCallData,
273
+ previousOutput: PublicKernelCircuitPublicInputs,
274
+ previousProof: Proof,
275
+ ): Promise<PublicKernelCircuitPublicInputs> {
276
+ const previousKernel = this.getPreviousKernelData(previousOutput, previousProof);
277
+ const inputs = new PublicKernelCircuitPrivateInputs(previousKernel, callData);
278
+ switch (this.phase) {
279
+ case PublicKernelPhase.SETUP:
280
+ return this.publicKernel.publicKernelCircuitSetup(inputs);
281
+ case PublicKernelPhase.APP_LOGIC:
282
+ return this.publicKernel.publicKernelCircuitAppLogic(inputs);
283
+ case PublicKernelPhase.TEARDOWN:
284
+ return this.publicKernel.publicKernelCircuitTeardown(inputs);
285
+ default:
286
+ throw new Error(`No public kernel circuit for inputs`);
287
+ }
288
+ }
289
+
290
+ protected getPreviousKernelData(
291
+ previousOutput: PublicKernelCircuitPublicInputs,
292
+ previousProof: Proof,
293
+ ): PublicKernelData {
294
+ const vk = getVerificationKeys().publicKernelCircuit;
295
+ const vkIndex = 0;
296
+ const vkSiblingPath = MembershipWitness.random(VK_TREE_HEIGHT).siblingPath;
297
+ return new PublicKernelData(previousOutput, previousProof, vk, vkIndex, vkSiblingPath);
298
+ }
299
+
300
+ protected async getPublicCircuitPublicInputs(result: PublicExecutionResult) {
301
+ const publicDataTreeInfo = await this.db.getTreeInfo(MerkleTreeId.PUBLIC_DATA_TREE);
302
+ this.historicalHeader.state.partial.publicDataTree.root = Fr.fromBuffer(publicDataTreeInfo.root);
303
+
304
+ const callStackPreimages = await this.getPublicCallStackPreimages(result);
305
+ const publicCallStackHashes = padArrayEnd(
306
+ callStackPreimages.map(c => c.hash()),
307
+ Fr.ZERO,
308
+ MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL,
309
+ );
310
+
311
+ // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) --> set this in Noir
312
+ const unencryptedLogsHash = to2Fields(result.unencryptedLogs.hash());
313
+ const unencryptedLogPreimagesLength = new Fr(result.unencryptedLogs.getSerializedLength());
314
+
315
+ return PublicCircuitPublicInputs.from({
316
+ callContext: result.execution.callContext,
317
+ proverAddress: AztecAddress.ZERO,
318
+ argsHash: computeVarArgsHash(result.execution.args),
319
+ newNoteHashes: padArrayEnd(result.newNoteHashes, SideEffect.empty(), MAX_NEW_NOTE_HASHES_PER_CALL),
320
+ newNullifiers: padArrayEnd(result.newNullifiers, SideEffectLinkedToNoteHash.empty(), MAX_NEW_NULLIFIERS_PER_CALL),
321
+ newL2ToL1Msgs: padArrayEnd(result.newL2ToL1Messages, L2ToL1Message.empty(), MAX_NEW_L2_TO_L1_MSGS_PER_CALL),
322
+ returnValues: padArrayEnd(result.returnValues, Fr.ZERO, RETURN_VALUES_LENGTH),
323
+ contractStorageReads: padArrayEnd(
324
+ result.contractStorageReads,
325
+ ContractStorageRead.empty(),
326
+ MAX_PUBLIC_DATA_READS_PER_CALL,
327
+ ),
328
+ contractStorageUpdateRequests: padArrayEnd(
329
+ result.contractStorageUpdateRequests,
330
+ ContractStorageUpdateRequest.empty(),
331
+ MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL,
332
+ ),
333
+ publicCallStackHashes,
334
+ unencryptedLogsHash,
335
+ unencryptedLogPreimagesLength,
336
+ historicalHeader: this.historicalHeader,
337
+ });
338
+ }
339
+
340
+ protected async getPublicCallStackItem(result: PublicExecutionResult, isExecutionRequest = false) {
341
+ return new PublicCallStackItem(
342
+ result.execution.contractAddress,
343
+ result.execution.functionData,
344
+ await this.getPublicCircuitPublicInputs(result),
345
+ isExecutionRequest,
346
+ );
347
+ }
348
+
349
+ protected async getPublicCallStackPreimages(result: PublicExecutionResult): Promise<PublicCallStackItem[]> {
350
+ const nested = result.nestedExecutions;
351
+ if (nested.length > MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL) {
352
+ throw new Error(
353
+ `Public call stack size exceeded (max ${MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL}, got ${nested.length})`,
354
+ );
355
+ }
356
+
357
+ return await Promise.all(nested.map(n => this.getPublicCallStackItem(n)));
358
+ }
359
+
360
+ protected getBytecodeHash(_result: PublicExecutionResult) {
361
+ // TODO: Determine how to calculate bytecode hash. Circuits just check it isn't zero for now.
362
+ // See https://github.com/AztecProtocol/aztec3-packages/issues/378
363
+ const bytecodeHash = new Fr(1n);
364
+ return Promise.resolve(bytecodeHash);
365
+ }
366
+
367
+ /**
368
+ * Calculates the PublicCircuitOutput for this execution result along with its proof,
369
+ * and assembles a PublicCallData object from it.
370
+ * @param result - The execution result.
371
+ * @param preimages - The preimages of the callstack items.
372
+ * @param isExecutionRequest - Whether the current callstack item should be considered a public fn execution request.
373
+ * @returns A corresponding PublicCallData object.
374
+ */
375
+ protected async getPublicCallData(result: PublicExecutionResult, isExecutionRequest = false) {
376
+ const bytecodeHash = await this.getBytecodeHash(result);
377
+ const callStackItem = await this.getPublicCallStackItem(result, isExecutionRequest);
378
+ const publicCallRequests = (await this.getPublicCallStackPreimages(result)).map(c =>
379
+ c.toCallRequest(callStackItem.publicInputs.callContext),
380
+ );
381
+ const publicCallStack = padArrayEnd(publicCallRequests, CallRequest.empty(), MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL);
382
+ const portalContractAddress = result.execution.callContext.portalContractAddress.toField();
383
+ const proof = await this.publicProver.getPublicCircuitProof(callStackItem.publicInputs);
384
+ return new PublicCallData(callStackItem, publicCallStack, proof, portalContractAddress, bytecodeHash);
385
+ }
386
+ }
387
+
388
+ function removeRedundantPublicDataWrites(publicInputs: PublicKernelCircuitPublicInputs) {
389
+ const patch = <N extends number>(requests: Tuple<PublicDataUpdateRequest, N>) => {
390
+ const lastWritesMap = new Map<string, PublicDataUpdateRequest>();
391
+ for (const write of requests) {
392
+ const key = write.leafSlot.toString();
393
+ lastWritesMap.set(key, write);
394
+ }
395
+ return requests.filter(write => lastWritesMap.get(write.leafSlot.toString())?.equals(write));
396
+ };
397
+
398
+ publicInputs.end.publicDataUpdateRequests = padArrayEnd(
399
+ patch(publicInputs.end.publicDataUpdateRequests),
400
+ PublicDataUpdateRequest.empty(),
401
+ MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
402
+ );
403
+
404
+ publicInputs.endNonRevertibleData.publicDataUpdateRequests = padArrayEnd(
405
+ patch(publicInputs.endNonRevertibleData.publicDataUpdateRequests),
406
+ PublicDataUpdateRequest.empty(),
407
+ MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
408
+ );
409
+ }
410
+
411
+ // HACK(#1622): this is a hack to fix ordering of public state in the call stack. Since the private kernel
412
+ // cannot keep track of side effects that happen after or before a nested call, we override the public
413
+ // state actions it emits with whatever we got from the simulator. As a sanity check, we at least verify
414
+ // that the elements are the same, so we are only tweaking their ordering.
415
+ // See yarn-project/end-to-end/src/e2e_ordering.test.ts
416
+ // See https://github.com/AztecProtocol/aztec-packages/issues/1616
417
+ // TODO(#757): Enforce proper ordering of public state actions
418
+ /**
419
+ * Patch the ordering of storage actions output from the public kernel.
420
+ * @param publicInputs - to be patched here: public inputs to the kernel iteration up to this point
421
+ * @param execResult - result of the top/first execution for this enqueued public call
422
+ */
423
+ function patchPublicStorageActionOrdering(
424
+ publicInputs: PublicKernelCircuitPublicInputs,
425
+ execResult: PublicExecutionResult,
426
+ phase: PublicKernelPhase,
427
+ ) {
428
+ const { publicDataReads, publicDataUpdateRequests } = PhaseIsRevertible[phase]
429
+ ? publicInputs.end
430
+ : publicInputs.endNonRevertibleData;
431
+
432
+ // Convert ContractStorage* objects to PublicData* objects and sort them in execution order.
433
+ // Note, this only pulls simulated reads/writes from the current phase,
434
+ // so the returned result will be a subset of the public kernel output.
435
+
436
+ const simPublicDataReads = collectPublicDataReads(execResult);
437
+ // verify that each read is in the kernel output
438
+ for (const read of simPublicDataReads) {
439
+ if (!publicDataReads.find(item => item.equals(read))) {
440
+ throw new Error(
441
+ `Public data reads from simulator do not match those from public kernel.\nFrom simulator: ${simPublicDataReads
442
+ .map(p => p.toFriendlyJSON())
443
+ .join(', ')}\nFrom public kernel: ${publicDataReads.map(i => i.toFriendlyJSON()).join(', ')}`,
444
+ );
445
+ }
446
+ }
447
+
448
+ const simPublicDataUpdateRequests = collectPublicDataUpdateRequests(execResult);
449
+ for (const update of simPublicDataUpdateRequests) {
450
+ if (!publicDataUpdateRequests.find(item => item.equals(update))) {
451
+ throw new Error(
452
+ `Public data update requests from simulator do not match those from public kernel.\nFrom simulator: ${simPublicDataUpdateRequests
453
+ .map(p => p.toFriendlyJSON())
454
+ .join(', ')}\nFrom public kernel revertible: ${publicDataUpdateRequests
455
+ .map(i => i.toFriendlyJSON())
456
+ .join(', ')}`,
457
+ );
458
+ }
459
+ }
460
+ // We only want to reorder the items from the public inputs of the
461
+ // most recently processed top/enqueued call.
462
+
463
+ const effectSet = PhaseIsRevertible[phase] ? 'end' : 'endNonRevertibleData';
464
+
465
+ const numReadsInKernel = arrayNonEmptyLength(publicDataReads, f => f.isEmpty());
466
+ const numReadsBeforeThisEnqueuedCall = numReadsInKernel - simPublicDataReads.length;
467
+ publicInputs[effectSet].publicDataReads = padArrayEnd(
468
+ [
469
+ // do not mess with items from previous top/enqueued calls in kernel output
470
+ ...publicInputs[effectSet].publicDataReads.slice(0, numReadsBeforeThisEnqueuedCall),
471
+ ...simPublicDataReads,
472
+ ],
473
+ PublicDataRead.empty(),
474
+ PhaseIsRevertible[phase] ? MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX : MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX,
475
+ );
476
+
477
+ const numUpdatesInKernel = arrayNonEmptyLength(publicDataUpdateRequests, f => f.isEmpty());
478
+ const numUpdatesBeforeThisEnqueuedCall = numUpdatesInKernel - simPublicDataUpdateRequests.length;
479
+ publicInputs[effectSet].publicDataUpdateRequests = padArrayEnd(
480
+ [
481
+ ...publicInputs[effectSet].publicDataUpdateRequests.slice(0, numUpdatesBeforeThisEnqueuedCall),
482
+ ...simPublicDataUpdateRequests,
483
+ ],
484
+ PublicDataUpdateRequest.empty(),
485
+ PhaseIsRevertible[phase]
486
+ ? MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX
487
+ : MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
488
+ );
489
+ }
@@ -0,0 +1,75 @@
1
+ import { Tx } from '@aztec/circuit-types';
2
+ import { GlobalVariables, Header, Proof, PublicKernelCircuitPublicInputs } from '@aztec/circuits.js';
3
+ import { PublicExecutor, PublicStateDB } from '@aztec/simulator';
4
+ import { MerkleTreeOperations } from '@aztec/world-state';
5
+
6
+ import { PublicProver } from '../prover/index.js';
7
+ import { PublicKernelCircuitSimulator } from '../simulator/index.js';
8
+ import { ContractsDataSourcePublicDB } from '../simulator/public_executor.js';
9
+ import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js';
10
+ import { FailedTx } from './processed_tx.js';
11
+
12
+ /**
13
+ * The phase manager responsible for performing the fee preparation phase.
14
+ */
15
+ export class AppLogicPhaseManager extends AbstractPhaseManager {
16
+ constructor(
17
+ protected db: MerkleTreeOperations,
18
+ protected publicExecutor: PublicExecutor,
19
+ protected publicKernel: PublicKernelCircuitSimulator,
20
+ protected publicProver: PublicProver,
21
+ protected globalVariables: GlobalVariables,
22
+ protected historicalHeader: Header,
23
+ protected publicContractsDB: ContractsDataSourcePublicDB,
24
+ protected publicStateDB: PublicStateDB,
25
+ public phase: PublicKernelPhase = PublicKernelPhase.APP_LOGIC,
26
+ ) {
27
+ super(db, publicExecutor, publicKernel, publicProver, globalVariables, historicalHeader, phase);
28
+ }
29
+
30
+ async handle(
31
+ tx: Tx,
32
+ previousPublicKernelOutput: PublicKernelCircuitPublicInputs,
33
+ previousPublicKernelProof: Proof,
34
+ ): Promise<{
35
+ /**
36
+ * the output of the public kernel circuit for this phase
37
+ */
38
+ publicKernelOutput: PublicKernelCircuitPublicInputs;
39
+ /**
40
+ * the proof of the public kernel circuit for this phase
41
+ */
42
+ publicKernelProof: Proof;
43
+ }> {
44
+ // add new contracts to the contracts db so that their functions may be found and called
45
+ // TODO(#4073): This is catching only private deployments, when we add public ones, we'll
46
+ // have to capture contracts emitted in that phase as well.
47
+ // TODO(@spalladino): Should we allow emitting contracts in the fee preparation phase?
48
+ this.log(`Processing tx ${tx.getTxHash()}`);
49
+ await this.publicContractsDB.addNewContracts(tx);
50
+ this.log(`Executing enqueued public calls for tx ${tx.getTxHash()}`);
51
+ const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs] = await this.processEnqueuedPublicCalls(
52
+ tx,
53
+ previousPublicKernelOutput,
54
+ previousPublicKernelProof,
55
+ );
56
+ tx.unencryptedLogs.addFunctionLogs(newUnencryptedFunctionLogs);
57
+
58
+ // commit the state updates from this transaction
59
+ await this.publicStateDB.commit();
60
+
61
+ return { publicKernelOutput, publicKernelProof };
62
+ }
63
+
64
+ async rollback(tx: Tx, err: unknown): Promise<FailedTx> {
65
+ this.log.warn(`Error processing tx ${tx.getTxHash()}: ${err}`);
66
+ // remove contracts on failure
67
+ await this.publicContractsDB.removeNewContracts(tx);
68
+ // rollback any state updates from this failed transaction
69
+ await this.publicStateDB.rollback();
70
+ return {
71
+ tx,
72
+ error: err instanceof Error ? err : new Error('Unknown error'),
73
+ };
74
+ }
75
+ }
@@ -0,0 +1 @@
1
+ export { SequencerConfig } from '@aztec/circuit-types';
@@ -0,0 +1,2 @@
1
+ export * from './sequencer.js';
2
+ export * from './config.js';
@@ -0,0 +1,122 @@
1
+ import { Tx } from '@aztec/circuit-types';
2
+ import { GlobalVariables, Header, PublicKernelCircuitPublicInputs } from '@aztec/circuits.js';
3
+ import { PublicExecutor, PublicStateDB } from '@aztec/simulator';
4
+ import { MerkleTreeOperations } from '@aztec/world-state';
5
+
6
+ import { PublicProver } from '../prover/index.js';
7
+ import { PublicKernelCircuitSimulator } from '../simulator/index.js';
8
+ import { ContractsDataSourcePublicDB } from '../simulator/public_executor.js';
9
+ import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js';
10
+ import { AppLogicPhaseManager } from './app_logic_phase_manager.js';
11
+ import { SetupPhaseManager } from './setup_phase_manager.js';
12
+ import { TeardownPhaseManager } from './teardown_phase_manager.js';
13
+
14
+ export class PhaseDidNotChangeError extends Error {
15
+ constructor(phase: PublicKernelPhase) {
16
+ super(`Tried to advance the phase from [${phase}] when the circuit still needs [${phase}]`);
17
+ }
18
+ }
19
+
20
+ export class CannotTransitionToSetupError extends Error {
21
+ constructor() {
22
+ super('Cannot transition to setup phase');
23
+ }
24
+ }
25
+
26
+ export class PhaseManagerFactory {
27
+ public static phaseFromTx(
28
+ tx: Tx,
29
+ db: MerkleTreeOperations,
30
+ publicExecutor: PublicExecutor,
31
+ publicKernel: PublicKernelCircuitSimulator,
32
+ publicProver: PublicProver,
33
+ globalVariables: GlobalVariables,
34
+ historicalHeader: Header,
35
+ publicContractsDB: ContractsDataSourcePublicDB,
36
+ publicStateDB: PublicStateDB,
37
+ ): AbstractPhaseManager | undefined {
38
+ if (tx.data.needsSetup) {
39
+ return new SetupPhaseManager(
40
+ db,
41
+ publicExecutor,
42
+ publicKernel,
43
+ publicProver,
44
+ globalVariables,
45
+ historicalHeader,
46
+ publicContractsDB,
47
+ publicStateDB,
48
+ );
49
+ } else if (tx.data.needsAppLogic) {
50
+ return new AppLogicPhaseManager(
51
+ db,
52
+ publicExecutor,
53
+ publicKernel,
54
+ publicProver,
55
+ globalVariables,
56
+ historicalHeader,
57
+ publicContractsDB,
58
+ publicStateDB,
59
+ );
60
+ } else if (tx.data.needsTeardown) {
61
+ return new TeardownPhaseManager(
62
+ db,
63
+ publicExecutor,
64
+ publicKernel,
65
+ publicProver,
66
+ globalVariables,
67
+ historicalHeader,
68
+ publicContractsDB,
69
+ publicStateDB,
70
+ );
71
+ } else {
72
+ return undefined;
73
+ }
74
+ }
75
+
76
+ public static phaseFromOutput(
77
+ output: PublicKernelCircuitPublicInputs,
78
+ currentPhaseManager: AbstractPhaseManager,
79
+ db: MerkleTreeOperations,
80
+ publicExecutor: PublicExecutor,
81
+ publicKernel: PublicKernelCircuitSimulator,
82
+ publicProver: PublicProver,
83
+ globalVariables: GlobalVariables,
84
+ historicalHeader: Header,
85
+ publicContractsDB: ContractsDataSourcePublicDB,
86
+ publicStateDB: PublicStateDB,
87
+ ): AbstractPhaseManager | undefined {
88
+ if (output.needsSetup) {
89
+ throw new CannotTransitionToSetupError();
90
+ } else if (output.needsAppLogic) {
91
+ if (currentPhaseManager.phase === PublicKernelPhase.APP_LOGIC) {
92
+ throw new PhaseDidNotChangeError(currentPhaseManager.phase);
93
+ }
94
+ return new AppLogicPhaseManager(
95
+ db,
96
+ publicExecutor,
97
+ publicKernel,
98
+ publicProver,
99
+ globalVariables,
100
+ historicalHeader,
101
+ publicContractsDB,
102
+ publicStateDB,
103
+ );
104
+ } else if (output.needsTeardown) {
105
+ if (currentPhaseManager.phase === PublicKernelPhase.TEARDOWN) {
106
+ throw new PhaseDidNotChangeError(currentPhaseManager.phase);
107
+ }
108
+ return new TeardownPhaseManager(
109
+ db,
110
+ publicExecutor,
111
+ publicKernel,
112
+ publicProver,
113
+ globalVariables,
114
+ historicalHeader,
115
+ publicContractsDB,
116
+ publicStateDB,
117
+ );
118
+ } else {
119
+ return undefined;
120
+ }
121
+ }
122
+ }