From 6f9a26ce8ea6f7aa0de0d47dd85f5eb262666be8 Mon Sep 17 00:00:00 2001 From: federicobarbacovi <171914500+federicobarbacovi@users.noreply.github.com> Date: Tue, 12 May 2026 09:19:51 +0000 Subject: [PATCH] Fix conflicts --- .../private_kernel_execution_prover.test.ts | 31 +++++++++++++--- .../private_kernel_execution_prover.ts | 35 ++++++++++++++++--- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/yarn-project/pxe/src/private_kernel/private_kernel_execution_prover.test.ts b/yarn-project/pxe/src/private_kernel/private_kernel_execution_prover.test.ts index 55bec6f00fb5..e16dab33ec23 100644 --- a/yarn-project/pxe/src/private_kernel/private_kernel_execution_prover.test.ts +++ b/yarn-project/pxe/src/private_kernel/private_kernel_execution_prover.test.ts @@ -65,16 +65,20 @@ describe('Private Kernel Sequencer', () => { { publicInputs, childPublicInputs = [], + address = contractAddress, + nestedResults, }: { publicInputs?: PrivateCircuitPublicInputs; childPublicInputs?: PrivateCircuitPublicInputs[]; + address?: AztecAddress; + nestedResults?: PrivateCallExecutionResult[]; } = {}, ): PrivateCallExecutionResult => { if (!publicInputs) { publicInputs = PrivateCircuitPublicInputs.empty(); } publicInputs.callContext.functionSelector = new FunctionSelector(fnName.charCodeAt(0)); - publicInputs.callContext.contractAddress = contractAddress; + publicInputs.callContext.contractAddress = address; return new PrivateCallExecutionResult( Buffer.alloc(0), @@ -86,9 +90,10 @@ describe('Private Kernel Sequencer', () => { [], [], [], - (dependencies[fnName] || []).map((name, i) => - createCallExecutionResult(name, { publicInputs: childPublicInputs[i] }), - ), + nestedResults ?? + (dependencies[fnName] || []).map((name, i) => + createCallExecutionResult(name, { publicInputs: childPublicInputs[i] }), + ), [], ); }; @@ -406,4 +411,22 @@ describe('Private Kernel Sequencer', () => { expect(proofCreator.simulateReset).toHaveBeenCalledTimes(3); expect(proofCreator.simulateTail).toHaveBeenCalledTimes(1); }); + + it('fetches updated class id hints once per unique contract address', async () => { + const contractAddressB = AztecAddress.fromBigInt(111111n); + + // a { b {} c {} } + // a and c use contractAddress, b uses contractAddressB → 2 unique contracts, 3 executions. + dependencies = {}; + const bExec = createCallExecutionResult('b', { address: contractAddressB }); + const cExec = createCallExecutionResult('c'); + const aExec = createCallExecutionResult('a', { nestedResults: [bExec, cExec] }); + + const executionResult = new PrivateExecutionResult(aExec, Fr.zero(), []); + await prove(executionResult); + + expect(oracle.getUpdatedClassIdHints).toHaveBeenCalledTimes(2); + expect(oracle.getUpdatedClassIdHints).toHaveBeenCalledWith(contractAddress); + expect(oracle.getUpdatedClassIdHints).toHaveBeenCalledWith(contractAddressB); + }); }); diff --git a/yarn-project/pxe/src/private_kernel/private_kernel_execution_prover.ts b/yarn-project/pxe/src/private_kernel/private_kernel_execution_prover.ts index c92689557f9e..dce2f9dfb7c9 100644 --- a/yarn-project/pxe/src/private_kernel/private_kernel_execution_prover.ts +++ b/yarn-project/pxe/src/private_kernel/private_kernel_execution_prover.ts @@ -1,4 +1,5 @@ import { MAX_APPS_PER_KERNEL } from '@aztec/constants'; +import { uniqueBy } from '@aztec/foundation/collection'; import { vkAsFieldsMegaHonk } from '@aztec/foundation/crypto/keys'; import { Fr } from '@aztec/foundation/curves/bn254'; import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log'; @@ -27,12 +28,14 @@ import { PrivateKernelTailCircuitPrivateInputs, type PrivateKernelTailCircuitPublicInputs, PrivateVerificationKeyHints, + type UpdatedClassIdHints, } from '@aztec/stdlib/kernel'; import { ChonkProof, ChonkProofWithPublicInputs } from '@aztec/stdlib/proofs'; import { type PrivateCallExecutionResult, type PrivateExecutionResult, TxRequest, + collectNested, collectNoteHashNullifierCounterMap, getFinalMinRevertibleSideEffectCounter, } from '@aztec/stdlib/tx'; @@ -120,6 +123,8 @@ export class PrivateKernelExecutionProver { // reusing the existing single-app `needsReset()` check. const planner = new BatchPlanner(noteHashNullifierCounterMap, splitCounter, this.maxBatchSize); + const updatedClassIdHintsMap = await this.prefetchUpdatedClassIdHints(executionResult); + while (executionStack.length) { if (!firstIteration) { let resetBuilder = new PrivateKernelResetPrivateInputsBuilder( @@ -156,7 +161,7 @@ export class PrivateKernelExecutionProver { const batchSize = planner.decideBatchSize(output.publicInputs, executionStack); const apps: PrivateCallData[] = []; for (let i = 0; i < batchSize; i++) { - apps.push(await this.consumeNextApp(executionStack, executionSteps)); + apps.push(await this.consumeNextApp(executionStack, executionSteps, updatedClassIdHintsMap)); } output = await this.runBatchedKernel({ @@ -365,6 +370,7 @@ export class PrivateKernelExecutionProver { private async consumeNextApp( executionStack: PrivateCallExecutionResult[], executionSteps: PrivateExecutionStep[], + updatedClassIdHintsMap: Map, ): Promise { const next = executionStack.pop()!; executionStack.push(...[...next.nestedExecutionResults].reverse()); @@ -385,10 +391,31 @@ export class PrivateKernelExecutionProver { }, }); - return await this.createPrivateCallData(next); + return await this.createPrivateCallData(next, updatedClassIdHintsMap); + } + + /** Prefetches updated class id hints for all unique contracts in the execution tree in parallel. */ + private async prefetchUpdatedClassIdHints( + executionResult: PrivateExecutionResult, + ): Promise> { + const allAddresses = collectNested([executionResult.entrypoint], exec => [ + exec.publicInputs.callContext.contractAddress, + ]); + const uniqueAddresses = uniqueBy(allAddresses, a => a.toString()); + return new Map( + await Promise.all( + uniqueAddresses.map( + async addr => + [addr.toString(), await this.oracle.getUpdatedClassIdHints(addr)] as [string, UpdatedClassIdHints], + ), + ), + ); } - private async createPrivateCallData({ publicInputs, vk: vkAsBuffer }: PrivateCallExecutionResult) { + private async createPrivateCallData( + { publicInputs, vk: vkAsBuffer }: PrivateCallExecutionResult, + updatedClassIdHintsMap: Map, + ) { const { contractAddress, functionSelector } = publicInputs.callContext; const vkAsFields = await vkAsFieldsMegaHonk(vkAsBuffer); @@ -404,7 +431,7 @@ export class PrivateKernelExecutionProver { const { artifactHash: contractClassArtifactHash, publicBytecodeCommitment: contractClassPublicBytecodeCommitment } = await this.oracle.getContractClassIdPreimage(currentContractClassId); - const updatedClassIdHints = await this.oracle.getUpdatedClassIdHints(contractAddress); + const updatedClassIdHints = updatedClassIdHintsMap.get(contractAddress.toString())!; return PrivateCallData.from({ publicInputs,