@aztec/sequencer-client 0.26.5 → 0.26.6

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 (57) hide show
  1. package/dest/block_builder/solo_block_builder.d.ts.map +1 -1
  2. package/dest/block_builder/solo_block_builder.js +8 -5
  3. package/dest/index.d.ts +7 -7
  4. package/dest/index.d.ts.map +1 -1
  5. package/dest/index.js +8 -8
  6. package/dest/sequencer/abstract_phase_manager.d.ts +12 -15
  7. package/dest/sequencer/abstract_phase_manager.d.ts.map +1 -1
  8. package/dest/sequencer/abstract_phase_manager.js +32 -24
  9. package/dest/sequencer/app_logic_phase_manager.d.ts +1 -6
  10. package/dest/sequencer/app_logic_phase_manager.d.ts.map +1 -1
  11. package/dest/sequencer/app_logic_phase_manager.js +11 -8
  12. package/dest/sequencer/hints_builder.d.ts +13 -0
  13. package/dest/sequencer/hints_builder.d.ts.map +1 -0
  14. package/dest/sequencer/hints_builder.js +21 -0
  15. package/dest/sequencer/index.d.ts +1 -1
  16. package/dest/sequencer/index.d.ts.map +1 -1
  17. package/dest/sequencer/index.js +2 -2
  18. package/dest/sequencer/phase_manager_factory.d.ts.map +1 -1
  19. package/dest/sequencer/phase_manager_factory.js +5 -1
  20. package/dest/sequencer/processed_tx.d.ts +37 -2
  21. package/dest/sequencer/processed_tx.d.ts.map +1 -1
  22. package/dest/sequencer/processed_tx.js +67 -9
  23. package/dest/sequencer/public_processor.d.ts.map +1 -1
  24. package/dest/sequencer/public_processor.js +15 -9
  25. package/dest/sequencer/sequencer.d.ts.map +1 -1
  26. package/dest/sequencer/sequencer.js +1 -2
  27. package/dest/sequencer/setup_phase_manager.d.ts +1 -6
  28. package/dest/sequencer/setup_phase_manager.d.ts.map +1 -1
  29. package/dest/sequencer/setup_phase_manager.js +3 -5
  30. package/dest/sequencer/tail_phase_manager.d.ts +28 -0
  31. package/dest/sequencer/tail_phase_manager.d.ts.map +1 -0
  32. package/dest/sequencer/tail_phase_manager.js +32 -0
  33. package/dest/sequencer/teardown_phase_manager.d.ts +1 -6
  34. package/dest/sequencer/teardown_phase_manager.d.ts.map +1 -1
  35. package/dest/sequencer/teardown_phase_manager.js +3 -4
  36. package/dest/simulator/index.d.ts +7 -1
  37. package/dest/simulator/index.d.ts.map +1 -1
  38. package/dest/simulator/index.js +1 -1
  39. package/dest/simulator/public_kernel.d.ts +7 -1
  40. package/dest/simulator/public_kernel.d.ts.map +1 -1
  41. package/dest/simulator/public_kernel.js +22 -4
  42. package/package.json +13 -13
  43. package/src/block_builder/solo_block_builder.ts +6 -32
  44. package/src/index.ts +7 -7
  45. package/src/sequencer/abstract_phase_manager.ts +58 -48
  46. package/src/sequencer/app_logic_phase_manager.ts +12 -22
  47. package/src/sequencer/hints_builder.ts +56 -0
  48. package/src/sequencer/index.ts +1 -1
  49. package/src/sequencer/phase_manager_factory.ts +12 -0
  50. package/src/sequencer/processed_tx.ts +147 -17
  51. package/src/sequencer/public_processor.ts +25 -13
  52. package/src/sequencer/sequencer.ts +0 -1
  53. package/src/sequencer/setup_phase_manager.ts +5 -19
  54. package/src/sequencer/tail_phase_manager.ts +49 -0
  55. package/src/sequencer/teardown_phase_manager.ts +5 -18
  56. package/src/simulator/index.ts +7 -0
  57. package/src/simulator/public_kernel.ts +35 -5
@@ -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,13 +1,29 @@
1
- import { ExtendedContractData, Tx, TxHash, TxL2Logs } from '@aztec/circuit-types';
1
+ import {
2
+ ContractData,
3
+ ExtendedContractData,
4
+ PublicDataWrite,
5
+ SimulationError,
6
+ Tx,
7
+ TxEffect,
8
+ TxHash,
9
+ TxL2Logs,
10
+ } from '@aztec/circuit-types';
2
11
  import {
3
12
  Fr,
4
13
  Header,
14
+ MAX_NEW_CONTRACTS_PER_TX,
15
+ MAX_NEW_NOTE_HASHES_PER_TX,
16
+ MAX_NEW_NULLIFIERS_PER_TX,
17
+ MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
5
18
  Proof,
6
19
  PublicAccumulatedNonRevertibleData,
7
20
  PublicAccumulatedRevertibleData,
8
21
  PublicKernelCircuitPublicInputs,
22
+ SideEffect,
23
+ SideEffectLinkedToNoteHash,
9
24
  makeEmptyProof,
10
25
  } from '@aztec/circuits.js';
26
+ import { Tuple, fromFieldsTuple } from '@aztec/foundation/serialize';
11
27
 
12
28
  /**
13
29
  * Represents a tx that has been processed by the sequencer public processor,
@@ -26,8 +42,39 @@ export type ProcessedTx = Pick<Tx, 'proof' | 'encryptedLogs' | 'unencryptedLogs'
26
42
  * Flag indicating the tx is 'empty' meaning it's a padding tx to take us to a power of 2.
27
43
  */
28
44
  isEmpty: boolean;
45
+
46
+ /**
47
+ * Reason the tx was reverted.
48
+ */
49
+ revertReason: SimulationError | undefined;
29
50
  };
30
51
 
52
+ export type RevertedTx = ProcessedTx & {
53
+ data: PublicKernelCircuitPublicInputs & {
54
+ reverted: true;
55
+ };
56
+
57
+ revertReason: SimulationError;
58
+ };
59
+
60
+ export function isRevertedTx(tx: ProcessedTx): tx is RevertedTx {
61
+ return tx.data.reverted;
62
+ }
63
+
64
+ export function partitionReverts(txs: ProcessedTx[]): { reverted: RevertedTx[]; nonReverted: ProcessedTx[] } {
65
+ return txs.reduce(
66
+ ({ reverted, nonReverted }, tx) => {
67
+ if (isRevertedTx(tx)) {
68
+ reverted.push(tx);
69
+ } else {
70
+ nonReverted.push(tx);
71
+ }
72
+ return { reverted, nonReverted };
73
+ },
74
+ { reverted: [], nonReverted: [] } as ReturnType<typeof partitionReverts>,
75
+ );
76
+ }
77
+
31
78
  /**
32
79
  * Represents a tx that failed to be processed by the sequencer public processor.
33
80
  */
@@ -42,31 +89,73 @@ export type FailedTx = {
42
89
  error: Error;
43
90
  };
44
91
 
92
+ /**
93
+ *
94
+ * @param tx - the TX being procesed
95
+ * @param publicKernelPublicInput - the output of the public kernel circuit, unless we just came from private
96
+ * @param publicKernelProof - the proof of the public kernel circuit, unless we just came from private
97
+ * @returns PublicKernelCircuitPublicInputs, either passed through from the input or converted from the output of the TX,
98
+ * and Proof, either passed through from the input or the proof of the TX
99
+ */
100
+ export function getPreviousOutputAndProof(
101
+ tx: Tx,
102
+ publicKernelPublicInput?: PublicKernelCircuitPublicInputs,
103
+ publicKernelProof?: Proof,
104
+ ): {
105
+ /**
106
+ * the output of the public kernel circuit for this phase
107
+ */
108
+ publicKernelPublicInput: PublicKernelCircuitPublicInputs;
109
+ /**
110
+ * the proof of the public kernel circuit for this phase
111
+ */
112
+ previousProof: Proof;
113
+ } {
114
+ if (publicKernelPublicInput && publicKernelProof) {
115
+ return {
116
+ publicKernelPublicInput,
117
+ previousProof: publicKernelProof,
118
+ };
119
+ } else {
120
+ const publicKernelPublicInput = new PublicKernelCircuitPublicInputs(
121
+ tx.data.aggregationObject,
122
+ PublicAccumulatedNonRevertibleData.fromPrivateAccumulatedNonRevertibleData(tx.data.endNonRevertibleData),
123
+ PublicAccumulatedRevertibleData.fromPrivateAccumulatedRevertibleData(tx.data.end),
124
+ tx.data.constants,
125
+ tx.data.needsSetup,
126
+ tx.data.needsAppLogic,
127
+ tx.data.needsTeardown,
128
+ false, // reverted
129
+ );
130
+ return {
131
+ publicKernelPublicInput,
132
+ previousProof: publicKernelProof || tx.proof,
133
+ };
134
+ }
135
+ }
136
+
45
137
  /**
46
138
  * Makes a processed tx out of source tx.
47
139
  * @param tx - Source tx.
48
140
  * @param kernelOutput - Output of the kernel circuit simulation for this tx.
49
141
  * @param proof - Proof of the kernel circuit for this tx.
50
142
  */
51
- export function makeProcessedTx(tx: Tx, kernelOutput?: PublicKernelCircuitPublicInputs, proof?: Proof): ProcessedTx {
143
+ export function makeProcessedTx(
144
+ tx: Tx,
145
+ kernelOutput?: PublicKernelCircuitPublicInputs,
146
+ proof?: Proof,
147
+ revertReason?: SimulationError,
148
+ ): ProcessedTx {
149
+ const { publicKernelPublicInput, previousProof } = getPreviousOutputAndProof(tx, kernelOutput, proof);
52
150
  return {
53
151
  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,
152
+ data: publicKernelPublicInput,
153
+ proof: previousProof,
154
+ encryptedLogs: revertReason ? new TxL2Logs([]) : tx.encryptedLogs,
155
+ unencryptedLogs: revertReason ? new TxL2Logs([]) : tx.unencryptedLogs,
156
+ newContracts: revertReason ? [ExtendedContractData.empty()] : tx.newContracts,
69
157
  isEmpty: false,
158
+ revertReason,
70
159
  };
71
160
  }
72
161
 
@@ -90,5 +179,46 @@ export function makeEmptyProcessedTx(header: Header, chainId: Fr, version: Fr):
90
179
  proof: emptyProof,
91
180
  newContracts: [ExtendedContractData.empty()],
92
181
  isEmpty: true,
182
+ revertReason: undefined,
93
183
  };
94
184
  }
185
+
186
+ export function toTxEffect(tx: ProcessedTx): TxEffect {
187
+ return new TxEffect(
188
+ tx.data.combinedData.newNoteHashes.map((c: SideEffect) => c.value) as Tuple<Fr, typeof MAX_NEW_NOTE_HASHES_PER_TX>,
189
+ tx.data.combinedData.newNullifiers.map((n: SideEffectLinkedToNoteHash) => n.value) as Tuple<
190
+ Fr,
191
+ typeof MAX_NEW_NULLIFIERS_PER_TX
192
+ >,
193
+ tx.data.combinedData.newL2ToL1Msgs,
194
+ tx.data.combinedData.publicDataUpdateRequests.map(t => new PublicDataWrite(t.leafSlot, t.newValue)) as Tuple<
195
+ PublicDataWrite,
196
+ typeof MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX
197
+ >,
198
+ tx.data.combinedData.newContracts.map(cd => cd.hash()) as Tuple<Fr, typeof MAX_NEW_CONTRACTS_PER_TX>,
199
+ tx.data.combinedData.newContracts.map(
200
+ cd => new ContractData(cd.contractAddress, cd.portalContractAddress),
201
+ ) as Tuple<ContractData, typeof MAX_NEW_CONTRACTS_PER_TX>,
202
+ tx.encryptedLogs || new TxL2Logs([]),
203
+ tx.unencryptedLogs || new TxL2Logs([]),
204
+ );
205
+ }
206
+
207
+ function validateProcessedTxLogs(tx: ProcessedTx): void {
208
+ const unencryptedLogs = tx.unencryptedLogs || new TxL2Logs([]);
209
+ const kernelUnencryptedLogsHash = fromFieldsTuple(tx.data.combinedData.unencryptedLogsHash);
210
+ if (!unencryptedLogs.hash().equals(kernelUnencryptedLogsHash)) {
211
+ throw new Error(
212
+ `Unencrypted logs hash mismatch. Expected ${unencryptedLogs
213
+ .hash()
214
+ .toString('hex')}, got ${kernelUnencryptedLogsHash.toString('hex')}.
215
+ Processed: ${JSON.stringify(unencryptedLogs.toJSON())}
216
+ Kernel Length: ${tx.data.combinedData.unencryptedLogPreimagesLength}`,
217
+ );
218
+ }
219
+ }
220
+
221
+ export function validateProcessedTx(tx: ProcessedTx): void {
222
+ validateProcessedTxLogs(tx);
223
+ // TODO: validate other fields
224
+ }
@@ -1,4 +1,4 @@
1
- import { ContractDataSource, L1ToL2MessageSource, Tx } from '@aztec/circuit-types';
1
+ import { ContractDataSource, L1ToL2MessageSource, SimulationError, Tx } from '@aztec/circuit-types';
2
2
  import { TxSequencerProcessingStats } from '@aztec/circuit-types/stats';
3
3
  import { GlobalVariables, Header } from '@aztec/circuits.js';
4
4
  import { createDebugLogger } from '@aztec/foundation/log';
@@ -14,7 +14,14 @@ import { RealPublicKernelCircuitSimulator } from '../simulator/public_kernel.js'
14
14
  import { SimulationProvider } from '../simulator/simulation_provider.js';
15
15
  import { AbstractPhaseManager } from './abstract_phase_manager.js';
16
16
  import { PhaseManagerFactory } from './phase_manager_factory.js';
17
- import { FailedTx, ProcessedTx, makeEmptyProcessedTx, makeProcessedTx } from './processed_tx.js';
17
+ import {
18
+ FailedTx,
19
+ ProcessedTx,
20
+ getPreviousOutputAndProof,
21
+ makeEmptyProcessedTx,
22
+ makeProcessedTx,
23
+ validateProcessedTx,
24
+ } from './processed_tx.js';
18
25
 
19
26
  /**
20
27
  * Creates new instances of PublicProcessor given the provided merkle tree db and contract data source.
@@ -99,17 +106,15 @@ export class PublicProcessor {
99
106
  this.publicStateDB,
100
107
  );
101
108
  this.log(`Beginning processing in phase ${phase?.phase} for tx ${tx.getTxHash()}`);
102
- let { publicKernelPublicInput, publicKernelProof } = AbstractPhaseManager.getKernelOutputAndProof(
103
- tx,
104
- undefined,
105
- undefined,
106
- );
109
+ let { publicKernelPublicInput, previousProof: proof } = getPreviousOutputAndProof(tx, undefined, undefined);
110
+ let revertReason: SimulationError | undefined;
107
111
  const timer = new Timer();
108
112
  try {
109
113
  while (phase) {
110
- const output = await phase.handle(tx, publicKernelPublicInput, publicKernelProof);
114
+ const output = await phase.handle(tx, publicKernelPublicInput, proof);
111
115
  publicKernelPublicInput = output.publicKernelOutput;
112
- publicKernelProof = output.publicKernelProof;
116
+ proof = output.publicKernelProof;
117
+ revertReason ??= output.revertReason;
113
118
  phase = PhaseManagerFactory.phaseFromOutput(
114
119
  publicKernelPublicInput,
115
120
  phase,
@@ -124,7 +129,9 @@ export class PublicProcessor {
124
129
  );
125
130
  }
126
131
 
127
- const processedTransaction = makeProcessedTx(tx, publicKernelPublicInput, publicKernelProof);
132
+ const processedTransaction = makeProcessedTx(tx, publicKernelPublicInput, proof, revertReason);
133
+ validateProcessedTx(processedTransaction);
134
+
128
135
  result.push(processedTransaction);
129
136
 
130
137
  this.log(`Processed public part of ${tx.data.endNonRevertibleData.newNullifiers[0].value}`, {
@@ -135,9 +142,14 @@ export class PublicProcessor {
135
142
  0,
136
143
  ...tx.getStats(),
137
144
  } satisfies TxSequencerProcessingStats);
138
- } catch (err) {
139
- const failedTx = await phase!.rollback(tx, err);
140
- failed.push(failedTx);
145
+ } catch (err: any) {
146
+ const errorMessage = err instanceof Error ? err.message : 'Unknown error';
147
+ this.log.warn(`Failed to process tx ${tx.getTxHash()}: ${errorMessage}`);
148
+
149
+ failed.push({
150
+ tx,
151
+ error: err instanceof Error ? err : new Error(errorMessage),
152
+ });
141
153
  }
142
154
  }
143
155
 
@@ -180,7 +180,6 @@ export class Sequencer {
180
180
  this.log.info(`Building block ${newBlockNumber} with ${validTxs.length} transactions`);
181
181
  this.state = SequencerState.CREATING_BLOCK;
182
182
 
183
- // Process txs and drop the ones that fail processing
184
183
  // We create a fresh processor each time to reset any cached state (eg storage writes)
185
184
  const processor = await this.publicProcessorFactory.create(historicalHeader, newGlobalVariables);
186
185
  const [publicProcessorDuration, [processedTxs, failedTxs]] = await elapsed(() => processor.process(validTxs));
@@ -27,34 +27,20 @@ export class SetupPhaseManager extends AbstractPhaseManager {
27
27
  super(db, publicExecutor, publicKernel, publicProver, globalVariables, historicalHeader, phase);
28
28
  }
29
29
 
30
- // this is a no-op for now
31
- async handle(
30
+ override async handle(
32
31
  tx: Tx,
33
32
  previousPublicKernelOutput: PublicKernelCircuitPublicInputs,
34
33
  previousPublicKernelProof: Proof,
35
- ): Promise<{
36
- /**
37
- * the output of the public kernel circuit for this phase
38
- */
39
- publicKernelOutput: PublicKernelCircuitPublicInputs;
40
- /**
41
- * the proof of the public kernel circuit for this phase
42
- */
43
- publicKernelProof: Proof;
44
- }> {
34
+ ) {
45
35
  this.log(`Processing tx ${tx.getTxHash()}`);
46
- this.log(`Executing enqueued public calls for tx ${tx.getTxHash()}`);
47
- const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs] = await this.processEnqueuedPublicCalls(
48
- tx,
49
- previousPublicKernelOutput,
50
- previousPublicKernelProof,
51
- );
36
+ const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs, revertReason] =
37
+ await this.processEnqueuedPublicCalls(tx, previousPublicKernelOutput, previousPublicKernelProof);
52
38
  tx.unencryptedLogs.addFunctionLogs(newUnencryptedFunctionLogs);
53
39
 
54
40
  // commit the state updates from this transaction
55
41
  await this.publicStateDB.commit();
56
42
 
57
- return { publicKernelOutput, publicKernelProof };
43
+ return { publicKernelOutput, publicKernelProof, revertReason };
58
44
  }
59
45
 
60
46
  async rollback(tx: Tx, err: unknown): Promise<FailedTx> {
@@ -0,0 +1,49 @@
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
+ export class TailPhaseManager extends AbstractPhaseManager {
13
+ constructor(
14
+ protected db: MerkleTreeOperations,
15
+ protected publicExecutor: PublicExecutor,
16
+ protected publicKernel: PublicKernelCircuitSimulator,
17
+ protected publicProver: PublicProver,
18
+ protected globalVariables: GlobalVariables,
19
+ protected historicalHeader: Header,
20
+ protected publicContractsDB: ContractsDataSourcePublicDB,
21
+ protected publicStateDB: PublicStateDB,
22
+ public readonly phase: PublicKernelPhase = PublicKernelPhase.TAIL,
23
+ ) {
24
+ super(db, publicExecutor, publicKernel, publicProver, globalVariables, historicalHeader, phase);
25
+ }
26
+
27
+ async handle(tx: Tx, previousPublicKernelOutput: PublicKernelCircuitPublicInputs, previousPublicKernelProof: Proof) {
28
+ this.log(`Processing tx ${tx.getTxHash()}`);
29
+ this.log(`Executing tail circuit for tx ${tx.getTxHash()}`);
30
+ const [publicKernelOutput, publicKernelProof] = await this.runKernelCircuit(
31
+ previousPublicKernelOutput,
32
+ previousPublicKernelProof,
33
+ );
34
+
35
+ // commit the state updates from this transaction
36
+ await this.publicStateDB.commit();
37
+
38
+ return { publicKernelOutput, publicKernelProof, revertReason: undefined };
39
+ }
40
+
41
+ async rollback(tx: Tx, err: unknown): Promise<FailedTx> {
42
+ this.log.warn(`Error processing tx ${tx.getTxHash()}: ${err}`);
43
+ await this.publicStateDB.rollback();
44
+ return {
45
+ tx,
46
+ error: err instanceof Error ? err : new Error('Unknown error'),
47
+ };
48
+ }
49
+ }
@@ -27,33 +27,20 @@ export class TeardownPhaseManager 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
  this.log(`Processing tx ${tx.getTxHash()}`);
45
- this.log(`Executing enqueued public calls for tx ${tx.getTxHash()}`);
46
- const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs] = await this.processEnqueuedPublicCalls(
47
- tx,
48
- previousPublicKernelOutput,
49
- previousPublicKernelProof,
50
- );
36
+ const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs, revertReason] =
37
+ await this.processEnqueuedPublicCalls(tx, previousPublicKernelOutput, previousPublicKernelProof);
51
38
  tx.unencryptedLogs.addFunctionLogs(newUnencryptedFunctionLogs);
52
39
 
53
40
  // commit the state updates from this transaction
54
41
  await this.publicStateDB.commit();
55
42
 
56
- return { publicKernelOutput, publicKernelProof };
43
+ return { publicKernelOutput, publicKernelProof, revertReason };
57
44
  }
58
45
 
59
46
  async rollback(tx: Tx, err: unknown): Promise<FailedTx> {
@@ -4,6 +4,7 @@ import {
4
4
  MergeRollupInputs,
5
5
  PublicKernelCircuitPrivateInputs,
6
6
  PublicKernelCircuitPublicInputs,
7
+ PublicKernelTailCircuitPrivateInputs,
7
8
  RootRollupInputs,
8
9
  RootRollupPublicInputs,
9
10
  } from '@aztec/circuits.js';
@@ -54,5 +55,11 @@ export interface PublicKernelCircuitSimulator {
54
55
  * @returns The public inputs as outputs of the simulation.
55
56
  */
56
57
  publicKernelCircuitTeardown(inputs: PublicKernelCircuitPrivateInputs): Promise<PublicKernelCircuitPublicInputs>;
58
+ /**
59
+ * Simulates the public kernel tail circuit from its inputs.
60
+ * @param inputs - Inputs to the circuit.
61
+ * @returns The public inputs as outputs of the simulation.
62
+ */
63
+ publicKernelCircuitTail(inputs: PublicKernelTailCircuitPrivateInputs): Promise<PublicKernelCircuitPublicInputs>;
57
64
  }
58
65
  export * from './acvm_wasm.js';
@@ -1,17 +1,24 @@
1
1
  import { CircuitSimulationStats } from '@aztec/circuit-types/stats';
2
- import { PublicKernelCircuitPrivateInputs, PublicKernelCircuitPublicInputs } from '@aztec/circuits.js';
2
+ import {
3
+ PublicKernelCircuitPrivateInputs,
4
+ PublicKernelCircuitPublicInputs,
5
+ PublicKernelTailCircuitPrivateInputs,
6
+ } from '@aztec/circuits.js';
3
7
  import { createDebugLogger } from '@aztec/foundation/log';
4
8
  import { elapsed } from '@aztec/foundation/timer';
5
9
  import {
6
10
  PublicKernelAppLogicArtifact,
7
11
  PublicKernelSetupArtifact,
12
+ PublicKernelTailArtifact,
8
13
  PublicKernelTeardownArtifact,
9
14
  convertPublicInnerRollupInputsToWitnessMap,
10
15
  convertPublicInnerRollupOutputFromWitnessMap,
11
16
  convertPublicSetupRollupInputsToWitnessMap,
12
17
  convertPublicSetupRollupOutputFromWitnessMap,
13
- convertPublicTailRollupInputsToWitnessMap,
14
- convertPublicTailRollupOutputFromWitnessMap,
18
+ convertPublicTailInputsToWitnessMap,
19
+ convertPublicTailOutputFromWitnessMap,
20
+ convertPublicTeardownRollupInputsToWitnessMap,
21
+ convertPublicTeardownRollupOutputFromWitnessMap,
15
22
  } from '@aztec/noir-protocol-circuits-types';
16
23
 
17
24
  import { PublicKernelCircuitSimulator, WASMSimulator } from './index.js';
@@ -91,11 +98,11 @@ export class RealPublicKernelCircuitSimulator implements PublicKernelCircuitSimu
91
98
  if (!input.previousKernel.publicInputs.needsTeardown) {
92
99
  throw new Error(`Expected previous kernel inputs to need teardown`);
93
100
  }
94
- const inputWitness = convertPublicTailRollupInputsToWitnessMap(input);
101
+ const inputWitness = convertPublicTeardownRollupInputsToWitnessMap(input);
95
102
  const [duration, witness] = await elapsed(() =>
96
103
  this.wasmSimulator.simulateCircuit(inputWitness, PublicKernelTeardownArtifact),
97
104
  );
98
- const result = convertPublicTailRollupOutputFromWitnessMap(witness);
105
+ const result = convertPublicTeardownRollupOutputFromWitnessMap(witness);
99
106
  this.log(`Simulated public kernel teardown circuit`, {
100
107
  eventName: 'circuit-simulation',
101
108
  circuitName: 'public-kernel-teardown',
@@ -105,4 +112,27 @@ export class RealPublicKernelCircuitSimulator implements PublicKernelCircuitSimu
105
112
  } satisfies CircuitSimulationStats);
106
113
  return result;
107
114
  }
115
+
116
+ /**
117
+ * Simulates the public kernel tail circuit from its inputs.
118
+ * @param input - Inputs to the circuit.
119
+ * @returns The public inputs as outputs of the simulation.
120
+ */
121
+ public async publicKernelCircuitTail(
122
+ input: PublicKernelTailCircuitPrivateInputs,
123
+ ): Promise<PublicKernelCircuitPublicInputs> {
124
+ const inputWitness = convertPublicTailInputsToWitnessMap(input);
125
+ const [duration, witness] = await elapsed(() =>
126
+ this.wasmSimulator.simulateCircuit(inputWitness, PublicKernelTailArtifact),
127
+ );
128
+ const result = convertPublicTailOutputFromWitnessMap(witness);
129
+ this.log(`Simulated public kernel tail circuit`, {
130
+ eventName: 'circuit-simulation',
131
+ circuitName: 'public-kernel-tail',
132
+ duration,
133
+ inputSize: input.toBuffer().length,
134
+ outputSize: result.toBuffer().length,
135
+ } satisfies CircuitSimulationStats);
136
+ return result;
137
+ }
108
138
  }