From 15177003e5cf6e1261f99f648697f869bab796a2 Mon Sep 17 00:00:00 2001 From: benesjan Date: Thu, 14 Dec 2023 09:28:55 +0000 Subject: [PATCH] failure case --- .../aztec/src/history/contract_inclusion.nr | 5 ++ .../src/e2e_inclusion_proofs_contract.test.ts | 49 +++++++++++++++---- .../inclusion_proofs_contract/src/main.nr | 4 +- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/yarn-project/aztec-nr/aztec/src/history/contract_inclusion.nr b/yarn-project/aztec-nr/aztec/src/history/contract_inclusion.nr index a2b26361da72..01e776434ae2 100644 --- a/yarn-project/aztec-nr/aztec/src/history/contract_inclusion.nr +++ b/yarn-project/aztec-nr/aztec/src/history/contract_inclusion.nr @@ -9,6 +9,11 @@ use crate::{ oracle::get_membership_witness::get_contract_membership_witness, }; +// Proves that the contract address, portal address and function tree root form a valid contract preimage of a leaf +// which exists at block `block_number`. +// Note: This can be used to approximate a factory pattern --> a factory contract could perform this proof and that +// way verify that a contract at a given address is what it expects. Then it could store it in an internal +// map of contracts (like what Uniswap Factory does with pool contracts - it stores them in a mapping). pub fn prove_contract_inclusion( contract_address: AztecAddress, portal_contract_address: EthAddress, diff --git a/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts b/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts index caba7d552806..a75b4f2997b1 100644 --- a/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts @@ -1,5 +1,13 @@ -import { AccountWallet, AztecAddress, CompleteAddress, Fr, INITIAL_L2_BLOCK_NUM, PXE } from '@aztec/aztec.js'; -import { FunctionSelector, generateFunctionLeaves } from '@aztec/circuits.js'; +import { + AccountWallet, + AztecAddress, + CompleteAddress, + Fr, + FunctionSelector, + INITIAL_L2_BLOCK_NUM, + PXE, +} from '@aztec/aztec.js'; +import { generateFunctionLeaves } from '@aztec/circuits.js'; import { computeFunctionTreeRoot } from '@aztec/circuits.js/abis'; import { InclusionProofsContract } from '@aztec/noir-contracts/types'; @@ -23,6 +31,7 @@ describe('e2e_inclusion_proofs_contract', () => { let contract: InclusionProofsContract; let deploymentBlockNumber: number; const publicValue = 236n; + let contractFunctionTreeRoot: Fr; beforeAll(async () => { ({ pxe, teardown, wallets, accounts } = await setup(1)); @@ -167,13 +176,7 @@ describe('e2e_inclusion_proofs_contract', () => { const contractAddress = contract.address; const portalContractAddress = contract.portalContract; - - const functions = contract.artifact.functions.map(f => ({ - ...f, - selector: FunctionSelector.fromNameAndParameters(f.name, f.parameters), - })); - const functionLeaves = generateFunctionLeaves(functions); - const functionTreeRoot = computeFunctionTreeRoot(functionLeaves); + const functionTreeRoot = getContractFunctionTreeRoot(); await contract.methods .test_contract_inclusion_proof(contractAddress, portalContractAddress, functionTreeRoot, blockNumber) @@ -181,6 +184,22 @@ describe('e2e_inclusion_proofs_contract', () => { .wait(); }); + it('contract existence failure case', async () => { + // This should fail because we choose a block number before the contract was deployed + const blockNumber = deploymentBlockNumber - 1; + + const contractAddress = contract.address; + const portalContractAddress = contract.portalContract; + const functionTreeRoot = getContractFunctionTreeRoot(); + + await expect( + contract.methods + .test_contract_inclusion_proof(contractAddress, portalContractAddress, functionTreeRoot, blockNumber) + .send() + .wait(), + ).rejects.toThrow(/Leaf value: 0x[0-9a-fA-F]+ not found in CONTRACT_TREE/); + }); + const getRandomBlockNumberSinceDeployment = async () => { const currentBlockNumber = await pxe.getBlockNumber(); return deploymentBlockNumber + Math.floor(Math.random() * (currentBlockNumber - deploymentBlockNumber)); @@ -190,4 +209,16 @@ describe('e2e_inclusion_proofs_contract', () => { const currentBlockNumber = await pxe.getBlockNumber(); return deploymentBlockNumber + Math.floor(Math.random() * (currentBlockNumber - INITIAL_L2_BLOCK_NUM)); }; + + const getContractFunctionTreeRoot = () => { + if (!contractFunctionTreeRoot) { + const functions = contract.artifact.functions.map(f => ({ + ...f, + selector: FunctionSelector.fromNameAndParameters(f.name, f.parameters), + })); + const functionLeaves = generateFunctionLeaves(functions); + contractFunctionTreeRoot = computeFunctionTreeRoot(functionLeaves); + } + return contractFunctionTreeRoot; + }; }); diff --git a/yarn-project/noir-contracts/src/contracts/inclusion_proofs_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/inclusion_proofs_contract/src/main.nr index 9fea22adebff..23189ba86612 100644 --- a/yarn-project/noir-contracts/src/contracts/inclusion_proofs_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/inclusion_proofs_contract/src/main.nr @@ -186,8 +186,8 @@ contract InclusionProofs { // Proves that the contract address, portal address and function tree root form a valid contract preimage of a leaf // which exists at block `block_number`. // Note: This can be used to approximate a factory pattern --> a factory contract could perform this proof and that - // way verify that a contract at a given address is what it expects. Then it could store in an internal map - // of contracts (similarily to what Uniswap Factory does with pool contracts). + // way verify that a contract at a given address is what it expects. Then it could store it in an internal + // map of contracts (like what Uniswap Factory does with pool contracts - it stores them in a mapping). #[aztec(private)] fn test_contract_inclusion_proof( contract_address: AztecAddress,