@aztec/prover-node 0.0.1-commit.2ed92850 → 0.0.1-commit.2f68f620
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/actions/download-epoch-proving-job.js +1 -1
- package/dest/actions/rerun-epoch-proving-job.d.ts +4 -3
- package/dest/actions/rerun-epoch-proving-job.d.ts.map +1 -1
- package/dest/actions/rerun-epoch-proving-job.js +105 -27
- 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.js +6 -5
- package/dest/config.d.ts +7 -8
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +23 -19
- package/dest/factory.d.ts +19 -13
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +41 -60
- package/dest/job/epoch-proving-job.d.ts +7 -2
- package/dest/job/epoch-proving-job.d.ts.map +1 -1
- package/dest/job/epoch-proving-job.js +212 -38
- package/dest/metrics.d.ts +21 -1
- package/dest/metrics.d.ts.map +1 -1
- package/dest/metrics.js +58 -3
- package/dest/monitors/epoch-monitor.d.ts +1 -1
- package/dest/monitors/epoch-monitor.d.ts.map +1 -1
- package/dest/monitors/epoch-monitor.js +11 -9
- package/dest/prover-node-publisher.d.ts +28 -5
- package/dest/prover-node-publisher.d.ts.map +1 -1
- package/dest/prover-node-publisher.js +209 -11
- package/dest/prover-node.d.ts +24 -14
- package/dest/prover-node.d.ts.map +1 -1
- package/dest/prover-node.js +93 -43
- package/dest/prover-publisher-factory.d.ts +9 -5
- package/dest/prover-publisher-factory.d.ts.map +1 -1
- package/dest/prover-publisher-factory.js +8 -5
- package/package.json +23 -22
- package/src/actions/download-epoch-proving-job.ts +1 -1
- package/src/actions/rerun-epoch-proving-job.ts +18 -6
- package/src/actions/upload-epoch-proof-failure.ts +1 -1
- package/src/bin/run-failed-epoch.ts +5 -3
- package/src/config.ts +33 -31
- package/src/factory.ts +69 -103
- package/src/job/epoch-proving-job.ts +145 -44
- package/src/metrics.ts +77 -2
- package/src/monitors/epoch-monitor.ts +5 -6
- package/src/prover-node-publisher.ts +245 -16
- package/src/prover-node.ts +100 -55
- package/src/prover-publisher-factory.ts +19 -10
package/src/factory.ts
CHANGED
|
@@ -1,34 +1,36 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import type { Archiver } from '@aztec/archiver';
|
|
2
|
+
import type { BlobClientInterface } from '@aztec/blob-client/client';
|
|
3
|
+
import { Blob } from '@aztec/blob-lib';
|
|
4
|
+
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
5
5
|
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
6
|
+
import { makeL1HttpTransport } from '@aztec/ethereum/client';
|
|
6
7
|
import { RollupContract } from '@aztec/ethereum/contracts';
|
|
7
8
|
import { L1TxUtils } from '@aztec/ethereum/l1-tx-utils';
|
|
8
9
|
import { PublisherManager } from '@aztec/ethereum/publisher-manager';
|
|
9
10
|
import { pick } from '@aztec/foundation/collection';
|
|
10
11
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
11
12
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
12
|
-
import
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
createForwarderL1TxUtilsFromEthSigner,
|
|
17
|
-
createL1TxUtilsFromEthSignerWithStore,
|
|
18
|
-
} from '@aztec/node-lib/factories';
|
|
19
|
-
import { NodeRpcTxSource, createP2PClient } from '@aztec/p2p';
|
|
20
|
-
import { type ProverClientConfig, createProverClient } from '@aztec/prover-client';
|
|
13
|
+
import { KeystoreManager } from '@aztec/node-keystore';
|
|
14
|
+
import { createForwarderL1TxUtilsFromSigners, createL1TxUtilsFromSigners } from '@aztec/node-lib/factories';
|
|
15
|
+
import { type ProverClientConfig, type ProverClientUserConfig, createProverClient } from '@aztec/prover-client';
|
|
21
16
|
import { createAndStartProvingBroker } from '@aztec/prover-client/broker';
|
|
22
|
-
import
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
17
|
+
import {
|
|
18
|
+
type ProverPublisherConfig,
|
|
19
|
+
type ProverTxSenderConfig,
|
|
20
|
+
getPublisherConfigFromProverConfig,
|
|
21
|
+
} from '@aztec/sequencer-client';
|
|
22
|
+
import type {
|
|
23
|
+
ITxProvider,
|
|
24
|
+
ProverConfig,
|
|
25
|
+
ProvingJobBroker,
|
|
26
|
+
Service,
|
|
27
|
+
WorldStateSynchronizer,
|
|
28
|
+
} from '@aztec/stdlib/interfaces/server';
|
|
26
29
|
import { L1Metrics, type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
27
|
-
import { createWorldStateSynchronizer } from '@aztec/world-state';
|
|
28
30
|
|
|
29
|
-
import { createPublicClient
|
|
31
|
+
import { createPublicClient } from 'viem';
|
|
30
32
|
|
|
31
|
-
import
|
|
33
|
+
import type { SpecificProverNodeConfig } from './config.js';
|
|
32
34
|
import { EpochMonitor } from './monitors/epoch-monitor.js';
|
|
33
35
|
import { ProverNode } from './prover-node.js';
|
|
34
36
|
import { ProverPublisherFactory } from './prover-publisher-factory.js';
|
|
@@ -36,54 +38,42 @@ import { ProverPublisherFactory } from './prover-publisher-factory.js';
|
|
|
36
38
|
export type ProverNodeDeps = {
|
|
37
39
|
telemetry?: TelemetryClient;
|
|
38
40
|
log?: Logger;
|
|
39
|
-
|
|
40
|
-
archiver?: Archiver;
|
|
41
|
+
archiver: Archiver;
|
|
41
42
|
publisherFactory?: ProverPublisherFactory;
|
|
42
43
|
broker?: ProvingJobBroker;
|
|
43
44
|
l1TxUtils?: L1TxUtils;
|
|
44
45
|
dateProvider?: DateProvider;
|
|
46
|
+
worldStateSynchronizer: WorldStateSynchronizer;
|
|
47
|
+
p2pClient: { getTxProvider(): ITxProvider } & Partial<Service>;
|
|
48
|
+
epochCache: EpochCacheInterface;
|
|
49
|
+
blobClient: BlobClientInterface;
|
|
50
|
+
keyStoreManager?: KeystoreManager;
|
|
45
51
|
};
|
|
46
52
|
|
|
47
|
-
/** Creates a new prover node given a config
|
|
53
|
+
/** Creates a new prover node subsystem given a config and dependencies */
|
|
48
54
|
export async function createProverNode(
|
|
49
|
-
userConfig:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
userConfig: SpecificProverNodeConfig &
|
|
56
|
+
ProverConfig &
|
|
57
|
+
ProverClientUserConfig &
|
|
58
|
+
ProverPublisherConfig &
|
|
59
|
+
ProverTxSenderConfig,
|
|
60
|
+
deps: ProverNodeDeps,
|
|
54
61
|
) {
|
|
55
62
|
const config = { ...userConfig };
|
|
56
63
|
const telemetry = deps.telemetry ?? getTelemetryClient();
|
|
57
64
|
const dateProvider = deps.dateProvider ?? new DateProvider();
|
|
58
|
-
const
|
|
59
|
-
const log = deps.log ?? createLogger('prover-node');
|
|
60
|
-
|
|
61
|
-
// Build a key store from file if given or from environment otherwise
|
|
62
|
-
let keyStoreManager: KeystoreManager | undefined;
|
|
63
|
-
const keyStoreProvided = config.keyStoreDirectory !== undefined && config.keyStoreDirectory.length > 0;
|
|
64
|
-
if (keyStoreProvided) {
|
|
65
|
-
const keyStores = loadKeystores(config.keyStoreDirectory!);
|
|
66
|
-
keyStoreManager = new KeystoreManager(mergeKeystores(keyStores));
|
|
67
|
-
} else {
|
|
68
|
-
const keyStore = createKeyStoreForProver(config);
|
|
69
|
-
if (keyStore) {
|
|
70
|
-
keyStoreManager = new KeystoreManager(keyStore);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
65
|
+
const log = deps.log ?? createLogger('prover');
|
|
73
66
|
|
|
74
|
-
|
|
67
|
+
const { p2pClient, archiver, keyStoreManager, worldStateSynchronizer } = deps;
|
|
75
68
|
|
|
76
69
|
// Extract the prover signers from the key store and verify that we have one.
|
|
70
|
+
await keyStoreManager?.validateSigners();
|
|
77
71
|
const proverSigners = keyStoreManager?.createProverSigners();
|
|
78
72
|
|
|
79
73
|
if (proverSigners === undefined) {
|
|
80
74
|
throw new Error('Failed to create prover key store configuration');
|
|
81
75
|
} else if (proverSigners.signers.length === 0) {
|
|
82
76
|
throw new Error('No prover signers found in the key store');
|
|
83
|
-
} else if (!keyStoreProvided) {
|
|
84
|
-
log.warn(
|
|
85
|
-
'KEY STORE CREATED FROM ENVIRONMENT, IT IS RECOMMENDED TO USE A FILE-BASED KEY STORE IN PRODUCTION ENVIRONMENTS',
|
|
86
|
-
);
|
|
87
77
|
}
|
|
88
78
|
|
|
89
79
|
log.info(`Creating prover with publishers ${proverSigners.signers.map(signer => signer.address.toString()).join()}`);
|
|
@@ -95,27 +85,7 @@ export async function createProverNode(
|
|
|
95
85
|
const proverId = proverSigners.id ?? proverIdInUserConfig ?? proverSigners.signers[0].address;
|
|
96
86
|
|
|
97
87
|
// Now create the prover client configuration from this.
|
|
98
|
-
const proverClientConfig: ProverClientConfig = {
|
|
99
|
-
...config,
|
|
100
|
-
proverId,
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
await trySnapshotSync(config, log);
|
|
104
|
-
|
|
105
|
-
const epochCache = await EpochCache.create(config.l1Contracts.rollupAddress, config);
|
|
106
|
-
|
|
107
|
-
const archiver =
|
|
108
|
-
deps.archiver ??
|
|
109
|
-
(await createArchiver(config, { blobClient, epochCache, telemetry, dateProvider }, { blockUntilSync: true }));
|
|
110
|
-
log.verbose(`Created archiver and synced to block ${await archiver.getBlockNumber()}`);
|
|
111
|
-
|
|
112
|
-
const worldStateSynchronizer = await createWorldStateSynchronizer(
|
|
113
|
-
config,
|
|
114
|
-
archiver,
|
|
115
|
-
options.prefilledPublicData,
|
|
116
|
-
telemetry,
|
|
117
|
-
);
|
|
118
|
-
await worldStateSynchronizer.start();
|
|
88
|
+
const proverClientConfig: ProverClientConfig = { ...config, proverId };
|
|
119
89
|
|
|
120
90
|
const broker = deps.broker ?? (await createAndStartProvingBroker(config, telemetry));
|
|
121
91
|
|
|
@@ -126,63 +96,54 @@ export async function createProverNode(
|
|
|
126
96
|
|
|
127
97
|
const publicClient = createPublicClient({
|
|
128
98
|
chain: chain.chainInfo,
|
|
129
|
-
transport:
|
|
99
|
+
transport: makeL1HttpTransport(config.l1RpcUrls, { timeout: config.l1HttpTimeoutMS }),
|
|
130
100
|
pollingInterval: config.viemPollingIntervalMS,
|
|
131
101
|
});
|
|
132
102
|
|
|
133
|
-
const rollupContract = new RollupContract(publicClient, config.
|
|
103
|
+
const rollupContract = new RollupContract(publicClient, config.rollupAddress.toString());
|
|
134
104
|
|
|
135
105
|
const l1TxUtils = deps.l1TxUtils
|
|
136
106
|
? [deps.l1TxUtils]
|
|
137
|
-
: config.
|
|
138
|
-
? await
|
|
107
|
+
: config.proverPublisherForwarderAddress
|
|
108
|
+
? await createForwarderL1TxUtilsFromSigners(
|
|
139
109
|
publicClient,
|
|
140
110
|
proverSigners.signers,
|
|
141
|
-
config.
|
|
111
|
+
config.proverPublisherForwarderAddress,
|
|
142
112
|
{ ...config, scope: 'prover' },
|
|
143
|
-
{ telemetry, logger: log.createChild('l1-tx-utils'), dateProvider },
|
|
113
|
+
{ telemetry, logger: log.createChild('l1-tx-utils'), dateProvider, kzg: Blob.getViemKzgInstance() },
|
|
144
114
|
)
|
|
145
|
-
: await
|
|
115
|
+
: await createL1TxUtilsFromSigners(
|
|
146
116
|
publicClient,
|
|
147
117
|
proverSigners.signers,
|
|
148
118
|
{ ...config, scope: 'prover' },
|
|
149
119
|
{ telemetry, logger: log.createChild('l1-tx-utils'), dateProvider },
|
|
150
120
|
);
|
|
151
121
|
|
|
122
|
+
// Create a funder L1TxUtils from the keystore funding account (if configured)
|
|
123
|
+
const fundingSigner = keyStoreManager?.createFundingSigner();
|
|
124
|
+
let funderL1TxUtils: L1TxUtils | undefined;
|
|
125
|
+
if (fundingSigner) {
|
|
126
|
+
const [funder] = await createL1TxUtilsFromSigners(
|
|
127
|
+
publicClient,
|
|
128
|
+
[fundingSigner],
|
|
129
|
+
{ ...config, scope: 'prover' },
|
|
130
|
+
{ telemetry, logger: log.createChild('l1-tx-utils:funder'), dateProvider },
|
|
131
|
+
);
|
|
132
|
+
funderL1TxUtils = funder;
|
|
133
|
+
}
|
|
134
|
+
|
|
152
135
|
const publisherFactory =
|
|
153
136
|
deps.publisherFactory ??
|
|
154
137
|
new ProverPublisherFactory(config, {
|
|
155
138
|
rollupContract,
|
|
156
|
-
|
|
139
|
+
proofSubmissionTarget: config.proofSubmissionTargetAddress,
|
|
140
|
+
publisherManager: new PublisherManager(l1TxUtils, getPublisherConfigFromProverConfig(config), {
|
|
141
|
+
bindings: log.getBindings(),
|
|
142
|
+
funder: funderL1TxUtils,
|
|
143
|
+
}),
|
|
157
144
|
telemetry,
|
|
158
145
|
});
|
|
159
146
|
|
|
160
|
-
const proofVerifier = new QueuedIVCVerifier(
|
|
161
|
-
config,
|
|
162
|
-
config.realProofs || config.debugForceTxProofVerification
|
|
163
|
-
? await BBCircuitVerifier.new(config)
|
|
164
|
-
: new TestCircuitVerifier(config.proverTestVerificationDelayMs),
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
const p2pClient = await createP2PClient(
|
|
168
|
-
P2PClientType.Prover,
|
|
169
|
-
config,
|
|
170
|
-
archiver,
|
|
171
|
-
proofVerifier,
|
|
172
|
-
worldStateSynchronizer,
|
|
173
|
-
epochCache,
|
|
174
|
-
getPackageVersion() ?? '',
|
|
175
|
-
dateProvider,
|
|
176
|
-
telemetry,
|
|
177
|
-
{
|
|
178
|
-
txCollectionNodeSources: deps.aztecNodeTxProvider
|
|
179
|
-
? [new NodeRpcTxSource(deps.aztecNodeTxProvider, 'TestNode')]
|
|
180
|
-
: [],
|
|
181
|
-
},
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
await p2pClient.start();
|
|
185
|
-
|
|
186
147
|
const proverNodeConfig = {
|
|
187
148
|
...pick(
|
|
188
149
|
config,
|
|
@@ -213,6 +174,9 @@ export async function createProverNode(
|
|
|
213
174
|
l1TxUtils.map(utils => utils.getSenderAddress()),
|
|
214
175
|
);
|
|
215
176
|
|
|
177
|
+
// Extract the shared delayer from the first L1TxUtils instance (all instances share the same delayer)
|
|
178
|
+
const delayer = l1TxUtils[0]?.delayer;
|
|
179
|
+
|
|
216
180
|
return new ProverNode(
|
|
217
181
|
prover,
|
|
218
182
|
publisherFactory,
|
|
@@ -226,5 +190,7 @@ export async function createProverNode(
|
|
|
226
190
|
l1Metrics,
|
|
227
191
|
proverNodeConfig,
|
|
228
192
|
telemetry,
|
|
193
|
+
delayer,
|
|
194
|
+
dateProvider,
|
|
229
195
|
);
|
|
230
196
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
|
|
2
1
|
import { asyncPool } from '@aztec/foundation/async-pool';
|
|
3
2
|
import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
4
|
-
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
5
3
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
6
|
-
import { createLogger } from '@aztec/foundation/log';
|
|
4
|
+
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
7
5
|
import { RunningPromise, promiseWithResolvers } from '@aztec/foundation/promise';
|
|
8
6
|
import { Timer } from '@aztec/foundation/timer';
|
|
7
|
+
import { AVM_MAX_CONCURRENT_SIMULATIONS } from '@aztec/native';
|
|
9
8
|
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
10
9
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
11
10
|
import { buildFinalBlobChallenges } from '@aztec/prover-client/helpers';
|
|
@@ -19,8 +18,8 @@ import {
|
|
|
19
18
|
EpochProvingJobTerminalState,
|
|
20
19
|
type ForkMerkleTreeOperations,
|
|
21
20
|
} from '@aztec/stdlib/interfaces/server';
|
|
21
|
+
import { appendL1ToL2MessagesToTree } from '@aztec/stdlib/messaging';
|
|
22
22
|
import { CheckpointConstantData } from '@aztec/stdlib/rollup';
|
|
23
|
-
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
24
23
|
import type { ProcessedTx, Tx } from '@aztec/stdlib/tx';
|
|
25
24
|
import { Attributes, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
|
|
26
25
|
|
|
@@ -43,10 +42,11 @@ export type EpochProvingJobOptions = {
|
|
|
43
42
|
*/
|
|
44
43
|
export class EpochProvingJob implements Traceable {
|
|
45
44
|
private state: EpochProvingJobState = 'initialized';
|
|
46
|
-
private log
|
|
45
|
+
private log: Logger;
|
|
47
46
|
private uuid: string;
|
|
48
47
|
|
|
49
48
|
private runPromise: Promise<void> | undefined;
|
|
49
|
+
private abortController = new AbortController();
|
|
50
50
|
private epochCheckPromise: RunningPromise | undefined;
|
|
51
51
|
private deadlineTimeoutHandler: NodeJS.Timeout | undefined;
|
|
52
52
|
|
|
@@ -57,14 +57,19 @@ export class EpochProvingJob implements Traceable {
|
|
|
57
57
|
private dbProvider: Pick<ForkMerkleTreeOperations, 'fork'>,
|
|
58
58
|
private prover: EpochProver,
|
|
59
59
|
private publicProcessorFactory: PublicProcessorFactory,
|
|
60
|
-
private publisher: Pick<ProverNodePublisher, 'submitEpochProof'>,
|
|
60
|
+
private publisher: Pick<ProverNodePublisher, 'submitEpochProof' | 'analyzeEpochProofSubmission'>,
|
|
61
61
|
private l2BlockSource: L2BlockSource | undefined,
|
|
62
62
|
private metrics: ProverNodeJobMetrics,
|
|
63
63
|
private deadline: Date | undefined,
|
|
64
64
|
private config: EpochProvingJobOptions,
|
|
65
|
+
bindings?: LoggerBindings,
|
|
65
66
|
) {
|
|
66
67
|
validateEpochProvingJobData(data);
|
|
67
68
|
this.uuid = crypto.randomUUID();
|
|
69
|
+
this.log = createLogger('prover-node:epoch-proving-job', {
|
|
70
|
+
...bindings,
|
|
71
|
+
instanceId: `epoch-${data.epochNumber}`,
|
|
72
|
+
});
|
|
68
73
|
this.tracer = metrics.tracer;
|
|
69
74
|
}
|
|
70
75
|
|
|
@@ -143,19 +148,32 @@ export class EpochProvingJob implements Traceable {
|
|
|
143
148
|
this.runPromise = promise;
|
|
144
149
|
|
|
145
150
|
try {
|
|
151
|
+
const blobTimer = new Timer();
|
|
146
152
|
const blobFieldsPerCheckpoint = this.checkpoints.map(checkpoint => checkpoint.toBlobFields());
|
|
147
153
|
const finalBlobBatchingChallenges = await buildFinalBlobChallenges(blobFieldsPerCheckpoint);
|
|
154
|
+
this.metrics.recordBlobProcessing(blobTimer.ms());
|
|
148
155
|
|
|
149
156
|
this.prover.startNewEpoch(epochNumber, epochSizeCheckpoints, finalBlobBatchingChallenges);
|
|
157
|
+
const chonkTimer = new Timer();
|
|
150
158
|
await this.prover.startChonkVerifierCircuits(Array.from(this.txs.values()));
|
|
159
|
+
this.metrics.recordChonkVerifier(chonkTimer.ms());
|
|
151
160
|
|
|
152
161
|
// Everything in the epoch should have the same chainId and version.
|
|
153
162
|
const { chainId, version } = this.checkpoints[0].blocks[0].header.globalVariables;
|
|
154
163
|
|
|
155
164
|
const previousBlockHeaders = this.gatherPreviousBlockHeaders();
|
|
156
165
|
|
|
157
|
-
|
|
166
|
+
const allCheckpointsTimer = new Timer();
|
|
167
|
+
|
|
168
|
+
const parallelism = this.config.parallelBlockLimit
|
|
169
|
+
? this.config.parallelBlockLimit
|
|
170
|
+
: AVM_MAX_CONCURRENT_SIMULATIONS > 0
|
|
171
|
+
? AVM_MAX_CONCURRENT_SIMULATIONS
|
|
172
|
+
: this.checkpoints.length;
|
|
173
|
+
|
|
174
|
+
await this.processCheckpoints(parallelism, async checkpoint => {
|
|
158
175
|
this.checkState();
|
|
176
|
+
const checkpointTimer = new Timer();
|
|
159
177
|
|
|
160
178
|
const checkpointIndex = checkpoint.number - fromCheckpoint;
|
|
161
179
|
const checkpointConstants = CheckpointConstantData.from({
|
|
@@ -172,11 +190,12 @@ export class EpochProvingJob implements Traceable {
|
|
|
172
190
|
const previousHeader = previousBlockHeaders[checkpointIndex];
|
|
173
191
|
const l1ToL2Messages = this.getL1ToL2Messages(checkpoint);
|
|
174
192
|
|
|
175
|
-
this.log.
|
|
193
|
+
this.log.debug(`Starting processing checkpoint ${checkpoint.number}`, {
|
|
176
194
|
number: checkpoint.number,
|
|
177
195
|
checkpointHash: checkpoint.hash().toString(),
|
|
178
|
-
|
|
179
|
-
|
|
196
|
+
headerHash: checkpoint.header.hash().toString(),
|
|
197
|
+
numL1ToL2Messages: l1ToL2Messages.length,
|
|
198
|
+
previousBlockNumber: previousHeader.globalVariables.blockNumber,
|
|
180
199
|
uuid: this.uuid,
|
|
181
200
|
});
|
|
182
201
|
|
|
@@ -188,7 +207,9 @@ export class EpochProvingJob implements Traceable {
|
|
|
188
207
|
previousHeader,
|
|
189
208
|
);
|
|
190
209
|
|
|
191
|
-
for (
|
|
210
|
+
for (let blockIndex = 0; blockIndex < checkpoint.blocks.length; blockIndex++) {
|
|
211
|
+
const blockTimer = new Timer();
|
|
212
|
+
const block = checkpoint.blocks[blockIndex];
|
|
192
213
|
const globalVariables = block.header.globalVariables;
|
|
193
214
|
const txs = this.getTxs(block);
|
|
194
215
|
|
|
@@ -206,20 +227,28 @@ export class EpochProvingJob implements Traceable {
|
|
|
206
227
|
// Start block proving
|
|
207
228
|
await this.prover.startNewBlock(block.number, globalVariables.timestamp, txs.length);
|
|
208
229
|
|
|
209
|
-
// Process public fns
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
230
|
+
// Process public fns. L1 to L2 messages are only inserted for the first block of a checkpoint,
|
|
231
|
+
// as the fork for subsequent blocks already includes them from the previous block's synced state.
|
|
232
|
+
{
|
|
233
|
+
await using db = await this.createFork(
|
|
234
|
+
BlockNumber(block.number - 1),
|
|
235
|
+
blockIndex === 0 ? l1ToL2Messages : undefined,
|
|
236
|
+
);
|
|
237
|
+
this.checkState();
|
|
238
|
+
const config = PublicSimulatorConfig.from({
|
|
239
|
+
proverId: this.prover.getProverId().toField(),
|
|
240
|
+
skipFeeEnforcement: false,
|
|
241
|
+
collectDebugLogs: false,
|
|
242
|
+
collectHints: true,
|
|
243
|
+
collectPublicInputs: true,
|
|
244
|
+
collectStatistics: false,
|
|
245
|
+
});
|
|
246
|
+
const publicProcessor = this.publicProcessorFactory.create(db, globalVariables, config);
|
|
247
|
+
const processed = await this.processTxs(publicProcessor, txs);
|
|
248
|
+
this.checkState();
|
|
249
|
+
await this.prover.addTxs(processed);
|
|
250
|
+
}
|
|
251
|
+
this.checkState();
|
|
223
252
|
this.log.verbose(`Processed all ${txs.length} txs for block ${block.number}`, {
|
|
224
253
|
blockNumber: block.number,
|
|
225
254
|
blockHash: (await block.hash()).toString(),
|
|
@@ -229,8 +258,11 @@ export class EpochProvingJob implements Traceable {
|
|
|
229
258
|
// Mark block as completed to pad it
|
|
230
259
|
const expectedBlockHeader = block.header;
|
|
231
260
|
await this.prover.setBlockCompleted(block.number, expectedBlockHeader);
|
|
261
|
+
this.metrics.recordBlockProcessing(blockTimer.ms());
|
|
232
262
|
}
|
|
263
|
+
this.metrics.recordCheckpointProcessing(checkpointTimer.ms());
|
|
233
264
|
});
|
|
265
|
+
this.metrics.recordAllCheckpointsProcessing(allCheckpointsTimer.ms());
|
|
234
266
|
|
|
235
267
|
const executionTime = timer.ms();
|
|
236
268
|
|
|
@@ -242,8 +274,21 @@ export class EpochProvingJob implements Traceable {
|
|
|
242
274
|
|
|
243
275
|
if (this.config.skipSubmitProof) {
|
|
244
276
|
this.log.info(
|
|
245
|
-
`Proof publishing is disabled.
|
|
277
|
+
`Proof publishing is disabled. Analyzing estimated L1 fees for epoch ${epochNumber} (checkpoints ${fromCheckpoint} to ${toCheckpoint})`,
|
|
246
278
|
);
|
|
279
|
+
try {
|
|
280
|
+
await this.publisher.analyzeEpochProofSubmission({
|
|
281
|
+
fromCheckpoint,
|
|
282
|
+
toCheckpoint,
|
|
283
|
+
epochNumber,
|
|
284
|
+
publicInputs,
|
|
285
|
+
proof,
|
|
286
|
+
batchedBlobInputs,
|
|
287
|
+
attestations,
|
|
288
|
+
});
|
|
289
|
+
} catch (err) {
|
|
290
|
+
this.log.warn(`Failed to analyze estimated L1 fees for epoch ${epochNumber}`, err);
|
|
291
|
+
}
|
|
247
292
|
this.state = 'completed';
|
|
248
293
|
this.metrics.recordProvingJob(executionTime, timer.ms(), epochSizeCheckpoints, epochSizeBlocks, epochSizeTxs);
|
|
249
294
|
return;
|
|
@@ -290,25 +335,63 @@ export class EpochProvingJob implements Traceable {
|
|
|
290
335
|
}
|
|
291
336
|
|
|
292
337
|
/**
|
|
293
|
-
* Create a new db fork for tx processing, inserting
|
|
338
|
+
* Create a new db fork for tx processing, optionally inserting L1 to L2 messages.
|
|
339
|
+
* L1 to L2 messages should only be inserted for the first block in a checkpoint,
|
|
340
|
+
* as subsequent blocks' synced state already includes them.
|
|
294
341
|
* REFACTOR: The prover already spawns a db fork of its own for each block, so we may be able to do away with just one fork.
|
|
295
342
|
*/
|
|
296
|
-
private async createFork(blockNumber: BlockNumber, l1ToL2Messages: Fr[]) {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
343
|
+
private async createFork(blockNumber: BlockNumber, l1ToL2Messages: Fr[] | undefined) {
|
|
344
|
+
this.log.verbose(`Creating fork at ${blockNumber}`, { blockNumber });
|
|
345
|
+
// temporary stack to control fork lifetime
|
|
346
|
+
await using cleanup = new AsyncDisposableStack();
|
|
347
|
+
const db = cleanup.use(await this.dbProvider.fork(blockNumber));
|
|
348
|
+
|
|
349
|
+
if (l1ToL2Messages !== undefined) {
|
|
350
|
+
this.log.verbose(`Inserting ${l1ToL2Messages.length} L1 to L2 messages in fork`, {
|
|
351
|
+
blockNumber,
|
|
352
|
+
l1ToL2Messages: l1ToL2Messages.map(m => m.toString()),
|
|
353
|
+
});
|
|
354
|
+
await appendL1ToL2MessagesToTree(db, l1ToL2Messages);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// everything run succesfully so we can release this stack and give control of the fork's lifetime to the caller
|
|
358
|
+
cleanup.move();
|
|
309
359
|
return db;
|
|
310
360
|
}
|
|
311
361
|
|
|
362
|
+
private async processCheckpoints(
|
|
363
|
+
parallelism: number,
|
|
364
|
+
processCheckpoint: (checkpoint: Checkpoint) => Promise<void>,
|
|
365
|
+
): Promise<void> {
|
|
366
|
+
let hasError = false;
|
|
367
|
+
let firstError: unknown;
|
|
368
|
+
|
|
369
|
+
await asyncPool(Math.max(parallelism, 1), this.checkpoints, async checkpoint => {
|
|
370
|
+
if (hasError || this.abortController.signal.aborted) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
try {
|
|
375
|
+
this.checkState();
|
|
376
|
+
await processCheckpoint(checkpoint);
|
|
377
|
+
} catch (err) {
|
|
378
|
+
if (!hasError) {
|
|
379
|
+
hasError = true;
|
|
380
|
+
firstError = err;
|
|
381
|
+
this.failProcessing();
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
if (hasError) {
|
|
387
|
+
throw firstError;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (this.abortController.signal.aborted) {
|
|
391
|
+
this.checkState();
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
312
395
|
private progressState(state: EpochProvingJobState) {
|
|
313
396
|
this.checkState();
|
|
314
397
|
this.state = state;
|
|
@@ -322,12 +405,24 @@ export class EpochProvingJob implements Traceable {
|
|
|
322
405
|
|
|
323
406
|
public async stop(state: EpochProvingJobTerminalState = 'stopped') {
|
|
324
407
|
this.state = state;
|
|
325
|
-
this.
|
|
408
|
+
this.interruptProcessing();
|
|
326
409
|
if (this.runPromise) {
|
|
327
410
|
await this.runPromise;
|
|
328
411
|
}
|
|
329
412
|
}
|
|
330
413
|
|
|
414
|
+
private failProcessing() {
|
|
415
|
+
if (!EpochProvingJobTerminalState.includes(this.state)) {
|
|
416
|
+
this.state = 'failed';
|
|
417
|
+
}
|
|
418
|
+
this.interruptProcessing();
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
private interruptProcessing() {
|
|
422
|
+
this.abortController.abort();
|
|
423
|
+
this.prover.cancel();
|
|
424
|
+
}
|
|
425
|
+
|
|
331
426
|
private scheduleDeadlineStop() {
|
|
332
427
|
const deadline = this.deadline;
|
|
333
428
|
if (deadline) {
|
|
@@ -362,8 +457,10 @@ export class EpochProvingJob implements Traceable {
|
|
|
362
457
|
const intervalMs = Math.ceil((await l2BlockSource.getL1Constants()).ethereumSlotDuration / 2) * 1000;
|
|
363
458
|
this.epochCheckPromise = new RunningPromise(
|
|
364
459
|
async () => {
|
|
365
|
-
const blockHeaders =
|
|
366
|
-
|
|
460
|
+
const blockHeaders = (
|
|
461
|
+
await l2BlockSource.getBlocksData({ epoch: this.epochNumber, onlyCheckpointed: true })
|
|
462
|
+
).map(d => d.header);
|
|
463
|
+
const blockHashes = await Promise.all(blockHeaders.map(header => header.hash()));
|
|
367
464
|
const thisBlocks = this.checkpoints.flatMap(checkpoint => checkpoint.blocks);
|
|
368
465
|
const thisBlockHashes = await Promise.all(thisBlocks.map(block => block.hash()));
|
|
369
466
|
if (
|
|
@@ -401,7 +498,11 @@ export class EpochProvingJob implements Traceable {
|
|
|
401
498
|
|
|
402
499
|
private async processTxs(publicProcessor: PublicProcessor, txs: Tx[]): Promise<ProcessedTx[]> {
|
|
403
500
|
const { deadline } = this;
|
|
404
|
-
const [processedTxs, failedTxs] = await publicProcessor.process(txs, {
|
|
501
|
+
const [processedTxs, failedTxs] = await publicProcessor.process(txs, {
|
|
502
|
+
deadline,
|
|
503
|
+
signal: this.abortController.signal,
|
|
504
|
+
});
|
|
505
|
+
this.checkState();
|
|
405
506
|
|
|
406
507
|
if (failedTxs.length) {
|
|
407
508
|
const failedTxHashes = await Promise.all(failedTxs.map(({ tx }) => tx.getTxHash()));
|