@aztec/prover-node 3.0.0-canary.a9708bd → 3.0.0-devnet.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/prover-node",
3
- "version": "3.0.0-canary.a9708bd",
3
+ "version": "3.0.0-devnet.3",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dest/index.js",
@@ -56,30 +56,30 @@
56
56
  ]
57
57
  },
58
58
  "dependencies": {
59
- "@aztec/archiver": "3.0.0-canary.a9708bd",
60
- "@aztec/bb-prover": "3.0.0-canary.a9708bd",
61
- "@aztec/blob-lib": "3.0.0-canary.a9708bd",
62
- "@aztec/blob-sink": "3.0.0-canary.a9708bd",
63
- "@aztec/constants": "3.0.0-canary.a9708bd",
64
- "@aztec/epoch-cache": "3.0.0-canary.a9708bd",
65
- "@aztec/ethereum": "3.0.0-canary.a9708bd",
66
- "@aztec/foundation": "3.0.0-canary.a9708bd",
67
- "@aztec/kv-store": "3.0.0-canary.a9708bd",
68
- "@aztec/l1-artifacts": "3.0.0-canary.a9708bd",
69
- "@aztec/node-keystore": "3.0.0-canary.a9708bd",
70
- "@aztec/node-lib": "3.0.0-canary.a9708bd",
71
- "@aztec/noir-protocol-circuits-types": "3.0.0-canary.a9708bd",
72
- "@aztec/p2p": "3.0.0-canary.a9708bd",
73
- "@aztec/protocol-contracts": "3.0.0-canary.a9708bd",
74
- "@aztec/prover-client": "3.0.0-canary.a9708bd",
75
- "@aztec/sequencer-client": "3.0.0-canary.a9708bd",
76
- "@aztec/simulator": "3.0.0-canary.a9708bd",
77
- "@aztec/stdlib": "3.0.0-canary.a9708bd",
78
- "@aztec/telemetry-client": "3.0.0-canary.a9708bd",
79
- "@aztec/world-state": "3.0.0-canary.a9708bd",
59
+ "@aztec/archiver": "3.0.0-devnet.3",
60
+ "@aztec/bb-prover": "3.0.0-devnet.3",
61
+ "@aztec/blob-lib": "3.0.0-devnet.3",
62
+ "@aztec/blob-sink": "3.0.0-devnet.3",
63
+ "@aztec/constants": "3.0.0-devnet.3",
64
+ "@aztec/epoch-cache": "3.0.0-devnet.3",
65
+ "@aztec/ethereum": "3.0.0-devnet.3",
66
+ "@aztec/foundation": "3.0.0-devnet.3",
67
+ "@aztec/kv-store": "3.0.0-devnet.3",
68
+ "@aztec/l1-artifacts": "3.0.0-devnet.3",
69
+ "@aztec/node-keystore": "3.0.0-devnet.3",
70
+ "@aztec/node-lib": "3.0.0-devnet.3",
71
+ "@aztec/noir-protocol-circuits-types": "3.0.0-devnet.3",
72
+ "@aztec/p2p": "3.0.0-devnet.3",
73
+ "@aztec/protocol-contracts": "3.0.0-devnet.3",
74
+ "@aztec/prover-client": "3.0.0-devnet.3",
75
+ "@aztec/sequencer-client": "3.0.0-devnet.3",
76
+ "@aztec/simulator": "3.0.0-devnet.3",
77
+ "@aztec/stdlib": "3.0.0-devnet.3",
78
+ "@aztec/telemetry-client": "3.0.0-devnet.3",
79
+ "@aztec/world-state": "3.0.0-devnet.3",
80
80
  "source-map-support": "^0.5.21",
81
81
  "tslib": "^2.4.0",
82
- "viem": "2.23.7"
82
+ "viem": "npm:@spalladino/viem@2.38.2-eip7594.0"
83
83
  },
84
84
  "devDependencies": {
85
85
  "@jest/globals": "^30.0.0",
@@ -25,7 +25,7 @@ async function rerunFailedEpoch(provingJobUrl: string, baseLocalDir: string) {
25
25
  const config = {
26
26
  ...getProverNodeConfigFromEnv(),
27
27
  dataDirectory: dataDir,
28
- dataStoreMapSizeKB: env.dataStoreMapSizeKB ?? 1024 * 1024,
28
+ dataStoreMapSizeKb: env.dataStoreMapSizeKb ?? 1024 * 1024,
29
29
  proverId: env.proverId ?? EthAddress.random(),
30
30
  };
31
31
 
package/src/config.ts CHANGED
@@ -1,16 +1,14 @@
1
1
  import { type ArchiverConfig, archiverConfigMappings } from '@aztec/archiver/config';
2
2
  import type { ACVMConfig, BBConfig } from '@aztec/bb-prover/config';
3
3
  import { type GenesisStateConfig, genesisStateConfigMappings } from '@aztec/ethereum';
4
- import { type ConfigMappingsType, getConfigFromMappings, numberConfigHelper } from '@aztec/foundation/config';
5
- import { type DataStoreConfig, dataConfigMappings } from '@aztec/kv-store/config';
6
4
  import {
7
- type EthAccount,
8
- type EthAddressHex,
9
- type EthRemoteSignerAccount,
10
- type KeyStore,
11
- type KeyStoreConfig,
12
- keyStoreConfigMappings,
13
- } from '@aztec/node-keystore';
5
+ type ConfigMappingsType,
6
+ booleanConfigHelper,
7
+ getConfigFromMappings,
8
+ numberConfigHelper,
9
+ } from '@aztec/foundation/config';
10
+ import { type DataStoreConfig, dataConfigMappings } from '@aztec/kv-store/config';
11
+ import { type KeyStore, type KeyStoreConfig, ethPrivateKeySchema, keyStoreConfigMappings } from '@aztec/node-keystore';
14
12
  import { type SharedNodeConfig, sharedNodeConfigMappings } from '@aztec/node-lib/config';
15
13
  import { type P2PConfig, p2pConfigMappings } from '@aztec/p2p/config';
16
14
  import {
@@ -45,6 +43,8 @@ export type SpecificProverNodeConfig = {
45
43
  proverNodePollingIntervalMs: number;
46
44
  proverNodeMaxParallelBlocksPerEpoch: number;
47
45
  proverNodeFailedEpochStore: string | undefined;
46
+ proverNodeEpochProvingDelayMs: number | undefined;
47
+ proverNodeDisableProofPublish?: boolean;
48
48
  txGatheringTimeoutMs: number;
49
49
  txGatheringIntervalMs: number;
50
50
  txGatheringBatchSize: number;
@@ -72,6 +72,10 @@ const specificProverNodeConfigMappings: ConfigMappingsType<SpecificProverNodeCon
72
72
  description: 'File store where to upload node state when an epoch fails to be proven',
73
73
  defaultValue: undefined,
74
74
  },
75
+ proverNodeEpochProvingDelayMs: {
76
+ description: 'Optional delay in milliseconds to wait before proving a new epoch',
77
+ defaultValue: undefined,
78
+ },
75
79
  txGatheringIntervalMs: {
76
80
  env: 'PROVER_NODE_TX_GATHERING_INTERVAL_MS',
77
81
  description: 'How often to check that tx data is available',
@@ -92,6 +96,11 @@ const specificProverNodeConfigMappings: ConfigMappingsType<SpecificProverNodeCon
92
96
  description: 'How long to wait for tx data to be available before giving up',
93
97
  ...numberConfigHelper(120_000),
94
98
  },
99
+ proverNodeDisableProofPublish: {
100
+ env: 'PROVER_NODE_DISABLE_PROOF_PUBLISH',
101
+ description: 'Whether the prover node skips publishing proofs to L1',
102
+ ...booleanConfigHelper(false),
103
+ },
95
104
  };
96
105
 
97
106
  export const proverNodeConfigMappings: ConfigMappingsType<ProverNodeConfig> = {
@@ -125,19 +134,14 @@ export function getProverNodeAgentConfigFromEnv(): ProverAgentConfig & BBConfig
125
134
  };
126
135
  }
127
136
 
128
- function createKeyStoreFromWeb3Signer(config: ProverNodeConfig) {
129
- // See what we have been given for proverId.
130
- const proverId = config.proverId ? (config.proverId.toString() as EthAddressHex) : undefined;
131
-
137
+ function createKeyStoreFromWeb3Signer(config: ProverNodeConfig): KeyStore | undefined {
132
138
  // If we don't have a valid prover Id then we can't build a valid key store with remote signers
133
- if (proverId === undefined) {
139
+ if (config.proverId === undefined) {
134
140
  return undefined;
135
141
  }
136
142
 
137
143
  // Also, we need at least one publisher address.
138
- const publishers = config.publisherAddresses
139
- ? config.publisherAddresses.map(k => k.toChecksumString() as EthRemoteSignerAccount)
140
- : [];
144
+ const publishers = config.publisherAddresses ?? [];
141
145
 
142
146
  if (publishers.length === 0) {
143
147
  return undefined;
@@ -147,7 +151,7 @@ function createKeyStoreFromWeb3Signer(config: ProverNodeConfig) {
147
151
  schemaVersion: 1,
148
152
  slasher: undefined,
149
153
  prover: {
150
- id: proverId,
154
+ id: config.proverId,
151
155
  publisher: publishers,
152
156
  },
153
157
  remoteSigner: config.web3SignerUrl,
@@ -156,10 +160,10 @@ function createKeyStoreFromWeb3Signer(config: ProverNodeConfig) {
156
160
  return keyStore;
157
161
  }
158
162
 
159
- function createKeyStoreFromPublisherKeys(config: ProverNodeConfig) {
163
+ function createKeyStoreFromPublisherKeys(config: ProverNodeConfig): KeyStore | undefined {
160
164
  // Extract the publisher keys from the provided config.
161
165
  const publisherKeys = config.publisherPrivateKeys
162
- ? config.publisherPrivateKeys.map(k => k.getValue() as EthAddressHex)
166
+ ? config.publisherPrivateKeys.map(k => ethPrivateKeySchema.parse(k.getValue()))
163
167
  : [];
164
168
 
165
169
  // There must be at least 1.
@@ -167,9 +171,6 @@ function createKeyStoreFromPublisherKeys(config: ProverNodeConfig) {
167
171
  return undefined;
168
172
  }
169
173
 
170
- // Now see what we have been given for proverId.
171
- const proverId = config.proverId ? (config.proverId.toString() as EthAddressHex) : undefined;
172
-
173
174
  // If we have a valid proverId then create a prover key store of the form { id, publisher: [publisherKeys] }
174
175
  // Otherwise create one of the form ("0x12345678....." as EthAccount).
175
176
 
@@ -177,11 +178,11 @@ function createKeyStoreFromPublisherKeys(config: ProverNodeConfig) {
177
178
  schemaVersion: 1,
178
179
  slasher: undefined,
179
180
  prover:
180
- proverId === undefined
181
- ? (publisherKeys[0] as EthAccount)
181
+ config.proverId === undefined
182
+ ? publisherKeys[0]
182
183
  : {
183
- id: proverId,
184
- publisher: publisherKeys.map(key => key as EthAccount),
184
+ id: config.proverId,
185
+ publisher: publisherKeys,
185
186
  },
186
187
  remoteSigner: undefined,
187
188
  validators: undefined,
@@ -189,7 +190,7 @@ function createKeyStoreFromPublisherKeys(config: ProverNodeConfig) {
189
190
  return keyStore;
190
191
  }
191
192
 
192
- export function createKeyStoreForProver(config: ProverNodeConfig) {
193
+ export function createKeyStoreForProver(config: ProverNodeConfig): KeyStore | undefined {
193
194
  if (config.web3SignerUrl !== undefined && config.web3SignerUrl.length > 0) {
194
195
  return createKeyStoreFromWeb3Signer(config);
195
196
  }
package/src/factory.ts CHANGED
@@ -2,20 +2,14 @@ import { type Archiver, createArchiver } from '@aztec/archiver';
2
2
  import { BBCircuitVerifier, QueuedIVCVerifier, TestCircuitVerifier } from '@aztec/bb-prover';
3
3
  import { type BlobSinkClientInterface, createBlobSinkClient } from '@aztec/blob-sink/client';
4
4
  import { EpochCache } from '@aztec/epoch-cache';
5
- import {
6
- type EthSigner,
7
- L1TxUtils,
8
- PublisherManager,
9
- RollupContract,
10
- createEthereumChain,
11
- createL1TxUtilsFromEthSigner,
12
- } from '@aztec/ethereum';
5
+ import { L1TxUtils, PublisherManager, RollupContract, createEthereumChain } from '@aztec/ethereum';
13
6
  import { pick } from '@aztec/foundation/collection';
14
7
  import { type Logger, createLogger } from '@aztec/foundation/log';
15
8
  import { DateProvider } from '@aztec/foundation/timer';
16
9
  import type { DataStoreConfig } from '@aztec/kv-store/config';
17
10
  import { type KeyStoreConfig, KeystoreManager, loadKeystores, mergeKeystores } from '@aztec/node-keystore';
18
11
  import { trySnapshotSync } from '@aztec/node-lib/actions';
12
+ import { createL1TxUtilsFromEthSignerWithStore } from '@aztec/node-lib/factories';
19
13
  import { NodeRpcTxSource, createP2PClient } from '@aztec/p2p';
20
14
  import { type ProverClientConfig, createProverClient } from '@aztec/prover-client';
21
15
  import { createAndStartProvingBroker } from '@aztec/prover-client/broker';
@@ -73,6 +67,8 @@ export async function createProverNode(
73
67
  }
74
68
  }
75
69
 
70
+ await keyStoreManager?.validateSigners();
71
+
76
72
  // Extract the prover signers from the key store and verify that we have one.
77
73
  const proverSigners = keyStoreManager?.createProverSigners();
78
74
 
@@ -86,6 +82,8 @@ export async function createProverNode(
86
82
  );
87
83
  }
88
84
 
85
+ log.info(`Creating prover with publishers ${proverSigners.signers.map(signer => signer.address.toString()).join()}`);
86
+
89
87
  // Only consider user provided config if it is valid
90
88
  const proverIdInUserConfig = config.proverId === undefined || config.proverId.isZero() ? undefined : config.proverId;
91
89
 
@@ -133,15 +131,18 @@ export async function createProverNode(
133
131
 
134
132
  const l1TxUtils = deps.l1TxUtils
135
133
  ? [deps.l1TxUtils]
136
- : proverSigners.signers.map((signer: EthSigner) => {
137
- return createL1TxUtilsFromEthSigner(publicClient, signer, log, dateProvider, config);
138
- });
134
+ : await createL1TxUtilsFromEthSignerWithStore(
135
+ publicClient,
136
+ proverSigners.signers,
137
+ { ...config, scope: 'prover' },
138
+ { telemetry, logger: log.createChild('l1-tx-utils'), dateProvider },
139
+ );
139
140
 
140
141
  const publisherFactory =
141
142
  deps.publisherFactory ??
142
143
  new ProverPublisherFactory(config, {
143
144
  rollupContract,
144
- publisherManager: new PublisherManager(l1TxUtils),
145
+ publisherManager: new PublisherManager(l1TxUtils, config),
145
146
  telemetry,
146
147
  });
147
148
 
@@ -175,6 +176,7 @@ export async function createProverNode(
175
176
  'proverNodeMaxPendingJobs',
176
177
  'proverNodeMaxParallelBlocksPerEpoch',
177
178
  'proverNodePollingIntervalMs',
179
+ 'proverNodeEpochProvingDelayMs',
178
180
  'txGatheringMaxParallelRequests',
179
181
  'txGatheringIntervalMs',
180
182
  'txGatheringTimeoutMs',
@@ -187,7 +189,7 @@ export async function createProverNode(
187
189
 
188
190
  const epochMonitor = await EpochMonitor.create(
189
191
  archiver,
190
- { pollingIntervalMs: config.proverNodePollingIntervalMs },
192
+ { pollingIntervalMs: config.proverNodePollingIntervalMs, provingDelayMs: config.proverNodeEpochProvingDelayMs },
191
193
  telemetry,
192
194
  );
193
195
 
@@ -1,4 +1,3 @@
1
- import { BatchedBlob, Blob } from '@aztec/blob-lib';
2
1
  import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
3
2
  import { asyncPool } from '@aztec/foundation/async-pool';
4
3
  import { padArrayEnd } from '@aztec/foundation/collection';
@@ -6,6 +5,9 @@ import { Fr } from '@aztec/foundation/fields';
6
5
  import { createLogger } from '@aztec/foundation/log';
7
6
  import { RunningPromise, promiseWithResolvers } from '@aztec/foundation/promise';
8
7
  import { Timer } from '@aztec/foundation/timer';
8
+ import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
9
+ import { protocolContractsHash } from '@aztec/protocol-contracts';
10
+ import { buildFinalBlobChallenges } from '@aztec/prover-client/helpers';
9
11
  import type { PublicProcessor, PublicProcessorFactory } from '@aztec/simulator/server';
10
12
  import type { L2Block, L2BlockSource } from '@aztec/stdlib/block';
11
13
  import {
@@ -14,6 +16,7 @@ import {
14
16
  EpochProvingJobTerminalState,
15
17
  type ForkMerkleTreeOperations,
16
18
  } from '@aztec/stdlib/interfaces/server';
19
+ import { CheckpointConstantData } from '@aztec/stdlib/rollup';
17
20
  import { MerkleTreeId } from '@aztec/stdlib/trees';
18
21
  import type { ProcessedTx, Tx } from '@aztec/stdlib/tx';
19
22
  import { Attributes, type Traceable, type Tracer, trackSpan } from '@aztec/telemetry-client';
@@ -24,6 +27,12 @@ import type { ProverNodeJobMetrics } from '../metrics.js';
24
27
  import type { ProverNodePublisher } from '../prover-node-publisher.js';
25
28
  import { type EpochProvingJobData, validateEpochProvingJobData } from './epoch-proving-job-data.js';
26
29
 
30
+ export type EpochProvingJobOptions = {
31
+ parallelBlockLimit?: number;
32
+ skipEpochCheck?: boolean;
33
+ skipSubmitProof?: boolean;
34
+ };
35
+
27
36
  /**
28
37
  * Job that grabs a range of blocks from the unfinalized chain from L1, gets their txs given their hashes,
29
38
  * re-executes their public calls, generates a rollup proof, and submits it to L1. This job will update the
@@ -49,7 +58,7 @@ export class EpochProvingJob implements Traceable {
49
58
  private l2BlockSource: L2BlockSource | undefined,
50
59
  private metrics: ProverNodeJobMetrics,
51
60
  private deadline: Date | undefined,
52
- private config: { parallelBlockLimit?: number; skipEpochCheck?: boolean },
61
+ private config: EpochProvingJobOptions,
53
62
  ) {
54
63
  validateEpochProvingJobData(data);
55
64
  this.uuid = crypto.randomUUID();
@@ -123,12 +132,14 @@ export class EpochProvingJob implements Traceable {
123
132
  this.runPromise = promise;
124
133
 
125
134
  try {
126
- const allBlobs = (
127
- await Promise.all(this.blocks.map(async block => await Blob.getBlobsPerBlock(block.body.toBlobFields())))
128
- ).flat();
135
+ const blobFieldsPerCheckpoint = this.blocks.map(block => block.getCheckpointBlobFields());
136
+ const finalBlobBatchingChallenges = await buildFinalBlobChallenges(blobFieldsPerCheckpoint);
137
+
138
+ // TODO(#17027): Enable multiple blocks per checkpoint.
139
+ // Total number of checkpoints equals number of blocks because we currently build a checkpoint with only one block.
140
+ const totalNumCheckpoints = epochSizeBlocks;
129
141
 
130
- const finalBlobBatchingChallenges = await BatchedBlob.precomputeBatchedBlobChallenges(allBlobs);
131
- this.prover.startNewEpoch(epochNumber, fromBlock, epochSizeBlocks, finalBlobBatchingChallenges);
142
+ this.prover.startNewEpoch(epochNumber, totalNumCheckpoints, finalBlobBatchingChallenges);
132
143
  await this.prover.startTubeCircuits(Array.from(this.txs.values()));
133
144
 
134
145
  await asyncPool(this.config.parallelBlockLimit ?? 32, this.blocks, async block => {
@@ -151,12 +162,41 @@ export class EpochProvingJob implements Traceable {
151
162
  ...globalVariables,
152
163
  });
153
164
 
165
+ const checkpointConstants = CheckpointConstantData.from({
166
+ chainId: globalVariables.chainId,
167
+ version: globalVariables.version,
168
+ vkTreeRoot: getVKTreeRoot(),
169
+ protocolContractsHash: protocolContractsHash,
170
+ proverId: this.prover.getProverId().toField(),
171
+ slotNumber: globalVariables.slotNumber,
172
+ coinbase: globalVariables.coinbase,
173
+ feeRecipient: globalVariables.feeRecipient,
174
+ gasFees: globalVariables.gasFees,
175
+ });
176
+
177
+ // TODO(#17027): Enable multiple blocks per checkpoint.
178
+ // Each checkpoint has only one block.
179
+ const totalNumBlocks = 1;
180
+ const checkpointIndex = block.number - fromBlock;
181
+ await this.prover.startNewCheckpoint(
182
+ checkpointIndex,
183
+ checkpointConstants,
184
+ l1ToL2Messages,
185
+ totalNumBlocks,
186
+ blobFieldsPerCheckpoint[checkpointIndex].length,
187
+ previousHeader,
188
+ );
189
+
154
190
  // Start block proving
155
- await this.prover.startNewBlock(globalVariables, l1ToL2Messages, previousHeader);
191
+ await this.prover.startNewBlock(block.number, globalVariables.timestamp, txs.length);
156
192
 
157
193
  // Process public fns
158
194
  const db = await this.createFork(block.number - 1, l1ToL2Messages);
159
- const publicProcessor = this.publicProcessorFactory.create(db, globalVariables, true);
195
+ const publicProcessor = this.publicProcessorFactory.create(db, globalVariables, {
196
+ skipFeeEnforcement: true,
197
+ clientInitiatedSimulation: false,
198
+ proverId: this.prover.getProverId().toField(),
199
+ });
160
200
  const processed = await this.processTxs(publicProcessor, txs);
161
201
  await this.prover.addTxs(processed);
162
202
  await db.close();
@@ -167,7 +207,8 @@ export class EpochProvingJob implements Traceable {
167
207
  });
168
208
 
169
209
  // Mark block as completed to pad it
170
- await this.prover.setBlockCompleted(block.number, block.header);
210
+ const expectedBlockHeader = block.getBlockHeader();
211
+ await this.prover.setBlockCompleted(block.number, expectedBlockHeader);
171
212
  });
172
213
 
173
214
  const executionTime = timer.ms();
@@ -178,6 +219,15 @@ export class EpochProvingJob implements Traceable {
178
219
 
179
220
  this.progressState('publishing-proof');
180
221
 
222
+ if (this.config.skipSubmitProof) {
223
+ this.log.info(
224
+ `Proof publishing is disabled. Dropping valid proof for epoch ${epochNumber} (blocks ${fromBlock} to ${toBlock})`,
225
+ );
226
+ this.state = 'completed';
227
+ this.metrics.recordProvingJob(executionTime, timer.ms(), epochSizeBlocks, epochSizeTxs);
228
+ return;
229
+ }
230
+
181
231
  const success = await this.publisher.submitEpochProof({
182
232
  fromBlock,
183
233
  toBlock,
@@ -224,7 +274,7 @@ export class EpochProvingJob implements Traceable {
224
274
  */
225
275
  private async createFork(blockNumber: number, l1ToL2Messages: Fr[]) {
226
276
  const db = await this.dbProvider.fork(blockNumber);
227
- const l1ToL2MessagesPadded = padArrayEnd(
277
+ const l1ToL2MessagesPadded = padArrayEnd<Fr, number>(
228
278
  l1ToL2Messages,
229
279
  Fr.ZERO,
230
280
  NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
@@ -252,7 +302,6 @@ export class EpochProvingJob implements Traceable {
252
302
  public async stop(state: EpochProvingJobTerminalState = 'stopped') {
253
303
  this.state = state;
254
304
  this.prover.cancel();
255
- // TODO(palla/prover): Stop the publisher as well
256
305
  if (this.runPromise) {
257
306
  await this.runPromise;
258
307
  }
@@ -318,7 +367,7 @@ export class EpochProvingJob implements Traceable {
318
367
  private getBlockHeader(blockNumber: number) {
319
368
  const block = this.blocks.find(b => b.number === blockNumber);
320
369
  if (block) {
321
- return block.header;
370
+ return block.getBlockHeader();
322
371
  }
323
372
 
324
373
  if (blockNumber === Number(this.data.previousBlockHeader.getBlockNumber())) {
package/src/metrics.ts CHANGED
@@ -91,7 +91,7 @@ export class ProverNodeRewardsMetrics {
91
91
  }
92
92
 
93
93
  private observe = async (observer: BatchObservableResult): Promise<void> => {
94
- const epoch = await this.rollup.getEpochNumber();
94
+ const epoch = await this.rollup.getCurrentEpochNumber();
95
95
 
96
96
  if (epoch > this.proofSubmissionEpochs) {
97
97
  // look at the prev epoch so that we get an accurate value, after proof submission window has closed
@@ -1,5 +1,6 @@
1
1
  import { createLogger } from '@aztec/foundation/log';
2
2
  import { RunningPromise } from '@aztec/foundation/running-promise';
3
+ import { sleep } from '@aztec/foundation/sleep';
3
4
  import type { L2BlockSource } from '@aztec/stdlib/block';
4
5
  import { type L1RollupConstants, getEpochAtSlot } from '@aztec/stdlib/epoch-helpers';
5
6
  import {
@@ -36,16 +37,19 @@ export class EpochMonitor implements Traceable {
36
37
  constructor(
37
38
  private readonly l2BlockSource: L2BlockSource,
38
39
  private readonly l1Constants: Pick<L1RollupConstants, 'epochDuration'>,
39
- private options: { pollingIntervalMs: number },
40
+ private options: { pollingIntervalMs: number; provingDelayMs?: number },
40
41
  telemetry: TelemetryClient = getTelemetryClient(),
41
42
  ) {
42
43
  this.tracer = telemetry.getTracer('EpochMonitor');
43
44
  this.runningPromise = new RunningPromise(this.work.bind(this), this.log, this.options.pollingIntervalMs);
45
+ if (this.options.provingDelayMs) {
46
+ this.log.warn(`Prover node epoch monitor running with delay of ${this.options.provingDelayMs}ms`);
47
+ }
44
48
  }
45
49
 
46
50
  public static async create(
47
51
  l2BlockSource: L2BlockSource,
48
- options: { pollingIntervalMs: number },
52
+ options: { pollingIntervalMs: number; provingDelayMs?: number },
49
53
  telemetry: TelemetryClient = getTelemetryClient(),
50
54
  ): Promise<EpochMonitor> {
51
55
  const l1Constants = await l2BlockSource.getL1Constants();
@@ -87,6 +91,11 @@ export class EpochMonitor implements Traceable {
87
91
  return;
88
92
  }
89
93
 
94
+ if (this.options.provingDelayMs) {
95
+ this.log.debug(`Waiting ${this.options.provingDelayMs}ms before proving epoch ${epochToProve}`);
96
+ await sleep(this.options.provingDelayMs);
97
+ }
98
+
90
99
  this.log.debug(`Epoch ${epochToProve} is ready to be proven`);
91
100
  if (await this.handler?.handleEpochReadyToProve(epochToProve)) {
92
101
  this.latestEpochNumber = epochToProve;
@@ -1,21 +1,16 @@
1
- import { type BatchedBlob, FinalBlobAccumulatorPublicInputs } from '@aztec/blob-lib';
1
+ import type { BatchedBlob } from '@aztec/blob-lib';
2
2
  import { AZTEC_MAX_EPOCH_DURATION } from '@aztec/constants';
3
- import {
4
- type L1TxUtils,
5
- type RollupContract,
6
- RollupContract as RollupContractClass,
7
- type ViemCommitteeAttestation,
8
- } from '@aztec/ethereum';
3
+ import type { L1TxUtils, RollupContract, ViemCommitteeAttestation } from '@aztec/ethereum';
9
4
  import { makeTuple } from '@aztec/foundation/array';
10
5
  import { areArraysEqual } from '@aztec/foundation/collection';
11
6
  import { EthAddress } from '@aztec/foundation/eth-address';
12
7
  import { Fr } from '@aztec/foundation/fields';
13
8
  import { createLogger } from '@aztec/foundation/log';
14
9
  import type { Tuple } from '@aztec/foundation/serialize';
15
- import { InterruptibleSleep } from '@aztec/foundation/sleep';
16
10
  import { Timer } from '@aztec/foundation/timer';
17
11
  import { RollupAbi } from '@aztec/l1-artifacts';
18
12
  import type { PublisherConfig, TxSenderConfig } from '@aztec/sequencer-client';
13
+ import { CommitteeAttestation, CommitteeAttestationsAndSigners } from '@aztec/stdlib/block';
19
14
  import type { Proof } from '@aztec/stdlib/proofs';
20
15
  import type { FeeRecipient, RootRollupPublicInputs } from '@aztec/stdlib/rollup';
21
16
  import type { L1PublishProofStats } from '@aztec/stdlib/stats';
@@ -39,8 +34,6 @@ export type L1SubmitEpochProofArgs = {
39
34
  };
40
35
 
41
36
  export class ProverNodePublisher {
42
- private interruptibleSleep = new InterruptibleSleep();
43
- private sleepTimeMs: number;
44
37
  private interrupted = false;
45
38
  private metrics: ProverNodePublisherMetrics;
46
39
 
@@ -58,8 +51,6 @@ export class ProverNodePublisher {
58
51
  telemetry?: TelemetryClient;
59
52
  },
60
53
  ) {
61
- this.sleepTimeMs = config?.l1PublishRetryIntervalMS ?? 60_000;
62
-
63
54
  const telemetry = deps.telemetry ?? getTelemetryClient();
64
55
 
65
56
  this.metrics = new ProverNodePublisherMetrics(telemetry, 'ProverNode');
@@ -80,12 +71,13 @@ export class ProverNodePublisher {
80
71
  */
81
72
  public interrupt() {
82
73
  this.interrupted = true;
83
- this.interruptibleSleep.interrupt();
74
+ this.l1TxUtils.interrupt();
84
75
  }
85
76
 
86
77
  /** Restarts the publisher after calling `interrupt`. */
87
78
  public restart() {
88
79
  this.interrupted = false;
80
+ this.l1TxUtils.restart();
89
81
  }
90
82
 
91
83
  public getSenderAddress() {
@@ -103,6 +95,7 @@ export class ProverNodePublisher {
103
95
  }): Promise<boolean> {
104
96
  const { epochNumber, fromBlock, toBlock } = args;
105
97
  const ctx = { epochNumber, fromBlock, toBlock };
98
+
106
99
  if (!this.interrupted) {
107
100
  const timer = new Timer();
108
101
  // Validate epoch proof range and hashes are correct before submitting
@@ -143,7 +136,6 @@ export class ProverNodePublisher {
143
136
 
144
137
  this.metrics.recordFailedTx();
145
138
  this.log.error(`Rollup.submitEpochProof tx status failed ${txReceipt.transactionHash}`, undefined, ctx);
146
- await this.sleepOrInterrupted();
147
139
  }
148
140
 
149
141
  this.log.verbose('L2 block data syncing interrupted', ctx);
@@ -188,9 +180,10 @@ export class ProverNodePublisher {
188
180
  }
189
181
 
190
182
  // Check the batched blob inputs from the root rollup against the batched blob computed in ts
191
- if (!publicInputs.blobPublicInputs.equals(FinalBlobAccumulatorPublicInputs.fromBatchedBlob(batchedBlobInputs))) {
183
+ const finalBlobAccumulator = batchedBlobInputs.toFinalBlobAccumulator();
184
+ if (!publicInputs.blobPublicInputs.equals(finalBlobAccumulator)) {
192
185
  throw new Error(
193
- `Batched blob mismatch: ${inspect(publicInputs.blobPublicInputs)} !== ${inspect(FinalBlobAccumulatorPublicInputs.fromBatchedBlob(batchedBlobInputs))}`,
186
+ `Batched blob mismatch: ${inspect(publicInputs.blobPublicInputs)} !== ${inspect(finalBlobAccumulator)}`,
194
187
  );
195
188
  }
196
189
 
@@ -263,7 +256,7 @@ export class ProverNodePublisher {
263
256
  {
264
257
  previousArchive: args.publicInputs.previousArchiveRoot.toString(),
265
258
  endArchive: args.publicInputs.endArchiveRoot.toString(),
266
- proverId: EthAddress.fromField(args.publicInputs.proverId).toString(),
259
+ proverId: EthAddress.fromField(args.publicInputs.constants.proverId).toString(),
267
260
  } /*_args*/,
268
261
  makeTuple(AZTEC_MAX_EPOCH_DURATION * 2, i =>
269
262
  i % 2 === 0
@@ -290,13 +283,11 @@ export class ProverNodePublisher {
290
283
  end: argsArray[1],
291
284
  args: argsArray[2],
292
285
  fees: argsArray[3],
293
- attestations: RollupContractClass.packAttestations(args.attestations),
286
+ attestations: new CommitteeAttestationsAndSigners(
287
+ args.attestations.map(a => CommitteeAttestation.fromViem(a)),
288
+ ).getPackedAttestations(),
294
289
  blobInputs: argsArray[4],
295
290
  proof: proofHex,
296
291
  };
297
292
  }
298
-
299
- protected async sleepOrInterrupted() {
300
- await this.interruptibleSleep.sleep(this.sleepTimeMs);
301
- }
302
293
  }
@@ -87,6 +87,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
87
87
  txGatheringMaxParallelRequestsPerNode: 100,
88
88
  txGatheringTimeoutMs: 120_000,
89
89
  proverNodeFailedEpochStore: undefined,
90
+ proverNodeEpochProvingDelayMs: undefined,
90
91
  ...compact(config),
91
92
  };
92
93
 
@@ -143,6 +144,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
143
144
  */
144
145
  async start() {
145
146
  this.epochsMonitor.start(this);
147
+ await this.publisherFactory.start();
146
148
  this.publisher = await this.publisherFactory.create();
147
149
  await this.rewardsMetrics.start();
148
150
  this.l1Metrics.start();
@@ -158,6 +160,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
158
160
  await this.prover.stop();
159
161
  await tryStop(this.p2pClient);
160
162
  await tryStop(this.l2BlockSource);
163
+ await tryStop(this.publisherFactory);
161
164
  this.publisher?.interrupt();
162
165
  await Promise.all(Array.from(this.jobs.values()).map(job => job.stop()));
163
166
  await this.worldState.stop();
@@ -366,7 +369,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
366
369
  publisher: ProverNodePublisher,
367
370
  opts: { skipEpochCheck?: boolean } = {},
368
371
  ) {
369
- const { proverNodeMaxParallelBlocksPerEpoch: parallelBlockLimit } = this.config;
372
+ const { proverNodeMaxParallelBlocksPerEpoch: parallelBlockLimit, proverNodeDisableProofPublish } = this.config;
370
373
  return new EpochProvingJob(
371
374
  data,
372
375
  this.worldState,
@@ -376,7 +379,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable
376
379
  this.l2BlockSource,
377
380
  this.jobMetrics,
378
381
  deadline,
379
- { parallelBlockLimit, ...opts },
382
+ { parallelBlockLimit, skipSubmitProof: proverNodeDisableProofPublish, ...opts },
380
383
  );
381
384
  }
382
385
 
@@ -13,6 +13,15 @@ export class ProverPublisherFactory {
13
13
  telemetry?: TelemetryClient;
14
14
  },
15
15
  ) {}
16
+
17
+ public async start() {
18
+ await this.deps.publisherManager.loadState();
19
+ }
20
+
21
+ public stop() {
22
+ this.deps.publisherManager.interrupt();
23
+ }
24
+
16
25
  /**
17
26
  * Creates a new Prover Publisher instance.
18
27
  * @returns A new ProverNodePublisher instance.