diff --git a/yarn-project/bb-prover/src/avm_proving.test.ts b/yarn-project/bb-prover/src/avm_proving.test.ts index ba17be603ab..ce65582ff79 100644 --- a/yarn-project/bb-prover/src/avm_proving.test.ts +++ b/yarn-project/bb-prover/src/avm_proving.test.ts @@ -254,6 +254,7 @@ const proveAndVerifyAvmTestContract = async ( const publicInputs = getPublicInputs(pxResult); const avmCircuitInputs = new AvmCircuitInputs( + functionName, uncompressedBytecode, context.environment.calldata, publicInputs, diff --git a/yarn-project/bb-prover/src/prover/bb_native_proof_creator.ts b/yarn-project/bb-prover/src/prover/bb_native_proof_creator.ts index e59a8b87d22..3cc08097278 100644 --- a/yarn-project/bb-prover/src/prover/bb_native_proof_creator.ts +++ b/yarn-project/bb-prover/src/prover/bb_native_proof_creator.ts @@ -42,6 +42,7 @@ import { type NoirCompiledCircuit } from '@aztec/types/noir'; import { serializeWitness } from '@noir-lang/noirc_abi'; import { type WitnessMap } from '@noir-lang/types'; import * as fs from 'fs/promises'; +import { join } from 'path'; import { BB_RESULT, @@ -175,7 +176,7 @@ export class BBNativeProofCreator implements ProofCreator { throw new Error(errorMessage); } - this.log.info(`Successfully verified ${circuitType} proof in ${result.duration} ms`); + this.log.info(`Successfully verified ${circuitType} proof in ${Math.ceil(result.duration)} ms`); } private async verifyProofFromKey( @@ -304,13 +305,14 @@ export class BBNativeProofCreator implements ProofCreator { }> { const compressedBincodedWitness = serializeWitness(partialWitness); - const inputsWitnessFile = `${directory}/witness.gz`; + const inputsWitnessFile = join(directory, 'witness.gz'); await fs.writeFile(inputsWitnessFile, compressedBincodedWitness); this.log.debug(`Written ${inputsWitnessFile}`); - this.log.info(`Proving ${circuitType} circuit...`); + const dbgCircuitName = appCircuitName ? `(${appCircuitName})` : ''; + this.log.info(`Proving ${circuitType}${dbgCircuitName} circuit...`); const timer = new Timer(); @@ -324,13 +326,11 @@ export class BBNativeProofCreator implements ProofCreator { ); if (provingResult.status === BB_RESULT.FAILURE) { - this.log.error(`Failed to generate proof for ${circuitType}: ${provingResult.reason}`); + this.log.error(`Failed to generate proof for ${circuitType}${dbgCircuitName}: ${provingResult.reason}`); throw new Error(provingResult.reason); } - this.log.info( - `Generated ${circuitType === 'App' ? appCircuitName : circuitType} circuit proof in ${timer.ms()} ms`, - ); + this.log.info(`Generated ${circuitType}${dbgCircuitName} circuit proof in ${Math.ceil(timer.ms())} ms`); if (circuitType === 'App') { const vkData = await extractVkData(directory); diff --git a/yarn-project/bb-prover/src/prover/bb_prover.ts b/yarn-project/bb-prover/src/prover/bb_prover.ts index ad39a749448..be45922558e 100644 --- a/yarn-project/bb-prover/src/prover/bb_prover.ts +++ b/yarn-project/bb-prover/src/prover/bb_prover.ts @@ -439,22 +439,17 @@ export class BBNativeRollupProver implements ServerCircuitProver { const rawProof = await fs.readFile(`${provingResult.proofPath!}/${PROOF_FILENAME}`); const proof = new Proof(rawProof, vkData.numPublicInputs); - logger.info( - `Generated proof for ${circuitType} in ${Math.ceil(provingResult.duration)} ms, size: ${ - proof.buffer.length - } bytes`, - { - circuitName: mapProtocolArtifactNameToCircuitName(circuitType), - // does not include reading the proof from disk - duration: provingResult.duration, - proofSize: proof.buffer.length, - eventName: 'circuit-proving', - // circuitOutput is the partial witness that became the input to the proof - inputSize: output.toBuffer().length, - circuitSize: vkData.circuitSize, - numPublicInputs: vkData.numPublicInputs, - } satisfies CircuitProvingStats, - ); + logger.info(`Generated proof for ${circuitType} in ${Math.ceil(provingResult.duration)} ms`, { + circuitName: mapProtocolArtifactNameToCircuitName(circuitType), + // does not include reading the proof from disk + duration: provingResult.duration, + proofSize: proof.buffer.length, + eventName: 'circuit-proving', + // circuitOutput is the partial witness that became the input to the proof + inputSize: output.toBuffer().length, + circuitSize: vkData.circuitSize, + numPublicInputs: vkData.numPublicInputs, + } satisfies CircuitProvingStats); return { circuitOutput: output, proof }; }; @@ -462,12 +457,12 @@ export class BBNativeRollupProver implements ServerCircuitProver { } private async generateAvmProofWithBB(input: AvmCircuitInputs, workingDirectory: string): Promise { - logger.debug(`Proving avm-circuit...`); + logger.info(`Proving avm-circuit for ${input.functionName}...`); const provingResult = await generateAvmProof(this.config.bbBinaryPath, workingDirectory, input, logger.verbose); if (provingResult.status === BB_RESULT.FAILURE) { - logger.error(`Failed to generate proof for avm-circuit: ${provingResult.reason}`); + logger.error(`Failed to generate AVM proof for ${input.functionName}: ${provingResult.reason}`); throw new Error(provingResult.reason); } @@ -490,11 +485,10 @@ export class BBNativeRollupProver implements ServerCircuitProver { const circuitType = 'avm-circuit' as const; logger.info( - `Generated proof for ${circuitType} in ${Math.ceil(provingResult.duration)} ms, size: ${ - proof.buffer.length - } bytes`, + `Generated proof for ${circuitType}(${input.functionName}) in ${Math.ceil(provingResult.duration)} ms`, { circuitName: circuitType, + appCircuitName: input.functionName, // does not include reading the proof from disk duration: provingResult.duration, proofSize: proof.buffer.length, diff --git a/yarn-project/circuit-types/src/tx/processed_tx.ts b/yarn-project/circuit-types/src/tx/processed_tx.ts index 130cc4a6a6d..cf6bb977423 100644 --- a/yarn-project/circuit-types/src/tx/processed_tx.ts +++ b/yarn-project/circuit-types/src/tx/processed_tx.ts @@ -54,6 +54,7 @@ export const AVM_REQUEST = 'AVM' as const; export type AvmProvingRequest = { type: typeof AVM_REQUEST; + functionName: string; // informational only bytecode: Buffer; calldata: Fr[]; avmHints: AvmExecutionHints; diff --git a/yarn-project/circuits.js/src/structs/avm/avm.ts b/yarn-project/circuits.js/src/structs/avm/avm.ts index 19a55c38667..f33335f800c 100644 --- a/yarn-project/circuits.js/src/structs/avm/avm.ts +++ b/yarn-project/circuits.js/src/structs/avm/avm.ts @@ -367,6 +367,7 @@ export class AvmExecutionHints { export class AvmCircuitInputs { constructor( + public readonly functionName: string, // only informational public readonly bytecode: Buffer, public readonly calldata: Fr[], public readonly publicInputs: PublicCircuitPublicInputs, @@ -378,7 +379,10 @@ export class AvmCircuitInputs { * @returns - The inputs serialized to a buffer. */ toBuffer() { + const functionNameBuffer = Buffer.from(this.functionName); return serializeToBuffer( + functionNameBuffer.length, + functionNameBuffer, this.bytecode.length, this.bytecode, this.calldata.length, @@ -402,7 +406,11 @@ export class AvmCircuitInputs { */ isEmpty(): boolean { return ( - this.bytecode.length == 0 && this.calldata.length == 0 && this.publicInputs.isEmpty() && this.avmHints.isEmpty() + this.functionName.length == 0 && + this.bytecode.length == 0 && + this.calldata.length == 0 && + this.publicInputs.isEmpty() && + this.avmHints.isEmpty() ); } @@ -421,7 +429,7 @@ export class AvmCircuitInputs { * @returns An array of fields. */ static getFields(fields: FieldsOf) { - return [fields.bytecode, fields.calldata, fields.publicInputs, fields.avmHints] as const; + return [fields.functionName, fields.bytecode, fields.calldata, fields.publicInputs, fields.avmHints] as const; } /** @@ -432,8 +440,9 @@ export class AvmCircuitInputs { static fromBuffer(buff: Buffer | BufferReader): AvmCircuitInputs { const reader = BufferReader.asReader(buff); return new AvmCircuitInputs( - reader.readBuffer(), - reader.readVector(Fr), + /*functionName=*/ reader.readBuffer().toString(), + /*bytecode=*/ reader.readBuffer(), + /*calldata=*/ reader.readVector(Fr), PublicCircuitPublicInputs.fromBuffer(reader), AvmExecutionHints.fromBuffer(reader), ); diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index feb968a0dd1..c6fc3c783ec 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -1336,6 +1336,7 @@ export function makeAvmExecutionHints( */ export function makeAvmCircuitInputs(seed = 0, overrides: Partial> = {}): AvmCircuitInputs { return AvmCircuitInputs.from({ + functionName: `function${seed}`, bytecode: makeBytes((seed % 100) + 100, seed), calldata: makeArray((seed % 100) + 10, i => new Fr(i), seed + 0x1000), publicInputs: makePublicCircuitPublicInputs(seed + 0x2000), diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator.ts b/yarn-project/prover-client/src/orchestrator/orchestrator.ts index a270cbb0628..99526b8dfd1 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator.ts @@ -772,6 +772,7 @@ export class ProvingOrchestrator { // Nothing downstream depends on the AVM proof yet. So having this mode lets us incrementally build the AVM circuit. const doAvmProving = async (signal: AbortSignal) => { const inputs: AvmCircuitInputs = new AvmCircuitInputs( + publicFunction.vmRequest!.functionName, publicFunction.vmRequest!.bytecode, publicFunction.vmRequest!.calldata, publicFunction.vmRequest!.kernelRequest.inputs.publicCall.callStackItem.publicInputs, diff --git a/yarn-project/scripts/src/benchmarks/aggregate.ts b/yarn-project/scripts/src/benchmarks/aggregate.ts index 8e7c8d8cba6..af175762de3 100644 --- a/yarn-project/scripts/src/benchmarks/aggregate.ts +++ b/yarn-project/scripts/src/benchmarks/aggregate.ts @@ -133,11 +133,11 @@ function processCircuitSimulation(entry: CircuitSimulationStats, results: Benchm * Buckets are circuit names */ function processCircuitProving(entry: CircuitProvingStats, results: BenchmarkCollectedResults) { - if (entry.circuitName === 'app-circuit') { - const bucket = entry.appCircuitName; - if (!bucket) { + if (entry.circuitName === 'app-circuit' || entry.circuitName === 'avm-circuit') { + if (!entry.appCircuitName) { return; } + const bucket = entry.appCircuitName + (entry.circuitName === 'avm-circuit' ? ' (avm)' : ''); append(results, 'app_circuit_proving_time_in_ms', bucket, entry.duration); append(results, 'app_circuit_proof_size_in_bytes', bucket, entry.proofSize); append(results, 'app_circuit_size_in_gates', bucket, entry.circuitSize); diff --git a/yarn-project/simulator/src/public/abstract_phase_manager.ts b/yarn-project/simulator/src/public/abstract_phase_manager.ts index 3dd7016612d..ce25f70189d 100644 --- a/yarn-project/simulator/src/public/abstract_phase_manager.ts +++ b/yarn-project/simulator/src/public/abstract_phase_manager.ts @@ -77,6 +77,7 @@ export const PhaseIsRevertible: Record = { }; export type PublicProvingInformation = { + functionName: string; // informational only calldata: Fr[]; bytecode: Buffer; inputs: PublicKernelCircuitPrivateInputs; @@ -89,6 +90,7 @@ export function makeAvmProvingRequest( ): AvmProvingRequest { return { type: AVM_REQUEST, + functionName: info.functionName, bytecode: info.bytecode, calldata: info.calldata, avmHints: info.avmHints, @@ -274,6 +276,13 @@ export abstract class AbstractPhaseManager { ) : current; + // For debug and stats. + const functionName = + (await this.publicExecutor.contractsDb.getDebugFunctionName( + result.execution.contractAddress, + result.execution.functionSelector, + )) ?? 'unknown'; + // Accumulate gas used in this execution gasUsed = gasUsed.add(Gas.from(result.startGasLeft).sub(Gas.from(result.endGasLeft))); @@ -282,13 +291,13 @@ export abstract class AbstractPhaseManager { const functionSelector = result.execution.functionSelector.toString(); if (result.reverted && !result.revertReason) { throw new Error( - `Simulation of ${result.execution.contractAddress.toString()}:${functionSelector} reverted with no reason.`, + `Simulation of ${result.execution.contractAddress.toString()}:${functionSelector}(${functionName}) reverted with no reason.`, ); } if (result.reverted && !PhaseIsRevertible[this.phase]) { this.log.debug( - `Simulation error on ${result.execution.contractAddress.toString()}:${functionSelector} with reason: ${ + `Simulation error on ${result.execution.contractAddress.toString()}:${functionSelector}(${functionName}) with reason: ${ result.revertReason }`, ); @@ -302,7 +311,7 @@ export abstract class AbstractPhaseManager { // Simulate the public kernel circuit. this.log.debug( - `Running public kernel circuit for ${result.execution.contractAddress.toString()}:${functionSelector}`, + `Running public kernel circuit for ${result.execution.contractAddress.toString()}:${functionSelector}(${functionName})`, ); const callData = await this.getPublicCallData(result, isExecutionRequest); const [privateInputs, publicInputs] = await this.runKernelCircuit(kernelPublicOutput, callData); @@ -310,6 +319,7 @@ export abstract class AbstractPhaseManager { // Capture the inputs for later proving in the AVM and kernel. const publicProvingInformation: PublicProvingInformation = { + functionName: functionName, calldata: result.calldata, bytecode: result.bytecode!, inputs: privateInputs, @@ -322,7 +332,7 @@ export abstract class AbstractPhaseManager { // but the kernel carries the reverted flag forward. But if the simulator reverts, so should the kernel. if (result.reverted && kernelPublicOutput.revertCode.isOK()) { throw new Error( - `Public kernel circuit did not revert on ${result.execution.contractAddress.toString()}:${functionSelector}, but simulator did.`, + `Public kernel circuit did not revert on ${result.execution.contractAddress.toString()}:${functionSelector}(${functionName}), but simulator did.`, ); } @@ -330,7 +340,7 @@ export abstract class AbstractPhaseManager { // So safely return the revert reason and the kernel output (which has had its revertible side effects dropped) if (result.reverted) { this.log.debug( - `Reverting on ${result.execution.contractAddress.toString()}:${functionSelector} with reason: ${ + `Reverting on ${result.execution.contractAddress.toString()}:${functionSelector}(${functionName}) with reason: ${ result.revertReason }`, ); diff --git a/yarn-project/simulator/src/public/executor.ts b/yarn-project/simulator/src/public/executor.ts index fde6b655eeb..c8c88c34d6b 100644 --- a/yarn-project/simulator/src/public/executor.ts +++ b/yarn-project/simulator/src/public/executor.ts @@ -18,7 +18,7 @@ import { convertAvmResultsToPxResult, createAvmExecutionEnvironment } from './tr export class PublicExecutor { constructor( private readonly stateDb: PublicStateDB, - private readonly contractsDb: PublicContractsDB, + public readonly contractsDb: PublicContractsDB, private readonly commitmentsDb: CommitmentsDB, private readonly header: Header, ) {}