See here for the latest contract creation proposal from Zac.
Just opening up a discussion thread on this topic.
See here for the latest contract creation proposal from Zac.
Just opening up a discussion thread on this topic.
From the hackmd:
Function Tree
Each contractâs function data is stored in a Merkle tree, where each leaf contains a hash of the following data:
- Function Signature
bool isPrivate
flag- Verification Key Hash
Where the âfunction signatureâ in this context would be something like the first 4 bytes of the hash of the abi encoding of the function.
This is a nice leaf, because we get the following:
*Just a small note: at the time of deployment, we MUST ensure each function signature is unique, within the contract. Similarly, we must also ensure uniqueness of verification key hashes.
Question: Is the contract tree a sparse merkle tree as well as the public state tree? Or are the contract leaves on the public state tree?
Also, a note on the function signature. Is it a hard requirement that function selectors be 4 bytes? ABI compatibility with Solidity is already broken by using different underlying primitive types and function selector derivation. Because of this, I would advocate for a larger function selector size, ideally no less than 8 bytes. This is useful to reduce the odds of function selector collision within a single contract as well as reducing selector ambiguity in client-side tooling.
I believe the contract tree will not be sparse. It will be a standard merkle tree and will be append-only.
It is declared as such in code here
No hard requirement on function selector size. You make a good point and we will likely choose >4 bytes for this exact reason
There should come more info in here Trees | Aztec Docs, but the contracts tree is not a sparse tree. As @david-banks says, its an append-only tree to allow us to easily do batch insertions.
There have been some discussions on function selector lengths earlier; the main thoughts were around 8 bytes and longer. I think the main reason that it was not changed already was just that no one made the PR fixing the length everywhere, as it was discussed when everything was in different repos instead of mono.
I have a question: In doc tree, it says:
The contract tree contains information about every function of every contract deployed to the Aztec network. This allows the Kernel Circuits to validate that for every function execution request, the requested function actually belongs to a deployed contract.
How exactly does the Kernel Circuits to validate one function belongs to one deployed contract? IIUC, one circuit(pk/vk) for one function, how does contract work in this situation?
For reference, this kernel logic lives here in the common_contract_logic
function which is called from both the initial and inner variations of the private kernel.
There are two relevant trees here:
When a user executes a private function, they will provide its proof of execution to the private kernel along with the some information about the function and contract they are calling:
function_selector
, vk_hash
, acir_hash
leaf_index
, sibling_path
storage_contract_address
, portal_contract_address
leaf_index
, sibling_path
We basically want to ensure the following:
So how do we do this?
First off, we can verify the function proof using snark recursion and the VK provided as a private input the kernel. We compute a function tree leaf given the function_selector
, vk_hash
(computed in-circuit from the VK), and acir_hash
. We can then use the provided leaf_index
and sibling_path
to compute the merkle root (function_tree_root
) of this contractâs function tree.
Cool so now we have a function_tree_root
, but how do we know itâs right? Well next we can compute a contract tree leaf using this function_tree_root
along with contract address and portal address. We then use the provided leaf_index
and sibling_path
to compute the merkle root (contract_tree_root
) of the contract tree.
Okay so now we have a contract_tree_root
, but how do we know itâs right? Well we donât⌠Not at this stage. The private kernel proves the numbered items above with an important exception; someone else needs to prove that this contract tree root matches a real historical root. That is the job of the rollup circuits.
By this point we know that the function and its vk matches a leaf in the contractâs function tree. We know that the functionâs execution is valid according to that vk. And we know that the contract along with the root of this function tree match a leaf in some contract tree. We then put off the job of verifying that contract tree root until a later stage.
TLDR: A contract is basically a function tree (including VKs) along with an address that is used to silo storage accesses. We validate that a function belongs to a deployed contract by doing merkle membership proofs for the function in the contractâs function tree, and the contract in the contract tree.
Thanks for detailed reply, it makes much sense! Is acir_hash
a commitment of deployed bytecode for function/contract?
Thatâs right! Iâm not sure if it needs to be calculated in-circuit for private functions. We will need to perform some bytecode validation for public functions though since Sequencers and Provers are responsible for executing public function bytecode. @Mike may be able to provide some more insight here.