@aztec/prover-client 0.47.1 → 0.48.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 (54) hide show
  1. package/dest/config.d.ts +2 -0
  2. package/dest/config.d.ts.map +1 -1
  3. package/dest/config.js +28 -30
  4. package/dest/mocks/fixtures.d.ts.map +1 -1
  5. package/dest/mocks/fixtures.js +11 -7
  6. package/dest/mocks/test_context.d.ts +1 -1
  7. package/dest/mocks/test_context.d.ts.map +1 -1
  8. package/dest/mocks/test_context.js +5 -23
  9. package/dest/orchestrator/block-building-helpers.d.ts +3 -3
  10. package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
  11. package/dest/orchestrator/block-building-helpers.js +6 -5
  12. package/dest/orchestrator/orchestrator.d.ts +11 -6
  13. package/dest/orchestrator/orchestrator.d.ts.map +1 -1
  14. package/dest/orchestrator/orchestrator.js +115 -89
  15. package/dest/orchestrator/orchestrator_metrics.d.ts +8 -0
  16. package/dest/orchestrator/orchestrator_metrics.d.ts.map +1 -0
  17. package/dest/orchestrator/orchestrator_metrics.js +19 -0
  18. package/dest/orchestrator/proving-state.d.ts +2 -0
  19. package/dest/orchestrator/proving-state.d.ts.map +1 -1
  20. package/dest/orchestrator/proving-state.js +5 -1
  21. package/dest/orchestrator/tx-proving-state.d.ts +3 -2
  22. package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
  23. package/dest/orchestrator/tx-proving-state.js +26 -8
  24. package/dest/prover-agent/memory-proving-queue.d.ts +15 -13
  25. package/dest/prover-agent/memory-proving-queue.d.ts.map +1 -1
  26. package/dest/prover-agent/memory-proving-queue.js +37 -55
  27. package/dest/prover-agent/prover-agent.d.ts.map +1 -1
  28. package/dest/prover-agent/prover-agent.js +24 -7
  29. package/dest/prover-agent/queue_metrics.d.ts +10 -0
  30. package/dest/prover-agent/queue_metrics.d.ts.map +1 -0
  31. package/dest/prover-agent/queue_metrics.js +23 -0
  32. package/dest/prover-agent/rpc.d.ts.map +1 -1
  33. package/dest/prover-agent/rpc.js +4 -2
  34. package/dest/tx-prover/factory.d.ts +1 -3
  35. package/dest/tx-prover/factory.d.ts.map +1 -1
  36. package/dest/tx-prover/factory.js +3 -3
  37. package/dest/tx-prover/tx-prover.d.ts +8 -33
  38. package/dest/tx-prover/tx-prover.d.ts.map +1 -1
  39. package/dest/tx-prover/tx-prover.js +18 -46
  40. package/package.json +10 -10
  41. package/src/config.ts +28 -47
  42. package/src/mocks/fixtures.ts +14 -4
  43. package/src/mocks/test_context.ts +5 -25
  44. package/src/orchestrator/block-building-helpers.ts +6 -5
  45. package/src/orchestrator/orchestrator.ts +197 -103
  46. package/src/orchestrator/orchestrator_metrics.ts +32 -0
  47. package/src/orchestrator/proving-state.ts +5 -0
  48. package/src/orchestrator/tx-proving-state.ts +33 -7
  49. package/src/prover-agent/memory-proving-queue.ts +54 -70
  50. package/src/prover-agent/prover-agent.ts +35 -6
  51. package/src/prover-agent/queue_metrics.ts +29 -0
  52. package/src/prover-agent/rpc.ts +3 -0
  53. package/src/tx-prover/factory.ts +2 -9
  54. package/src/tx-prover/tx-prover.ts +21 -64
@@ -1,5 +1,7 @@
1
1
  import {
2
2
  Body,
3
+ EncryptedNoteTxL2Logs,
4
+ EncryptedTxL2Logs,
3
5
  L2Block,
4
6
  MerkleTreeId,
5
7
  type PaddingProcessedTx,
@@ -15,6 +17,7 @@ import {
15
17
  } from '@aztec/circuit-types';
16
18
  import {
17
19
  BlockProofError,
20
+ type BlockProver,
18
21
  type BlockResult,
19
22
  PROVING_STATUS,
20
23
  type ProvingResult,
@@ -34,19 +37,22 @@ import {
34
37
  type KernelCircuitPublicInputs,
35
38
  L1_TO_L2_MSG_SUBTREE_HEIGHT,
36
39
  L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH,
37
- type NESTED_RECURSIVE_PROOF_LENGTH,
40
+ NESTED_RECURSIVE_PROOF_LENGTH,
38
41
  NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
39
42
  NUM_BASE_PARITY_PER_ROOT_PARITY,
43
+ PrivateKernelEmptyInputData,
40
44
  type Proof,
41
45
  type PublicKernelCircuitPublicInputs,
42
46
  type RECURSIVE_PROOF_LENGTH,
43
47
  type RecursiveProof,
44
48
  type RootParityInput,
45
49
  RootParityInputs,
50
+ type TUBE_PROOF_LENGTH,
46
51
  TubeInputs,
47
52
  type VerificationKeyAsFields,
48
53
  VerificationKeyData,
49
54
  makeEmptyProof,
55
+ makeEmptyRecursiveProof,
50
56
  } from '@aztec/circuits.js';
51
57
  import { makeTuple } from '@aztec/foundation/array';
52
58
  import { padArrayEnd } from '@aztec/foundation/collection';
@@ -55,7 +61,8 @@ import { createDebugLogger } from '@aztec/foundation/log';
55
61
  import { promiseWithResolvers } from '@aztec/foundation/promise';
56
62
  import { BufferReader, type Tuple } from '@aztec/foundation/serialize';
57
63
  import { pushTestData } from '@aztec/foundation/testing';
58
- import { ProtocolCircuitVks, getVKIndex, getVKSiblingPath, getVKTreeRoot } from '@aztec/noir-protocol-circuits-types';
64
+ import { elapsed } from '@aztec/foundation/timer';
65
+ import { getVKIndex, getVKSiblingPath, getVKTreeRoot } from '@aztec/noir-protocol-circuits-types';
59
66
  import { Attributes, type TelemetryClient, type Tracer, trackSpan, wrapCallbackInSpan } from '@aztec/telemetry-client';
60
67
  import { type MerkleTreeOperations } from '@aztec/world-state';
61
68
 
@@ -71,8 +78,9 @@ import {
71
78
  validateRootOutput,
72
79
  validateTx,
73
80
  } from './block-building-helpers.js';
81
+ import { ProvingOrchestratorMetrics } from './orchestrator_metrics.js';
74
82
  import { type MergeRollupInputData, ProvingState, type TreeSnapshots } from './proving-state.js';
75
- import { TX_PROVING_CODE, TxProvingState } from './tx-proving-state.js';
83
+ import { TX_PROVING_CODE, type TxProvingInstruction, TxProvingState } from './tx-proving-state.js';
76
84
 
77
85
  const logger = createDebugLogger('aztec:prover:proving-orchestrator');
78
86
 
@@ -90,15 +98,28 @@ const logger = createDebugLogger('aztec:prover:proving-orchestrator');
90
98
  /**
91
99
  * The orchestrator, managing the flow of recursive proving operations required to build the rollup proof tree.
92
100
  */
93
- export class ProvingOrchestrator {
101
+ export class ProvingOrchestrator implements BlockProver {
94
102
  private provingState: ProvingState | undefined = undefined;
95
103
  private pendingProvingJobs: AbortController[] = [];
96
104
  private paddingTx: PaddingProcessedTx | undefined = undefined;
97
105
 
98
- public readonly tracer: Tracer;
106
+ private metrics: ProvingOrchestratorMetrics;
99
107
 
100
- constructor(private db: MerkleTreeOperations, private prover: ServerCircuitProver, telemetryClient: TelemetryClient) {
101
- this.tracer = telemetryClient.getTracer('ProvingOrchestrator');
108
+ constructor(
109
+ private db: MerkleTreeOperations,
110
+ private prover: ServerCircuitProver,
111
+ telemetryClient: TelemetryClient,
112
+ private readonly proverId: Fr = Fr.ZERO,
113
+ ) {
114
+ this.metrics = new ProvingOrchestratorMetrics(telemetryClient, 'ProvingOrchestrator');
115
+ }
116
+
117
+ get tracer(): Tracer {
118
+ return this.metrics.tracer;
119
+ }
120
+
121
+ public getProverId(): Fr {
122
+ return this.proverId;
102
123
  }
103
124
 
104
125
  /**
@@ -128,9 +149,22 @@ export class ProvingOrchestrator {
128
149
  if (!Number.isInteger(numTxs) || numTxs < 2) {
129
150
  throw new Error(`Length of txs for the block should be at least two (got ${numTxs})`);
130
151
  }
152
+
153
+ // TODO(palla/prover-node): Store block number in the db itself to make this check more reliable,
154
+ // and turn this warning into an exception that we throw.
155
+ const { blockNumber } = globalVariables;
156
+ const dbBlockNumber = (await this.db.getTreeInfo(MerkleTreeId.ARCHIVE)).size - 1n;
157
+ if (dbBlockNumber !== blockNumber.toBigInt() - 1n) {
158
+ logger.warn(
159
+ `Database is at wrong block number (starting block ${blockNumber.toBigInt()} with db at ${dbBlockNumber})`,
160
+ );
161
+ }
162
+
131
163
  // Cancel any currently proving block before starting a new one
132
164
  this.cancelBlock();
133
- logger.info(`Starting new block with ${numTxs} transactions`);
165
+ logger.info(
166
+ `Starting block ${globalVariables.blockNumber} for slot ${globalVariables.slotNumber} with ${numTxs} transactions`,
167
+ );
134
168
  // we start the block by enqueueing all of the base parity circuits
135
169
  let baseParityInputs: BaseParityInputs[] = [];
136
170
  let l1ToL2MessagesPadded: Tuple<Fr, typeof NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP>;
@@ -218,7 +252,7 @@ export class ProvingOrchestrator {
218
252
  }
219
253
 
220
254
  const [inputs, treeSnapshots] = await this.prepareTransaction(tx, this.provingState);
221
- this.enqueueFirstProof(inputs, treeSnapshots, tx, this.provingState);
255
+ this.enqueueFirstProofs(inputs, treeSnapshots, tx, this.provingState);
222
256
  }
223
257
 
224
258
  /**
@@ -301,16 +335,17 @@ export class ProvingOrchestrator {
301
335
  },
302
336
  signal =>
303
337
  this.prover.getEmptyPrivateKernelProof(
304
- {
338
+ new PrivateKernelEmptyInputData(
339
+ unprovenPaddingTx.data.constants.historicalHeader,
305
340
  // Chain id and version should not change even if the proving state does, so it's safe to use them for the padding tx
306
341
  // which gets cached across multiple runs of the orchestrator with different proving states. If they were to change,
307
342
  // we'd have to clear out the paddingTx here and regenerate it when they do.
308
- chainId: unprovenPaddingTx.data.constants.txContext.chainId,
309
- version: unprovenPaddingTx.data.constants.txContext.version,
310
- header: unprovenPaddingTx.data.constants.historicalHeader,
311
- vkTreeRoot: getVKTreeRoot(),
312
- },
343
+ unprovenPaddingTx.data.constants.txContext.chainId,
344
+ unprovenPaddingTx.data.constants.txContext.version,
345
+ getVKTreeRoot(),
346
+ ),
313
347
  signal,
348
+ provingState.epochNumber,
314
349
  ),
315
350
  ),
316
351
  result => {
@@ -333,14 +368,16 @@ export class ProvingOrchestrator {
333
368
  provingState: ProvingState,
334
369
  ) {
335
370
  // The padding tx contains the proof and vk, generated separately from the base inputs
336
- // Copy these into the base rollup inputs
371
+ // Copy these into the base rollup inputs and enqueue the base rollup proof
337
372
  for (let i = 0; i < txInputs.length; i++) {
338
373
  txInputs[i].inputs.kernelData.vk = paddingTx.verificationKey;
339
374
  txInputs[i].inputs.kernelData.proof = paddingTx.recursiveProof;
340
375
 
341
376
  txInputs[i].inputs.kernelData.vkIndex = getVKIndex(paddingTx.verificationKey);
342
377
  txInputs[i].inputs.kernelData.vkPath = getVKSiblingPath(txInputs[i].inputs.kernelData.vkIndex);
343
- this.enqueueFirstProof(txInputs[i].inputs, txInputs[i].snapshot, paddingTx, provingState);
378
+ const txProvingState = new TxProvingState(paddingTx, txInputs[i].inputs, txInputs[i].snapshot);
379
+ const txIndex = provingState.addNewTx(txProvingState);
380
+ this.enqueueBaseRollup(provingState, BigInt(txIndex), txProvingState);
344
381
  }
345
382
  }
346
383
 
@@ -443,32 +480,22 @@ export class ProvingOrchestrator {
443
480
  const txInputs = await this.prepareBaseRollupInputs(provingState, tx);
444
481
  if (!txInputs) {
445
482
  // This should not be possible
446
- throw new Error(`Unable to add padding transaction, preparing base inputs failed`);
483
+ throw new Error(`Unable to add transaction, preparing base inputs failed`);
447
484
  }
448
485
  return txInputs;
449
486
  }
450
487
 
451
- private enqueueFirstProof(
488
+ private enqueueFirstProofs(
452
489
  inputs: BaseRollupInputs,
453
490
  treeSnapshots: TreeSnapshots,
454
491
  tx: ProcessedTx,
455
492
  provingState: ProvingState,
456
493
  ) {
457
- const txProvingState = new TxProvingState(
458
- tx,
459
- inputs,
460
- treeSnapshots,
461
- ProtocolCircuitVks.PrivateKernelTailToPublicArtifact,
462
- );
494
+ const txProvingState = new TxProvingState(tx, inputs, treeSnapshots);
463
495
  const txIndex = provingState.addNewTx(txProvingState);
496
+ this.enqueueTube(provingState, txIndex);
464
497
  const numPublicKernels = txProvingState.getNumPublicKernels();
465
- if (!numPublicKernels) {
466
- // no public functions, go straight to the base rollup
467
- logger.debug(`Enqueueing base rollup for tx ${txIndex}`);
468
- this.enqueueBaseRollup(provingState, BigInt(txIndex), txProvingState);
469
- return;
470
- }
471
- // Enqueue all of the VM/kernel proving requests
498
+ // Enqueue all of the VM proving requests
472
499
  // Rather than handle the Kernel Tail as a special case here, we will just handle it inside enqueueVM
473
500
  for (let i = 0; i < numPublicKernels; i++) {
474
501
  logger.debug(`Enqueueing public VM ${i} for tx ${txIndex}`);
@@ -551,22 +578,22 @@ export class ProvingOrchestrator {
551
578
  return;
552
579
  }
553
580
 
554
- const getBaseInputsEmptyTx = async () => {
555
- const inputs = {
556
- header: this.db.getInitialHeader(),
557
- chainId: tx.data.constants.globalVariables.chainId,
558
- version: tx.data.constants.globalVariables.version,
559
- vkTreeRoot: tx.data.constants.vkTreeRoot,
560
- };
581
+ // We build the base rollup inputs using a mock proof and verification key.
582
+ // These will be overwritten later once we have proven the tube circuit and any public kernels
583
+ const [ms, inputs] = await elapsed(
584
+ buildBaseRollupInput(
585
+ tx,
586
+ makeEmptyRecursiveProof(NESTED_RECURSIVE_PROOF_LENGTH),
587
+ provingState.globalVariables,
588
+ this.db,
589
+ VerificationKeyData.makeFake(),
590
+ ),
591
+ );
592
+
593
+ if (!tx.isEmpty) {
594
+ this.metrics.recordBaseRollupInputs(ms);
595
+ }
561
596
 
562
- const proof = await this.prover.getEmptyTubeProof(inputs);
563
- return await buildBaseRollupInput(tx, proof.proof, provingState.globalVariables, this.db, proof.verificationKey);
564
- };
565
- const getBaseInputsNonEmptyTx = async () => {
566
- const proof = await this.prover.getTubeProof(new TubeInputs(tx.clientIvcProof));
567
- return await buildBaseRollupInput(tx, proof.tubeProof, provingState.globalVariables, this.db, proof.tubeVK);
568
- };
569
- const inputs = tx.isEmpty ? await getBaseInputsEmptyTx() : await getBaseInputsNonEmptyTx();
570
597
  const promises = [MerkleTreeId.NOTE_HASH_TREE, MerkleTreeId.NULLIFIER_TREE, MerkleTreeId.PUBLIC_DATA_TREE].map(
571
598
  async (id: MerkleTreeId) => {
572
599
  return { key: id, value: await getTreeSnapshot(id, this.db) };
@@ -613,28 +640,30 @@ export class ProvingOrchestrator {
613
640
  logger.debug('Not running base rollup, state invalid');
614
641
  return;
615
642
  }
616
- if (
617
- !tx.baseRollupInputs.kernelData.publicInputs.end.noteEncryptedLogsHash
618
- .toBuffer()
619
- .equals(tx.processedTx.noteEncryptedLogs.hash())
620
- ) {
643
+ const txNoteEncryptedLogs = EncryptedNoteTxL2Logs.hashNoteLogs(
644
+ tx.baseRollupInputs.kernelData.publicInputs.end.noteEncryptedLogsHashes
645
+ .filter(log => !log.isEmpty())
646
+ .map(log => log.value.toBuffer()),
647
+ );
648
+ if (!txNoteEncryptedLogs.equals(tx.processedTx.noteEncryptedLogs.hash())) {
621
649
  provingState.reject(
622
- `Note encrypted logs hash mismatch: ${
623
- tx.baseRollupInputs.kernelData.publicInputs.end.noteEncryptedLogsHash
624
- } === ${Fr.fromBuffer(tx.processedTx.noteEncryptedLogs.hash())}`,
650
+ `Note encrypted logs hash mismatch: ${Fr.fromBuffer(txNoteEncryptedLogs)} === ${Fr.fromBuffer(
651
+ tx.processedTx.noteEncryptedLogs.hash(),
652
+ )}`,
625
653
  );
626
654
  return;
627
655
  }
628
- if (
629
- !tx.baseRollupInputs.kernelData.publicInputs.end.encryptedLogsHash
630
- .toBuffer()
631
- .equals(tx.processedTx.encryptedLogs.hash())
632
- ) {
656
+ const txEncryptedLogs = EncryptedTxL2Logs.hashSiloedLogs(
657
+ tx.baseRollupInputs.kernelData.publicInputs.end.encryptedLogsHashes
658
+ .filter(log => !log.isEmpty())
659
+ .map(log => log.getSiloedHash()),
660
+ );
661
+ if (!txEncryptedLogs.equals(tx.processedTx.encryptedLogs.hash())) {
633
662
  // @todo This rejection messages is never seen. Never making it out to the logs
634
663
  provingState.reject(
635
- `Encrypted logs hash mismatch: ${
636
- tx.baseRollupInputs.kernelData.publicInputs.end.encryptedLogsHash
637
- } === ${Fr.fromBuffer(tx.processedTx.encryptedLogs.hash())}`,
664
+ `Encrypted logs hash mismatch: ${Fr.fromBuffer(txEncryptedLogs)} === ${Fr.fromBuffer(
665
+ tx.processedTx.encryptedLogs.hash(),
666
+ )}`,
638
667
  );
639
668
  return;
640
669
  }
@@ -669,7 +698,7 @@ export class ProvingOrchestrator {
669
698
  [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
670
699
  [Attributes.PROTOCOL_CIRCUIT_NAME]: 'base-rollup' as CircuitName,
671
700
  },
672
- signal => this.prover.getBaseRollupProof(tx.baseRollupInputs, signal),
701
+ signal => this.prover.getBaseRollupProof(tx.baseRollupInputs, signal, provingState.epochNumber),
673
702
  ),
674
703
  result => {
675
704
  logger.debug(`Completed proof for base rollup for tx ${tx.processedTx.hash.toString()}`);
@@ -684,6 +713,49 @@ export class ProvingOrchestrator {
684
713
  );
685
714
  }
686
715
 
716
+ // Enqueues the tub circuit for a given transaction index
717
+ // Once completed, will enqueue the next circuit, either a public kernel or the base rollup
718
+ private enqueueTube(provingState: ProvingState, txIndex: number) {
719
+ if (!provingState?.verifyState()) {
720
+ logger.debug('Not running tube circuit, state invalid');
721
+ return;
722
+ }
723
+
724
+ const txProvingState = provingState.getTxProvingState(txIndex);
725
+ logger.debug(`Enqueuing tube circuit for tx index: ${txIndex}`);
726
+
727
+ this.deferredProving(
728
+ provingState,
729
+ wrapCallbackInSpan(
730
+ this.tracer,
731
+ 'ProvingOrchestrator.prover.getTubeProof',
732
+ {
733
+ [Attributes.TX_HASH]: txProvingState.processedTx.hash.toString(),
734
+ [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
735
+ [Attributes.PROTOCOL_CIRCUIT_NAME]: 'tube-circuit' as CircuitName,
736
+ },
737
+ signal =>
738
+ this.prover.getTubeProof(
739
+ new TubeInputs(txProvingState.processedTx.clientIvcProof),
740
+ signal,
741
+ provingState.epochNumber,
742
+ ),
743
+ ),
744
+ result => {
745
+ logger.debug(`Completed tube proof for tx index: ${txIndex}`);
746
+ const nextKernelRequest = txProvingState.getNextPublicKernelFromTubeProof(result.tubeProof, result.tubeVK);
747
+ this.checkAndEnqueueNextTxCircuit(
748
+ provingState,
749
+ txIndex,
750
+ -1,
751
+ result.tubeProof,
752
+ result.tubeVK,
753
+ nextKernelRequest,
754
+ );
755
+ },
756
+ );
757
+ }
758
+
687
759
  // Executes the merge rollup circuit and stored the output as intermediate state for the parent merge/root circuit
688
760
  // Enqueues the next level of merge if all inputs are available
689
761
  private enqueueMergeRollup(
@@ -706,7 +778,7 @@ export class ProvingOrchestrator {
706
778
  [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
707
779
  [Attributes.PROTOCOL_CIRCUIT_NAME]: 'merge-rollup' as CircuitName,
708
780
  },
709
- signal => this.prover.getMergeRollupProof(inputs, signal),
781
+ signal => this.prover.getMergeRollupProof(inputs, signal, provingState.epochNumber),
710
782
  ),
711
783
  result => {
712
784
  this.storeAndExecuteNextMergeLevel(provingState, level, index, [
@@ -739,6 +811,7 @@ export class ProvingOrchestrator {
739
811
  provingState.messageTreeSnapshot,
740
812
  provingState.messageTreeRootSiblingPath,
741
813
  this.db,
814
+ this.proverId,
742
815
  );
743
816
 
744
817
  this.deferredProving(
@@ -750,7 +823,7 @@ export class ProvingOrchestrator {
750
823
  [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
751
824
  [Attributes.PROTOCOL_CIRCUIT_NAME]: 'root-rollup' as CircuitName,
752
825
  },
753
- signal => this.prover.getRootRollupProof(inputs, signal),
826
+ signal => this.prover.getRootRollupProof(inputs, signal, provingState.epochNumber),
754
827
  ),
755
828
  result => {
756
829
  provingState.rootRollupPublicInputs = result.inputs;
@@ -780,7 +853,7 @@ export class ProvingOrchestrator {
780
853
  [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
781
854
  [Attributes.PROTOCOL_CIRCUIT_NAME]: 'base-parity' as CircuitName,
782
855
  },
783
- signal => this.prover.getBaseParityProof(inputs, signal),
856
+ signal => this.prover.getBaseParityProof(inputs, signal, provingState.epochNumber),
784
857
  ),
785
858
  rootInput => {
786
859
  provingState.setRootParityInputs(rootInput, index);
@@ -799,7 +872,7 @@ export class ProvingOrchestrator {
799
872
 
800
873
  // Runs the root parity circuit ans stored the outputs
801
874
  // Enqueues the root rollup proof if all inputs are available
802
- private enqueueRootParityCircuit(provingState: ProvingState | undefined, inputs: RootParityInputs) {
875
+ private enqueueRootParityCircuit(provingState: ProvingState, inputs: RootParityInputs) {
803
876
  this.deferredProving(
804
877
  provingState,
805
878
  wrapCallbackInSpan(
@@ -809,7 +882,7 @@ export class ProvingOrchestrator {
809
882
  [Attributes.PROTOCOL_CIRCUIT_TYPE]: 'server',
810
883
  [Attributes.PROTOCOL_CIRCUIT_NAME]: 'root-parity' as CircuitName,
811
884
  },
812
- signal => this.prover.getRootParityProof(inputs, signal),
885
+ signal => this.prover.getRootParityProof(inputs, signal, provingState.epochNumber),
813
886
  ),
814
887
  async rootInput => {
815
888
  provingState!.finalRootParityInput = rootInput;
@@ -895,7 +968,7 @@ export class ProvingOrchestrator {
895
968
  publicFunction.vmRequest!.avmHints,
896
969
  );
897
970
  try {
898
- return await this.prover.getAvmProof(inputs, signal);
971
+ return await this.prover.getAvmProof(inputs, signal, provingState.epochNumber);
899
972
  } catch (err) {
900
973
  if (process.env.AVM_PROVING_STRICT) {
901
974
  throw err;
@@ -909,14 +982,14 @@ export class ProvingOrchestrator {
909
982
  );
910
983
  this.deferredProving(provingState, doAvmProving, proofAndVk => {
911
984
  logger.debug(`Proven VM for function index ${functionIndex} of tx index ${txIndex}`);
912
- this.checkAndEnqueuePublicKernel(provingState, txIndex, functionIndex, proofAndVk.proof);
985
+ this.checkAndEnqueuePublicKernelFromVMProof(provingState, txIndex, functionIndex, proofAndVk.proof);
913
986
  });
914
987
  } else {
915
- this.checkAndEnqueuePublicKernel(provingState, txIndex, functionIndex, /*vmProof=*/ makeEmptyProof());
988
+ this.checkAndEnqueuePublicKernelFromVMProof(provingState, txIndex, functionIndex, /*vmProof=*/ makeEmptyProof());
916
989
  }
917
990
  }
918
991
 
919
- private checkAndEnqueuePublicKernel(
992
+ private checkAndEnqueuePublicKernelFromVMProof(
920
993
  provingState: ProvingState,
921
994
  txIndex: number,
922
995
  functionIndex: number,
@@ -934,6 +1007,47 @@ export class ProvingOrchestrator {
934
1007
  }
935
1008
  }
936
1009
 
1010
+ // Takes a proof and verification key, passes it to the proving state before enqueueing the next proof
1011
+ // This could be either a public kernel or the base rollup
1012
+ // Alternatively, if we are still waiting on a public VM prof then it will continue waiting
1013
+ private checkAndEnqueueNextTxCircuit(
1014
+ provingState: ProvingState,
1015
+ txIndex: number,
1016
+ completedFunctionIndex: number,
1017
+ proof: RecursiveProof<typeof NESTED_RECURSIVE_PROOF_LENGTH> | RecursiveProof<typeof TUBE_PROOF_LENGTH>,
1018
+ verificationKey: VerificationKeyData,
1019
+ nextKernelRequest: TxProvingInstruction,
1020
+ ) {
1021
+ const txProvingState = provingState.getTxProvingState(txIndex);
1022
+ // What's the status of the next kernel?
1023
+ if (nextKernelRequest.code === TX_PROVING_CODE.NOT_READY) {
1024
+ // Must be waiting on a VM proof
1025
+ return;
1026
+ }
1027
+
1028
+ if (nextKernelRequest.code === TX_PROVING_CODE.COMPLETED) {
1029
+ // We must have completed all public function proving, we now move to the base rollup
1030
+ logger.debug(`Public functions completed for tx ${txIndex} enqueueing base rollup`);
1031
+ // Take the final proof and assign it to the base rollup inputs
1032
+ txProvingState.baseRollupInputs.kernelData.proof = proof;
1033
+ txProvingState.baseRollupInputs.kernelData.vk = verificationKey;
1034
+ txProvingState.baseRollupInputs.kernelData.vkIndex = getVKIndex(verificationKey);
1035
+ txProvingState.baseRollupInputs.kernelData.vkPath = getVKSiblingPath(
1036
+ txProvingState.baseRollupInputs.kernelData.vkIndex,
1037
+ );
1038
+
1039
+ this.enqueueBaseRollup(provingState, BigInt(txIndex), txProvingState);
1040
+ return;
1041
+ }
1042
+ // There must be another kernel ready to be proven
1043
+ if (nextKernelRequest.function === undefined) {
1044
+ // Should not be possible
1045
+ throw new Error(`Error occurred, public function request undefined after kernel proof completed`);
1046
+ }
1047
+
1048
+ this.enqueuePublicKernel(provingState, txIndex, completedFunctionIndex + 1);
1049
+ }
1050
+
937
1051
  /**
938
1052
  * Executes the kernel circuit for a public function, will enqueue the next kernel circuit if it's VM is already proven
939
1053
  * or the base rollup circuit if there are no more kernels to be proven
@@ -965,46 +1079,26 @@ export class ProvingOrchestrator {
965
1079
  signal,
966
1080
  ): Promise<PublicInputsAndRecursiveProof<KernelCircuitPublicInputs | PublicKernelCircuitPublicInputs>> => {
967
1081
  if (request.type === PublicKernelType.TAIL) {
968
- return this.prover.getPublicTailProof(request, signal);
1082
+ return this.prover.getPublicTailProof(request, signal, provingState.epochNumber);
969
1083
  } else {
970
- return this.prover.getPublicKernelProof(request, signal);
1084
+ return this.prover.getPublicKernelProof(request, signal, provingState.epochNumber);
971
1085
  }
972
1086
  },
973
1087
  ),
974
1088
  result => {
975
1089
  const nextKernelRequest = txProvingState.getNextPublicKernelFromKernelProof(
976
1090
  functionIndex,
977
- // PUBLIC KERNEL: I want to pass a client ivc proof into here?
978
1091
  result.proof,
979
1092
  result.verificationKey,
980
1093
  );
981
- // What's the status of the next kernel?
982
- if (nextKernelRequest.code === TX_PROVING_CODE.NOT_READY) {
983
- // Must be waiting on a VM proof
984
- return;
985
- }
986
-
987
- if (nextKernelRequest.code === TX_PROVING_CODE.COMPLETED) {
988
- // We must have completed all public function proving, we now move to the base rollup
989
- logger.debug(`Public functions completed for tx ${txIndex} enqueueing base rollup`);
990
- // Take the final public tail proof and verification key and pass them to the base rollup
991
- txProvingState.baseRollupInputs.kernelData.proof = result.proof;
992
- txProvingState.baseRollupInputs.kernelData.vk = result.verificationKey;
993
- txProvingState.baseRollupInputs.kernelData.vkIndex = getVKIndex(result.verificationKey);
994
- txProvingState.baseRollupInputs.kernelData.vkPath = getVKSiblingPath(
995
- txProvingState.baseRollupInputs.kernelData.vkIndex,
996
- );
997
-
998
- this.enqueueBaseRollup(provingState, BigInt(txIndex), txProvingState);
999
- return;
1000
- }
1001
- // There must be another kernel ready to be proven
1002
- if (nextKernelRequest.function === undefined) {
1003
- // Should not be possible
1004
- throw new Error(`Error occurred, public function request undefined after kernel proof completed`);
1005
- }
1006
-
1007
- this.enqueuePublicKernel(provingState, txIndex, functionIndex + 1);
1094
+ this.checkAndEnqueueNextTxCircuit(
1095
+ provingState,
1096
+ txIndex,
1097
+ functionIndex,
1098
+ result.proof,
1099
+ result.verificationKey,
1100
+ nextKernelRequest,
1101
+ );
1008
1102
  },
1009
1103
  );
1010
1104
  }
@@ -0,0 +1,32 @@
1
+ import {
2
+ type Histogram,
3
+ Metrics,
4
+ type TelemetryClient,
5
+ type Tracer,
6
+ ValueType,
7
+ millisecondBuckets,
8
+ } from '@aztec/telemetry-client';
9
+
10
+ export class ProvingOrchestratorMetrics {
11
+ public readonly tracer: Tracer;
12
+
13
+ private baseRollupInputsDuration: Histogram;
14
+
15
+ constructor(client: TelemetryClient, name = 'ProvingOrchestrator') {
16
+ this.tracer = client.getTracer(name);
17
+ const meter = client.getMeter(name);
18
+
19
+ this.baseRollupInputsDuration = meter.createHistogram(Metrics.PROVING_ORCHESTRATOR_BASE_ROLLUP_INPUTS_DURATION, {
20
+ unit: 'ms',
21
+ description: 'Duration to build base rollup inputs',
22
+ valueType: ValueType.INT,
23
+ advice: {
24
+ explicitBucketBoundaries: millisecondBuckets(1), // 10ms -> ~327s
25
+ },
26
+ });
27
+ }
28
+
29
+ recordBaseRollupInputs(durationMs: number) {
30
+ this.baseRollupInputsDuration.record(Math.ceil(durationMs));
31
+ }
32
+ }
@@ -143,6 +143,11 @@ export class ProvingState {
143
143
  return this.txs;
144
144
  }
145
145
 
146
+ /** Returns the block number as an epoch number. Used for prioritizing proof requests. */
147
+ public get epochNumber(): number {
148
+ return this.globalVariables.blockNumber.toNumber();
149
+ }
150
+
146
151
  /**
147
152
  * Stores the inputs to a merge circuit and determines if the circuit is ready to be executed
148
153
  * @param mergeInputs - The inputs to store
@@ -11,6 +11,7 @@ import {
11
11
  type BaseRollupInputs,
12
12
  type NESTED_RECURSIVE_PROOF_LENGTH,
13
13
  type Proof,
14
+ type RECURSIVE_PROOF_LENGTH,
14
15
  type RecursiveProof,
15
16
  type VerificationKeyData,
16
17
  } from '@aztec/circuits.js';
@@ -48,23 +49,17 @@ export class TxProvingState {
48
49
  public readonly processedTx: ProcessedTx,
49
50
  public readonly baseRollupInputs: BaseRollupInputs,
50
51
  public readonly treeSnapshots: Map<MerkleTreeId, AppendOnlyTreeSnapshot>,
51
- privateKernelVk: VerificationKeyData,
52
52
  ) {
53
53
  let previousProofType = PublicKernelType.NON_PUBLIC;
54
54
  for (let i = 0; i < processedTx.publicProvingRequests.length; i++) {
55
55
  const provingRequest = processedTx.publicProvingRequests[i];
56
56
  const kernelRequest = provingRequest.type === AVM_REQUEST ? provingRequest.kernelRequest : provingRequest;
57
- // the first circuit has a valid previous proof, it came from private
58
- if (i === 0) {
59
- kernelRequest.inputs.previousKernel.vk = privateKernelVk;
60
- kernelRequest.inputs.previousKernel.clientIvcProof = processedTx.clientIvcProof;
61
- }
62
57
  const vmRequest = provingRequest.type === AVM_REQUEST ? provingRequest : undefined;
63
58
  const publicFunction: PublicFunction = {
64
59
  vmRequest,
65
60
  vmProof: undefined,
66
61
  previousProofType,
67
- previousKernelProven: i === 0,
62
+ previousKernelProven: false,
68
63
  publicKernelRequest: kernelRequest,
69
64
  };
70
65
  this.publicFunctions.push(publicFunction);
@@ -105,6 +100,37 @@ export class TxProvingState {
105
100
  return { code: TX_PROVING_CODE.READY, function: nextFunction };
106
101
  }
107
102
 
103
+ // Updates the transaction's proving state after completion of a tube proof
104
+ // Returns an instruction as to the next stage of tx proving
105
+ public getNextPublicKernelFromTubeProof(
106
+ proof: RecursiveProof<typeof RECURSIVE_PROOF_LENGTH>,
107
+ verificationKey: VerificationKeyData,
108
+ ): TxProvingInstruction {
109
+ const nextKernelIndex = 0;
110
+ if (nextKernelIndex >= this.publicFunctions.length) {
111
+ // The next kernel index is greater than our set of functions, we are done!
112
+ return { code: TX_PROVING_CODE.COMPLETED, function: undefined };
113
+ }
114
+
115
+ // There is more work to do, are we ready?
116
+ const nextFunction = this.publicFunctions[nextKernelIndex];
117
+
118
+ // pass both the proof and verification key forward to the next circuit
119
+ nextFunction.publicKernelRequest.inputs.previousKernel.proof = proof;
120
+ nextFunction.publicKernelRequest.inputs.previousKernel.vk = verificationKey;
121
+
122
+ // We need to update this so the state machine knows this proof is ready
123
+ nextFunction.previousKernelProven = true;
124
+ nextFunction.previousProofType = PublicKernelType.NON_PUBLIC;
125
+ if (nextFunction.vmProof === undefined) {
126
+ // The VM proof for the next function is not ready
127
+ return { code: TX_PROVING_CODE.NOT_READY, function: undefined };
128
+ }
129
+
130
+ // The VM proof is ready, we can continue
131
+ return { code: TX_PROVING_CODE.READY, function: nextFunction };
132
+ }
133
+
108
134
  // Updates the transaction's proving state after completion of a VM proof
109
135
  // Returns an instruction as to the next stage of tx proving
110
136
  public getNextPublicKernelFromVMProof(provenIndex: number, proof: Proof): TxProvingInstruction {