From 39da8a8a3e5ef2de1838a32add4168745a553bcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 13 Mar 2026 19:56:09 -0300 Subject: [PATCH 1/6] feat: add public log filtering by tag (#21561) Reimplementation of https://github.com/AztecProtocol/aztec-packages/pull/21471. I did the filtering in-memory as explained there due to lack of indices. Additionally I fixed a bug in which certain index tuples were ignored - e.g. if `afterLog` and `txHash` were both specified, `txHash` was ignored. --------- Co-authored-by: Claude Opus 4.6 (1M context) --- .../src/store/kv_archiver_store.test.ts | 24 +++++++++++++++--- yarn-project/archiver/src/store/log_store.ts | 25 ++++++++++++++++++- yarn-project/stdlib/src/logs/log_filter.ts | 5 ++++ 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/yarn-project/archiver/src/store/kv_archiver_store.test.ts b/yarn-project/archiver/src/store/kv_archiver_store.test.ts index e84fa3d43710..d2057ed482d1 100644 --- a/yarn-project/archiver/src/store/kv_archiver_store.test.ts +++ b/yarn-project/archiver/src/store/kv_archiver_store.test.ts @@ -2782,6 +2782,24 @@ describe('KVArchiverDataStore', () => { } }); + it('"tag" filter param is respected', async () => { + // Get a random tag from the logs + const targetBlockIndex = randomInt(numBlocksForPublicLogs); + const targetBlock = publishedCheckpoints[targetBlockIndex].checkpoint.blocks[0]; + const targetTxIndex = randomInt(getTxsPerBlock(targetBlock)); + const targetLogIndex = randomInt(getPublicLogsPerTx(targetBlock, targetTxIndex)); + const targetTag = targetBlock.body.txEffects[targetTxIndex].publicLogs[targetLogIndex].fields[0]; + + const response = await store.getPublicLogs({ tag: targetTag }); + + expect(response.maxLogsHit).toBeFalsy(); + expect(response.logs.length).toBeGreaterThan(0); + + for (const extendedLog of response.logs) { + expect(extendedLog.log.fields[0].equals(targetTag)).toBeTruthy(); + } + }); + it('"afterLog" filter param is respected', async () => { // Get a random log as reference const targetBlockIndex = randomInt(numBlocksForPublicLogs); @@ -2817,13 +2835,13 @@ describe('KVArchiverDataStore', () => { } }); - it('"txHash" filter param is ignored when "afterLog" is set', async () => { - // Get random txHash + it('"txHash" filter param is respected when "afterLog" is set', async () => { + // A random txHash should match nothing, even with afterLog set const txHash = TxHash.random(); const afterLog = new LogId(BlockNumber(1), BlockHash.random(), TxHash.random(), 0, 0); const response = await store.getPublicLogs({ txHash, afterLog }); - expect(response.logs.length).toBeGreaterThan(1); + expect(response.logs.length).toBe(0); }); it('intersecting works', async () => { diff --git a/yarn-project/archiver/src/store/log_store.ts b/yarn-project/archiver/src/store/log_store.ts index e389cba458e2..e2230e7c2847 100644 --- a/yarn-project/archiver/src/store/log_store.ts +++ b/yarn-project/archiver/src/store/log_store.ts @@ -588,11 +588,24 @@ export class LogStore { txLogs: PublicLog[], filter: LogFilter = {}, ): boolean { + if (filter.fromBlock && blockNumber < filter.fromBlock) { + return false; + } + if (filter.toBlock && blockNumber >= filter.toBlock) { + return false; + } + if (filter.txHash && !txHash.equals(filter.txHash)) { + return false; + } + let maxLogsHit = false; let logIndex = typeof filter.afterLog?.logIndex === 'number' ? filter.afterLog.logIndex + 1 : 0; for (; logIndex < txLogs.length; logIndex++) { const log = txLogs[logIndex]; - if (!filter.contractAddress || log.contractAddress.equals(filter.contractAddress)) { + if ( + (!filter.contractAddress || log.contractAddress.equals(filter.contractAddress)) && + (!filter.tag || log.fields[0]?.equals(filter.tag)) + ) { results.push( new ExtendedPublicLog(new LogId(BlockNumber(blockNumber), blockHash, txHash, txIndex, logIndex), log), ); @@ -616,6 +629,16 @@ export class LogStore { txLogs: ContractClassLog[], filter: LogFilter = {}, ): boolean { + if (filter.fromBlock && blockNumber < filter.fromBlock) { + return false; + } + if (filter.toBlock && blockNumber >= filter.toBlock) { + return false; + } + if (filter.txHash && !txHash.equals(filter.txHash)) { + return false; + } + let maxLogsHit = false; let logIndex = typeof filter.afterLog?.logIndex === 'number' ? filter.afterLog.logIndex + 1 : 0; for (; logIndex < txLogs.length; logIndex++) { diff --git a/yarn-project/stdlib/src/logs/log_filter.ts b/yarn-project/stdlib/src/logs/log_filter.ts index d2c191a803a9..75f97cd1ee20 100644 --- a/yarn-project/stdlib/src/logs/log_filter.ts +++ b/yarn-project/stdlib/src/logs/log_filter.ts @@ -1,3 +1,5 @@ +import type { Fr } from '@aztec/foundation/curves/bn254'; + import { z } from 'zod'; import type { AztecAddress } from '../aztec-address/index.js'; @@ -20,6 +22,8 @@ export type LogFilter = { afterLog?: LogId; /** The contract address to filter logs by. */ contractAddress?: AztecAddress; + /** The tag (first field of the log) to filter logs by. */ + tag?: Fr; }; export const LogFilterSchema: ZodFor = z.object({ @@ -28,4 +32,5 @@ export const LogFilterSchema: ZodFor = z.object({ toBlock: schemas.Integer.optional(), afterLog: LogId.schema.optional(), contractAddress: schemas.AztecAddress.optional(), + tag: schemas.Fr.optional(), }); From f3fe3a56f7e58f15e67a16e4dd0f03ca28130434 Mon Sep 17 00:00:00 2001 From: benesjan Date: Fri, 13 Mar 2026 05:40:04 +0000 Subject: [PATCH 2/6] fix(aztec-node): throw error in getLowNullifierMembershipWitness when nullifier exists Previously, getLowNullifierMembershipWitness would log a warning and return the nullifier's own witness when it already existed in the tree. This is wrong for a non-inclusion proof and led to cryptic circuit assertion failures downstream. Now it throws a descriptive error early. Co-Authored-By: Claude Opus 4.6 --- .../aztec-node/src/aztec-node/server.test.ts | 27 +++++++++++++++++++ .../aztec-node/src/aztec-node/server.ts | 13 ++++----- .../stdlib/src/interfaces/aztec-node.ts | 1 + 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/yarn-project/aztec-node/src/aztec-node/server.test.ts b/yarn-project/aztec-node/src/aztec-node/server.test.ts index 223f4d1e29ea..5803432b342b 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.test.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.test.ts @@ -398,6 +398,33 @@ describe('aztec node', () => { }); }); + describe('getLowNullifierMembershipWitness', () => { + beforeEach(() => { + lastBlockNumber = BlockNumber(1); + }); + + it('throws when nullifier already exists in the tree', async () => { + const nullifier = Fr.random(); + merkleTreeOps.getPreviousValueIndex.mockImplementation((treeId: MerkleTreeId, value: bigint) => { + if (treeId === MerkleTreeId.NULLIFIER_TREE && value === nullifier.toBigInt()) { + return Promise.resolve({ index: 42n, alreadyPresent: true }); + } + return Promise.resolve(undefined); + }); + + await expect(node.getLowNullifierMembershipWitness('latest', nullifier)).rejects.toThrow( + /Cannot prove nullifier non-inclusion/, + ); + }); + + it('returns undefined when nullifier not found', async () => { + merkleTreeOps.getPreviousValueIndex.mockResolvedValue(undefined); + + const result = await node.getLowNullifierMembershipWitness('latest', Fr.random()); + expect(result).toBeUndefined(); + }); + }); + describe('findLeavesIndexes', () => { const blockHash1 = Fr.random(); const blockHash2 = Fr.random(); diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 203d2b4f866a..b905aeec7ba4 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -1135,18 +1135,13 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable { /** * Returns a low nullifier membership witness for a given nullifier at a given block. - * @param referenceBlock - The block parameter (block number, block hash, or 'latest') at which to get the data - * (which contains the root of the nullifier tree in which we are searching for the nullifier). + * @param referenceBlock - The block parameter (block number, block hash, or 'latest') at which to get the data. * @param nullifier - Nullifier we try to find the low nullifier witness for. * @returns The low nullifier membership witness (if found). + * @throws If the nullifier already exists in the tree, since non-inclusion cannot be proven. * @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked * list structure" of leaves and proving that a lower nullifier is pointing to a bigger next value than the nullifier * we are trying to prove non-inclusion for. - * - * Note: This function returns the membership witness of the nullifier itself and not the low nullifier when - * the nullifier already exists in the tree. This is because the `getPreviousValueIndex` function returns the - * index of the nullifier itself when it already exists in the tree. - * TODO: This is a confusing behavior and we should eventually address that. */ public async getLowNullifierMembershipWitness( referenceBlock: BlockParameter, @@ -1159,7 +1154,9 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable { } const { index, alreadyPresent } = findResult; if (alreadyPresent) { - this.log.warn(`Nullifier ${nullifier.toBigInt()} already exists in the tree`); + throw new Error( + `Cannot prove nullifier non-inclusion: nullifier ${nullifier.toBigInt()} already exists in the tree`, + ); } const preimageData = (await committedDb.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index))!; diff --git a/yarn-project/stdlib/src/interfaces/aztec-node.ts b/yarn-project/stdlib/src/interfaces/aztec-node.ts index 94ec70a55654..183354098fd5 100644 --- a/yarn-project/stdlib/src/interfaces/aztec-node.ts +++ b/yarn-project/stdlib/src/interfaces/aztec-node.ts @@ -122,6 +122,7 @@ export interface AztecNode * @param referenceBlock - The block parameter (block number, block hash, or 'latest') at which to get the data. * @param nullifier - Nullifier we try to find the low nullifier witness for. * @returns The low nullifier membership witness (if found). + * @throws If the nullifier already exists in the tree, since non-inclusion cannot be proven. * @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked * list structure" of leaves and proving that a lower nullifier is pointing to a bigger next value than the nullifier * we are trying to prove non-inclusion for. From 46393470aa7b2f8453a75ba362d3ae1bfe37ed43 Mon Sep 17 00:00:00 2001 From: benesjan Date: Fri, 13 Mar 2026 05:42:24 +0000 Subject: [PATCH 3/6] dropping redundant docs --- yarn-project/aztec-node/src/aztec-node/server.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index b905aeec7ba4..8aeee75d54b5 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -1133,16 +1133,6 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable { return new NullifierMembershipWitness(index, leafPreimage as NullifierLeafPreimage, path); } - /** - * Returns a low nullifier membership witness for a given nullifier at a given block. - * @param referenceBlock - The block parameter (block number, block hash, or 'latest') at which to get the data. - * @param nullifier - Nullifier we try to find the low nullifier witness for. - * @returns The low nullifier membership witness (if found). - * @throws If the nullifier already exists in the tree, since non-inclusion cannot be proven. - * @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked - * list structure" of leaves and proving that a lower nullifier is pointing to a bigger next value than the nullifier - * we are trying to prove non-inclusion for. - */ public async getLowNullifierMembershipWitness( referenceBlock: BlockParameter, nullifier: Fr, From 82d21952cf7a73eae0b7a925d12b1e341446b4a1 Mon Sep 17 00:00:00 2001 From: Gregorio Juliana Date: Mon, 16 Mar 2026 10:44:40 +0100 Subject: [PATCH 4/6] feat: default to kernelless simulations (#21575) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're confident enough in them after ensuring expiration_timestamp is set --------- Co-authored-by: Jan Beneš --- .../contract_function_simulator.ts | 14 +++- yarn-project/pxe/src/pxe.ts | 25 ++++-- .../wallets/src/embedded/embedded_wallet.ts | 81 +++++++++---------- 3 files changed, 71 insertions(+), 49 deletions(-) diff --git a/yarn-project/pxe/src/contract_function_simulator/contract_function_simulator.ts b/yarn-project/pxe/src/contract_function_simulator/contract_function_simulator.ts index a81e986f162a..6b1bd80e6baf 100644 --- a/yarn-project/pxe/src/contract_function_simulator/contract_function_simulator.ts +++ b/yarn-project/pxe/src/contract_function_simulator/contract_function_simulator.ts @@ -17,6 +17,7 @@ import { MAX_NULLIFIERS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PRIVATE_LOGS_PER_TX, + MAX_TX_LIFETIME, PRIVATE_TX_L2_GAS_OVERHEAD, PUBLIC_TX_L2_GAS_OVERHEAD, TX_DA_GAS_OVERHEAD, @@ -442,12 +443,23 @@ export async function generateSimulatedProvingResult( let publicTeardownCallRequest; + // We set expiration timestamp to anchor_block_timestamp + MAX_TX_LIFETIME (24h) just like kernels do + let expirationTimestamp = + privateExecutionResult.entrypoint.publicInputs.anchorBlockHeader.globalVariables.timestamp + + BigInt(MAX_TX_LIFETIME); + const executions = [privateExecutionResult.entrypoint]; while (executions.length !== 0) { const execution = executions.shift()!; executions.unshift(...execution!.nestedExecutionResults); + // Just like kernels we overwrite the default value if the call sets it. + const callExpirationTimestamp = execution.publicInputs.expirationTimestamp; + if (callExpirationTimestamp !== 0n && callExpirationTimestamp < expirationTimestamp) { + expirationTimestamp = callExpirationTimestamp; + } + const { contractAddress } = execution.publicInputs.callContext; scopedNoteHashes.push( @@ -671,7 +683,7 @@ export async function generateSimulatedProvingResult( }), ), /*feePayer=*/ AztecAddress.zero(), - /*expirationTimestamp=*/ 0n, + /*expirationTimestamp=*/ expirationTimestamp, hasPublicCalls ? inputsForPublic : undefined, !hasPublicCalls ? inputsForRollup : undefined, ); diff --git a/yarn-project/pxe/src/pxe.ts b/yarn-project/pxe/src/pxe.ts index 449e051e7f03..2688ead9d442 100644 --- a/yarn-project/pxe/src/pxe.ts +++ b/yarn-project/pxe/src/pxe.ts @@ -107,7 +107,9 @@ export type SimulateTxOpts = { skipTxValidation?: boolean; /** If false, fees are enforced. */ skipFeeEnforcement?: boolean; - /** State overrides for the simulation, such as contract instances and artifacts. */ + /** If true, kernel logic is emulated in TS for simulation */ + skipKernels?: boolean; + /** State overrides for the simulation, such as contract instances and artifacts. Requires skipKernels: true */ overrides?: SimulationOverrides; /** Addresses whose private state and keys are accessible during private execution */ scopes: AccessScopes; @@ -896,7 +898,14 @@ export class PXE { */ public simulateTx( txRequest: TxExecutionRequest, - { simulatePublic, skipTxValidation = false, skipFeeEnforcement = false, overrides, scopes }: SimulateTxOpts, + { + simulatePublic, + skipTxValidation = false, + skipFeeEnforcement = false, + skipKernels = true, + overrides, + scopes, + }: SimulateTxOpts, ): Promise { // We disable concurrent simulations since those might execute oracles which read and write to the PXE stores (e.g. // to the capsules), and we need to prevent concurrent runs from interfering with one another (e.g. attempting to @@ -920,13 +929,15 @@ export class PXE { await this.blockStateSynchronizer.sync(); const syncTime = syncTimer.ms(); - const contractFunctionSimulator = this.#getSimulatorForTx(overrides); - // Temporary: in case there are overrides, we have to skip the kernels or validations - // will fail. Consider handing control to the user/wallet on whether they want to run them - // or not. const overriddenContracts = overrides?.contracts ? new Set(Object.keys(overrides.contracts)) : undefined; const hasOverriddenContracts = overriddenContracts !== undefined && overriddenContracts.size > 0; - const skipKernels = hasOverriddenContracts; + + if (hasOverriddenContracts && !skipKernels) { + throw new Error( + 'Simulating with overridden contracts is not compatible with kernel execution. Please set skipKernels to true when simulating with overridden contracts.', + ); + } + const contractFunctionSimulator = this.#getSimulatorForTx(overrides); // Set overridden contracts on the sync service so it knows to skip syncing them if (hasOverriddenContracts) { diff --git a/yarn-project/wallets/src/embedded/embedded_wallet.ts b/yarn-project/wallets/src/embedded/embedded_wallet.ts index e1f69cf6ad09..df2a73b9ecf1 100644 --- a/yarn-project/wallets/src/embedded/embedded_wallet.ts +++ b/yarn-project/wallets/src/embedded/embedded_wallet.ts @@ -10,7 +10,12 @@ import { AztecAddress } from '@aztec/stdlib/aztec-address'; import { getContractInstanceFromInstantiationParams } from '@aztec/stdlib/contract'; import type { AztecNode } from '@aztec/stdlib/interfaces/client'; import { deriveSigningKey } from '@aztec/stdlib/keys'; -import { ExecutionPayload, type TxSimulationResult, mergeExecutionPayloads } from '@aztec/stdlib/tx'; +import { + ExecutionPayload, + SimulationOverrides, + type TxSimulationResult, + mergeExecutionPayloads, +} from '@aztec/stdlib/tx'; import { BaseWallet, type FeeOptions } from '@aztec/wallet-sdk/base-wallet'; import type { AccountContractsProvider } from './account-contract-providers/types.js'; @@ -84,10 +89,20 @@ export class EmbeddedWallet extends BaseWallet { from: AztecAddress, feeOptions: FeeOptions, scopes: AccessScopes, - _skipTxValidation?: boolean, - _skipFeeEnforcement?: boolean, + skipTxValidation?: boolean, + skipFeeEnforcement?: boolean, ): Promise { - const { account: fromAccount, instance, artifact } = await this.getFakeAccountDataFor(from); + let overrides: SimulationOverrides | undefined; + let fromAccount: Account; + if (!from.equals(AztecAddress.ZERO)) { + const { account, instance, artifact } = await this.getFakeAccountDataFor(from); + fromAccount = account; + overrides = { + contracts: { [from.toString()]: { instance, artifact } }, + }; + } else { + fromAccount = await this.getAccountFromAddress(from); + } const feeExecutionPayload = await feeOptions.walletFeePaymentMethod?.getExecutionPayload(); const executionOptions: DefaultAccountEntrypointOptions = { @@ -107,49 +122,33 @@ export class EmbeddedWallet extends BaseWallet { ); return this.pxe.simulateTx(txRequest, { simulatePublic: true, - skipFeeEnforcement: true, - skipTxValidation: true, - overrides: { - contracts: { [from.toString()]: { instance, artifact } }, - }, + skipFeeEnforcement, + skipTxValidation, + overrides, scopes, }); } private async getFakeAccountDataFor(address: AztecAddress) { - // While we have the convention of "Zero address means no auth", and also - // we don't have a way to trigger kernelless simulations without overrides, - // we need to explicitly handle the zero address case here by - // returning the actual multicall contract instead of trying to create a stub account for it. - if (!address.equals(AztecAddress.ZERO)) { - const originalAccount = await this.getAccountFromAddress(address); - if (originalAccount instanceof SignerlessAccount) { - throw new Error(`Cannot create fake account data for SignerlessAccount at address: ${address}`); - } - const originalAddress = (originalAccount as Account).getCompleteAddress(); - const contractInstance = await this.pxe.getContractInstance(originalAddress.address); - if (!contractInstance) { - throw new Error(`No contract instance found for address: ${originalAddress.address}`); - } - const stubAccount = await this.accountContracts.createStubAccount(originalAddress); - const stubArtifact = await this.accountContracts.getStubAccountContractArtifact(); - const instance = await getContractInstanceFromInstantiationParams(stubArtifact, { - salt: Fr.random(), - }); - return { - account: stubAccount, - instance, - artifact: stubArtifact, - }; - } else { - const { instance, artifact } = await this.accountContracts.getMulticallContract(); - const account = new SignerlessAccount(); - return { - instance, - account, - artifact, - }; + const originalAccount = await this.getAccountFromAddress(address); + if (originalAccount instanceof SignerlessAccount) { + throw new Error(`Cannot create fake account data for SignerlessAccount at address: ${address}`); } + const originalAddress = (originalAccount as Account).getCompleteAddress(); + const contractInstance = await this.pxe.getContractInstance(originalAddress.address); + if (!contractInstance) { + throw new Error(`No contract instance found for address: ${originalAddress.address}`); + } + const stubAccount = await this.accountContracts.createStubAccount(originalAddress); + const stubArtifact = await this.accountContracts.getStubAccountContractArtifact(); + const instance = await getContractInstanceFromInstantiationParams(stubArtifact, { + salt: Fr.random(), + }); + return { + account: stubAccount, + instance, + artifact: stubArtifact, + }; } protected async createAccountInternal( From 52010f0edac9c9d53cc9d718f0b29c867622025e Mon Sep 17 00:00:00 2001 From: Nicolas Chamo Date: Mon, 16 Mar 2026 11:31:21 -0300 Subject: [PATCH 5/6] fix: update nullifier non-inclusion test expectations after early oracle throw (#21600) --- noir-projects/aztec-nr/aztec/src/history/note/test.nr | 2 +- noir-projects/aztec-nr/aztec/src/history/nullifier/test.nr | 4 ++-- .../test/test_contract/src/test/deployment_proofs.nr | 4 ++-- .../delayed_public_mutable_values/test.nr | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/history/note/test.nr b/noir-projects/aztec-nr/aztec/src/history/note/test.nr index 783959e9f8f5..b41f31f7490e 100644 --- a/noir-projects/aztec-nr/aztec/src/history/note/test.nr +++ b/noir-projects/aztec-nr/aztec/src/history/note/test.nr @@ -42,7 +42,7 @@ unconstrained fn succeeds_on_blocks_after_creation_and_before_nullification() { }); } -#[test(should_fail_with = "Proving nullifier non-inclusion failed")] +#[test(should_fail_with = "Cannot prove nullifier non-inclusion")] unconstrained fn fails_on_blocks_after_note_nullification() { let (env, hinted_note) = test::create_note_and_nullify_it(); diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier/test.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier/test.nr index 8b754f67759d..a83e216854b3 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier/test.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier/test.nr @@ -79,7 +79,7 @@ unconstrained fn note_not_nullified_succeeds_in_blocks_before_note_nullification ); } -#[test(should_fail_with = "Proving nullifier non-inclusion failed")] +#[test(should_fail_with = "Cannot prove nullifier non-inclusion")] unconstrained fn note_not_nullified_fails_in_blocks_after_note_nullification_fails() { let (env, hinted_note) = test::create_note_and_nullify_it(); @@ -100,7 +100,7 @@ unconstrained fn nullifier_non_inclusion_succeeds_in_blocks_before_nullifier_cre }); } -#[test(should_fail_with = "Proving nullifier non-inclusion failed")] +#[test(should_fail_with = "Cannot prove nullifier non-inclusion")] unconstrained fn nullifier_non_inclusion_fails_in_blocks_after_nullifier_creation() { let env = TestEnvironment::new(); diff --git a/noir-projects/noir-contracts/contracts/test/test_contract/src/test/deployment_proofs.nr b/noir-projects/noir-contracts/contracts/test/test_contract/src/test/deployment_proofs.nr index 03adb43fcb81..c285062e440a 100644 --- a/noir-projects/noir-contracts/contracts/test/test_contract/src/test/deployment_proofs.nr +++ b/noir-projects/noir-contracts/contracts/test/test_contract/src/test/deployment_proofs.nr @@ -103,7 +103,7 @@ unconstrained fn assert_contract_was_initialized_by_before_initialization_fails( ); } -#[test(should_fail_with = "Proving nullifier non-inclusion failed")] +#[test(should_fail_with = "Cannot prove nullifier non-inclusion")] unconstrained fn assert_contract_bytecode_was_not_published_by_of_deployed_fails() { let (env, contract_address, _owner) = setup(); @@ -119,7 +119,7 @@ unconstrained fn assert_contract_bytecode_was_not_published_by_of_deployed_fails ); } -#[test(should_fail_with = "Proving nullifier non-inclusion failed")] +#[test(should_fail_with = "Cannot prove nullifier non-inclusion")] unconstrained fn assert_contract_was_not_initialized_by_of_initialized_fails() { let (env, contract_address, _owner) = setup(); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/delayed_public_mutable/delayed_public_mutable_values/test.nr b/noir-projects/noir-protocol-circuits/crates/types/src/delayed_public_mutable/delayed_public_mutable_values/test.nr index acfb537c9869..c4d409d11f0b 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/delayed_public_mutable/delayed_public_mutable_values/test.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/delayed_public_mutable/delayed_public_mutable_values/test.nr @@ -74,7 +74,7 @@ unconstrained fn packed_delayed_public_mutable_values_match_typescript() { let pre_value = MockStruct { a: 1, b: 2 }; let post_value = MockStruct { a: 3, b: 4 }; - let sdc = ScheduledDelayChange::<0u64>::new(Option::some(1), Option::some(50), 2); + let sdc = ScheduledDelayChange::<0_u64>::new(Option::some(1), Option::some(50), 2); let svc = ScheduledValueChange::new(pre_value, post_value, 50); let dpmv = DelayedPublicMutableValues::new(svc, sdc); From 659d4763482ef89384e65e2967ac76f40c7bd801 Mon Sep 17 00:00:00 2001 From: Nicolas Chamo Date: Mon, 16 Mar 2026 12:41:02 -0300 Subject: [PATCH 6/6] refactor(pxe): type and audit legacy oracle mappings (#21569) --- .../oracle/legacy_oracle_mappings.ts | 155 +++++++++++++----- 1 file changed, 110 insertions(+), 45 deletions(-) diff --git a/yarn-project/pxe/src/contract_function_simulator/oracle/legacy_oracle_mappings.ts b/yarn-project/pxe/src/contract_function_simulator/oracle/legacy_oracle_mappings.ts index ee95befc339a..d8c7297824db 100644 --- a/yarn-project/pxe/src/contract_function_simulator/oracle/legacy_oracle_mappings.ts +++ b/yarn-project/pxe/src/contract_function_simulator/oracle/legacy_oracle_mappings.ts @@ -11,39 +11,108 @@ import type { Oracle } from './oracle.js'; export function buildLegacyOracleCallbacks(oracle: Oracle): ACIRCallback { return { // Simple prefix renames (privateXxx/utilityXxx → aztec_prv_/aztec_utl_) - utilityLog: (...args: ACVMField[][]) => oracle.aztec_utl_log(args[0], args[1], args[2], args[3]), - utilityAssertCompatibleOracleVersion: (...args: ACVMField[][]) => - oracle.aztec_utl_assertCompatibleOracleVersion(args[0]), - utilityLoadCapsule: (...args: ACVMField[][]) => oracle.aztec_utl_loadCapsule(args[0], args[1], args[2]), - privateStoreInExecutionCache: (...args: ACVMField[][]) => oracle.aztec_prv_storeInExecutionCache(args[0], args[1]), - privateLoadFromExecutionCache: (...args: ACVMField[][]) => oracle.aztec_prv_loadFromExecutionCache(args[0]), - privateCallPrivateFunction: (...args: ACVMField[][]) => - oracle.aztec_prv_callPrivateFunction(args[0], args[1], args[2], args[3], args[4]), - privateIsNullifierPending: (...args: ACVMField[][]) => oracle.aztec_prv_isNullifierPending(args[0], args[1]), - privateNotifyCreatedNullifier: (...args: ACVMField[][]) => oracle.aztec_prv_notifyCreatedNullifier(args[0]), - privateNotifyCreatedContractClassLog: (...args: ACVMField[][]) => - oracle.aztec_prv_notifyCreatedContractClassLog(args[0], args[1], args[2], args[3]), - privateGetNextAppTagAsSender: (...args: ACVMField[][]) => oracle.aztec_prv_getNextAppTagAsSender(args[0], args[1]), - privateGetSenderForTags: () => oracle.aztec_prv_getSenderForTags(), - privateSetSenderForTags: (...args: ACVMField[][]) => oracle.aztec_prv_setSenderForTags(args[0]), - utilityGetUtilityContext: () => oracle.aztec_utl_getUtilityContext(), - utilityStorageRead: (...args: ACVMField[][]) => oracle.aztec_utl_storageRead(args[0], args[1], args[2], args[3]), - utilityStoreCapsule: (...args: ACVMField[][]) => oracle.aztec_utl_storeCapsule(args[0], args[1], args[2]), - utilityCopyCapsule: (...args: ACVMField[][]) => oracle.aztec_utl_copyCapsule(args[0], args[1], args[2], args[3]), - utilityDeleteCapsule: (...args: ACVMField[][]) => oracle.aztec_utl_deleteCapsule(args[0], args[1]), - utilityAes128Decrypt: (...args: ACVMField[][]) => - oracle.aztec_utl_aes128Decrypt(args[0], args[1], args[2], args[3]), - utilityGetSharedSecret: (...args: ACVMField[][]) => - oracle.aztec_utl_getSharedSecret(args[0], args[1], args[2], args[3]), - utilityFetchTaggedLogs: (...args: ACVMField[][]) => oracle.aztec_utl_fetchTaggedLogs(args[0]), - utilityBulkRetrieveLogs: (...args: ACVMField[][]) => oracle.aztec_utl_bulkRetrieveLogs(args[0], args[1], args[2]), + utilityLog: ( + level: ACVMField[], + message: ACVMField[], + _ignoredFieldsSize: ACVMField[], + fields: ACVMField[], + ): Promise => oracle.aztec_utl_log(level, message, _ignoredFieldsSize, fields), + utilityAssertCompatibleOracleVersion: (version: ACVMField[]): Promise => + oracle.aztec_utl_assertCompatibleOracleVersion(version), + utilityLoadCapsule: ( + contractAddress: ACVMField[], + slot: ACVMField[], + tSize: ACVMField[], + ): Promise<(ACVMField | ACVMField[])[]> => oracle.aztec_utl_loadCapsule(contractAddress, slot, tSize), + privateStoreInExecutionCache: (values: ACVMField[], hash: ACVMField[]): Promise => + oracle.aztec_prv_storeInExecutionCache(values, hash), + privateLoadFromExecutionCache: (returnsHash: ACVMField[]): Promise => + oracle.aztec_prv_loadFromExecutionCache(returnsHash), + privateCallPrivateFunction: ( + contractAddress: ACVMField[], + functionSelector: ACVMField[], + argsHash: ACVMField[], + sideEffectCounter: ACVMField[], + isStaticCall: ACVMField[], + ): Promise => + oracle.aztec_prv_callPrivateFunction( + contractAddress, + functionSelector, + argsHash, + sideEffectCounter, + isStaticCall, + ), + privateIsNullifierPending: (innerNullifier: ACVMField[], contractAddress: ACVMField[]): Promise => + oracle.aztec_prv_isNullifierPending(innerNullifier, contractAddress), + privateNotifyCreatedNullifier: (innerNullifier: ACVMField[]): Promise => + oracle.aztec_prv_notifyCreatedNullifier(innerNullifier), + privateNotifyCreatedContractClassLog: ( + contractAddress: ACVMField[], + message: ACVMField[], + length: ACVMField[], + counter: ACVMField[], + ): Promise => + oracle.aztec_prv_notifyCreatedContractClassLog(contractAddress, message, length, counter), + utilityGetUtilityContext: (): Promise<(ACVMField | ACVMField[])[]> => oracle.aztec_utl_getUtilityContext(), + utilityStorageRead: ( + blockHash: ACVMField[], + contractAddress: ACVMField[], + startStorageSlot: ACVMField[], + numberOfElements: ACVMField[], + ): Promise => + oracle.aztec_utl_storageRead(blockHash, contractAddress, startStorageSlot, numberOfElements), + utilityStoreCapsule: ( + contractAddress: ACVMField[], + slot: ACVMField[], + capsule: ACVMField[], + ): Promise => oracle.aztec_utl_storeCapsule(contractAddress, slot, capsule), + utilityCopyCapsule: ( + contractAddress: ACVMField[], + srcSlot: ACVMField[], + dstSlot: ACVMField[], + numEntries: ACVMField[], + ): Promise => oracle.aztec_utl_copyCapsule(contractAddress, srcSlot, dstSlot, numEntries), + utilityDeleteCapsule: (contractAddress: ACVMField[], slot: ACVMField[]): Promise => + oracle.aztec_utl_deleteCapsule(contractAddress, slot), + utilityAes128Decrypt: ( + ciphertextBVecStorage: ACVMField[], + ciphertextLength: ACVMField[], + iv: ACVMField[], + symKey: ACVMField[], + ): Promise<(ACVMField | ACVMField[])[]> => + oracle.aztec_utl_aes128Decrypt(ciphertextBVecStorage, ciphertextLength, iv, symKey), + utilityGetSharedSecret: ( + address: ACVMField[], + ephPKField0: ACVMField[], + ephPKField1: ACVMField[], + ephPKField2: ACVMField[], + ): Promise => oracle.aztec_utl_getSharedSecret(address, ephPKField0, ephPKField1, ephPKField2), + utilityFetchTaggedLogs: (pendingTaggedLogArrayBaseSlot: ACVMField[]): Promise => + oracle.aztec_utl_fetchTaggedLogs(pendingTaggedLogArrayBaseSlot), + utilityBulkRetrieveLogs: ( + contractAddress: ACVMField[], + logRetrievalRequestsArrayBaseSlot: ACVMField[], + logRetrievalResponsesArrayBaseSlot: ACVMField[], + ): Promise => + oracle.aztec_utl_bulkRetrieveLogs( + contractAddress, + logRetrievalRequestsArrayBaseSlot, + logRetrievalResponsesArrayBaseSlot, + ), + utilityGetL1ToL2MembershipWitness: ( + contractAddress: ACVMField[], + messageHash: ACVMField[], + secret: ACVMField[], + ): Promise<(ACVMField | ACVMField[])[]> => + oracle.aztec_utl_getL1ToL2MembershipWitness(contractAddress, messageHash, secret), + utilityEmitOffchainEffect: (data: ACVMField[]): Promise => oracle.aztec_utl_emitOffchainEffect(data), // Adapter: old 3-param signature → new 5-param with injected constants. // Values derived from: MAX_MESSAGE_CONTENT_LEN(11) - RESERVED_FIELDS (3 for notes, 1 for events). utilityValidateAndStoreEnqueuedNotesAndEvents: ( contractAddress: ACVMField[], noteValidationRequestsArrayBaseSlot: ACVMField[], eventValidationRequestsArrayBaseSlot: ACVMField[], - ) => + ): Promise => oracle.aztec_utl_validateAndStoreEnqueuedNotesAndEvents( contractAddress, noteValidationRequestsArrayBaseSlot, @@ -51,27 +120,23 @@ export function buildLegacyOracleCallbacks(oracle: Oracle): ACIRCallback { [new Fr(8).toString()], [new Fr(10).toString()], ), - utilityGetL1ToL2MembershipWitness: (...args: ACVMField[][]) => - oracle.aztec_utl_getL1ToL2MembershipWitness(args[0], args[1], args[2]), - utilityCheckNullifierExists: (...args: ACVMField[][]) => oracle.aztec_utl_checkNullifierExists(args[0]), - utilityGetRandomField: () => oracle.aztec_utl_getRandomField(), - utilityEmitOffchainEffect: (...args: ACVMField[][]) => oracle.aztec_utl_emitOffchainEffect(args[0]), // Renames (same signature, different oracle name) - privateNotifySetMinRevertibleSideEffectCounter: (...args: ACVMField[][]) => - oracle.aztec_prv_notifyRevertiblePhaseStart(args[0]), - privateIsSideEffectCounterRevertible: (...args: ACVMField[][]) => oracle.aztec_prv_inRevertiblePhase(args[0]), + privateNotifySetMinRevertibleSideEffectCounter: (counter: ACVMField[]): Promise => + oracle.aztec_prv_notifyRevertiblePhaseStart(counter), + privateIsSideEffectCounterRevertible: (sideEffectCounter: ACVMField[]): Promise => + oracle.aztec_prv_inRevertiblePhase(sideEffectCounter), // Signature changes: old 4-param oracles → new 1-param validatePublicCalldata privateNotifyEnqueuedPublicFunctionCall: ( - [_contractAddress]: ACVMField[], - [calldataHash]: ACVMField[], - [_sideEffectCounter]: ACVMField[], - [_isStaticCall]: ACVMField[], - ) => oracle.aztec_prv_validatePublicCalldata([calldataHash]), + _contractAddress: ACVMField[], + calldataHash: ACVMField[], + _sideEffectCounter: ACVMField[], + _isStaticCall: ACVMField[], + ): Promise => oracle.aztec_prv_validatePublicCalldata(calldataHash), privateNotifySetPublicTeardownFunctionCall: ( - [_contractAddress]: ACVMField[], - [calldataHash]: ACVMField[], - [_sideEffectCounter]: ACVMField[], - [_isStaticCall]: ACVMField[], - ) => oracle.aztec_prv_validatePublicCalldata([calldataHash]), + _contractAddress: ACVMField[], + calldataHash: ACVMField[], + _sideEffectCounter: ACVMField[], + _isStaticCall: ACVMField[], + ): Promise => oracle.aztec_prv_validatePublicCalldata(calldataHash), }; }