diff --git a/yarn-project/cli/package.json b/yarn-project/cli/package.json index 4a6033e3a5f..7c9959d2b1e 100644 --- a/yarn-project/cli/package.json +++ b/yarn-project/cli/package.json @@ -63,6 +63,7 @@ ] }, "dependencies": { + "@aztec/archiver": "workspace:^", "@aztec/aztec.js": "workspace:^", "@aztec/circuit-types": "workspace:^", "@aztec/foundation": "workspace:^", @@ -71,6 +72,7 @@ "@iarna/toml": "^2.2.5", "@libp2p/peer-id-factory": "^3.0.4", "commander": "^12.1.0", + "lodash.groupby": "^4.6.0", "semver": "^7.5.4", "solc": "^0.8.26", "source-map-support": "^0.5.21", @@ -84,6 +86,7 @@ "@aztec/protocol-contracts": "workspace:^", "@jest/globals": "^29.5.0", "@types/jest": "^29.5.0", + "@types/lodash.groupby": "^4.6.9", "@types/lodash.startcase": "^4.4.7", "@types/node": "^18.7.23", "@types/semver": "^7.5.2", diff --git a/yarn-project/cli/src/cmds/l1/index.ts b/yarn-project/cli/src/cmds/l1/index.ts index febe2a446ca..87abe65f357 100644 --- a/yarn-project/cli/src/cmds/l1/index.ts +++ b/yarn-project/cli/src/cmds/l1/index.ts @@ -157,7 +157,7 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: DebugL }); program - .command('set-proven-until') + .command('set-proven-until', { hidden: true }) .description( 'Instructs the L1 rollup contract to assume all blocks until the given number are automatically proven.', ) @@ -188,5 +188,26 @@ export function injectCommands(program: Command, log: LogFn, debugLogger: DebugL ); }); + program + .command('prover-stats', { hidden: true }) + .requiredOption( + '--l1-rpc-url ', + 'Url of the ethereum host. Chain identifiers localhost and testnet can be used', + ETHEREUM_HOST, + ) + .addOption(l1ChainIdOption) + .option('--start-block ', 'The block number to start from', parseBigint, 1n) + .option('--batch-size ', 'The number of blocks to query in each batch', parseBigint, 100n) + .option('--l1-rollup-address ', 'Address of the rollup contract (required if node URL is not set)') + .option( + '--node-url ', + 'JSON RPC URL of an Aztec node to retrieve the rollup contract address (required if L1 rollup address is not set)', + ) + .action(async options => { + const { proverStats } = await import('./prover_stats.js'); + const { l1RpcUrl, chainId, l1RollupAddress, startBlock, batchSize, nodeUrl } = options; + await proverStats({ l1RpcUrl, chainId, l1RollupAddress, startBlock, batchSize, nodeUrl, log }); + }); + return program; } diff --git a/yarn-project/cli/src/cmds/l1/prover_stats.ts b/yarn-project/cli/src/cmds/l1/prover_stats.ts new file mode 100644 index 00000000000..4cda8a13a45 --- /dev/null +++ b/yarn-project/cli/src/cmds/l1/prover_stats.ts @@ -0,0 +1,50 @@ +import { retrieveL2ProofVerifiedEvents } from '@aztec/archiver'; +import { createAztecNodeClient } from '@aztec/circuit-types'; +import { EthAddress } from '@aztec/circuits.js'; +import { createEthereumChain } from '@aztec/ethereum'; +import { type LogFn, createDebugLogger } from '@aztec/foundation/log'; + +import groupBy from 'lodash.groupby'; +import { createPublicClient, http } from 'viem'; + +export async function proverStats(opts: { + l1RpcUrl: string; + chainId: number; + l1RollupAddress: string | undefined; + nodeUrl: string | undefined; + log: LogFn; + startBlock: bigint; + batchSize: bigint; +}) { + const debugLog = createDebugLogger('aztec:cli:prover_stats'); + const { startBlock, chainId, l1RpcUrl, l1RollupAddress, batchSize, nodeUrl, log } = opts; + if (!l1RollupAddress && !nodeUrl) { + throw new Error('Either L1 rollup address or node URL must be set'); + } + const rollup = l1RollupAddress + ? EthAddress.fromString(l1RollupAddress) + : await createAztecNodeClient(nodeUrl!) + .getL1ContractAddresses() + .then(a => a.rollupAddress); + + const chain = createEthereumChain(l1RpcUrl, chainId).chainInfo; + const publicClient = createPublicClient({ chain, transport: http(l1RpcUrl) }); + const lastBlockNum = await publicClient.getBlockNumber(); + debugLog.verbose(`Querying events on rollup at ${rollup.toString()} from ${startBlock} up to ${lastBlockNum}`); + + let blockNum = startBlock; + const events = []; + while (blockNum <= lastBlockNum) { + const end = blockNum + batchSize > lastBlockNum + 1n ? lastBlockNum + 1n : blockNum + batchSize; + debugLog.verbose(`Querying events from block ${blockNum} to ${end}`); + const newEvents = await retrieveL2ProofVerifiedEvents(publicClient, rollup, blockNum, end); + events.push(...newEvents); + debugLog.verbose(`Got ${newEvents.length} events`); + blockNum += batchSize; + } + + const stats = groupBy(events, 'proverId'); + for (const proverId in stats) { + log(`${proverId}, ${stats[proverId].length}`); + } +} diff --git a/yarn-project/cli/tsconfig.json b/yarn-project/cli/tsconfig.json index 69a3c280d81..4d6ad7125a3 100644 --- a/yarn-project/cli/tsconfig.json +++ b/yarn-project/cli/tsconfig.json @@ -6,6 +6,9 @@ "tsBuildInfoFile": ".tsbuildinfo" }, "references": [ + { + "path": "../archiver" + }, { "path": "../aztec.js" }, @@ -15,6 +18,9 @@ { "path": "../foundation" }, + { + "path": "../l1-artifacts" + }, { "path": "../types" }, @@ -27,9 +33,6 @@ { "path": "../ethereum" }, - { - "path": "../l1-artifacts" - }, { "path": "../protocol-contracts" } diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 2f89126d3f8..a5f52210f28 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -448,6 +448,7 @@ __metadata: resolution: "@aztec/cli@workspace:cli" dependencies: "@aztec/accounts": "workspace:^" + "@aztec/archiver": "workspace:^" "@aztec/aztec.js": "workspace:^" "@aztec/circuit-types": "workspace:^" "@aztec/circuits.js": "workspace:^" @@ -460,6 +461,7 @@ __metadata: "@jest/globals": ^29.5.0 "@libp2p/peer-id-factory": ^3.0.4 "@types/jest": ^29.5.0 + "@types/lodash.groupby": ^4.6.9 "@types/lodash.startcase": ^4.4.7 "@types/node": ^18.7.23 "@types/semver": ^7.5.2 @@ -467,6 +469,7 @@ __metadata: commander: ^12.1.0 jest: ^29.5.0 jest-mock-extended: ^3.0.5 + lodash.groupby: ^4.6.0 semver: ^7.5.4 solc: ^0.8.26 source-map-support: ^0.5.21