@aztec/prover-node 0.0.1-commit.9ef841308 → 0.0.1-commit.a4600f49

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 (71) hide show
  1. package/README.md +518 -0
  2. package/dest/actions/download-epoch-proving-job.js +1 -1
  3. package/dest/actions/rerun-epoch-proving-job.d.ts +4 -3
  4. package/dest/actions/rerun-epoch-proving-job.d.ts.map +1 -1
  5. package/dest/actions/rerun-epoch-proving-job.js +191 -28
  6. package/dest/bin/run-failed-epoch.js +1 -3
  7. package/dest/checkpoint-store.d.ts +87 -0
  8. package/dest/checkpoint-store.d.ts.map +1 -0
  9. package/dest/checkpoint-store.js +186 -0
  10. package/dest/config.d.ts +3 -1
  11. package/dest/config.d.ts.map +1 -1
  12. package/dest/config.js +8 -1
  13. package/dest/factory.d.ts +4 -1
  14. package/dest/factory.d.ts.map +1 -1
  15. package/dest/factory.js +3 -7
  16. package/dest/index.d.ts +2 -1
  17. package/dest/index.d.ts.map +1 -1
  18. package/dest/index.js +1 -0
  19. package/dest/job/checkpoint-prover.d.ts +134 -0
  20. package/dest/job/checkpoint-prover.d.ts.map +1 -0
  21. package/dest/job/checkpoint-prover.js +353 -0
  22. package/dest/job/epoch-session.d.ts +146 -0
  23. package/dest/job/epoch-session.d.ts.map +1 -0
  24. package/dest/job/epoch-session.js +720 -0
  25. package/dest/job/top-tree-job.d.ts +82 -0
  26. package/dest/job/top-tree-job.d.ts.map +1 -0
  27. package/dest/job/top-tree-job.js +152 -0
  28. package/dest/metrics.d.ts +35 -8
  29. package/dest/metrics.d.ts.map +1 -1
  30. package/dest/metrics.js +86 -14
  31. package/dest/monitors/epoch-monitor.js +6 -2
  32. package/dest/proof-publishing-service.d.ts +161 -0
  33. package/dest/proof-publishing-service.d.ts.map +1 -0
  34. package/dest/proof-publishing-service.js +335 -0
  35. package/dest/prover-node-publisher.d.ts +25 -15
  36. package/dest/prover-node-publisher.d.ts.map +1 -1
  37. package/dest/prover-node-publisher.js +201 -62
  38. package/dest/prover-node.d.ts +107 -67
  39. package/dest/prover-node.d.ts.map +1 -1
  40. package/dest/prover-node.js +484 -224
  41. package/dest/prover-publisher-factory.d.ts +3 -1
  42. package/dest/prover-publisher-factory.d.ts.map +1 -1
  43. package/dest/prover-publisher-factory.js +1 -0
  44. package/dest/session-manager.d.ts +158 -0
  45. package/dest/session-manager.d.ts.map +1 -0
  46. package/dest/session-manager.js +452 -0
  47. package/dest/test/index.d.ts +7 -6
  48. package/dest/test/index.d.ts.map +1 -1
  49. package/package.json +24 -23
  50. package/src/actions/download-epoch-proving-job.ts +1 -1
  51. package/src/actions/rerun-epoch-proving-job.ts +117 -29
  52. package/src/bin/run-failed-epoch.ts +1 -2
  53. package/src/checkpoint-store.ts +218 -0
  54. package/src/config.ts +12 -1
  55. package/src/factory.ts +6 -9
  56. package/src/index.ts +1 -0
  57. package/src/job/checkpoint-prover.ts +468 -0
  58. package/src/job/epoch-session.ts +436 -0
  59. package/src/job/top-tree-job.ts +227 -0
  60. package/src/metrics.ts +102 -23
  61. package/src/monitors/epoch-monitor.ts +2 -2
  62. package/src/proof-publishing-service.ts +427 -0
  63. package/src/prover-node-publisher.ts +236 -78
  64. package/src/prover-node.ts +555 -252
  65. package/src/prover-publisher-factory.ts +3 -0
  66. package/src/session-manager.ts +552 -0
  67. package/src/test/index.ts +6 -6
  68. package/dest/job/epoch-proving-job.d.ts +0 -63
  69. package/dest/job/epoch-proving-job.d.ts.map +0 -1
  70. package/dest/job/epoch-proving-job.js +0 -762
  71. package/src/job/epoch-proving-job.ts +0 -465
package/dest/factory.js CHANGED
@@ -12,7 +12,6 @@ import { createAndStartProvingBroker } from '@aztec/prover-client/broker';
12
12
  import { getPublisherConfigFromProverConfig } from '@aztec/sequencer-client';
13
13
  import { L1Metrics, getTelemetryClient } from '@aztec/telemetry-client';
14
14
  import { createPublicClient } from 'viem';
15
- import { EpochMonitor } from './monitors/epoch-monitor.js';
16
15
  import { ProverNode } from './prover-node.js';
17
16
  import { ProverPublisherFactory } from './prover-publisher-factory.js';
18
17
  /** Creates a new prover node subsystem given a config and dependencies */ export async function createProverNode(userConfig, deps) {
@@ -52,7 +51,7 @@ import { ProverPublisherFactory } from './prover-publisher-factory.js';
52
51
  }),
53
52
  pollingInterval: config.viemPollingIntervalMS
54
53
  });
55
- const rollupContract = new RollupContract(publicClient, config.l1Contracts.rollupAddress.toString());
54
+ const rollupContract = new RollupContract(publicClient, config.rollupAddress.toString());
56
55
  const l1TxUtils = deps.l1TxUtils ? [
57
56
  deps.l1TxUtils
58
57
  ] : config.proverPublisherForwarderAddress ? await createForwarderL1TxUtilsFromSigners(publicClient, proverSigners.signers, config.proverPublisherForwarderAddress, {
@@ -89,6 +88,7 @@ import { ProverPublisherFactory } from './prover-publisher-factory.js';
89
88
  }
90
89
  const publisherFactory = deps.publisherFactory ?? new ProverPublisherFactory(config, {
91
90
  rollupContract,
91
+ proofSubmissionTarget: config.proofSubmissionTargetAddress,
92
92
  publisherManager: new PublisherManager(l1TxUtils, getPublisherConfigFromProverConfig(config), {
93
93
  bindings: log.getBindings(),
94
94
  funder: funderL1TxUtils
@@ -98,12 +98,8 @@ import { ProverPublisherFactory } from './prover-publisher-factory.js';
98
98
  const proverNodeConfig = {
99
99
  ...pick(config, 'proverNodeMaxPendingJobs', 'proverNodeMaxParallelBlocksPerEpoch', 'proverNodePollingIntervalMs', 'proverNodeEpochProvingDelayMs', 'txGatheringMaxParallelRequests', 'txGatheringIntervalMs', 'txGatheringTimeoutMs', 'proverNodeFailedEpochStore', 'proverNodeDisableProofPublish', 'dataDirectory', 'l1ChainId', 'rollupVersion')
100
100
  };
101
- const epochMonitor = await EpochMonitor.create(archiver, {
102
- pollingIntervalMs: config.proverNodePollingIntervalMs,
103
- provingDelayMs: config.proverNodeEpochProvingDelayMs
104
- }, telemetry);
105
101
  const l1Metrics = new L1Metrics(telemetry.getMeter('ProverNodeL1Metrics'), publicClient, l1TxUtils.map((utils)=>utils.getSenderAddress()));
106
102
  // Extract the shared delayer from the first L1TxUtils instance (all instances share the same delayer)
107
103
  const delayer = l1TxUtils[0]?.delayer;
108
- return new ProverNode(prover, publisherFactory, archiver, archiver, archiver, worldStateSynchronizer, p2pClient, epochMonitor, rollupContract, l1Metrics, proverNodeConfig, telemetry, delayer, dateProvider);
104
+ return new ProverNode(prover, publisherFactory, archiver, archiver, archiver, worldStateSynchronizer, p2pClient, rollupContract, l1Metrics, deps.avmSimulator, proverNodeConfig, telemetry, delayer, dateProvider);
109
105
  }
package/dest/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export * from './actions/index.js';
2
2
  export * from './config.js';
3
3
  export * from './factory.js';
4
4
  export * from './monitors/index.js';
5
+ export * from './proof-publishing-service.js';
5
6
  export * from './prover-node-publisher.js';
6
7
  export * from './prover-node.js';
7
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLG9CQUFvQixDQUFDO0FBQ25DLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsY0FBYyxDQUFDO0FBQzdCLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyw0QkFBNEIsQ0FBQztBQUMzQyxjQUFjLGtCQUFrQixDQUFDIn0=
8
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLG9CQUFvQixDQUFDO0FBQ25DLGNBQWMsYUFBYSxDQUFDO0FBQzVCLGNBQWMsY0FBYyxDQUFDO0FBQzdCLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYywrQkFBK0IsQ0FBQztBQUM5QyxjQUFjLDRCQUE0QixDQUFDO0FBQzNDLGNBQWMsa0JBQWtCLENBQUMifQ==
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC"}
package/dest/index.js CHANGED
@@ -2,5 +2,6 @@ export * from './actions/index.js';
2
2
  export * from './config.js';
3
3
  export * from './factory.js';
4
4
  export * from './monitors/index.js';
5
+ export * from './proof-publishing-service.js';
5
6
  export * from './prover-node-publisher.js';
6
7
  export * from './prover-node.js';
@@ -0,0 +1,134 @@
1
+ import { type ARCHIVE_HEIGHT } from '@aztec/constants';
2
+ import { type EpochNumber, type SlotNumber } from '@aztec/foundation/branded-types';
3
+ import { Fr } from '@aztec/foundation/curves/bn254';
4
+ import type { EthAddress } from '@aztec/foundation/eth-address';
5
+ import type { Logger } from '@aztec/foundation/log';
6
+ import type { Tuple } from '@aztec/foundation/serialize';
7
+ import { type DateProvider } from '@aztec/foundation/timer';
8
+ import type { EpochProverFactory } from '@aztec/prover-client';
9
+ import type { ChonkCache, SubTreeResult } from '@aztec/prover-client/orchestrator';
10
+ import type { PublicProcessorFactory } from '@aztec/simulator/server';
11
+ import type { CommitteeAttestation } from '@aztec/stdlib/block';
12
+ import type { Checkpoint } from '@aztec/stdlib/checkpoint';
13
+ import type { ForkMerkleTreeOperations, ITxProvider } from '@aztec/stdlib/interfaces/server';
14
+ import type { BlockHeader, Tx } from '@aztec/stdlib/tx';
15
+ import type { ProverNodeJobMetrics } from '../metrics.js';
16
+ /** Dependencies a `CheckpointProver` needs at construction. */
17
+ export type CheckpointProverDeps = {
18
+ proverFactory: EpochProverFactory;
19
+ /** Shared chonk-verifier cache. Survives across all sessions / epochs. */
20
+ chonkCache: ChonkCache;
21
+ publicProcessorFactory: PublicProcessorFactory;
22
+ dbProvider: Pick<ForkMerkleTreeOperations, 'fork'>;
23
+ txProvider: ITxProvider;
24
+ /** Clock the prover-node operates against — e2e fixtures inject a cheat-controlled one. */
25
+ dateProvider: DateProvider;
26
+ proverId: EthAddress;
27
+ metrics: ProverNodeJobMetrics;
28
+ /** Tx gathering deadline. */
29
+ txGatheringTimeoutMs: number;
30
+ /** Public processor deadline. */
31
+ deadline: Date | undefined;
32
+ log: Logger;
33
+ };
34
+ /** Inputs that fully describe a checkpoint at register time. */
35
+ export type CheckpointProverArgs = {
36
+ checkpoint: Checkpoint;
37
+ /** Epoch the checkpoint belongs to (derivable from slot + L1 constants; cached at register time). */
38
+ epochNumber: EpochNumber;
39
+ attestations: CommitteeAttestation[];
40
+ previousBlockHeader: BlockHeader;
41
+ l1ToL2Messages: Fr[];
42
+ previousArchiveSiblingPath: Tuple<Fr, typeof ARCHIVE_HEIGHT>;
43
+ };
44
+ /**
45
+ * Self-contained per-checkpoint prover, content-addressed by
46
+ * `(checkpoint number, slot number, checkpoint archive root)`.
47
+ *
48
+ * The store creates a CheckpointProver once per content-key. Keying on the checkpoint's
49
+ * own archive root (its post-state) means two checkpoints are "the same" iff they
50
+ * produce the same archive — so a reorg branch, or a replacement built on the same
51
+ * predecessor but with different content, keys to a distinct prover; an identical
52
+ * re-add keys to the same one and reuses its in-flight sub-tree work.
53
+ *
54
+ * The prover eagerly starts its own tx gather and sub-tree work in the constructor, so
55
+ * callers only need to call `whenBlockProofsReady()` to obtain the resulting block-rollup
56
+ * proofs.
57
+ *
58
+ * The prover survives prune/re-add cycles via `markPruned()` / `markCanonical()` —
59
+ * sub-tree proving keeps running underneath, so a checkpoint that is re-added after
60
+ * a brief reorg can be re-consumed with no re-proving.
61
+ *
62
+ * `cancel()` is idempotent. It aborts the gather + sub-tree, rejects the block-proof
63
+ * promise, and exposes a `whenDone()` that resolves once teardown has unwound.
64
+ */
65
+ export declare class CheckpointProver {
66
+ private readonly deps;
67
+ readonly id: string;
68
+ readonly checkpoint: Checkpoint;
69
+ readonly epochNumber: EpochNumber;
70
+ readonly slotNumber: SlotNumber;
71
+ readonly attestations: CommitteeAttestation[];
72
+ readonly previousBlockHeader: BlockHeader;
73
+ readonly l1ToL2Messages: Fr[];
74
+ readonly previousArchiveSiblingPath: Tuple<Fr, typeof ARCHIVE_HEIGHT>;
75
+ /** Per-prover tx map — populated by the internal gather. Empty until then. */
76
+ readonly txs: Map<string, Tx>;
77
+ /** Resolved by the sub-tree on success, rejected on cancel/failure. */
78
+ private readonly blockProofs;
79
+ private cancelled;
80
+ private subTree?;
81
+ private completed;
82
+ /** Pruned in the canonical chain but not yet reaped — sub-tree continues running. */
83
+ private pruned;
84
+ private readonly abortController;
85
+ /** Tracks the eager gather+execute task so `cancel()` and `whenDone()` can await its unwind. */
86
+ private readonly runPromise;
87
+ /** Tracks the cancel-driven teardown so `whenDone()` can await it. */
88
+ private cancelPromise?;
89
+ constructor(args: CheckpointProverArgs, deps: CheckpointProverDeps);
90
+ /**
91
+ * Stable content-addressed identifier: `${checkpoint number}:${slot}:${archive root}`.
92
+ * The archive root is the checkpoint's post-state, so it distinguishes any two
93
+ * checkpoints that differ in history or content while collapsing identical re-adds.
94
+ */
95
+ static idFor(checkpoint: Checkpoint): string;
96
+ isCancelled(): boolean;
97
+ /** True once block-level proving has been fully *enqueued* (sub-tree completion may still be pending). */
98
+ isCompleted(): boolean;
99
+ isPruned(): boolean;
100
+ /**
101
+ * Mark this prover as no longer present in the canonical chain. Sub-tree proving keeps
102
+ * running so the work survives if the checkpoint is re-added. Idempotent.
103
+ */
104
+ markPruned(): void;
105
+ /** Mark this prover as part of the canonical chain again after a re-add. Idempotent. */
106
+ markCanonical(): void;
107
+ /** AbortSignal that fires on cancel — for callers that want to wire their own tasks. */
108
+ getAbortSignal(): AbortSignal;
109
+ /** Promise that resolves with the block-rollup proofs for this checkpoint (or rejects on cancel/failure). */
110
+ whenBlockProofsReady(): Promise<SubTreeResult['blockProofOutputs']>;
111
+ /** Resolves when all in-flight work for this prover has fully unwound. */
112
+ whenDone(): Promise<void>;
113
+ private gatherAndExecute;
114
+ private gatherTxs;
115
+ private executeCheckpoint;
116
+ /**
117
+ * Mark cancelled. Idempotent. Aborts in-flight work, rejects the block-proof promise,
118
+ * and kicks off a background teardown of the sub-tree. The teardown promise is exposed
119
+ * via `whenDone()`.
120
+ *
121
+ * `routine` distinguishes a post-finalize teardown (sub-tree already proven, fires
122
+ * once at prover exit) from a real abort (reorg, prune, deadline). Behaviour is
123
+ * identical either way; the flag only adjusts log verbosity.
124
+ */
125
+ cancel({ routine }?: {
126
+ routine?: boolean;
127
+ }): void;
128
+ private runCancel;
129
+ private teardownSubTree;
130
+ private getTxsForBlock;
131
+ private processTxs;
132
+ private createFork;
133
+ }
134
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlY2twb2ludC1wcm92ZXIuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9qb2IvY2hlY2twb2ludC1wcm92ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLEtBQUssY0FBYyxFQUF1QyxNQUFNLGtCQUFrQixDQUFDO0FBQzVGLE9BQU8sRUFBZSxLQUFLLFdBQVcsRUFBRSxLQUFLLFVBQVUsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRWpHLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNwRCxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUNoRSxPQUFPLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUVwRCxPQUFPLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsS0FBSyxZQUFZLEVBQVMsTUFBTSx5QkFBeUIsQ0FBQztBQUduRSxPQUFPLEtBQUssRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQy9ELE9BQU8sS0FBSyxFQUFpQyxVQUFVLEVBQUUsYUFBYSxFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDbEgsT0FBTyxLQUFLLEVBQW1CLHNCQUFzQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFFdkYsT0FBTyxLQUFLLEVBQUUsb0JBQW9CLEVBQVcsTUFBTSxxQkFBcUIsQ0FBQztBQUN6RSxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMzRCxPQUFPLEtBQUssRUFBRSx3QkFBd0IsRUFBRSxXQUFXLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUc3RixPQUFPLEtBQUssRUFBRSxXQUFXLEVBQWUsRUFBRSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFckUsT0FBTyxLQUFLLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxlQUFlLENB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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkpoint-prover.d.ts","sourceRoot":"","sources":["../../src/job/checkpoint-prover.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,353 @@
1
+ import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
2
+ import { BlockNumber } from '@aztec/foundation/branded-types';
3
+ import { padArrayEnd } from '@aztec/foundation/collection';
4
+ import { Fr } from '@aztec/foundation/curves/bn254';
5
+ import { promiseWithResolvers } from '@aztec/foundation/promise';
6
+ import { Timer } from '@aztec/foundation/timer';
7
+ import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
8
+ import { protocolContractsHash } from '@aztec/protocol-contracts';
9
+ import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
10
+ import { CheckpointConstantData } from '@aztec/stdlib/rollup';
11
+ import { MerkleTreeId } from '@aztec/stdlib/trees';
12
+ /**
13
+ * Self-contained per-checkpoint prover, content-addressed by
14
+ * `(checkpoint number, slot number, checkpoint archive root)`.
15
+ *
16
+ * The store creates a CheckpointProver once per content-key. Keying on the checkpoint's
17
+ * own archive root (its post-state) means two checkpoints are "the same" iff they
18
+ * produce the same archive — so a reorg branch, or a replacement built on the same
19
+ * predecessor but with different content, keys to a distinct prover; an identical
20
+ * re-add keys to the same one and reuses its in-flight sub-tree work.
21
+ *
22
+ * The prover eagerly starts its own tx gather and sub-tree work in the constructor, so
23
+ * callers only need to call `whenBlockProofsReady()` to obtain the resulting block-rollup
24
+ * proofs.
25
+ *
26
+ * The prover survives prune/re-add cycles via `markPruned()` / `markCanonical()` —
27
+ * sub-tree proving keeps running underneath, so a checkpoint that is re-added after
28
+ * a brief reorg can be re-consumed with no re-proving.
29
+ *
30
+ * `cancel()` is idempotent. It aborts the gather + sub-tree, rejects the block-proof
31
+ * promise, and exposes a `whenDone()` that resolves once teardown has unwound.
32
+ */ export class CheckpointProver {
33
+ deps;
34
+ id;
35
+ checkpoint;
36
+ epochNumber;
37
+ slotNumber;
38
+ attestations;
39
+ previousBlockHeader;
40
+ l1ToL2Messages;
41
+ previousArchiveSiblingPath;
42
+ /** Per-prover tx map — populated by the internal gather. Empty until then. */ txs;
43
+ /** Resolved by the sub-tree on success, rejected on cancel/failure. */ blockProofs;
44
+ cancelled;
45
+ subTree;
46
+ completed;
47
+ /** Pruned in the canonical chain but not yet reaped — sub-tree continues running. */ pruned;
48
+ abortController;
49
+ /** Tracks the eager gather+execute task so `cancel()` and `whenDone()` can await its unwind. */ runPromise;
50
+ /** Tracks the cancel-driven teardown so `whenDone()` can await it. */ cancelPromise;
51
+ constructor(args, deps){
52
+ this.deps = deps;
53
+ this.txs = new Map();
54
+ this.blockProofs = promiseWithResolvers();
55
+ this.cancelled = false;
56
+ this.completed = false;
57
+ this.pruned = false;
58
+ this.abortController = new AbortController();
59
+ this.checkpoint = args.checkpoint;
60
+ this.epochNumber = args.epochNumber;
61
+ this.slotNumber = args.checkpoint.header.slotNumber;
62
+ this.attestations = args.attestations;
63
+ this.previousBlockHeader = args.previousBlockHeader;
64
+ this.l1ToL2Messages = args.l1ToL2Messages;
65
+ this.previousArchiveSiblingPath = args.previousArchiveSiblingPath;
66
+ this.id = CheckpointProver.idFor(args.checkpoint);
67
+ // Mark blockProofs as observed so a cancel that lands before any consumer awaits
68
+ // does not surface as an unhandled rejection.
69
+ this.blockProofs.promise.catch(()=>{});
70
+ deps.log.info(`Created CheckpointProver ${this.id}`, {
71
+ checkpointNumber: this.checkpoint.number,
72
+ epochNumber: this.epochNumber,
73
+ slotNumber: this.slotNumber,
74
+ blockCount: this.checkpoint.blocks.length,
75
+ l1ToL2MessageCount: this.l1ToL2Messages.length,
76
+ archiveRoot: this.checkpoint.archive.root.toString()
77
+ });
78
+ // Kick off the eager gather + sub-tree pipeline.
79
+ this.runPromise = this.gatherAndExecute();
80
+ }
81
+ /**
82
+ * Stable content-addressed identifier: `${checkpoint number}:${slot}:${archive root}`.
83
+ * The archive root is the checkpoint's post-state, so it distinguishes any two
84
+ * checkpoints that differ in history or content while collapsing identical re-adds.
85
+ */ static idFor(checkpoint) {
86
+ return `${checkpoint.number}:${checkpoint.header.slotNumber}:${checkpoint.archive.root.toString()}`;
87
+ }
88
+ isCancelled() {
89
+ return this.cancelled;
90
+ }
91
+ /** True once block-level proving has been fully *enqueued* (sub-tree completion may still be pending). */ isCompleted() {
92
+ return this.completed;
93
+ }
94
+ isPruned() {
95
+ return this.pruned;
96
+ }
97
+ /**
98
+ * Mark this prover as no longer present in the canonical chain. Sub-tree proving keeps
99
+ * running so the work survives if the checkpoint is re-added. Idempotent.
100
+ */ markPruned() {
101
+ if (this.pruned) {
102
+ return;
103
+ }
104
+ this.pruned = true;
105
+ this.deps.log.info(`Marking CheckpointProver ${this.id} as pruned`, {
106
+ checkpointNumber: this.checkpoint.number,
107
+ slotNumber: this.slotNumber
108
+ });
109
+ }
110
+ /** Mark this prover as part of the canonical chain again after a re-add. Idempotent. */ markCanonical() {
111
+ if (!this.pruned) {
112
+ return;
113
+ }
114
+ this.pruned = false;
115
+ this.deps.log.info(`Marking CheckpointProver ${this.id} as canonical`, {
116
+ checkpointNumber: this.checkpoint.number,
117
+ slotNumber: this.slotNumber
118
+ });
119
+ }
120
+ /** AbortSignal that fires on cancel — for callers that want to wire their own tasks. */ getAbortSignal() {
121
+ return this.abortController.signal;
122
+ }
123
+ /** Promise that resolves with the block-rollup proofs for this checkpoint (or rejects on cancel/failure). */ whenBlockProofsReady() {
124
+ return this.blockProofs.promise;
125
+ }
126
+ /** Resolves when all in-flight work for this prover has fully unwound. */ async whenDone() {
127
+ await this.runPromise.catch(()=>{});
128
+ if (this.cancelPromise) {
129
+ await this.cancelPromise;
130
+ }
131
+ }
132
+ async gatherAndExecute() {
133
+ try {
134
+ const txs = await this.gatherTxs();
135
+ if (this.cancelled) {
136
+ return;
137
+ }
138
+ await this.executeCheckpoint(txs);
139
+ } catch (err) {
140
+ if (this.cancelled) {
141
+ this.deps.log.debug(`CheckpointProver ${this.id} cancelled during gather/execute`, {
142
+ checkpointNumber: this.checkpoint.number
143
+ });
144
+ return;
145
+ }
146
+ this.deps.log.error(`Error in CheckpointProver ${this.id}`, err, {
147
+ checkpointNumber: this.checkpoint.number
148
+ });
149
+ this.blockProofs.reject(err instanceof Error ? err : new Error(String(err)));
150
+ }
151
+ }
152
+ async gatherTxs() {
153
+ const deadline = new Date(this.deps.dateProvider.now() + this.deps.txGatheringTimeoutMs);
154
+ const txsByBlock = await Promise.all(this.checkpoint.blocks.map((block)=>this.deps.txProvider.getTxsForBlock(block, {
155
+ deadline
156
+ })));
157
+ const txs = txsByBlock.map(({ txs })=>txs).flat();
158
+ const missingTxs = txsByBlock.map(({ missingTxs })=>missingTxs).flat();
159
+ if (missingTxs.length > 0) {
160
+ throw new Error(`Txs not found for checkpoint ${this.checkpoint.number}: ${missingTxs.map((hash)=>hash.toString()).join(', ')}`);
161
+ }
162
+ return new Map(txs.map((tx)=>[
163
+ tx.getTxHash().toString(),
164
+ tx
165
+ ]));
166
+ }
167
+ async executeCheckpoint(txs) {
168
+ const signal = this.abortController.signal;
169
+ const checkpointTimer = new Timer();
170
+ let subTreeStarted = false;
171
+ try {
172
+ for (const [hash, tx] of txs){
173
+ this.txs.set(hash, tx);
174
+ }
175
+ const { chainId, version } = this.checkpoint.blocks[0].header.globalVariables;
176
+ const checkpointConstants = CheckpointConstantData.from({
177
+ chainId,
178
+ version,
179
+ vkTreeRoot: getVKTreeRoot(),
180
+ protocolContractsHash: protocolContractsHash,
181
+ proverId: this.deps.proverId.toField(),
182
+ slotNumber: this.checkpoint.header.slotNumber,
183
+ coinbase: this.checkpoint.header.coinbase,
184
+ feeRecipient: this.checkpoint.header.feeRecipient,
185
+ gasFees: this.checkpoint.header.gasFees
186
+ });
187
+ this.deps.log.info(`Starting processing checkpoint ${this.checkpoint.number}`, {
188
+ checkpointNumber: this.checkpoint.number,
189
+ checkpointHash: this.checkpoint.hash().toString(),
190
+ blockCount: this.checkpoint.blocks.length
191
+ });
192
+ this.subTree = await this.deps.proverFactory.createCheckpointSubTreeOrchestrator(this.deps.chonkCache, this.epochNumber, checkpointConstants, this.l1ToL2Messages, this.checkpoint.blocks.length, this.previousBlockHeader);
193
+ subTreeStarted = true;
194
+ // Bridge the sub-tree's result onto blockProofs.
195
+ void this.subTree.getSubTreeResult().then((result)=>{
196
+ this.deps.log.info(`Sub-tree block proofs ready for checkpoint ${this.checkpoint.number}`, {
197
+ checkpointNumber: this.checkpoint.number,
198
+ blockProofCount: result.blockProofOutputs.length
199
+ });
200
+ // Spans processing + proving (from executeCheckpoint start, after tx gathering) to proofs ready.
201
+ this.deps.metrics.recordCheckpointProving(checkpointTimer.ms());
202
+ this.blockProofs.resolve(result.blockProofOutputs);
203
+ }, (err)=>this.blockProofs.reject(err));
204
+ if (signal.aborted) {
205
+ return;
206
+ }
207
+ const allTxs = this.checkpoint.blocks.flatMap((block)=>block.body.txEffects.map((txEffect)=>txs.get(txEffect.txHash.toString())));
208
+ const publicTxs = allTxs.filter((tx)=>tx?.data.forPublic);
209
+ if (publicTxs.length > 0) {
210
+ await this.subTree.startChonkVerifierCircuits(publicTxs);
211
+ if (signal.aborted) {
212
+ return;
213
+ }
214
+ }
215
+ for(let blockIndex = 0; blockIndex < this.checkpoint.blocks.length; blockIndex++){
216
+ const blockTimer = new Timer();
217
+ const block = this.checkpoint.blocks[blockIndex];
218
+ const globalVariables = block.header.globalVariables;
219
+ const blockTxs = this.getTxsForBlock(block, txs);
220
+ await this.subTree.startNewBlock(block.number, globalVariables.timestamp, blockTxs.length);
221
+ if (signal.aborted) {
222
+ return;
223
+ }
224
+ const db = await this.createFork(BlockNumber(block.number - 1), blockIndex === 0 ? this.l1ToL2Messages : undefined);
225
+ try {
226
+ if (signal.aborted) {
227
+ return;
228
+ }
229
+ const config = PublicSimulatorConfig.from({
230
+ proverId: this.deps.proverId.toField(),
231
+ skipFeeEnforcement: false,
232
+ collectDebugLogs: false,
233
+ collectHints: true,
234
+ collectPublicInputs: true,
235
+ collectStatistics: false
236
+ });
237
+ const publicProcessor = this.deps.publicProcessorFactory.create(db, globalVariables, config);
238
+ const processed = await this.processTxs(publicProcessor, blockTxs);
239
+ if (signal.aborted) {
240
+ return;
241
+ }
242
+ await this.subTree.addTxs(processed);
243
+ } finally{
244
+ await db.close();
245
+ }
246
+ if (signal.aborted) {
247
+ return;
248
+ }
249
+ await this.subTree.setBlockCompleted(block.number, block.header);
250
+ this.deps.metrics.recordBlockProcessing(blockTimer.ms());
251
+ if (signal.aborted) {
252
+ return;
253
+ }
254
+ }
255
+ this.completed = true;
256
+ const numTxs = this.checkpoint.blocks.reduce((acc, block)=>acc + block.body.txEffects.length, 0);
257
+ this.deps.metrics.recordCheckpointProcessing(checkpointTimer.ms(), this.checkpoint.blocks.length, numTxs);
258
+ this.deps.log.info(`Finished enqueueing block-level proving for checkpoint ${this.checkpoint.number} in ${checkpointTimer.ms()}ms`, {
259
+ checkpointNumber: this.checkpoint.number,
260
+ blockCount: this.checkpoint.blocks.length,
261
+ durationMs: checkpointTimer.ms()
262
+ });
263
+ } finally{
264
+ if (!this.completed) {
265
+ if (subTreeStarted) {
266
+ await this.teardownSubTree();
267
+ }
268
+ this.blockProofs.reject(new Error(`Checkpoint ${this.id} did not complete block processing`));
269
+ }
270
+ }
271
+ }
272
+ /**
273
+ * Mark cancelled. Idempotent. Aborts in-flight work, rejects the block-proof promise,
274
+ * and kicks off a background teardown of the sub-tree. The teardown promise is exposed
275
+ * via `whenDone()`.
276
+ *
277
+ * `routine` distinguishes a post-finalize teardown (sub-tree already proven, fires
278
+ * once at prover exit) from a real abort (reorg, prune, deadline). Behaviour is
279
+ * identical either way; the flag only adjusts log verbosity.
280
+ */ cancel({ routine = false } = {}) {
281
+ if (this.cancelled) {
282
+ return;
283
+ }
284
+ this.cancelled = true;
285
+ // A teardown of a completed prover is routine regardless of the caller's flag —
286
+ // we logged the work as done already, so don't relabel it as a mid-flight cancel.
287
+ if (routine || this.completed) {
288
+ this.deps.log.verbose(`Tearing down CheckpointProver ${this.id}`, {
289
+ checkpointNumber: this.checkpoint.number,
290
+ wasCompleted: this.completed
291
+ });
292
+ } else {
293
+ this.deps.log.info(`Cancelling in-flight CheckpointProver ${this.id}`, {
294
+ checkpointNumber: this.checkpoint.number,
295
+ wasCompleted: this.completed
296
+ });
297
+ }
298
+ this.abortController.abort();
299
+ this.blockProofs.reject(new Error(`Checkpoint ${this.id} cancelled`));
300
+ this.cancelPromise = this.runCancel().catch(()=>{});
301
+ }
302
+ async runCancel() {
303
+ if (this.subTree) {
304
+ try {
305
+ this.subTree.cancel();
306
+ } catch (err) {
307
+ this.deps.log.error('Error cancelling sub-tree', err);
308
+ }
309
+ }
310
+ await this.runPromise.catch(()=>{});
311
+ if (this.subTree) {
312
+ await this.teardownSubTree();
313
+ }
314
+ }
315
+ async teardownSubTree() {
316
+ const { subTree } = this;
317
+ this.subTree = undefined;
318
+ if (subTree) {
319
+ this.deps.log.debug(`Tearing down sub-tree for checkpoint ${this.checkpoint.number}`, {
320
+ checkpointNumber: this.checkpoint.number
321
+ });
322
+ try {
323
+ await subTree.stop();
324
+ } catch (err) {
325
+ this.deps.log.error('Error stopping sub-tree', err);
326
+ }
327
+ }
328
+ }
329
+ getTxsForBlock(block, txs) {
330
+ return block.body.txEffects.map((txEffect)=>txs.get(txEffect.txHash.toString()));
331
+ }
332
+ async processTxs(publicProcessor, txs) {
333
+ const [processedTxs, failedTxs] = await publicProcessor.process(txs, {
334
+ deadline: this.deps.deadline
335
+ });
336
+ if (failedTxs.length) {
337
+ const failedTxHashes = await Promise.all(failedTxs.map(({ tx })=>tx.getTxHash()));
338
+ throw new Error(`Txs failed processing: ${failedTxs.map(({ error }, index)=>`${failedTxHashes[index]} (${error})`).join(', ')}`);
339
+ }
340
+ if (processedTxs.length !== txs.length) {
341
+ throw new Error(`Failed to process all txs: processed ${processedTxs.length} out of ${txs.length}`);
342
+ }
343
+ return processedTxs;
344
+ }
345
+ async createFork(blockNumber, l1ToL2Messages) {
346
+ const db = await this.deps.dbProvider.fork(blockNumber);
347
+ if (l1ToL2Messages !== undefined) {
348
+ const l1ToL2MessagesPadded = padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 'Too many L1 to L2 messages');
349
+ await db.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2MessagesPadded);
350
+ }
351
+ return db;
352
+ }
353
+ }