@aztec/sequencer-client 0.26.5 → 0.27.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.
Files changed (72) hide show
  1. package/dest/block_builder/solo_block_builder.d.ts.map +1 -1
  2. package/dest/block_builder/solo_block_builder.js +12 -28
  3. package/dest/config.d.ts.map +1 -1
  4. package/dest/config.js +2 -5
  5. package/dest/index.d.ts +7 -7
  6. package/dest/index.d.ts.map +1 -1
  7. package/dest/index.js +8 -8
  8. package/dest/publisher/l1-publisher.d.ts +1 -21
  9. package/dest/publisher/l1-publisher.d.ts.map +1 -1
  10. package/dest/publisher/l1-publisher.js +1 -55
  11. package/dest/publisher/viem-tx-sender.d.ts +1 -10
  12. package/dest/publisher/viem-tx-sender.d.ts.map +1 -1
  13. package/dest/publisher/viem-tx-sender.js +2 -41
  14. package/dest/sequencer/abstract_phase_manager.d.ts +12 -15
  15. package/dest/sequencer/abstract_phase_manager.d.ts.map +1 -1
  16. package/dest/sequencer/abstract_phase_manager.js +32 -24
  17. package/dest/sequencer/app_logic_phase_manager.d.ts +1 -6
  18. package/dest/sequencer/app_logic_phase_manager.d.ts.map +1 -1
  19. package/dest/sequencer/app_logic_phase_manager.js +11 -8
  20. package/dest/sequencer/hints_builder.d.ts +13 -0
  21. package/dest/sequencer/hints_builder.d.ts.map +1 -0
  22. package/dest/sequencer/hints_builder.js +21 -0
  23. package/dest/sequencer/index.d.ts +1 -1
  24. package/dest/sequencer/index.d.ts.map +1 -1
  25. package/dest/sequencer/index.js +2 -2
  26. package/dest/sequencer/phase_manager_factory.d.ts.map +1 -1
  27. package/dest/sequencer/phase_manager_factory.js +5 -1
  28. package/dest/sequencer/processed_tx.d.ts +38 -3
  29. package/dest/sequencer/processed_tx.d.ts.map +1 -1
  30. package/dest/sequencer/processed_tx.js +66 -10
  31. package/dest/sequencer/public_processor.d.ts.map +1 -1
  32. package/dest/sequencer/public_processor.js +15 -9
  33. package/dest/sequencer/sequencer.d.ts +0 -6
  34. package/dest/sequencer/sequencer.d.ts.map +1 -1
  35. package/dest/sequencer/sequencer.js +1 -27
  36. package/dest/sequencer/setup_phase_manager.d.ts +1 -6
  37. package/dest/sequencer/setup_phase_manager.d.ts.map +1 -1
  38. package/dest/sequencer/setup_phase_manager.js +3 -5
  39. package/dest/sequencer/tail_phase_manager.d.ts +28 -0
  40. package/dest/sequencer/tail_phase_manager.d.ts.map +1 -0
  41. package/dest/sequencer/tail_phase_manager.js +32 -0
  42. package/dest/sequencer/teardown_phase_manager.d.ts +1 -6
  43. package/dest/sequencer/teardown_phase_manager.d.ts.map +1 -1
  44. package/dest/sequencer/teardown_phase_manager.js +3 -4
  45. package/dest/simulator/index.d.ts +7 -1
  46. package/dest/simulator/index.d.ts.map +1 -1
  47. package/dest/simulator/index.js +1 -1
  48. package/dest/simulator/public_executor.d.ts.map +1 -1
  49. package/dest/simulator/public_executor.js +1 -15
  50. package/dest/simulator/public_kernel.d.ts +7 -1
  51. package/dest/simulator/public_kernel.d.ts.map +1 -1
  52. package/dest/simulator/public_kernel.js +22 -4
  53. package/package.json +13 -13
  54. package/src/block_builder/solo_block_builder.ts +17 -77
  55. package/src/config.ts +0 -4
  56. package/src/index.ts +7 -7
  57. package/src/publisher/l1-publisher.ts +1 -85
  58. package/src/publisher/viem-tx-sender.ts +2 -52
  59. package/src/sequencer/abstract_phase_manager.ts +58 -48
  60. package/src/sequencer/app_logic_phase_manager.ts +12 -22
  61. package/src/sequencer/hints_builder.ts +56 -0
  62. package/src/sequencer/index.ts +1 -1
  63. package/src/sequencer/phase_manager_factory.ts +12 -0
  64. package/src/sequencer/processed_tx.ts +133 -19
  65. package/src/sequencer/public_processor.ts +25 -13
  66. package/src/sequencer/sequencer.ts +0 -36
  67. package/src/sequencer/setup_phase_manager.ts +5 -19
  68. package/src/sequencer/tail_phase_manager.ts +49 -0
  69. package/src/sequencer/teardown_phase_manager.ts +5 -18
  70. package/src/simulator/index.ts +7 -0
  71. package/src/simulator/public_executor.ts +0 -20
  72. package/src/simulator/public_kernel.ts +35 -5
@@ -1,8 +1,7 @@
1
- import { ExtendedContractData, L2Block } from '@aztec/circuit-types';
2
- import { BLOB_SIZE_IN_BYTES } from '@aztec/circuits.js/constants';
1
+ import { L2Block } from '@aztec/circuit-types';
3
2
  import { createEthereumChain } from '@aztec/ethereum';
4
3
  import { createDebugLogger } from '@aztec/foundation/log';
5
- import { AvailabilityOracleAbi, ContractDeploymentEmitterAbi, RollupAbi } from '@aztec/l1-artifacts';
4
+ import { AvailabilityOracleAbi, RollupAbi } from '@aztec/l1-artifacts';
6
5
 
7
6
  import {
8
7
  GetContractReturnType,
@@ -40,10 +39,6 @@ export class ViemTxSender implements L1PublisherTxSender {
40
39
  typeof RollupAbi,
41
40
  WalletClient<HttpTransport, chains.Chain, PrivateKeyAccount>
42
41
  >;
43
- private contractDeploymentEmitterContract: GetContractReturnType<
44
- typeof ContractDeploymentEmitterAbi,
45
- WalletClient<HttpTransport, chains.Chain, PrivateKeyAccount>
46
- >;
47
42
 
48
43
  private log = createDebugLogger('aztec:sequencer:viem-tx-sender');
49
44
  private publicClient: PublicClient<HttpTransport, chains.Chain>;
@@ -74,11 +69,6 @@ export class ViemTxSender implements L1PublisherTxSender {
74
69
  abi: RollupAbi,
75
70
  client: walletClient,
76
71
  });
77
- this.contractDeploymentEmitterContract = getContract({
78
- address: getAddress(l1Contracts.contractDeploymentEmitterAddress.toString()),
79
- abi: ContractDeploymentEmitterAbi,
80
- client: walletClient,
81
- });
82
72
  }
83
73
 
84
74
  async getCurrentArchive(): Promise<Buffer> {
@@ -169,46 +159,6 @@ export class ViemTxSender implements L1PublisherTxSender {
169
159
  return hash;
170
160
  }
171
161
 
172
- /**
173
- * Sends a tx to the contract deployment emitter contract with contract deployment data such as bytecode. Returns once the tx has been mined.
174
- * @param l2BlockNum - Number of the L2 block that owns this encrypted logs.
175
- * @param l2BlockHash - The hash of the block corresponding to this data.
176
- * @param newExtendedContractData - Data to publish.
177
- * @returns The hash of the mined tx.
178
- */
179
- async sendEmitContractDeploymentTx(
180
- l2BlockNum: number,
181
- l2BlockHash: Buffer,
182
- newExtendedContractData: ExtendedContractData[],
183
- ): Promise<(string | undefined)[]> {
184
- const hashes: string[] = [];
185
- for (const extendedContractData of newExtendedContractData) {
186
- const args = [
187
- BigInt(l2BlockNum),
188
- extendedContractData.contractData.contractAddress.toString() as Hex,
189
- extendedContractData.contractData.portalContractAddress.toString() as Hex,
190
- `0x${l2BlockHash.toString('hex')}`,
191
- extendedContractData.contractClassId.toString(),
192
- extendedContractData.saltedInitializationHash.toString(),
193
- extendedContractData.publicKeyHash.toString(),
194
- `0x${extendedContractData.bytecode.toString('hex')}`,
195
- ] as const;
196
-
197
- const codeSize = extendedContractData.bytecode.length;
198
- this.log(`Bytecode is ${codeSize} bytes and require ${codeSize / BLOB_SIZE_IN_BYTES} blobs`);
199
-
200
- const gas = await this.contractDeploymentEmitterContract.estimateGas.emitContractDeployment(args, {
201
- account: this.account,
202
- });
203
- const hash = await this.contractDeploymentEmitterContract.write.emitContractDeployment(args, {
204
- gas,
205
- account: this.account,
206
- });
207
- hashes.push(hash);
208
- }
209
- return hashes;
210
- }
211
-
212
162
  /**
213
163
  * Gets the chain object for the given chain id.
214
164
  * @param chainId - Chain id of the target EVM chain.
@@ -1,4 +1,4 @@
1
- import { FunctionL2Logs, MerkleTreeId, Tx } from '@aztec/circuit-types';
1
+ import { FunctionL2Logs, MerkleTreeId, SimulationError, Tx } from '@aztec/circuit-types';
2
2
  import {
3
3
  AztecAddress,
4
4
  CallRequest,
@@ -13,6 +13,7 @@ import {
13
13
  MAX_NEW_NULLIFIERS_PER_CALL,
14
14
  MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX,
15
15
  MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
16
+ MAX_NULLIFIER_READ_REQUESTS_PER_CALL,
16
17
  MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL,
17
18
  MAX_PUBLIC_DATA_READS_PER_CALL,
18
19
  MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL,
@@ -21,8 +22,6 @@ import {
21
22
  MembershipWitness,
22
23
  PrivateKernelTailCircuitPublicInputs,
23
24
  Proof,
24
- PublicAccumulatedNonRevertibleData,
25
- PublicAccumulatedRevertibleData,
26
25
  PublicCallData,
27
26
  PublicCallRequest,
28
27
  PublicCallStackItem,
@@ -32,7 +31,9 @@ import {
32
31
  PublicKernelCircuitPrivateInputs,
33
32
  PublicKernelCircuitPublicInputs,
34
33
  PublicKernelData,
34
+ PublicKernelTailCircuitPrivateInputs,
35
35
  RETURN_VALUES_LENGTH,
36
+ ReadRequest,
36
37
  SideEffect,
37
38
  SideEffectLinkedToNoteHash,
38
39
  VK_TREE_HEIGHT,
@@ -56,21 +57,25 @@ import { env } from 'process';
56
57
  import { getVerificationKeys } from '../mocks/verification_keys.js';
57
58
  import { PublicProver } from '../prover/index.js';
58
59
  import { PublicKernelCircuitSimulator } from '../simulator/index.js';
60
+ import { HintsBuilder } from './hints_builder.js';
59
61
  import { FailedTx } from './processed_tx.js';
60
62
 
61
63
  export enum PublicKernelPhase {
62
64
  SETUP = 'setup',
63
65
  APP_LOGIC = 'app-logic',
64
66
  TEARDOWN = 'teardown',
67
+ TAIL = 'tail',
65
68
  }
66
69
 
67
70
  export const PhaseIsRevertible: Record<PublicKernelPhase, boolean> = {
68
71
  [PublicKernelPhase.SETUP]: false,
69
72
  [PublicKernelPhase.APP_LOGIC]: true,
70
73
  [PublicKernelPhase.TEARDOWN]: false,
74
+ [PublicKernelPhase.TAIL]: false,
71
75
  };
72
76
 
73
77
  export abstract class AbstractPhaseManager {
78
+ protected hintsBuilder: HintsBuilder;
74
79
  protected log: DebugLogger;
75
80
  constructor(
76
81
  protected db: MerkleTreeOperations,
@@ -81,6 +86,7 @@ export abstract class AbstractPhaseManager {
81
86
  protected historicalHeader: Header,
82
87
  public phase: PublicKernelPhase,
83
88
  ) {
89
+ this.hintsBuilder = new HintsBuilder(db);
84
90
  this.log = createDebugLogger(`aztec:sequencer:${phase}`);
85
91
  }
86
92
  /**
@@ -102,6 +108,10 @@ export abstract class AbstractPhaseManager {
102
108
  * the proof of the public kernel circuit for this phase
103
109
  */
104
110
  publicKernelProof: Proof;
111
+ /**
112
+ * revert reason, if any
113
+ */
114
+ revertReason: SimulationError | undefined;
105
115
  }>;
106
116
  abstract rollback(tx: Tx, err: unknown): Promise<FailedTx>;
107
117
 
@@ -127,6 +137,7 @@ export abstract class AbstractPhaseManager {
127
137
  [PublicKernelPhase.SETUP]: [],
128
138
  [PublicKernelPhase.APP_LOGIC]: [],
129
139
  [PublicKernelPhase.TEARDOWN]: [],
140
+ [PublicKernelPhase.TAIL]: [],
130
141
  };
131
142
  }
132
143
 
@@ -140,12 +151,14 @@ export abstract class AbstractPhaseManager {
140
151
  [PublicKernelPhase.SETUP]: [],
141
152
  [PublicKernelPhase.APP_LOGIC]: publicCallsStack,
142
153
  [PublicKernelPhase.TEARDOWN]: [],
154
+ [PublicKernelPhase.TAIL]: [],
143
155
  };
144
156
  } else {
145
157
  return {
146
158
  [PublicKernelPhase.SETUP]: publicCallsStack.slice(0, firstRevertibleCallIndex - 1),
147
159
  [PublicKernelPhase.APP_LOGIC]: publicCallsStack.slice(firstRevertibleCallIndex),
148
160
  [PublicKernelPhase.TEARDOWN]: [publicCallsStack[firstRevertibleCallIndex - 1]],
161
+ [PublicKernelPhase.TAIL]: [],
149
162
  };
150
163
  }
151
164
  }
@@ -158,55 +171,18 @@ export abstract class AbstractPhaseManager {
158
171
  return calls;
159
172
  }
160
173
 
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
174
  protected async processEnqueuedPublicCalls(
199
175
  tx: Tx,
200
176
  previousPublicKernelOutput: PublicKernelCircuitPublicInputs,
201
177
  previousPublicKernelProof: Proof,
202
- ): Promise<[PublicKernelCircuitPublicInputs, Proof, FunctionL2Logs[]]> {
178
+ ): Promise<[PublicKernelCircuitPublicInputs, Proof, FunctionL2Logs[], SimulationError | undefined]> {
203
179
  let kernelOutput = previousPublicKernelOutput;
204
180
  let kernelProof = previousPublicKernelProof;
205
181
 
206
182
  const enqueuedCalls = this.extractEnqueuedPublicCalls(tx);
207
183
 
208
184
  if (!enqueuedCalls || !enqueuedCalls.length) {
209
- return [kernelOutput, kernelProof, []];
185
+ return [kernelOutput, kernelProof, [], undefined];
210
186
  }
211
187
 
212
188
  const newUnencryptedFunctionLogs: FunctionL2Logs[] = [];
@@ -241,7 +217,18 @@ export abstract class AbstractPhaseManager {
241
217
  executionStack.push(...result.nestedExecutions);
242
218
  const callData = await this.getPublicCallData(result, isExecutionRequest);
243
219
 
244
- [kernelOutput, kernelProof] = await this.runKernelCircuit(callData, kernelOutput, kernelProof);
220
+ [kernelOutput, kernelProof] = await this.runKernelCircuit(kernelOutput, kernelProof, callData);
221
+
222
+ if (kernelOutput.reverted && this.phase === PublicKernelPhase.APP_LOGIC) {
223
+ this.log.debug(
224
+ `Reverting on ${result.execution.contractAddress.toString()}:${functionSelector} with reason: ${
225
+ result.revertReason
226
+ }`,
227
+ );
228
+ // halt immediately if the public kernel circuit has reverted.
229
+ // return no logs, as they should not go on-chain.
230
+ return [kernelOutput, kernelProof, [], result.revertReason];
231
+ }
245
232
 
246
233
  if (!enqueuedExecutionResult) {
247
234
  enqueuedExecutionResult = result;
@@ -255,25 +242,42 @@ export abstract class AbstractPhaseManager {
255
242
  // TODO(#3675): This should be done in a public kernel circuit
256
243
  removeRedundantPublicDataWrites(kernelOutput);
257
244
 
258
- return [kernelOutput, kernelProof, newUnencryptedFunctionLogs];
245
+ return [kernelOutput, kernelProof, newUnencryptedFunctionLogs, undefined];
259
246
  }
260
247
 
261
248
  protected async runKernelCircuit(
262
- callData: PublicCallData,
263
249
  previousOutput: PublicKernelCircuitPublicInputs,
264
250
  previousProof: Proof,
251
+ callData?: PublicCallData,
265
252
  ): Promise<[PublicKernelCircuitPublicInputs, Proof]> {
266
- const output = await this.getKernelCircuitOutput(callData, previousOutput, previousProof);
253
+ const output = await this.getKernelCircuitOutput(previousOutput, previousProof, callData);
267
254
  const proof = await this.publicProver.getPublicKernelCircuitProof(output);
268
255
  return [output, proof];
269
256
  }
270
257
 
271
- protected getKernelCircuitOutput(
272
- callData: PublicCallData,
258
+ protected async getKernelCircuitOutput(
273
259
  previousOutput: PublicKernelCircuitPublicInputs,
274
260
  previousProof: Proof,
261
+ callData?: PublicCallData,
275
262
  ): Promise<PublicKernelCircuitPublicInputs> {
276
263
  const previousKernel = this.getPreviousKernelData(previousOutput, previousProof);
264
+
265
+ if (this.phase === PublicKernelPhase.TAIL) {
266
+ const { endNonRevertibleData, end } = previousOutput;
267
+ const nullifierReadRequestResetHints = await this.hintsBuilder.getNullifierReadRequestResetHints(
268
+ endNonRevertibleData.nullifierReadRequests,
269
+ end.nullifierReadRequests,
270
+ endNonRevertibleData.newNullifiers,
271
+ end.newNullifiers,
272
+ );
273
+ const inputs = new PublicKernelTailCircuitPrivateInputs(previousKernel, nullifierReadRequestResetHints);
274
+ return this.publicKernel.publicKernelCircuitTail(inputs);
275
+ }
276
+
277
+ if (!callData) {
278
+ throw new Error(`Cannot run public kernel circuit without call data for phase '${this.phase}'.`);
279
+ }
280
+
277
281
  const inputs = new PublicKernelCircuitPrivateInputs(previousKernel, callData);
278
282
  switch (this.phase) {
279
283
  case PublicKernelPhase.SETUP:
@@ -320,6 +324,11 @@ export abstract class AbstractPhaseManager {
320
324
  newNullifiers: padArrayEnd(result.newNullifiers, SideEffectLinkedToNoteHash.empty(), MAX_NEW_NULLIFIERS_PER_CALL),
321
325
  newL2ToL1Msgs: padArrayEnd(result.newL2ToL1Messages, L2ToL1Message.empty(), MAX_NEW_L2_TO_L1_MSGS_PER_CALL),
322
326
  returnValues: padArrayEnd(result.returnValues, Fr.ZERO, RETURN_VALUES_LENGTH),
327
+ nullifierReadRequests: padArrayEnd(
328
+ result.nullifierReadRequests,
329
+ ReadRequest.empty(),
330
+ MAX_NULLIFIER_READ_REQUESTS_PER_CALL,
331
+ ),
323
332
  contractStorageReads: padArrayEnd(
324
333
  result.contractStorageReads,
325
334
  ContractStorageRead.empty(),
@@ -334,6 +343,7 @@ export abstract class AbstractPhaseManager {
334
343
  unencryptedLogsHash,
335
344
  unencryptedLogPreimagesLength,
336
345
  historicalHeader: this.historicalHeader,
346
+ reverted: result.reverted,
337
347
  });
338
348
  }
339
349
 
@@ -27,42 +27,32 @@ export class AppLogicPhaseManager extends AbstractPhaseManager {
27
27
  super(db, publicExecutor, publicKernel, publicProver, globalVariables, historicalHeader, phase);
28
28
  }
29
29
 
30
- async handle(
30
+ override async handle(
31
31
  tx: Tx,
32
32
  previousPublicKernelOutput: PublicKernelCircuitPublicInputs,
33
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
- }> {
34
+ ) {
44
35
  // add new contracts to the contracts db so that their functions may be found and called
45
36
  // TODO(#4073): This is catching only private deployments, when we add public ones, we'll
46
37
  // have to capture contracts emitted in that phase as well.
47
38
  // TODO(@spalladino): Should we allow emitting contracts in the fee preparation phase?
48
39
  this.log(`Processing tx ${tx.getTxHash()}`);
49
40
  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);
41
+ const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs, revertReason] =
42
+ await this.processEnqueuedPublicCalls(tx, previousPublicKernelOutput, previousPublicKernelProof);
57
43
 
58
- // commit the state updates from this transaction
59
- await this.publicStateDB.commit();
44
+ if (revertReason) {
45
+ await this.rollback(tx, revertReason);
46
+ } else {
47
+ tx.unencryptedLogs.addFunctionLogs(newUnencryptedFunctionLogs);
48
+ await this.publicStateDB.commit();
49
+ }
60
50
 
61
- return { publicKernelOutput, publicKernelProof };
51
+ return { publicKernelOutput, publicKernelProof, revertReason };
62
52
  }
63
53
 
64
54
  async rollback(tx: Tx, err: unknown): Promise<FailedTx> {
65
- this.log.warn(`Error processing tx ${tx.getTxHash()}: ${err}`);
55
+ this.log.warn(`Rolling back changes from ${tx.getTxHash()}`);
66
56
  // remove contracts on failure
67
57
  await this.publicContractsDB.removeNewContracts(tx);
68
58
  // rollback any state updates from this failed transaction
@@ -0,0 +1,56 @@
1
+ import { MerkleTreeId } from '@aztec/circuit-types';
2
+ import {
3
+ Fr,
4
+ MAX_NEW_NULLIFIERS_PER_TX,
5
+ MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX,
6
+ MAX_NULLIFIER_READ_REQUESTS_PER_TX,
7
+ MAX_REVERTIBLE_NULLIFIERS_PER_TX,
8
+ MembershipWitness,
9
+ NULLIFIER_TREE_HEIGHT,
10
+ NullifierLeafPreimage,
11
+ ReadRequestContext,
12
+ SideEffectLinkedToNoteHash,
13
+ buildNullifierReadRequestResetHints,
14
+ concatAccumulatedData,
15
+ mergeAccumulatedData,
16
+ } from '@aztec/circuits.js';
17
+ import { Tuple } from '@aztec/foundation/serialize';
18
+ import { MerkleTreeOperations } from '@aztec/world-state';
19
+
20
+ export class HintsBuilder {
21
+ constructor(private db: MerkleTreeOperations) {}
22
+
23
+ getNullifierReadRequestResetHints(
24
+ nullifierReadRequestsNonRevertible: Tuple<ReadRequestContext, typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX>,
25
+ nullifierReadRequestsRevertible: Tuple<ReadRequestContext, typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX>,
26
+ nullifiersNonRevertible: Tuple<SideEffectLinkedToNoteHash, typeof MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX>,
27
+ nullifiersRevertible: Tuple<SideEffectLinkedToNoteHash, typeof MAX_REVERTIBLE_NULLIFIERS_PER_TX>,
28
+ ) {
29
+ return buildNullifierReadRequestResetHints(
30
+ this,
31
+ mergeAccumulatedData(
32
+ MAX_NULLIFIER_READ_REQUESTS_PER_TX,
33
+ nullifierReadRequestsNonRevertible,
34
+ nullifierReadRequestsRevertible,
35
+ ),
36
+ concatAccumulatedData(MAX_NEW_NULLIFIERS_PER_TX, nullifiersNonRevertible, nullifiersRevertible),
37
+ );
38
+ }
39
+
40
+ async getNullifierMembershipWitness(nullifier: Fr) {
41
+ const index = await this.db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
42
+ if (index === undefined) {
43
+ return;
44
+ }
45
+
46
+ const siblingPath = await this.db.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, index);
47
+ const membershipWitness = new MembershipWitness(
48
+ NULLIFIER_TREE_HEIGHT,
49
+ index,
50
+ siblingPath.toTuple<typeof NULLIFIER_TREE_HEIGHT>(),
51
+ );
52
+ const leafPreimage = (await this.db.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index))! as NullifierLeafPreimage;
53
+
54
+ return { membershipWitness, leafPreimage };
55
+ }
56
+ }
@@ -1,2 +1,2 @@
1
- export * from './sequencer.js';
2
1
  export * from './config.js';
2
+ export * from './sequencer.js';
@@ -9,6 +9,7 @@ import { ContractsDataSourcePublicDB } from '../simulator/public_executor.js';
9
9
  import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js';
10
10
  import { AppLogicPhaseManager } from './app_logic_phase_manager.js';
11
11
  import { SetupPhaseManager } from './setup_phase_manager.js';
12
+ import { TailPhaseManager } from './tail_phase_manager.js';
12
13
  import { TeardownPhaseManager } from './teardown_phase_manager.js';
13
14
 
14
15
  export class PhaseDidNotChangeError extends Error {
@@ -115,6 +116,17 @@ export class PhaseManagerFactory {
115
116
  publicContractsDB,
116
117
  publicStateDB,
117
118
  );
119
+ } else if (currentPhaseManager.phase !== PublicKernelPhase.TAIL) {
120
+ return new TailPhaseManager(
121
+ db,
122
+ publicExecutor,
123
+ publicKernel,
124
+ publicProver,
125
+ globalVariables,
126
+ historicalHeader,
127
+ publicContractsDB,
128
+ publicStateDB,
129
+ );
118
130
  } else {
119
131
  return undefined;
120
132
  }
@@ -1,19 +1,25 @@
1
- import { ExtendedContractData, Tx, TxHash, TxL2Logs } from '@aztec/circuit-types';
1
+ import { PublicDataWrite, SimulationError, Tx, TxEffect, TxHash, TxL2Logs } from '@aztec/circuit-types';
2
2
  import {
3
3
  Fr,
4
4
  Header,
5
+ MAX_NEW_NOTE_HASHES_PER_TX,
6
+ MAX_NEW_NULLIFIERS_PER_TX,
7
+ MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
5
8
  Proof,
6
9
  PublicAccumulatedNonRevertibleData,
7
10
  PublicAccumulatedRevertibleData,
8
11
  PublicKernelCircuitPublicInputs,
12
+ SideEffect,
13
+ SideEffectLinkedToNoteHash,
9
14
  makeEmptyProof,
10
15
  } from '@aztec/circuits.js';
16
+ import { Tuple, fromFieldsTuple } from '@aztec/foundation/serialize';
11
17
 
12
18
  /**
13
19
  * Represents a tx that has been processed by the sequencer public processor,
14
20
  * so its kernel circuit public inputs are filled in.
15
21
  */
16
- export type ProcessedTx = Pick<Tx, 'proof' | 'encryptedLogs' | 'unencryptedLogs' | 'newContracts'> & {
22
+ export type ProcessedTx = Pick<Tx, 'proof' | 'encryptedLogs' | 'unencryptedLogs'> & {
17
23
  /**
18
24
  * Output of the public kernel circuit for this tx.
19
25
  */
@@ -26,8 +32,39 @@ export type ProcessedTx = Pick<Tx, 'proof' | 'encryptedLogs' | 'unencryptedLogs'
26
32
  * Flag indicating the tx is 'empty' meaning it's a padding tx to take us to a power of 2.
27
33
  */
28
34
  isEmpty: boolean;
35
+
36
+ /**
37
+ * Reason the tx was reverted.
38
+ */
39
+ revertReason: SimulationError | undefined;
40
+ };
41
+
42
+ export type RevertedTx = ProcessedTx & {
43
+ data: PublicKernelCircuitPublicInputs & {
44
+ reverted: true;
45
+ };
46
+
47
+ revertReason: SimulationError;
29
48
  };
30
49
 
50
+ export function isRevertedTx(tx: ProcessedTx): tx is RevertedTx {
51
+ return tx.data.reverted;
52
+ }
53
+
54
+ export function partitionReverts(txs: ProcessedTx[]): { reverted: RevertedTx[]; nonReverted: ProcessedTx[] } {
55
+ return txs.reduce(
56
+ ({ reverted, nonReverted }, tx) => {
57
+ if (isRevertedTx(tx)) {
58
+ reverted.push(tx);
59
+ } else {
60
+ nonReverted.push(tx);
61
+ }
62
+ return { reverted, nonReverted };
63
+ },
64
+ { reverted: [], nonReverted: [] } as ReturnType<typeof partitionReverts>,
65
+ );
66
+ }
67
+
31
68
  /**
32
69
  * Represents a tx that failed to be processed by the sequencer public processor.
33
70
  */
@@ -42,31 +79,72 @@ export type FailedTx = {
42
79
  error: Error;
43
80
  };
44
81
 
82
+ /**
83
+ *
84
+ * @param tx - the TX being procesed
85
+ * @param publicKernelPublicInput - the output of the public kernel circuit, unless we just came from private
86
+ * @param publicKernelProof - the proof of the public kernel circuit, unless we just came from private
87
+ * @returns PublicKernelCircuitPublicInputs, either passed through from the input or converted from the output of the TX,
88
+ * and Proof, either passed through from the input or the proof of the TX
89
+ */
90
+ export function getPreviousOutputAndProof(
91
+ tx: Tx,
92
+ publicKernelPublicInput?: PublicKernelCircuitPublicInputs,
93
+ publicKernelProof?: Proof,
94
+ ): {
95
+ /**
96
+ * the output of the public kernel circuit for this phase
97
+ */
98
+ publicKernelPublicInput: PublicKernelCircuitPublicInputs;
99
+ /**
100
+ * the proof of the public kernel circuit for this phase
101
+ */
102
+ previousProof: Proof;
103
+ } {
104
+ if (publicKernelPublicInput && publicKernelProof) {
105
+ return {
106
+ publicKernelPublicInput,
107
+ previousProof: publicKernelProof,
108
+ };
109
+ } else {
110
+ const publicKernelPublicInput = new PublicKernelCircuitPublicInputs(
111
+ tx.data.aggregationObject,
112
+ PublicAccumulatedNonRevertibleData.fromPrivateAccumulatedNonRevertibleData(tx.data.endNonRevertibleData),
113
+ PublicAccumulatedRevertibleData.fromPrivateAccumulatedRevertibleData(tx.data.end),
114
+ tx.data.constants,
115
+ tx.data.needsSetup,
116
+ tx.data.needsAppLogic,
117
+ tx.data.needsTeardown,
118
+ false, // reverted
119
+ );
120
+ return {
121
+ publicKernelPublicInput,
122
+ previousProof: publicKernelProof || tx.proof,
123
+ };
124
+ }
125
+ }
126
+
45
127
  /**
46
128
  * Makes a processed tx out of source tx.
47
129
  * @param tx - Source tx.
48
130
  * @param kernelOutput - Output of the kernel circuit simulation for this tx.
49
131
  * @param proof - Proof of the kernel circuit for this tx.
50
132
  */
51
- export function makeProcessedTx(tx: Tx, kernelOutput?: PublicKernelCircuitPublicInputs, proof?: Proof): ProcessedTx {
133
+ export function makeProcessedTx(
134
+ tx: Tx,
135
+ kernelOutput?: PublicKernelCircuitPublicInputs,
136
+ proof?: Proof,
137
+ revertReason?: SimulationError,
138
+ ): ProcessedTx {
139
+ const { publicKernelPublicInput, previousProof } = getPreviousOutputAndProof(tx, kernelOutput, proof);
52
140
  return {
53
141
  hash: tx.getTxHash(),
54
- data:
55
- kernelOutput ??
56
- new PublicKernelCircuitPublicInputs(
57
- tx.data.aggregationObject,
58
- PublicAccumulatedNonRevertibleData.fromPrivateAccumulatedNonRevertibleData(tx.data.endNonRevertibleData),
59
- PublicAccumulatedRevertibleData.fromPrivateAccumulatedRevertibleData(tx.data.end),
60
- tx.data.constants,
61
- tx.data.needsSetup,
62
- tx.data.needsAppLogic,
63
- tx.data.needsTeardown,
64
- ),
65
- proof: proof ?? tx.proof,
66
- encryptedLogs: tx.encryptedLogs,
67
- unencryptedLogs: tx.unencryptedLogs,
68
- newContracts: tx.newContracts,
142
+ data: publicKernelPublicInput,
143
+ proof: previousProof,
144
+ encryptedLogs: revertReason ? new TxL2Logs([]) : tx.encryptedLogs,
145
+ unencryptedLogs: revertReason ? new TxL2Logs([]) : tx.unencryptedLogs,
69
146
  isEmpty: false,
147
+ revertReason,
70
148
  };
71
149
  }
72
150
 
@@ -88,7 +166,43 @@ export function makeEmptyProcessedTx(header: Header, chainId: Fr, version: Fr):
88
166
  unencryptedLogs: new TxL2Logs([]),
89
167
  data: emptyKernelOutput,
90
168
  proof: emptyProof,
91
- newContracts: [ExtendedContractData.empty()],
92
169
  isEmpty: true,
170
+ revertReason: undefined,
93
171
  };
94
172
  }
173
+
174
+ export function toTxEffect(tx: ProcessedTx): TxEffect {
175
+ return new TxEffect(
176
+ tx.data.combinedData.newNoteHashes.map((c: SideEffect) => c.value) as Tuple<Fr, typeof MAX_NEW_NOTE_HASHES_PER_TX>,
177
+ tx.data.combinedData.newNullifiers.map((n: SideEffectLinkedToNoteHash) => n.value) as Tuple<
178
+ Fr,
179
+ typeof MAX_NEW_NULLIFIERS_PER_TX
180
+ >,
181
+ tx.data.combinedData.newL2ToL1Msgs,
182
+ tx.data.combinedData.publicDataUpdateRequests.map(t => new PublicDataWrite(t.leafSlot, t.newValue)) as Tuple<
183
+ PublicDataWrite,
184
+ typeof MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX
185
+ >,
186
+ tx.encryptedLogs || new TxL2Logs([]),
187
+ tx.unencryptedLogs || new TxL2Logs([]),
188
+ );
189
+ }
190
+
191
+ function validateProcessedTxLogs(tx: ProcessedTx): void {
192
+ const unencryptedLogs = tx.unencryptedLogs || new TxL2Logs([]);
193
+ const kernelUnencryptedLogsHash = fromFieldsTuple(tx.data.combinedData.unencryptedLogsHash);
194
+ if (!unencryptedLogs.hash().equals(kernelUnencryptedLogsHash)) {
195
+ throw new Error(
196
+ `Unencrypted logs hash mismatch. Expected ${unencryptedLogs
197
+ .hash()
198
+ .toString('hex')}, got ${kernelUnencryptedLogsHash.toString('hex')}.
199
+ Processed: ${JSON.stringify(unencryptedLogs.toJSON())}
200
+ Kernel Length: ${tx.data.combinedData.unencryptedLogPreimagesLength}`,
201
+ );
202
+ }
203
+ }
204
+
205
+ export function validateProcessedTx(tx: ProcessedTx): void {
206
+ validateProcessedTxLogs(tx);
207
+ // TODO: validate other fields
208
+ }