diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 29fab24d9a3..7658dd95029 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -51,13 +51,8 @@ import { initStoreForRollup, openTmpStore } from '@aztec/kv-store/utils'; import { SHA256Trunc, StandardTree } from '@aztec/merkle-tree'; import { AztecKVTxPool, type P2P, createP2PClient } from '@aztec/p2p'; import { DummyProver, TxProver } from '@aztec/prover-client'; -import { - type GlobalVariableBuilder, - PublicProcessorFactory, - SequencerClient, - getGlobalVariableBuilder, -} from '@aztec/sequencer-client'; -import { WASMSimulator } from '@aztec/simulator'; +import { type GlobalVariableBuilder, SequencerClient, getGlobalVariableBuilder } from '@aztec/sequencer-client'; +import { PublicProcessorFactory, WASMSimulator } from '@aztec/simulator'; import { type ContractClassPublic, type ContractDataSource, diff --git a/yarn-project/circuit-types/src/tx/index.ts b/yarn-project/circuit-types/src/tx/index.ts index 114cb41ab57..e113a56430e 100644 --- a/yarn-project/circuit-types/src/tx/index.ts +++ b/yarn-project/circuit-types/src/tx/index.ts @@ -3,3 +3,4 @@ export * from './simulated_tx.js'; export * from './tx_hash.js'; export * from './tx_receipt.js'; export * from './processed_tx.js'; +export * from './tx_validator.js'; diff --git a/yarn-project/circuit-types/src/tx/processed_tx.ts b/yarn-project/circuit-types/src/tx/processed_tx.ts index 4c041c1d5f5..4d94a199d29 100644 --- a/yarn-project/circuit-types/src/tx/processed_tx.ts +++ b/yarn-project/circuit-types/src/tx/processed_tx.ts @@ -22,6 +22,7 @@ import { * Used to communicate to the prover which type of circuit to prove */ export enum PublicKernelType { + NON_PUBLIC, SETUP, APP_LOGIC, TEARDOWN, diff --git a/yarn-project/sequencer-client/src/tx_validator/tx_validator.ts b/yarn-project/circuit-types/src/tx/tx_validator.ts similarity index 100% rename from yarn-project/sequencer-client/src/tx_validator/tx_validator.ts rename to yarn-project/circuit-types/src/tx/tx_validator.ts diff --git a/yarn-project/prover-client/Dockerfile.test b/yarn-project/prover-client/Dockerfile.test index 45895a749e8..f267727de46 100644 --- a/yarn-project/prover-client/Dockerfile.test +++ b/yarn-project/prover-client/Dockerfile.test @@ -32,7 +32,7 @@ RUN ln -s /usr/src/yarn-project/node_modules /usr/src/node_modules ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true RUN ./bootstrap.sh -RUN cd prover-client && LOG_LEVEL=verbose ACVM_WORKING_DIRECTORY='/tmp/acvm' BB_WORKING_DIRECTORY='/tmp/bb' yarn test +RUN cd prover-client && ACVM_WORKING_DIRECTORY='/tmp/acvm' BB_WORKING_DIRECTORY='/tmp/bb' yarn test # Avoid pushing some huge container back to ecr. FROM scratch diff --git a/yarn-project/prover-client/package.json b/yarn-project/prover-client/package.json index a831caf6783..ca938c16f86 100644 --- a/yarn-project/prover-client/package.json +++ b/yarn-project/prover-client/package.json @@ -48,6 +48,7 @@ "@aztec/noir-protocol-circuits-types": "workspace:^", "@aztec/simulator": "workspace:^", "@aztec/world-state": "workspace:^", + "@noir-lang/types": "portal:../../noir/packages/types", "commander": "^9.0.0", "lodash.chunk": "^4.2.0", "source-map-support": "^0.5.21", diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator.ts b/yarn-project/prover-client/src/orchestrator/orchestrator.ts index 6090461179f..4bf498b96eb 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator.ts @@ -1,4 +1,12 @@ -import { Body, L2Block, MerkleTreeId, type ProcessedTx, type TxEffect, toTxEffect } from '@aztec/circuit-types'; +import { + Body, + L2Block, + MerkleTreeId, + type ProcessedTx, + PublicKernelType, + type TxEffect, + toTxEffect, +} from '@aztec/circuit-types'; import { type BlockResult, PROVING_STATUS, @@ -7,7 +15,6 @@ import { } from '@aztec/circuit-types/interfaces'; import { type CircuitSimulationStats } from '@aztec/circuit-types/stats'; import { - type AppendOnlyTreeSnapshot, type BaseOrMergeRollupPublicInputs, BaseParityInputs, type BaseRollupInputs, @@ -20,6 +27,7 @@ import { type Proof, RootParityInput, RootParityInputs, + makeEmptyProof, } from '@aztec/circuits.js'; import { makeTuple } from '@aztec/foundation/array'; import { padArrayEnd } from '@aztec/foundation/collection'; @@ -43,7 +51,8 @@ import { validateRootOutput, validateTx, } from './block-building-helpers.js'; -import { type MergeRollupInputData, ProvingState } from './proving-state.js'; +import { type MergeRollupInputData, ProvingState, type TreeSnapshots } from './proving-state.js'; +import { TX_PROVING_CODE, TxProvingState } from './tx-proving-state.js'; const logger = createDebugLogger('aztec:prover:proving-orchestrator'); @@ -66,6 +75,11 @@ enum PROMISE_RESULT { OPERATIONS, } +const KernelTypesWithoutFunctions: Set = new Set([ + PublicKernelType.NON_PUBLIC, + PublicKernelType.TAIL, +]); + /** * Enums and structs to communicate the type of work required in each request. */ @@ -77,6 +91,7 @@ export enum PROVING_JOB_TYPE { BASE_PARITY, ROOT_PARITY, PUBLIC_KERNEL, + PUBLIC_VM, } export type ProvingJob = { @@ -98,17 +113,20 @@ export class ProvingOrchestrator { private maxConcurrentJobs = MAX_CONCURRENT_JOBS, ) {} + // Constructs and starts a new orchestrator public static async new(db: MerkleTreeOperations, prover: CircuitProver) { const orchestrator = new ProvingOrchestrator(db, prover); await orchestrator.start(); return Promise.resolve(orchestrator); } + // Starts the proving job queue public start() { this.jobProcessPromise = this.processJobQueue(); return Promise.resolve(); } + // Stops the proving job queue public async stop() { this.stopped = true; this.jobQueue.cancel(); @@ -214,12 +232,7 @@ export class ProvingOrchestrator { logger.info(`Received transaction: ${tx.hash}`); - // We start the transaction by enqueueing the state updates - const txIndex = this.provingState.addNewTx(tx); - await this.prepareBaseRollupInputs(this.provingState, tx); - this.enqueueJob(this.provingState, PROVING_JOB_TYPE.PUBLIC_KERNEL, () => - this.proveNextPublicFunction(this.provingState, txIndex, 0), - ); + await this.startTransaction(tx, this.provingState); } /** @@ -237,15 +250,7 @@ export class ProvingOrchestrator { } empty transactions`, ); for (let i = this.provingState.transactionsReceived; i < this.provingState.totalNumTxs; i++) { - const paddingTxIndex = this.provingState.addNewTx(this.provingState.emptyTx); - await this.prepareBaseRollupInputs(this.provingState, this.provingState!.emptyTx); - // TODO(@Phil): Properly encapsulate this stuff - const tx = this.provingState.allTxs[paddingTxIndex]; - const inputs = this.provingState.baseRollupInputs[paddingTxIndex]; - const treeSnapshots = this.provingState.txTreeSnapshots[paddingTxIndex]; - this.enqueueJob(this.provingState, PROVING_JOB_TYPE.BASE_ROLLUP, () => - this.runBaseRollup(this.provingState, BigInt(paddingTxIndex), tx, inputs, treeSnapshots), - ); + await this.startTransaction(this.provingState.emptyTx, this.provingState); } } @@ -276,9 +281,9 @@ export class ProvingOrchestrator { await validateRootOutput(rootRollupOutputs, this.db); // Collect all new nullifiers, commitments, and contracts from all txs in this block - const nonEmptyTxEffects: TxEffect[] = this.provingState!.allTxs.map(tx => toTxEffect(tx)).filter( - txEffect => !txEffect.isEmpty(), - ); + const nonEmptyTxEffects: TxEffect[] = this.provingState!.allTxs.map(txProvingState => + toTxEffect(txProvingState.processedTx), + ).filter(txEffect => !txEffect.isEmpty()); const blockBody = new Body(nonEmptyTxEffects); const l2Block = L2Block.fromFields({ @@ -308,6 +313,37 @@ export class ProvingOrchestrator { return blockResult; } + /** + * Starts the proving process for the given transaction and adds it to our state + * @param tx - The transaction whose proving we wish to commence + * @param provingState - The proving state being worked on + */ + private async startTransaction(tx: ProcessedTx, provingState: ProvingState) { + const txInputs = await this.prepareBaseRollupInputs(provingState, tx); + if (!txInputs) { + // This should not be possible + throw new Error(`Unable to add padding transaction, preparing base inputs failed`); + } + const [inputs, treeSnapshots] = txInputs; + const txProvingState = new TxProvingState(tx, inputs, treeSnapshots); + const txIndex = provingState.addNewTx(txProvingState); + const numPublicKernels = txProvingState.getNumPublicKernels(); + if (!numPublicKernels) { + // no public functions, go straight to the base rollup + logger.debug(`Enqueueing base rollup for tx ${txIndex}`); + this.enqueueJob(provingState, PROVING_JOB_TYPE.BASE_ROLLUP, () => + this.runBaseRollup(provingState, BigInt(txIndex), txProvingState), + ); + return; + } + // Enqueue all of the VM proving requests + // Rather than handle the Kernel Tail as a special case here, we will just handle it inside executeVM + for (let i = 0; i < numPublicKernels; i++) { + logger.debug(`Enqueueing public VM ${i} for tx ${txIndex}`); + this.enqueueJob(provingState, PROVING_JOB_TYPE.PUBLIC_VM, () => this.executeVM(provingState, txIndex, i)); + } + } + /** * Enqueue a job to be scheduled * @param provingState - The proving state object being operated on @@ -336,30 +372,11 @@ export class ProvingOrchestrator { this.jobQueue.put(provingJob); } - private proveNextPublicFunction(provingState: ProvingState | undefined, txIndex: number, nextFunctionIndex: number) { - if (!provingState?.verifyState()) { - logger.debug(`Not executing public function, state invalid`); - return Promise.resolve(); - } - const request = provingState.getPublicFunction(txIndex, nextFunctionIndex); - if (!request) { - // TODO(@Phil): Properly encapsulate this stuff - const tx = provingState.allTxs[txIndex]; - const inputs = provingState.baseRollupInputs[txIndex]; - const treeSnapshots = provingState.txTreeSnapshots[txIndex]; - this.enqueueJob(provingState, PROVING_JOB_TYPE.BASE_ROLLUP, () => - this.runBaseRollup(provingState, BigInt(txIndex), tx, inputs, treeSnapshots), - ); - return Promise.resolve(); - } - this.enqueueJob(provingState, PROVING_JOB_TYPE.PUBLIC_KERNEL, () => - this.proveNextPublicFunction(provingState, txIndex, nextFunctionIndex + 1), - ); - return Promise.resolve(); - } - // Updates the merkle trees for a transaction. The first enqueued job for a transaction - private async prepareBaseRollupInputs(provingState: ProvingState | undefined, tx: ProcessedTx) { + private async prepareBaseRollupInputs( + provingState: ProvingState | undefined, + tx: ProcessedTx, + ): Promise<[BaseRollupInputs, TreeSnapshots] | undefined> { if (!provingState?.verifyState()) { logger.debug('Not preparing base rollup inputs, state invalid'); return; @@ -370,17 +387,13 @@ export class ProvingOrchestrator { return { key: id, value: await getTreeSnapshot(id, this.db) }; }, ); - const treeSnapshots: Map = new Map( - (await Promise.all(promises)).map(obj => [obj.key, obj.value]), - ); + const treeSnapshots: TreeSnapshots = new Map((await Promise.all(promises)).map(obj => [obj.key, obj.value])); if (!provingState?.verifyState()) { logger.debug(`Discarding proving job, state no longer valid`); return; } - // TODO(@Phil): Properly encapsulate this stuff - provingState!.baseRollupInputs.push(inputs); - provingState!.txTreeSnapshots.push(treeSnapshots); + return [inputs, treeSnapshots]; } // Stores the intermediate inputs prepared for a merge proof @@ -401,27 +414,21 @@ export class ProvingOrchestrator { // Executes the base rollup circuit and stored the output as intermediate state for the parent merge/root circuit // Executes the next level of merge if all inputs are available - private async runBaseRollup( - provingState: ProvingState | undefined, - index: bigint, - tx: ProcessedTx, - inputs: BaseRollupInputs, - treeSnapshots: Map, - ) { + private async runBaseRollup(provingState: ProvingState | undefined, index: bigint, tx: TxProvingState) { if (!provingState?.verifyState()) { logger.debug('Not running base rollup, state invalid'); return; } const [duration, baseRollupOutputs] = await elapsed(async () => { - const [rollupOutput, proof] = await this.prover.getBaseRollupProof(inputs); - validatePartialState(rollupOutput.end, treeSnapshots); + const [rollupOutput, proof] = await this.prover.getBaseRollupProof(tx.baseRollupInputs); + validatePartialState(rollupOutput.end, tx.treeSnapshots); return { rollupOutput, proof }; }); logger.debug(`Simulated base rollup circuit`, { eventName: 'circuit-simulation', circuitName: 'base-rollup', duration, - inputSize: inputs.toBuffer().length, + inputSize: tx.baseRollupInputs.toBuffer().length, outputSize: baseRollupOutputs.rollupOutput.toBuffer().length, } satisfies CircuitSimulationStats); if (!provingState?.verifyState()) { @@ -437,7 +444,7 @@ export class ProvingOrchestrator { } // Executes the merge rollup circuit and stored the output as intermediate state for the parent merge/root circuit - // Executes the next level of merge if all inputs are available + // Enqueues the next level of merge if all inputs are available private async runMergeRollup( provingState: ProvingState | undefined, level: bigint, @@ -575,6 +582,13 @@ export class ProvingOrchestrator { this.enqueueJob(provingState, PROVING_JOB_TYPE.ROOT_ROLLUP, () => this.runRootRollup(provingState)); } + /** + * Stores the inputs to a merge/root circuit and enqueues the circuit if ready + * @param provingState - The proving state being operated on + * @param currentLevel - The level of the merge/root circuit + * @param currentIndex - The index of the merge/root circuit + * @param mergeInputData - The inputs to be stored + */ private storeAndExecuteNextMergeLevel( provingState: ProvingState, currentLevel: bigint, @@ -598,6 +612,101 @@ export class ProvingOrchestrator { } } + /** + * Executes the VM circuit for a public function, will enqueue the corresponding kernel if the + * previous kernel is ready + * @param provingState - The proving state being operated on + * @param txIndex - The index of the transaction being proven + * @param functionIndex - The index of the function/kernel being proven + */ + private async executeVM(provingState: ProvingState | undefined, txIndex: number, functionIndex: number) { + if (!provingState?.verifyState()) { + logger.debug(`Not running VM circuit as state is no longer valid`); + return; + } + + const txProvingState = provingState.getTxProvingState(txIndex); + const publicFunction = txProvingState.getPublicFunctionState(functionIndex); + + // Prove the VM if this is a kernel that requires one + if (!KernelTypesWithoutFunctions.has(publicFunction.publicKernelRequest.type)) { + // Just sleep for a small amount of time + await sleep(Math.random() * 10 + 10); + logger.debug(`Proven VM for function index ${functionIndex} of tx index ${txIndex}`); + } + + if (!provingState?.verifyState()) { + logger.debug(`Not continuing after VM circuit as state is no longer valid`); + return; + } + + const kernelRequest = txProvingState.getNextPublicKernelFromVMProof(functionIndex, makeEmptyProof()); + if (kernelRequest.code === TX_PROVING_CODE.READY) { + if (kernelRequest.function === undefined) { + // Should not be possible + throw new Error(`Error occurred, public function request undefined after VM proof completed`); + } + logger.debug(`Enqueuing kernel from VM for tx ${txIndex}, function ${functionIndex}`); + this.enqueueJob(provingState, PROVING_JOB_TYPE.PUBLIC_KERNEL, () => + this.executePublicKernel(provingState, txIndex, functionIndex), + ); + } + } + + /** + * Executes the kernel circuit for a public function, will enqueue the next kernel circuit if it's VM is already proven + * or the base rollup circuit if there are no more kernels to be proven + * @param provingState - The proving state being operated on + * @param txIndex - The index of the transaction being proven + * @param functionIndex - The index of the function/kernel being proven + */ + private async executePublicKernel(provingState: ProvingState | undefined, txIndex: number, functionIndex: number) { + if (!provingState?.verifyState()) { + logger.debug(`Not running public kernel circuit as state is no longer valid`); + return; + } + + const txProvingState = provingState.getTxProvingState(txIndex); + const kernelRequest = txProvingState.getPublicFunctionState(functionIndex).publicKernelRequest; + + // We may need to use the public inputs produced here instead of those coming from the sequencer + const [_, proof] = + kernelRequest.type == PublicKernelType.TAIL + ? await this.prover.getPublicTailProof(kernelRequest) + : await this.prover.getPublicKernelProof(kernelRequest); + + if (!provingState?.verifyState()) { + logger.debug(`Not continuing after public kernel circuit as state is no longer valid`); + return; + } + + logger.debug(`Proven ${PublicKernelType[kernelRequest.type]} at index ${functionIndex} for tx index ${txIndex}`); + + const nextKernelRequest = txProvingState.getNextPublicKernelFromKernelProof(functionIndex, proof); + // What's the status of the next kernel? + if (nextKernelRequest.code === TX_PROVING_CODE.NOT_READY) { + // Must be waiting on a VM proof + return; + } + if (nextKernelRequest.code === TX_PROVING_CODE.COMPLETED) { + // We must have completed all public function proving, we now move to the base rollup + logger.debug(`Public functions completed for tx ${txIndex} enqueueing base rollup`); + this.enqueueJob(provingState, PROVING_JOB_TYPE.BASE_ROLLUP, () => + this.runBaseRollup(provingState, BigInt(txIndex), txProvingState), + ); + return; + } + // There must be another kernel ready to be proven + if (nextKernelRequest.function === undefined) { + // Should not be possible + throw new Error(`Error occurred, public function request undefined after kernel proof completed`); + } + logger.debug(`Enqueuing kernel from kernel for tx ${txIndex}, function ${functionIndex + 1}`); + this.enqueueJob(provingState, PROVING_JOB_TYPE.PUBLIC_KERNEL, () => + this.executePublicKernel(provingState, txIndex, functionIndex + 1), + ); + } + /** * Process the job queue * Works by managing an input queue of proof requests and an active pool of proving 'jobs' diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator_public_functions.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator_public_functions.test.ts new file mode 100644 index 00000000000..5a1ccaea82d --- /dev/null +++ b/yarn-project/prover-client/src/orchestrator/orchestrator_public_functions.test.ts @@ -0,0 +1,139 @@ +import { PROVING_STATUS, mockTx } from '@aztec/circuit-types'; +import { GlobalVariables, Header } from '@aztec/circuits.js'; +import { createDebugLogger } from '@aztec/foundation/log'; +import { openTmpStore } from '@aztec/kv-store/utils'; +import { + type ContractsDataSourcePublicDB, + PublicExecutionResultBuilder, + type PublicExecutor, + type PublicKernelCircuitSimulator, + PublicProcessor, + RealPublicKernelCircuitSimulator, + WASMSimulator, + type WorldStatePublicDB, +} from '@aztec/simulator'; +import { type MerkleTreeOperations, MerkleTrees, type TreeInfo } from '@aztec/world-state'; + +import { type MockProxy, mock } from 'jest-mock-extended'; +import { type MemDown, default as memdown } from 'memdown'; + +import { getConfig, getSimulationProvider, makeEmptyProcessedTestTx, makeGlobals } from '../mocks/fixtures.js'; +import { TestCircuitProver } from '../prover/test_circuit_prover.js'; +import { ProvingOrchestrator } from './orchestrator.js'; + +export const createMemDown = () => (memdown as any)() as MemDown; + +const logger = createDebugLogger('aztec:orchestrator-test'); + +describe('prover/orchestrator', () => { + let builder: ProvingOrchestrator; + let db: MockProxy; + let builderDb: MerkleTreeOperations; + let publicExecutor: MockProxy; + let publicContractsDB: MockProxy; + let publicWorldStateDB: MockProxy; + let publicKernel: PublicKernelCircuitSimulator; + let processor: PublicProcessor; + + let prover: TestCircuitProver; + + let blockNumber: number; + let testCount = 1; + + let globalVariables: GlobalVariables; + let root: Buffer; + + beforeEach(async () => { + blockNumber = 3; + globalVariables = makeGlobals(blockNumber); + + const acvmConfig = await getConfig(logger); + const simulationProvider = await getSimulationProvider({ + acvmWorkingDirectory: acvmConfig?.acvmWorkingDirectory, + acvmBinaryPath: acvmConfig?.expectedAcvmPath, + }); + prover = new TestCircuitProver(simulationProvider); + + builderDb = await MerkleTrees.new(openTmpStore()).then(t => t.asLatest()); + builder = new ProvingOrchestrator(builderDb, prover, 1); + }, 20_000); + + describe('blocks with public functions', () => { + beforeEach(async () => { + publicExecutor = mock(); + db = mock(); + root = Buffer.alloc(32, 5); + db.getTreeInfo.mockResolvedValue({ root } as TreeInfo); + publicContractsDB = mock(); + publicWorldStateDB = mock(); + builder = await ProvingOrchestrator.new(builderDb, prover); + publicKernel = new RealPublicKernelCircuitSimulator(new WASMSimulator()); + processor = new PublicProcessor( + db, + publicExecutor, + publicKernel, + GlobalVariables.empty(), + Header.empty(), + publicContractsDB, + publicWorldStateDB, + ); + }); + + afterEach(async () => { + await builder.stop(); + }); + + it.each([ + [0, 4], + [1, 0], + [2, 0], + [1, 5], + [2, 4], + [8, 1], + ] as const)( + 'builds an L2 block with %i non-revertible and %i revertible calls', + async (numberOfNonRevertiblePublicCallRequests: number, numberOfRevertiblePublicCallRequests: number) => { + const tx = mockTx(1000 * testCount++, { + numberOfNonRevertiblePublicCallRequests, + numberOfRevertiblePublicCallRequests, + }); + tx.data.constants.historicalHeader = await builderDb.buildInitialHeader(); + + publicExecutor.simulate.mockImplementation(execution => { + for (const request of tx.enqueuedPublicFunctionCalls) { + if (execution.contractAddress.equals(request.contractAddress)) { + const result = PublicExecutionResultBuilder.fromPublicCallRequest({ request }).build(); + // result.unencryptedLogs = tx.unencryptedLogs.functionLogs[0]; + return Promise.resolve(result); + } + } + throw new Error(`Unexpected execution request: ${execution}`); + }); + + const [processed, _] = await processor.process([tx], 1, undefined); + + // This will need to be a 2 tx block + const blockTicket = await builder.startNewBlock( + 2, + globalVariables, + [], + await makeEmptyProcessedTestTx(builderDb), + ); + + for (const processedTx of processed) { + await builder.addNewTx(processedTx); + } + + // we need to complete the block as we have not added a full set of txs + await builder.setBlockCompleted(); + + const result = await blockTicket.provingPromise; + expect(result.status).toBe(PROVING_STATUS.SUCCESS); + const finalisedBlock = await builder.finaliseBlock(); + + expect(finalisedBlock.block.number).toEqual(blockNumber); + }, + 60_000, + ); + }); +}); diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator_single_blocks.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator_single_blocks.test.ts index 87babf686e1..140a6d2278d 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator_single_blocks.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator_single_blocks.test.ts @@ -1,10 +1,6 @@ -import { PROVING_STATUS, type PublicKernelRequest, PublicKernelType } from '@aztec/circuit-types'; +import { PROVING_STATUS } from '@aztec/circuit-types'; import { type GlobalVariables, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/circuits.js'; -import { - fr, - makePublicKernelCircuitPrivateInputs, - makePublicKernelTailCircuitPrivateInputs, -} from '@aztec/circuits.js/testing'; +import { fr } from '@aztec/circuits.js/testing'; import { range } from '@aztec/foundation/array'; import { createDebugLogger } from '@aztec/foundation/log'; import { sleep } from '@aztec/foundation/sleep'; @@ -112,51 +108,6 @@ describe('prover/orchestrator', () => { expect(finalisedBlock.block.number).toEqual(blockNumber); }, 60_000); - it('builds a block with a transaction with public functions', async () => { - const tx = await makeBloatedProcessedTx(builderDb, 1); - - const setup: PublicKernelRequest = { - type: PublicKernelType.SETUP, - inputs: makePublicKernelCircuitPrivateInputs(2), - }; - - const app: PublicKernelRequest = { - type: PublicKernelType.APP_LOGIC, - inputs: makePublicKernelCircuitPrivateInputs(3), - }; - - const teardown: PublicKernelRequest = { - type: PublicKernelType.TEARDOWN, - inputs: makePublicKernelCircuitPrivateInputs(4), - }; - - const tail: PublicKernelRequest = { - type: PublicKernelType.TAIL, - inputs: makePublicKernelTailCircuitPrivateInputs(5), - }; - - tx.publicKernelRequests = [setup, app, teardown, tail]; - - // This will need to be a 2 tx block - const blockTicket = await builder.startNewBlock( - 2, - globalVariables, - [], - await makeEmptyProcessedTestTx(builderDb), - ); - - await builder.addNewTx(tx); - - // we need to complete the block as we have not added a full set of txs - await builder.setBlockCompleted(); - - const result = await blockTicket.provingPromise; - expect(result.status).toBe(PROVING_STATUS.SUCCESS); - const finalisedBlock = await builder.finaliseBlock(); - - expect(finalisedBlock.block.number).toEqual(blockNumber); - }, 60_000); - it('builds a block concurrently with transaction simulation', async () => { const txs = await Promise.all([ makeBloatedProcessedTx(builderDb, 1), diff --git a/yarn-project/prover-client/src/orchestrator/proving-state.ts b/yarn-project/prover-client/src/orchestrator/proving-state.ts index 3f70a88b450..f5098debd6e 100644 --- a/yarn-project/prover-client/src/orchestrator/proving-state.ts +++ b/yarn-project/prover-client/src/orchestrator/proving-state.ts @@ -2,7 +2,6 @@ import { type L2Block, type MerkleTreeId, type ProcessedTx, type ProvingResult } import { type AppendOnlyTreeSnapshot, type BaseOrMergeRollupPublicInputs, - type BaseRollupInputs, type Fr, type GlobalVariables, type L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, @@ -13,11 +12,15 @@ import { } from '@aztec/circuits.js'; import { type Tuple } from '@aztec/foundation/serialize'; +import { type TxProvingState } from './tx-proving-state.js'; + export type MergeRollupInputData = { inputs: [BaseOrMergeRollupPublicInputs | undefined, BaseOrMergeRollupPublicInputs | undefined]; proofs: [Proof | undefined, Proof | undefined]; }; +export type TreeSnapshots = Map; + enum PROVING_STATE_LIFECYCLE { PROVING_STATE_CREATED, PROVING_STATE_FULL, @@ -38,9 +41,7 @@ export class ProvingState { public rootRollupPublicInputs: RootRollupPublicInputs | undefined; public finalProof: Proof | undefined; public block: L2Block | undefined; - private txs: ProcessedTx[] = []; - public baseRollupInputs: BaseRollupInputs[] = []; - public txTreeSnapshots: Map[] = []; + private txs: TxProvingState[] = []; constructor( public readonly totalNumTxs: number, private completionCallback: (result: ProvingResult) => void, @@ -55,15 +56,14 @@ export class ProvingState { this.rootParityInputs = Array.from({ length: numRootParityInputs }).map(_ => undefined); } - public get baseMergeLevel() { - return BigInt(Math.ceil(Math.log2(this.totalNumTxs)) - 1); - } - + // Returns the number of levels of merge rollups public get numMergeLevels() { - return this.baseMergeLevel; + return BigInt(Math.ceil(Math.log2(this.totalNumTxs)) - 1); } - public addNewTx(tx: ProcessedTx) { + // Adds a transaction to the proving state, returns it's index + // Will update the proving life cycle if this is the last transaction + public addNewTx(tx: TxProvingState) { this.txs.push(tx); if (this.txs.length === this.totalNumTxs) { this.provingStateLifecycle = PROVING_STATE_LIFECYCLE.PROVING_STATE_FULL; @@ -71,22 +71,27 @@ export class ProvingState { return this.txs.length - 1; } + // Returns the number of received transactions public get transactionsReceived() { return this.txs.length; } + // Returns the final set of root parity inputs public get finalRootParityInput() { return this.finalRootParityInputs; } + // Sets the final set of root parity inputs public set finalRootParityInput(input: RootParityInput | undefined) { this.finalRootParityInputs = input; } + // Returns the set of root parity inputs public get rootParityInput() { return this.rootParityInputs; } + // Returns true if this proving state is still valid, false otherwise public verifyState() { return ( this.provingStateLifecycle === PROVING_STATE_LIFECYCLE.PROVING_STATE_CREATED || @@ -94,14 +99,23 @@ export class ProvingState { ); } + // Returns true if we are still able to accept transactions, false otherwise public isAcceptingTransactions() { return this.provingStateLifecycle === PROVING_STATE_LIFECYCLE.PROVING_STATE_CREATED; } + // Returns the complete set of transaction proving state objects public get allTxs() { return this.txs; } + /** + * Stores the inputs to a merge circuit and determines if the circuit is ready to be executed + * @param mergeInputs - The inputs to store + * @param indexWithinMerge - The index in the set of inputs to this merge circuit + * @param indexOfMerge - The global index of this merge circuit + * @returns True if the merge circuit is ready to be executed, false otherwise + */ public storeMergeInputs( mergeInputs: [BaseOrMergeRollupPublicInputs, Proof], indexWithinMerge: number, @@ -123,10 +137,17 @@ export class ProvingState { return true; } + // Returns a specific transaction proving state + public getTxProvingState(txIndex: number) { + return this.txs[txIndex]; + } + + // Returns a set of merge rollup inputs public getMergeInputs(indexOfMerge: number) { return this.mergeRollupInputs[indexOfMerge]; } + // Returns true if we have sufficient inputs to execute the root rollup public isReadyForRootRollup() { return !( this.mergeRollupInputs[0] === undefined || @@ -135,33 +156,23 @@ export class ProvingState { ); } + // Stores a set of root parity inputs at the given index public setRootParityInputs(inputs: RootParityInput, index: number) { this.rootParityInputs[index] = inputs; } + // Returns true if we have sufficient root parity inputs to execute the root parity circuit public areRootParityInputsReady() { return this.rootParityInputs.findIndex(p => !p) === -1; } - public txHasPublicFunctions(index: number) { - return index >= 0 && this.txs.length > index && this.txs[index].publicKernelRequests.length; - } - - public getPublicFunction(txIndex: number, nextIndex: number) { - if (txIndex < 0 || txIndex >= this.txs.length) { - return undefined; - } - const tx = this.txs[txIndex]; - if (nextIndex < 0 || nextIndex >= tx.publicKernelRequests.length) { - return undefined; - } - return tx.publicKernelRequests[nextIndex]; - } - + // Attempts to reject the proving state promise with a reason of 'cancelled' public cancel() { this.reject('Proving cancelled'); } + // Attempts to reject the proving state promise with the given reason + // Does nothing if not in a valid state public reject(reason: string) { if (!this.verifyState()) { return; @@ -170,6 +181,8 @@ export class ProvingState { this.rejectionCallback(reason); } + // Attempts to resolve the proving state promise with the given result + // Does nothing if not in a valid state public resolve(result: ProvingResult) { if (!this.verifyState()) { return; diff --git a/yarn-project/prover-client/src/orchestrator/tx-proving-state.ts b/yarn-project/prover-client/src/orchestrator/tx-proving-state.ts new file mode 100644 index 00000000000..ab8802d2fcc --- /dev/null +++ b/yarn-project/prover-client/src/orchestrator/tx-proving-state.ts @@ -0,0 +1,102 @@ +import { type MerkleTreeId, type ProcessedTx, type PublicKernelRequest, PublicKernelType } from '@aztec/circuit-types'; +import { type AppendOnlyTreeSnapshot, type BaseRollupInputs, type Proof } from '@aztec/circuits.js'; + +export enum TX_PROVING_CODE { + NOT_READY, + READY, + COMPLETED, +} + +export type PublicFunction = { + vmProof: Proof | undefined; + previousProofType: PublicKernelType; + previousKernelProof: Proof | undefined; + publicKernelRequest: PublicKernelRequest; +}; + +// Type encapsulating the instruction to the orchestrator as to what +// needs to be proven next +export type TxProvingInstruction = { + code: TX_PROVING_CODE; + function: PublicFunction | undefined; +}; + +/** + * Helper class to manage the proving cycle of a transaction + * This includes the public VMs and the public kernels + * Also stores the inputs to the base rollup for this transaction and the tree snapshots + */ +export class TxProvingState { + private publicFunctions: PublicFunction[] = []; + + constructor( + public readonly processedTx: ProcessedTx, + public readonly baseRollupInputs: BaseRollupInputs, + public readonly treeSnapshots: Map, + ) { + let previousKernelProof: Proof | undefined = processedTx.proof; + let previousProofType = PublicKernelType.NON_PUBLIC; + for (const kernelRequest of processedTx.publicKernelRequests) { + const publicFunction: PublicFunction = { + vmProof: undefined, + previousProofType, + previousKernelProof, + publicKernelRequest: kernelRequest, + }; + this.publicFunctions.push(publicFunction); + previousKernelProof = undefined; + previousProofType = kernelRequest.type; + } + } + + // Updates the transaction's proving state after completion of a kernel proof + // Returns an instruction as to the next stage of tx proving + public getNextPublicKernelFromKernelProof(provenIndex: number, proof: Proof): TxProvingInstruction { + const kernelRequest = this.getPublicFunctionState(provenIndex).publicKernelRequest; + const nextKernelIndex = provenIndex + 1; + if (nextKernelIndex >= this.publicFunctions.length) { + // The next kernel index is greater than our set of functions, we are done! + return { code: TX_PROVING_CODE.COMPLETED, function: undefined }; + } + + // There is more work to do, are we ready? + const nextFunction = this.publicFunctions[nextKernelIndex]; + nextFunction.previousKernelProof = proof; + nextFunction.previousProofType = kernelRequest.type; + if (nextFunction.vmProof === undefined) { + // The VM proof for the next function is not ready + return { code: TX_PROVING_CODE.NOT_READY, function: undefined }; + } + + // The VM proof is ready, we can continue + return { code: TX_PROVING_CODE.READY, function: nextFunction }; + } + + // Updates the transaction's proving state after completion of a VM proof + // Returns an instruction as to the next stage of tx proving + public getNextPublicKernelFromVMProof(provenIndex: number, proof: Proof): TxProvingInstruction { + const provenFunction = this.publicFunctions[provenIndex]; + provenFunction.vmProof = proof; + + if (provenFunction.previousKernelProof === undefined) { + // The previous kernel is not yet ready + return { code: TX_PROVING_CODE.NOT_READY, function: undefined }; + } + // The previous kernel is ready so we can prove this kernel + return { code: TX_PROVING_CODE.READY, function: provenFunction }; + } + + // Returns the public function state at the given index + // Throws if out of bounds + public getPublicFunctionState(functionIndex: number) { + if (functionIndex < 0 || functionIndex >= this.publicFunctions.length) { + throw new Error(`Requested public function index was out of bounds`); + } + return this.publicFunctions[functionIndex]; + } + + // Returns the number of public kernels required by this transaction + public getNumPublicKernels() { + return this.publicFunctions.length; + } +} diff --git a/yarn-project/prover-client/src/prover/bb_prover.ts b/yarn-project/prover-client/src/prover/bb_prover.ts index 29105d370ca..73c450c1317 100644 --- a/yarn-project/prover-client/src/prover/bb_prover.ts +++ b/yarn-project/prover-client/src/prover/bb_prover.ts @@ -1,12 +1,15 @@ /* eslint-disable require-await */ +import { type PublicKernelNonTailRequest, type PublicKernelTailRequest } from '@aztec/circuit-types'; import { type BaseOrMergeRollupPublicInputs, type BaseParityInputs, type BaseRollupInputs, + type KernelCircuitPublicInputs, type MergeRollupInputs, type ParityPublicInputs, type PreviousRollupData, Proof, + type PublicKernelCircuitPublicInputs, RollupTypes, type RootParityInputs, type RootRollupInputs, @@ -255,4 +258,11 @@ export class BBNativeRollupProver implements CircuitProver { : 'MergeRollupArtifact'; await this.verifyProof(circuitType, proof); } + + getPublicKernelProof(_: PublicKernelNonTailRequest): Promise<[PublicKernelCircuitPublicInputs, Proof]> { + throw new Error('Method not implemented.'); + } + getPublicTailProof(_: PublicKernelTailRequest): Promise<[KernelCircuitPublicInputs, Proof]> { + throw new Error('Method not implemented.'); + } } diff --git a/yarn-project/prover-client/src/prover/interface.ts b/yarn-project/prover-client/src/prover/interface.ts index 2764f76dbf3..93a3460d87d 100644 --- a/yarn-project/prover-client/src/prover/interface.ts +++ b/yarn-project/prover-client/src/prover/interface.ts @@ -1,7 +1,9 @@ +import { type PublicKernelNonTailRequest, type PublicKernelTailRequest } from '@aztec/circuit-types'; import { type BaseOrMergeRollupPublicInputs, type BaseParityInputs, type BaseRollupInputs, + type KernelCircuitPublicInputs, type MergeRollupInputs, type ParityPublicInputs, type Proof, @@ -45,6 +47,18 @@ export interface CircuitProver { * @param input - Input to the circuit. */ getRootRollupProof(input: RootRollupInputs): Promise<[RootRollupPublicInputs, Proof]>; + + /** + * Create a public kernel proof. + * @param kernelRequest - Object containing the details of the proof required + */ + getPublicKernelProof(kernelRequest: PublicKernelNonTailRequest): Promise<[PublicKernelCircuitPublicInputs, Proof]>; + + /** + * Create a public kernel tail proof. + * @param kernelRequest - Object containing the details of the proof required + */ + getPublicTailProof(kernelRequest: PublicKernelTailRequest): Promise<[KernelCircuitPublicInputs, Proof]>; } /** diff --git a/yarn-project/prover-client/src/prover/test_circuit_prover.ts b/yarn-project/prover-client/src/prover/test_circuit_prover.ts index 8be054a6e9a..d6fe74e938e 100644 --- a/yarn-project/prover-client/src/prover/test_circuit_prover.ts +++ b/yarn-project/prover-client/src/prover/test_circuit_prover.ts @@ -1,11 +1,15 @@ +import { type PublicKernelNonTailRequest, type PublicKernelTailRequest, PublicKernelType } from '@aztec/circuit-types'; import { type CircuitSimulationStats } from '@aztec/circuit-types/stats'; import { type BaseOrMergeRollupPublicInputs, type BaseParityInputs, type BaseRollupInputs, + type KernelCircuitPublicInputs, type MergeRollupInputs, type ParityPublicInputs, type Proof, + type PublicKernelCircuitPrivateInputs, + type PublicKernelCircuitPublicInputs, type RootParityInputs, type RootRollupInputs, type RootRollupPublicInputs, @@ -18,11 +22,21 @@ import { MergeRollupArtifact, RootParityArtifact, RootRollupArtifact, + ServerCircuitArtifacts, + type ServerProtocolArtifact, SimulatedBaseRollupArtifact, convertBaseParityInputsToWitnessMap, convertBaseParityOutputsFromWitnessMap, convertMergeRollupInputsToWitnessMap, convertMergeRollupOutputsFromWitnessMap, + convertPublicInnerRollupInputsToWitnessMap, + convertPublicInnerRollupOutputFromWitnessMap, + convertPublicSetupRollupInputsToWitnessMap, + convertPublicSetupRollupOutputFromWitnessMap, + convertPublicTailInputsToWitnessMap, + convertPublicTailOutputFromWitnessMap, + convertPublicTeardownRollupInputsToWitnessMap, + convertPublicTeardownRollupOutputFromWitnessMap, convertRootParityInputsToWitnessMap, convertRootParityOutputsFromWitnessMap, convertRootRollupInputsToWitnessMap, @@ -32,8 +46,38 @@ import { } from '@aztec/noir-protocol-circuits-types'; import { type SimulationProvider, WASMSimulator } from '@aztec/simulator'; +import { type WitnessMap } from '@noir-lang/types'; + import { type CircuitProver } from './interface.js'; +type PublicKernelProvingOps = { + artifact: ServerProtocolArtifact; + convertInputs: (inputs: PublicKernelCircuitPrivateInputs) => WitnessMap; + convertOutputs: (outputs: WitnessMap) => PublicKernelCircuitPublicInputs; +}; + +type KernelTypeToArtifact = Record; + +const KernelArtifactMapping: KernelTypeToArtifact = { + [PublicKernelType.NON_PUBLIC]: undefined, + [PublicKernelType.APP_LOGIC]: { + artifact: 'PublicKernelAppLogicArtifact', + convertInputs: convertPublicInnerRollupInputsToWitnessMap, + convertOutputs: convertPublicInnerRollupOutputFromWitnessMap, + }, + [PublicKernelType.SETUP]: { + artifact: 'PublicKernelSetupArtifact', + convertInputs: convertPublicSetupRollupInputsToWitnessMap, + convertOutputs: convertPublicSetupRollupOutputFromWitnessMap, + }, + [PublicKernelType.TEARDOWN]: { + artifact: 'PublicKernelTeardownArtifact', + convertInputs: convertPublicTeardownRollupInputsToWitnessMap, + convertOutputs: convertPublicTeardownRollupOutputFromWitnessMap, + }, + [PublicKernelType.TAIL]: undefined, +}; + /** * A class for use in testing situations (e2e, unit test etc) * Simulates circuits using the most efficient method and performs no proving @@ -130,4 +174,31 @@ export class TestCircuitProver implements CircuitProver { } satisfies CircuitSimulationStats); return Promise.resolve([result, makeEmptyProof()]); } + + public async getPublicKernelProof( + kernelRequest: PublicKernelNonTailRequest, + ): Promise<[PublicKernelCircuitPublicInputs, Proof]> { + const kernelOps = KernelArtifactMapping[kernelRequest.type]; + if (kernelOps === undefined) { + throw new Error(`Unable to prove for kernel type ${PublicKernelType[kernelRequest.type]}`); + } + const witnessMap = kernelOps.convertInputs(kernelRequest.inputs); + + const witness = await this.wasmSimulator.simulateCircuit(witnessMap, ServerCircuitArtifacts[kernelOps.artifact]); + + const result = kernelOps.convertOutputs(witness); + return [result, makeEmptyProof()]; + } + + public async getPublicTailProof(kernelRequest: PublicKernelTailRequest): Promise<[KernelCircuitPublicInputs, Proof]> { + const witnessMap = convertPublicTailInputsToWitnessMap(kernelRequest.inputs); + // use WASM here as it is faster for small circuits + const witness = await this.wasmSimulator.simulateCircuit( + witnessMap, + ServerCircuitArtifacts['PublicKernelTailArtifact'], + ); + + const result = convertPublicTailOutputFromWitnessMap(witness); + return [result, makeEmptyProof()]; + } } diff --git a/yarn-project/sequencer-client/src/client/sequencer-client.ts b/yarn-project/sequencer-client/src/client/sequencer-client.ts index 24d9cbd99f6..5ec55a03db9 100644 --- a/yarn-project/sequencer-client/src/client/sequencer-client.ts +++ b/yarn-project/sequencer-client/src/client/sequencer-client.ts @@ -1,7 +1,7 @@ import { type L1ToL2MessageSource, type L2BlockSource } from '@aztec/circuit-types'; import { type BlockProver } from '@aztec/circuit-types/interfaces'; import { type P2P } from '@aztec/p2p'; -import { type SimulationProvider } from '@aztec/simulator'; +import { PublicProcessorFactory, type SimulationProvider } from '@aztec/simulator'; import { type ContractDataSource } from '@aztec/types/contracts'; import { type WorldStateSynchronizer } from '@aztec/world-state'; @@ -9,7 +9,6 @@ import { type SequencerClientConfig } from '../config.js'; import { getGlobalVariableBuilder } from '../global_variable_builder/index.js'; import { getL1Publisher } from '../publisher/index.js'; import { Sequencer, type SequencerConfig } from '../sequencer/index.js'; -import { PublicProcessorFactory } from '../sequencer/public_processor.js'; import { TxValidatorFactory } from '../tx_validator/tx_validator_factory.js'; /** diff --git a/yarn-project/sequencer-client/src/index.ts b/yarn-project/sequencer-client/src/index.ts index ca2c6f3e5a2..66c24396853 100644 --- a/yarn-project/sequencer-client/src/index.ts +++ b/yarn-project/sequencer-client/src/index.ts @@ -5,4 +5,3 @@ export * from './sequencer/index.js'; // Used by the node to simulate public parts of transactions. Should these be moved to a shared library? export * from './global_variable_builder/index.js'; -export * from './sequencer/public_processor.js'; diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index b3e2ab97bdc..72af68c53fc 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -23,15 +23,15 @@ import { } from '@aztec/circuits.js'; import { makeProof } from '@aztec/circuits.js/testing'; import { type P2P, P2PClientState } from '@aztec/p2p'; +import { type PublicProcessor, type PublicProcessorFactory } from '@aztec/simulator'; import { type ContractDataSource } from '@aztec/types/contracts'; import { type MerkleTreeOperations, WorldStateRunningState, type WorldStateSynchronizer } from '@aztec/world-state'; import { type MockProxy, mock, mockFn } from 'jest-mock-extended'; import { type GlobalVariableBuilder } from '../global_variable_builder/global_builder.js'; -import { type L1Publisher } from '../index.js'; +import { type L1Publisher } from '../publisher/l1-publisher.js'; import { TxValidatorFactory } from '../tx_validator/tx_validator_factory.js'; -import { type PublicProcessor, type PublicProcessorFactory } from './public_processor.js'; import { Sequencer } from './sequencer.js'; describe('sequencer', () => { diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index 0c7ffdd01de..d365f94bfbe 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -1,4 +1,11 @@ -import { type L1ToL2MessageSource, type L2Block, type L2BlockSource, type ProcessedTx, Tx } from '@aztec/circuit-types'; +import { + type L1ToL2MessageSource, + type L2Block, + type L2BlockSource, + type ProcessedTx, + Tx, + type TxValidator, +} from '@aztec/circuit-types'; import { type AllowedFunction, type BlockProver, PROVING_STATUS } from '@aztec/circuit-types/interfaces'; import { type L2BlockBuiltStats } from '@aztec/circuit-types/stats'; import { AztecAddress, EthAddress } from '@aztec/circuits.js'; @@ -7,14 +14,13 @@ import { createDebugLogger } from '@aztec/foundation/log'; import { RunningPromise } from '@aztec/foundation/running-promise'; import { Timer, elapsed } from '@aztec/foundation/timer'; import { type P2P } from '@aztec/p2p'; +import { type PublicProcessorFactory } from '@aztec/simulator'; import { type WorldStateStatus, type WorldStateSynchronizer } from '@aztec/world-state'; import { type GlobalVariableBuilder } from '../global_variable_builder/global_builder.js'; import { type L1Publisher } from '../publisher/l1-publisher.js'; -import { type TxValidator } from '../tx_validator/tx_validator.js'; import { type TxValidatorFactory } from '../tx_validator/tx_validator_factory.js'; import { type SequencerConfig } from './config.js'; -import { type PublicProcessorFactory } from './public_processor.js'; /** * Sequencer client diff --git a/yarn-project/sequencer-client/src/tx_validator/aggregate_tx_validator.test.ts b/yarn-project/sequencer-client/src/tx_validator/aggregate_tx_validator.test.ts index 520bca760bf..1eb7558bf25 100644 --- a/yarn-project/sequencer-client/src/tx_validator/aggregate_tx_validator.test.ts +++ b/yarn-project/sequencer-client/src/tx_validator/aggregate_tx_validator.test.ts @@ -1,7 +1,6 @@ -import { Tx, type TxHash, mockTx } from '@aztec/circuit-types'; +import { type AnyTx, Tx, type TxHash, type TxValidator, mockTx } from '@aztec/circuit-types'; import { AggregateTxValidator } from './aggregate_tx_validator.js'; -import { type AnyTx, type TxValidator } from './tx_validator.js'; describe('AggregateTxValidator', () => { it('allows txs that pass all validation', async () => { diff --git a/yarn-project/sequencer-client/src/tx_validator/aggregate_tx_validator.ts b/yarn-project/sequencer-client/src/tx_validator/aggregate_tx_validator.ts index 5c829322f6f..8397a45eede 100644 --- a/yarn-project/sequencer-client/src/tx_validator/aggregate_tx_validator.ts +++ b/yarn-project/sequencer-client/src/tx_validator/aggregate_tx_validator.ts @@ -1,6 +1,4 @@ -import { type ProcessedTx, type Tx } from '@aztec/circuit-types'; - -import { type TxValidator } from './tx_validator.js'; +import { type ProcessedTx, type Tx, type TxValidator } from '@aztec/circuit-types'; export class AggregateTxValidator implements TxValidator { #validators: TxValidator[]; diff --git a/yarn-project/sequencer-client/src/tx_validator/double_spend_validator.test.ts b/yarn-project/sequencer-client/src/tx_validator/double_spend_validator.test.ts index da88e4ce396..5cf758a6cfd 100644 --- a/yarn-project/sequencer-client/src/tx_validator/double_spend_validator.test.ts +++ b/yarn-project/sequencer-client/src/tx_validator/double_spend_validator.test.ts @@ -1,9 +1,8 @@ -import { mockTx, mockTxForRollup } from '@aztec/circuit-types'; +import { type AnyTx, mockTx, mockTxForRollup } from '@aztec/circuit-types'; import { type MockProxy, mock, mockFn } from 'jest-mock-extended'; import { DoubleSpendTxValidator, type NullifierSource } from './double_spend_validator.js'; -import { type AnyTx } from './tx_validator.js'; describe('DoubleSpendTxValidator', () => { let txValidator: DoubleSpendTxValidator; diff --git a/yarn-project/sequencer-client/src/tx_validator/double_spend_validator.ts b/yarn-project/sequencer-client/src/tx_validator/double_spend_validator.ts index 695e7b7b6f5..62db72b5ec9 100644 --- a/yarn-project/sequencer-client/src/tx_validator/double_spend_validator.ts +++ b/yarn-project/sequencer-client/src/tx_validator/double_spend_validator.ts @@ -1,9 +1,7 @@ -import { Tx } from '@aztec/circuit-types'; +import { type AnyTx, Tx, type TxValidator } from '@aztec/circuit-types'; import { Fr } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; -import { type AnyTx, type TxValidator } from './tx_validator.js'; - export interface NullifierSource { getNullifierIndex: (nullifier: Fr) => Promise; } diff --git a/yarn-project/sequencer-client/src/tx_validator/gas_validator.ts b/yarn-project/sequencer-client/src/tx_validator/gas_validator.ts index 5775fb7c623..3d4bf8b39a2 100644 --- a/yarn-project/sequencer-client/src/tx_validator/gas_validator.ts +++ b/yarn-project/sequencer-client/src/tx_validator/gas_validator.ts @@ -1,11 +1,9 @@ -import { Tx } from '@aztec/circuit-types'; +import { Tx, type TxValidator } from '@aztec/circuit-types'; import { type AztecAddress, Fr } from '@aztec/circuits.js'; import { pedersenHash } from '@aztec/foundation/crypto'; import { createDebugLogger } from '@aztec/foundation/log'; import { GasTokenContract } from '@aztec/noir-contracts.js'; - -import { AbstractPhaseManager, PublicKernelPhase } from '../sequencer/abstract_phase_manager.js'; -import { type TxValidator } from './tx_validator.js'; +import { AbstractPhaseManager, PublicKernelPhase } from '@aztec/simulator'; /** Provides a view into public contract state */ export interface PublicStateSource { diff --git a/yarn-project/sequencer-client/src/tx_validator/metadata_validator.test.ts b/yarn-project/sequencer-client/src/tx_validator/metadata_validator.test.ts index b73c1442562..c78ee70961a 100644 --- a/yarn-project/sequencer-client/src/tx_validator/metadata_validator.test.ts +++ b/yarn-project/sequencer-client/src/tx_validator/metadata_validator.test.ts @@ -1,9 +1,8 @@ -import { mockTx, mockTxForRollup } from '@aztec/circuit-types'; +import { type AnyTx, mockTx, mockTxForRollup } from '@aztec/circuit-types'; import { Fr, type GlobalVariables, MaxBlockNumber } from '@aztec/circuits.js'; import { makeGlobalVariables } from '@aztec/circuits.js/testing'; import { MetadataTxValidator } from './metadata_validator.js'; -import { type AnyTx } from './tx_validator.js'; describe('MetadataTxValidator', () => { let globalVariables: GlobalVariables; diff --git a/yarn-project/sequencer-client/src/tx_validator/metadata_validator.ts b/yarn-project/sequencer-client/src/tx_validator/metadata_validator.ts index 38f0c0714dc..d08e7a8929f 100644 --- a/yarn-project/sequencer-client/src/tx_validator/metadata_validator.ts +++ b/yarn-project/sequencer-client/src/tx_validator/metadata_validator.ts @@ -1,9 +1,7 @@ -import { Tx } from '@aztec/circuit-types'; +import { type AnyTx, Tx, type TxValidator } from '@aztec/circuit-types'; import { type GlobalVariables } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; -import { type AnyTx, type TxValidator } from './tx_validator.js'; - export class MetadataTxValidator implements TxValidator { #log = createDebugLogger('aztec:sequencer:tx_validator:tx_metadata'); #globalVariables: GlobalVariables; diff --git a/yarn-project/sequencer-client/src/tx_validator/phases_validator.ts b/yarn-project/sequencer-client/src/tx_validator/phases_validator.ts index b4d62d5ed94..0c795a22a32 100644 --- a/yarn-project/sequencer-client/src/tx_validator/phases_validator.ts +++ b/yarn-project/sequencer-client/src/tx_validator/phases_validator.ts @@ -1,11 +1,9 @@ -import { type AllowedFunction, Tx } from '@aztec/circuit-types'; +import { type AllowedFunction, Tx, type TxValidator } from '@aztec/circuit-types'; import { type PublicCallRequest } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; +import { AbstractPhaseManager, PublicKernelPhase } from '@aztec/simulator'; import { type ContractDataSource } from '@aztec/types/contracts'; -import { AbstractPhaseManager, PublicKernelPhase } from '../sequencer/abstract_phase_manager.js'; -import { type TxValidator } from './tx_validator.js'; - export class PhasesTxValidator implements TxValidator { #log = createDebugLogger('aztec:sequencer:tx_validator:tx_phases'); diff --git a/yarn-project/sequencer-client/src/tx_validator/tx_validator_factory.ts b/yarn-project/sequencer-client/src/tx_validator/tx_validator_factory.ts index 6162d502f0e..2f881e27f24 100644 --- a/yarn-project/sequencer-client/src/tx_validator/tx_validator_factory.ts +++ b/yarn-project/sequencer-client/src/tx_validator/tx_validator_factory.ts @@ -1,16 +1,15 @@ -import { type AllowedFunction, type ProcessedTx, type Tx } from '@aztec/circuit-types'; +import { type AllowedFunction, type ProcessedTx, type Tx, type TxValidator } from '@aztec/circuit-types'; import { type EthAddress, type GlobalVariables } from '@aztec/circuits.js'; import { getCanonicalGasTokenAddress } from '@aztec/protocol-contracts/gas-token'; +import { WorldStateDB, WorldStatePublicDB } from '@aztec/simulator'; import { type ContractDataSource } from '@aztec/types/contracts'; import { type MerkleTreeOperations } from '@aztec/world-state'; -import { WorldStateDB, WorldStatePublicDB } from '../simulator/public_executor.js'; import { AggregateTxValidator } from './aggregate_tx_validator.js'; import { DoubleSpendTxValidator } from './double_spend_validator.js'; import { GasTxValidator } from './gas_validator.js'; import { MetadataTxValidator } from './metadata_validator.js'; import { PhasesTxValidator } from './phases_validator.js'; -import { type TxValidator } from './tx_validator.js'; export class TxValidatorFactory { constructor( diff --git a/yarn-project/simulator/package.json b/yarn-project/simulator/package.json index a42ff7c0d1b..1c13ca0a631 100644 --- a/yarn-project/simulator/package.json +++ b/yarn-project/simulator/package.json @@ -40,7 +40,10 @@ "@aztec/circuit-types": "workspace:^", "@aztec/circuits.js": "workspace:^", "@aztec/foundation": "workspace:^", + "@aztec/noir-protocol-circuits-types": "workspace:^", + "@aztec/protocol-contracts": "workspace:^", "@aztec/types": "workspace:^", + "@aztec/world-state": "workspace:^", "@noir-lang/acvm_js": "portal:../../noir/packages/acvm_js", "@noir-lang/types": "portal:../../noir/packages/types", "levelup": "^5.1.1", diff --git a/yarn-project/simulator/src/index.ts b/yarn-project/simulator/src/index.ts index e55ef8e402e..6701aa44352 100644 --- a/yarn-project/simulator/src/index.ts +++ b/yarn-project/simulator/src/index.ts @@ -3,3 +3,4 @@ export * from './client/index.js'; export * from './common/index.js'; export * from './public/index.js'; export * from './simulator/index.js'; +export * from './mocks/index.js'; diff --git a/yarn-project/simulator/src/mocks/fixtures.ts b/yarn-project/simulator/src/mocks/fixtures.ts new file mode 100644 index 00000000000..cdcfba83666 --- /dev/null +++ b/yarn-project/simulator/src/mocks/fixtures.ts @@ -0,0 +1,166 @@ +import { type FunctionCall, type SimulationError, UnencryptedFunctionL2Logs } from '@aztec/circuit-types'; +import { + ARGS_LENGTH, + type AztecAddress, + CallContext, + CallRequest, + type ContractStorageUpdateRequest, + EthAddress, + Fr, + FunctionData, + GasSettings, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, + type PrivateKernelTailCircuitPublicInputs, + type PublicCallRequest, +} from '@aztec/circuits.js'; +import { makeAztecAddress, makeSelector } from '@aztec/circuits.js/testing'; +import { padArrayEnd } from '@aztec/foundation/collection'; + +import { type PublicExecution, type PublicExecutionResult } from '../public/execution.js'; + +export class PublicExecutionResultBuilder { + private _execution: PublicExecution; + private _nestedExecutions: PublicExecutionResult[] = []; + private _contractStorageUpdateRequests: ContractStorageUpdateRequest[] = []; + private _returnValues: Fr[] = []; + private _reverted = false; + private _revertReason: SimulationError | undefined = undefined; + + constructor(execution: PublicExecution) { + this._execution = execution; + } + + static fromPublicCallRequest({ + request, + returnValues = [new Fr(1n)], + nestedExecutions = [], + contractStorageUpdateRequests = [], + }: { + request: PublicCallRequest; + returnValues?: Fr[]; + nestedExecutions?: PublicExecutionResult[]; + contractStorageUpdateRequests?: ContractStorageUpdateRequest[]; + }): PublicExecutionResultBuilder { + const builder = new PublicExecutionResultBuilder(request); + + builder.withNestedExecutions(...nestedExecutions); + builder.withContractStorageUpdateRequest(...contractStorageUpdateRequests); + builder.withReturnValues(...returnValues); + + return builder; + } + + static fromFunctionCall({ + from, + tx, + returnValues = [new Fr(1n)], + nestedExecutions = [], + contractStorageUpdateRequests = [], + revertReason, + }: { + from: AztecAddress; + tx: FunctionCall; + returnValues?: Fr[]; + nestedExecutions?: PublicExecutionResult[]; + contractStorageUpdateRequests?: ContractStorageUpdateRequest[]; + revertReason?: SimulationError; + }) { + const builder = new PublicExecutionResultBuilder({ + callContext: new CallContext( + from, + tx.to, + EthAddress.ZERO, + tx.functionData.selector, + false, + false, + 0, + GasSettings.empty(), + Fr.ZERO, + ), + contractAddress: tx.to, + functionData: tx.functionData, + args: tx.args, + }); + + builder.withNestedExecutions(...nestedExecutions); + builder.withContractStorageUpdateRequest(...contractStorageUpdateRequests); + builder.withReturnValues(...returnValues); + if (revertReason) { + builder.withReverted(revertReason); + } + + return builder; + } + + withNestedExecutions(...nested: PublicExecutionResult[]): PublicExecutionResultBuilder { + this._nestedExecutions.push(...nested); + return this; + } + + withContractStorageUpdateRequest(...request: ContractStorageUpdateRequest[]): PublicExecutionResultBuilder { + this._contractStorageUpdateRequests.push(...request); + return this; + } + + withReturnValues(...values: Fr[]): PublicExecutionResultBuilder { + this._returnValues.push(...values); + return this; + } + + withReverted(reason: SimulationError): PublicExecutionResultBuilder { + this._reverted = true; + this._revertReason = reason; + return this; + } + + build(): PublicExecutionResult { + return { + execution: this._execution, + nestedExecutions: this._nestedExecutions, + nullifierReadRequests: [], + nullifierNonExistentReadRequests: [], + contractStorageUpdateRequests: this._contractStorageUpdateRequests, + returnValues: padArrayEnd(this._returnValues, Fr.ZERO, 4), // TODO(#5450) Need to use the proper return values here + newNoteHashes: [], + newNullifiers: [], + newL2ToL1Messages: [], + contractStorageReads: [], + unencryptedLogs: UnencryptedFunctionL2Logs.empty(), + startSideEffectCounter: Fr.ZERO, + endSideEffectCounter: Fr.ZERO, + reverted: this._reverted, + revertReason: this._revertReason, + }; + } +} + +export const makeFunctionCall = ( + to = makeAztecAddress(30), + selector = makeSelector(5), + args = new Array(ARGS_LENGTH).fill(Fr.ZERO), +) => ({ to, functionData: new FunctionData(selector, false), args }); + +export function addKernelPublicCallStack( + kernelOutput: PrivateKernelTailCircuitPublicInputs, + calls: { + setupCalls: PublicCallRequest[]; + appLogicCalls: PublicCallRequest[]; + teardownCall: PublicCallRequest; + }, +) { + // the first two calls are non-revertible + // the first is for setup, the second is for teardown + kernelOutput.forPublic!.endNonRevertibleData.publicCallStack = padArrayEnd( + // this is a stack, so the first item is the last call + // and callRequests is in the order of the calls + [calls.teardownCall.toCallRequest(), ...calls.setupCalls.map(c => c.toCallRequest())], + CallRequest.empty(), + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, + ); + + kernelOutput.forPublic!.end.publicCallStack = padArrayEnd( + calls.appLogicCalls.map(c => c.toCallRequest()), + CallRequest.empty(), + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, + ); +} diff --git a/yarn-project/simulator/src/mocks/index.ts b/yarn-project/simulator/src/mocks/index.ts new file mode 100644 index 00000000000..dd1a464237b --- /dev/null +++ b/yarn-project/simulator/src/mocks/index.ts @@ -0,0 +1 @@ +export * from './fixtures.js'; diff --git a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts b/yarn-project/simulator/src/public/abstract_phase_manager.ts similarity index 99% rename from yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts rename to yarn-project/simulator/src/public/abstract_phase_manager.ts index 0733cb967e1..092adbbc620 100644 --- a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts +++ b/yarn-project/simulator/src/public/abstract_phase_manager.ts @@ -66,8 +66,8 @@ import { } from '@aztec/simulator'; import { type MerkleTreeOperations } from '@aztec/world-state'; -import { type PublicKernelCircuitSimulator } from '../simulator/index.js'; import { HintsBuilder } from './hints_builder.js'; +import { type PublicKernelCircuitSimulator } from './public_kernel_circuit_simulator.js'; import { lastSideEffectCounter } from './utils.js'; export enum PublicKernelPhase { diff --git a/yarn-project/sequencer-client/src/sequencer/app_logic_phase_manager.ts b/yarn-project/simulator/src/public/app_logic_phase_manager.ts similarity index 94% rename from yarn-project/sequencer-client/src/sequencer/app_logic_phase_manager.ts rename to yarn-project/simulator/src/public/app_logic_phase_manager.ts index 831714e4468..b3253260b83 100644 --- a/yarn-project/sequencer-client/src/sequencer/app_logic_phase_manager.ts +++ b/yarn-project/simulator/src/public/app_logic_phase_manager.ts @@ -8,9 +8,9 @@ import { import { type PublicExecutor, type PublicStateDB } from '@aztec/simulator'; import { type MerkleTreeOperations } from '@aztec/world-state'; -import { type PublicKernelCircuitSimulator } from '../simulator/index.js'; -import { type ContractsDataSourcePublicDB } from '../simulator/public_executor.js'; import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js'; +import { type ContractsDataSourcePublicDB } from './public_executor.js'; +import { type PublicKernelCircuitSimulator } from './public_kernel_circuit_simulator.js'; /** * The phase manager responsible for performing the fee preparation phase. diff --git a/yarn-project/sequencer-client/src/sequencer/hints_builder.ts b/yarn-project/simulator/src/public/hints_builder.ts similarity index 100% rename from yarn-project/sequencer-client/src/sequencer/hints_builder.ts rename to yarn-project/simulator/src/public/hints_builder.ts diff --git a/yarn-project/simulator/src/public/index.ts b/yarn-project/simulator/src/public/index.ts index 7791d89ec4e..f44e9c47aab 100644 --- a/yarn-project/simulator/src/public/index.ts +++ b/yarn-project/simulator/src/public/index.ts @@ -7,3 +7,8 @@ export { collectPublicDataUpdateRequests, } from './execution.js'; export { PublicExecutor } from './executor.js'; +export { PublicProcessor, PublicProcessorFactory } from './public_processor.js'; +export * from './public_executor.js'; +export * from './abstract_phase_manager.js'; +export * from './public_kernel_circuit_simulator.js'; +export * from './public_kernel.js'; diff --git a/yarn-project/sequencer-client/src/sequencer/phase_manager_factory.ts b/yarn-project/simulator/src/public/phase_manager_factory.ts similarity index 95% rename from yarn-project/sequencer-client/src/sequencer/phase_manager_factory.ts rename to yarn-project/simulator/src/public/phase_manager_factory.ts index dd4d24c6a82..39e47f37703 100644 --- a/yarn-project/sequencer-client/src/sequencer/phase_manager_factory.ts +++ b/yarn-project/simulator/src/public/phase_manager_factory.ts @@ -3,10 +3,10 @@ import { type GlobalVariables, type Header, type PublicKernelCircuitPublicInputs import { type PublicExecutor, type PublicStateDB } from '@aztec/simulator'; import { type MerkleTreeOperations } from '@aztec/world-state'; -import { type PublicKernelCircuitSimulator } from '../simulator/index.js'; -import { type ContractsDataSourcePublicDB } from '../simulator/public_executor.js'; import { type AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js'; import { AppLogicPhaseManager } from './app_logic_phase_manager.js'; +import { type ContractsDataSourcePublicDB } from './public_executor.js'; +import { type PublicKernelCircuitSimulator } from './public_kernel_circuit_simulator.js'; import { SetupPhaseManager } from './setup_phase_manager.js'; import { TailPhaseManager } from './tail_phase_manager.js'; import { TeardownPhaseManager } from './teardown_phase_manager.js'; diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/simulator/src/public/public_executor.ts similarity index 100% rename from yarn-project/sequencer-client/src/simulator/public_executor.ts rename to yarn-project/simulator/src/public/public_executor.ts diff --git a/yarn-project/sequencer-client/src/simulator/public_kernel.ts b/yarn-project/simulator/src/public/public_kernel.ts similarity index 98% rename from yarn-project/sequencer-client/src/simulator/public_kernel.ts rename to yarn-project/simulator/src/public/public_kernel.ts index 86bf06484ff..87ca08af2cf 100644 --- a/yarn-project/sequencer-client/src/simulator/public_kernel.ts +++ b/yarn-project/simulator/src/public/public_kernel.ts @@ -23,7 +23,7 @@ import { } from '@aztec/noir-protocol-circuits-types'; import { type SimulationProvider, WASMSimulator } from '@aztec/simulator'; -import { type PublicKernelCircuitSimulator } from './index.js'; +import { type PublicKernelCircuitSimulator } from './public_kernel_circuit_simulator.js'; /** * Implements the PublicKernelCircuitSimulator. diff --git a/yarn-project/sequencer-client/src/simulator/index.ts b/yarn-project/simulator/src/public/public_kernel_circuit_simulator.ts similarity index 100% rename from yarn-project/sequencer-client/src/simulator/index.ts rename to yarn-project/simulator/src/public/public_kernel_circuit_simulator.ts diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts b/yarn-project/simulator/src/public/public_processor.test.ts similarity index 84% rename from yarn-project/sequencer-client/src/sequencer/public_processor.test.ts rename to yarn-project/simulator/src/public/public_processor.test.ts index 8abe3dc31b5..2904b08319e 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/simulator/src/public/public_processor.test.ts @@ -1,33 +1,23 @@ import { type BlockProver, EncryptedTxL2Logs, - type FunctionCall, type ProcessedTx, PublicDataWrite, SiblingPath, SimulationError, Tx, - UnencryptedFunctionL2Logs, + type TxValidator, UnencryptedTxL2Logs, mockTx, toTxEffect, } from '@aztec/circuit-types'; import { - ARGS_LENGTH, - type AztecAddress, - CallContext, - CallRequest, ContractStorageUpdateRequest, - EthAddress, Fr, - FunctionData, - GasSettings, GlobalVariables, Header, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PUBLIC_DATA_TREE_HEIGHT, - type PrivateKernelTailCircuitPublicInputs, type Proof, type PublicCallRequest, PublicDataUpdateRequest, @@ -42,17 +32,17 @@ import { makeSelector, } from '@aztec/circuits.js/testing'; import { makeTuple } from '@aztec/foundation/array'; -import { arrayNonEmptyLength, padArrayEnd, times } from '@aztec/foundation/collection'; -import { type PublicExecution, type PublicExecutionResult, type PublicExecutor, WASMSimulator } from '@aztec/simulator'; +import { arrayNonEmptyLength, times } from '@aztec/foundation/collection'; +import { type PublicExecutionResult, type PublicExecutor, WASMSimulator } from '@aztec/simulator'; import { type MerkleTreeOperations, type TreeInfo } from '@aztec/world-state'; import { jest } from '@jest/globals'; import { type MockProxy, mock } from 'jest-mock-extended'; -import { type PublicKernelCircuitSimulator } from '../simulator/index.js'; -import { type ContractsDataSourcePublicDB, type WorldStatePublicDB } from '../simulator/public_executor.js'; -import { RealPublicKernelCircuitSimulator } from '../simulator/public_kernel.js'; -import { type TxValidator } from '../tx_validator/tx_validator.js'; +import { PublicExecutionResultBuilder, addKernelPublicCallStack, makeFunctionCall } from '../mocks/fixtures.js'; +import { type ContractsDataSourcePublicDB, type WorldStatePublicDB } from './public_executor.js'; +import { RealPublicKernelCircuitSimulator } from './public_kernel.js'; +import { type PublicKernelCircuitSimulator } from './public_kernel_circuit_simulator.js'; import { PublicProcessor } from './public_processor.js'; describe('public_processor', () => { @@ -746,150 +736,3 @@ describe('public_processor', () => { }); }); }); - -class PublicExecutionResultBuilder { - private _execution: PublicExecution; - private _nestedExecutions: PublicExecutionResult[] = []; - private _contractStorageUpdateRequests: ContractStorageUpdateRequest[] = []; - private _returnValues: Fr[] = []; - private _reverted = false; - private _revertReason: SimulationError | undefined = undefined; - - constructor(execution: PublicExecution) { - this._execution = execution; - } - - static fromPublicCallRequest({ - request, - returnValues = [new Fr(1n)], - nestedExecutions = [], - contractStorageUpdateRequests = [], - }: { - request: PublicCallRequest; - returnValues?: Fr[]; - nestedExecutions?: PublicExecutionResult[]; - contractStorageUpdateRequests?: ContractStorageUpdateRequest[]; - }): PublicExecutionResultBuilder { - const builder = new PublicExecutionResultBuilder(request); - - builder.withNestedExecutions(...nestedExecutions); - builder.withContractStorageUpdateRequest(...contractStorageUpdateRequests); - builder.withReturnValues(...returnValues); - - return builder; - } - - static fromFunctionCall({ - from, - tx, - returnValues = [new Fr(1n)], - nestedExecutions = [], - contractStorageUpdateRequests = [], - revertReason, - }: { - from: AztecAddress; - tx: FunctionCall; - returnValues?: Fr[]; - nestedExecutions?: PublicExecutionResult[]; - contractStorageUpdateRequests?: ContractStorageUpdateRequest[]; - revertReason?: SimulationError; - }) { - const builder = new PublicExecutionResultBuilder({ - callContext: new CallContext( - from, - tx.to, - EthAddress.ZERO, - tx.functionData.selector, - false, - false, - 0, - GasSettings.empty(), - Fr.ZERO, - ), - contractAddress: tx.to, - functionData: tx.functionData, - args: tx.args, - }); - - builder.withNestedExecutions(...nestedExecutions); - builder.withContractStorageUpdateRequest(...contractStorageUpdateRequests); - builder.withReturnValues(...returnValues); - if (revertReason) { - builder.withReverted(revertReason); - } - - return builder; - } - - withNestedExecutions(...nested: PublicExecutionResult[]): PublicExecutionResultBuilder { - this._nestedExecutions.push(...nested); - return this; - } - - withContractStorageUpdateRequest(...request: ContractStorageUpdateRequest[]): PublicExecutionResultBuilder { - this._contractStorageUpdateRequests.push(...request); - return this; - } - - withReturnValues(...values: Fr[]): PublicExecutionResultBuilder { - this._returnValues.push(...values); - return this; - } - - withReverted(reason: SimulationError): PublicExecutionResultBuilder { - this._reverted = true; - this._revertReason = reason; - return this; - } - - build(): PublicExecutionResult { - return { - execution: this._execution, - nestedExecutions: this._nestedExecutions, - nullifierReadRequests: [], - nullifierNonExistentReadRequests: [], - contractStorageUpdateRequests: this._contractStorageUpdateRequests, - returnValues: padArrayEnd(this._returnValues, Fr.ZERO, 4), // TODO(#5450) Need to use the proper return values here - newNoteHashes: [], - newNullifiers: [], - newL2ToL1Messages: [], - contractStorageReads: [], - unencryptedLogs: UnencryptedFunctionL2Logs.empty(), - startSideEffectCounter: Fr.ZERO, - endSideEffectCounter: Fr.ZERO, - reverted: this._reverted, - revertReason: this._revertReason, - }; - } -} - -const makeFunctionCall = ( - to = makeAztecAddress(30), - selector = makeSelector(5), - args = new Array(ARGS_LENGTH).fill(Fr.ZERO), -) => ({ to, functionData: new FunctionData(selector, false), args }); - -function addKernelPublicCallStack( - kernelOutput: PrivateKernelTailCircuitPublicInputs, - calls: { - setupCalls: PublicCallRequest[]; - appLogicCalls: PublicCallRequest[]; - teardownCall: PublicCallRequest; - }, -) { - // the first two calls are non-revertible - // the first is for setup, the second is for teardown - kernelOutput.forPublic!.endNonRevertibleData.publicCallStack = padArrayEnd( - // this is a stack, so the first item is the last call - // and callRequests is in the order of the calls - [calls.teardownCall.toCallRequest(), ...calls.setupCalls.map(c => c.toCallRequest())], - CallRequest.empty(), - MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, - ); - - kernelOutput.forPublic!.end.publicCallStack = padArrayEnd( - calls.appLogicCalls.map(c => c.toCallRequest()), - CallRequest.empty(), - MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, - ); -} diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.ts b/yarn-project/simulator/src/public/public_processor.ts similarity index 96% rename from yarn-project/sequencer-client/src/sequencer/public_processor.ts rename to yarn-project/simulator/src/public/public_processor.ts index e2df7c8f1ab..9354bd6d6e9 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.ts +++ b/yarn-project/simulator/src/public/public_processor.ts @@ -5,6 +5,7 @@ import { type PublicKernelRequest, type SimulationError, Tx, + type TxValidator, makeEmptyProcessedTx, makeProcessedTx, toTxEffect, @@ -19,12 +20,11 @@ import { PublicExecutor, type PublicStateDB, type SimulationProvider } from '@az import { type ContractDataSource } from '@aztec/types/contracts'; import { type MerkleTreeOperations } from '@aztec/world-state'; -import { type PublicKernelCircuitSimulator } from '../simulator/index.js'; -import { ContractsDataSourcePublicDB, WorldStateDB, WorldStatePublicDB } from '../simulator/public_executor.js'; -import { RealPublicKernelCircuitSimulator } from '../simulator/public_kernel.js'; -import { type TxValidator } from '../tx_validator/tx_validator.js'; import { type AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js'; import { PhaseManagerFactory } from './phase_manager_factory.js'; +import { ContractsDataSourcePublicDB, WorldStateDB, WorldStatePublicDB } from './public_executor.js'; +import { RealPublicKernelCircuitSimulator } from './public_kernel.js'; +import { type PublicKernelCircuitSimulator } from './public_kernel_circuit_simulator.js'; /** * Creates new instances of PublicProcessor given the provided merkle tree db and contract data source. diff --git a/yarn-project/sequencer-client/src/sequencer/setup_phase_manager.test.ts b/yarn-project/simulator/src/public/setup_phase_manager.test.ts similarity index 94% rename from yarn-project/sequencer-client/src/sequencer/setup_phase_manager.test.ts rename to yarn-project/simulator/src/public/setup_phase_manager.test.ts index 9253ae06055..b90c2a0147d 100644 --- a/yarn-project/sequencer-client/src/sequencer/setup_phase_manager.test.ts +++ b/yarn-project/simulator/src/public/setup_phase_manager.test.ts @@ -7,8 +7,8 @@ import { type MerkleTreeOperations, type TreeInfo } from '@aztec/world-state'; import { it } from '@jest/globals'; import { type MockProxy, mock } from 'jest-mock-extended'; -import { type PublicKernelCircuitSimulator } from '../simulator/index.js'; -import { type ContractsDataSourcePublicDB, type WorldStatePublicDB } from '../simulator/public_executor.js'; +import { type ContractsDataSourcePublicDB, type WorldStatePublicDB } from './public_executor.js'; +import { type PublicKernelCircuitSimulator } from './public_kernel_circuit_simulator.js'; import { SetupPhaseManager } from './setup_phase_manager.js'; class TestSetupPhaseManager extends SetupPhaseManager { diff --git a/yarn-project/sequencer-client/src/sequencer/setup_phase_manager.ts b/yarn-project/simulator/src/public/setup_phase_manager.ts similarity index 93% rename from yarn-project/sequencer-client/src/sequencer/setup_phase_manager.ts rename to yarn-project/simulator/src/public/setup_phase_manager.ts index d1735e52500..591cc5814e2 100644 --- a/yarn-project/sequencer-client/src/sequencer/setup_phase_manager.ts +++ b/yarn-project/simulator/src/public/setup_phase_manager.ts @@ -8,9 +8,9 @@ import { import { type PublicExecutor, type PublicStateDB } from '@aztec/simulator'; import { type MerkleTreeOperations } from '@aztec/world-state'; -import { type PublicKernelCircuitSimulator } from '../simulator/index.js'; -import { type ContractsDataSourcePublicDB } from '../simulator/public_executor.js'; import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js'; +import { type ContractsDataSourcePublicDB } from './public_executor.js'; +import { type PublicKernelCircuitSimulator } from './public_kernel_circuit_simulator.js'; /** * The phase manager responsible for performing the fee preparation phase. diff --git a/yarn-project/sequencer-client/src/sequencer/tail_phase_manager.ts b/yarn-project/simulator/src/public/tail_phase_manager.ts similarity index 96% rename from yarn-project/sequencer-client/src/sequencer/tail_phase_manager.ts rename to yarn-project/simulator/src/public/tail_phase_manager.ts index 87fbf9b460e..0cc78be521f 100644 --- a/yarn-project/sequencer-client/src/sequencer/tail_phase_manager.ts +++ b/yarn-project/simulator/src/public/tail_phase_manager.ts @@ -17,9 +17,9 @@ import { type Tuple } from '@aztec/foundation/serialize'; import { type PublicExecutor, type PublicStateDB } from '@aztec/simulator'; import { type MerkleTreeOperations } from '@aztec/world-state'; -import { type PublicKernelCircuitSimulator } from '../simulator/index.js'; -import { type ContractsDataSourcePublicDB } from '../simulator/public_executor.js'; import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js'; +import { type ContractsDataSourcePublicDB } from './public_executor.js'; +import { type PublicKernelCircuitSimulator } from './public_kernel_circuit_simulator.js'; export class TailPhaseManager extends AbstractPhaseManager { constructor( diff --git a/yarn-project/sequencer-client/src/sequencer/teardown_phase_manager.ts b/yarn-project/simulator/src/public/teardown_phase_manager.ts similarity index 93% rename from yarn-project/sequencer-client/src/sequencer/teardown_phase_manager.ts rename to yarn-project/simulator/src/public/teardown_phase_manager.ts index 0fd37bb9340..5d6cff3a3bd 100644 --- a/yarn-project/sequencer-client/src/sequencer/teardown_phase_manager.ts +++ b/yarn-project/simulator/src/public/teardown_phase_manager.ts @@ -8,9 +8,9 @@ import { import { type PublicExecutor, type PublicStateDB } from '@aztec/simulator'; import { type MerkleTreeOperations } from '@aztec/world-state'; -import { type PublicKernelCircuitSimulator } from '../simulator/index.js'; -import { type ContractsDataSourcePublicDB } from '../simulator/public_executor.js'; import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js'; +import { type ContractsDataSourcePublicDB } from './public_executor.js'; +import { type PublicKernelCircuitSimulator } from './public_kernel_circuit_simulator.js'; /** * The phase manager responsible for performing the fee preparation phase. diff --git a/yarn-project/sequencer-client/src/sequencer/utils.test.ts b/yarn-project/simulator/src/public/utils.test.ts similarity index 100% rename from yarn-project/sequencer-client/src/sequencer/utils.test.ts rename to yarn-project/simulator/src/public/utils.test.ts diff --git a/yarn-project/sequencer-client/src/sequencer/utils.ts b/yarn-project/simulator/src/public/utils.ts similarity index 100% rename from yarn-project/sequencer-client/src/sequencer/utils.ts rename to yarn-project/simulator/src/public/utils.ts diff --git a/yarn-project/sequencer-client/src/simulator/world_state_public_db.test.ts b/yarn-project/simulator/src/public/world_state_public_db.test.ts similarity index 100% rename from yarn-project/sequencer-client/src/simulator/world_state_public_db.test.ts rename to yarn-project/simulator/src/public/world_state_public_db.test.ts diff --git a/yarn-project/simulator/tsconfig.json b/yarn-project/simulator/tsconfig.json index 6e26d91b215..effb5a7151c 100644 --- a/yarn-project/simulator/tsconfig.json +++ b/yarn-project/simulator/tsconfig.json @@ -15,9 +15,18 @@ { "path": "../foundation" }, + { + "path": "../noir-protocol-circuits-types" + }, + { + "path": "../protocol-contracts" + }, { "path": "../types" }, + { + "path": "../world-state" + }, { "path": "../kv-store" }, diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 4f58d8e7e66..23adca3a1b6 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -752,6 +752,7 @@ __metadata: "@aztec/simulator": "workspace:^" "@aztec/world-state": "workspace:^" "@jest/globals": ^29.5.0 + "@noir-lang/types": "portal:../../noir/packages/types" "@types/jest": ^29.5.0 "@types/memdown": ^3.0.0 "@types/node": ^18.7.23 @@ -881,7 +882,10 @@ __metadata: "@aztec/kv-store": "workspace:^" "@aztec/merkle-tree": "workspace:^" "@aztec/noir-contracts.js": "workspace:^" + "@aztec/noir-protocol-circuits-types": "workspace:^" + "@aztec/protocol-contracts": "workspace:^" "@aztec/types": "workspace:^" + "@aztec/world-state": "workspace:^" "@jest/globals": ^29.5.0 "@noir-lang/acvm_js": "portal:../../noir/packages/acvm_js" "@noir-lang/types": "portal:../../noir/packages/types"