From 54d2d17c64e89cb71c073e490a9f600a3dd14d50 Mon Sep 17 00:00:00 2001 From: fcarreiro Date: Fri, 4 Apr 2025 14:56:50 +0000 Subject: [PATCH] chore(avm): use tx hash as avm proof identifier --- .../barretenberg/vm2/common/avm_inputs.hpp | 4 +- .../vm2/common/avm_inputs.testdata.bin | Bin 275377 -> 272977 bytes .../vm2/simulation/tx_execution.cpp | 4 +- .../bb-prover/src/prover/bb_prover.ts | 10 +-- .../public_tx_simulator/public_tx_context.ts | 2 +- .../public_tx_simulator.ts | 3 +- yarn-project/stdlib/src/avm/avm.ts | 71 +++++++++++------- yarn-project/stdlib/src/tests/factories.ts | 7 +- 8 files changed, 59 insertions(+), 42 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/vm2/common/avm_inputs.hpp b/barretenberg/cpp/src/barretenberg/vm2/common/avm_inputs.hpp index 096a44fa8c9f..546f7eede956 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/common/avm_inputs.hpp +++ b/barretenberg/cpp/src/barretenberg/vm2/common/avm_inputs.hpp @@ -253,6 +253,7 @@ struct AccumulatedData { // We are currently using this structure as the input to TX simulation. // That's why I'm not calling it TxHint. We can reconsider if the inner types seem to dirty. struct Tx { + std::string hash; AccumulatedData nonRevertibleAccumulatedData; AccumulatedData revertibleAccumulatedData; std::vector setupEnqueuedCalls; @@ -261,7 +262,8 @@ struct Tx { bool operator==(const Tx& other) const = default; - MSGPACK_FIELDS(nonRevertibleAccumulatedData, + MSGPACK_FIELDS(hash, + nonRevertibleAccumulatedData, revertibleAccumulatedData, setupEnqueuedCalls, appLogicEnqueuedCalls, diff --git a/barretenberg/cpp/src/barretenberg/vm2/common/avm_inputs.testdata.bin b/barretenberg/cpp/src/barretenberg/vm2/common/avm_inputs.testdata.bin index 4c79d413107038d55a1c33ee513d24e35a523800..f868b34c446b8ded904a9767662ac3f982c3d160 100644 GIT binary patch delta 75 zcmdn^T;Spr0kwM!OiME|^Gb^EG4L%askq0$wj?95IAcvo1&Go$Ha4}e*poN?{t0H; b$sD}8%@;V^FK{vfF%u9oZ@<9F@=y~1p~W4> delta 520 zcmX}oJ4?e*90l;CO>q#ULC~pSih~M@0jVwyL2wZY`3RvZ7HXPe1f4WPKS0TFeId45 zsM@7!@l6dbzLtWc6fzamiunfK^B-J(NzTc+fi&NvwRUuH9DI=4aH*DiWaODFiRPYL|qI6Ooiqe9CpC0bXq)bNvv#HU=FL8hub~ z!-5RuEiUt98U%Gj{v-_UVXhz2M_oOJdu5x;YM*qTc!|iHhGGM1gHS2L;tW)GxXk;a zfqX^vF_a(3C#aSvuR(2>%bMRbP_C&yq1q##p>|058PxZ<%djF zbLh=+S@1&x?Uw2))sN&WG|H4;z}!BUiN7?EyAY`w6z3pX{{cOao@@XB diff --git a/barretenberg/cpp/src/barretenberg/vm2/simulation/tx_execution.cpp b/barretenberg/cpp/src/barretenberg/vm2/simulation/tx_execution.cpp index dbf61b8ca100..7b06caf4d0c8 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/simulation/tx_execution.cpp +++ b/barretenberg/cpp/src/barretenberg/vm2/simulation/tx_execution.cpp @@ -5,7 +5,9 @@ namespace bb::avm2::simulation { void TxExecution::simulate(const Tx& tx) { - info("Simulating tx with ", + info("Simulating tx ", + tx.hash, + " with ", tx.setupEnqueuedCalls.size(), " setup enqueued calls, ", tx.appLogicEnqueuedCalls.size(), diff --git a/yarn-project/bb-prover/src/prover/bb_prover.ts b/yarn-project/bb-prover/src/prover/bb_prover.ts index e6ce7227da0b..577f5bb746e1 100644 --- a/yarn-project/bb-prover/src/prover/bb_prover.ts +++ b/yarn-project/bb-prover/src/prover/bb_prover.ts @@ -183,7 +183,7 @@ export class BBNativeRollupProver implements ServerCircuitProver { * @returns The proof. */ @trackSpan('BBNativeRollupProver.getAvmProof', inputs => ({ - [Attributes.APP_CIRCUIT_NAME]: inputs.functionName, + [Attributes.APP_CIRCUIT_NAME]: inputs.hints.tx.hash, })) public async getAvmProof( inputs: AvmCircuitInputs, @@ -503,12 +503,12 @@ export class BBNativeRollupProver implements ServerCircuitProver { } private async generateAvmProofWithBB(input: AvmCircuitInputs, workingDirectory: string): Promise { - logger.info(`Proving avm-circuit for ${input.functionName}...`); + logger.info(`Proving avm-circuit for TX ${input.hints.tx.hash}...`); const provingResult = await generateAvmProof(this.config.bbBinaryPath, workingDirectory, input, logger); if (provingResult.status === BB_RESULT.FAILURE) { - logger.error(`Failed to generate AVM proof for ${input.functionName}: ${provingResult.reason}`); + logger.error(`Failed to generate AVM proof for TX ${input.hints.tx.hash}: ${provingResult.reason}`); throw new ProvingError(provingResult.reason, provingResult, provingResult.retry); } @@ -556,10 +556,10 @@ export class BBNativeRollupProver implements ServerCircuitProver { this.instrumentation.recordAvmSize('circuitSize', appCircuitName, verificationKey.circuitSize); logger.info( - `Generated proof for ${circuitType}(${input.functionName}) in ${Math.ceil(provingResult.durationMs)} ms`, + `Generated proof for ${circuitType}(${input.hints.tx.hash}) in ${Math.ceil(provingResult.durationMs)} ms`, { circuitName: circuitType, - appCircuitName: input.functionName, + appCircuitName: input.hints.tx.hash, // does not include reading the proof from disk duration: provingResult.durationMs, proofSize: avmProof.binaryProof.buffer.length, diff --git a/yarn-project/simulator/src/public/public_tx_simulator/public_tx_context.ts b/yarn-project/simulator/src/public/public_tx_simulator/public_tx_context.ts index 2dbf1556cb72..bab71c33accd 100644 --- a/yarn-project/simulator/src/public/public_tx_simulator/public_tx_context.ts +++ b/yarn-project/simulator/src/public/public_tx_simulator/public_tx_context.ts @@ -111,7 +111,7 @@ export class PublicTxContext { const firstNullifier = nonRevertibleAccumulatedDataFromPrivate.nullifiers[0]; // We wrap the DB to collect AVM hints. - const hints = new AvmExecutionHints(AvmTxHint.fromTx(tx)); + const hints = new AvmExecutionHints(await AvmTxHint.fromTx(tx)); const hintingContractsDB = new HintingPublicContractsDB(contractsDB, hints); const hintingTreesDB = new HintingPublicTreesDB(treesDB, hints); diff --git a/yarn-project/simulator/src/public/public_tx_simulator/public_tx_simulator.ts b/yarn-project/simulator/src/public/public_tx_simulator/public_tx_simulator.ts index e14a2d235912..fc36712d310a 100644 --- a/yarn-project/simulator/src/public/public_tx_simulator/public_tx_simulator.ts +++ b/yarn-project/simulator/src/public/public_tx_simulator/public_tx_simulator.ts @@ -69,7 +69,6 @@ export class PublicTxSimulator { public async simulate(tx: Tx): Promise { try { const txHash = await this.computeTxHash(tx); - this.log.debug(`Simulating ${tx.publicFunctionCalldata.length} public calls for tx ${txHash}`, { txHash }); const context = await PublicTxContext.create( @@ -437,7 +436,7 @@ export class PublicTxSimulator { ): AvmProvingRequest { return { type: ProvingRequestType.PUBLIC_VM, - inputs: new AvmCircuitInputs('public_dispatch', [], hints, publicInputs), + inputs: new AvmCircuitInputs(hints, publicInputs), }; } } diff --git a/yarn-project/stdlib/src/avm/avm.ts b/yarn-project/stdlib/src/avm/avm.ts index cf25670366b3..cd49411bef77 100644 --- a/yarn-project/stdlib/src/avm/avm.ts +++ b/yarn-project/stdlib/src/avm/avm.ts @@ -376,6 +376,7 @@ export class AvmEnqueuedCallHint { export class AvmTxHint { constructor( + public readonly hash: string, public readonly nonRevertibleAccumulatedData: { noteHashes: Fr[]; nullifiers: Fr[]; @@ -393,12 +394,16 @@ export class AvmTxHint { public readonly teardownEnqueuedCall: AvmEnqueuedCallHint | null, ) {} - static fromTx(tx: Tx): AvmTxHint { + static async fromTx(tx: Tx): Promise { const setupCallRequests = tx.getNonRevertiblePublicCallRequestsWithCalldata(); const appLogicCallRequests = tx.getRevertiblePublicCallRequestsWithCalldata(); const teardownCallRequest = tx.getTeardownPublicCallRequestWithCalldata(); + // For informational purposes. Assumed quick because it should be cached. + const txHash = await tx.getTxHash(); + return new AvmTxHint( + txHash.hash.toString(), { noteHashes: tx.data.forPublic!.nonRevertibleAccumulatedData.noteHashes.filter(x => !x.isZero()), nullifiers: tx.data.forPublic!.nonRevertibleAccumulatedData.nullifiers.filter(x => !x.isZero()), @@ -437,23 +442,43 @@ export class AvmTxHint { } static empty() { - return new AvmTxHint({ noteHashes: [], nullifiers: [] }, { noteHashes: [], nullifiers: [] }, [], [], null); + return new AvmTxHint('', { noteHashes: [], nullifiers: [] }, { noteHashes: [], nullifiers: [] }, [], [], null); } static get schema() { - return z.object({ - nonRevertibleAccumulatedData: z.object({ - noteHashes: schemas.Fr.array(), - nullifiers: schemas.Fr.array(), - }), - revertibleAccumulatedData: z.object({ - noteHashes: schemas.Fr.array(), - nullifiers: schemas.Fr.array(), - }), - setupEnqueuedCalls: AvmEnqueuedCallHint.schema.array(), - appLogicEnqueuedCalls: AvmEnqueuedCallHint.schema.array(), - teardownEnqueuedCall: AvmEnqueuedCallHint.schema.nullable(), - }); + return z + .object({ + hash: z.string(), + nonRevertibleAccumulatedData: z.object({ + noteHashes: schemas.Fr.array(), + nullifiers: schemas.Fr.array(), + }), + revertibleAccumulatedData: z.object({ + noteHashes: schemas.Fr.array(), + nullifiers: schemas.Fr.array(), + }), + setupEnqueuedCalls: AvmEnqueuedCallHint.schema.array(), + appLogicEnqueuedCalls: AvmEnqueuedCallHint.schema.array(), + teardownEnqueuedCall: AvmEnqueuedCallHint.schema.nullable(), + }) + .transform( + ({ + hash, + nonRevertibleAccumulatedData, + revertibleAccumulatedData, + setupEnqueuedCalls, + appLogicEnqueuedCalls, + teardownEnqueuedCall, + }) => + new AvmTxHint( + hash, + nonRevertibleAccumulatedData, + revertibleAccumulatedData, + setupEnqueuedCalls, + appLogicEnqueuedCalls, + teardownEnqueuedCall, + ), + ); } } @@ -537,29 +562,19 @@ export class AvmExecutionHints { } export class AvmCircuitInputs { - constructor( - public readonly functionName: string, // only informational - public readonly calldata: Fr[], - public readonly hints: AvmExecutionHints, - public publicInputs: AvmCircuitPublicInputs, - ) {} + constructor(public readonly hints: AvmExecutionHints, public publicInputs: AvmCircuitPublicInputs) {} static empty() { - return new AvmCircuitInputs('', [], AvmExecutionHints.empty(), AvmCircuitPublicInputs.empty()); + return new AvmCircuitInputs(AvmExecutionHints.empty(), AvmCircuitPublicInputs.empty()); } static get schema() { return z .object({ - functionName: z.string(), - calldata: schemas.Fr.array(), hints: AvmExecutionHints.schema, publicInputs: AvmCircuitPublicInputs.schema, }) - .transform( - ({ functionName, calldata, hints, publicInputs }) => - new AvmCircuitInputs(functionName, calldata, hints, publicInputs), - ); + .transform(({ hints, publicInputs }) => new AvmCircuitInputs(hints, publicInputs)); } public serializeWithMessagePack(): Buffer { diff --git a/yarn-project/stdlib/src/tests/factories.ts b/yarn-project/stdlib/src/tests/factories.ts index d154bcdc4595..249695cc1e3c 100644 --- a/yarn-project/stdlib/src/tests/factories.ts +++ b/yarn-project/stdlib/src/tests/factories.ts @@ -1459,6 +1459,7 @@ export function makeAvmEnqueuedCallHint(seed = 0): AvmEnqueuedCallHint { export function makeAvmTxHint(seed = 0): AvmTxHint { return new AvmTxHint( + `txhash-${seed}`, { noteHashes: makeArray((seed % 20) + 4, i => new Fr(i), seed + 0x1000), nullifiers: makeArray((seed % 20) + 4, i => new Fr(i), seed + 0x2000), @@ -1544,14 +1545,12 @@ export async function makeAvmCircuitInputs( overrides: Partial> = {}, ): Promise { const fields = { - functionName: `function${seed}`, - calldata: makeArray((seed % 100) + 10, i => new Fr(i), seed + 0x1000), - avmHints: await makeAvmExecutionHints(seed + 0x3000), + hints: await makeAvmExecutionHints(seed + 0x3000), publicInputs: makeAvmCircuitPublicInputs(seed + 0x4000), ...overrides, }; - return new AvmCircuitInputs(fields.functionName, fields.calldata, fields.avmHints, fields.publicInputs); + return new AvmCircuitInputs(fields.hints, fields.publicInputs); } /**