-
Notifications
You must be signed in to change notification settings - Fork 234
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6dec777
commit fac94b8
Showing
17 changed files
with
437 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
module.exports = require('@aztec/foundation/eslint'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Prover Node |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
{ | ||
"name": "@aztec/prover-node", | ||
"version": "0.1.0", | ||
"type": "module", | ||
"exports": { | ||
".": "./dest/index.js" | ||
}, | ||
"inherits": [ | ||
"../package.common.json" | ||
], | ||
"scripts": { | ||
"build": "yarn clean && tsc -b", | ||
"build:dev": "tsc -b --watch", | ||
"clean": "rm -rf ./dest .tsbuildinfo", | ||
"formatting": "run -T prettier --check ./src && run -T eslint ./src", | ||
"formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src", | ||
"bb": "node --no-warnings ./dest/bb/index.js", | ||
"test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --passWithNoTests" | ||
}, | ||
"jest": { | ||
"moduleNameMapper": { | ||
"^(\\.{1,2}/.*)\\.[cm]?js$": "$1" | ||
}, | ||
"testRegex": "./src/.*\\.test\\.(js|mjs|ts)$", | ||
"rootDir": "./src", | ||
"transform": { | ||
"^.+\\.tsx?$": [ | ||
"@swc/jest", | ||
{ | ||
"jsc": { | ||
"parser": { | ||
"syntax": "typescript", | ||
"decorators": true | ||
} | ||
} | ||
} | ||
] | ||
}, | ||
"extensionsToTreatAsEsm": [ | ||
".ts" | ||
], | ||
"reporters": [ | ||
[ | ||
"default", | ||
{ | ||
"summaryThreshold": 9999 | ||
} | ||
] | ||
] | ||
}, | ||
"dependencies": { | ||
"@aztec/archiver": "workspace:^", | ||
"@aztec/circuit-types": "workspace:^", | ||
"@aztec/circuits.js": "workspace:^", | ||
"@aztec/foundation": "workspace:^", | ||
"@aztec/kv-store": "workspace:^", | ||
"@aztec/prover-client": "workspace:^", | ||
"@aztec/sequencer-client": "workspace:^", | ||
"@aztec/simulator": "workspace:^", | ||
"@aztec/telemetry-client": "workspace:^", | ||
"@aztec/world-state": "workspace:^", | ||
"source-map-support": "^0.5.21", | ||
"tslib": "^2.4.0" | ||
}, | ||
"devDependencies": { | ||
"@jest/globals": "^29.5.0", | ||
"@types/jest": "^29.5.0", | ||
"@types/memdown": "^3.0.0", | ||
"@types/node": "^18.7.23", | ||
"@types/source-map-support": "^0.5.10", | ||
"jest": "^29.5.0", | ||
"jest-mock-extended": "^3.0.3", | ||
"ts-node": "^10.9.1", | ||
"typescript": "^5.0.4" | ||
}, | ||
"files": [ | ||
"dest", | ||
"src", | ||
"!*.test.*" | ||
], | ||
"types": "./dest/index.d.ts", | ||
"engines": { | ||
"node": ">=18" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { type ArchiverConfig, getArchiverConfigFromEnv } from '@aztec/archiver'; | ||
import { type ProverClientConfig, getProverEnvVars } from '@aztec/prover-client'; | ||
import { type PublisherConfig, type TxSenderConfig, getTxSenderConfigFromEnv } from '@aztec/sequencer-client'; | ||
import { type WorldStateConfig, getWorldStateConfigFromEnv } from '@aztec/world-state'; | ||
|
||
import { type TxProviderConfig, getTxProviderConfigFromEnv } from './tx-provider/config.js'; | ||
|
||
export type ProverNodeConfig = ArchiverConfig & | ||
ProverClientConfig & | ||
WorldStateConfig & | ||
PublisherConfig & | ||
TxSenderConfig & | ||
TxProviderConfig; | ||
|
||
export function getProverNodeConfigFromEnv(): ProverNodeConfig { | ||
const { PROOF_PUBLISH_RETRY_INTERVAL_MS } = process.env; | ||
return { | ||
...getArchiverConfigFromEnv(), | ||
...getProverEnvVars(), | ||
...getWorldStateConfigFromEnv(), | ||
...getTxSenderConfigFromEnv('PROVER'), | ||
...getTxProviderConfigFromEnv(), | ||
l1PublishRetryIntervalMS: PROOF_PUBLISH_RETRY_INTERVAL_MS ? +PROOF_PUBLISH_RETRY_INTERVAL_MS : 1_000, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { createArchiver } from '@aztec/archiver'; | ||
import { createDebugLogger } from '@aztec/foundation/log'; | ||
import { createStore } from '@aztec/kv-store/utils'; | ||
import { createProverClient } from '@aztec/prover-client'; | ||
import { getL1Publisher } from '@aztec/sequencer-client'; | ||
import { PublicProcessorFactory, createSimulationProvider } from '@aztec/simulator'; | ||
import { type TelemetryClient } from '@aztec/telemetry-client'; | ||
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; | ||
import { createWorldStateSynchronizer } from '@aztec/world-state'; | ||
|
||
import { type ProverNodeConfig } from './config.js'; | ||
import { ProverNode } from './prover-node.js'; | ||
import { createTxProvider } from './tx-provider/factory.js'; | ||
|
||
/** Creates a new prover node given a config. */ | ||
export async function createProverNode( | ||
config: ProverNodeConfig, | ||
telemetry: TelemetryClient = new NoopTelemetryClient(), | ||
log = createDebugLogger('aztec:prover'), | ||
storeLog = createDebugLogger('aztec:prover:lmdb'), | ||
) { | ||
const store = await createStore(config, config.l1Contracts.rollupAddress, storeLog); | ||
|
||
const archiver = await createArchiver(config, store, telemetry, { blockUntilSync: true }); | ||
|
||
const worldStateConfig = { ...config, worldStateProvenBlocksOnly: true }; | ||
const worldStateSynchronizer = await createWorldStateSynchronizer(worldStateConfig, store, archiver); | ||
await worldStateSynchronizer.start(); | ||
|
||
const simulationProvider = await createSimulationProvider(config, log); | ||
|
||
const prover = await createProverClient(config, worldStateSynchronizer, archiver); | ||
|
||
// REFACTOR: Move publisher out of sequencer package and into an L1-related package | ||
const publisher = getL1Publisher(config); | ||
|
||
const latestWorldState = worldStateSynchronizer.getLatest(); | ||
const publicProcessorFactory = new PublicProcessorFactory(latestWorldState, archiver, simulationProvider, telemetry); | ||
|
||
const txProvider = createTxProvider(config); | ||
|
||
return new ProverNode(prover!, publicProcessorFactory, publisher, archiver, txProvider); | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import { | ||
type BlockProver, | ||
EmptyTxValidator, | ||
type L2Block, | ||
type L2BlockSource, | ||
type ProcessedTx, | ||
type Tx, | ||
type TxHash, | ||
type TxProvider, | ||
} from '@aztec/circuit-types'; | ||
import { type Fr } from '@aztec/circuits.js'; | ||
import { createDebugLogger } from '@aztec/foundation/log'; | ||
import { type L1Publisher } from '@aztec/sequencer-client'; | ||
import { type PublicProcessor, type PublicProcessorFactory } from '@aztec/simulator'; | ||
|
||
export class BlockProvingJob { | ||
private state: BlockProvingJobState = 'initialized'; | ||
private log = createDebugLogger('aztec:block-proving-job'); | ||
|
||
constructor( | ||
private prover: BlockProver, | ||
private publicProcessorFactory: PublicProcessorFactory, | ||
private publisher: L1Publisher, | ||
private l2BlockSource: L2BlockSource, | ||
private txProvider: TxProvider, | ||
) {} | ||
|
||
public getState(): BlockProvingJobState { | ||
return this.state; | ||
} | ||
|
||
public async run(fromBlock: number, toBlock: number) { | ||
if (fromBlock !== toBlock) { | ||
throw new Error(`Block ranges are not yet supported`); | ||
} | ||
|
||
this.log.info(`Starting block proving job`, { fromBlock, toBlock }); | ||
this.state = 'started'; | ||
|
||
// TODO: Fast-forward world state to fromBlock and/or await fromBlock to be published to the unproven chain | ||
|
||
this.state = 'processing'; | ||
|
||
let historicalHeader = (await this.l2BlockSource.getBlock(fromBlock - 1))?.header; | ||
for (let blockNumber = fromBlock; blockNumber <= toBlock; blockNumber++) { | ||
const block = await this.getBlock(blockNumber); | ||
const globalVariables = block.header.globalVariables; | ||
const txHashes = block.body.txEffects.map(tx => tx.txHash); | ||
const l1ToL2Messages: Fr[] = []; // TODO: grab L1 to L2 messages for this block | ||
|
||
this.log.debug(`Starting block processing`, { blockNumber: block.number, blockHash: block.hash().toString() }); | ||
await this.prover.startNewBlock(txHashes.length, globalVariables, l1ToL2Messages); | ||
const publicProcessor = await this.publicProcessorFactory.create(historicalHeader, globalVariables); | ||
|
||
const txs = await this.getTxs(txHashes); | ||
const txCount = block.body.numberOfTxsIncludingPadded; | ||
await this.processTxs(publicProcessor, txs, txCount); | ||
|
||
this.log.debug(`Processed all txs for block`, { blockNumber: block.number, blockHash: block.hash().toString() }); | ||
await this.prover.setBlockCompleted(); | ||
|
||
historicalHeader = block.header; | ||
} | ||
|
||
this.state = 'awaiting-prover'; | ||
const { block, aggregationObject, proof } = await this.prover.finaliseBlock(); | ||
this.log.info(`Finalised proof for block range`, { fromBlock, toBlock }); | ||
|
||
this.state = 'publishing-proof'; | ||
await this.publisher.submitProof(block.header, block.archive.root, aggregationObject, proof); | ||
this.log.info(`Submitted proof for block range`, { fromBlock, toBlock }); | ||
|
||
this.state = 'completed'; | ||
} | ||
|
||
private async getBlock(blockNumber: number): Promise<L2Block> { | ||
const block = await this.l2BlockSource.getBlock(blockNumber); | ||
if (!block) { | ||
throw new Error(`Block ${blockNumber} not found in L2 block source`); | ||
} | ||
return block; | ||
} | ||
|
||
private async getTxs(txHashes: TxHash[]): Promise<Tx[]> { | ||
const txs = await Promise.all( | ||
txHashes.map(txHash => this.txProvider.getTxByHash(txHash).then(tx => [txHash, tx] as const)), | ||
); | ||
const notFound = txs.filter(([_, tx]) => !tx); | ||
if (notFound.length) { | ||
throw new Error(`Txs not found: ${notFound.map(([txHash]) => txHash.toString()).join(', ')}`); | ||
} | ||
return txs.map(([_, tx]) => tx!); | ||
} | ||
|
||
private async processTxs( | ||
publicProcessor: PublicProcessor, | ||
txs: Tx[], | ||
totalNumberOfTxs: number, | ||
): Promise<ProcessedTx[]> { | ||
const [processedTxs, failedTxs] = await publicProcessor.process( | ||
txs, | ||
totalNumberOfTxs, | ||
this.prover, | ||
new EmptyTxValidator(), | ||
); | ||
|
||
if (failedTxs.length) { | ||
throw new Error( | ||
`Failed to process txs: ${failedTxs.map(({ tx, error }) => `${tx.getTxHash()} (${error})`).join(', ')}`, | ||
); | ||
} | ||
|
||
return processedTxs; | ||
} | ||
} | ||
|
||
export type BlockProvingJobState = | ||
| 'initialized' | ||
| 'started' | ||
| 'processing' | ||
| 'awaiting-prover' | ||
| 'publishing-proof' | ||
| 'completed'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { type L2BlockSource, type ProverClient, type TxProvider } from '@aztec/circuit-types'; | ||
import { createDebugLogger } from '@aztec/foundation/log'; | ||
import { type L1Publisher } from '@aztec/sequencer-client'; | ||
import { type PublicProcessorFactory } from '@aztec/simulator'; | ||
|
||
import { BlockProvingJob } from './job/block-proving-job.js'; | ||
|
||
export class ProverNode { | ||
private log = createDebugLogger('aztec:prover-node'); | ||
|
||
constructor( | ||
private prover: ProverClient, | ||
private publicProcessorFactory: PublicProcessorFactory, | ||
private publisher: L1Publisher, | ||
private l2BlockSource: L2BlockSource, | ||
private txProvider: TxProvider, | ||
) {} | ||
|
||
async stop() { | ||
this.log.info('Stopping ProverNode'); | ||
await this.prover.stop(); | ||
await this.l2BlockSource.stop(); | ||
// TODO: Should we stop the L1Publisher as well? | ||
this.log.info('Stopped ProverNode'); | ||
} | ||
|
||
/** | ||
* Creates a proof for a block range. Returns once the proof has been submitted to L1. | ||
*/ | ||
public prove(fromBlock: number, toBlock: number) { | ||
return this.createProvingJob().run(fromBlock, toBlock); | ||
} | ||
|
||
/** | ||
* Starts a proving process and returns immediately. | ||
*/ | ||
public startProof(fromBlock: number, toBlock: number) { | ||
void this.createProvingJob().run(fromBlock, toBlock); | ||
return Promise.resolve(); | ||
} | ||
|
||
private createProvingJob() { | ||
return new BlockProvingJob( | ||
this.prover, | ||
this.publicProcessorFactory, | ||
this.publisher, | ||
this.l2BlockSource, | ||
this.txProvider, | ||
); | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
yarn-project/prover-node/src/tx-provider/aztec-node-tx-provider.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { type AztecNode, type Tx, type TxHash, type TxProvider } from '@aztec/circuit-types'; | ||
|
||
/** Implements TxProvider by querying an Aztec node for the txs. */ | ||
export class AztecNodeTxProvider implements TxProvider { | ||
constructor(private node: AztecNode) {} | ||
|
||
getTxByHash(txHash: TxHash): Promise<Tx | undefined> { | ||
return this.node.getTxByHash(txHash); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
export type TxProviderConfig = { | ||
txProviderNodeUrl: string | undefined; | ||
}; | ||
|
||
export function getTxProviderConfigFromEnv(): TxProviderConfig { | ||
return { | ||
txProviderNodeUrl: process.env.TX_PROVIDER_NODE_URL, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { type TxProvider, createAztecNodeClient } from '@aztec/circuit-types'; | ||
|
||
import { AztecNodeTxProvider } from './aztec-node-tx-provider.js'; | ||
import { type TxProviderConfig } from './config.js'; | ||
|
||
export function createTxProvider(config: TxProviderConfig): TxProvider { | ||
if (config.txProviderNodeUrl) { | ||
const node = createAztecNodeClient(config.txProviderNodeUrl); | ||
return new AztecNodeTxProvider(node); | ||
} else { | ||
throw new Error(`Tx provider node URL is not set`); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './aztec-node-tx-provider.js'; | ||
export * from './factory.js'; | ||
export * from './config.js'; |
Oops, something went wrong.