feat(aztec-noir): align public and private execution patterns#1515
Conversation
|
Tagging @sirasistant, as this touches on some design decisions you've made in the past. |
| let returnValue = base_value + context.chain_id() + context.version() + context.block_number() + context.timestamp(); | ||
|
|
||
| context.return_values.push(returnValue); | ||
| // TODO(MADDIAA): MAYBE we put the return values inside the finish object? That could have nice UX |
There was a problem hiding this comment.
I think return_values are part of the PublicCircuitPublicInputs, although I think there are plans to instead return a return_values_hash. When that change happens, the simulator will keep track of the return_values, and the simulator could return those.
There was a problem hiding this comment.
Yeah but it's true that even if we do return_values_hash we don't need to keep them inside the context, they can instead be passed as arguments to finish() both in public and private, and when we have return_values_hash then finish(hash_returns(whatever))
LHerskind
left a comment
There was a problem hiding this comment.
Nice job. Got some minor comments.
There was a problem hiding this comment.
How come the ordering change in here? Was there a mismatch or was this to follow the structure of historic_block_data?
There was a problem hiding this comment.
Ive made a followup pr that does some reorg to prevent structuring mistakes like this: #1567.
It can be merged into this one or run as a standalone pr. It was a big change so Ive broken it up
There was a problem hiding this comment.
Is the cpp using a different formatter? Some of these files have different formats without other stuff changing.
There was a problem hiding this comment.
Yep, i think these changes came from adams commits where he was using clion as his ide
There was a problem hiding this comment.
Should the tidy not have been angry about it? 👀
There was a problem hiding this comment.
good question, im i suppose it exists within both rulesets
| common_validate_kernel_execution(builder, public_kernel_inputs); | ||
|
|
||
| // vallidate our public call hash | ||
| // valLidate our public call hash |
There was a problem hiding this comment.
| // valLidate our public call hash | |
| // validate our public call hash |
| ); | ||
|
|
||
| const argsHash = witnessReader.readField(); | ||
| const returnValues = padArrayEnd(witnessReader.readFieldArray(RETURN_VALUES_LENGTH), Fr.ZERO, RETURN_VALUES_LENGTH); |
There was a problem hiding this comment.
Do you need to pad it when reading array of length RETURN_VALUES_LENGTH? Won't you be filling RETURN_VALUES_LENGTH - RETURN_VALUES_LENGTH = 0 elements with Fr.ZERO values.
There was a problem hiding this comment.
It is there as a sanity check, i can remove
There was a problem hiding this comment.
Just seemed strange when no others had it.
|
|
||
| const returnValues = extractReturnWitness(acir, partialWitness).map(fromACVMField); | ||
| const publicInputs = extractPublicCircuitPublicInputs(partialWitness, acir); | ||
| const { returnValues } = publicInputs; |
There was a problem hiding this comment.
What is the reason you are not doing? Don't seems like you are using the publicInputs
const { returnValues } = extractPublicCircuitPublicInputs(partialWitness, acir);
There was a problem hiding this comment.
The use of the public inputs is dependant on some ongoing discussions around how we will handle context in the vm setting. I am unsure if we will use the publicInputs further. When i started the work I was under the impression that I was going to. I will update
| dep::std::hash::pedersen_with_separator(self.serialize(), GENERATOR_INDEX__PUBLIC_DATA_READ)[0] | ||
| } | ||
|
|
||
| fn empty() -> Self { |
There was a problem hiding this comment.
Do we need empty_contract_storage_read() if we have empty here, seems like we should use the empty instead for clarity.
In call_public_function_with_packed_args in the context we populate contract_storage_read with the empty ones.
|
|
||
| fn empty_block_data() -> HistoricBlockData { | ||
| HistoricBlockData{ private_data_tree_root: 0, nullifier_tree_root: 0, contract_tree_root: 0, l1_to_l2_messages_tree_root: 0, blocks_tree_root: 0, prev_global_variables_hash: 0, public_data_tree_root: 0 } | ||
| HistoricBlockData{ private_data_tree_root: 0, nullifier_tree_root: 0, contract_tree_root: 0, l1_to_l2_messages_tree_root: 0, blocks_tree_root: 0, public_data_tree_root: 0, global_variables_hash: 0 } |
There was a problem hiding this comment.
I think we should replace this with an HistoricBlockData::empty() instead? Seems better for consistency. Only used in context.call_public_function_with_packed_args.
| } | ||
| } | ||
|
|
||
| fn empty_contract_storage_update_request() -> ContractStorageUpdateRequest { |
There was a problem hiding this comment.
My brain want us to use ContractStorageUpdateRequest::empty() where this was used and get rid of this one.
| prover_address: Field, | ||
|
|
||
|
|
||
| // TODO: include globals in here and check them elsewhere |
There was a problem hiding this comment.
Will you do this as part of this pr or create an issue for it?
There was a problem hiding this comment.
Lets create an issue, it is out of scope
edit: #1567
| const unencryptedLogPreimagesLength = new Fr(result.unencryptedLogs.getSerializedLength()); | ||
|
|
||
| return PublicCircuitPublicInputs.from({ | ||
| const pub = PublicCircuitPublicInputs.from({ |
There was a problem hiding this comment.
Seems like you printed pub for debugging, but as not done anymore, you might as well return it directly here 👍.
| open fn mint( | ||
| _inputs: PublicContextInputs, | ||
| inputs: PublicContextInputs, | ||
| amount: Field, | ||
| recipient: Field, | ||
| ) -> pub Field { | ||
| ) -> pub abi::PublicCircuitPublicInputs { | ||
| let mut context = PublicContext::new(inputs, abi::hash_args([amount, recipient])); | ||
|
|
||
| let storage = Storage::init(); | ||
| let recipient_balance = storage.balances.at(recipient); | ||
| let new_amount = recipient_balance.read() + amount; | ||
| // TODO: Remove return value. | ||
| let _hash = emit_unencrypted_log("Coins minted"); | ||
| recipient_balance.write(new_amount); | ||
| new_amount | ||
|
|
||
| context.return_values.push(new_amount); | ||
|
|
||
| context.finish() | ||
| } |
There was a problem hiding this comment.
Highlighting this diff, so I can link to it elsewhere, for a discussion.
…ts (#1571) Add a bit more consistency across the code base, I came into these issues when working on #1515. Running this in a separate pr as it is not directly related. And to minimise the diff between the two ## Overview Replaces 6 seperate roots with one single data structure that is used literally everywhere else
Metadata
fixes
Relevant discussions
PrivateContextInputsas a required parameter to a private noir contract function #1358 (comment)Overview
This PR aims to align the implementations of Public and Private state.
Other work I am thinking of completing within this PR
Right now,
PublicCircuitPublicInputs(The object which is fed to the public kernel after circuit completion) is not created within the application circuit. It is created within the sequencer. If we zoom out, this is not a direct security concern as execution is occuring within the sequencer, however it does break away from the pattern seen withinPrivateExecutionwhere the result of each execution is thePrivateCircuitPublicInputsobject.We could leave this as is, (alot of this code will be dumped when the vm arrives). However similar code paths will make building the library easier. For example, for some library methods we have two implementations, one for public and one for private. More and more standardisation would allow these methods to take in a generic context and utilise the same code paths. (A goal I think is worth pursuing).
Checklist:
Remove the checklist to signal you've completed it. Enable auto-merge if the PR is ready to merge.