Skip to content

Commit

Permalink
broken messed up WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan committed Dec 14, 2023
1 parent 4698f78 commit 0fc3cf5
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 87 deletions.
56 changes: 43 additions & 13 deletions yarn-project/aztec-nr/aztec/src/history/contract_inclusion.nr
Original file line number Diff line number Diff line change
@@ -1,35 +1,63 @@
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,
hash::compute_partial_address,
};
use dep::std::merkle::compute_merkle_root;

use crate::{
context::PrivateContext,
oracle::get_membership_witness::get_contract_membership_witness,
oracle::debug_log::debug_log_format,
};

// 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).
// 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,
let partial_address = compute_partial_address(contract_address_salt, function_tree_root, constructor_hash);
debug_log_format("partial_address: {0}", [partial_address]);

// 2) Compute the contract address
let complete_contract_address = CompleteAddress::compute(
deployer_public_key,
contract_address_salt,
function_tree_root,
};
constructor_hash
);

let contract_address = complete_contract_address.address;

debug_log_format(
"deployer_pubKey .x: {0} .y: {1}, salt: {2}, function_tree_root: {3}, constructor_hash: {4}, contract address: {5}, partial_address: {6}",
[
deployer_public_key.x, deployer_public_key.y, contract_address_salt, function_tree_root, constructor_hash, contract_address.to_field(),
complete_contract_address.partial_address
]
);

// 2) Form the contract tree leaf preimage
let preimage = ContractLeafPreimage { contract_address, portal_contract_address, function_tree_root };

// 3) Get the contract tree leaf by hashing the preimage
let contract_leaf = preimage.hash();
Expand All @@ -39,9 +67,11 @@ pub fn prove_contract_inclusion(

// 5) 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
}
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);
}
5 changes: 4 additions & 1 deletion yarn-project/circuits.js/src/abis/abis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ export function computeCompleteAddress(
constructorHash: Fr,
): CompleteAddress {
const partialAddress = computePartialAddress(contractAddrSalt, fnTreeRoot, constructorHash);
// console.log(
// `salt: ${contractAddrSalt.toString()}, function_tree_root: ${fnTreeRoot.toString()}, constructor_hash: ${constructorHash.toString()}, partial_address ${partialAddress.toString()}`,
// );
return new CompleteAddress(
computeContractAddressFromPartial(deployerPubKey, partialAddress),
deployerPubKey,
Expand All @@ -192,7 +195,7 @@ export function computeCompleteAddress(
/**
*
*/
function computePartialAddress(contractAddrSalt: Fr, fnTreeRoot: Fr, constructorHash: Fr) {
export function computePartialAddress(contractAddrSalt: Fr, fnTreeRoot: Fr, constructorHash: Fr) {
return Fr.fromBuffer(
pedersenHash(
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export function getContractDeploymentInfo(

return {
completeAddress,
constructorHash: constructorVkHash,
constructorHash: constructorVkHash, // !!!!!!!!!!!!!
functionTreeRoot,
};
}
88 changes: 59 additions & 29 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,8 +5,10 @@ import {
Fr,
INITIAL_L2_BLOCK_NUM,
PXE,
computeContractFunctionTreeRoot,
Point,
getContractDeploymentInfo,
} from '@aztec/aztec.js';
import { computePartialAddress } from '@aztec/circuits.js/abis';
import { InclusionProofsContract } from '@aztec/noir-contracts/types';

import { jest } from '@jest/globals';
Expand All @@ -29,12 +31,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 @@ -168,35 +170,70 @@ describe('e2e_inclusion_proofs_contract', () => {
).rejects.toThrow(/Low nullifier witness not found for nullifier 0x[0-9a-fA-F]+ at block/);
});

it('proves existence of a contract', async () => {
it.only('proves existence of a contract', async () => {
// 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

console.log("+++++++++++++++++++++++++++++++++++++")
const deploymentData = getContractDeploymentInfo(contractArtifact, constructorArgs, contractAddressSalt, publicKey);

// console.log(
// `deployer_pubKey .x: ${publicKey.x.toString()} .y: ${publicKey.y.toString()}, salt: ${contractAddressSalt.toString()}, function_tree_root: ${deploymentData.functionTreeRoot.toString()}, constructor_hash: ${deploymentData.constructorHash.toString()}, contract address: ${contract.address.toString()}, partial_address ${deploymentData.completeAddress.partialAddress.toString()}`,
// );

const constructorHash = deploymentData.constructorHash;

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

console.log("computePartialAddress, constructorHash", constructorHash.toString());
const partialAddress = computePartialAddress(contractAddressSalt, functionTreeRoot, constructorHash);

// console.log(`salt: ${contractAddressSalt.toString()}, function_tree_root: ${deploymentData.functionTreeRoot.toString()}, constructor_hash: ${constructorHash.toString()}, partial_address: ${partialAddress.toString()}`);

if (!partialAddress.equals(deploymentData.completeAddress.partialAddress)) {
throw new Error('Partial address mismatch');
}

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 +244,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 0fc3cf5

Please sign in to comment.