Skip to content

Commit

Permalink
it's working
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan committed Dec 15, 2023
1 parent 40ec8a3 commit 3485b03
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 90 deletions.
47 changes: 31 additions & 16 deletions yarn-project/aztec-nr/aztec/src/history/contract_inclusion.nr
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use dep::protocol_types::{
abis::new_contract_data::NewContractData as ContractLeafPreimage,
abis::{
complete_address::CompleteAddress,
new_contract_data::NewContractData as ContractLeafPreimage,
},
address::{AztecAddress, EthAddress},
point::Point,
};
use dep::std::merkle::compute_merkle_root;

Expand All @@ -14,34 +18,45 @@ use crate::{
// 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).
// By passing in the construct hash the factory can also verify that the contract was constructed with the
// correct constructor arguments. Typically the factory would store the expect construct hash and assert that
// it is what it expects.
pub fn prove_contract_inclusion(
contract_address: AztecAddress,
portal_contract_address: EthAddress,
deployer_public_key: Point,
contract_address_salt: Field,
function_tree_root: Field,
block_number: u32, // The block at which we'll prove that the contract exists
constructor_hash: Field,
portal_contract_address: EthAddress,
block_number: u32, // The block at which we'll prove that the public value exists
context: PrivateContext
) {
) -> AztecAddress {
// 1) Get block header from oracle and ensure that the block is included in the archive.
let block_header = context.get_block_header(block_number);

// 2) Form the contract tree leaf preimage
let preimage = ContractLeafPreimage {
contract_address,
portal_contract_address,
// 2) Compute the contract address
let contract_address = CompleteAddress::compute(
deployer_public_key,
contract_address_salt,
function_tree_root,
};
constructor_hash
).address;

// 3) Get the contract tree leaf by hashing the preimage
// 3) Form the contract tree leaf preimage
let preimage = ContractLeafPreimage { contract_address, portal_contract_address, function_tree_root };

// 4) Get the contract tree leaf by hashing the preimage
let contract_leaf = preimage.hash();

// 4) Get the membership witness of the leaf in the contract tree
// 5) Get the membership witness of the leaf in the contract tree
let witness = get_contract_membership_witness(block_number, contract_leaf);

// 5) Prove that the leaf is in the contract tree
// 6) Prove that the leaf is in the contract tree
assert(
block_header.contract_tree_root == compute_merkle_root(contract_leaf, witness.index, witness.path),
"Proving contract inclusion failed"
block_header.contract_tree_root
== compute_merkle_root(contract_leaf, witness.index, witness.path), "Proving contract inclusion failed"
);

// --> Now we have traversed the trees all the way up to archive root.
}

contract_address
}
4 changes: 2 additions & 2 deletions yarn-project/aztec.js/src/contract_deployer/deploy_method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas

const { chainId, protocolVersion } = await this.pxe.getNodeInfo();

const { completeAddress, constructorHash, functionTreeRoot } = getContractDeploymentInfo(
const { completeAddress, constructorVkHash, functionTreeRoot } = getContractDeploymentInfo(
this.artifact,
this.args,
contractAddressSalt,
Expand All @@ -78,7 +78,7 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas

const contractDeploymentData = new ContractDeploymentData(
this.publicKey,
constructorHash,
constructorVkHash,
functionTreeRoot,
contractAddressSalt,
portalContract,
Expand Down
1 change: 0 additions & 1 deletion yarn-project/aztec.js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ export {
isContractDeployed,
EthCheatCodes,
computeAuthWitMessageHash,
computeContractFunctionTreeRoot,
} from './utils/index.js';

export { createPXEClient } from './pxe_client.js';
Expand Down
17 changes: 0 additions & 17 deletions yarn-project/aztec.js/src/utils/l2_contracts.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import { Fr, generateFunctionLeaves } from '@aztec/circuits.js';
import { computeFunctionTreeRoot } from '@aztec/circuits.js/abis';
import { ContractArtifact, FunctionSelector } from '@aztec/foundation/abi';
import { AztecAddress } from '@aztec/foundation/aztec-address';
import { PXE } from '@aztec/types';

Expand All @@ -13,17 +10,3 @@ import { PXE } from '@aztec/types';
export async function isContractDeployed(pxe: PXE, contractAddress: AztecAddress): Promise<boolean> {
return !!(await pxe.getContractData(contractAddress));
}

/**
* Computes the root of a function tree for a given smart contract artifact.
* @param artifact - The smart contract artifact.
* @returns The computed function tree root based on the functions in the given contract artifact.
*/
export function computeContractFunctionTreeRoot(artifact: ContractArtifact): Fr {
const functions = artifact.functions.map(f => ({
...f,
selector: FunctionSelector.fromNameAndParameters(f.name, f.parameters),
}));
const functionLeaves = generateFunctionLeaves(functions);
return computeFunctionTreeRoot(functionLeaves);
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ export function getContractDeploymentInfo(

return {
completeAddress,
constructorHash: constructorVkHash,
constructorHash,
constructorVkHash,
functionTreeRoot,
};
}
4 changes: 4 additions & 0 deletions yarn-project/circuits.js/src/types/deployment_info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ export type DeploymentInfo = {
* The complete address of the deployed contract.
*/
completeAddress: CompleteAddress;
/**
* The contract's constructor verification key hash.
*/
constructorVkHash: Fr;
/**
* The contract's constructor hash.
*/
Expand Down
73 changes: 45 additions & 28 deletions yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {
Fr,
INITIAL_L2_BLOCK_NUM,
PXE,
computeContractFunctionTreeRoot,
Point,
getContractDeploymentInfo,
} from '@aztec/aztec.js';
import { InclusionProofsContract } from '@aztec/noir-contracts/types';

Expand All @@ -29,12 +30,12 @@ describe('e2e_inclusion_proofs_contract', () => {
let contract: InclusionProofsContract;
let deploymentBlockNumber: number;
const publicValue = 236n;
let contractFunctionTreeRoot: Fr;
const contractAddressSalt = Fr.random();

beforeAll(async () => {
({ pxe, teardown, wallets, accounts } = await setup(1));

const receipt = await InclusionProofsContract.deploy(wallets[0], publicValue).send().wait();
const receipt = await InclusionProofsContract.deploy(wallets[0], publicValue).send({ contractAddressSalt }).wait();
contract = receipt.contract;
deploymentBlockNumber = receipt.blockNumber!;
}, 100_000);
Expand Down Expand Up @@ -172,31 +173,54 @@ describe('e2e_inclusion_proofs_contract', () => {
// Choose random block number between first block and current block number to test archival node
const blockNumber = await getRandomBlockNumberSinceDeployment();

const contractAddress = contract.address;
const contractArtifact = contract.artifact;

// bellow are contents of a preimage of AztecAddress
const constructorArgs = [publicValue];
const publicKey = Point.ZERO; // InclusionProofs contract doesn't have associated public key because it's not an account contract

const { constructorHash, functionTreeRoot } = getContractDeploymentInfo(
contractArtifact,
constructorArgs,
contractAddressSalt,
publicKey,
);

const portalContractAddress = contract.portalContract;
const functionTreeRoot = getContractFunctionTreeRoot();

await contract.methods
.test_contract_inclusion_proof(contractAddress, portalContractAddress, functionTreeRoot, blockNumber)
.test_contract_inclusion_proof(
publicKey,
contractAddressSalt,
functionTreeRoot,
constructorHash,
portalContractAddress,
blockNumber,
)
.send()
.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/);
});
// 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; // I will unwind contract address
// // I need to pass in:
// // 1) deployer pub key,
// // 2) contract address salt,
// // 3) function tree root, DONE
// // 4) constructor hash
// 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();
Expand All @@ -207,11 +231,4 @@ 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) {
contractFunctionTreeRoot = computeContractFunctionTreeRoot(contract.artifact);
}
return contractFunctionTreeRoot;
};
});
Loading

0 comments on commit 3485b03

Please sign in to comment.