@aztec/sequencer-client 0.27.1 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/block_builder/index.d.ts +3 -1
- package/dest/block_builder/index.d.ts.map +1 -1
- package/dest/block_builder/solo_block_builder.d.ts +10 -5
- package/dest/block_builder/solo_block_builder.d.ts.map +1 -1
- package/dest/block_builder/solo_block_builder.js +119 -52
- package/dest/prover/empty.d.ts +13 -1
- package/dest/prover/empty.d.ts.map +1 -1
- package/dest/prover/empty.js +19 -1
- package/dest/prover/index.d.ts +14 -2
- package/dest/prover/index.d.ts.map +1 -1
- package/dest/sequencer/abstract_phase_manager.d.ts +0 -2
- package/dest/sequencer/abstract_phase_manager.d.ts.map +1 -1
- package/dest/sequencer/abstract_phase_manager.js +30 -7
- package/dest/sequencer/app_logic_phase_manager.d.ts +0 -2
- package/dest/sequencer/app_logic_phase_manager.d.ts.map +1 -1
- package/dest/sequencer/app_logic_phase_manager.js +10 -15
- package/dest/sequencer/sequencer.d.ts +4 -1
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +8 -4
- package/dest/sequencer/setup_phase_manager.d.ts +0 -2
- package/dest/sequencer/setup_phase_manager.d.ts.map +1 -1
- package/dest/sequencer/setup_phase_manager.js +8 -12
- package/dest/sequencer/tail_phase_manager.d.ts +0 -2
- package/dest/sequencer/tail_phase_manager.d.ts.map +1 -1
- package/dest/sequencer/tail_phase_manager.js +7 -11
- package/dest/sequencer/teardown_phase_manager.d.ts +0 -2
- package/dest/sequencer/teardown_phase_manager.d.ts.map +1 -1
- package/dest/sequencer/teardown_phase_manager.js +8 -12
- package/dest/sequencer/utils.d.ts +8 -0
- package/dest/sequencer/utils.d.ts.map +1 -0
- package/dest/sequencer/utils.js +28 -0
- package/dest/simulator/index.d.ts +13 -1
- package/dest/simulator/index.d.ts.map +1 -1
- package/dest/simulator/index.js +1 -1
- package/dest/simulator/public_executor.d.ts +8 -3
- package/dest/simulator/public_executor.d.ts.map +1 -1
- package/dest/simulator/public_executor.js +39 -15
- package/dest/simulator/rollup.d.ts +13 -1
- package/dest/simulator/rollup.d.ts.map +1 -1
- package/dest/simulator/rollup.js +24 -2
- package/package.json +13 -13
- package/src/block_builder/index.ts +3 -1
- package/src/block_builder/solo_block_builder.ts +150 -52
- package/src/prover/empty.ts +23 -0
- package/src/prover/index.ts +18 -1
- package/src/sequencer/abstract_phase_manager.ts +37 -8
- package/src/sequencer/app_logic_phase_manager.ts +10 -16
- package/src/sequencer/sequencer.ts +12 -3
- package/src/sequencer/setup_phase_manager.ts +8 -15
- package/src/sequencer/tail_phase_manager.ts +6 -11
- package/src/sequencer/teardown_phase_manager.ts +8 -15
- package/src/sequencer/utils.ts +30 -0
- package/src/simulator/index.ts +15 -0
- package/src/simulator/public_executor.ts +41 -14
- package/src/simulator/rollup.ts +39 -0
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
ARCHIVE_HEIGHT,
|
|
5
5
|
AppendOnlyTreeSnapshot,
|
|
6
6
|
BaseOrMergeRollupPublicInputs,
|
|
7
|
+
BaseParityInputs,
|
|
7
8
|
BaseRollupInputs,
|
|
8
9
|
ConstantRollupData,
|
|
9
10
|
GlobalVariables,
|
|
@@ -20,6 +21,7 @@ import {
|
|
|
20
21
|
NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH,
|
|
21
22
|
NULLIFIER_TREE_HEIGHT,
|
|
22
23
|
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
24
|
+
NUM_BASE_PARITY_PER_ROOT_PARITY,
|
|
23
25
|
NullifierLeafPreimage,
|
|
24
26
|
PUBLIC_DATA_SUBTREE_HEIGHT,
|
|
25
27
|
PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH,
|
|
@@ -33,6 +35,8 @@ import {
|
|
|
33
35
|
RollupKernelCircuitPublicInputs,
|
|
34
36
|
RollupKernelData,
|
|
35
37
|
RollupTypes,
|
|
38
|
+
RootParityInput,
|
|
39
|
+
RootParityInputs,
|
|
36
40
|
RootRollupInputs,
|
|
37
41
|
RootRollupPublicInputs,
|
|
38
42
|
StateDiffHints,
|
|
@@ -85,6 +89,7 @@ export class SoloBlockBuilder implements BlockBuilder {
|
|
|
85
89
|
* Builds an L2 block with the given number containing the given txs, updating state trees.
|
|
86
90
|
* @param globalVariables - Global variables to be used in the block.
|
|
87
91
|
* @param txs - Processed transactions to include in the block.
|
|
92
|
+
* @param newModelL1ToL2Messages - L1 to L2 messages emitted by the new inbox.
|
|
88
93
|
* @param newL1ToL2Messages - L1 to L2 messages to be part of the block.
|
|
89
94
|
* @param timestamp - Timestamp of the block.
|
|
90
95
|
* @returns The new L2 block and a correctness proof as returned by the root rollup circuit.
|
|
@@ -92,13 +97,19 @@ export class SoloBlockBuilder implements BlockBuilder {
|
|
|
92
97
|
public async buildL2Block(
|
|
93
98
|
globalVariables: GlobalVariables,
|
|
94
99
|
txs: ProcessedTx[],
|
|
100
|
+
newModelL1ToL2Messages: Fr[], // TODO(#4492): Rename this when purging the old inbox
|
|
95
101
|
newL1ToL2Messages: Fr[],
|
|
96
102
|
): Promise<[L2Block, Proof]> {
|
|
97
103
|
// Check txs are good for processing by checking if all the tree snapshots in header are non-empty
|
|
98
104
|
this.validateTxs(txs);
|
|
99
105
|
|
|
100
106
|
// We fill the tx batch with empty txs, we process only one tx at a time for now
|
|
101
|
-
const [circuitsOutput, proof] = await this.runCircuits(
|
|
107
|
+
const [circuitsOutput, proof] = await this.runCircuits(
|
|
108
|
+
globalVariables,
|
|
109
|
+
txs,
|
|
110
|
+
newModelL1ToL2Messages,
|
|
111
|
+
newL1ToL2Messages,
|
|
112
|
+
);
|
|
102
113
|
|
|
103
114
|
// Collect all new nullifiers, commitments, and contracts from all txs in this block
|
|
104
115
|
const txEffects: TxEffect[] = txs.map(tx => toTxEffect(tx));
|
|
@@ -149,7 +160,8 @@ export class SoloBlockBuilder implements BlockBuilder {
|
|
|
149
160
|
protected async runCircuits(
|
|
150
161
|
globalVariables: GlobalVariables,
|
|
151
162
|
txs: ProcessedTx[],
|
|
152
|
-
|
|
163
|
+
newModelL1ToL2Messages: Fr[], // TODO(#4492): Rename this when purging the old inbox
|
|
164
|
+
newL1ToL2Messages: Fr[], // TODO(#4492): Nuke this when purging the old inbox
|
|
153
165
|
): Promise<[RootRollupPublicInputs, Proof]> {
|
|
154
166
|
// Check that the length of the array of txs is a power of two
|
|
155
167
|
// See https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
|
|
@@ -157,71 +169,154 @@ export class SoloBlockBuilder implements BlockBuilder {
|
|
|
157
169
|
throw new Error(`Length of txs for the block should be a power of two and at least two (got ${txs.length})`);
|
|
158
170
|
}
|
|
159
171
|
|
|
172
|
+
// BASE PARITY CIRCUIT (run in parallel)
|
|
173
|
+
let baseParityInputs: BaseParityInputs[] = [];
|
|
174
|
+
let elapsedBaseParityOutputsPromise: Promise<[number, RootParityInput[]]>;
|
|
175
|
+
{
|
|
176
|
+
const newModelL1ToL2MessagesTuple = padArrayEnd(
|
|
177
|
+
newModelL1ToL2Messages,
|
|
178
|
+
Fr.ZERO,
|
|
179
|
+
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
180
|
+
);
|
|
181
|
+
baseParityInputs = Array.from({ length: NUM_BASE_PARITY_PER_ROOT_PARITY }, (_, i) =>
|
|
182
|
+
BaseParityInputs.fromSlice(newModelL1ToL2MessagesTuple, i),
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const baseParityOutputs: Promise<RootParityInput>[] = [];
|
|
186
|
+
for (const inputs of baseParityInputs) {
|
|
187
|
+
baseParityOutputs.push(this.baseParityCircuit(inputs));
|
|
188
|
+
}
|
|
189
|
+
elapsedBaseParityOutputsPromise = elapsed(() => Promise.all(baseParityOutputs));
|
|
190
|
+
}
|
|
191
|
+
|
|
160
192
|
// padArrayEnd throws if the array is already full. Otherwise it pads till we reach the required size
|
|
161
193
|
const newL1ToL2MessagesTuple = padArrayEnd(newL1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
|
|
162
194
|
|
|
163
|
-
//
|
|
195
|
+
// BASE ROLLUP CIRCUIT (run in parallel)
|
|
196
|
+
let elapsedBaseRollupOutputsPromise: Promise<[number, [BaseOrMergeRollupPublicInputs, Proof][]]>;
|
|
164
197
|
const baseRollupInputs: BaseRollupInputs[] = [];
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
198
|
+
{
|
|
199
|
+
// Perform all tree insertions and retrieve snapshots for all base rollups
|
|
200
|
+
const treeSnapshots: Map<MerkleTreeId, AppendOnlyTreeSnapshot>[] = [];
|
|
201
|
+
for (const tx of txs) {
|
|
202
|
+
const input = await this.buildBaseRollupInput(tx, globalVariables);
|
|
203
|
+
baseRollupInputs.push(input);
|
|
204
|
+
const promises = [MerkleTreeId.NOTE_HASH_TREE, MerkleTreeId.NULLIFIER_TREE, MerkleTreeId.PUBLIC_DATA_TREE].map(
|
|
205
|
+
async (id: MerkleTreeId) => {
|
|
206
|
+
return { key: id, value: await this.getTreeSnapshot(id) };
|
|
207
|
+
},
|
|
208
|
+
);
|
|
209
|
+
const snapshots: Map<MerkleTreeId, AppendOnlyTreeSnapshot> = new Map(
|
|
210
|
+
(await Promise.all(promises)).map(obj => [obj.key, obj.value]),
|
|
211
|
+
);
|
|
212
|
+
treeSnapshots.push(snapshots);
|
|
213
|
+
}
|
|
179
214
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
215
|
+
// Run the base rollup circuits for the txs in parallel
|
|
216
|
+
const baseRollupOutputs: Promise<[BaseOrMergeRollupPublicInputs, Proof]>[] = [];
|
|
217
|
+
for (let i = 0; i < txs.length; i++) {
|
|
218
|
+
baseRollupOutputs.push(this.baseRollupCircuit(txs[i], baseRollupInputs[i], treeSnapshots[i]));
|
|
219
|
+
}
|
|
185
220
|
|
|
186
|
-
|
|
187
|
-
// All merge circuits for each layer are simulated in parallel
|
|
188
|
-
const [duration, mergeInputs] = await elapsed(() => Promise.all(baseRollupOutputs));
|
|
189
|
-
for (let i = 0; i < mergeInputs.length; i++) {
|
|
190
|
-
this.debug(`Simulated base rollup circuit`, {
|
|
191
|
-
eventName: 'circuit-simulation',
|
|
192
|
-
circuitName: 'base-rollup',
|
|
193
|
-
duration: duration / mergeInputs.length,
|
|
194
|
-
inputSize: baseRollupInputs[i].toBuffer().length,
|
|
195
|
-
outputSize: mergeInputs[i][0].toBuffer().length,
|
|
196
|
-
} satisfies CircuitSimulationStats);
|
|
221
|
+
elapsedBaseRollupOutputsPromise = elapsed(() => Promise.all(baseRollupOutputs));
|
|
197
222
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
223
|
+
|
|
224
|
+
// ROOT PARITY CIRCUIT
|
|
225
|
+
let elapsedRootParityOutputPromise: Promise<[number, RootParityInput]>;
|
|
226
|
+
let rootParityInputs: RootParityInputs;
|
|
227
|
+
{
|
|
228
|
+
// First we await the base parity outputs
|
|
229
|
+
const [duration, baseParityOutputs] = await elapsedBaseParityOutputsPromise;
|
|
230
|
+
|
|
231
|
+
// We emit stats for base parity circuits
|
|
232
|
+
for (let i = 0; i < baseParityOutputs.length; i++) {
|
|
233
|
+
this.debug(`Simulated base parity circuit`, {
|
|
234
|
+
eventName: 'circuit-simulation',
|
|
235
|
+
circuitName: 'base-parity',
|
|
236
|
+
duration: duration / baseParityOutputs.length,
|
|
237
|
+
inputSize: baseParityInputs[i].toBuffer().length,
|
|
238
|
+
outputSize: baseParityOutputs[i].toBuffer().length,
|
|
239
|
+
} satisfies CircuitSimulationStats);
|
|
204
240
|
}
|
|
205
241
|
|
|
206
|
-
|
|
207
|
-
|
|
242
|
+
rootParityInputs = new RootParityInputs(
|
|
243
|
+
baseParityOutputs as Tuple<RootParityInput, typeof NUM_BASE_PARITY_PER_ROOT_PARITY>,
|
|
208
244
|
);
|
|
245
|
+
elapsedRootParityOutputPromise = elapsed(() => this.rootParityCircuit(rootParityInputs));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// MERGE ROLLUP CIRCUIT (each layer run in parallel)
|
|
249
|
+
let mergeOutputLeft: [BaseOrMergeRollupPublicInputs, Proof];
|
|
250
|
+
let mergeOutputRight: [BaseOrMergeRollupPublicInputs, Proof];
|
|
251
|
+
{
|
|
252
|
+
// Run merge rollups in layers until we have only two outputs
|
|
253
|
+
const [duration, mergeInputs] = await elapsedBaseRollupOutputsPromise;
|
|
209
254
|
|
|
210
|
-
|
|
211
|
-
|
|
255
|
+
// We emit stats for base rollup circuits
|
|
256
|
+
for (let i = 0; i < mergeInputs.length; i++) {
|
|
257
|
+
this.debug(`Simulated base rollup circuit`, {
|
|
212
258
|
eventName: 'circuit-simulation',
|
|
213
|
-
circuitName: '
|
|
214
|
-
duration: duration /
|
|
215
|
-
inputSize:
|
|
216
|
-
outputSize:
|
|
259
|
+
circuitName: 'base-rollup',
|
|
260
|
+
duration: duration / mergeInputs.length,
|
|
261
|
+
inputSize: baseRollupInputs[i].toBuffer().length,
|
|
262
|
+
outputSize: mergeInputs[i][0].toBuffer().length,
|
|
217
263
|
} satisfies CircuitSimulationStats);
|
|
218
264
|
}
|
|
219
|
-
|
|
265
|
+
|
|
266
|
+
let mergeRollupInputs: [BaseOrMergeRollupPublicInputs, Proof][] = mergeInputs;
|
|
267
|
+
while (mergeRollupInputs.length > 2) {
|
|
268
|
+
const mergeInputStructs: MergeRollupInputs[] = [];
|
|
269
|
+
for (const pair of chunk(mergeRollupInputs, 2)) {
|
|
270
|
+
const [r1, r2] = pair;
|
|
271
|
+
mergeInputStructs.push(this.createMergeRollupInputs(r1, r2));
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const [duration, mergeOutputs] = await elapsed(() =>
|
|
275
|
+
Promise.all(mergeInputStructs.map(async input => await this.mergeRollupCircuit(input))),
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
// We emit stats for merge rollup circuits
|
|
279
|
+
for (let i = 0; i < mergeOutputs.length; i++) {
|
|
280
|
+
this.debug(`Simulated merge rollup circuit`, {
|
|
281
|
+
eventName: 'circuit-simulation',
|
|
282
|
+
circuitName: 'merge-rollup',
|
|
283
|
+
duration: duration / mergeOutputs.length,
|
|
284
|
+
inputSize: mergeInputStructs[i].toBuffer().length,
|
|
285
|
+
outputSize: mergeOutputs[i][0].toBuffer().length,
|
|
286
|
+
} satisfies CircuitSimulationStats);
|
|
287
|
+
}
|
|
288
|
+
mergeRollupInputs = mergeOutputs;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Run the root rollup with the last two merge rollups (or base, if no merge layers)
|
|
292
|
+
[mergeOutputLeft, mergeOutputRight] = mergeRollupInputs;
|
|
220
293
|
}
|
|
221
294
|
|
|
222
|
-
//
|
|
223
|
-
const [
|
|
224
|
-
|
|
295
|
+
// Finally, we emit stats for root parity circuit
|
|
296
|
+
const [duration, rootParityOutput] = await elapsedRootParityOutputPromise;
|
|
297
|
+
this.debug(`Simulated root parity circuit`, {
|
|
298
|
+
eventName: 'circuit-simulation',
|
|
299
|
+
circuitName: 'root-parity',
|
|
300
|
+
duration: duration,
|
|
301
|
+
inputSize: rootParityInputs.toBuffer().length,
|
|
302
|
+
outputSize: rootParityOutput.toBuffer().length,
|
|
303
|
+
} satisfies CircuitSimulationStats);
|
|
304
|
+
|
|
305
|
+
return this.rootRollupCircuit(mergeOutputLeft, mergeOutputRight, rootParityOutput, newL1ToL2MessagesTuple);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
protected async baseParityCircuit(inputs: BaseParityInputs): Promise<RootParityInput> {
|
|
309
|
+
this.debug(`Running base parity circuit`);
|
|
310
|
+
const parityPublicInputs = await this.simulator.baseParityCircuit(inputs);
|
|
311
|
+
const proof = await this.prover.getBaseParityProof(inputs, parityPublicInputs);
|
|
312
|
+
return new RootParityInput(proof, parityPublicInputs);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
protected async rootParityCircuit(inputs: RootParityInputs): Promise<RootParityInput> {
|
|
316
|
+
this.debug(`Running root parity circuit`);
|
|
317
|
+
const parityPublicInputs = await this.simulator.rootParityCircuit(inputs);
|
|
318
|
+
const proof = await this.prover.getRootParityProof(inputs, parityPublicInputs);
|
|
319
|
+
return new RootParityInput(proof, parityPublicInputs);
|
|
225
320
|
}
|
|
226
321
|
|
|
227
322
|
protected async baseRollupCircuit(
|
|
@@ -269,10 +364,11 @@ export class SoloBlockBuilder implements BlockBuilder {
|
|
|
269
364
|
protected async rootRollupCircuit(
|
|
270
365
|
left: [BaseOrMergeRollupPublicInputs, Proof],
|
|
271
366
|
right: [BaseOrMergeRollupPublicInputs, Proof],
|
|
367
|
+
l1ToL2Roots: RootParityInput,
|
|
272
368
|
newL1ToL2Messages: Tuple<Fr, typeof NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP>,
|
|
273
369
|
): Promise<[RootRollupPublicInputs, Proof]> {
|
|
274
370
|
this.debug(`Running root rollup circuit`);
|
|
275
|
-
const rootInput = await this.getRootRollupInput(...left, ...right, newL1ToL2Messages);
|
|
371
|
+
const rootInput = await this.getRootRollupInput(...left, ...right, l1ToL2Roots, newL1ToL2Messages);
|
|
276
372
|
|
|
277
373
|
// Update the local trees to include the new l1 to l2 messages
|
|
278
374
|
await this.db.appendLeaves(
|
|
@@ -365,6 +461,7 @@ export class SoloBlockBuilder implements BlockBuilder {
|
|
|
365
461
|
rollupProofLeft: Proof,
|
|
366
462
|
rollupOutputRight: BaseOrMergeRollupPublicInputs,
|
|
367
463
|
rollupProofRight: Proof,
|
|
464
|
+
l1ToL2Roots: RootParityInput,
|
|
368
465
|
newL1ToL2Messages: Tuple<Fr, typeof NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP>,
|
|
369
466
|
) {
|
|
370
467
|
const vk = this.getVerificationKey(rollupOutputLeft.rollupType);
|
|
@@ -406,6 +503,7 @@ export class SoloBlockBuilder implements BlockBuilder {
|
|
|
406
503
|
|
|
407
504
|
return RootRollupInputs.from({
|
|
408
505
|
previousRollupData,
|
|
506
|
+
l1ToL2Roots,
|
|
409
507
|
newL1ToL2Messages,
|
|
410
508
|
newL1ToL2MessageTreeRootSiblingPath,
|
|
411
509
|
startL1ToL2MessageTreeSnapshot,
|
package/src/prover/empty.ts
CHANGED
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
import {
|
|
3
3
|
AggregationObject,
|
|
4
4
|
BaseOrMergeRollupPublicInputs,
|
|
5
|
+
BaseParityInputs,
|
|
5
6
|
BaseRollupInputs,
|
|
6
7
|
MergeRollupInputs,
|
|
8
|
+
ParityPublicInputs,
|
|
7
9
|
Proof,
|
|
8
10
|
PublicCircuitPublicInputs,
|
|
9
11
|
PublicKernelCircuitPublicInputs,
|
|
12
|
+
RootParityInputs,
|
|
10
13
|
RootRollupInputs,
|
|
11
14
|
RootRollupPublicInputs,
|
|
12
15
|
} from '@aztec/circuits.js';
|
|
@@ -22,6 +25,26 @@ const EMPTY_PROOF_SIZE = 42;
|
|
|
22
25
|
* Prover implementation that returns empty proofs and overrides aggregation objects.
|
|
23
26
|
*/
|
|
24
27
|
export class EmptyRollupProver implements RollupProver {
|
|
28
|
+
/**
|
|
29
|
+
* Creates an empty proof for the given input.
|
|
30
|
+
* @param inputs - Inputs to the circuit.
|
|
31
|
+
* @param publicInputs - Public inputs of the circuit obtained via simulation, modified by this call.
|
|
32
|
+
*/
|
|
33
|
+
async getBaseParityProof(inputs: BaseParityInputs, publicInputs: ParityPublicInputs): Promise<Proof> {
|
|
34
|
+
publicInputs.aggregationObject = AggregationObject.makeFake();
|
|
35
|
+
return new Proof(Buffer.alloc(EMPTY_PROOF_SIZE, 0));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Creates an empty proof for the given input.
|
|
40
|
+
* @param inputs - Inputs to the circuit.
|
|
41
|
+
* @param publicInputs - Public inputs of the circuit obtained via simulation, modified by this call.
|
|
42
|
+
*/
|
|
43
|
+
async getRootParityProof(inputs: RootParityInputs, publicInputs: ParityPublicInputs): Promise<Proof> {
|
|
44
|
+
publicInputs.aggregationObject = AggregationObject.makeFake();
|
|
45
|
+
return new Proof(Buffer.alloc(EMPTY_PROOF_SIZE, 0));
|
|
46
|
+
}
|
|
47
|
+
|
|
25
48
|
/**
|
|
26
49
|
* Creates an empty proof for the given input.
|
|
27
50
|
* @param _input - Input to the circuit.
|
package/src/prover/index.ts
CHANGED
|
@@ -1,18 +1,35 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BaseOrMergeRollupPublicInputs,
|
|
3
|
+
BaseParityInputs,
|
|
3
4
|
BaseRollupInputs,
|
|
4
5
|
MergeRollupInputs,
|
|
6
|
+
ParityPublicInputs,
|
|
5
7
|
Proof,
|
|
6
8
|
PublicCircuitPublicInputs,
|
|
7
9
|
PublicKernelCircuitPublicInputs,
|
|
10
|
+
RootParityInputs,
|
|
8
11
|
RootRollupInputs,
|
|
9
12
|
RootRollupPublicInputs,
|
|
10
13
|
} from '@aztec/circuits.js';
|
|
11
14
|
|
|
12
15
|
/**
|
|
13
|
-
* Generates proofs for
|
|
16
|
+
* Generates proofs for parity and rollup circuits.
|
|
14
17
|
*/
|
|
15
18
|
export interface RollupProver {
|
|
19
|
+
/**
|
|
20
|
+
* Creates a proof for the given input.
|
|
21
|
+
* @param input - Input to the circuit.
|
|
22
|
+
* @param publicInputs - Public inputs of the circuit obtained via simulation, modified by this call.
|
|
23
|
+
*/
|
|
24
|
+
getBaseParityProof(inputs: BaseParityInputs, publicInputs: ParityPublicInputs): Promise<Proof>;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Creates a proof for the given input.
|
|
28
|
+
* @param input - Input to the circuit.
|
|
29
|
+
* @param publicInputs - Public inputs of the circuit obtained via simulation, modified by this call.
|
|
30
|
+
*/
|
|
31
|
+
getRootParityProof(inputs: RootParityInputs, publicInputs: ParityPublicInputs): Promise<Proof>;
|
|
32
|
+
|
|
16
33
|
/**
|
|
17
34
|
* Creates a proof for the given input.
|
|
18
35
|
* @param input - Input to the circuit.
|
|
@@ -59,7 +59,7 @@ import { getVerificationKeys } from '../mocks/verification_keys.js';
|
|
|
59
59
|
import { PublicProver } from '../prover/index.js';
|
|
60
60
|
import { PublicKernelCircuitSimulator } from '../simulator/index.js';
|
|
61
61
|
import { HintsBuilder } from './hints_builder.js';
|
|
62
|
-
import {
|
|
62
|
+
import { lastSideEffectCounter } from './utils.js';
|
|
63
63
|
|
|
64
64
|
export enum PublicKernelPhase {
|
|
65
65
|
SETUP = 'setup',
|
|
@@ -114,7 +114,6 @@ export abstract class AbstractPhaseManager {
|
|
|
114
114
|
*/
|
|
115
115
|
revertReason: SimulationError | undefined;
|
|
116
116
|
}>;
|
|
117
|
-
abstract rollback(tx: Tx, err: unknown): Promise<FailedTx>;
|
|
118
117
|
|
|
119
118
|
public static extractEnqueuedPublicCallsByPhase(
|
|
120
119
|
publicInputs: PrivateKernelTailCircuitPublicInputs,
|
|
@@ -154,6 +153,14 @@ export abstract class AbstractPhaseManager {
|
|
|
154
153
|
[PublicKernelPhase.TEARDOWN]: [],
|
|
155
154
|
[PublicKernelPhase.TAIL]: [],
|
|
156
155
|
};
|
|
156
|
+
} else if (firstRevertibleCallIndex === -1) {
|
|
157
|
+
// there's no app logic, split the functions between setup (many) and teardown (just one function call)
|
|
158
|
+
return {
|
|
159
|
+
[PublicKernelPhase.SETUP]: publicCallsStack.slice(0, -1),
|
|
160
|
+
[PublicKernelPhase.APP_LOGIC]: [],
|
|
161
|
+
[PublicKernelPhase.TEARDOWN]: [publicCallsStack[publicCallsStack.length - 1]],
|
|
162
|
+
[PublicKernelPhase.TAIL]: [],
|
|
163
|
+
};
|
|
157
164
|
} else {
|
|
158
165
|
return {
|
|
159
166
|
[PublicKernelPhase.SETUP]: publicCallsStack.slice(0, firstRevertibleCallIndex - 1),
|
|
@@ -202,16 +209,27 @@ export abstract class AbstractPhaseManager {
|
|
|
202
209
|
const current = executionStack.pop()!;
|
|
203
210
|
const isExecutionRequest = !isPublicExecutionResult(current);
|
|
204
211
|
|
|
212
|
+
const sideEffectCounter = lastSideEffectCounter(tx) + 1;
|
|
205
213
|
// NOTE: temporary glue to incorporate avm execution calls
|
|
206
214
|
const simulator = (execution: PublicExecution, globalVariables: GlobalVariables) =>
|
|
207
215
|
env.AVM_ENABLED
|
|
208
|
-
? this.publicExecutor.simulateAvm(execution, globalVariables)
|
|
209
|
-
: this.publicExecutor.simulate(execution, globalVariables);
|
|
216
|
+
? this.publicExecutor.simulateAvm(execution, globalVariables, sideEffectCounter)
|
|
217
|
+
: this.publicExecutor.simulate(execution, globalVariables, sideEffectCounter);
|
|
210
218
|
|
|
211
219
|
const result = isExecutionRequest ? await simulator(current, this.globalVariables) : current;
|
|
212
220
|
|
|
213
|
-
newUnencryptedFunctionLogs.push(result.unencryptedLogs);
|
|
214
221
|
const functionSelector = result.execution.functionData.selector.toString();
|
|
222
|
+
if (result.reverted && !PhaseIsRevertible[this.phase]) {
|
|
223
|
+
this.log.debug(
|
|
224
|
+
`Simulation error on ${result.execution.contractAddress.toString()}:${functionSelector} with reason: ${
|
|
225
|
+
result.revertReason
|
|
226
|
+
}`,
|
|
227
|
+
);
|
|
228
|
+
throw result.revertReason;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
newUnencryptedFunctionLogs.push(result.unencryptedLogs);
|
|
232
|
+
|
|
215
233
|
this.log.debug(
|
|
216
234
|
`Running public kernel circuit for ${result.execution.contractAddress.toString()}:${functionSelector}`,
|
|
217
235
|
);
|
|
@@ -220,14 +238,23 @@ export abstract class AbstractPhaseManager {
|
|
|
220
238
|
|
|
221
239
|
[kernelOutput, kernelProof] = await this.runKernelCircuit(kernelOutput, kernelProof, callData);
|
|
222
240
|
|
|
223
|
-
|
|
241
|
+
// sanity check. Note we can't expect them to just be equal, because e.g.
|
|
242
|
+
// if the simulator reverts in app logic, it "resets" and result.reverted will be false when we run teardown,
|
|
243
|
+
// but the kernel carries the reverted flag forward. But if the simulator reverts, so should the kernel.
|
|
244
|
+
if (result.reverted && !kernelOutput.reverted) {
|
|
245
|
+
throw new Error(
|
|
246
|
+
`Public kernel circuit did not revert on ${result.execution.contractAddress.toString()}:${functionSelector}, but simulator did.`,
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// We know the phase is revertible due to the above check.
|
|
251
|
+
// So safely return the revert reason and the kernel output (which has had its revertible side effects dropped)
|
|
252
|
+
if (result.reverted) {
|
|
224
253
|
this.log.debug(
|
|
225
254
|
`Reverting on ${result.execution.contractAddress.toString()}:${functionSelector} with reason: ${
|
|
226
255
|
result.revertReason
|
|
227
256
|
}`,
|
|
228
257
|
);
|
|
229
|
-
// halt immediately if the public kernel circuit has reverted.
|
|
230
|
-
// return no logs, as they should not go on-chain.
|
|
231
258
|
return [kernelOutput, kernelProof, [], result.revertReason];
|
|
232
259
|
}
|
|
233
260
|
|
|
@@ -333,6 +360,8 @@ export abstract class AbstractPhaseManager {
|
|
|
333
360
|
newNoteHashes: padArrayEnd(result.newNoteHashes, SideEffect.empty(), MAX_NEW_NOTE_HASHES_PER_CALL),
|
|
334
361
|
newNullifiers: padArrayEnd(result.newNullifiers, SideEffectLinkedToNoteHash.empty(), MAX_NEW_NULLIFIERS_PER_CALL),
|
|
335
362
|
newL2ToL1Msgs: padArrayEnd(result.newL2ToL1Messages, L2ToL1Message.empty(), MAX_NEW_L2_TO_L1_MSGS_PER_CALL),
|
|
363
|
+
startSideEffectCounter: result.startSideEffectCounter,
|
|
364
|
+
endSideEffectCounter: result.endSideEffectCounter,
|
|
336
365
|
returnValues: padArrayEnd(result.returnValues, Fr.ZERO, RETURN_VALUES_LENGTH),
|
|
337
366
|
nullifierReadRequests: padArrayEnd(
|
|
338
367
|
result.nullifierReadRequests,
|
|
@@ -7,7 +7,6 @@ import { PublicProver } from '../prover/index.js';
|
|
|
7
7
|
import { PublicKernelCircuitSimulator } from '../simulator/index.js';
|
|
8
8
|
import { ContractsDataSourcePublicDB } from '../simulator/public_executor.js';
|
|
9
9
|
import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js';
|
|
10
|
-
import { FailedTx } from './processed_tx.js';
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
12
|
* The phase manager responsible for performing the fee preparation phase.
|
|
@@ -39,27 +38,22 @@ export class AppLogicPhaseManager extends AbstractPhaseManager {
|
|
|
39
38
|
this.log(`Processing tx ${tx.getTxHash()}`);
|
|
40
39
|
await this.publicContractsDB.addNewContracts(tx);
|
|
41
40
|
const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs, revertReason] =
|
|
42
|
-
await this.processEnqueuedPublicCalls(tx, previousPublicKernelOutput, previousPublicKernelProof)
|
|
41
|
+
await this.processEnqueuedPublicCalls(tx, previousPublicKernelOutput, previousPublicKernelProof).catch(
|
|
42
|
+
// if we throw for any reason other than simulation, we need to rollback and drop the TX
|
|
43
|
+
async err => {
|
|
44
|
+
await this.publicStateDB.rollbackToCommit();
|
|
45
|
+
throw err;
|
|
46
|
+
},
|
|
47
|
+
);
|
|
43
48
|
|
|
44
49
|
if (revertReason) {
|
|
45
|
-
await this.
|
|
50
|
+
await this.publicContractsDB.removeNewContracts(tx);
|
|
51
|
+
await this.publicStateDB.rollbackToCheckpoint();
|
|
46
52
|
} else {
|
|
47
53
|
tx.unencryptedLogs.addFunctionLogs(newUnencryptedFunctionLogs);
|
|
48
|
-
await this.publicStateDB.
|
|
54
|
+
await this.publicStateDB.checkpoint();
|
|
49
55
|
}
|
|
50
56
|
|
|
51
57
|
return { publicKernelOutput, publicKernelProof, revertReason };
|
|
52
58
|
}
|
|
53
|
-
|
|
54
|
-
async rollback(tx: Tx, err: unknown): Promise<FailedTx> {
|
|
55
|
-
this.log.warn(`Rolling back changes from ${tx.getTxHash()}`);
|
|
56
|
-
// remove contracts on failure
|
|
57
|
-
await this.publicContractsDB.removeNewContracts(tx);
|
|
58
|
-
// rollback any state updates from this failed transaction
|
|
59
|
-
await this.publicStateDB.rollback();
|
|
60
|
-
return {
|
|
61
|
-
tx,
|
|
62
|
-
error: err instanceof Error ? err : new Error('Unknown error'),
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
59
|
}
|
|
@@ -202,6 +202,8 @@ export class Sequencer {
|
|
|
202
202
|
|
|
203
203
|
await assertBlockHeight();
|
|
204
204
|
|
|
205
|
+
const newModelL1ToL2Messages = await this.l1ToL2MessageSource.getNewL1ToL2Messages(BigInt(newBlockNumber));
|
|
206
|
+
|
|
205
207
|
// Get l1 to l2 messages from the contract
|
|
206
208
|
this.log('Requesting L1 to L2 messages from contract');
|
|
207
209
|
const l1ToL2Messages = await this.getPendingL1ToL2EntryKeys();
|
|
@@ -214,7 +216,7 @@ export class Sequencer {
|
|
|
214
216
|
|
|
215
217
|
const emptyTx = processor.makeEmptyProcessedTx();
|
|
216
218
|
const [rollupCircuitsDuration, block] = await elapsed(() =>
|
|
217
|
-
this.buildBlock(processedValidTxs, l1ToL2Messages, emptyTx, newGlobalVariables),
|
|
219
|
+
this.buildBlock(processedValidTxs, newModelL1ToL2Messages, l1ToL2Messages, emptyTx, newGlobalVariables),
|
|
218
220
|
);
|
|
219
221
|
|
|
220
222
|
this.log(`Assembled block ${block.number}`, {
|
|
@@ -312,6 +314,7 @@ export class Sequencer {
|
|
|
312
314
|
/**
|
|
313
315
|
* Pads the set of txs to a power of two and assembles a block by calling the block builder.
|
|
314
316
|
* @param txs - Processed txs to include in the next block.
|
|
317
|
+
* @param newModelL1ToL2Messages - L1 to L2 messages emitted by the new inbox.
|
|
315
318
|
* @param newL1ToL2Messages - L1 to L2 messages to be part of the block.
|
|
316
319
|
* @param emptyTx - Empty tx to repeat at the end of the block to pad to a power of two.
|
|
317
320
|
* @param globalVariables - Global variables to use in the block.
|
|
@@ -319,7 +322,8 @@ export class Sequencer {
|
|
|
319
322
|
*/
|
|
320
323
|
protected async buildBlock(
|
|
321
324
|
txs: ProcessedTx[],
|
|
322
|
-
|
|
325
|
+
newModelL1ToL2Messages: Fr[], // TODO(#4492): Rename this when purging the old inbox
|
|
326
|
+
newL1ToL2Messages: Fr[], // TODO(#4492): Nuke this when purging the old inbox
|
|
323
327
|
emptyTx: ProcessedTx,
|
|
324
328
|
globalVariables: GlobalVariables,
|
|
325
329
|
) {
|
|
@@ -330,7 +334,12 @@ export class Sequencer {
|
|
|
330
334
|
const allTxs = [...txs, ...times(emptyTxCount, () => emptyTx)];
|
|
331
335
|
this.log(`Building block ${globalVariables.blockNumber}`);
|
|
332
336
|
|
|
333
|
-
const [block] = await this.blockBuilder.buildL2Block(
|
|
337
|
+
const [block] = await this.blockBuilder.buildL2Block(
|
|
338
|
+
globalVariables,
|
|
339
|
+
allTxs,
|
|
340
|
+
newModelL1ToL2Messages,
|
|
341
|
+
newL1ToL2Messages,
|
|
342
|
+
);
|
|
334
343
|
return block;
|
|
335
344
|
}
|
|
336
345
|
|
|
@@ -7,7 +7,6 @@ import { PublicProver } from '../prover/index.js';
|
|
|
7
7
|
import { PublicKernelCircuitSimulator } from '../simulator/index.js';
|
|
8
8
|
import { ContractsDataSourcePublicDB } from '../simulator/public_executor.js';
|
|
9
9
|
import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js';
|
|
10
|
-
import { FailedTx } from './processed_tx.js';
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
12
|
* The phase manager responsible for performing the fee preparation phase.
|
|
@@ -34,21 +33,15 @@ export class SetupPhaseManager extends AbstractPhaseManager {
|
|
|
34
33
|
) {
|
|
35
34
|
this.log(`Processing tx ${tx.getTxHash()}`);
|
|
36
35
|
const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs, revertReason] =
|
|
37
|
-
await this.processEnqueuedPublicCalls(tx, previousPublicKernelOutput, previousPublicKernelProof)
|
|
36
|
+
await this.processEnqueuedPublicCalls(tx, previousPublicKernelOutput, previousPublicKernelProof).catch(
|
|
37
|
+
// the abstract phase manager throws if simulation gives error in a non-revertible phase
|
|
38
|
+
async err => {
|
|
39
|
+
await this.publicStateDB.rollbackToCommit();
|
|
40
|
+
throw err;
|
|
41
|
+
},
|
|
42
|
+
);
|
|
38
43
|
tx.unencryptedLogs.addFunctionLogs(newUnencryptedFunctionLogs);
|
|
39
|
-
|
|
40
|
-
// commit the state updates from this transaction
|
|
41
|
-
await this.publicStateDB.commit();
|
|
42
|
-
|
|
44
|
+
await this.publicStateDB.checkpoint();
|
|
43
45
|
return { publicKernelOutput, publicKernelProof, revertReason };
|
|
44
46
|
}
|
|
45
|
-
|
|
46
|
-
async rollback(tx: Tx, err: unknown): Promise<FailedTx> {
|
|
47
|
-
this.log.warn(`Error processing tx ${tx.getTxHash()}: ${err}`);
|
|
48
|
-
await this.publicStateDB.rollback();
|
|
49
|
-
return {
|
|
50
|
-
tx,
|
|
51
|
-
error: err instanceof Error ? err : new Error('Unknown error'),
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
47
|
}
|
|
@@ -7,7 +7,6 @@ import { PublicProver } from '../prover/index.js';
|
|
|
7
7
|
import { PublicKernelCircuitSimulator } from '../simulator/index.js';
|
|
8
8
|
import { ContractsDataSourcePublicDB } from '../simulator/public_executor.js';
|
|
9
9
|
import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js';
|
|
10
|
-
import { FailedTx } from './processed_tx.js';
|
|
11
10
|
|
|
12
11
|
export class TailPhaseManager extends AbstractPhaseManager {
|
|
13
12
|
constructor(
|
|
@@ -26,10 +25,15 @@ export class TailPhaseManager extends AbstractPhaseManager {
|
|
|
26
25
|
|
|
27
26
|
async handle(tx: Tx, previousPublicKernelOutput: PublicKernelCircuitPublicInputs, previousPublicKernelProof: Proof) {
|
|
28
27
|
this.log(`Processing tx ${tx.getTxHash()}`);
|
|
29
|
-
this.log(`Executing tail circuit for tx ${tx.getTxHash()}`);
|
|
30
28
|
const [publicKernelOutput, publicKernelProof] = await this.runKernelCircuit(
|
|
31
29
|
previousPublicKernelOutput,
|
|
32
30
|
previousPublicKernelProof,
|
|
31
|
+
).catch(
|
|
32
|
+
// the abstract phase manager throws if simulation gives error in non-revertible phase
|
|
33
|
+
async err => {
|
|
34
|
+
await this.publicStateDB.rollbackToCommit();
|
|
35
|
+
throw err;
|
|
36
|
+
},
|
|
33
37
|
);
|
|
34
38
|
|
|
35
39
|
// commit the state updates from this transaction
|
|
@@ -37,13 +41,4 @@ export class TailPhaseManager extends AbstractPhaseManager {
|
|
|
37
41
|
|
|
38
42
|
return { publicKernelOutput, publicKernelProof, revertReason: undefined };
|
|
39
43
|
}
|
|
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
44
|
}
|