@aztec/prover-node 0.0.1-commit.b655e406 → 0.0.1-commit.b8a057fa
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/README.md +518 -0
- package/dest/actions/download-epoch-proving-job.d.ts +4 -4
- package/dest/actions/download-epoch-proving-job.js +1 -1
- package/dest/actions/index.d.ts +1 -1
- package/dest/actions/rerun-epoch-proving-job.d.ts +6 -4
- package/dest/actions/rerun-epoch-proving-job.d.ts.map +1 -1
- package/dest/actions/rerun-epoch-proving-job.js +191 -28
- package/dest/actions/upload-epoch-proof-failure.d.ts +2 -2
- package/dest/actions/upload-epoch-proof-failure.d.ts.map +1 -1
- package/dest/bin/run-failed-epoch.d.ts +1 -1
- package/dest/bin/run-failed-epoch.js +6 -5
- package/dest/checkpoint-store.d.ts +87 -0
- package/dest/checkpoint-store.d.ts.map +1 -0
- package/dest/checkpoint-store.js +186 -0
- package/dest/config.d.ts +10 -10
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +27 -22
- package/dest/factory.d.ts +23 -16
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +49 -68
- package/dest/index.d.ts +3 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +2 -0
- package/dest/job/checkpoint-prover.d.ts +134 -0
- package/dest/job/checkpoint-prover.d.ts.map +1 -0
- package/dest/job/checkpoint-prover.js +353 -0
- package/dest/job/epoch-proving-job-data.d.ts +8 -6
- package/dest/job/epoch-proving-job-data.d.ts.map +1 -1
- package/dest/job/epoch-proving-job-data.js +25 -18
- package/dest/job/epoch-session.d.ts +146 -0
- package/dest/job/epoch-session.d.ts.map +1 -0
- package/dest/job/epoch-session.js +720 -0
- package/dest/job/top-tree-job.d.ts +82 -0
- package/dest/job/top-tree-job.d.ts.map +1 -0
- package/dest/job/top-tree-job.js +152 -0
- package/dest/metrics.d.ts +42 -4
- package/dest/metrics.d.ts.map +1 -1
- package/dest/metrics.js +128 -99
- package/dest/monitors/epoch-monitor.d.ts +3 -2
- package/dest/monitors/epoch-monitor.d.ts.map +1 -1
- package/dest/monitors/epoch-monitor.js +14 -20
- package/dest/monitors/index.d.ts +1 -1
- package/dest/proof-publishing-service.d.ts +161 -0
- package/dest/proof-publishing-service.d.ts.map +1 -0
- package/dest/proof-publishing-service.js +335 -0
- package/dest/prover-node-publisher.d.ts +36 -23
- package/dest/prover-node-publisher.d.ts.map +1 -1
- package/dest/prover-node-publisher.js +244 -98
- package/dest/prover-node.d.ts +122 -71
- package/dest/prover-node.d.ts.map +1 -1
- package/dest/prover-node.js +872 -226
- package/dest/prover-publisher-factory.d.ts +12 -6
- package/dest/prover-publisher-factory.d.ts.map +1 -1
- package/dest/prover-publisher-factory.js +8 -5
- package/dest/session-manager.d.ts +158 -0
- package/dest/session-manager.d.ts.map +1 -0
- package/dest/session-manager.js +452 -0
- package/dest/test/index.d.ts +7 -6
- package/dest/test/index.d.ts.map +1 -1
- package/package.json +28 -25
- package/src/actions/download-epoch-proving-job.ts +1 -1
- package/src/actions/rerun-epoch-proving-job.ts +120 -30
- package/src/actions/upload-epoch-proof-failure.ts +1 -1
- package/src/bin/run-failed-epoch.ts +5 -3
- package/src/checkpoint-store.ts +218 -0
- package/src/config.ts +39 -34
- package/src/factory.ts +86 -111
- package/src/index.ts +2 -0
- package/src/job/checkpoint-prover.ts +468 -0
- package/src/job/epoch-proving-job-data.ts +31 -25
- package/src/job/epoch-session.ts +436 -0
- package/src/job/top-tree-job.ts +227 -0
- package/src/metrics.ts +146 -84
- package/src/monitors/epoch-monitor.ts +10 -17
- package/src/proof-publishing-service.ts +427 -0
- package/src/prover-node-publisher.ts +300 -129
- package/src/prover-node.ts +569 -254
- package/src/prover-publisher-factory.ts +22 -11
- package/src/session-manager.ts +552 -0
- package/src/test/index.ts +6 -6
- package/dest/job/epoch-proving-job.d.ts +0 -69
- package/dest/job/epoch-proving-job.d.ts.map +0 -1
- package/dest/job/epoch-proving-job.js +0 -354
- package/src/job/epoch-proving-job.ts +0 -420
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import type { L1TxUtils
|
|
1
|
+
import { BatchedBlob } from '@aztec/blob-lib';
|
|
2
|
+
import type { RollupContract, ViemCommitteeAttestation } from '@aztec/ethereum/contracts';
|
|
3
|
+
import type { L1TxUtils } from '@aztec/ethereum/l1-tx-utils';
|
|
4
|
+
import { CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
5
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
6
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
5
|
-
import {
|
|
6
|
-
import type { Tuple } from '@aztec/foundation/serialize';
|
|
7
|
+
import { type Logger, type LoggerBindings } from '@aztec/foundation/log';
|
|
7
8
|
import type { PublisherConfig, TxSenderConfig } from '@aztec/sequencer-client';
|
|
8
9
|
import type { Proof } from '@aztec/stdlib/proofs';
|
|
9
|
-
import type {
|
|
10
|
+
import type { CheckpointHeader, RootRollupPublicInputs } from '@aztec/stdlib/rollup';
|
|
10
11
|
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
12
|
+
import { type Hex } from 'viem';
|
|
11
13
|
/** Arguments to the submitEpochProof method of the rollup contract */
|
|
12
14
|
export type L1SubmitEpochProofArgs = {
|
|
13
15
|
epochSize: number;
|
|
@@ -16,43 +18,54 @@ export type L1SubmitEpochProofArgs = {
|
|
|
16
18
|
endTimestamp: Fr;
|
|
17
19
|
outHash: Fr;
|
|
18
20
|
proverId: Fr;
|
|
19
|
-
|
|
21
|
+
headers: CheckpointHeader[];
|
|
20
22
|
proof: Proof;
|
|
21
23
|
};
|
|
22
24
|
export declare class ProverNodePublisher {
|
|
23
|
-
private interrupted;
|
|
24
25
|
private metrics;
|
|
25
|
-
protected log:
|
|
26
|
+
protected log: Logger;
|
|
26
27
|
protected rollupContract: RollupContract;
|
|
28
|
+
protected proofSubmissionTarget: Hex;
|
|
27
29
|
readonly l1TxUtils: L1TxUtils;
|
|
28
30
|
constructor(config: TxSenderConfig & PublisherConfig, deps: {
|
|
29
31
|
rollupContract: RollupContract;
|
|
30
32
|
l1TxUtils: L1TxUtils;
|
|
33
|
+
proofSubmissionTarget?: EthAddress;
|
|
31
34
|
telemetry?: TelemetryClient;
|
|
32
|
-
});
|
|
35
|
+
}, bindings?: LoggerBindings);
|
|
33
36
|
getRollupContract(): RollupContract;
|
|
34
|
-
/**
|
|
35
|
-
* Calling `interrupt` will cause any in progress call to `publishRollup` to return `false` asap.
|
|
36
|
-
* Be warned, the call may return false even if the tx subsequently gets successfully mined.
|
|
37
|
-
* In practice this shouldn't matter, as we'll only ever be calling `interrupt` when we know it's going to fail.
|
|
38
|
-
* A call to `restart` is required before you can continue publishing.
|
|
39
|
-
*/
|
|
40
|
-
interrupt(): void;
|
|
41
|
-
/** Restarts the publisher after calling `interrupt`. */
|
|
42
|
-
restart(): void;
|
|
43
37
|
getSenderAddress(): EthAddress;
|
|
44
38
|
submitEpochProof(args: {
|
|
45
|
-
epochNumber:
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
epochNumber: EpochNumber;
|
|
40
|
+
fromCheckpoint: CheckpointNumber;
|
|
41
|
+
toCheckpoint: CheckpointNumber;
|
|
48
42
|
publicInputs: RootRollupPublicInputs;
|
|
49
43
|
proof: Proof;
|
|
50
44
|
batchedBlobInputs: BatchedBlob;
|
|
51
45
|
attestations: ViemCommitteeAttestation[];
|
|
46
|
+
headers: CheckpointHeader[];
|
|
47
|
+
/** Wall-clock deadline (proof-submission window end) past which the L1 tx should stop retrying. */
|
|
48
|
+
deadline?: Date;
|
|
52
49
|
}): Promise<boolean>;
|
|
53
50
|
private validateEpochProofSubmission;
|
|
51
|
+
/**
|
|
52
|
+
* Estimates what submitting the epoch proof would have cost on L1 without actually sending it.
|
|
53
|
+
* Runs the same validation as `submitEpochProof`, encodes the calldata, estimates gas, and records metrics.
|
|
54
|
+
* Used when proof publishing is disabled (e.g. PROVER_NODE_DISABLE_PROOF_PUBLISH=true on mainnet).
|
|
55
|
+
*/
|
|
56
|
+
analyzeEpochProofSubmission(args: {
|
|
57
|
+
epochNumber: EpochNumber;
|
|
58
|
+
fromCheckpoint: CheckpointNumber;
|
|
59
|
+
toCheckpoint: CheckpointNumber;
|
|
60
|
+
publicInputs: RootRollupPublicInputs;
|
|
61
|
+
proof: Proof;
|
|
62
|
+
batchedBlobInputs: BatchedBlob;
|
|
63
|
+
attestations: ViemCommitteeAttestation[];
|
|
64
|
+
headers: CheckpointHeader[];
|
|
65
|
+
}): Promise<void>;
|
|
66
|
+
private encodeSubmitEpochProofCalldata;
|
|
54
67
|
private sendSubmitEpochProofTx;
|
|
55
68
|
private getEpochProofPublicInputsArgs;
|
|
56
69
|
private getSubmitEpochProofArgs;
|
|
57
70
|
}
|
|
58
|
-
//# sourceMappingURL=
|
|
71
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdmVyLW5vZGUtcHVibGlzaGVyLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvcHJvdmVyLW5vZGUtcHVibGlzaGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxXQUFXLEVBQThCLE1BQU0saUJBQWlCLENBQUM7QUFFMUUsT0FBTyxLQUFLLEVBQUUsY0FBYyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDMUYsT0FBTyxLQUFLLEVBQUUsU0FBUyxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDN0QsT0FBTyxFQUFFLGdCQUFnQixFQUFFLFdBQVcsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRWhGLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNwRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDM0QsT0FBTyxFQUFFLEtBQUssTUFBTSxFQUFFLEtBQUssY0FBYyxFQUFnQixNQUFNLHVCQUF1QixDQUFDO0FBR3ZGLE9BQU8sS0FBSyxFQUFFLGVBQWUsRUFBRSxjQUFjLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUUvRSxPQUFPLEtBQUssRUFBRSxLQUFLLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNsRCxPQUFPLEtBQUssRUFBRSxnQkFBZ0IsRUFBRSxzQkFBc0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBRXJGLE9BQU8sRUFBRSxLQUFLLGVBQWUsRUFBc0IsTUFBTSx5QkFBeUIsQ0FBQztBQUduRixPQUFPLEVBQUUsS0FBSyxHQUFHLEVBQXdFLE1BQU0sTUFBTSxDQUFDO0FBSXRHLHNFQUFzRTtBQUN0RSxNQUFNLE1BQU0sc0JBQXNCLEdBQUc7SUFDbkMsU0FBUyxFQUFFLE1BQU0sQ0FBQztJQUNsQixlQUFlLEVBQUUsRUFBRSxDQUFDO0lBQ3BCLFVBQVUsRUFBRSxFQUFFLENBQUM7SUFDZixZQUFZLEVBQUUsRUFBRSxDQUFDO0lBQ2pCLE9BQU8sRUFBRSxFQUFFLENBQUM7SUFDWixRQUFRLEVBQUUsRUFBRSxDQUFDO0lBQ2IsT0FBTyxFQUFFLGdCQUFnQixFQUFFLENBQUM7SUFDNUIsS0FBSyxFQUFFLEtBQUssQ0FBQztDQUNkLENBQUM7QUFFRixxQkFBYSxtQkFBbUI7SUFDOUIsT0FBTyxDQUFDLE9BQU8sQ0FBNkI7SUFFNUMsU0FBUyxDQUFDLEdBQUcsRUFBRSxNQUFNLENBQUM7SUFFdEIsU0FBUyxDQUFDLGNBQWMsRUFBRSxjQUFjLENBQUM7SUFFekMsU0FBUyxDQUFDLHFCQUFxQixFQUFFLEdBQUcsQ0FBQztJQUVyQyxTQUFnQixTQUFTLEVBQUUsU0FBUyxDQUFDO0lBRXJDLFlBQ0UsTUFBTSxFQUFFLGNBQWMsR0FBRyxlQUFlLEVBQ3hDLElBQUksRUFBRTtRQUNKLGNBQWMsRUFBRSxjQUFjLENBQUM7UUFDL0IsU0FBUyxFQUFFLFNBQVMsQ0FBQztRQUNyQixxQkFBcUIsQ0FBQyxFQUFFLFVBQVUsQ0FBQztRQUNuQyxTQUFTLENBQUMsRUFBRSxlQUFlLENBQUM7S0FDN0IsRUFDRCxRQUFRLENBQUMsRUFBRSxjQUFjLEVBVTFCO0lBRU0saUJBQWlCLG1CQUV2QjtJQUVNLGdCQUFnQixlQUV0QjtJQUVZLGdCQUFnQixDQUFDLElBQUksRUFBRTtRQUNsQyxXQUFXLEVBQUUsV0FBVyxDQUFDO1FBQ3pCLGNBQWMsRUFBRSxnQkFBZ0IsQ0FBQztRQUNqQyxZQUFZLEVBQUUsZ0JBQWdCLENBQUM7UUFDL0IsWUFBWSxFQUFFLHNCQUFzQixDQUFDO1FBQ3JDLEtBQUssRUFBRSxLQUFLLENBQUM7UUFDYixpQkFBaUIsRUFBRSxXQUFXLENBQUM7UUFDL0IsWUFBWSxFQUFFLHdCQUF3QixFQUFFLENBQUM7UUFDekMsT0FBTyxFQUFFLGdCQUFnQixFQUFFLENBQUM7UUFDNUIsbUdBQW1HO1FBQ25HLFFBQVEsQ0FBQyxFQUFFLElBQUksQ0FBQztLQUNqQixHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0E2Q25CO1lBRWEsNEJBQTRCO0lBb0UxQzs7OztPQUlHO0lBQ1UsMkJBQTJCLENBQUMsSUFBSSxFQUFFO1FBQzdDLFdBQVcsRUFBRSxXQUFXLENBQUM7UUFDekIsY0FBYyxFQUFFLGdCQUFnQixDQUFDO1FBQ2pDLFlBQVksRUFBRSxnQkFBZ0IsQ0FBQztRQUMvQixZQUFZLEVBQUUsc0JBQXNCLENBQUM7UUFDckMsS0FBSyxFQUFFLEtBQUssQ0FBQztRQUNiLGlCQUFpQixFQUFFLFdBQVcsQ0FBQztRQUMvQixZQUFZLEVBQUUsd0JBQXdCLEVBQUUsQ0FBQztRQUN6QyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsQ0FBQztLQUM3QixHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FzQ2hCO0lBRUQsT0FBTyxDQUFDLDhCQUE4QjtZQWdCeEIsc0JBQXNCO0lBaURwQyxPQUFPLENBQUMsNkJBQTZCO0lBdUJyQyxPQUFPLENBQUMsdUJBQXVCO0NBd0JoQyJ9
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prover-node-publisher.d.ts","sourceRoot":"","sources":["../src/prover-node-publisher.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"prover-node-publisher.d.ts","sourceRoot":"","sources":["../src/prover-node-publisher.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,115 +1,103 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { getEthBlobEvaluationInputs } from '@aztec/blob-lib';
|
|
2
|
+
import { MAX_CHECKPOINTS_PER_EPOCH } from '@aztec/constants';
|
|
3
|
+
import { CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
3
4
|
import { areArraysEqual } from '@aztec/foundation/collection';
|
|
5
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
6
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
5
|
-
import { Fr } from '@aztec/foundation/fields';
|
|
6
7
|
import { createLogger } from '@aztec/foundation/log';
|
|
7
8
|
import { Timer } from '@aztec/foundation/timer';
|
|
8
9
|
import { RollupAbi } from '@aztec/l1-artifacts';
|
|
9
10
|
import { CommitteeAttestation, CommitteeAttestationsAndSigners } from '@aztec/stdlib/block';
|
|
10
11
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
11
12
|
import { inspect } from 'util';
|
|
12
|
-
import { encodeFunctionData } from 'viem';
|
|
13
|
+
import { encodeFunctionData, formatEther, formatGwei } from 'viem';
|
|
13
14
|
import { ProverNodePublisherMetrics } from './metrics.js';
|
|
14
15
|
export class ProverNodePublisher {
|
|
15
|
-
interrupted = false;
|
|
16
16
|
metrics;
|
|
17
|
-
log
|
|
17
|
+
log;
|
|
18
18
|
rollupContract;
|
|
19
|
+
proofSubmissionTarget;
|
|
19
20
|
l1TxUtils;
|
|
20
|
-
constructor(config, deps){
|
|
21
|
+
constructor(config, deps, bindings){
|
|
21
22
|
const telemetry = deps.telemetry ?? getTelemetryClient();
|
|
22
23
|
this.metrics = new ProverNodePublisherMetrics(telemetry, 'ProverNode');
|
|
24
|
+
this.log = createLogger('prover-node:l1-tx-publisher', bindings);
|
|
23
25
|
this.rollupContract = deps.rollupContract;
|
|
26
|
+
this.proofSubmissionTarget = deps.proofSubmissionTarget?.toString() ?? deps.rollupContract.address;
|
|
24
27
|
this.l1TxUtils = deps.l1TxUtils;
|
|
25
28
|
}
|
|
26
29
|
getRollupContract() {
|
|
27
30
|
return this.rollupContract;
|
|
28
31
|
}
|
|
29
|
-
/**
|
|
30
|
-
* Calling `interrupt` will cause any in progress call to `publishRollup` to return `false` asap.
|
|
31
|
-
* Be warned, the call may return false even if the tx subsequently gets successfully mined.
|
|
32
|
-
* In practice this shouldn't matter, as we'll only ever be calling `interrupt` when we know it's going to fail.
|
|
33
|
-
* A call to `restart` is required before you can continue publishing.
|
|
34
|
-
*/ interrupt() {
|
|
35
|
-
this.interrupted = true;
|
|
36
|
-
this.l1TxUtils.interrupt();
|
|
37
|
-
}
|
|
38
|
-
/** Restarts the publisher after calling `interrupt`. */ restart() {
|
|
39
|
-
this.interrupted = false;
|
|
40
|
-
this.l1TxUtils.restart();
|
|
41
|
-
}
|
|
42
32
|
getSenderAddress() {
|
|
43
33
|
return this.l1TxUtils.getSenderAddress();
|
|
44
34
|
}
|
|
45
35
|
async submitEpochProof(args) {
|
|
46
|
-
const { epochNumber,
|
|
36
|
+
const { epochNumber, fromCheckpoint, toCheckpoint } = args;
|
|
47
37
|
const ctx = {
|
|
48
38
|
epochNumber,
|
|
49
|
-
|
|
50
|
-
|
|
39
|
+
fromCheckpoint,
|
|
40
|
+
toCheckpoint
|
|
51
41
|
};
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
this.metrics.recordFailedTx();
|
|
87
|
-
this.log.error(`Rollup.submitEpochProof tx status failed ${txReceipt.transactionHash}`, undefined, ctx);
|
|
42
|
+
const timer = new Timer();
|
|
43
|
+
// Validate epoch proof range and hashes are correct before submitting
|
|
44
|
+
await this.validateEpochProofSubmission(args);
|
|
45
|
+
const txReceipt = await this.sendSubmitEpochProofTx(args);
|
|
46
|
+
if (!txReceipt) {
|
|
47
|
+
this.log.error(`Failed to mine submitEpochProof tx`, undefined, ctx);
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
this.metrics.recordSenderBalance(await this.l1TxUtils.getSenderBalance(), this.l1TxUtils.getSenderAddress().toString());
|
|
52
|
+
} catch (err) {
|
|
53
|
+
this.log.warn(`Failed to record the ETH balance of the prover node: ${err}`);
|
|
54
|
+
}
|
|
55
|
+
// Tx was mined successfully
|
|
56
|
+
if (txReceipt.status === 'success') {
|
|
57
|
+
const tx = await this.l1TxUtils.getTransactionStats(txReceipt.transactionHash);
|
|
58
|
+
const stats = {
|
|
59
|
+
gasPrice: txReceipt.effectiveGasPrice,
|
|
60
|
+
gasUsed: txReceipt.gasUsed,
|
|
61
|
+
transactionHash: txReceipt.transactionHash,
|
|
62
|
+
calldataGas: tx.calldataGas,
|
|
63
|
+
calldataSize: tx.calldataSize,
|
|
64
|
+
sender: tx.sender,
|
|
65
|
+
blobDataGas: 0n,
|
|
66
|
+
blobGasUsed: 0n,
|
|
67
|
+
eventName: 'proof-published-to-l1'
|
|
68
|
+
};
|
|
69
|
+
this.log.info(`Published epoch proof to L1 rollup contract`, {
|
|
70
|
+
...stats,
|
|
71
|
+
...ctx
|
|
72
|
+
});
|
|
73
|
+
this.metrics.recordSubmitProof(timer.ms(), stats);
|
|
74
|
+
return true;
|
|
88
75
|
}
|
|
89
|
-
this.
|
|
76
|
+
this.metrics.recordFailedTx();
|
|
77
|
+
this.log.error(`Rollup submitEpochProof tx reverted ${txReceipt.transactionHash}`, undefined, ctx);
|
|
90
78
|
return false;
|
|
91
79
|
}
|
|
92
80
|
async validateEpochProofSubmission(args) {
|
|
93
|
-
const {
|
|
94
|
-
// Check that the
|
|
95
|
-
const {
|
|
96
|
-
// Don't publish if proven is beyond our
|
|
97
|
-
if (proven >
|
|
98
|
-
throw new Error(`Cannot submit epoch proof for ${
|
|
81
|
+
const { fromCheckpoint, toCheckpoint, publicInputs, batchedBlobInputs } = args;
|
|
82
|
+
// Check that the checkpoint numbers match the expected epoch to be proven
|
|
83
|
+
const { pending, proven } = await this.rollupContract.getTips();
|
|
84
|
+
// Don't publish if proven is beyond our toCheckpoint, pointless to do so
|
|
85
|
+
if (proven > toCheckpoint) {
|
|
86
|
+
throw new Error(`Cannot submit epoch proof for ${fromCheckpoint}-${toCheckpoint} as proven checkpoint is ${proven}`);
|
|
99
87
|
}
|
|
100
|
-
//
|
|
101
|
-
if (
|
|
102
|
-
throw new Error(`Cannot submit epoch proof for ${
|
|
88
|
+
// toCheckpoint can't be greater than pending
|
|
89
|
+
if (toCheckpoint > pending) {
|
|
90
|
+
throw new Error(`Cannot submit epoch proof for ${fromCheckpoint}-${toCheckpoint} as proposed checkpoint is ${pending}`);
|
|
103
91
|
}
|
|
104
|
-
// Check the archive for the immediate
|
|
105
|
-
const
|
|
106
|
-
if (publicInputs.previousArchiveRoot.
|
|
107
|
-
throw new Error(`Previous archive root mismatch: ${publicInputs.previousArchiveRoot.toString()} !== ${
|
|
92
|
+
// Check the archive for the immediate checkpoint before the epoch
|
|
93
|
+
const checkpointLog = await this.rollupContract.getCheckpoint(CheckpointNumber(fromCheckpoint - 1));
|
|
94
|
+
if (!publicInputs.previousArchiveRoot.equals(checkpointLog.archive)) {
|
|
95
|
+
throw new Error(`Previous archive root mismatch: ${publicInputs.previousArchiveRoot.toString()} !== ${checkpointLog.archive.toString()}`);
|
|
108
96
|
}
|
|
109
|
-
// Check the archive for the last
|
|
110
|
-
const
|
|
111
|
-
if (publicInputs.endArchiveRoot.
|
|
112
|
-
throw new Error(`End archive root mismatch: ${publicInputs.endArchiveRoot.toString()} !== ${
|
|
97
|
+
// Check the archive for the last checkpoint in the epoch
|
|
98
|
+
const endCheckpointLog = await this.rollupContract.getCheckpoint(toCheckpoint);
|
|
99
|
+
if (!publicInputs.endArchiveRoot.equals(endCheckpointLog.archive)) {
|
|
100
|
+
throw new Error(`End archive root mismatch: ${publicInputs.endArchiveRoot.toString()} !== ${endCheckpointLog.archive.toString()}`);
|
|
113
101
|
}
|
|
114
102
|
// Check the batched blob inputs from the root rollup against the batched blob computed in ts
|
|
115
103
|
const finalBlobAccumulator = batchedBlobInputs.toFinalBlobAccumulator();
|
|
@@ -121,19 +109,74 @@ export class ProverNodePublisher {
|
|
|
121
109
|
const argsPublicInputs = [
|
|
122
110
|
...publicInputs.toFields()
|
|
123
111
|
];
|
|
124
|
-
if (!areArraysEqual(rollupPublicInputs
|
|
125
|
-
|
|
126
|
-
|
|
112
|
+
if (!areArraysEqual(rollupPublicInputs, argsPublicInputs, (a, b)=>a.equals(b))) {
|
|
113
|
+
throw await reportPublicInputsMismatch({
|
|
114
|
+
rollupPublicInputs,
|
|
115
|
+
argsPublicInputs,
|
|
116
|
+
fromCheckpoint,
|
|
117
|
+
toCheckpoint,
|
|
118
|
+
rollupContract: this.rollupContract,
|
|
119
|
+
log: this.log
|
|
120
|
+
});
|
|
127
121
|
}
|
|
128
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* Estimates what submitting the epoch proof would have cost on L1 without actually sending it.
|
|
125
|
+
* Runs the same validation as `submitEpochProof`, encodes the calldata, estimates gas, and records metrics.
|
|
126
|
+
* Used when proof publishing is disabled (e.g. PROVER_NODE_DISABLE_PROOF_PUBLISH=true on mainnet).
|
|
127
|
+
*/ async analyzeEpochProofSubmission(args) {
|
|
128
|
+
const { epochNumber, fromCheckpoint, toCheckpoint } = args;
|
|
129
|
+
await this.validateEpochProofSubmission(args);
|
|
130
|
+
const data = this.encodeSubmitEpochProofCalldata(args);
|
|
131
|
+
const senderAddress = this.l1TxUtils.getSenderAddress();
|
|
132
|
+
const [gasLimit, gasPrice, latestBlock] = await Promise.all([
|
|
133
|
+
this.l1TxUtils.estimateGas(senderAddress.toString(), {
|
|
134
|
+
to: this.proofSubmissionTarget,
|
|
135
|
+
data
|
|
136
|
+
}),
|
|
137
|
+
this.l1TxUtils.getGasPrice(),
|
|
138
|
+
this.l1TxUtils.client.getBlock({
|
|
139
|
+
blockTag: 'latest'
|
|
140
|
+
})
|
|
141
|
+
]);
|
|
142
|
+
const baseFeePerGas = latestBlock.baseFeePerGas ?? 0n;
|
|
143
|
+
const { maxPriorityFeePerGas } = gasPrice;
|
|
144
|
+
const effectiveFeePerGas = baseFeePerGas + maxPriorityFeePerGas;
|
|
145
|
+
const estimatedTotalFee = gasLimit * effectiveFeePerGas;
|
|
146
|
+
const stats = {
|
|
147
|
+
gasLimit,
|
|
148
|
+
baseFeePerGas,
|
|
149
|
+
maxPriorityFeePerGas,
|
|
150
|
+
estimatedTotalFee
|
|
151
|
+
};
|
|
152
|
+
this.log.info(`Estimated epoch proof submission cost (not submitted)`, {
|
|
153
|
+
epochNumber,
|
|
154
|
+
fromCheckpoint,
|
|
155
|
+
toCheckpoint,
|
|
156
|
+
gasLimit: gasLimit.toString(),
|
|
157
|
+
baseFeePerGas: formatGwei(baseFeePerGas),
|
|
158
|
+
maxPriorityFeePerGas: formatGwei(maxPriorityFeePerGas),
|
|
159
|
+
estimatedTotalFeeEth: formatEther(estimatedTotalFee)
|
|
160
|
+
});
|
|
161
|
+
this.metrics.recordEstimatedSubmitProof(stats);
|
|
162
|
+
}
|
|
163
|
+
encodeSubmitEpochProofCalldata(args) {
|
|
164
|
+
return encodeFunctionData({
|
|
165
|
+
abi: RollupAbi,
|
|
166
|
+
functionName: 'submitEpochRootProof',
|
|
167
|
+
args: [
|
|
168
|
+
this.getSubmitEpochProofArgs(args)
|
|
169
|
+
]
|
|
170
|
+
});
|
|
171
|
+
}
|
|
129
172
|
async sendSubmitEpochProofTx(args) {
|
|
130
173
|
const txArgs = [
|
|
131
174
|
this.getSubmitEpochProofArgs(args)
|
|
132
175
|
];
|
|
133
176
|
this.log.info(`Submitting epoch proof to L1 rollup contract`, {
|
|
134
177
|
proofSize: args.proof.withoutPublicInputs().length,
|
|
135
|
-
|
|
136
|
-
|
|
178
|
+
fromCheckpoint: args.fromCheckpoint,
|
|
179
|
+
toCheckpoint: args.toCheckpoint
|
|
137
180
|
});
|
|
138
181
|
const data = encodeFunctionData({
|
|
139
182
|
abi: RollupAbi,
|
|
@@ -142,36 +185,42 @@ export class ProverNodePublisher {
|
|
|
142
185
|
});
|
|
143
186
|
try {
|
|
144
187
|
const { receipt } = await this.l1TxUtils.sendAndMonitorTransaction({
|
|
145
|
-
to: this.
|
|
188
|
+
to: this.proofSubmissionTarget,
|
|
146
189
|
data
|
|
190
|
+
}, {
|
|
191
|
+
txTimeoutAt: args.deadline
|
|
147
192
|
});
|
|
193
|
+
if (receipt.status !== 'success') {
|
|
194
|
+
const errorMsg = await this.l1TxUtils.tryGetErrorFromRevertedTx(data, {
|
|
195
|
+
args: [
|
|
196
|
+
...txArgs
|
|
197
|
+
],
|
|
198
|
+
functionName: 'submitEpochRootProof',
|
|
199
|
+
abi: RollupAbi,
|
|
200
|
+
address: this.proofSubmissionTarget
|
|
201
|
+
}, /*blobInputs*/ undefined, /*stateOverride*/ []);
|
|
202
|
+
this.log.error(`Rollup submit epoch proof tx reverted with ${errorMsg ?? 'unknown error'}`);
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
148
205
|
return receipt;
|
|
149
206
|
} catch (err) {
|
|
150
207
|
this.log.error(`Rollup submit epoch proof failed`, err);
|
|
151
|
-
const errorMsg = await this.l1TxUtils.tryGetErrorFromRevertedTx(data, {
|
|
152
|
-
args: [
|
|
153
|
-
...txArgs
|
|
154
|
-
],
|
|
155
|
-
functionName: 'submitEpochRootProof',
|
|
156
|
-
abi: RollupAbi,
|
|
157
|
-
address: this.rollupContract.address
|
|
158
|
-
}, /*blobInputs*/ undefined, /*stateOverride*/ []);
|
|
159
|
-
this.log.error(`Rollup submit epoch proof tx reverted. ${errorMsg}`);
|
|
160
208
|
return undefined;
|
|
161
209
|
}
|
|
162
210
|
}
|
|
163
211
|
getEpochProofPublicInputsArgs(args) {
|
|
164
212
|
// Returns arguments for EpochProofLib.sol -> getEpochProofPublicInputs()
|
|
165
213
|
return [
|
|
166
|
-
BigInt(args.
|
|
167
|
-
BigInt(args.
|
|
214
|
+
BigInt(args.fromCheckpoint),
|
|
215
|
+
BigInt(args.toCheckpoint),
|
|
168
216
|
{
|
|
169
217
|
previousArchive: args.publicInputs.previousArchiveRoot.toString(),
|
|
170
218
|
endArchive: args.publicInputs.endArchiveRoot.toString(),
|
|
219
|
+
outHash: args.publicInputs.outHash.toString(),
|
|
171
220
|
proverId: EthAddress.fromField(args.publicInputs.constants.proverId).toString()
|
|
172
221
|
} /*_args*/ ,
|
|
173
|
-
|
|
174
|
-
args.batchedBlobInputs
|
|
222
|
+
args.headers.map((header)=>header.toViem()),
|
|
223
|
+
getEthBlobEvaluationInputs(args.batchedBlobInputs)
|
|
175
224
|
];
|
|
176
225
|
}
|
|
177
226
|
getSubmitEpochProofArgs(args) {
|
|
@@ -182,10 +231,107 @@ export class ProverNodePublisher {
|
|
|
182
231
|
start: argsArray[0],
|
|
183
232
|
end: argsArray[1],
|
|
184
233
|
args: argsArray[2],
|
|
185
|
-
|
|
186
|
-
attestations:
|
|
234
|
+
headers: argsArray[3],
|
|
235
|
+
attestations: CommitteeAttestationsAndSigners.packAttestations(args.attestations.map((a)=>CommitteeAttestation.fromViem(a))),
|
|
187
236
|
blobInputs: argsArray[4],
|
|
188
237
|
proof: proofHex
|
|
189
238
|
};
|
|
190
239
|
}
|
|
191
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* Decodes a `Root rollup public inputs mismatch`, fetches the on-chain CheckpointLog for any
|
|
243
|
+
* mismatching `checkpointHeaderHashes[i]`, emits a structured error log, and returns a thrown-ready
|
|
244
|
+
* Error with a human-readable summary.
|
|
245
|
+
*
|
|
246
|
+
* Layout of `RootRollupPublicInputs.toFields()`:
|
|
247
|
+
* [0] previousArchiveRoot
|
|
248
|
+
* [1] endArchiveRoot
|
|
249
|
+
* [2] outHash
|
|
250
|
+
* [3 .. 3+N-1] checkpointHeaderHashes[i] for i in 0..N-1 (N = MAX_CHECKPOINTS_PER_EPOCH)
|
|
251
|
+
* [3+N .. 3+3N-1] fees[i] = (recipient, value) for i in 0..N-1
|
|
252
|
+
* [3+3N .. 3+3N+4] EpochConstantData (chainId, version, vkTreeRoot, protocolContractsHash, proverId)
|
|
253
|
+
* [3+3N+5 ..] blobPublicInputs (FinalBlobAccumulator)
|
|
254
|
+
*/ async function reportPublicInputsMismatch(input) {
|
|
255
|
+
const { rollupPublicInputs, argsPublicInputs, fromCheckpoint, toCheckpoint, rollupContract, log } = input;
|
|
256
|
+
const N = MAX_CHECKPOINTS_PER_EPOCH;
|
|
257
|
+
const constantsStart = 3 + 3 * N;
|
|
258
|
+
const blobStart = constantsStart + 5;
|
|
259
|
+
const constantLabels = [
|
|
260
|
+
'chainId',
|
|
261
|
+
'version',
|
|
262
|
+
'vkTreeRoot',
|
|
263
|
+
'protocolContractsHash',
|
|
264
|
+
'proverId'
|
|
265
|
+
];
|
|
266
|
+
const diffs = [];
|
|
267
|
+
const len = Math.max(rollupPublicInputs.length, argsPublicInputs.length);
|
|
268
|
+
for(let i = 0; i < len; i++){
|
|
269
|
+
const a = rollupPublicInputs[i] ?? Fr.ZERO;
|
|
270
|
+
const b = argsPublicInputs[i] ?? Fr.ZERO;
|
|
271
|
+
if (a.equals(b)) {
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
let label;
|
|
275
|
+
let checkpointIndex;
|
|
276
|
+
if (i === 0) {
|
|
277
|
+
label = 'previousArchiveRoot';
|
|
278
|
+
} else if (i === 1) {
|
|
279
|
+
label = 'endArchiveRoot';
|
|
280
|
+
} else if (i === 2) {
|
|
281
|
+
label = 'outHash';
|
|
282
|
+
} else if (i < 3 + N) {
|
|
283
|
+
checkpointIndex = i - 3;
|
|
284
|
+
label = `checkpointHeaderHashes[${checkpointIndex}]`;
|
|
285
|
+
} else if (i < 3 + 3 * N) {
|
|
286
|
+
const feePairIndex = i - (3 + N);
|
|
287
|
+
const feeIndex = Math.floor(feePairIndex / 2);
|
|
288
|
+
const sub = feePairIndex % 2 === 0 ? 'recipient' : 'value';
|
|
289
|
+
label = `fees[${feeIndex}].${sub}`;
|
|
290
|
+
} else if (i < blobStart) {
|
|
291
|
+
label = `constants.${constantLabels[i - constantsStart]}`;
|
|
292
|
+
} else {
|
|
293
|
+
label = `blobPublicInputs[${i - blobStart}]`;
|
|
294
|
+
}
|
|
295
|
+
diffs.push({
|
|
296
|
+
index: i,
|
|
297
|
+
label,
|
|
298
|
+
rollup: a,
|
|
299
|
+
computed: b,
|
|
300
|
+
checkpointIndex
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
// For each mismatching checkpointHeaderHash, fetch the L1 CheckpointLog so the operator can
|
|
304
|
+
// see what was published on-chain alongside the prover's recomputed hash.
|
|
305
|
+
const onChainCheckpoints = await Promise.all(diffs.filter((d)=>d.checkpointIndex !== undefined).map(async (d)=>{
|
|
306
|
+
const checkpointNumber = CheckpointNumber(fromCheckpoint + d.checkpointIndex);
|
|
307
|
+
try {
|
|
308
|
+
const cp = await rollupContract.getCheckpoint(checkpointNumber);
|
|
309
|
+
return {
|
|
310
|
+
checkpointIndex: d.checkpointIndex,
|
|
311
|
+
checkpointNumber,
|
|
312
|
+
headerHash: cp.headerHash.toString()
|
|
313
|
+
};
|
|
314
|
+
} catch (err) {
|
|
315
|
+
return {
|
|
316
|
+
checkpointIndex: d.checkpointIndex,
|
|
317
|
+
checkpointNumber,
|
|
318
|
+
error: err.message
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
}));
|
|
322
|
+
log.error(`Root rollup public inputs mismatch`, undefined, {
|
|
323
|
+
fromCheckpoint,
|
|
324
|
+
toCheckpoint,
|
|
325
|
+
numDiffs: diffs.length,
|
|
326
|
+
diffs: diffs.map((d)=>({
|
|
327
|
+
index: d.index,
|
|
328
|
+
label: d.label,
|
|
329
|
+
rollup: d.rollup.toString(),
|
|
330
|
+
computed: d.computed.toString()
|
|
331
|
+
})),
|
|
332
|
+
onChainCheckpoints
|
|
333
|
+
});
|
|
334
|
+
const fmt = (inputs)=>inputs.map((x)=>x.toString()).join(', ');
|
|
335
|
+
const summary = diffs.map((d)=>`[${d.index} ${d.label}] L1=${d.rollup} prover=${d.computed}`).join('\n');
|
|
336
|
+
return new Error(`Root rollup public inputs mismatch (${diffs.length} fields differ):\n${summary}\n` + `Rollup: ${fmt(rollupPublicInputs)}\nComputed:${fmt(argsPublicInputs)}`);
|
|
337
|
+
}
|