diff --git a/yarn-project/aztec-node/src/aztec-node/config.ts b/yarn-project/aztec-node/src/aztec-node/config.ts index 15ec2cf7048..ce8af0e112b 100644 --- a/yarn-project/aztec-node/src/aztec-node/config.ts +++ b/yarn-project/aztec-node/src/aztec-node/config.ts @@ -18,12 +18,10 @@ export type AztecNodeConfig = ArchiverConfig & SequencerClientConfig & ProverClientConfig & WorldStateConfig & + Pick & P2PConfig & { /** Whether the sequencer is disabled for this node. */ disableSequencer: boolean; - - /** Whether the prover is disabled for this node. */ - disableProver: boolean; }; export const aztecNodeConfigMappings: ConfigMappingsType = { @@ -37,11 +35,6 @@ export const aztecNodeConfigMappings: ConfigMappingsType = { description: 'Whether the sequencer is disabled for this node.', ...booleanConfigHelper(), }, - disableProver: { - env: 'PROVER_DISABLED', - description: 'Whether the prover is disabled for this node.', - ...booleanConfigHelper(), - }, }; /** diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index cd5b8b8b097..262217e9e46 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -14,7 +14,6 @@ import { LogType, MerkleTreeId, NullifierMembershipWitness, - type ProverClient, type ProverConfig, PublicDataWitness, PublicSimulationOutput, @@ -59,7 +58,6 @@ import { getCanonicalFeeJuice } from '@aztec/protocol-contracts/fee-juice'; import { getCanonicalInstanceDeployer } from '@aztec/protocol-contracts/instance-deployer'; import { getCanonicalKeyRegistryAddress } from '@aztec/protocol-contracts/key-registry'; import { getCanonicalMultiCallEntrypointAddress } from '@aztec/protocol-contracts/multi-call-entrypoint'; -import { createProverClient } from '@aztec/prover-client'; import { AggregateTxValidator, DataTxValidator, @@ -105,7 +103,6 @@ export class AztecNodeService implements AztecNode { protected readonly version: number, protected readonly globalVariableBuilder: GlobalVariableBuilder, protected readonly merkleTreesDb: AztecKVStore, - private readonly prover: ProverClient | undefined, private txValidator: TxValidator, private telemetry: TelemetryClient, private log = createDebugLogger('aztec:node'), @@ -169,12 +166,6 @@ export class AztecNodeService implements AztecNode { const simulationProvider = await createSimulationProvider(config, log); - const prover = await createProverClient(config, telemetry); - - if (!prover && !config.disableSequencer) { - throw new Error("Can't start a sequencer without a prover"); - } - // now create the sequencer const sequencer = config.disableSequencer ? undefined @@ -185,7 +176,6 @@ export class AztecNodeService implements AztecNode { archiver, archiver, archiver, - prover!, simulationProvider, telemetry, ); @@ -204,7 +194,6 @@ export class AztecNodeService implements AztecNode { config.version, getGlobalVariableBuilder(config), store, - prover, txValidator, telemetry, log, @@ -219,10 +208,6 @@ export class AztecNodeService implements AztecNode { return this.sequencer; } - public getProver(): ProverClient | undefined { - return this.prover; - } - public getBlockSource(): L2BlockSource { return this.blockSource; } @@ -381,7 +366,6 @@ export class AztecNodeService implements AztecNode { await this.p2pClient.stop(); await this.worldStateSynchronizer.stop(); await this.blockSource.stop(); - await this.prover?.stop(); this.log.info(`Stopped`); } @@ -771,7 +755,6 @@ export class AztecNodeService implements AztecNode { public async setConfig(config: Partial): Promise { const newConfig = { ...this.config, ...config }; this.sequencer?.updateSequencerConfig(config); - await this.prover?.updateProverConfig(config); if (newConfig.realProofs !== this.config.realProofs) { const proofVerifier = config.realProofs ? await BBCircuitVerifier.new(newConfig) : new TestCircuitVerifier(); diff --git a/yarn-project/aztec/src/cli/cmds/start_node.ts b/yarn-project/aztec/src/cli/cmds/start_node.ts index 511ce520e22..d1e2f1121da 100644 --- a/yarn-project/aztec/src/cli/cmds/start_node.ts +++ b/yarn-project/aztec/src/cli/cmds/start_node.ts @@ -3,7 +3,6 @@ import { type PXE } from '@aztec/circuit-types'; import { NULL_KEY } from '@aztec/ethereum'; import { type ServerList } from '@aztec/foundation/json-rpc/server'; import { type LogFn } from '@aztec/foundation/log'; -import { createProvingJobSourceServer } from '@aztec/prover-client/prover-agent'; import { type TelemetryClientConfig, createAndStartTelemetryClient, @@ -33,9 +32,6 @@ export const startNode = async ( }; if (options.proverNode) { - // TODO(palla/prover-node) We need to tweak the semantics of disableProver so that it doesn't inject - // a null prover into the sequencer, but instead injects a circuit simulator, which is what the - // sequencer ultimately needs. userLog(`Running a Prover Node within a Node is not yet supported`); process.exit(1); } @@ -87,11 +83,6 @@ export const startNode = async ( } } - if (!options.prover) { - userLog(`Prover is disabled, using mocked proofs`); - nodeConfig.disableProver = true; - } - if (nodeConfig.p2pEnabled) { // ensure bootstrapNodes is an array if (nodeConfig.bootstrapNodes && typeof nodeConfig.bootstrapNodes === 'string') { @@ -99,12 +90,6 @@ export const startNode = async ( } } - if (!nodeConfig.disableSequencer && nodeConfig.disableProver) { - // TODO(palla/prover-node) Sequencer should not need a prover unless we are running the prover - // within it, it should just need a circuit simulator. We need to refactor the sequencer so it can accept either. - throw new Error('Cannot run a sequencer without a prover'); - } - const telemetryConfig = extractRelevantOptions(options, telemetryClientConfigMappings); const telemetryClient = createAndStartTelemetryClient(telemetryConfig); @@ -115,11 +100,6 @@ export const startNode = async ( // Add node to services list services.push({ node: nodeServer }); - if (!nodeConfig.disableProver) { - const provingJobSource = createProvingJobSourceServer(node.getProver()!.getProvingJobSource()); - services.push({ provingJobSource }); - } - // Add node stop function to signal handlers signalHandlers.push(node.stop); diff --git a/yarn-project/bb-prover/src/test/test_circuit_prover.ts b/yarn-project/bb-prover/src/test/test_circuit_prover.ts index a3530c272a7..f9c5560e5be 100644 --- a/yarn-project/bb-prover/src/test/test_circuit_prover.ts +++ b/yarn-project/bb-prover/src/test/test_circuit_prover.ts @@ -65,8 +65,8 @@ import { SimulatedPublicKernelArtifactMapping } from '../mappings/mappings.js'; import { mapPublicKernelToCircuitName } from '../stats.js'; /** - * A class for use in testing situations (e2e, unit test etc) - * Simulates circuits using the most efficient method and performs no proving + * A class for use in testing situations (e2e, unit test, etc) and temporarily for assembling a block in the sequencer. + * Simulates circuits using the most efficient method and performs no proving. */ export class TestCircuitProver implements ServerCircuitProver { private wasmSimulator = new WASMSimulator(); diff --git a/yarn-project/circuit-types/src/interfaces/block-prover.ts b/yarn-project/circuit-types/src/interfaces/block-prover.ts index a2afdc2f494..4823fcbc505 100644 --- a/yarn-project/circuit-types/src/interfaces/block-prover.ts +++ b/yarn-project/circuit-types/src/interfaces/block-prover.ts @@ -23,48 +23,52 @@ export type ProvingTicket = { provingPromise: Promise; }; -export type BlockResult = { +export type SimulationBlockResult = { block: L2Block; +}; + +export type ProvingBlockResult = SimulationBlockResult & { proof: Proof; aggregationObject: Fr[]; }; -/** - * The interface to the block prover. - * Provides the ability to generate proofs and build rollups. - */ -export interface BlockProver { +/** Receives processed txs as part of block simulation or proving. */ +export interface ProcessedTxHandler { /** - * Cancels any block that is currently being built and prepares for a new one to be built + * Add a processed transaction to the current block. + * @param tx - The transaction to be added. + */ + addNewTx(tx: ProcessedTx): Promise; +} + +/** The interface to a block simulator. Generates an L2 block out of a set of processed txs by calling into the Aztec circuits. */ +export interface BlockSimulator extends ProcessedTxHandler { + /** + * Prepares to build a new block. * @param numTxs - The complete size of the block, must be a power of 2 * @param globalVariables - The global variables for this block * @param l1ToL2Messages - The set of L1 to L2 messages to be included in this block - * @param emptyTx - An instance of an empty transaction to be used in this block */ startNewBlock(numTxs: number, globalVariables: GlobalVariables, l1ToL2Messages: Fr[]): Promise; - /** - * Add a processed transaction to the current block - * @param tx - The transaction to be added - */ - addNewTx(tx: ProcessedTx): Promise; - - /** - * Cancels the block currently being proven. Proofs already bring built may continue but further proofs should not be started. - */ + /** Cancels the block currently being processed. Processes already in progress built may continue but further proofs should not be started. */ cancelBlock(): void; - /** - * Performs the final archive tree insertion for this block and returns the L2Block and Proof instances - */ - finaliseBlock(): Promise; + /** Performs the final archive tree insertion for this block and returns the L2Block. */ + finaliseBlock(): Promise; /** * Mark the block as having all the transactions it is going to contain. - * Will pad the block to it's complete size with empty transactions and prove all the way to the root rollup. + * Will pad the block to its complete size with empty transactions and prove all the way to the root rollup. */ setBlockCompleted(): Promise; +} +/** The interface to a block prover. Generates a root rollup proof out of a set of processed txs by recursively proving Aztec circuits. */ +export interface BlockProver extends BlockSimulator { /** Returns an identifier for the prover or zero if not set. */ getProverId(): Fr; + + /** Performs the final archive tree insertion for this block and returns the L2Block. */ + finaliseBlock(): Promise; } diff --git a/yarn-project/circuit-types/src/interfaces/configs.ts b/yarn-project/circuit-types/src/interfaces/configs.ts index eeb03ac6950..020b4e09877 100644 --- a/yarn-project/circuit-types/src/interfaces/configs.ts +++ b/yarn-project/circuit-types/src/interfaces/configs.ts @@ -37,6 +37,4 @@ export interface SequencerConfig { maxBlockSizeInBytes?: number; /** Whether to require every tx to have a fee payer */ enforceFees?: boolean; - /** Temporary flag to skip submitting proofs, so a prover-node takes care of it. */ - sequencerSkipSubmitProofs?: boolean; } diff --git a/yarn-project/end-to-end/src/e2e_prover_node.test.ts b/yarn-project/end-to-end/src/e2e_prover_node.test.ts index df5a6207904..a2bc44ea239 100644 --- a/yarn-project/end-to-end/src/e2e_prover_node.test.ts +++ b/yarn-project/end-to-end/src/e2e_prover_node.test.ts @@ -16,7 +16,6 @@ import { } from '@aztec/aztec.js'; import { StatefulTestContract, TestContract } from '@aztec/noir-contracts.js'; import { createProverNode } from '@aztec/prover-node'; -import { type SequencerClientConfig } from '@aztec/sequencer-client'; import { sendL1ToL2Message } from './fixtures/l1_to_l2_messaging.js'; import { @@ -46,8 +45,7 @@ describe('e2e_prover_node', () => { beforeAll(async () => { logger = createDebugLogger('aztec:e2e_prover_node'); - const config: Partial = { sequencerSkipSubmitProofs: true }; - snapshotManager = createSnapshotManager(`e2e_prover_node`, process.env.E2E_DATA_PATH, config); + snapshotManager = createSnapshotManager(`e2e_prover_node`, process.env.E2E_DATA_PATH); const testContractOpts = { contractAddressSalt: Fr.ONE, universalDeploy: true }; await snapshotManager.snapshot( diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index d50b60fcafc..2edf2a92d8a 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -61,7 +61,6 @@ import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types'; import { getCanonicalAuthRegistry } from '@aztec/protocol-contracts/auth-registry'; import { FeeJuiceAddress, getCanonicalFeeJuice } from '@aztec/protocol-contracts/fee-juice'; import { getCanonicalKeyRegistry } from '@aztec/protocol-contracts/key-registry'; -import { type ProverClient } from '@aztec/prover-client'; import { PXEService, type PXEServiceConfig, createPXEService, getPXEServiceConfig } from '@aztec/pxe'; import { type SequencerClient } from '@aztec/sequencer-client'; import { createAndStartTelemetryClient, getConfigEnvVars as getTelemetryConfig } from '@aztec/telemetry-client/start'; @@ -303,8 +302,6 @@ export type EndToEndContext = { logger: DebugLogger; /** The cheat codes. */ cheatCodes: CheatCodes; - /** Proving jobs */ - prover: ProverClient | undefined; /** Function to stop the started services. */ teardown: () => Promise; }; @@ -381,7 +378,6 @@ export async function setup( config.l1PublishRetryIntervalMS = 100; const aztecNode = await AztecNodeService.createAndSync(config, telemetry); const sequencer = aztecNode.getSequencer(); - const prover = aztecNode.getProver(); logger.verbose('Creating a pxe...'); @@ -434,7 +430,6 @@ export async function setup( logger, cheatCodes, sequencer, - prover, teardown, }; } diff --git a/yarn-project/prover-client/package.json b/yarn-project/prover-client/package.json index afb8851498c..6f451907c83 100644 --- a/yarn-project/prover-client/package.json +++ b/yarn-project/prover-client/package.json @@ -4,7 +4,8 @@ "type": "module", "exports": { ".": "./dest/index.js", - "./prover-agent": "./dest/prover-agent/index.js" + "./prover-agent": "./dest/prover-agent/index.js", + "./orchestrator": "./dest/orchestrator/index.js" }, "typedocOptions": { "entryPoints": [ diff --git a/yarn-project/prover-client/src/config.ts b/yarn-project/prover-client/src/config.ts index fb751c5c605..cfb598feb69 100644 --- a/yarn-project/prover-client/src/config.ts +++ b/yarn-project/prover-client/src/config.ts @@ -1,5 +1,5 @@ import { type ProverConfig, proverConfigMappings } from '@aztec/circuit-types'; -import { type ConfigMappingsType, booleanConfigHelper, getConfigFromMappings } from '@aztec/foundation/config'; +import { type ConfigMappingsType, getConfigFromMappings } from '@aztec/foundation/config'; /** * The prover configuration. @@ -13,8 +13,6 @@ export type ProverClientConfig = ProverConfig & { bbWorkingDirectory: string; /** The path to the bb binary */ bbBinaryPath: string; - /** True to disable proving altogether. */ - disableProver: boolean; }; export const proverClientConfigMappings: ConfigMappingsType = { @@ -34,11 +32,6 @@ export const proverClientConfigMappings: ConfigMappingsType env: 'BB_BINARY_PATH', description: 'The path to the bb binary', }, - disableProver: { - env: 'PROVER_DISABLED', - description: 'Whether to disable proving.', - ...booleanConfigHelper(), - }, ...proverConfigMappings, }; diff --git a/yarn-project/prover-client/src/orchestrator/index.ts b/yarn-project/prover-client/src/orchestrator/index.ts new file mode 100644 index 00000000000..a4b15f3e891 --- /dev/null +++ b/yarn-project/prover-client/src/orchestrator/index.ts @@ -0,0 +1 @@ +export { ProvingOrchestrator } from './orchestrator.js'; diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator.ts b/yarn-project/prover-client/src/orchestrator/orchestrator.ts index ae00044dcda..8fa8902d9cd 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator.ts @@ -18,8 +18,8 @@ import { import { BlockProofError, type BlockProver, - type BlockResult, PROVING_STATUS, + type ProvingBlockResult, type ProvingResult, type ProvingTicket, type PublicInputsAndRecursiveProof, @@ -450,7 +450,7 @@ export class ProvingOrchestrator implements BlockProver { this.provingState.block = l2Block; - const blockResult: BlockResult = { + const blockResult: ProvingBlockResult = { proof: this.provingState.finalProof, aggregationObject: this.provingState.finalAggregationObject, block: l2Block, diff --git a/yarn-project/prover-client/src/tx-prover/factory.ts b/yarn-project/prover-client/src/tx-prover/factory.ts index 742002239a8..d81ff2e15e7 100644 --- a/yarn-project/prover-client/src/tx-prover/factory.ts +++ b/yarn-project/prover-client/src/tx-prover/factory.ts @@ -5,5 +5,5 @@ import { type ProverClientConfig } from '../config.js'; import { TxProver } from './tx-prover.js'; export function createProverClient(config: ProverClientConfig, telemetry: TelemetryClient = new NoopTelemetryClient()) { - return config.disableProver ? undefined : TxProver.new(config, telemetry); + return TxProver.new(config, telemetry); } diff --git a/yarn-project/sequencer-client/package.json b/yarn-project/sequencer-client/package.json index 96574ecbb1b..0445a6ed59d 100644 --- a/yarn-project/sequencer-client/package.json +++ b/yarn-project/sequencer-client/package.json @@ -24,6 +24,7 @@ "test:integration:run": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --config jest.integration.config.json" }, "dependencies": { + "@aztec/bb-prover": "workspace:^", "@aztec/circuit-types": "workspace:^", "@aztec/circuits.js": "workspace:^", "@aztec/ethereum": "workspace:^", @@ -34,6 +35,7 @@ "@aztec/noir-protocol-circuits-types": "workspace:^", "@aztec/p2p": "workspace:^", "@aztec/protocol-contracts": "workspace:^", + "@aztec/prover-client": "workspace:^", "@aztec/simulator": "workspace:^", "@aztec/telemetry-client": "workspace:^", "@aztec/types": "workspace:^", diff --git a/yarn-project/sequencer-client/src/block_builder/index.ts b/yarn-project/sequencer-client/src/block_builder/index.ts new file mode 100644 index 00000000000..0b32950acda --- /dev/null +++ b/yarn-project/sequencer-client/src/block_builder/index.ts @@ -0,0 +1,51 @@ +import { TestCircuitProver } from '@aztec/bb-prover'; +import { + type BlockSimulator, + type MerkleTreeOperations, + type ProcessedTx, + type ProvingTicket, + type SimulationBlockResult, +} from '@aztec/circuit-types'; +import { type Fr, type GlobalVariables } from '@aztec/circuits.js'; +import { ProvingOrchestrator } from '@aztec/prover-client/orchestrator'; +import { type SimulationProvider } from '@aztec/simulator'; +import { type TelemetryClient } from '@aztec/telemetry-client'; +import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; + +/** + * Implements a block simulator using a test circuit prover under the hood, which just simulates circuits and outputs empty proofs. + * This class is temporary and should die once we switch from tx effects to tx objects submissions, since sequencers won't have + * the need to create L2 block headers to submit to L1. When we do that, we should also remove the references to the + * prover-client and bb-prover packages from this package. + */ +export class BlockBuilder implements BlockSimulator { + private orchestrator: ProvingOrchestrator; + constructor(db: MerkleTreeOperations, simulationProvider: SimulationProvider, telemetry: TelemetryClient) { + const testProver = new TestCircuitProver(telemetry, simulationProvider); + this.orchestrator = new ProvingOrchestrator(db, testProver, telemetry); + } + + startNewBlock(numTxs: number, globalVariables: GlobalVariables, l1ToL2Messages: Fr[]): Promise { + return this.orchestrator.startNewBlock(numTxs, globalVariables, l1ToL2Messages); + } + cancelBlock(): void { + this.orchestrator.cancelBlock(); + } + finaliseBlock(): Promise { + return this.orchestrator.finaliseBlock(); + } + setBlockCompleted(): Promise { + return this.orchestrator.setBlockCompleted(); + } + addNewTx(tx: ProcessedTx): Promise { + return this.orchestrator.addNewTx(tx); + } +} + +export class BlockBuilderFactory { + constructor(private simulationProvider: SimulationProvider, private telemetry?: TelemetryClient) {} + + create(db: MerkleTreeOperations): BlockSimulator { + return new BlockBuilder(db, this.simulationProvider, this.telemetry ?? new NoopTelemetryClient()); + } +} diff --git a/yarn-project/sequencer-client/src/client/sequencer-client.ts b/yarn-project/sequencer-client/src/client/sequencer-client.ts index dcb72921a15..a3cc6060d56 100644 --- a/yarn-project/sequencer-client/src/client/sequencer-client.ts +++ b/yarn-project/sequencer-client/src/client/sequencer-client.ts @@ -1,11 +1,11 @@ import { type L1ToL2MessageSource, type L2BlockSource } from '@aztec/circuit-types'; -import { type ProverClient } from '@aztec/circuit-types/interfaces'; import { type P2P } from '@aztec/p2p'; import { PublicProcessorFactory, type SimulationProvider } from '@aztec/simulator'; import { type TelemetryClient } from '@aztec/telemetry-client'; import { type ContractDataSource } from '@aztec/types/contracts'; import { type WorldStateSynchronizer } from '@aztec/world-state'; +import { BlockBuilderFactory } from '../block_builder/index.js'; import { type SequencerClientConfig } from '../config.js'; import { getGlobalVariableBuilder } from '../global_variable_builder/index.js'; import { getL1Publisher } from '../publisher/index.js'; @@ -37,7 +37,6 @@ export class SequencerClient { contractDataSource: ContractDataSource, l2BlockSource: L2BlockSource, l1ToL2MessageSource: L1ToL2MessageSource, - prover: ProverClient, simulationProvider: SimulationProvider, telemetryClient: TelemetryClient, ) { @@ -57,7 +56,7 @@ export class SequencerClient { globalsBuilder, p2pClient, worldStateSynchronizer, - prover, + new BlockBuilderFactory(simulationProvider, telemetryClient), l2BlockSource, l1ToL2MessageSource, publicProcessorFactory, diff --git a/yarn-project/sequencer-client/src/config.ts b/yarn-project/sequencer-client/src/config.ts index d9f8317aa68..3451fe099ed 100644 --- a/yarn-project/sequencer-client/src/config.ts +++ b/yarn-project/sequencer-client/src/config.ts @@ -104,11 +104,6 @@ export const sequencerConfigMappings: ConfigMappingsType = { description: 'Whether to require every tx to have a fee payer', ...booleanConfigHelper(), }, - sequencerSkipSubmitProofs: { - env: 'SEQ_SKIP_SUBMIT_PROOFS', - description: 'Temporary flag to skip submitting proofs, so a prover-node takes care of it.', - ...booleanConfigHelper(), - }, }; export const chainConfigMappings: ConfigMappingsType = { diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index b79d22eda7d..1d8e9e79b84 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -1,11 +1,10 @@ import { - type BlockProver, + type BlockSimulator, type L1ToL2MessageSource, L2Block, type L2BlockSource, MerkleTreeId, PROVING_STATUS, - type ProverClient, type ProvingSuccess, type ProvingTicket, type Tx, @@ -22,7 +21,6 @@ import { GlobalVariables, IS_DEV_NET, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, - makeEmptyProof, } from '@aztec/circuits.js'; import { randomBytes } from '@aztec/foundation/crypto'; import { type Writeable } from '@aztec/foundation/types'; @@ -34,6 +32,7 @@ import { type MerkleTreeOperations, WorldStateRunningState, type WorldStateSynch import { type MockProxy, mock, mockFn } from 'jest-mock-extended'; +import { type BlockBuilderFactory } from '../block_builder/index.js'; import { type GlobalVariableBuilder } from '../global_variable_builder/global_builder.js'; import { type L1Publisher } from '../publisher/l1-publisher.js'; import { TxValidatorFactory } from '../tx_validator/tx_validator_factory.js'; @@ -44,8 +43,7 @@ describe('sequencer', () => { let globalVariableBuilder: MockProxy; let p2p: MockProxy; let worldState: MockProxy; - let blockProver: MockProxy; - let proverClient: MockProxy; + let blockSimulator: MockProxy; let merkleTreeOps: MockProxy; let publicProcessor: MockProxy; let l2BlockSource: MockProxy; @@ -85,11 +83,7 @@ describe('sequencer', () => { globalVariableBuilder = mock(); merkleTreeOps = mock(); - blockProver = mock(); - - proverClient = mock({ - createBlockProver: () => blockProver, - }); + blockSimulator = mock(); p2p = mock({ getStatus: () => Promise.resolve({ state: P2PClientState.IDLE, syncedToL2Block: lastBlockNumber }), @@ -127,12 +121,16 @@ describe('sequencer', () => { getContractClass: mockFn().mockResolvedValue(fpcClassId), }); + const blockBuilderFactory = mock({ + create: () => blockSimulator, + }); + sequencer = new TestSubject( publisher, globalVariableBuilder, p2p, worldState, - proverClient, + blockBuilderFactory, l2BlockSource, l1ToL2MessageSource, publicProcessorFactory, @@ -145,7 +143,6 @@ describe('sequencer', () => { const tx = mockTxForRollup(); tx.data.constants.txContext.chainId = chainId; const block = L2Block.random(lastBlockNumber + 1); - const proof = makeEmptyProof(); const result: ProvingSuccess = { status: PROVING_STATUS.SUCCESS, }; @@ -154,8 +151,8 @@ describe('sequencer', () => { }; p2p.getTxs.mockReturnValueOnce([tx]); - blockProver.startNewBlock.mockResolvedValueOnce(ticket); - blockProver.finaliseBlock.mockResolvedValue({ block, aggregationObject: [], proof }); + blockSimulator.startNewBlock.mockResolvedValueOnce(ticket); + blockSimulator.finaliseBlock.mockResolvedValue({ block }); publisher.processL2Block.mockResolvedValueOnce(true); const mockedGlobalVariables = new GlobalVariables( @@ -174,21 +171,20 @@ describe('sequencer', () => { await sequencer.initialSync(); await sequencer.work(); - expect(blockProver.startNewBlock).toHaveBeenCalledWith( + expect(blockSimulator.startNewBlock).toHaveBeenCalledWith( 2, mockedGlobalVariables, Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), ); expect(publisher.processL2Block).toHaveBeenCalledTimes(1); expect(publisher.processL2Block).toHaveBeenCalledWith(block, getAttestations()); - expect(blockProver.cancelBlock).toHaveBeenCalledTimes(0); + expect(blockSimulator.cancelBlock).toHaveBeenCalledTimes(0); }); it('builds a block when it is their turn', async () => { const tx = mockTxForRollup(); tx.data.constants.txContext.chainId = chainId; const block = L2Block.random(lastBlockNumber + 1); - const proof = makeEmptyProof(); const result: ProvingSuccess = { status: PROVING_STATUS.SUCCESS, }; @@ -197,8 +193,8 @@ describe('sequencer', () => { }; p2p.getTxs.mockReturnValueOnce([tx]); - blockProver.startNewBlock.mockResolvedValueOnce(ticket); - blockProver.finaliseBlock.mockResolvedValue({ block, aggregationObject: [], proof }); + blockSimulator.startNewBlock.mockResolvedValueOnce(ticket); + blockSimulator.finaliseBlock.mockResolvedValue({ block }); publisher.processL2Block.mockResolvedValueOnce(true); const mockedGlobalVariables = new GlobalVariables( @@ -218,18 +214,18 @@ describe('sequencer', () => { publisher.isItMyTurnToSubmit.mockClear().mockResolvedValue(false); await sequencer.initialSync(); await sequencer.work(); - expect(blockProver.startNewBlock).not.toHaveBeenCalled(); + expect(blockSimulator.startNewBlock).not.toHaveBeenCalled(); // Now it is! publisher.isItMyTurnToSubmit.mockClear().mockResolvedValue(true); await sequencer.work(); - expect(blockProver.startNewBlock).toHaveBeenCalledWith( + expect(blockSimulator.startNewBlock).toHaveBeenCalledWith( 2, mockedGlobalVariables, Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), ); expect(publisher.processL2Block).toHaveBeenCalledWith(block, getAttestations()); - expect(blockProver.cancelBlock).toHaveBeenCalledTimes(0); + expect(blockSimulator.cancelBlock).toHaveBeenCalledTimes(0); }); it('builds a block out of several txs rejecting double spends', async () => { @@ -239,7 +235,6 @@ describe('sequencer', () => { }); const doubleSpendTx = txs[1]; const block = L2Block.random(lastBlockNumber + 1); - const proof = makeEmptyProof(); const result: ProvingSuccess = { status: PROVING_STATUS.SUCCESS, }; @@ -248,8 +243,8 @@ describe('sequencer', () => { }; p2p.getTxs.mockReturnValueOnce(txs); - blockProver.startNewBlock.mockResolvedValueOnce(ticket); - blockProver.finaliseBlock.mockResolvedValue({ block, aggregationObject: [], proof }); + blockSimulator.startNewBlock.mockResolvedValueOnce(ticket); + blockSimulator.finaliseBlock.mockResolvedValue({ block }); publisher.processL2Block.mockResolvedValueOnce(true); const mockedGlobalVariables = new GlobalVariables( @@ -276,14 +271,14 @@ describe('sequencer', () => { await sequencer.initialSync(); await sequencer.work(); - expect(blockProver.startNewBlock).toHaveBeenCalledWith( + expect(blockSimulator.startNewBlock).toHaveBeenCalledWith( 2, mockedGlobalVariables, Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), ); expect(publisher.processL2Block).toHaveBeenCalledWith(block, getAttestations()); expect(p2p.deleteTxs).toHaveBeenCalledWith([doubleSpendTx.getTxHash()]); - expect(blockProver.cancelBlock).toHaveBeenCalledTimes(0); + expect(blockSimulator.cancelBlock).toHaveBeenCalledTimes(0); }); it('builds a block out of several txs rejecting incorrect chain ids', async () => { @@ -293,7 +288,6 @@ describe('sequencer', () => { }); const invalidChainTx = txs[1]; const block = L2Block.random(lastBlockNumber + 1); - const proof = makeEmptyProof(); const result: ProvingSuccess = { status: PROVING_STATUS.SUCCESS, }; @@ -302,8 +296,8 @@ describe('sequencer', () => { }; p2p.getTxs.mockReturnValueOnce(txs); - blockProver.startNewBlock.mockResolvedValueOnce(ticket); - blockProver.finaliseBlock.mockResolvedValue({ block, aggregationObject: [], proof }); + blockSimulator.startNewBlock.mockResolvedValueOnce(ticket); + blockSimulator.finaliseBlock.mockResolvedValue({ block }); publisher.processL2Block.mockResolvedValueOnce(true); const mockedGlobalVariables = new GlobalVariables( @@ -325,14 +319,14 @@ describe('sequencer', () => { await sequencer.initialSync(); await sequencer.work(); - expect(blockProver.startNewBlock).toHaveBeenCalledWith( + expect(blockSimulator.startNewBlock).toHaveBeenCalledWith( 2, mockedGlobalVariables, Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), ); expect(publisher.processL2Block).toHaveBeenCalledWith(block, getAttestations()); expect(p2p.deleteTxs).toHaveBeenCalledWith([invalidChainTx.getTxHash()]); - expect(blockProver.cancelBlock).toHaveBeenCalledTimes(0); + expect(blockSimulator.cancelBlock).toHaveBeenCalledTimes(0); }); it('builds a block out of several txs dropping the ones that go over max size', async () => { @@ -341,7 +335,6 @@ describe('sequencer', () => { tx.data.constants.txContext.chainId = chainId; }); const block = L2Block.random(lastBlockNumber + 1); - const proof = makeEmptyProof(); const result: ProvingSuccess = { status: PROVING_STATUS.SUCCESS, }; @@ -350,8 +343,8 @@ describe('sequencer', () => { }; p2p.getTxs.mockReturnValueOnce(txs); - blockProver.startNewBlock.mockResolvedValueOnce(ticket); - blockProver.finaliseBlock.mockResolvedValue({ block, aggregationObject: [], proof }); + blockSimulator.startNewBlock.mockResolvedValueOnce(ticket); + blockSimulator.finaliseBlock.mockResolvedValue({ block }); publisher.processL2Block.mockResolvedValueOnce(true); const mockedGlobalVariables = new GlobalVariables( @@ -374,20 +367,19 @@ describe('sequencer', () => { await sequencer.initialSync(); await sequencer.work(); - expect(blockProver.startNewBlock).toHaveBeenCalledWith( + expect(blockSimulator.startNewBlock).toHaveBeenCalledWith( 2, mockedGlobalVariables, Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), ); expect(publisher.processL2Block).toHaveBeenCalledWith(block, getAttestations()); - expect(blockProver.cancelBlock).toHaveBeenCalledTimes(0); + expect(blockSimulator.cancelBlock).toHaveBeenCalledTimes(0); }); it('aborts building a block if the chain moves underneath it', async () => { const tx = mockTxForRollup(); tx.data.constants.txContext.chainId = chainId; const block = L2Block.random(lastBlockNumber + 1); - const proof = makeEmptyProof(); const result: ProvingSuccess = { status: PROVING_STATUS.SUCCESS, }; @@ -396,8 +388,8 @@ describe('sequencer', () => { }; p2p.getTxs.mockReturnValueOnce([tx]); - blockProver.startNewBlock.mockResolvedValueOnce(ticket); - blockProver.finaliseBlock.mockResolvedValue({ block, aggregationObject: [], proof }); + blockSimulator.startNewBlock.mockResolvedValueOnce(ticket); + blockSimulator.finaliseBlock.mockResolvedValue({ block }); publisher.processL2Block.mockResolvedValueOnce(true); const mockedGlobalVariables = new GlobalVariables( diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index ffa1d5d8fb5..ccb1168ebed 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -6,12 +6,7 @@ import { Tx, type TxValidator, } from '@aztec/circuit-types'; -import { - type AllowedElement, - BlockProofError, - PROVING_STATUS, - type ProverClient, -} from '@aztec/circuit-types/interfaces'; +import { type AllowedElement, BlockProofError, PROVING_STATUS } from '@aztec/circuit-types/interfaces'; import { type L2BlockBuiltStats } from '@aztec/circuit-types/stats'; import { AztecAddress, EthAddress, type GlobalVariables, type Header, IS_DEV_NET } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; @@ -23,6 +18,7 @@ import { type PublicProcessorFactory } from '@aztec/simulator'; import { Attributes, type TelemetryClient, type Tracer, trackSpan } from '@aztec/telemetry-client'; import { type WorldStateStatus, type WorldStateSynchronizer } from '@aztec/world-state'; +import { type BlockBuilderFactory } from '../block_builder/index.js'; import { type GlobalVariableBuilder } from '../global_variable_builder/global_builder.js'; import { type Attestation, type L1Publisher } from '../publisher/l1-publisher.js'; import { type TxValidatorFactory } from '../tx_validator/tx_validator_factory.js'; @@ -53,7 +49,6 @@ export class Sequencer { private allowedInSetup: AllowedElement[] = []; private allowedInTeardown: AllowedElement[] = []; private maxBlockSizeInBytes: number = 1024 * 1024; - private skipSubmitProofs: boolean = false; private metrics: SequencerMetrics; constructor( @@ -61,13 +56,13 @@ export class Sequencer { private globalsBuilder: GlobalVariableBuilder, private p2pClient: P2P, private worldState: WorldStateSynchronizer, - private prover: ProverClient, + private blockBuilderFactory: BlockBuilderFactory, private l2BlockSource: L2BlockSource, private l1ToL2MessageSource: L1ToL2MessageSource, private publicProcessorFactory: PublicProcessorFactory, private txValidatorFactory: TxValidatorFactory, telemetry: TelemetryClient, - config: SequencerConfig = {}, + private config: SequencerConfig = {}, private log = createDebugLogger('aztec:sequencer'), ) { this.updateConfig(config); @@ -115,10 +110,8 @@ export class Sequencer { if (config.allowedInTeardown) { this.allowedInTeardown = config.allowedInTeardown; } - // TODO(palla/prover) This flag should not be needed: the sequencer should be initialized with a blockprover - // that does not return proofs at all (just simulates circuits), and use that to determine whether to submit - // proofs or not. - this.skipSubmitProofs = !!config.sequencerSkipSubmitProofs; + // TODO: Just read everything from the config object as needed instead of copying everything into local vars. + this.config = config; } /** @@ -318,11 +311,11 @@ export class Sequencer { const blockSize = Math.max(2, numRealTxs); const blockBuildingTimer = new Timer(); - const prover = this.prover.createBlockProver(this.worldState.getLatest()); - const blockTicket = await prover.startNewBlock(blockSize, newGlobalVariables, l1ToL2Messages); + const blockBuilder = this.blockBuilderFactory.create(this.worldState.getLatest()); + const blockTicket = await blockBuilder.startNewBlock(blockSize, newGlobalVariables, l1ToL2Messages); const [publicProcessorDuration, [processedTxs, failedTxs]] = await elapsed(() => - processor.process(validTxs, blockSize, prover, this.txValidatorFactory.validatorForProcessedTxs()), + processor.process(validTxs, blockSize, blockBuilder, this.txValidatorFactory.validatorForProcessedTxs()), ); if (failedTxs.length > 0) { const failedTxData = failedTxs.map(fail => fail.tx); @@ -336,14 +329,14 @@ export class Sequencer { // we should bail. if (processedTxs.length === 0 && !this.skipMinTxsPerBlockCheck(elapsedSinceLastBlock)) { this.log.verbose('No txs processed correctly to build block. Exiting'); - prover.cancelBlock(); + blockBuilder.cancelBlock(); return; } await assertBlockHeight(); // All real transactions have been added, set the block as full and complete the proving. - await prover.setBlockCompleted(); + await blockBuilder.setBlockCompleted(); // Here we are now waiting for the block to be proven. // TODO(@PhilWindle) We should probably periodically check for things like another @@ -355,8 +348,8 @@ export class Sequencer { await assertBlockHeight(); - // Block is proven, now finalise and publish! - const { block, aggregationObject, proof } = await prover.finaliseBlock(); + // Block is ready, now finalise and publish! + const { block } = await blockBuilder.finaliseBlock(); await assertBlockHeight(); @@ -387,20 +380,6 @@ export class Sequencer { this.metrics.recordFailedBlock(); throw err; } - - // Submit the proof if we have configured this sequencer to run with an actual prover. - // This is temporary while we submit one proof per block, but will have to change once we - // move onto proving batches of multiple blocks at a time. - if (aggregationObject && proof && !this.skipSubmitProofs) { - await this.publisher.submitProof( - block.header, - block.archive.root, - prover.getProverId(), - aggregationObject, - proof, - ); - this.log.info(`Submitted proof for block ${block.number}`); - } } protected async collectAttestations(block: L2Block): Promise { diff --git a/yarn-project/sequencer-client/tsconfig.json b/yarn-project/sequencer-client/tsconfig.json index b4140a80da4..cff0c4789de 100644 --- a/yarn-project/sequencer-client/tsconfig.json +++ b/yarn-project/sequencer-client/tsconfig.json @@ -6,6 +6,9 @@ "tsBuildInfoFile": ".tsbuildinfo" }, "references": [ + { + "path": "../bb-prover" + }, { "path": "../circuit-types" }, @@ -36,6 +39,9 @@ { "path": "../protocol-contracts" }, + { + "path": "../prover-client" + }, { "path": "../simulator" }, diff --git a/yarn-project/simulator/src/public/public_processor.ts b/yarn-project/simulator/src/public/public_processor.ts index f2fbdf92352..84cffb190f0 100644 --- a/yarn-project/simulator/src/public/public_processor.ts +++ b/yarn-project/simulator/src/public/public_processor.ts @@ -1,8 +1,8 @@ import { - type BlockProver, type FailedTx, NestedProcessReturnValues, type ProcessedTx, + type ProcessedTxHandler, PublicKernelType, type PublicProvingRequest, type SimulationError, @@ -116,12 +116,13 @@ export class PublicProcessor { /** * Run each tx through the public circuit and the public kernel circuit if needed. * @param txs - Txs to process. + * @param processedTxHandler - Handler for processed txs in the context of block building or proving. * @returns The list of processed txs with their circuit simulation outputs. */ public async process( txs: Tx[], maxTransactions = txs.length, - blockProver?: BlockProver, + processedTxHandler?: ProcessedTxHandler, txValidator?: TxValidator, ): Promise<[ProcessedTx[], FailedTx[], NestedProcessReturnValues[]]> { // The processor modifies the tx objects in place, so we need to clone them. @@ -164,9 +165,9 @@ export class PublicProcessor { throw new Error(`Transaction ${invalid[0].hash} invalid after processing public functions`); } } - // if we were given a prover then send the transaction to it for proving - if (blockProver) { - await blockProver.addNewTx(processedTx); + // if we were given a handler then send the transaction to it for block building or proving + if (processedTxHandler) { + await processedTxHandler.addNewTx(processedTx); } result.push(processedTx); returns = returns.concat(returnValues ?? []); diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index bf70edd1a0a..c34c9923500 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -988,6 +988,7 @@ __metadata: version: 0.0.0-use.local resolution: "@aztec/sequencer-client@workspace:sequencer-client" dependencies: + "@aztec/bb-prover": "workspace:^" "@aztec/circuit-types": "workspace:^" "@aztec/circuits.js": "workspace:^" "@aztec/ethereum": "workspace:^" @@ -999,6 +1000,7 @@ __metadata: "@aztec/noir-protocol-circuits-types": "workspace:^" "@aztec/p2p": "workspace:^" "@aztec/protocol-contracts": "workspace:^" + "@aztec/prover-client": "workspace:^" "@aztec/simulator": "workspace:^" "@aztec/telemetry-client": "workspace:^" "@aztec/types": "workspace:^"