diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic-simulated/src/main.nr index 8bcc9f1643f..1993752060a 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic-simulated/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic-simulated/src/main.nr @@ -2,5 +2,5 @@ use dep::public_kernel_lib::PublicKernelAppLogicCircuitPrivateInputs; use dep::types::PublicKernelCircuitPublicInputs; unconstrained fn main(input: PublicKernelAppLogicCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { - input.public_kernel_app_logic() + input.execute() } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic/src/main.nr index e327d6c051f..8f63370cc4b 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic/src/main.nr @@ -3,5 +3,5 @@ use dep::types::PublicKernelCircuitPublicInputs; #[recursive] fn main(input: PublicKernelAppLogicCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { - input.public_kernel_app_logic() + input.execute() } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr deleted file mode 100644 index 7f1a9f3d1b6..00000000000 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr +++ /dev/null @@ -1,554 +0,0 @@ -use dep::types::{ - abis::{ - public_call_stack_item::PublicCallStackItem, - kernel_circuit_public_inputs::PublicKernelCircuitPublicInputsBuilder, - public_kernel_data::PublicKernelData, note_hash::ScopedNoteHash, nullifier::Nullifier, - public_call_data::PublicCallData, public_call_request::PublicCallRequest, - public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - log_hash::{ScopedLogHash, LogHash}, global_variables::GlobalVariables, - combined_constant_data::CombinedConstantData -}, - address::AztecAddress, - contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, - messaging::l2_to_l1_message::ScopedL2ToL1Message, - constants::{ - MAX_L2_TO_L1_MSGS_PER_CALL, MAX_NOTE_HASHES_PER_CALL, MAX_NULLIFIERS_PER_CALL, - MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, - MAX_PUBLIC_DATA_READS_PER_CALL, MAX_UNENCRYPTED_LOGS_PER_CALL -}, - hash::{compute_siloed_nullifier, compute_l2_to_l1_hash}, - utils::{arrays::{array_length, array_to_bounded_vec}}, traits::{is_empty, is_empty_array} -}; - -// Validates inputs to the kernel circuit that are common to all invocation scenarios. -pub fn validate_inputs(public_call: PublicCallData) { - // Validates commons inputs for all type of kernel inputs - let this_call_stack_item: PublicCallStackItem = public_call.call_stack_item; - assert( - !this_call_stack_item.contract_address.eq(AztecAddress::zero()), "Contract address cannot be zero" - ); - assert(this_call_stack_item.function_data.selector.to_field() != 0, "Function signature cannot be zero"); - assert( - this_call_stack_item.function_data.is_private == false, "Cannot execute a private function with the public kernel circuit" - ); - assert_eq( - this_call_stack_item.function_data.selector, this_call_stack_item.public_inputs.call_context.function_selector, "function selector in call context does not match call stack item" - ); - assert(public_call.bytecode_hash != 0, "Bytecode hash cannot be zero"); -} - -pub fn validate_public_call_global_variables(public_call: PublicCallData, constants: CombinedConstantData) { - let public_call_globals = public_call.call_stack_item.public_inputs.global_variables; - assert( - public_call_globals == constants.global_variables, "Global variables injected into the public call do not match constants" - ); -} - -// Validates constants injected into the public call are correct. -// Note that the previous_kernel.public_inputs.constants returned from the private kernel tail -// will be empty, so in the first run on of this circuit we load them from the first public -// call, following the same pattern as in the private_kernel_init. -// TODO(@spalladino): This can be a security risk since it allows a sequencer to run public -// circuits with empty global variables. This must be patched by having a differentiated init public -// circuit that runs only once, or by having a way to differentiate when we're coming from a private -// kernel tail vs from another public run. -pub fn initialize_from_or_validate_public_call_variables( - previous_kernel: PublicKernelData, - public_call: PublicCallData, - public_inputs: &mut PublicKernelCircuitPublicInputsBuilder -) { - if public_inputs.constants.global_variables.is_empty() { - let public_call_global_variables = public_call.call_stack_item.public_inputs.global_variables; - public_inputs.constants.global_variables = public_call_global_variables; - } else { - validate_public_call_global_variables(public_call, previous_kernel.public_inputs.constants); - } -} - -pub fn validate_public_call_non_revert(public_call: PublicCallData) { - assert(public_call.call_stack_item.public_inputs.revert_code == 0, "Public call cannot be reverted"); -} - -pub fn initialize_end_values( - previous_kernel: PublicKernelData, - circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder -) { - let start = previous_kernel.public_inputs.end; - circuit_outputs.end.note_hashes = array_to_bounded_vec(start.note_hashes); - circuit_outputs.end.nullifiers = array_to_bounded_vec(start.nullifiers); - circuit_outputs.end.l2_to_l1_msgs = array_to_bounded_vec(start.l2_to_l1_msgs); - circuit_outputs.end.public_data_update_requests = array_to_bounded_vec(start.public_data_update_requests); - circuit_outputs.end.unencrypted_logs_hashes = array_to_bounded_vec(start.unencrypted_logs_hashes); - circuit_outputs.end.note_encrypted_logs_hashes = array_to_bounded_vec(start.note_encrypted_logs_hashes); - circuit_outputs.end.encrypted_logs_hashes = array_to_bounded_vec(start.encrypted_logs_hashes); - circuit_outputs.end.public_call_stack = array_to_bounded_vec(start.public_call_stack); -} - -// Initialises the circuit outputs with the end state of the previous iteration. -// Includes data that will be checked and cleared in the tail circuit. -pub fn initialize_non_revertible_values( - previous_kernel: PublicKernelData, - circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder -) { - circuit_outputs.constants = previous_kernel.public_inputs.constants; - circuit_outputs.fee_payer = previous_kernel.public_inputs.fee_payer; - - // Copy gas-used as-is. Gas used in this iteration will be deducted later in update_(non)_revertible_gas_used. - circuit_outputs.end.gas_used = previous_kernel.public_inputs.end.gas_used; - circuit_outputs.end_non_revertible.gas_used = previous_kernel.public_inputs.end_non_revertible.gas_used; - - let start_non_revertible = previous_kernel.public_inputs.end_non_revertible; - circuit_outputs.end_non_revertible.note_hashes = array_to_bounded_vec(start_non_revertible.note_hashes); - circuit_outputs.end_non_revertible.nullifiers = array_to_bounded_vec(start_non_revertible.nullifiers); - circuit_outputs.end_non_revertible.l2_to_l1_msgs = array_to_bounded_vec(start_non_revertible.l2_to_l1_msgs); - circuit_outputs.end_non_revertible.public_data_update_requests = array_to_bounded_vec(start_non_revertible.public_data_update_requests); - circuit_outputs.end_non_revertible.unencrypted_logs_hashes = array_to_bounded_vec(start_non_revertible.unencrypted_logs_hashes); - circuit_outputs.end_non_revertible.note_encrypted_logs_hashes = array_to_bounded_vec(start_non_revertible.note_encrypted_logs_hashes); - circuit_outputs.end_non_revertible.encrypted_logs_hashes = array_to_bounded_vec(start_non_revertible.encrypted_logs_hashes); - circuit_outputs.end_non_revertible.public_call_stack = array_to_bounded_vec(start_non_revertible.public_call_stack); - - let start = previous_kernel.public_inputs.validation_requests; - circuit_outputs.validation_requests.max_block_number = start.for_rollup.max_block_number; - circuit_outputs.validation_requests.nullifier_read_requests = array_to_bounded_vec(start.nullifier_read_requests); - circuit_outputs.validation_requests.nullifier_non_existent_read_requests = array_to_bounded_vec(start.nullifier_non_existent_read_requests); - circuit_outputs.validation_requests.public_data_reads = array_to_bounded_vec(start.public_data_reads); -} - -fn perform_static_call_checks(public_call: PublicCallData) { - let public_inputs = public_call.call_stack_item.public_inputs; - if public_inputs.call_context.is_static_call { - // No state changes are allowed for static calls: - let note_hashes_length = array_length(public_inputs.note_hashes); - assert(note_hashes_length == 0, "note_hashes must be empty for static calls"); - - let nullifiers_length = array_length(public_inputs.nullifiers); - assert(nullifiers_length == 0, "nullifiers must be empty for static calls"); - - let update_requests_length = array_length(public_inputs.contract_storage_update_requests); - assert( - update_requests_length == 0, "No contract storage update requests are allowed for static calls" - ); - - let l2_to_l1_msgs_length = array_length(public_inputs.l2_to_l1_msgs); - assert(l2_to_l1_msgs_length == 0, "l2_to_l1_msgs must be empty for static calls"); - - let new_unencrypted_logs_length = array_length(public_inputs.unencrypted_logs_hashes); - assert(new_unencrypted_logs_length == 0, "No unencrypted logs are allowed for static calls"); - } -} - -fn validate_call_context(request: PublicCallRequest, public_call: PublicCallData) { - let target_context = request.item.call_context; - let target_contract = request.item.contract_address; - let this_context = public_call.call_stack_item.public_inputs.call_context; - - if target_context.is_delegate_call { - assert_eq( - target_context.msg_sender, this_context.msg_sender, "incorrect msg_sender for delegate call request" - ); - assert_eq( - target_context.storage_contract_address, this_context.storage_contract_address, "incorrect storage_contract_address for delegate call request" - ); - } else { - assert_eq( - target_context.msg_sender, this_context.storage_contract_address, "incorrect msg_sender for call request" - ); - assert_eq( - target_context.storage_contract_address, target_contract, "incorrect storage_contract_address for call request" - ); - } - if !target_context.is_static_call { - assert(this_context.is_static_call == false, "static call cannot make non-static calls"); - } -} - -pub fn update_end_non_revertible_call_stack( - public_call: PublicCallData, - circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder -) { - let requests = validate_public_call_stack(public_call); - circuit_outputs.end_non_revertible.public_call_stack.extend_from_bounded_vec(requests); -} - -pub fn update_end_call_stack( - public_call: PublicCallData, - circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder -) { - let requests = validate_public_call_stack(public_call); - circuit_outputs.end.public_call_stack.extend_from_bounded_vec(requests); -} - -pub fn update_teardown_call_stack(public_call: PublicCallData, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder) { - let requests = validate_public_call_stack(public_call); - circuit_outputs.public_teardown_call_stack.extend_from_bounded_vec(requests); -} - -fn validate_public_call_stack(public_call: PublicCallData) -> BoundedVec { - let public_call_requests = public_call.call_stack_item.public_inputs.public_call_requests; - for i in 0..public_call_requests.len() { - let request = public_call_requests[i]; - if !request.item.contract_address.is_zero() { - validate_call_context(request, public_call); - } - } - array_to_bounded_vec(public_call_requests) -} - -pub fn update_validation_requests(public_call: PublicCallData, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder) { - // Note that the public kernel cannot modify the max block number value - it simply forwards it to the rollup - propagate_nullifier_read_requests(public_call, circuit_outputs); - propagate_nullifier_non_existent_read_requests(public_call, circuit_outputs); - propagate_valid_public_data_reads(public_call, circuit_outputs); -} - -pub fn update_revertible_gas_used(public_call: PublicCallData, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder) { - let tx_gas_limits = circuit_outputs.constants.tx_context.gas_settings.gas_limits; - let call_gas_left = public_call.call_stack_item.public_inputs.end_gas_left; - let accum_end_non_revertible_gas_used = circuit_outputs.end_non_revertible.gas_used; - - // dep::types::debug_log::debug_log_format( - // "Updating revertible gas: limit.da={0} limit.l1={1} limit.l2={2} left.da={3} left.l1={4} left.l2={5} used.da={6} used.l1={7} used.l2={8}", - // [ - // tx_gas_limits.da_gas as Field, - // tx_gas_limits.l2_gas as Field, - // call_gas_left.da_gas as Field, - // call_gas_left.l2_gas as Field, - // accum_end_non_revertible_gas_used.da_gas as Field, - // accum_end_non_revertible_gas_used.l2_gas as Field - // ] - // ); - - // println( - // f"Updating revertible gas: tx_gas_limits={tx_gas_limits} call_gas_left={call_gas_left} accum_end_non_revertible_gas_used={accum_end_non_revertible_gas_used}" - // ); - - circuit_outputs.end.gas_used = tx_gas_limits - .sub(call_gas_left) - .sub(accum_end_non_revertible_gas_used); -} - -pub fn update_non_revertible_gas_used(public_call: PublicCallData, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder) { - let tx_gas_limits = circuit_outputs.constants.tx_context.gas_settings.gas_limits; - let call_gas_left = public_call.call_stack_item.public_inputs.end_gas_left; - let accum_end_gas_used = circuit_outputs.end.gas_used; - - // dep::types::debug_log::debug_log_format( - // "Updating non-revertible gas: limit.da={0} limit.l2={1} left.da={2} left.l2={3} used.da={4} used.l2={5}", - // [ - // tx_gas_limits.da_gas as Field, - // tx_gas_limits.l2_gas as Field, - // call_gas_left.da_gas as Field, - // call_gas_left.l2_gas as Field, - // accum_end_gas_used.da_gas as Field, - // accum_end_gas_used.l2_gas as Field - // ] - // ); - - circuit_outputs.end_non_revertible.gas_used = tx_gas_limits - .sub(call_gas_left) - .sub(accum_end_gas_used); -} - -// Validates that the start gas injected into the app circuit matches the remaining gas -pub fn validate_start_gas(public_call: PublicCallData, previous_kernel: PublicKernelData) { - // If this is a nested call (not an execution request), the start gas is correct as long as the - // call being processed by this kernel iteration matches the call at the top of the callstack - // as per the previous kernel's outputs. - // An execution request's start gas is the remaining gas left in the transaction after the previous kernel. - // A nested call's start gas is the gas allocated to it by its caller and placed in the callstack. - if (public_call.call_stack_item.is_execution_request) { - let public_call_start_gas = public_call.call_stack_item.public_inputs.start_gas_left; - let tx_gas_limits = previous_kernel.public_inputs.constants.tx_context.gas_settings.gas_limits; - let computed_start_gas = tx_gas_limits.sub(previous_kernel.public_inputs.end.gas_used).sub(previous_kernel.public_inputs.end_non_revertible.gas_used); - assert( - public_call_start_gas == computed_start_gas, "Start gas for public phase does not match transaction gas left" - ); - } -} - -// Validates the transaction fee injected into the app circuit is zero for non-teardown phases -pub fn validate_transaction_fee_is_zero(public_call: PublicCallData) { - let transaction_fee = public_call.call_stack_item.public_inputs.transaction_fee; - assert(transaction_fee == 0, "Transaction fee must be zero on setup and app phases"); -} - -pub fn update_public_end_non_revertible_values( - public_call: PublicCallData, - circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder -) { - // Updates the circuit outputs with new state changes - - // If this call is a static call, certain operations are disallowed, such as creating new state. - perform_static_call_checks(public_call); - - propagate_nullifiers_non_revertible(public_call, circuit_outputs); - propagate_note_hashes_non_revertible(public_call, circuit_outputs); - propagate_new_l2_to_l1_messages_non_revertible(public_call, circuit_outputs); - propagate_new_unencrypted_logs_non_revertible(public_call, circuit_outputs); - propagate_valid_non_revertible_public_data_update_requests(public_call, circuit_outputs); -} - -pub fn update_public_end_values(public_call: PublicCallData, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder) { - // Updates the circuit outputs with new state changes - - // If this call is a static call, certain operations are disallowed, such as creating new state. - perform_static_call_checks(public_call); - - propagate_nullifiers(public_call, circuit_outputs); - propagate_note_hashes(public_call, circuit_outputs); - propagate_new_l2_to_l1_messages(public_call, circuit_outputs); - propagate_new_unencrypted_logs(public_call, circuit_outputs); - propagate_valid_public_data_update_requests(public_call, circuit_outputs); -} - -fn propagate_nullifier_read_requests( - public_call: PublicCallData, - circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder -) { - let public_call_public_inputs = public_call.call_stack_item.public_inputs; - let nullifier_read_requests = public_call_public_inputs.nullifier_read_requests; - let storage_contract_address = public_call_public_inputs.call_context.storage_contract_address; - - for i in 0..MAX_NULLIFIER_READ_REQUESTS_PER_CALL { - let request = nullifier_read_requests[i]; - if !is_empty(request) { - circuit_outputs.validation_requests.nullifier_read_requests.push(request.scope(storage_contract_address)); - } - } -} - -fn propagate_nullifier_non_existent_read_requests( - public_call: PublicCallData, - circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder -) { - let public_call_public_inputs = public_call.call_stack_item.public_inputs; - let nullifier_non_existent_read_requests = public_call_public_inputs.nullifier_non_existent_read_requests; - let storage_contract_address = public_call_public_inputs.call_context.storage_contract_address; - - for i in 0..MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL { - let request = nullifier_non_existent_read_requests[i]; - if !is_empty(request) { - circuit_outputs.validation_requests.nullifier_non_existent_read_requests.push(request.scope(storage_contract_address)); - } - } -} - -fn propagate_valid_public_data_update_requests( - public_call: PublicCallData, - circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder -) { - let contract_address = public_call.call_stack_item.public_inputs.call_context.storage_contract_address; - let update_requests = public_call.call_stack_item.public_inputs.contract_storage_update_requests; - - let mut public_data_update_requests : BoundedVec = BoundedVec::new(); - - for i in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL { - let update_request = update_requests[i]; - if (!update_request.is_empty()) { - let public_data_update_request = PublicDataUpdateRequest::from_contract_storage_update_request(contract_address, update_request); - public_data_update_requests.push(public_data_update_request); - } - } - circuit_outputs.end.public_data_update_requests.extend_from_bounded_vec(public_data_update_requests); -} - -fn propagate_valid_non_revertible_public_data_update_requests( - public_call: PublicCallData, - circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder -) { - let contract_address = public_call.call_stack_item.contract_address; - let update_requests = public_call.call_stack_item.public_inputs.contract_storage_update_requests; - - let mut public_data_update_requests : BoundedVec = BoundedVec::new(); - - for i in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL { - let update_request = update_requests[i]; - if (!update_request.is_empty()) { - let public_data_update_request = PublicDataUpdateRequest::from_contract_storage_update_request(contract_address, update_request); - - public_data_update_requests.push(public_data_update_request); - } - } - circuit_outputs.end_non_revertible.public_data_update_requests.extend_from_bounded_vec(public_data_update_requests); -} - -fn propagate_valid_public_data_reads(public_call: PublicCallData, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder) { - let contract_address = public_call.call_stack_item.public_inputs.call_context.storage_contract_address; - let read_requests = public_call.call_stack_item.public_inputs.contract_storage_reads; - - let mut public_data_reads : BoundedVec = BoundedVec::new(); - - for i in 0..MAX_PUBLIC_DATA_READS_PER_CALL { - let read_request: StorageRead = read_requests[i]; - if !read_request.is_empty() { - let public_data_read = PublicDataRead::from_contract_storage_read(contract_address, read_request); - public_data_reads.push(public_data_read); - } - } - circuit_outputs.validation_requests.public_data_reads.extend_from_bounded_vec(public_data_reads); -} - -fn propagate_note_hashes_non_revertible( - public_call: PublicCallData, - circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder -) { - let public_call_public_inputs = public_call.call_stack_item.public_inputs; - - let note_hashes = public_call.call_stack_item.public_inputs.note_hashes; - let storage_contract_address = public_call_public_inputs.call_context.storage_contract_address; - - let mut scoped_note_hashes : BoundedVec = BoundedVec::new(); - for i in 0..MAX_NOTE_HASHES_PER_CALL { - let note_hash = note_hashes[i]; - if note_hash.value != 0 { - scoped_note_hashes.push(note_hash.scope(storage_contract_address)); - } - } - circuit_outputs.end_non_revertible.note_hashes.extend_from_bounded_vec(scoped_note_hashes); -} - -fn propagate_note_hashes(public_call: PublicCallData, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder) { - let public_call_public_inputs = public_call.call_stack_item.public_inputs; - - let note_hashes = public_call.call_stack_item.public_inputs.note_hashes; - let storage_contract_address = public_call_public_inputs.call_context.storage_contract_address; - - let mut scoped_note_hashes : BoundedVec = BoundedVec::new(); - for i in 0..MAX_NOTE_HASHES_PER_CALL { - let note_hash = note_hashes[i]; - if note_hash.value != 0 { - scoped_note_hashes.push(note_hash.scope(storage_contract_address)); - } - } - circuit_outputs.end.note_hashes.extend_from_bounded_vec(scoped_note_hashes); -} - -fn propagate_nullifiers_non_revertible(public_call: PublicCallData, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder) { - let nullifiers = public_call.call_stack_item.public_inputs.nullifiers; - let storage_contract_address = public_call.call_stack_item.public_inputs.call_context.storage_contract_address; - - // Enhance commitments and nullifiers with domain separation whereby domain is the contract. - let mut siloed_nullifiers : BoundedVec = BoundedVec::new(); - for i in 0..MAX_NULLIFIERS_PER_CALL { - let new_nullifier = nullifiers[i].value; - if new_nullifier != 0 { - let siloed_new_nullifier = compute_siloed_nullifier(storage_contract_address, new_nullifier); - siloed_nullifiers.push( - Nullifier { value: siloed_new_nullifier, counter: nullifiers[i].counter, note_hash: nullifiers[i].note_hash } - ); - } - } - - circuit_outputs.end_non_revertible.nullifiers.extend_from_bounded_vec(siloed_nullifiers); -} - -fn propagate_nullifiers(public_call: PublicCallData, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder) { - let nullifiers = public_call.call_stack_item.public_inputs.nullifiers; - let storage_contract_address = public_call.call_stack_item.public_inputs.call_context.storage_contract_address; - - // Enhance commitments and nullifiers with domain separation whereby domain is the contract. - let mut siloed_nullifiers : BoundedVec = BoundedVec::new(); - for i in 0..MAX_NULLIFIERS_PER_CALL { - let new_nullifier = nullifiers[i].value; - if new_nullifier != 0 { - let siloed_new_nullifier = compute_siloed_nullifier(storage_contract_address, new_nullifier); - siloed_nullifiers.push( - Nullifier { value: siloed_new_nullifier, counter: nullifiers[i].counter, note_hash: nullifiers[i].note_hash } - ); - } - } - - circuit_outputs.end.nullifiers.extend_from_bounded_vec(siloed_nullifiers); -} - -fn propagate_new_l2_to_l1_messages_non_revertible( - public_call: PublicCallData, - public_inputs: &mut PublicKernelCircuitPublicInputsBuilder -) { - // new l2 to l1 messages - let public_call_public_inputs = public_call.call_stack_item.public_inputs; - let storage_contract_address = public_call_public_inputs.call_context.storage_contract_address; - - let l2_to_l1_msgs = public_call_public_inputs.l2_to_l1_msgs; - let mut l2_to_l1_msgs_to_insert : BoundedVec = BoundedVec::new(); - for i in 0..MAX_L2_TO_L1_MSGS_PER_CALL { - let msg = l2_to_l1_msgs[i]; - if !is_empty(msg) { - l2_to_l1_msgs_to_insert.push(msg.scope(storage_contract_address)); - } - } - public_inputs.end_non_revertible.l2_to_l1_msgs.extend_from_bounded_vec(l2_to_l1_msgs_to_insert); -} - -fn propagate_new_l2_to_l1_messages(public_call: PublicCallData, public_inputs: &mut PublicKernelCircuitPublicInputsBuilder) { - // new l2 to l1 messages - let public_call_public_inputs = public_call.call_stack_item.public_inputs; - let storage_contract_address = public_call_public_inputs.call_context.storage_contract_address; - - let l2_to_l1_msgs = public_call_public_inputs.l2_to_l1_msgs; - let mut l2_to_l1_msgs_to_insert : BoundedVec = BoundedVec::new(); - for i in 0..MAX_L2_TO_L1_MSGS_PER_CALL { - let msg = l2_to_l1_msgs[i]; - if !is_empty(msg) { - l2_to_l1_msgs_to_insert.push(msg.scope(storage_contract_address)); - } - } - public_inputs.end.l2_to_l1_msgs.extend_from_bounded_vec(l2_to_l1_msgs_to_insert); -} - -pub fn propagate_new_unencrypted_logs(public_call: PublicCallData, public_inputs: &mut PublicKernelCircuitPublicInputsBuilder) { - // new unencrypted logs - let new_logs = public_call.call_stack_item.public_inputs.unencrypted_logs_hashes; - let storage_contract_address = public_call.call_stack_item.public_inputs.call_context.storage_contract_address; - let mut new_logs_to_insert : BoundedVec = BoundedVec::new(); - for i in 0..MAX_UNENCRYPTED_LOGS_PER_CALL { - let new_log = new_logs[i]; - if new_log.value != 0 { - new_logs_to_insert.push(ScopedLogHash { log_hash: new_log, contract_address: storage_contract_address }); - } - } - public_inputs.end.unencrypted_logs_hashes.extend_from_bounded_vec(new_logs_to_insert); -} - -pub fn propagate_new_unencrypted_logs_non_revertible( - public_call: PublicCallData, - public_inputs: &mut PublicKernelCircuitPublicInputsBuilder -) { - // new unencrypted logs - let new_logs = public_call.call_stack_item.public_inputs.unencrypted_logs_hashes; - let storage_contract_address = public_call.call_stack_item.public_inputs.call_context.storage_contract_address; - let mut new_logs_to_insert : BoundedVec = BoundedVec::new(); - for i in 0..MAX_UNENCRYPTED_LOGS_PER_CALL { - let new_log = new_logs[i]; - if new_log.value != 0 { - new_logs_to_insert.push(ScopedLogHash { log_hash: new_log, contract_address: storage_contract_address }); - } - } - public_inputs.end_non_revertible.unencrypted_logs_hashes.extend_from_bounded_vec(new_logs_to_insert); -} - -/** - * @brief Validates that the call stack item for this circuit iteration is at the top of the call stack - * @param builder The circuit builder - * @param public_kernel_inputs The inputs to this iteration of the kernel circuit - */ -pub fn validate_call_against_request(public_call: PublicCallData, request: PublicCallRequest) { - // TODO: this logic might need to change to accommodate the weird edge 3 initial txs (the 'main' tx, the 'fee' tx, - // and the 'gas rebate' tx). - let call_stack_item = public_call.call_stack_item; - assert( - call_stack_item.get_compressed() == request.item, "call stack item does not match item at the top of the call stack" - ); - - let call_context = call_stack_item.public_inputs.call_context; - if call_context.is_delegate_call { - assert( - !call_stack_item.contract_address.eq(call_context.storage_contract_address), "curent contract address must not match storage contract address for delegate calls" - ); - } else { - assert( - call_context.storage_contract_address.eq(call_stack_item.contract_address), "call stack storage address does not match expected contract address" - ); - } -} diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/mod.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/mod.nr new file mode 100644 index 00000000000..962c5490905 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/mod.nr @@ -0,0 +1,4 @@ +mod previous_kernel_validator; +mod public_call_data_validator; +mod public_kernel_output_composer; +mod public_tail_output_composer; diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/previous_kernel_validator.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/previous_kernel_validator.nr new file mode 100644 index 00000000000..42b748709db --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/previous_kernel_validator.nr @@ -0,0 +1,55 @@ +use crate::public_kernel_phase::PublicKernelPhase; +use dep::types::abis::public_kernel_data::PublicKernelData; + +struct PreviousKernelValidator { + previous_kernel: PublicKernelData, +} + +impl PreviousKernelValidator { + pub fn new(previous_kernel: PublicKernelData) -> Self { + PreviousKernelValidator { previous_kernel } + } + + pub fn validate_proof(self, _allowed_indices: [u32; N]) { + if !dep::std::runtime::is_unconstrained() { + // Recursively verify the tube proof or a previous public kernel proof + self.previous_kernel.verify(); + // TODO(#7410) currently stubbed out until tube vk handled + // self.previous_kernel.validate_in_vk_tree(allowed_indices); + } + } + + pub fn validate_phase(self, phase: u8) { + let public_inputs = self.previous_kernel.public_inputs; + + let needs_setup = !public_inputs.end_non_revertible.public_call_stack[0].item.contract_address.is_zero(); + if phase == PublicKernelPhase.SETUP { + assert_eq(needs_setup, true, "Cannot run unnecessary setup circuit"); + } + + let needs_app_logic = !public_inputs.end.public_call_stack[0].item.contract_address.is_zero(); + if phase == PublicKernelPhase.APP_LOGIC { + assert_eq(needs_setup, false, "Cannot run app logic circuit before setup circuit"); + assert_eq(needs_app_logic, true, "Cannot run unnecessary app logic circuit"); + } + + let needs_teardown = !public_inputs.public_teardown_call_stack[0].item.contract_address.is_zero(); + if phase == PublicKernelPhase.TEARDOWN { + assert_eq(needs_setup, false, "Cannot run teardown circuit before setup circuit"); + assert_eq(needs_app_logic, false, "Cannot run teardown circuit before app logic circuit"); + assert_eq(needs_teardown, true, "Cannot run unnecessary teardown circuit"); + } + + if phase == PublicKernelPhase.TAIL { + assert_eq( + needs_setup, false, "Revertible call stack must be empty when executing the tail circuit" + ); + assert_eq( + needs_app_logic, false, "Non-revertible call stack must be empty when executing the tail circuit" + ); + assert_eq( + needs_teardown, false, "Teardown call stack must be empty when executing the tail circuit" + ); + } + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_call_data_validator.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_call_data_validator.nr new file mode 100644 index 00000000000..c4b906c8d68 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_call_data_validator.nr @@ -0,0 +1,187 @@ +use crate::public_kernel_phase::PublicKernelPhase; +use dep::types::{ + abis::{ + kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, public_call_data::PublicCallData, + public_call_request::PublicCallRequest +}, + constants::MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, utils::arrays::array_length +}; + +struct PublicCallDataValidator { + data: PublicCallData, + phase: u8, +} + +impl PublicCallDataValidator { + pub fn new(data: PublicCallData, phase: u8) -> Self { + PublicCallDataValidator { data, phase } + } + + pub fn validate(self) { + self.validate_common_inputs(); + self.validate_revert_code(); + self.validate_call(); + self.validate_call_requests(); + } + + pub fn validate_against_previous_kernel(self, previous_kernel: PublicKernelCircuitPublicInputs) { + self.validate_global_variables(previous_kernel); + self.validate_start_gas(previous_kernel); + self.validate_transaction_fee(previous_kernel); + self.validate_against_call_request(previous_kernel); + } + + fn validate_common_inputs(self) { + let call_stack_item = self.data.call_stack_item; + assert(!call_stack_item.contract_address.is_zero(), "Contract address cannot be zero"); + assert(call_stack_item.function_data.selector.to_field() != 0, "Function signature cannot be zero"); + assert_eq( + call_stack_item.function_data.is_private, false, "Cannot execute a private function with the public kernel circuit" + ); + assert_eq( + call_stack_item.function_data.selector, call_stack_item.public_inputs.call_context.function_selector, "function selector in call context does not match call stack item" + ); + assert(self.data.bytecode_hash != 0, "Bytecode hash cannot be zero"); + } + + fn validate_revert_code(self) { + if self.phase == PublicKernelPhase.SETUP { + assert_eq(self.data.call_stack_item.public_inputs.revert_code, 0, "Public call cannot be reverted"); + } + } + + fn validate_call(self) { + let call_stack_item = self.data.call_stack_item; + let public_inputs = call_stack_item.public_inputs; + + let call_context = public_inputs.call_context; + if call_context.is_delegate_call { + assert( + !call_stack_item.contract_address.eq(call_context.storage_contract_address), "curent contract address must not match storage contract address for delegate calls" + ); + } else { + assert( + call_context.storage_contract_address.eq(call_stack_item.contract_address), "call stack storage address does not match expected contract address" + ); + } + + if call_context.is_static_call { + // No state changes are allowed for static calls: + let note_hashes_length = array_length(public_inputs.note_hashes); + assert(note_hashes_length == 0, "note_hashes must be empty for static calls"); + + let nullifiers_length = array_length(public_inputs.nullifiers); + assert(nullifiers_length == 0, "nullifiers must be empty for static calls"); + + let update_requests_length = array_length(public_inputs.contract_storage_update_requests); + assert( + update_requests_length == 0, "No contract storage update requests are allowed for static calls" + ); + + let l2_to_l1_msgs_length = array_length(public_inputs.l2_to_l1_msgs); + assert(l2_to_l1_msgs_length == 0, "l2_to_l1_msgs must be empty for static calls"); + + let new_unencrypted_logs_length = array_length(public_inputs.unencrypted_logs_hashes); + assert(new_unencrypted_logs_length == 0, "No unencrypted logs are allowed for static calls"); + } + } + + fn validate_call_requests(self) { + let call_requests = self.data.call_stack_item.public_inputs.public_call_requests; + let this_context = self.data.call_stack_item.public_inputs.call_context; + for i in 0..call_requests.len() { + let request = call_requests[i]; + if !request.item.contract_address.is_zero() { + let target_context = request.item.call_context; + let target_contract = request.item.contract_address; + + if target_context.is_delegate_call { + assert_eq( + target_context.msg_sender, this_context.msg_sender, "incorrect msg_sender for delegate call request" + ); + assert_eq( + target_context.storage_contract_address, this_context.storage_contract_address, "incorrect storage_contract_address for delegate call request" + ); + } else { + assert_eq( + target_context.msg_sender, this_context.storage_contract_address, "incorrect msg_sender for call request" + ); + assert_eq( + target_context.storage_contract_address, target_contract, "incorrect storage_contract_address for call request" + ); + } + if !target_context.is_static_call { + assert(this_context.is_static_call == false, "static call cannot make non-static calls"); + } + } + } + } + + fn validate_against_call_request(self, previous_kernel: PublicKernelCircuitPublicInputs) { + let call_stack = if self.phase == PublicKernelPhase.SETUP { + previous_kernel.end_non_revertible.public_call_stack + } else if self.phase == PublicKernelPhase.APP_LOGIC { + previous_kernel.end.public_call_stack + } else if self.phase == PublicKernelPhase.TEARDOWN { + previous_kernel.public_teardown_call_stack + } else { + assert(false, "Unknown phase"); + [PublicCallRequest::empty(); MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX] + }; + + let call_request = call_stack[array_length(call_stack) - 1]; + assert( + self.data.call_stack_item.get_compressed() == call_request.item, "call stack item does not match item at the top of the call stack" + ); + } + + fn validate_global_variables(self, previous_kernel: PublicKernelCircuitPublicInputs) { + let prev_global_variables = previous_kernel.constants.global_variables; + if !prev_global_variables.is_empty() { // It's empty when the previous kernel is from private_kernel_tail_to_pubic. + let public_call_globals = self.data.call_stack_item.public_inputs.global_variables; + assert_eq( + public_call_globals, prev_global_variables, "Global variables injected into the public call do not match constants" + ); + } + } + + // Validates that the start gas injected into the app circuit matches the remaining gas. + fn validate_start_gas(self, previous_kernel: PublicKernelCircuitPublicInputs) { + // If this is a nested call (not an execution request), the start gas is correct as long as the + // call being processed by this kernel iteration matches the call at the top of the callstack + // as per the previous kernel's outputs. + // An execution request's start gas is the remaining gas left in the transaction after the previous kernel. + // A nested call's start gas is the gas allocated to it by its caller and placed in the callstack. + if self.data.call_stack_item.is_execution_request { + let public_call_start_gas = self.data.call_stack_item.public_inputs.start_gas_left; + if self.phase != PublicKernelPhase.TEARDOWN { + let tx_gas_limits = previous_kernel.constants.tx_context.gas_settings.gas_limits; + let computed_start_gas = tx_gas_limits.sub(previous_kernel.end.gas_used).sub(previous_kernel.end_non_revertible.gas_used); + assert_eq( + public_call_start_gas, computed_start_gas, "Start gas for public phase does not match transaction gas left" + ); + } else { + let teardown_gas_limit = previous_kernel.constants.tx_context.gas_settings.teardown_gas_limits; + assert_eq( + public_call_start_gas, teardown_gas_limit, "Start gas for teardown phase does not match teardown gas allocation" + ); + } + } + } + + fn validate_transaction_fee(self, previous_kernel: PublicKernelCircuitPublicInputs) { + let transaction_fee = self.data.call_stack_item.public_inputs.transaction_fee; + if self.phase != PublicKernelPhase.TEARDOWN { + assert_eq(transaction_fee, 0, "Transaction fee must be zero on setup and app phases"); + } else { + // Note that teardown_gas is already included in end.gas_used as it was injected by the private kernel + let total_gas_used = previous_kernel.end.gas_used + previous_kernel.end_non_revertible.gas_used; + let block_gas_fees = self.data.call_stack_item.public_inputs.global_variables.gas_fees; + let inclusion_fee = previous_kernel.constants.tx_context.gas_settings.inclusion_fee; + let computed_transaction_fee = total_gas_used.compute_fee(block_gas_fees) + inclusion_fee; + assert( + transaction_fee == computed_transaction_fee, "Transaction fee on teardown phase does not match expected value" + ); + } + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_kernel_output_composer.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_kernel_output_composer.nr new file mode 100644 index 00000000000..a690bc819d9 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_kernel_output_composer.nr @@ -0,0 +1,166 @@ +mod propagate_accumulated_data; + +use crate::{ + components::public_kernel_output_composer::propagate_accumulated_data::propagate_accumulated_data, + public_kernel_phase::PublicKernelPhase +}; +use dep::types::{ + abis::{ + accumulated_data::PublicAccumulatedDataBuilder, + kernel_circuit_public_inputs::{PublicKernelCircuitPublicInputs, PublicKernelCircuitPublicInputsBuilder}, + public_call_data::PublicCallData, public_call_request::PublicCallRequest, + public_circuit_public_inputs::PublicCircuitPublicInputs, public_data_read::PublicDataRead +}, + traits::is_empty, utils::arrays::array_to_bounded_vec +}; + +struct PublicKernelOutputComposer { + output_builder: PublicKernelCircuitPublicInputsBuilder, +} + +impl PublicKernelOutputComposer { + pub fn new_from_previous_kernel(previous_kernel: PublicKernelCircuitPublicInputs) -> Self { + let output_builder = PublicKernelCircuitPublicInputsBuilder::new(previous_kernel); + PublicKernelOutputComposer { output_builder } + } + + pub fn remove_top_call_request(&mut self, phase: u8) -> Self { + if phase == PublicKernelPhase.SETUP { + let _ = self.output_builder.end_non_revertible.public_call_stack.pop(); + } + if phase == PublicKernelPhase.APP_LOGIC { + let _ = self.output_builder.end.public_call_stack.pop(); + } + if phase == PublicKernelPhase.TEARDOWN { + let _ = self.output_builder.public_teardown_call_stack.pop(); + } + *self + } + + pub fn propagate_from_public_call(&mut self, public_call: PublicCircuitPublicInputs, phase: u8) -> Self { + self.output_builder.constants.global_variables = public_call.global_variables; + self.propagate_revert_code(public_call, phase); + self.propagate_validation_requests(public_call); + self.propagate_accumulated_data(public_call, phase); + self.update_gas_used(public_call, phase); + *self + } + + pub fn finish(self) -> PublicKernelCircuitPublicInputs { + self.output_builder.finish() + } + + fn propagate_revert_code(&mut self, public_call: PublicCircuitPublicInputs, phase: u8) { + let prev_revert_code = self.output_builder.revert_code; + let public_call_revert_code = public_call.revert_code; + if phase == PublicKernelPhase.SETUP { + // Keep prev_revert_code. + // public_call_revert_code should be 0. If not, PublicCallDataValidator > validate_revert_code will fail. + } + if phase == PublicKernelPhase.APP_LOGIC { + if prev_revert_code == 0 { + self.output_builder.revert_code = public_call_revert_code; + } + } + if phase == PublicKernelPhase.TEARDOWN { + // See https://docs.aztec.network/protocol-specs/gas-and-fees/kernel-tracking#handling-reverts + if public_call_revert_code != 0 { + self.output_builder.revert_code = if prev_revert_code == 0 { + // Case where there is a new error in teardown + 2 + } else { + // Case where there is an error in both app logic and teardown + 3 + }; + } + } + } + + fn propagate_validation_requests(&mut self, public_call: PublicCircuitPublicInputs) { + // Note that the public kernel cannot modify the max block number value - it simply forwards it to the rollup + + let storage_contract_address = public_call.call_context.storage_contract_address; + + let nullifier_read_requests = public_call.nullifier_read_requests; + for i in 0..nullifier_read_requests.len() { + let request = nullifier_read_requests[i]; + if !is_empty(request) { + self.output_builder.validation_requests.nullifier_read_requests.push(request.scope(storage_contract_address)); + } + } + + let nullifier_non_existent_read_requests = public_call.nullifier_non_existent_read_requests; + for i in 0..nullifier_non_existent_read_requests.len() { + let request = nullifier_non_existent_read_requests[i]; + if !is_empty(request) { + self.output_builder.validation_requests.nullifier_non_existent_read_requests.push(request.scope(storage_contract_address)); + } + } + + let read_requests = public_call.contract_storage_reads; + for i in 0..read_requests.len() { + let read_request = read_requests[i]; + if !is_empty(read_request) { + self.output_builder.validation_requests.public_data_reads.push(PublicDataRead::from_contract_storage_read(storage_contract_address, read_request)); + } + } + } + + fn propagate_accumulated_data(&mut self, public_call: PublicCircuitPublicInputs, phase: u8) { + let revert_in_phase = (self.output_builder.revert_code != 0) + & ((phase != PublicKernelPhase.TEARDOWN) | (self.output_builder.revert_code != 1)); // Revert in APP_LOGIC + + if phase == PublicKernelPhase.SETUP { + self.output_builder.end_non_revertible = propagate_accumulated_data(&mut self.output_builder.end_non_revertible, public_call); + } + if (phase == PublicKernelPhase.APP_LOGIC) | (phase == PublicKernelPhase.TEARDOWN) { + self.output_builder.end = propagate_accumulated_data(&mut self.output_builder.end, public_call); + } + + // TODO: Should keep the data even when reverts. + // The data is required for verifying validation requests in the tail circuit, which will then discard the + // revertible data. + if revert_in_phase { + self.output_builder.end = PublicAccumulatedDataBuilder::empty(); + if phase == PublicKernelPhase.TEARDOWN { + self.output_builder.public_teardown_call_stack = BoundedVec::new(); + } + } + if !revert_in_phase { + self.propagate_call_requests(public_call, phase); + } + } + + fn propagate_call_requests(&mut self, public_call: PublicCircuitPublicInputs, phase: u8) { + let call_requests = array_to_bounded_vec(public_call.public_call_requests); + + // TODO: Insert call requests in reversed order. + if phase == PublicKernelPhase.SETUP { + self.output_builder.end_non_revertible.public_call_stack.extend_from_bounded_vec(call_requests); + } + if phase == PublicKernelPhase.APP_LOGIC { + self.output_builder.end.public_call_stack.extend_from_bounded_vec(call_requests); + } + if phase == PublicKernelPhase.TEARDOWN { + self.output_builder.public_teardown_call_stack.extend_from_bounded_vec(call_requests); + } + } + + fn update_gas_used(&mut self, public_call: PublicCircuitPublicInputs, phase: u8) { + let tx_gas_limits = self.output_builder.constants.tx_context.gas_settings.gas_limits; + let call_gas_left = public_call.end_gas_left; + if phase == PublicKernelPhase.SETUP { + let accum_end_gas_used = self.output_builder.end.gas_used; + self.output_builder.end_non_revertible.gas_used = tx_gas_limits + .sub(call_gas_left) + .sub(accum_end_gas_used); + } + + if phase == PublicKernelPhase.APP_LOGIC { + let accum_end_non_revertible_gas_used = self.output_builder.end_non_revertible.gas_used; + self.output_builder.end.gas_used = tx_gas_limits + .sub(call_gas_left) + .sub(accum_end_non_revertible_gas_used); + } + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_kernel_output_composer/propagate_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_kernel_output_composer/propagate_accumulated_data.nr new file mode 100644 index 00000000000..c3edd3ee575 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_kernel_output_composer/propagate_accumulated_data.nr @@ -0,0 +1,80 @@ +use dep::types::{ + abis::{ + accumulated_data::PublicAccumulatedDataBuilder, log_hash::LogHash, nullifier::Nullifier, + public_circuit_public_inputs::PublicCircuitPublicInputs, + public_data_update_request::PublicDataUpdateRequest +}, + hash::compute_siloed_nullifier +}; + +pub fn propagate_accumulated_data( + data: &mut PublicAccumulatedDataBuilder, + public_call: PublicCircuitPublicInputs +) -> PublicAccumulatedDataBuilder { + propagate_note_hashes(data, public_call); + propagate_nullifiers(data, public_call); + propagate_l2_to_l1_messages(data, public_call); + propagate_unencrypted_logs(data, public_call); + propagate_public_data_writes(data, public_call); + *data +} + +fn propagate_note_hashes(data: &mut PublicAccumulatedDataBuilder, public_call: PublicCircuitPublicInputs) { + let storage_contract_address = public_call.call_context.storage_contract_address; + let note_hashes = public_call.note_hashes; + for i in 0..note_hashes.len() { + let note_hash = note_hashes[i]; + if note_hash.counter != 0 { + data.note_hashes.push(note_hash.scope(storage_contract_address)); + } + } +} + +fn propagate_nullifiers(data: &mut PublicAccumulatedDataBuilder, public_call: PublicCircuitPublicInputs) { + let storage_contract_address = public_call.call_context.storage_contract_address; + let nullifiers = public_call.nullifiers; + for i in 0..nullifiers.len() { + let nullifier = nullifiers[i]; + if nullifier.counter != 0 { + let siloed_value = compute_siloed_nullifier(storage_contract_address, nullifier.value); + data.nullifiers.push( + Nullifier { value: siloed_value, counter: nullifier.counter, note_hash: nullifier.note_hash } + ); + } + } +} + +fn propagate_l2_to_l1_messages(data: &mut PublicAccumulatedDataBuilder, public_call: PublicCircuitPublicInputs) { + let storage_contract_address = public_call.call_context.storage_contract_address; + let msgs = public_call.l2_to_l1_msgs; + for i in 0..msgs.len() { + let msg = msgs[i]; + if msg.counter != 0 { + data.l2_to_l1_msgs.push(msg.scope(storage_contract_address)); + } + } +} + +fn propagate_unencrypted_logs(data: &mut PublicAccumulatedDataBuilder, public_call: PublicCircuitPublicInputs) { + let storage_contract_address = public_call.call_context.storage_contract_address; + let logs = public_call.unencrypted_logs_hashes; + for i in 0..logs.len() { + let log = logs[i]; + if log.counter != 0 { + data.unencrypted_logs_hashes.push(log.scope(storage_contract_address)); + } + } +} + +fn propagate_public_data_writes(data: &mut PublicAccumulatedDataBuilder, public_call: PublicCircuitPublicInputs) { + let storage_contract_address = public_call.call_context.storage_contract_address; + let writes = public_call.contract_storage_update_requests; + for i in 0..writes.len() { + let write = writes[i]; + if write.counter != 0 { + data.public_data_update_requests.push( + PublicDataUpdateRequest::from_contract_storage_update_request(storage_contract_address, write) + ); + } + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_tail_output_composer.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_tail_output_composer.nr new file mode 100644 index 00000000000..a4212e4d65d --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_tail_output_composer.nr @@ -0,0 +1,40 @@ +mod combine_data; + +use crate::components::public_tail_output_composer::combine_data::{combine_data, CombineHints}; +use dep::types::{ + abis::{kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PublicKernelCircuitPublicInputs}}, + partial_state_reference::PartialStateReference +}; + +struct PublicTailOutputComposer { + previous_kernel: PublicKernelCircuitPublicInputs, + start_state: PartialStateReference, + combine_hints: CombineHints +} + +impl PublicTailOutputComposer { + pub fn new( + previous_kernel: PublicKernelCircuitPublicInputs, + start_state: PartialStateReference, + combine_hints: CombineHints + ) -> Self { + PublicTailOutputComposer { previous_kernel, start_state, combine_hints } + } + + pub fn finish(self) -> KernelCircuitPublicInputs { + let end = combine_data( + self.previous_kernel.end_non_revertible, + self.previous_kernel.end, + self.combine_hints + ); + + KernelCircuitPublicInputs { + rollup_validation_requests: self.previous_kernel.validation_requests.for_rollup, + end, + constants: self.previous_kernel.constants, + start_state: self.start_state, + revert_code: self.previous_kernel.revert_code, + fee_payer: self.previous_kernel.fee_payer + } + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_tail_output_composer/combine_data.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_tail_output_composer/combine_data.nr new file mode 100644 index 00000000000..8ab94be1acd --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_tail_output_composer/combine_data.nr @@ -0,0 +1,134 @@ +use dep::types::{ + hash::{compute_tx_logs_hash, compute_tx_note_logs_hash}, + abis::{ + accumulated_data::{CombinedAccumulatedData, PublicAccumulatedData}, + log_hash::{LogHash, ScopedLogHash}, note_hash::ScopedNoteHash, nullifier::Nullifier, + public_data_update_request::PublicDataUpdateRequest, side_effect::Ordered +}, + constants::{ + MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, + MAX_ENCRYPTED_LOGS_PER_TX +}, + hash::silo_note_hash, + utils::arrays::{array_merge, assert_sorted_array, assert_deduped_array, check_permutation} +}; + +struct CombineHints { + sorted_note_hashes: [ScopedNoteHash; MAX_NOTE_HASHES_PER_TX], + sorted_note_hashes_indexes: [u32; MAX_NOTE_HASHES_PER_TX], + sorted_note_encrypted_logs_hashes: [LogHash; MAX_NOTE_ENCRYPTED_LOGS_PER_TX], + sorted_note_encrypted_logs_hashes_indexes: [u32; MAX_NOTE_ENCRYPTED_LOGS_PER_TX], + sorted_encrypted_logs_hashes: [ScopedLogHash; MAX_ENCRYPTED_LOGS_PER_TX], + sorted_encrypted_logs_hashes_indexes: [u32; MAX_ENCRYPTED_LOGS_PER_TX], + sorted_unencrypted_logs_hashes: [ScopedLogHash; MAX_UNENCRYPTED_LOGS_PER_TX], + sorted_unencrypted_logs_hashes_indexes: [u32; MAX_UNENCRYPTED_LOGS_PER_TX], + // the public data update requests are sorted by their leaf index AND counter + sorted_public_data_update_requests: [PublicDataUpdateRequest; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], + sorted_public_data_update_requests_indexes: [u32; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], + // THEN deduplicated based on their leaf slot + deduped_public_data_update_requests: [PublicDataUpdateRequest; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], + deduped_public_data_update_requests_runs: [u32; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], +} + +fn asc_sort_by_counters(a: T, b: T) -> bool where T: Ordered { + a.counter() <= b.counter() +} + +pub fn combine_data( + non_revertible: PublicAccumulatedData, + revertible: PublicAccumulatedData, + combine_hints: CombineHints +) -> CombinedAccumulatedData { + let merged_note_hashes = array_merge(non_revertible.note_hashes, revertible.note_hashes); + assert_sorted_array( + merged_note_hashes, + combine_hints.sorted_note_hashes, + combine_hints.sorted_note_hashes_indexes, + asc_sort_by_counters + ); + + let mut siloed_note_hashes = [0; MAX_NOTE_HASHES_PER_TX]; + let sorted_note_hashes = combine_hints.sorted_note_hashes; + let tx_hash = non_revertible.nullifiers[0].value; + for i in 0..sorted_note_hashes.len() { + let note_hash = sorted_note_hashes[i]; + siloed_note_hashes[i] = if note_hash.counter() == 0 { + // If counter is zero, the note hash was emitted from private and has been siloed in private_kernel_tail_to_public. + note_hash.value() + } else { + silo_note_hash(note_hash, tx_hash, i) + }; + } + + let merged_public_data_update_requests = array_merge( + non_revertible.public_data_update_requests, + revertible.public_data_update_requests + ); + + // Just check a permutation here... + check_permutation( + merged_public_data_update_requests, + combine_hints.sorted_public_data_update_requests, + combine_hints.sorted_public_data_update_requests_indexes + ); + // ...because the ordering checks are done here. + assert_deduped_array( + combine_hints.sorted_public_data_update_requests, + combine_hints.deduped_public_data_update_requests, + combine_hints.deduped_public_data_update_requests_runs + ); + + let merged_note_encrypted_logs_hashes = array_merge( + non_revertible.note_encrypted_logs_hashes, + revertible.note_encrypted_logs_hashes + ); + assert_sorted_array( + merged_note_encrypted_logs_hashes, + combine_hints.sorted_note_encrypted_logs_hashes, + combine_hints.sorted_note_encrypted_logs_hashes_indexes, + asc_sort_by_counters + ); + + let merged_encrypted_logs_hashes = array_merge( + non_revertible.encrypted_logs_hashes, + revertible.encrypted_logs_hashes + ); + assert_sorted_array( + merged_encrypted_logs_hashes, + combine_hints.sorted_encrypted_logs_hashes, + combine_hints.sorted_encrypted_logs_hashes_indexes, + asc_sort_by_counters + ); + + let merged_unencrypted_logs_hashes = array_merge( + non_revertible.unencrypted_logs_hashes, + revertible.unencrypted_logs_hashes + ); + assert_sorted_array( + merged_unencrypted_logs_hashes, + combine_hints.sorted_unencrypted_logs_hashes, + combine_hints.sorted_unencrypted_logs_hashes_indexes, + asc_sort_by_counters + ); + + let note_encrypted_log_preimages_length = non_revertible.note_encrypted_logs_hashes.fold(0, |a, b: LogHash| a + b.length) + + revertible.note_encrypted_logs_hashes.fold(0, |a, b: LogHash| a + b.length); + let encrypted_log_preimages_length = non_revertible.encrypted_logs_hashes.fold(0, |a, b: ScopedLogHash| a + b.log_hash.length) + + revertible.encrypted_logs_hashes.fold(0, |a, b: ScopedLogHash| a + b.log_hash.length); + let unencrypted_log_preimages_length = non_revertible.unencrypted_logs_hashes.fold(0, |a, b: ScopedLogHash| a + b.log_hash.length) + + revertible.unencrypted_logs_hashes.fold(0, |a, b: ScopedLogHash| a + b.log_hash.length); + CombinedAccumulatedData { + note_hashes: siloed_note_hashes, + nullifiers: array_merge(non_revertible.nullifiers, revertible.nullifiers).map(|n: Nullifier| n.value), + l2_to_l1_msgs: array_merge(non_revertible.l2_to_l1_msgs, revertible.l2_to_l1_msgs), + note_encrypted_logs_hashes: combine_hints.sorted_note_encrypted_logs_hashes, + encrypted_logs_hashes: combine_hints.sorted_encrypted_logs_hashes, + unencrypted_logs_hashes: combine_hints.sorted_unencrypted_logs_hashes, + note_encrypted_log_preimages_length, + encrypted_log_preimages_length, + unencrypted_log_preimages_length, + public_data_update_requests: combine_hints.deduped_public_data_update_requests, + gas_used: revertible.gas_used + non_revertible.gas_used + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/lib.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/lib.nr index 7b8104d1a6a..164d717ea3a 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/lib.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/lib.nr @@ -1,8 +1,5 @@ -// TODO: rename to be precise as to what its common to (the public kernel circuits). -mod common; - -mod utils; - +mod components; +mod public_kernel_phase; mod public_kernel_setup; mod public_kernel_app_logic; mod public_kernel_teardown; diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr index 4b654a968e4..7f6b5f4e93b 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr @@ -1,10 +1,18 @@ -use dep::types::abis::public_call_data::PublicCallData; -use dep::types::abis::public_kernel_data::PublicKernelData; -use dep::types::PublicKernelCircuitPublicInputs; -use dep::types::abis::kernel_circuit_public_inputs::PublicKernelCircuitPublicInputsBuilder; -use dep::types::utils::arrays::array_to_bounded_vec; -use dep::types::constants::{PUBLIC_KERNEL_SETUP_INDEX, PUBLIC_KERNEL_APP_LOGIC_INDEX, PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX}; -use crate::common; +use crate::{ + components::{ + previous_kernel_validator::PreviousKernelValidator, + public_call_data_validator::PublicCallDataValidator, + public_kernel_output_composer::PublicKernelOutputComposer +}, + public_kernel_phase::PublicKernelPhase +}; +use dep::types::{ + abis::{ + kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, public_kernel_data::PublicKernelData, + public_call_data::PublicCallData +}, + constants::{PUBLIC_KERNEL_SETUP_INDEX, PUBLIC_KERNEL_APP_LOGIC_INDEX, PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX} +}; global ALLOWED_PREVIOUS_CIRCUITS = [ PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX, @@ -18,92 +26,27 @@ struct PublicKernelAppLogicCircuitPrivateInputs { } impl PublicKernelAppLogicCircuitPrivateInputs { - - fn initialize_revert_code(self, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder) { - if self.previous_kernel.public_inputs.revert_code != 0 { - circuit_outputs.revert_code = self.previous_kernel.public_inputs.revert_code; - } else if self.public_call.call_stack_item.public_inputs.revert_code != 0 { - circuit_outputs.revert_code = self.public_call.call_stack_item.public_inputs.revert_code; - } - } - - fn initialize_non_revertible_values( - self, - circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder - ) { - // initialise the end state with our provided previous kernel state - common::initialize_non_revertible_values(self.previous_kernel, circuit_outputs); - - // We always pass the teardown call stack forward during app logic - circuit_outputs.public_teardown_call_stack = array_to_bounded_vec(self.previous_kernel.public_inputs.public_teardown_call_stack); - } - - fn validate_inputs(self) { - let needs_setup = self.previous_kernel.public_inputs.needs_setup(); - assert(needs_setup == false, "Cannot run app logic circuit before setup circuit"); - let needs_app_logic = self.previous_kernel.public_inputs.needs_app_logic(); - assert(needs_app_logic == true, "Cannot run unnecessary app logic circuit"); - } - - fn public_kernel_app_logic(self) -> PublicKernelCircuitPublicInputs { - if !dep::std::runtime::is_unconstrained() { - // TODO(#7410) currently stubbed out until tube vk handled - // self.previous_kernel.validate_in_vk_tree(ALLOWED_PREVIOUS_CIRCUITS); - } - // construct the circuit outputs - let mut public_inputs = PublicKernelCircuitPublicInputsBuilder::empty(); - - self.initialize_revert_code(&mut public_inputs); - - self.initialize_non_revertible_values(&mut public_inputs); - - // validate the inputs common to all invocation circumstances - common::validate_inputs(self.public_call); - - // validate constants injected into the public call are correct or set them if this is the first public call - common::initialize_from_or_validate_public_call_variables(self.previous_kernel, self.public_call, &mut public_inputs); - - // validate the inputs unique to having a previous public kernel - self.validate_inputs(); - - common::validate_start_gas(self.public_call, self.previous_kernel); - common::validate_transaction_fee_is_zero(self.public_call); - - common::update_validation_requests(self.public_call, &mut public_inputs); - - common::update_revertible_gas_used(self.public_call, &mut public_inputs); - - if public_inputs.revert_code == 0 { - common::initialize_end_values(self.previous_kernel, &mut public_inputs); - // Pops the item from the call stack and validates it against the current execution. - let call_request = public_inputs.end.public_call_stack.pop(); - common::validate_call_against_request(self.public_call, call_request); - common::update_end_call_stack(self.public_call, &mut public_inputs); - common::update_public_end_values(self.public_call, &mut public_inputs); - } else { - let mut remaining_calls = array_to_bounded_vec(self.previous_kernel.public_inputs.end.public_call_stack); - let reverted_call_request = remaining_calls.pop(); - // even though we reverted, we still need to make sure the correct call was made - // but don't do the full `validate_call_against_request` because - // that makes a bunch of assertions that we don't want to make - // e.g. that msg_sender is self in the case of internal. - // We don't want to make those checks because we already know we reverted, - // and we aren't updating the public end values, so we want this kernel circuit to solve. - // So just check that the call request is the same as the one we expected. - assert( - reverted_call_request.item == self.public_call.call_stack_item.get_compressed(), "call stack item does not match item at the top of the call stack" - ); - } - - public_inputs.finish() + fn execute(self) -> PublicKernelCircuitPublicInputs { + let phase = PublicKernelPhase.APP_LOGIC; + + let previous_kernel_validator = PreviousKernelValidator::new(self.previous_kernel); + previous_kernel_validator.validate_phase(phase); + previous_kernel_validator.validate_proof(ALLOWED_PREVIOUS_CIRCUITS); + + let call_data_validator = PublicCallDataValidator::new(self.public_call, PublicKernelPhase.APP_LOGIC); + call_data_validator.validate(); + call_data_validator.validate_against_previous_kernel(self.previous_kernel.public_inputs); + + // noir-fmt:ignore + PublicKernelOutputComposer::new_from_previous_kernel(self.previous_kernel.public_inputs) + .remove_top_call_request(phase) + .propagate_from_public_call(self.public_call.call_stack_item.public_inputs, phase) + .finish() } } mod tests { - use crate::{ - public_kernel_app_logic::{PublicKernelAppLogicCircuitPrivateInputs, ALLOWED_PREVIOUS_CIRCUITS}, - utils::{compute_public_data_reads, compute_public_data_update_requests} - }; + use crate::{public_kernel_app_logic::{PublicKernelAppLogicCircuitPrivateInputs, ALLOWED_PREVIOUS_CIRCUITS}}; use dep::types::{ abis::{ gas::Gas, kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, @@ -113,31 +56,26 @@ mod tests { public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, read_request::ReadRequest }, - messaging::l2_to_l1_message::ScopedL2ToL1Message, address::{AztecAddress, EthAddress}, - contract_class_id::ContractClassId, hash::{compute_l2_to_l1_hash, compute_siloed_nullifier}, - messaging::l2_to_l1_message::L2ToL1Message, - tests::{ - fixture_builder::FixtureBuilder, public_call_data_builder::PublicCallDataBuilder, - utils::assert_array_eq - }, - utils::arrays::{array_eq, array_length}, traits::is_empty - }; - use dep::types::constants::{ - MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, - PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX, PUBLIC_KERNEL_APP_LOGIC_INDEX, BASE_ROLLUP_INDEX + constants::{PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX, PUBLIC_KERNEL_APP_LOGIC_INDEX, BASE_ROLLUP_INDEX}, + contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, + address::AztecAddress, hash::compute_siloed_nullifier, + tests::{fixture_builder::FixtureBuilder, utils::assert_array_eq}, traits::is_empty }; struct PublicKernelAppLogicCircuitPrivateInputsBuilder { previous_kernel: FixtureBuilder, - public_call: PublicCallDataBuilder, + previous_non_revertible: FixtureBuilder, + public_call: FixtureBuilder, } impl PublicKernelAppLogicCircuitPrivateInputsBuilder { pub fn new() -> Self { let previous_kernel = FixtureBuilder::new().as_parent_contract().in_vk_tree(PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX); - let public_call = PublicCallDataBuilder::new(); + let previous_non_revertible = FixtureBuilder::new().as_parent_contract(); + let mut public_call = FixtureBuilder::new().is_public_function(); + public_call.value_offset = 9999; // Add an offset so that the mock data won't be the same as the values in previous_kernel. - PublicKernelAppLogicCircuitPrivateInputsBuilder { previous_kernel, public_call } + PublicKernelAppLogicCircuitPrivateInputsBuilder { previous_kernel, previous_non_revertible, public_call } } pub fn is_delegate_call(&mut self) -> Self { @@ -145,41 +83,56 @@ mod tests { *self } - pub fn get_current_public_data_reads(self) -> [PublicDataRead; MAX_PUBLIC_DATA_READS_PER_CALL] { - let read_requests = self.public_call.public_inputs.contract_storage_reads.storage; - compute_public_data_reads(self.public_call.contract_address, read_requests) + pub fn to_public_data_reads(self, contract_storage_reads: [StorageRead; N]) -> [PublicDataRead; N] { + let storage_contract_address = self.public_call.storage_contract_address; + contract_storage_reads.map(|r: StorageRead| PublicDataRead::from_contract_storage_read(storage_contract_address, r)) } - pub fn get_current_public_data_update_requests(self) -> [PublicDataUpdateRequest; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL] { - compute_public_data_update_requests( - self.public_call.contract_address, - self.public_call.public_inputs.contract_storage_update_requests.storage + pub fn to_public_data_update_requests( + self, + storage_update_requests: [StorageUpdateRequest; N] + ) -> [PublicDataUpdateRequest; N] { + let storage_contract_address = self.public_call.storage_contract_address; + storage_update_requests.map( + |r: StorageUpdateRequest| + PublicDataUpdateRequest::from_contract_storage_update_request(storage_contract_address, r) + ) + } + + pub fn to_siloed_nullifiers(self, nullifiers: [ScopedNullifier; N]) -> [Nullifier; N] { + let storage_contract_address = self.public_call.storage_contract_address; + nullifiers.map( + |n: ScopedNullifier| Nullifier { + value: compute_siloed_nullifier(storage_contract_address, n.value()), + note_hash: n.nullifier.note_hash, + counter: n.counter() + } ) } pub fn execute(&mut self) -> PublicKernelCircuitPublicInputs { - let public_call = self.public_call.finish(); + let public_call = self.public_call.to_public_call_data(); // Adjust the call stack item hash for the current call in the previous iteration. let compressed = public_call.call_stack_item.get_compressed(); self.previous_kernel.push_public_call_request(compressed); - let previous_kernel = self.previous_kernel.to_public_kernel_data(true); + let mut previous_kernel = self.previous_kernel.to_public_kernel_data(true); + previous_kernel.public_inputs.end_non_revertible = self.previous_non_revertible.to_public_accumulated_data(); let kernel = PublicKernelAppLogicCircuitPrivateInputs { previous_kernel, public_call }; - kernel.public_kernel_app_logic() + kernel.execute() } pub fn get_call_request_item(self) -> PublicCallStackItemCompressed { - let public_call = self.public_call.finish(); - public_call.call_stack_item.get_compressed() + self.public_call.to_public_call_stack_item().get_compressed() } pub fn failed_with_call_request_item(&mut self, item: PublicCallStackItemCompressed) { - let public_call = self.public_call.finish(); + let public_call = self.public_call.to_public_call_data(); self.previous_kernel.push_public_call_request(item); let previous_kernel = self.previous_kernel.to_public_kernel_data(true); let kernel = PublicKernelAppLogicCircuitPrivateInputs { previous_kernel, public_call }; - let _ = kernel.public_kernel_app_logic(); + let _ = kernel.execute(); } pub fn succeeded(&mut self) { @@ -197,26 +150,11 @@ mod tests { builder.succeeded(); } - // TODO: Find another way to test this. Currently it will crash because we are popping from an empty array: - // The application panicked (crashed). Message: Expected array index to fit in u64 - // #[test(should_fail_with="Public call stack can not be empty")] - // fn public_previous_kernel_empty_public_call_stack_should_fail() { - // let builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); - // let previous_kernel = builder.previous_kernel.finish(); - // let public_call = builder.public_call.finish(); - // let kernel = PublicKernelAppLogicCircuitPrivateInputs { - // previous_kernel, - // public_call, - // }; - // - // let _ = kernel.public_kernel_app_logic(); - // } - #[test(should_fail_with="Cannot run unnecessary app logic circuit")] fn public_previous_kernel_private_previous_kernel_should_fail() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); builder.previous_kernel = FixtureBuilder::new().in_vk_tree(PUBLIC_KERNEL_APP_LOGIC_INDEX); - let public_call = builder.public_call.finish(); + let public_call = builder.public_call.to_public_call_data(); // the key difference in this test versus those that use builder.execute() // is that we do not add a public call request to the previous kernel. @@ -227,53 +165,63 @@ mod tests { let kernel = PublicKernelAppLogicCircuitPrivateInputs { previous_kernel, public_call }; - let _ = kernel.public_kernel_app_logic(); + let _ = kernel.execute(); } #[test] fn circuit_outputs_should_be_correctly_populated_with_previous_commitments() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); - let contract_address = builder.public_call.contract_address; - // Setup 2 new note hashes and logs on the previous kernel. + + // Setup 1 non-revertible note hash and log on the previous kernel. + builder.previous_non_revertible.append_note_hashes_with_logs(1); + let prev_non_rev_notes = builder.previous_non_revertible.note_hashes.storage; + let prev_non_rev_logs = builder.previous_non_revertible.to_public_accumulated_data().note_encrypted_logs_hashes; + + // Setup 2 revertible note hashes and logs on the previous kernel. builder.previous_kernel.append_note_hashes_with_logs(2); - let previous = builder.previous_kernel.note_hashes.storage; - let prev_data = builder.previous_kernel.to_public_accumulated_data(); - let prev_note_logs = prev_data.note_encrypted_logs_hashes; - // Setup 2 new note hashes on the current public inputs. - let current = [ - NoteHash { value: previous[1].value() + 1, counter: 5 }, - NoteHash { value: previous[1].value() + 2, counter: 6 } - ]; - builder.public_call.public_inputs.note_hashes.extend_from_array(current); - let current = current.map(|n: NoteHash| n.scope(contract_address)); - let note_hashes = [previous[0], previous[1], current[0], current[1]]; + let prev_notes = builder.previous_kernel.note_hashes.storage; + let prev_logs = builder.previous_kernel.to_public_accumulated_data().note_encrypted_logs_hashes; + + // Setup 2 note hashes and logs on the current public call. + builder.public_call.append_note_hashes(2); + let curr_notes = builder.public_call.note_hashes.storage; let public_inputs = builder.execute(); - assert(array_eq(public_inputs.end.note_hashes, note_hashes)); - assert( - array_eq( - public_inputs.end.note_encrypted_logs_hashes, - [prev_note_logs[0], prev_note_logs[1]] - ) + assert_array_eq( + public_inputs.end_non_revertible.note_hashes, + [prev_non_rev_notes[0]] + ); + assert_array_eq( + public_inputs.end.note_hashes, + [prev_notes[0], prev_notes[1], curr_notes[0], curr_notes[1]] + ); + assert_array_eq( + public_inputs.end_non_revertible.note_encrypted_logs_hashes, + [prev_non_rev_logs[0]] + ); + assert_array_eq( + public_inputs.end.note_encrypted_logs_hashes, + [prev_logs[0], prev_logs[1]] ); } #[test] fn circuit_outputs_should_be_correctly_populated_with_previous_update_requests() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); + // Setup 2 data writes on the previous kernel. builder.previous_kernel.append_public_data_update_requests(2); let previous = builder.previous_kernel.public_data_update_requests.storage; // Setup 2 data writes on the current public inputs. - builder.public_call.append_update_requests(2); - let current = builder.get_current_public_data_update_requests(); - let public_data_update_requests = [previous[0], previous[1], current[0], current[1]]; + builder.public_call.append_contract_storage_update_requests(2); + let current = builder.to_public_data_update_requests(builder.public_call.contract_storage_update_requests.storage); let public_inputs = builder.execute(); + assert_array_eq( public_inputs.end.public_data_update_requests, - public_data_update_requests + [previous[0], previous[1], current[0], current[1]] ); } @@ -285,116 +233,83 @@ mod tests { builder.previous_kernel.append_public_data_read_requests(2); let previous = builder.previous_kernel.public_data_reads.storage; // Setup 2 data reads on the current public inputs. - builder.public_call.append_public_data_read_requests(2); - let current = builder.get_current_public_data_reads(); - let public_data_read_requests = [previous[0], previous[1], current[0], current[1]]; + builder.public_call.append_contract_storage_read_requests(2); + let current = builder.to_public_data_reads(builder.public_call.contract_storage_reads.storage); + let public_inputs = builder.execute(); assert_array_eq( public_inputs.validation_requests.public_data_reads, - public_data_read_requests + [previous[0], previous[1], current[0], current[1]] ); } #[test] fn circuit_outputs_should_be_correctly_populated_with_previous_nullifiers() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); - let contract_address = builder.public_call.contract_address; // Setup 2 new nullifiers on the previous kernel. builder.previous_kernel.append_nullifiers(2); let previous = builder.previous_kernel.nullifiers.storage.map(|n: ScopedNullifier| n.nullifier); - // Setup 2 new note hashes on the current public inputs. - - let current = [ - Nullifier { value: previous[1].value + 1, note_hash: 0, counter: 4 }, Nullifier { value: previous[1].value + 2, note_hash: 0, counter: 5 } - ]; - builder.public_call.public_inputs.nullifiers.extend_from_array(current); - - let siloed = current.map( - |current: Nullifier| - Nullifier { value: compute_siloed_nullifier(contract_address, current.value), note_hash: current.note_hash, counter: current.counter } - ); - - // There are 2 revertible nullifiers in the previous kernel. - // The tx nullifier is part of the non-revertible nullifiers. - let nullifiers = [previous[0], previous[1], siloed[0], siloed[1]]; + // Setup 2 new nullifiers on the current public call. + builder.public_call.append_nullifiers(2); + let siloed = builder.to_siloed_nullifiers(builder.public_call.nullifiers.storage); let public_inputs = builder.execute(); - assert(array_eq(public_inputs.end.nullifiers, nullifiers)); + assert_array_eq( + public_inputs.end.nullifiers, + [previous[0], previous[1], siloed[0], siloed[1]] + ); } #[test] fn circuit_outputs_should_be_correctly_populated_with_previous_l2_to_l1_msg() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); - let contract_address = builder.public_call.contract_address; - let portal_contract_address = EthAddress::from_field(0xdead); - // Setup 1 new l2 to l1 message on the previous kernel. - - builder.previous_kernel.add_l2_to_l1_message(12345, portal_contract_address); + builder.previous_kernel.append_l2_to_l1_msgs(1); + let previous = builder.previous_kernel.l2_to_l1_msgs.storage; // Setup 1 new l2 to l1 message on the current public inputs. - let current = [L2ToL1Message { recipient: portal_contract_address, content: 67890, counter: 0 }]; - builder.public_call.public_inputs.l2_to_l1_msgs.extend_from_array(current); - - let scoped = current.map(|c: L2ToL1Message| c.scope(contract_address)); - let l2_to_l1_msgs = [builder.previous_kernel.l2_to_l1_msgs.get(0), scoped[0]]; + builder.public_call.append_l2_to_l1_msgs(1); + let current = builder.public_call.l2_to_l1_msgs.storage; let public_inputs = builder.execute(); - assert(array_eq(public_inputs.end.l2_to_l1_msgs, l2_to_l1_msgs)); + + assert_array_eq(public_inputs.end.l2_to_l1_msgs, [previous[0], current[0]]); } // TODO: Break up this test into smaller tests. #[test] fn circuit_outputs_should_be_correctly_populated_with_previous_public_kernel_logs() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); // Logs for the current call stack. - let unencrypted_logs_hash = 26; - let unencrypted_log_preimages_length = 50; - builder.public_call.set_unencrypted_logs(unencrypted_logs_hash, unencrypted_log_preimages_length); + builder.public_call.append_unencrypted_log_hashes(1); + let curr_data = builder.public_call.to_public_accumulated_data(); // Logs for the previous call stack. - let prev_encrypted_logs_hash = 80; - let prev_encrypted_log_preimages_length = 13; - let prev_unencrypted_logs_hash = 956; - let prev_unencrypted_log_preimages_length = 24; - builder.previous_kernel.add_encrypted_log_hash(prev_encrypted_logs_hash, prev_encrypted_log_preimages_length); - builder.previous_kernel.add_unencrypted_log_hash( - prev_unencrypted_logs_hash, - prev_unencrypted_log_preimages_length - ); + builder.previous_kernel.append_encrypted_log_hashes(1); + builder.previous_kernel.append_unencrypted_log_hashes(1); let prev_data = builder.previous_kernel.to_public_accumulated_data(); - - let expected_unencrypted_logs = [ - prev_data.unencrypted_logs_hashes[0], ScopedLogHash { - log_hash: builder.public_call.public_inputs.unencrypted_logs_hashes.storage[0], - contract_address: builder.public_call.contract_address - } - ]; + let expected_unencrypted_logs = [prev_data.unencrypted_logs_hashes[0], curr_data.unencrypted_logs_hashes[0]]; // we assume the encrypted log is already siloed from private kernels let expected_encrypted_logs = [prev_data.encrypted_logs_hashes[0]]; let public_inputs = builder.execute(); - assert( - array_eq( - public_inputs.end.encrypted_logs_hashes, - expected_encrypted_logs - ) + assert_array_eq( + public_inputs.end.encrypted_logs_hashes, + expected_encrypted_logs ); - assert( - array_eq( - public_inputs.end.unencrypted_logs_hashes, - expected_unencrypted_logs - ) + assert_array_eq( + public_inputs.end.unencrypted_logs_hashes, + expected_unencrypted_logs ); } #[test(should_fail_with="No contract storage update requests are allowed for static calls")] fn previous_public_kernel_fails_if_contract_storage_update_requests_on_static_call() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.call_context.is_static_call = true; - builder.public_call.append_update_requests(1); + builder.public_call.is_static_call = true; + builder.public_call.append_contract_storage_update_requests(1); builder.failed(); } @@ -403,7 +318,7 @@ mod tests { fn previous_public_kernel_fails_if_incorrect_storage_contract_on_delegate_call() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new().is_delegate_call(); - builder.public_call.contract_address = builder.public_call.public_inputs.call_context.storage_contract_address; + builder.public_call.contract_address = builder.public_call.storage_contract_address; builder.failed(); } @@ -411,8 +326,8 @@ mod tests { #[test(should_fail_with="note_hashes must be empty for static calls")] fn public_kernel_fails_creating_note_hashes_on_static_call() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.call_context.is_static_call = true; - builder.public_call.public_inputs.note_hashes.push(NoteHash { value: 1, counter: 0 }); + builder.public_call.is_static_call = true; + builder.public_call.append_note_hashes(1); builder.failed(); } @@ -420,8 +335,8 @@ mod tests { #[test(should_fail_with="nullifiers must be empty for static calls")] fn public_kernel_fails_creating_nullifiers_on_static_call() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.call_context.is_static_call = true; - builder.public_call.public_inputs.nullifiers.push(Nullifier { value: 1, note_hash: 0, counter: 0 }); + builder.public_call.is_static_call = true; + builder.public_call.append_nullifiers(1); builder.failed(); } @@ -438,71 +353,44 @@ mod tests { } #[test] - fn only_valid_update_requests_should_be_propagated() { + fn circuit_outputs_should_be_correctly_populated_with_public_call_requests() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); - builder.public_call.append_update_requests(1); - builder.public_call.append_empty_update_requests(1); - builder.public_call.append_update_requests(1); - let public_data_update_requests = builder.get_current_public_data_update_requests(); + + builder.previous_kernel.append_public_call_requests(2); + let prev_calls = builder.previous_kernel.public_call_requests.storage; + + builder.public_call.append_public_call_requests(2); + let curr_calls = builder.public_call.public_call_requests.storage; let public_inputs = builder.execute(); - // Only the 2 valid reads should have been propagated. - let expected = [public_data_update_requests[0], public_data_update_requests[2]]; - assert_array_eq(public_inputs.end.public_data_update_requests, expected); + assert_array_eq( + public_inputs.end.public_call_stack, + [prev_calls[0], prev_calls[1], curr_calls[0], curr_calls[1]] + ); } - #[test] - fn circuit_outputs_should_be_correctly_populated_with_previous_private_kernel() { + #[test(should_fail_with="Cannot run app logic circuit before setup circuit")] + fn previous_kernel_non_empty_non_revertible_public_call_requests_should_fail() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); - builder.public_call.append_public_call_requests_for_regular_calls(2); - let storage = builder.public_call.public_inputs.public_call_requests.storage; - let public_call_stack = [storage[0], storage[1]]; + builder.previous_non_revertible.append_public_call_requests(1); + builder.public_call.append_public_call_requests(1); - builder.public_call.append_update_requests(2); - let storage = builder.get_current_public_data_update_requests(); - let update_requests = [storage[0], storage[1]]; - - builder.public_call.append_public_data_read_requests(3); - let storage = builder.get_current_public_data_reads(); - let read_requests = [storage[0], storage[1], storage[2]]; - - let public_inputs = builder.execute(); - - assert_array_eq(public_inputs.end.public_call_stack, public_call_stack); - assert_array_eq( - public_inputs.end.public_data_update_requests, - update_requests - ); - assert_array_eq( - public_inputs.validation_requests.public_data_reads, - read_requests - ); + builder.failed(); } #[test] fn propagate_nullifier_non_existent_read_requests() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); - let storage_contract_address = builder.public_call.public_inputs.call_context.storage_contract_address; - let request_0 = ReadRequest { value: 123, counter: 4567 }; - builder.public_call.public_inputs.nullifier_non_existent_read_requests.push(request_0); - let request_1 = ReadRequest { value: 777888, counter: 90 }; - builder.public_call.public_inputs.nullifier_non_existent_read_requests.push(request_1); + builder.public_call.append_nullifier_non_existent_read_requests(2); + let requests = builder.public_call.nullifier_non_existent_read_requests.storage; let public_inputs = builder.execute(); let end_requests = public_inputs.validation_requests.nullifier_non_existent_read_requests; - assert_eq(array_length(end_requests), 2); - - let request = end_requests[0]; - assert_eq(request.read_request, request_0); - assert_eq(request.contract_address, storage_contract_address); - - let request = end_requests[1]; - assert_eq(request.read_request, request_1); - assert_eq(request.contract_address, storage_contract_address); + assert_array_eq(end_requests, [requests[0], requests[1]]); } #[test] @@ -516,10 +404,10 @@ mod tests { builder.previous_kernel.gas_used = Gas::new(300, 300); // This call starts with 700 gas left - builder.public_call.public_inputs.start_gas_left = Gas::new(700, 700); + builder.public_call.start_gas_left = Gas::new(700, 700); // And uses 200, ending with 500 left - builder.public_call.public_inputs.end_gas_left = Gas::new(500, 500); + builder.public_call.end_gas_left = Gas::new(500, 500); // So the updated gas used by revertible must go up by 200, and non-revertible must stay the same let output = builder.execute(); @@ -532,7 +420,7 @@ mod tests { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); builder.public_call.is_execution_request = true; // don't need to check start gas for nested calls - builder.public_call.public_inputs.start_gas_left = Gas::new(100, 100); + builder.public_call.start_gas_left = Gas::new(100, 100); builder.failed(); } @@ -541,7 +429,7 @@ mod tests { fn validates_transaction_fee() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.transaction_fee = 10; + builder.public_call.transaction_fee = 10; builder.failed(); } @@ -550,7 +438,7 @@ mod tests { fn propagates_global_variables_if_empty() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.global_variables.block_number = 11; + builder.public_call.global_variables.block_number = 11; let public_inputs = builder.execute(); @@ -562,7 +450,7 @@ mod tests { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); builder.previous_kernel.global_variables.block_number = 10; - builder.public_call.public_inputs.global_variables.block_number = 11; + builder.public_call.global_variables.block_number = 11; builder.failed(); } @@ -589,7 +477,7 @@ mod tests { assert_eq(public_inputs.revert_code, 0); let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.revert_code = 1; + builder.public_call.revert_code = 1; let public_inputs = builder.execute(); assert_eq(public_inputs.revert_code, 1); @@ -602,23 +490,20 @@ mod tests { #[test] fn clears_stack_if_current_call_revert_code_is_set() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.revert_code = 1; - let public_call = builder.public_call.finish(); - let item = public_call.call_stack_item.get_compressed(); + builder.public_call.revert_code = 1; builder.previous_kernel.append_public_call_requests(2); - builder.previous_kernel.push_public_call_request(item); - builder.previous_kernel.append_public_teardown_call_request(); - builder.previous_kernel.append_public_teardown_call_request(); + builder.previous_kernel.append_public_teardown_call_requests(2); + let teardown_calls = builder.previous_kernel.public_teardown_call_stack.storage; - let previous_kernel = builder.previous_kernel.to_public_kernel_data(true); - let kernel = PublicKernelAppLogicCircuitPrivateInputs { previous_kernel, public_call }; - - let public_inputs = kernel.public_kernel_app_logic(); + let public_inputs = builder.execute(); - assert_eq(array_length(public_inputs.end.public_call_stack), 0); - assert_eq(array_length(public_inputs.public_teardown_call_stack), 2); + assert_array_eq(public_inputs.end.public_call_stack, []); + assert_array_eq( + public_inputs.public_teardown_call_stack, + [teardown_calls[0], teardown_calls[1]] + ); } #[test] diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_phase.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_phase.nr new file mode 100644 index 00000000000..af0421c8d3e --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_phase.nr @@ -0,0 +1,13 @@ +struct PublicKernelPhaseEnum { + SETUP: u8, + APP_LOGIC: u8, + TEARDOWN: u8, + TAIL: u8, +} + +global PublicKernelPhase = PublicKernelPhaseEnum { + SETUP: 0, + APP_LOGIC: 1, + TEARDOWN: 2, + TAIL: 3, +}; diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr index bc343e0d002..793f9083f0c 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr @@ -1,10 +1,18 @@ -use crate::common; -use dep::types::abis::{ - kernel_circuit_public_inputs::{PublicKernelCircuitPublicInputs, PublicKernelCircuitPublicInputsBuilder}, - public_kernel_data::PublicKernelData, public_call_data::PublicCallData +use crate::{ + components::{ + previous_kernel_validator::PreviousKernelValidator, + public_call_data_validator::PublicCallDataValidator, + public_kernel_output_composer::PublicKernelOutputComposer +}, + public_kernel_phase::PublicKernelPhase +}; +use dep::types::{ + abis::{ + kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, public_kernel_data::PublicKernelData, + public_call_data::PublicCallData +}, + constants::{PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX, PUBLIC_KERNEL_SETUP_INDEX} }; -use dep::types::utils::arrays::array_to_bounded_vec; -use dep::types::constants::{PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX, PUBLIC_KERNEL_SETUP_INDEX}; global ALLOWED_PREVIOUS_CIRCUITS = [ PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX, @@ -26,168 +34,105 @@ struct PublicKernelSetupCircuitPrivateInputs { } impl PublicKernelSetupCircuitPrivateInputs { - fn initialize_revert_code(self, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder) { - // since this phase is non-revertible, we must assert the public call did not revert - common::validate_public_call_non_revert(self.public_call); - circuit_outputs.revert_code = 0; - } - - fn initialize_values(self, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder) { - // initialise the end state with our provided previous kernel state - common::initialize_non_revertible_values(self.previous_kernel, circuit_outputs); - common::initialize_end_values(self.previous_kernel, circuit_outputs); - circuit_outputs.public_teardown_call_stack = array_to_bounded_vec(self.previous_kernel.public_inputs.public_teardown_call_stack); - } - - fn validate_inputs(self) { - let needs_setup = self.previous_kernel.public_inputs.needs_setup(); - assert(needs_setup == true, "Cannot run unnecessary setup circuit"); - } - - fn public_kernel_setup(self) -> PublicKernelCircuitPublicInputs { - if !dep::std::runtime::is_unconstrained() { - // Recursively verify the tube proof or a previous public kernel proof - self.previous_kernel.verify(); - // TODO(#7410) currently stubbed out until tube vk handled - // self.previous_kernel.validate_in_vk_tree(ALLOWED_PREVIOUS_CIRCUITS); - } - // construct the circuit outputs - let mut public_inputs = PublicKernelCircuitPublicInputsBuilder::empty(); - self.initialize_revert_code(&mut public_inputs); - - self.initialize_values(&mut public_inputs); - // validate the inputs common to all invocation circumstances - common::validate_inputs(self.public_call); - - // validate constants injected into the public call are correct or set them if this is the first public call - common::initialize_from_or_validate_public_call_variables(self.previous_kernel, self.public_call, &mut public_inputs); + fn execute(self) -> PublicKernelCircuitPublicInputs { + let phase = PublicKernelPhase.SETUP; - // validate the inputs unique to having a previous private kernel - self.validate_inputs(); + let previous_kernel_validator = PreviousKernelValidator::new(self.previous_kernel); + previous_kernel_validator.validate_phase(phase); + previous_kernel_validator.validate_proof(ALLOWED_PREVIOUS_CIRCUITS); - common::validate_start_gas(self.public_call, self.previous_kernel); - common::validate_transaction_fee_is_zero(self.public_call); + let call_data_validator = PublicCallDataValidator::new(self.public_call, phase); + call_data_validator.validate(); + call_data_validator.validate_against_previous_kernel(self.previous_kernel.public_inputs); - common::update_non_revertible_gas_used(self.public_call, &mut public_inputs); - - // Pops the item from the call stack and validates it against the current execution. - let call_request = public_inputs.end_non_revertible.public_call_stack.pop(); - common::validate_call_against_request(self.public_call, call_request); - - common::update_validation_requests(self.public_call, &mut public_inputs); - - common::update_end_non_revertible_call_stack(self.public_call, &mut public_inputs); - common::update_public_end_non_revertible_values(self.public_call, &mut public_inputs); - - public_inputs.finish() + // noir-fmt:ignore + PublicKernelOutputComposer::new_from_previous_kernel(self.previous_kernel.public_inputs) + .remove_top_call_request(phase) + .propagate_from_public_call(self.public_call.call_stack_item.public_inputs, phase) + .finish() } } mod tests { - use crate::{ - public_kernel_setup::{PublicKernelSetupCircuitPrivateInputs, ALLOWED_PREVIOUS_CIRCUITS}, - utils::{compute_public_data_reads, compute_public_data_update_requests} - }; + use crate::{public_kernel_setup::{PublicKernelSetupCircuitPrivateInputs, ALLOWED_PREVIOUS_CIRCUITS}}; use dep::types::{ abis::{ function_selector::FunctionSelector, gas::Gas, kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, max_block_number::MaxBlockNumber, - public_call_stack_item_compressed::PublicCallStackItemCompressed, + note_hash::NoteHash, public_call_stack_item_compressed::PublicCallStackItemCompressed, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - public_call_data::PublicCallData, read_request::ReadRequest, log_hash::ScopedLogHash + public_call_data::PublicCallData, public_kernel_data::PublicKernelData, + read_request::ReadRequest }, - address::{AztecAddress, EthAddress}, contract_class_id::ContractClassId, - contrakt::storage_read::StorageRead, - tests::{ - fixture_builder::FixtureBuilder, public_call_data_builder::PublicCallDataBuilder, - utils::assert_array_eq - }, - utils::{arrays::{array_eq, array_length}}, traits::is_empty - }; - use dep::types::constants::{ - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX, BASE_ROLLUP_INDEX + address::AztecAddress, constants::{PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX, BASE_ROLLUP_INDEX}, + contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, + tests::{fixture_builder::FixtureBuilder, utils::assert_array_eq}, traits::is_empty }; struct PublicKernelSetupCircuitPrivateInputsBuilder { previous_kernel: FixtureBuilder, previous_revertible: FixtureBuilder, - public_call: PublicCallDataBuilder, + public_call: FixtureBuilder, } impl PublicKernelSetupCircuitPrivateInputsBuilder { pub fn new() -> Self { let previous_kernel = FixtureBuilder::new().as_parent_contract().in_vk_tree(PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX); let previous_revertible = FixtureBuilder::new(); - let public_call = PublicCallDataBuilder::new(); + let mut public_call = FixtureBuilder::new().is_public_function(); + public_call.value_offset = 9999; // Add an offset so that the mock data won't be the same as the values in previous_kernel. PublicKernelSetupCircuitPrivateInputsBuilder { previous_kernel, previous_revertible, public_call } } - pub fn stub_teardown_call(&mut self) { - let teardown_call = PublicCallDataBuilder::new(); - let teardown_call = teardown_call.finish(); - let compressed_item = teardown_call.call_stack_item.get_compressed(); - self.previous_kernel.push_public_call_request(compressed_item); - } - - pub fn push_public_call(&mut self, public_call: PublicCallData) { - let compressed_item = public_call.call_stack_item.get_compressed(); - self.previous_kernel.push_public_call_request(compressed_item); - } - pub fn is_delegate_call(&mut self) -> Self { let _ = self.public_call.is_delegate_call(); *self } - pub fn get_current_public_data_reads(self) -> [PublicDataRead; MAX_PUBLIC_DATA_READS_PER_CALL] { - let read_requests = self.public_call.public_inputs.contract_storage_reads.storage; - compute_public_data_reads(self.public_call.contract_address, read_requests) + pub fn to_public_data_reads(self, contract_storage_reads: [StorageRead; N]) -> [PublicDataRead; N] { + let storage_contract_address = self.public_call.storage_contract_address; + contract_storage_reads.map(|r: StorageRead| PublicDataRead::from_contract_storage_read(storage_contract_address, r)) } - pub fn get_current_public_data_update_requests(self) -> [PublicDataUpdateRequest; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL] { - compute_public_data_update_requests( - self.public_call.contract_address, - self.public_call.public_inputs.contract_storage_update_requests.storage + pub fn to_public_data_update_requests( + self, + storage_update_requests: [StorageUpdateRequest; N] + ) -> [PublicDataUpdateRequest; N] { + let storage_contract_address = self.public_call.storage_contract_address; + storage_update_requests.map( + |r: StorageUpdateRequest| + PublicDataUpdateRequest::from_contract_storage_update_request(storage_contract_address, r) ) } pub fn execute(&mut self) -> PublicKernelCircuitPublicInputs { - // In order to run the setup circuit, we must have an enqueued public call for setup. - // In order to have an enqueued public call for setup, we must have an enqueued public call for teardown. + let public_call = self.public_call.to_public_call_data(); - // The teardown call is at the bottom of the call stack. - self.stub_teardown_call(); + // In order to run the setup circuit, we must have an enqueued public call for setup. + let compressed_item = public_call.call_stack_item.get_compressed(); + self.previous_kernel.push_public_call_request(compressed_item); - // Push the public call on top of the teardown call. - let setup_call = self.public_call.finish(); - self.push_public_call(setup_call); let mut previous_kernel = self.previous_kernel.to_public_kernel_data(false); previous_kernel.public_inputs.end = self.previous_revertible.to_public_accumulated_data(); // Run the kernel on the setup call - let kernel = PublicKernelSetupCircuitPrivateInputs { previous_kernel, public_call: setup_call }; - - kernel.public_kernel_setup() + let kernel = PublicKernelSetupCircuitPrivateInputs { previous_kernel, public_call }; + kernel.execute() } pub fn get_call_request_item(self) -> PublicCallStackItemCompressed { - let public_call = self.public_call.finish(); - public_call.call_stack_item.get_compressed() + self.public_call.to_public_call_stack_item().get_compressed() } pub fn failed_with_call_request_item(&mut self, item: PublicCallStackItemCompressed) { - // The teardown call is at the bottom of the call stack. - self.stub_teardown_call(); - - let public_call = self.public_call.finish(); + let public_call = self.public_call.to_public_call_data(); self.previous_kernel.push_public_call_request(item); let previous_kernel = self.previous_kernel.to_public_kernel_data(false); let kernel = PublicKernelSetupCircuitPrivateInputs { previous_kernel, public_call }; - let _ = kernel.public_kernel_setup(); + let _ = kernel.execute(); } pub fn succeeded(&mut self) { @@ -199,37 +144,6 @@ mod tests { } } - #[test] - fn only_valid_public_data_reads_should_be_propagated() { - let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); - builder.public_call.append_public_data_read_requests(1); - builder.public_call.append_empty_public_data_read_requests(1); - builder.public_call.append_public_data_read_requests(1); - let _ = builder.get_current_public_data_reads(); - - let _ = builder.execute(); - // TODO(fees) we don't yet handle non-revertible reads - // Only the 2 valid reads should have been propagated. - // let expected = [public_data_reads[0], public_data_reads[2]]; - // assert_array_eq(public_inputs.end.public_data_reads, expected); - } - - // TODO(fees) we don't yet handle non-revertible update requests - // #[test] - // fn only_valid_update_requests_should_be_propagated() { - // let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); - // builder.public_call.append_update_requests(1); - // builder.public_call.append_empty_update_requests(1); - // builder.public_call.append_update_requests(1); - // let public_data_update_requests = builder.get_current_public_data_update_requests(); - - // let public_inputs = builder.execute(); - - // // Only the 2 valid reads should have been propagated. - // let expected = [public_data_update_requests[0], public_data_update_requests[2]]; - // assert_array_eq(public_inputs.end.public_data_update_requests, expected); - // } - #[test(should_fail_with="Bytecode hash cannot be zero")] fn no_bytecode_hash_should_fail() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); @@ -241,6 +155,8 @@ mod tests { #[test(should_fail_with="Contract address cannot be zero")] fn contract_address_must_be_valid() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); + + builder.previous_kernel.append_public_call_requests(1); builder.public_call.contract_address = AztecAddress::zero(); builder.failed(); @@ -265,18 +181,12 @@ mod tests { #[test(should_fail_with="call stack item does not match item at the top of the call stack")] fn inconsistent_call_request_item_should_fail() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); - builder.stub_teardown_call(); - let public_call = builder.public_call.finish(); - let mut item = public_call.call_stack_item.get_compressed(); + let mut item = builder.get_call_request_item(); // Tweak the call stack item. item.args_hash += 1; - builder.previous_kernel.push_public_call_request(item); - let previous_kernel = builder.previous_kernel.to_public_kernel_data(false); - let kernel = PublicKernelSetupCircuitPrivateInputs { previous_kernel, public_call }; - - let _ = kernel.public_kernel_setup(); + builder.failed_with_call_request_item(item); } #[test(should_fail_with="call stack item does not match item at the top of the call stack")] @@ -295,7 +205,7 @@ mod tests { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); // Set the storage contract address to a wrong value. - builder.public_call.public_inputs.call_context.storage_contract_address.inner += 1; + builder.public_call.storage_contract_address.inner += 1; builder.failed(); } @@ -321,7 +231,7 @@ mod tests { fn previous_private_kernel_fails_if_incorrect_storage_contract_on_delegate_call() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new().is_delegate_call(); - builder.public_call.contract_address = builder.public_call.public_inputs.call_context.storage_contract_address; + builder.public_call.contract_address = builder.public_call.storage_contract_address; builder.failed(); } @@ -330,11 +240,11 @@ mod tests { fn incorrect_storage_contract_address_for_call_request_fails() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); - builder.public_call.append_public_call_requests_for_regular_calls(1); - let mut call_request = builder.public_call.public_inputs.public_call_requests.pop(); + builder.public_call.append_public_call_requests(1); + let mut call_request = builder.public_call.public_call_requests.pop(); // Change the caller contract address to be a different value. call_request.item.call_context.storage_contract_address.inner += 1; - builder.public_call.public_inputs.public_call_requests.push(call_request); + builder.public_call.public_call_requests.push(call_request); builder.failed(); } @@ -343,11 +253,11 @@ mod tests { fn incorrect_call_context_for_delegate_call_request_fails() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); - builder.public_call.append_public_call_requests_for_delegate_calls(1); - let mut call_request = builder.public_call.public_inputs.public_call_requests.pop(); + builder.public_call.append_public_call_requests_delegate(1); + let mut call_request = builder.public_call.public_call_requests.pop(); // Change the storage contract address to be the contract address. call_request.item.call_context.storage_contract_address = call_request.item.contract_address; - builder.public_call.public_inputs.public_call_requests.push(call_request); + builder.public_call.public_call_requests.push(call_request); builder.failed(); } @@ -364,65 +274,49 @@ mod tests { builder.previous_kernel.max_block_number = MaxBlockNumber::new(13); - builder.public_call.append_public_call_requests_for_regular_calls(2); - let storage = builder.public_call.public_inputs.public_call_requests.storage; + builder.public_call.append_public_call_requests(2); + let curr_calls = builder.public_call.public_call_requests.storage; - builder.stub_teardown_call(); - let non_revertible_call_stack = [ - builder.previous_kernel.public_call_requests.get(0), - storage[0], storage[1] - ]; + builder.previous_kernel.append_public_call_requests(1); + let prev_calls = builder.previous_kernel.public_call_requests.storage; - builder.public_call.append_update_requests(2); - let storage = builder.get_current_public_data_update_requests(); - let _update_requests = [storage[0], storage[1]]; + builder.public_call.append_contract_storage_update_requests(2); + let update_requests = builder.public_call.contract_storage_update_requests.storage; - builder.public_call.append_public_data_read_requests(3); - let storage = builder.get_current_public_data_reads(); - let _read_requests = [storage[0], storage[1], storage[2]]; - - // Push the public call on top of the teardown call. - let setup_call = builder.public_call.finish(); - builder.push_public_call(setup_call); - let previous_kernel = builder.previous_kernel.to_public_kernel_data(false); + builder.public_call.append_contract_storage_read_requests(3); + let read_requests = builder.public_call.contract_storage_reads.storage; - // Run the kernel on the setup call - let kernel = PublicKernelSetupCircuitPrivateInputs { previous_kernel, public_call: setup_call }; - - let public_inputs = kernel.public_kernel_setup(); + let public_inputs = builder.execute(); assert_eq(public_inputs.validation_requests.for_rollup.max_block_number.unwrap(), 13); assert_array_eq( public_inputs.end_non_revertible.public_call_stack, - non_revertible_call_stack + [prev_calls[0], curr_calls[0], curr_calls[1]] + ); + assert_array_eq( + public_inputs.end_non_revertible.public_data_update_requests, + builder.to_public_data_update_requests([update_requests[0], update_requests[1]]) + ); + assert_array_eq( + public_inputs.validation_requests.public_data_reads, + builder.to_public_data_reads([read_requests[0], read_requests[1], read_requests[2]]) ); - // TODO(fees) we don't yet handle non-revertible update requests - // assert_array_eq( - // public_inputs.end.public_data_update_requests, - // update_requests - // ); - // assert_array_eq(public_inputs.end.public_data_reads, read_requests); } - // TODO: Find another way to test this. Currently it will crash because we are popping from an empty array: - // The application panicked (crashed). Message: Expected array index to fit in u64 - // #[test(should_fail_with="Public call stack can not be empty")] - // fn private_previous_kernel_empty_public_call_stack_should_fail() { - // let builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); - // let previous_kernel = builder.previous_kernel.finish(); - // let kernel = PublicKernelSetupCircuitPrivateInputs { - // previous_kernel, - // public_call: builder.public_call.finish(), - // }; - - // let _ = kernel.public_kernel_setup(); - // } + #[test(should_fail_with="Cannot run unnecessary setup circuit")] + fn previous_kernel_empty_public_call_stack_should_fail() { + let builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); + let previous_kernel = builder.previous_kernel.to_public_kernel_data(false); + let public_call = builder.public_call.to_public_call_data(); + let kernel = PublicKernelSetupCircuitPrivateInputs { previous_kernel, public_call }; + let _ = kernel.execute(); + } #[test(should_fail_with="No contract storage update requests are allowed for static calls")] fn previous_private_kernel_fails_if_contract_storage_update_requests_on_static_call() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.call_context.is_static_call = true; - builder.public_call.append_update_requests(1); + builder.public_call.is_static_call = true; + builder.public_call.append_contract_storage_update_requests(1); builder.failed(); } @@ -434,7 +328,7 @@ mod tests { // Logs for the current call stack. let unencrypted_logs_hash = 26; let unencrypted_log_preimages_length = 50; - builder.public_call.set_unencrypted_logs(unencrypted_logs_hash, unencrypted_log_preimages_length); + builder.public_call.add_unencrypted_log_hash(unencrypted_logs_hash, unencrypted_log_preimages_length); // Logs for the previous call stack. let prev_encrypted_logs_hash = 80; @@ -448,59 +342,42 @@ mod tests { ); let prev_data = builder.previous_kernel.to_public_accumulated_data(); - let expected_unencrypted_logs = [ - prev_data.unencrypted_logs_hashes[0], ScopedLogHash { - log_hash: builder.public_call.public_inputs.unencrypted_logs_hashes.storage[0], - contract_address: builder.public_call.contract_address - } - ]; + let expected_unencrypted_logs = [prev_data.unencrypted_logs_hashes[0], builder.public_call.unencrypted_logs_hashes.storage[0]]; // we assume the encrypted log is already siloed from private kernels let expected_encrypted_logs = [prev_data.encrypted_logs_hashes[0]]; let public_inputs = builder.execute(); - assert( - array_eq( - public_inputs.end_non_revertible.encrypted_logs_hashes, - expected_encrypted_logs - ) + assert_array_eq( + public_inputs.end_non_revertible.encrypted_logs_hashes, + expected_encrypted_logs ); - assert( - array_eq( - public_inputs.end_non_revertible.unencrypted_logs_hashes, - expected_unencrypted_logs - ) + assert_array_eq( + public_inputs.end_non_revertible.unencrypted_logs_hashes, + expected_unencrypted_logs ); } #[test] fn propagate_nullifier_non_existent_read_requests() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); - let storage_contract_address = builder.public_call.public_inputs.call_context.storage_contract_address; + let storage_contract_address = builder.public_call.storage_contract_address; - let request_0 = ReadRequest { value: 123, counter: 4567 }; - builder.public_call.public_inputs.nullifier_non_existent_read_requests.push(request_0); - let request_1 = ReadRequest { value: 777888, counter: 90 }; - builder.public_call.public_inputs.nullifier_non_existent_read_requests.push(request_1); + let request_0 = ReadRequest { value: 123, counter: 4567 }.scope(storage_contract_address); + builder.public_call.nullifier_non_existent_read_requests.push(request_0); + let request_1 = ReadRequest { value: 777888, counter: 90 }.scope(storage_contract_address); + builder.public_call.nullifier_non_existent_read_requests.push(request_1); let public_inputs = builder.execute(); let end_requests = public_inputs.validation_requests.nullifier_non_existent_read_requests; - assert_eq(array_length(end_requests), 2); - - let request = end_requests[0]; - assert_eq(request.read_request, request_0); - assert_eq(request.contract_address, storage_contract_address); - - let request = end_requests[1]; - assert_eq(request.read_request, request_1); - assert_eq(request.contract_address, storage_contract_address); + assert_array_eq(end_requests, [request_0, request_1]); } #[test(should_fail_with="Public call cannot be reverted")] fn fails_if_public_call_reverted() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.revert_code = 1; + builder.public_call.revert_code = 1; builder.failed(); } @@ -519,10 +396,10 @@ mod tests { builder.previous_kernel.gas_used = Gas::new(200, 200); // So this call starts with 700 gas left - builder.public_call.public_inputs.start_gas_left = Gas::new(700, 700); + builder.public_call.start_gas_left = Gas::new(700, 700); // And uses 300, ending with 400 left - builder.public_call.public_inputs.end_gas_left = Gas::new(400, 400); + builder.public_call.end_gas_left = Gas::new(400, 400); // So the updated gas used by non-revertible must go up by 300, and revertible must stay the same let output = builder.execute(); @@ -535,7 +412,7 @@ mod tests { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); builder.public_call.is_execution_request = true; // don't need to check start gas for nested calls - builder.public_call.public_inputs.start_gas_left = Gas::new(100, 100); + builder.public_call.start_gas_left = Gas::new(100, 100); builder.failed(); } @@ -544,7 +421,7 @@ mod tests { fn validates_transaction_fee() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.transaction_fee = 10; + builder.public_call.transaction_fee = 10; builder.failed(); } @@ -553,7 +430,7 @@ mod tests { fn propagates_global_variables_if_empty() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.global_variables.block_number = 11; + builder.public_call.global_variables.block_number = 11; let public_inputs = builder.execute(); @@ -565,7 +442,7 @@ mod tests { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); builder.previous_kernel.global_variables.block_number = 10; - builder.public_call.public_inputs.global_variables.block_number = 11; + builder.public_call.global_variables.block_number = 11; builder.failed(); } @@ -588,23 +465,33 @@ mod tests { #[test] fn propagate_call_stacks_on_success() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.revert_code = 0; - let public_call = builder.public_call.finish(); - let item = public_call.call_stack_item.get_compressed(); - builder.previous_kernel.push_public_call_request(item); - builder.previous_kernel.push_public_call_request(item); + builder.previous_kernel.append_public_call_requests(1); + let prev_non_rev_calls = builder.previous_kernel.public_call_requests.storage; - builder.previous_kernel.push_public_teardown_call_request(item); - builder.previous_kernel.push_public_teardown_call_request(item); + builder.previous_revertible.append_public_call_requests(2); + let prev_rev_calls = builder.previous_revertible.public_call_requests.storage; - let previous_kernel = builder.previous_kernel.to_public_kernel_data(false); - let kernel = PublicKernelSetupCircuitPrivateInputs { previous_kernel, public_call }; + builder.previous_kernel.append_public_teardown_call_requests(1); + let prev_teardoen_calls = builder.previous_kernel.public_teardown_call_stack.storage; - let public_inputs = kernel.public_kernel_setup(); + builder.public_call.append_public_call_requests(2); + let curr_calls = builder.public_call.public_call_requests.storage; - assert_eq(array_length(public_inputs.end_non_revertible.public_call_stack), 1); - assert_eq(array_length(public_inputs.public_teardown_call_stack), 2); + let public_inputs = builder.execute(); + + assert_array_eq( + public_inputs.end_non_revertible.public_call_stack, + [prev_non_rev_calls[0], curr_calls[0], curr_calls[1]] + ); + assert_array_eq( + public_inputs.end.public_call_stack, + [prev_rev_calls[0], prev_rev_calls[1]] + ); + assert_array_eq( + public_inputs.public_teardown_call_stack, + [prev_teardoen_calls[0]] + ); } #[test] diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr index 84279fd1003..7cb0cff6bea 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr @@ -1,22 +1,21 @@ -use crate::common; +use crate::{ + components::{ + previous_kernel_validator::PreviousKernelValidator, + public_tail_output_composer::{PublicTailOutputComposer, CombineHints} +}, + public_kernel_phase::PublicKernelPhase +}; use dep::reset_kernel_lib::{ NullifierReadRequestHints, NullifierNonExistentReadRequestHints, PublicDataReadRequestHints, PublicValidationRequestProcessor }; use dep::types::{ - abis::{ - accumulated_data::{CombinedAccumulatedData, CombineHints}, - kernel_circuit_public_inputs::KernelCircuitPublicInputs, public_kernel_data::PublicKernelData, - public_data_update_request::PublicDataUpdateRequest, side_effect::Ordered -}, + abis::{kernel_circuit_public_inputs::KernelCircuitPublicInputs, public_kernel_data::PublicKernelData}, constants::{ - MAX_NOTE_HASHES_PER_TX, MAX_PUBLIC_DATA_HINTS, MAX_NULLIFIER_READ_REQUESTS_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PUBLIC_KERNEL_SETUP_INDEX, PUBLIC_KERNEL_APP_LOGIC_INDEX, - PUBLIC_KERNEL_TEARDOWN_INDEX + MAX_PUBLIC_DATA_HINTS, MAX_NULLIFIER_READ_REQUESTS_PER_TX, PUBLIC_KERNEL_SETUP_INDEX, + PUBLIC_KERNEL_APP_LOGIC_INDEX, PUBLIC_KERNEL_TEARDOWN_INDEX }, - data::public_data_hint::PublicDataHint, - merkle_tree::{conditionally_assert_check_membership, MembershipWitness}, - partial_state_reference::PartialStateReference, utils::{arrays::array_length}, address::AztecAddress + data::public_data_hint::PublicDataHint, partial_state_reference::PartialStateReference }; global ALLOWED_PREVIOUS_CIRCUITS = [ @@ -36,72 +35,31 @@ struct PublicKernelTailCircuitPrivateInputs { } impl PublicKernelTailCircuitPrivateInputs { - fn validate_inputs(self) { - let previous_public_inputs = self.previous_kernel.public_inputs; - assert(previous_public_inputs.needs_setup() == false, "Previous kernel needs setup"); - assert(previous_public_inputs.needs_app_logic() == false, "Previous kernel needs app logic"); - assert(previous_public_inputs.needs_teardown() == false, "Previous kernel needs teardown"); - assert_eq( - array_length(previous_public_inputs.end.public_call_stack), 0, "Public call stack must be empty when executing the tail circuit" - ); - assert_eq( - array_length(previous_public_inputs.end_non_revertible.public_call_stack), 0, "Public call stack must be empty when executing the tail circuit" - ); - } - - fn validate_public_data_hints(self) { - let public_data_tree_root = self.start_state.public_data_tree.root; - for i in 0..self.public_data_hints.len() { - self.public_data_hints[i].validate(public_data_tree_root); - } - } - - fn propagate_accumulated_data(self) -> CombinedAccumulatedData { - let previous_public_inputs = self.previous_kernel.public_inputs; - CombinedAccumulatedData::combine( - previous_public_inputs.end_non_revertible, - previous_public_inputs.end, - self.combine_hints - ) - } - pub fn public_kernel_tail(self) -> KernelCircuitPublicInputs { - if !dep::std::runtime::is_unconstrained() { - // Recursively verify the tube proof or a previous public kernel proof - self.previous_kernel.verify(); - // TODO(#7410) currently stubbed out until tube vk handled - // self.previous_kernel.validate_in_vk_tree(ALLOWED_PREVIOUS_CIRCUITS); - } - self.validate_inputs(); - - self.validate_public_data_hints(); + let previous_kernel_validator = PreviousKernelValidator::new(self.previous_kernel); + previous_kernel_validator.validate_phase(PublicKernelPhase.TAIL); + previous_kernel_validator.validate_proof(ALLOWED_PREVIOUS_CIRCUITS); let previous_public_inputs = self.previous_kernel.public_inputs; - let request_processor = PublicValidationRequestProcessor::new( + PublicValidationRequestProcessor::new( previous_public_inputs, self.nullifier_read_request_hints, self.nullifier_non_existent_read_request_hints, self.start_state.nullifier_tree.root, self.public_data_read_request_hints, - self.public_data_hints - ); - request_processor.validate(); - - let end = self.propagate_accumulated_data(); + self.public_data_hints, + self.start_state.public_data_tree.root + ).validate(); - KernelCircuitPublicInputs { - rollup_validation_requests: previous_public_inputs.validation_requests.for_rollup, - end, - constants: previous_public_inputs.constants, - start_state: self.start_state, - revert_code: previous_public_inputs.revert_code, - fee_payer: previous_public_inputs.fee_payer - } + PublicTailOutputComposer::new(previous_public_inputs, self.start_state, self.combine_hints).finish() } } mod tests { - use crate::public_kernel_tail::{ALLOWED_PREVIOUS_CIRCUITS, PublicKernelTailCircuitPrivateInputs}; + use crate::{ + components::public_tail_output_composer::CombineHints, + public_kernel_tail::{ALLOWED_PREVIOUS_CIRCUITS, PublicKernelTailCircuitPrivateInputs} + }; use dep::reset_kernel_lib::{ tests::{ nullifier_non_existent_read_request_hints_builder::NullifierNonExistentReadRequestHintsBuilder, @@ -114,9 +72,8 @@ mod tests { abis::{ kernel_circuit_public_inputs::KernelCircuitPublicInputs, public_kernel_data::PublicKernelData, nullifier::ScopedNullifier, nullifier_leaf_preimage::NullifierLeafPreimage, - accumulated_data::{CombinedAccumulatedData, CombineHints}, - public_data_update_request::PublicDataUpdateRequest, note_hash::ScopedNoteHash, - log_hash::{ScopedLogHash, LogHash} + accumulated_data::CombinedAccumulatedData, public_data_update_request::PublicDataUpdateRequest, + note_hash::ScopedNoteHash, log_hash::{ScopedLogHash, LogHash} }, address::AztecAddress, constants::{ diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr index e8ff3f09a8c..84be93df240 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr @@ -1,12 +1,20 @@ -use crate::common; -use dep::types::abis::{ - kernel_circuit_public_inputs::{PublicKernelCircuitPublicInputs, PublicKernelCircuitPublicInputsBuilder}, - public_kernel_data::PublicKernelData, public_call_data::PublicCallData, gas_fees::GasFees +use crate::{ + components::{ + previous_kernel_validator::PreviousKernelValidator, + public_call_data_validator::PublicCallDataValidator, + public_kernel_output_composer::PublicKernelOutputComposer +}, + public_kernel_phase::PublicKernelPhase }; -use dep::types::utils::arrays::array_to_bounded_vec; -use dep::types::constants::{ +use dep::types::{ + abis::{ + kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, public_kernel_data::PublicKernelData, + public_call_data::PublicCallData +}, + constants::{ PUBLIC_KERNEL_SETUP_INDEX, PUBLIC_KERNEL_APP_LOGIC_INDEX, PUBLIC_KERNEL_TEARDOWN_INDEX, PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX +} }; struct PublicKernelTeardownCircuitPrivateInputs { @@ -22,174 +30,49 @@ global ALLOWED_PREVIOUS_CIRCUITS = [ ]; impl PublicKernelTeardownCircuitPrivateInputs { - fn initialize_revert_code(self, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder) { - // See https://docs.aztec.network/protocol-specs/gas-and-fees/kernel-tracking#handling-reverts - let previous_kernel_revert_code = self.previous_kernel.public_inputs.revert_code; - let public_call_revert_code = self.public_call.call_stack_item.public_inputs.revert_code; - if previous_kernel_revert_code.eq(0) & public_call_revert_code.eq(0) { - circuit_outputs.revert_code = 0; - } else if previous_kernel_revert_code.eq(1) & public_call_revert_code.eq(0) { - // Case where we carry forward a revert code from app logic - circuit_outputs.revert_code = 1; - } else if previous_kernel_revert_code.eq(0) & !public_call_revert_code.eq(0) { - // Case where there is a new error in teardown - circuit_outputs.revert_code = 2; - } else if previous_kernel_revert_code.eq(1) & !public_call_revert_code.eq(0) { - // Case where there is an error in both app logic and teardown - circuit_outputs.revert_code = 3; - } - } + fn execute(self) -> PublicKernelCircuitPublicInputs { + let phase = PublicKernelPhase.TEARDOWN; - fn validate_inputs(self) { - // Currently the nested calls will be pushed to the public call stack and need_setup will return true. - // This should not be the case when nested calls are handled in avm. - // But we should also consider merging this and the setup circuit and have one circuit that deals with non-revertibles. - let needs_setup = self.previous_kernel.public_inputs.needs_setup(); - assert(needs_setup == false, "Cannot run teardown circuit before setup circuit"); - let needs_app_logic = self.previous_kernel.public_inputs.needs_app_logic(); - assert(needs_app_logic == false, "Cannot run teardown circuit before app logic circuit"); - let needs_teardown = self.previous_kernel.public_inputs.needs_teardown(); - assert(needs_teardown == true, "Cannot run unnecessary teardown circuit"); - } - - // Validates that the start gas injected into the app circuit matches the teardown gas limits set by the user - fn validate_start_gas(self) { - // If this is a nested call (not an execution request), the start gas is correct as long as the - // call being processed by this kernel iteration matches the call at the top of the callstack - // as per the previous kernel's outputs. - // An execution request's start gas is the remaining gas left in the transaction after the previous kernel. - // A nested call's start gas is the gas allocated to it by its caller and placed in the callstack. - if (self.public_call.call_stack_item.is_execution_request) { - let public_call_start_gas = self.public_call.call_stack_item.public_inputs.start_gas_left; - let teardown_gas_limit = self.previous_kernel.public_inputs.constants.tx_context.gas_settings.teardown_gas_limits; - assert( - public_call_start_gas == teardown_gas_limit, "Start gas for teardown phase does not match teardown gas allocation" - ); - } - } + let previous_kernel_validator = PreviousKernelValidator::new(self.previous_kernel); + previous_kernel_validator.validate_phase(phase); + previous_kernel_validator.validate_proof(ALLOWED_PREVIOUS_CIRCUITS); - // Validates the transaction fee injected into the app circuit is properly computed from gas_used and block gas_fees - fn validate_transaction_fee(self, public_inputs: PublicKernelCircuitPublicInputsBuilder) { - let transaction_fee = self.public_call.call_stack_item.public_inputs.transaction_fee; - // Note that teardown_gas is already included in end.gas_used as it was injected by the private kernel - let total_gas_used = self.previous_kernel.public_inputs.end.gas_used - + self.previous_kernel.public_inputs.end_non_revertible.gas_used; - let block_gas_fees = public_inputs.constants.global_variables.gas_fees; - let inclusion_fee = self.previous_kernel.public_inputs.constants.tx_context.gas_settings.inclusion_fee; - let computed_transaction_fee = total_gas_used.compute_fee(block_gas_fees) + inclusion_fee; - - // dep::types::debug_log::debug_log_format( - // "Validating tx fee: end.gas_used.da={0} end.gas_used.l2={1} non_revertible.gas_used.da={2} non_revertible.gas_used.l2={3} block_fee_per_gas.da={4} block_fee_per_gas.l2={5} inclusion_fee={6} computed={7} actual={8}", - // [ - // self.previous_kernel.public_inputs.end.gas_used.da_gas as Field, - // self.previous_kernel.public_inputs.end.gas_used.l2_gas as Field, - // self.previous_kernel.public_inputs.end_non_revertible.gas_used.da_gas as Field, - // self.previous_kernel.public_inputs.end_non_revertible.gas_used.l2_gas as Field, - // block_gas_fees.fee_per_da_gas as Field, - // block_gas_fees.fee_per_l2_gas as Field, - // inclusion_fee, - // computed_transaction_fee, - // transaction_fee - // ] - // ); - - assert( - transaction_fee == computed_transaction_fee, "Transaction fee on teardown phase does not match expected value" - ); - } - - fn initialize_end_values(self, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder) { - common::initialize_end_values(self.previous_kernel, circuit_outputs); - // unlike app logic, only pass forward the teardown call stack if there is no new error - circuit_outputs.public_teardown_call_stack = array_to_bounded_vec(self.previous_kernel.public_inputs.public_teardown_call_stack); - } - - fn public_kernel_teardown(self) -> PublicKernelCircuitPublicInputs { - if !dep::std::runtime::is_unconstrained() { - // verify the previous kernel proof - self.previous_kernel.verify(); - // TODO(#7410) currently stubbed out until tube vk handled - // self.previous_kernel.validate_in_vk_tree(ALLOWED_PREVIOUS_CIRCUITS); - } - - // construct the circuit outputs - let mut public_inputs = PublicKernelCircuitPublicInputsBuilder::empty(); - self.initialize_revert_code(&mut public_inputs); - - // initialise the end state with our provided previous kernel state - common::initialize_non_revertible_values(self.previous_kernel, &mut public_inputs); - - // validate the inputs common to all invocation circumstances - common::validate_inputs(self.public_call); - - // validate constants injected into the public call are correct or set them if this is the first public call - common::initialize_from_or_validate_public_call_variables(self.previous_kernel, self.public_call, &mut public_inputs); - - // validate the inputs unique to having a previous private kernel - self.validate_inputs(); - - self.validate_start_gas(); - self.validate_transaction_fee(public_inputs); - - common::update_validation_requests(self.public_call, &mut public_inputs); - - // there was no revert, or a revert in app logic - if public_inputs.revert_code.eq(0) | public_inputs.revert_code.eq(1) { - self.initialize_end_values(&mut public_inputs); - // Pops the item from the call stack and validates it against the current execution. - let call_request = public_inputs.public_teardown_call_stack.pop(); - common::validate_call_against_request(self.public_call, call_request); - common::update_teardown_call_stack(self.public_call, &mut public_inputs); - common::update_public_end_values(self.public_call, &mut public_inputs); - } else { - let mut remaining_calls = array_to_bounded_vec(self.previous_kernel.public_inputs.public_teardown_call_stack); - let reverted_call_request = remaining_calls.pop(); - - assert( - reverted_call_request.item == self.public_call.call_stack_item.get_compressed(), "call stack item does not match item at the top of the call stack" - ); - } + let call_data_validator = PublicCallDataValidator::new(self.public_call, phase); + call_data_validator.validate(); + call_data_validator.validate_against_previous_kernel(self.previous_kernel.public_inputs); - public_inputs.finish() + // noir-fmt:ignore + PublicKernelOutputComposer::new_from_previous_kernel(self.previous_kernel.public_inputs) + .remove_top_call_request(phase) + .propagate_from_public_call(self.public_call.call_stack_item.public_inputs, phase) + .finish() } } mod tests { - use crate::{ - public_kernel_teardown::{ALLOWED_PREVIOUS_CIRCUITS, PublicKernelTeardownCircuitPrivateInputs}, - utils::{compute_public_data_reads, compute_public_data_update_requests} - }; + use crate::{public_kernel_teardown::{ALLOWED_PREVIOUS_CIRCUITS, PublicKernelTeardownCircuitPrivateInputs}}; use dep::types::{ abis::{ function_selector::FunctionSelector, gas::Gas, kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, - public_call_stack_item_compressed::PublicCallStackItemCompressed, - public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - log_hash::ScopedLogHash + public_call_stack_item_compressed::PublicCallStackItemCompressed }, - address::{AztecAddress, EthAddress}, contract_class_id::ContractClassId, - contrakt::storage_read::StorageRead, - tests::{fixture_builder::FixtureBuilder, public_call_data_builder::PublicCallDataBuilder}, - utils::{arrays::{array_eq, array_length}}, traits::is_empty - }; - use dep::types::constants::{ - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX, BASE_ROLLUP_INDEX + address::AztecAddress, constants::{PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX, BASE_ROLLUP_INDEX}, + tests::{fixture_builder::FixtureBuilder, utils::assert_array_eq}, traits::is_empty }; struct PublicKernelTeardownCircuitPrivateInputsBuilder { previous_kernel: FixtureBuilder, - previous_revertible: FixtureBuilder, - public_call: PublicCallDataBuilder, + public_call: FixtureBuilder, } impl PublicKernelTeardownCircuitPrivateInputsBuilder { pub fn new() -> Self { let previous_kernel = FixtureBuilder::new().as_parent_contract().in_vk_tree(PRIVATE_KERNEL_TAIL_TO_PUBLIC_INDEX); - let previous_revertible = FixtureBuilder::new(); - let public_call = PublicCallDataBuilder::new(); + let mut public_call = FixtureBuilder::new().is_public_function(); + public_call.value_offset = 9999; // Add an offset so that the mock data won't be the same as the values in previous_kernel. - PublicKernelTeardownCircuitPrivateInputsBuilder { previous_kernel, previous_revertible, public_call } + PublicKernelTeardownCircuitPrivateInputsBuilder { previous_kernel, public_call } } pub fn is_delegate_call(&mut self) -> Self { @@ -197,20 +80,8 @@ mod tests { *self } - pub fn get_current_public_data_reads(self) -> [PublicDataRead; MAX_PUBLIC_DATA_READS_PER_CALL] { - let read_requests = self.public_call.public_inputs.contract_storage_reads.storage; - compute_public_data_reads(self.public_call.contract_address, read_requests) - } - - pub fn get_current_public_data_update_requests(self) -> [PublicDataUpdateRequest; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL] { - compute_public_data_update_requests( - self.public_call.contract_address, - self.public_call.public_inputs.contract_storage_update_requests.storage - ) - } - pub fn execute(&mut self) -> PublicKernelCircuitPublicInputs { - let public_call = self.public_call.finish(); + let public_call = self.public_call.to_public_call_data(); // Adjust the call stack item hash for the current call in the previous iteration. let compressed = public_call.call_stack_item.get_compressed(); self.previous_kernel.push_public_teardown_call_request(compressed); @@ -218,20 +89,19 @@ mod tests { let kernel = PublicKernelTeardownCircuitPrivateInputs { previous_kernel, public_call }; - kernel.public_kernel_teardown() + kernel.execute() } pub fn get_call_request_item(self) -> PublicCallStackItemCompressed { - let public_call = self.public_call.finish(); - public_call.call_stack_item.get_compressed() + self.public_call.to_public_call_stack_item().get_compressed() } pub fn failed_with_call_request_item(&mut self, item: PublicCallStackItemCompressed) { - let public_call = self.public_call.finish(); + let public_call = self.public_call.to_public_call_data(); self.previous_kernel.push_public_teardown_call_request(item); let previous_kernel = self.previous_kernel.to_public_kernel_data(true); let kernel = PublicKernelTeardownCircuitPrivateInputs { previous_kernel, public_call }; - let _ = kernel.public_kernel_teardown(); + let _ = kernel.execute(); } pub fn succeeded(&mut self) { @@ -254,6 +124,8 @@ mod tests { #[test(should_fail_with="Contract address cannot be zero")] fn contract_address_must_be_valid() { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); + + builder.previous_kernel.append_public_teardown_call_requests(1); builder.public_call.contract_address = AztecAddress::zero(); builder.failed(); @@ -278,17 +150,12 @@ mod tests { #[test(should_fail_with="call stack item does not match item at the top of the call stack")] fn inconsistent_call_request_item_should_fail() { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); - let public_call = builder.public_call.finish(); - let mut item = public_call.call_stack_item.get_compressed(); + let mut item = builder.get_call_request_item(); // Tweak the call stack item. item.args_hash += 1; - builder.previous_kernel.push_public_teardown_call_request(item); - let previous_kernel = builder.previous_kernel.to_public_kernel_data(true); - - let kernel = PublicKernelTeardownCircuitPrivateInputs { previous_kernel, public_call }; - let _ = kernel.public_kernel_teardown(); + builder.failed_with_call_request_item(item); } #[test(should_fail_with="call stack item does not match item at the top of the call stack")] @@ -307,7 +174,7 @@ mod tests { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); // Set the storage contract address to a wrong value. - builder.public_call.public_inputs.call_context.storage_contract_address.inner += 1; + builder.public_call.storage_contract_address.inner += 1; builder.failed(); } @@ -344,7 +211,7 @@ mod tests { fn previous_private_kernel_fails_if_incorrect_storage_contract_on_delegate_call() { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new().is_delegate_call(); - builder.public_call.contract_address = builder.public_call.public_inputs.call_context.storage_contract_address; + builder.public_call.contract_address = builder.public_call.storage_contract_address; builder.failed(); } @@ -353,11 +220,11 @@ mod tests { fn incorrect_storage_contract_address_for_call_request_fails() { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); - builder.public_call.append_public_call_requests_for_regular_calls(1); - let mut call_request = builder.public_call.public_inputs.public_call_requests.pop(); + builder.public_call.append_public_call_requests(1); + let mut call_request = builder.public_call.public_call_requests.pop(); // Change the caller contract address to be a different value. call_request.item.call_context.storage_contract_address.inner += 1; - builder.public_call.public_inputs.public_call_requests.push(call_request); + builder.public_call.public_call_requests.push(call_request); builder.failed(); } @@ -366,11 +233,11 @@ mod tests { fn incorrect_call_context_for_delegate_call_request_fails() { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); - builder.public_call.append_public_call_requests_for_delegate_calls(1); - let mut call_request = builder.public_call.public_inputs.public_call_requests.pop(); + builder.public_call.append_public_call_requests_delegate(1); + let mut call_request = builder.public_call.public_call_requests.pop(); // Change the storage contract address to be the target contract address. call_request.item.call_context.storage_contract_address = call_request.item.contract_address; - builder.public_call.public_inputs.public_call_requests.push(call_request); + builder.public_call.public_call_requests.push(call_request); builder.failed(); } @@ -385,20 +252,20 @@ mod tests { fn private_previous_kernel_non_empty_private_call_stack_should_fail() { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); - let public_call = builder.public_call.finish(); + let public_call = builder.public_call.to_public_call_data(); // Don't push a call for teardown let previous_kernel = builder.previous_kernel.to_public_kernel_data(true); let kernel = PublicKernelTeardownCircuitPrivateInputs { previous_kernel, public_call }; - let _ = kernel.public_kernel_teardown(); + let _ = kernel.execute(); } #[test(should_fail_with="No contract storage update requests are allowed for static calls")] fn previous_private_kernel_fails_if_contract_storage_update_requests_on_static_call() { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.call_context.is_static_call = true; - builder.public_call.append_update_requests(1); + builder.public_call.is_static_call = true; + builder.public_call.append_contract_storage_update_requests(1); builder.failed(); } @@ -408,44 +275,27 @@ mod tests { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); // Logs for the current call stack. - let unencrypted_logs_hash = 26; - let unencrypted_log_preimages_length = 50; - builder.public_call.set_unencrypted_logs(unencrypted_logs_hash, unencrypted_log_preimages_length); + builder.public_call.append_unencrypted_log_hashes(1); + let curr_data = builder.public_call.to_public_accumulated_data(); // Logs for the previous call stack. - let prev_encrypted_logs_hash = 80; - let prev_encrypted_log_preimages_length = 13; - let prev_unencrypted_logs_hash = 956; - let prev_unencrypted_log_preimages_length = 24; - builder.previous_kernel.add_encrypted_log_hash(prev_encrypted_logs_hash, prev_encrypted_log_preimages_length); - builder.previous_kernel.add_unencrypted_log_hash( - prev_unencrypted_logs_hash, - prev_unencrypted_log_preimages_length - ); + builder.previous_kernel.append_encrypted_log_hashes(1); + builder.previous_kernel.append_unencrypted_log_hashes(1); let prev_data = builder.previous_kernel.to_public_accumulated_data(); - let expected_unencrypted_logs = [ - prev_data.unencrypted_logs_hashes[0], ScopedLogHash { - log_hash: builder.public_call.public_inputs.unencrypted_logs_hashes.storage[0], - contract_address: builder.public_call.contract_address - } - ]; + let expected_unencrypted_logs = [prev_data.unencrypted_logs_hashes[0], curr_data.unencrypted_logs_hashes[0]]; // we assume the encrypted log is already siloed from private kernels let expected_encrypted_logs = [prev_data.encrypted_logs_hashes[0]]; let public_inputs = builder.execute(); - assert( - array_eq( - public_inputs.end.encrypted_logs_hashes, - expected_encrypted_logs - ) + assert_array_eq( + public_inputs.end.encrypted_logs_hashes, + expected_encrypted_logs ); - assert( - array_eq( - public_inputs.end.unencrypted_logs_hashes, - expected_unencrypted_logs - ) + assert_array_eq( + public_inputs.end.unencrypted_logs_hashes, + expected_unencrypted_logs ); } @@ -454,7 +304,7 @@ mod tests { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); builder.public_call.is_execution_request = true; // don't need to check start gas for nested calls - builder.public_call.public_inputs.start_gas_left = Gas::new(10, 30); + builder.public_call.start_gas_left = Gas::new(10, 30); builder.failed(); } @@ -462,7 +312,7 @@ mod tests { #[test(should_fail_with="Transaction fee on teardown phase does not match expected value")] fn validates_transaction_fee() { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.transaction_fee = 1234; + builder.public_call.transaction_fee = 1234; builder.failed(); } @@ -471,7 +321,7 @@ mod tests { fn propagates_global_variables_if_empty() { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.global_variables.block_number = 11; + builder.public_call.global_variables.block_number = 11; let public_inputs = builder.execute(); @@ -483,7 +333,7 @@ mod tests { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); builder.previous_kernel.global_variables.block_number = 10; - builder.public_call.public_inputs.global_variables.block_number = 11; + builder.public_call.global_variables.block_number = 11; builder.failed(); } @@ -506,37 +356,29 @@ mod tests { #[test] fn clears_stack_if_current_call_revert_code_is_set() { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.revert_code = 1; - let public_call = builder.public_call.finish(); - let item = public_call.call_stack_item.get_compressed(); - builder.previous_kernel.push_public_teardown_call_request(item); - // push again to check that the stack is cleared - builder.previous_kernel.push_public_teardown_call_request(item); - let previous_kernel = builder.previous_kernel.to_public_kernel_data(true); + builder.public_call.revert_code = 1; - let kernel = PublicKernelTeardownCircuitPrivateInputs { previous_kernel, public_call }; + builder.previous_kernel.append_public_teardown_call_requests(2); - let public_inputs = kernel.public_kernel_teardown(); + let public_inputs = builder.execute(); - assert_eq(array_length(public_inputs.public_teardown_call_stack), 0); + assert_array_eq(public_inputs.public_teardown_call_stack, []); } #[test] fn retains_stack_if_fail_in_app_logic() { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); builder.previous_kernel.revert_code = 1; - let public_call = builder.public_call.finish(); - let item = public_call.call_stack_item.get_compressed(); - builder.previous_kernel.push_public_teardown_call_request(item); - // push again to check that we keep one item after popping the current call - builder.previous_kernel.push_public_teardown_call_request(item); - let previous_kernel = builder.previous_kernel.to_public_kernel_data(true); - let kernel = PublicKernelTeardownCircuitPrivateInputs { previous_kernel, public_call }; + builder.previous_kernel.append_public_teardown_call_requests(2); + let teardown_calls = builder.previous_kernel.public_teardown_call_stack.storage; - let public_inputs = kernel.public_kernel_teardown(); + let public_inputs = builder.execute(); - assert_eq(array_length(public_inputs.public_teardown_call_stack), 1); + assert_array_eq( + public_inputs.public_teardown_call_stack, + [teardown_calls[0], teardown_calls[1]] + ); } #[test] @@ -559,7 +401,7 @@ mod tests { unconstrained fn correctly_updates_revert_code_2() { // Case where there is a new error in teardown let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.revert_code = 1; + builder.public_call.revert_code = 1; let public_inputs = builder.execute(); assert_eq(public_inputs.revert_code, 2); } @@ -569,7 +411,7 @@ mod tests { // Case where there is an error in both app logic and teardown let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); builder.previous_kernel.revert_code = 1; - builder.public_call.public_inputs.revert_code = 1; + builder.public_call.revert_code = 1; let public_inputs = builder.execute(); assert_eq(public_inputs.revert_code, 3); } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/utils.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/utils.nr deleted file mode 100644 index 974a124119e..00000000000 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/utils.nr +++ /dev/null @@ -1,33 +0,0 @@ -use dep::types::{ - abis::{public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest}, - address::AztecAddress, - contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest} -}; - -pub fn compute_public_data_reads( - contract_address: AztecAddress, - read_requests: [StorageRead; N] -) -> [PublicDataRead; N] { - let mut public_data_reads = [PublicDataRead::empty(); N]; - for i in 0..N { - let read_request = read_requests[i]; - if !read_request.is_empty() { - public_data_reads[i] = PublicDataRead::from_contract_storage_read(contract_address, read_request); - } - } - public_data_reads -} - -pub fn compute_public_data_update_requests( - contract_address: AztecAddress, - update_requests: [StorageUpdateRequest; N] -) -> [PublicDataUpdateRequest; N] { - let mut public_data_update_requests = [PublicDataUpdateRequest::empty(); N]; - for i in 0..N { - let update_request = update_requests[i]; - if !update_request.is_empty() { - public_data_update_requests[i] = PublicDataUpdateRequest::from_contract_storage_update_request(contract_address, update_request); - } - } - public_data_update_requests -} diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-setup-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-setup-simulated/src/main.nr index be09565d0ac..c27a53e2dec 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-setup-simulated/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-setup-simulated/src/main.nr @@ -2,5 +2,5 @@ use dep::public_kernel_lib::PublicKernelSetupCircuitPrivateInputs; use dep::types::PublicKernelCircuitPublicInputs; unconstrained fn main(input: PublicKernelSetupCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { - input.public_kernel_setup() + input.execute() } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-setup/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-setup/src/main.nr index c8ab71e4a8a..6849a58b4fa 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-setup/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-setup/src/main.nr @@ -3,5 +3,5 @@ use dep::types::PublicKernelCircuitPublicInputs; #[recursive] fn main(input: PublicKernelSetupCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { - input.public_kernel_setup() + input.execute() } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-teardown-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-teardown-simulated/src/main.nr index 78cb6040500..aaef26a016f 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-teardown-simulated/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-teardown-simulated/src/main.nr @@ -2,5 +2,5 @@ use dep::public_kernel_lib::PublicKernelTeardownCircuitPrivateInputs; use dep::types::PublicKernelCircuitPublicInputs; unconstrained fn main(input: PublicKernelTeardownCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { - input.public_kernel_teardown() + input.execute() } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-teardown/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-teardown/src/main.nr index 905a0077db6..adc9d2eda65 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-teardown/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-teardown/src/main.nr @@ -3,5 +3,5 @@ use dep::types::PublicKernelCircuitPublicInputs; #[recursive] fn main(input: PublicKernelTeardownCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { - input.public_kernel_teardown() + input.execute() } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr index c0d030493e2..0e069fdd86f 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr @@ -29,6 +29,7 @@ struct PublicValidationRequestProcessor { nullifier_tree_root: Field, public_data_read_request_hints: PublicDataReadRequestHints, public_data_hints: [PublicDataHint; NUM_PUBLIC_DATA_HINTS], + public_data_tree_root: Field, } impl PublicValidationRequestProcessor { @@ -38,7 +39,8 @@ impl PublicValidationRequestProcessor Self { let end_non_revertible = public_inputs.end_non_revertible; let end = public_inputs.end; @@ -58,7 +60,8 @@ impl PublicValidationRequestProcessor PublicValidationRequestProcessor PublicValidationRequestProcessor(a: T, b: T) -> bool where T: Ordered { - a.counter() <= b.counter() -} - -impl CombinedAccumulatedData { - pub fn combine( - non_revertible: PublicAccumulatedData, - revertible: PublicAccumulatedData, - combine_hints: CombineHints - ) -> Self { - let merged_note_hashes = array_merge(non_revertible.note_hashes, revertible.note_hashes); - assert_sorted_array( - merged_note_hashes, - combine_hints.sorted_note_hashes, - combine_hints.sorted_note_hashes_indexes, - asc_sort_by_counters - ); - - let mut siloed_note_hashes = [0; MAX_NOTE_HASHES_PER_TX]; - let sorted_note_hashes = combine_hints.sorted_note_hashes; - let tx_hash = non_revertible.nullifiers[0].value; - for i in 0..sorted_note_hashes.len() { - let note_hash = sorted_note_hashes[i]; - siloed_note_hashes[i] = if note_hash.counter() == 0 { - // If counter is zero, the note hash was emitted from private and has been siloed in private_kernel_tail_to_public. - note_hash.value() - } else { - silo_note_hash(note_hash, tx_hash, i) - }; - } - - let merged_public_data_update_requests = array_merge( - non_revertible.public_data_update_requests, - revertible.public_data_update_requests - ); - - // Just check a permutation here... - check_permutation( - merged_public_data_update_requests, - combine_hints.sorted_public_data_update_requests, - combine_hints.sorted_public_data_update_requests_indexes - ); - // ...because the ordering checks are done here. - assert_deduped_array( - combine_hints.sorted_public_data_update_requests, - combine_hints.deduped_public_data_update_requests, - combine_hints.deduped_public_data_update_requests_runs - ); - - let merged_note_encrypted_logs_hashes = array_merge( - non_revertible.note_encrypted_logs_hashes, - revertible.note_encrypted_logs_hashes - ); - assert_sorted_array( - merged_note_encrypted_logs_hashes, - combine_hints.sorted_note_encrypted_logs_hashes, - combine_hints.sorted_note_encrypted_logs_hashes_indexes, - asc_sort_by_counters - ); - - let merged_encrypted_logs_hashes = array_merge( - non_revertible.encrypted_logs_hashes, - revertible.encrypted_logs_hashes - ); - assert_sorted_array( - merged_encrypted_logs_hashes, - combine_hints.sorted_encrypted_logs_hashes, - combine_hints.sorted_encrypted_logs_hashes_indexes, - asc_sort_by_counters - ); - - let merged_unencrypted_logs_hashes = array_merge( - non_revertible.unencrypted_logs_hashes, - revertible.unencrypted_logs_hashes - ); - assert_sorted_array( - merged_unencrypted_logs_hashes, - combine_hints.sorted_unencrypted_logs_hashes, - combine_hints.sorted_unencrypted_logs_hashes_indexes, - asc_sort_by_counters - ); - - let note_encrypted_log_preimages_length = non_revertible.note_encrypted_logs_hashes.fold(0, |a, b: LogHash| a + b.length) - + revertible.note_encrypted_logs_hashes.fold(0, |a, b: LogHash| a + b.length); - let encrypted_log_preimages_length = non_revertible.encrypted_logs_hashes.fold(0, |a, b: ScopedLogHash| a + b.log_hash.length) - + revertible.encrypted_logs_hashes.fold(0, |a, b: ScopedLogHash| a + b.log_hash.length); - let unencrypted_log_preimages_length = non_revertible.unencrypted_logs_hashes.fold(0, |a, b: ScopedLogHash| a + b.log_hash.length) - + revertible.unencrypted_logs_hashes.fold(0, |a, b: ScopedLogHash| a + b.log_hash.length); - CombinedAccumulatedData { - note_hashes: siloed_note_hashes, - nullifiers: array_merge(non_revertible.nullifiers, revertible.nullifiers).map(|n: Nullifier| n.value), - l2_to_l1_msgs: array_merge(non_revertible.l2_to_l1_msgs, revertible.l2_to_l1_msgs), - note_encrypted_logs_hashes: combine_hints.sorted_note_encrypted_logs_hashes, - encrypted_logs_hashes: combine_hints.sorted_encrypted_logs_hashes, - unencrypted_logs_hashes: combine_hints.sorted_unencrypted_logs_hashes, - note_encrypted_log_preimages_length, - encrypted_log_preimages_length, - unencrypted_log_preimages_length, - public_data_update_requests: combine_hints.deduped_public_data_update_requests, - gas_used: revertible.gas_used + non_revertible.gas_used - } - } -} - impl Empty for CombinedAccumulatedData { fn empty() -> Self { CombinedAccumulatedData { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_data_builder.nr index d193809e0e4..8a44667de99 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_data_builder.nr @@ -10,7 +10,7 @@ use crate::{ MAX_L2_TO_L1_MSGS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX }, - traits::Empty + traits::Empty, utils::arrays::array_to_bounded_vec }; struct PublicAccumulatedDataBuilder { @@ -30,6 +30,20 @@ struct PublicAccumulatedDataBuilder { } impl PublicAccumulatedDataBuilder { + pub fn new(data: PublicAccumulatedData) -> Self { + PublicAccumulatedDataBuilder { + note_hashes: array_to_bounded_vec(data.note_hashes), + nullifiers: array_to_bounded_vec(data.nullifiers), + l2_to_l1_msgs: array_to_bounded_vec(data.l2_to_l1_msgs), + note_encrypted_logs_hashes: array_to_bounded_vec(data.note_encrypted_logs_hashes), + encrypted_logs_hashes: array_to_bounded_vec(data.encrypted_logs_hashes), + unencrypted_logs_hashes: array_to_bounded_vec(data.unencrypted_logs_hashes), + public_data_update_requests: array_to_bounded_vec(data.public_data_update_requests), + public_call_stack: array_to_bounded_vec(data.public_call_stack), + gas_used: data.gas_used + } + } + pub fn finish(self) -> PublicAccumulatedData { PublicAccumulatedData { note_hashes: self.note_hashes.storage, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr index 1755db26a0f..c9903d28e68 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr @@ -18,25 +18,6 @@ struct PublicKernelCircuitPublicInputs { fee_payer: AztecAddress } -impl PublicKernelCircuitPublicInputs { - pub fn needs_setup(self) -> bool { - // public calls for setup are deposited in the non-revertible public call stack. - // if an element is present, we need to run setup - !self.end_non_revertible.public_call_stack[0].item.contract_address.is_zero() - } - - pub fn needs_app_logic(self) -> bool { - // public calls for app logic are deposited in the revertible public call stack. - // if an element is present, we need to run app logic - !self.end.public_call_stack[0].item.contract_address.is_zero() - } - - pub fn needs_teardown(self) -> bool { - // the public call specified for teardown, if any, is placed in the teardown call stack - !self.public_teardown_call_stack[0].item.contract_address.is_zero() - } -} - impl Empty for PublicKernelCircuitPublicInputs { fn empty() -> Self { PublicKernelCircuitPublicInputs { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr index 3f1d8e029f6..263b4fc8494 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr @@ -5,7 +5,8 @@ use crate::{ kernel_circuit_public_inputs::{public_kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs}, public_call_request::PublicCallRequest, validation_requests::PublicValidationRequestsBuilder }, - address::AztecAddress, constants::MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, traits::Empty + address::AztecAddress, constants::MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, traits::Empty, + utils::arrays::array_to_bounded_vec }; struct PublicKernelCircuitPublicInputsBuilder { @@ -19,6 +20,18 @@ struct PublicKernelCircuitPublicInputsBuilder { } impl PublicKernelCircuitPublicInputsBuilder { + pub fn new(data: PublicKernelCircuitPublicInputs) -> Self { + PublicKernelCircuitPublicInputsBuilder { + validation_requests: PublicValidationRequestsBuilder::new(data.validation_requests), + end_non_revertible: PublicAccumulatedDataBuilder::new(data.end_non_revertible), + end: PublicAccumulatedDataBuilder::new(data.end), + constants: data.constants, + revert_code: data.revert_code, + public_teardown_call_stack: array_to_bounded_vec(data.public_teardown_call_stack), + fee_payer: data.fee_payer + } + } + pub fn finish(self) -> PublicKernelCircuitPublicInputs { PublicKernelCircuitPublicInputs { // Note that we're including both the validation_requests AND the rollup_validation requests, because this diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/public_validation_requests_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/public_validation_requests_builder.nr index c05b4339886..cde568a6152 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/public_validation_requests_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/public_validation_requests_builder.nr @@ -10,7 +10,7 @@ use crate::{ MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX }, - traits::Empty + traits::Empty, utils::arrays::array_to_bounded_vec }; struct PublicValidationRequestsBuilder { @@ -21,6 +21,15 @@ struct PublicValidationRequestsBuilder { } impl PublicValidationRequestsBuilder { + pub fn new(requests: PublicValidationRequests) -> Self { + PublicValidationRequestsBuilder { + max_block_number: requests.for_rollup.max_block_number, + nullifier_read_requests: array_to_bounded_vec(requests.nullifier_read_requests), + nullifier_non_existent_read_requests: array_to_bounded_vec(requests.nullifier_non_existent_read_requests), + public_data_reads: array_to_bounded_vec(requests.public_data_reads) + } + } + pub fn finish(self) -> PublicValidationRequests { PublicValidationRequests { for_rollup: self.for_rollup(), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr index b96c5dcd83e..0427e00154a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr @@ -13,8 +13,10 @@ use crate::{ nullifier::{Nullifier, ScopedNullifier}, private_call_request::PrivateCallRequest, private_call_stack_item::PrivateCallStackItem, private_circuit_public_inputs::PrivateCircuitPublicInputs, - private_kernel::private_call_data::PrivateCallData, public_call_request::PublicCallRequest, - public_call_stack_item_compressed::PublicCallStackItemCompressed, public_data_read::PublicDataRead, + private_kernel::private_call_data::PrivateCallData, public_call_data::{Proof, PublicCallData}, + public_call_request::PublicCallRequest, public_call_stack_item::PublicCallStackItem, + public_call_stack_item_compressed::PublicCallStackItemCompressed, + public_circuit_public_inputs::PublicCircuitPublicInputs, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, read_request::{ReadRequest, ScopedReadRequest}, log_hash::{LogHash, NoteLogHash, ScopedLogHash, EncryptedLogHash, ScopedEncryptedLogHash}, validation_requests::{ @@ -24,14 +26,17 @@ use crate::{ }, address::{AztecAddress, EthAddress, SaltedInitializationHash, PublicKeysHash}, constants::{ - FUNCTION_TREE_HEIGHT, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, - MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_FIELD_VALUE, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, MAX_KEY_VALIDATION_REQUESTS_PER_TX, VK_TREE_HEIGHT, - MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, - PRIVATE_CALL_REQUEST_LENGTH, PUBLIC_CALL_STACK_ITEM_COMPRESSED_LENGTH + FUNCTION_TREE_HEIGHT, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, + MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, MAX_PUBLIC_DATA_READS_PER_CALL, + MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_FIELD_VALUE, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, + MAX_KEY_VALIDATION_REQUESTS_PER_TX, VK_TREE_HEIGHT, MAX_ENCRYPTED_LOGS_PER_TX, + MAX_UNENCRYPTED_LOGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, PRIVATE_CALL_REQUEST_LENGTH, + PUBLIC_CALL_STACK_ITEM_COMPRESSED_LENGTH }, + contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, hash::{ compute_l2_to_l1_hash, compute_tx_logs_hash, compute_tx_note_logs_hash, compute_siloed_nullifier, silo_encrypted_log_hash, silo_note_hash, silo_unencrypted_log_hash, mask_encrypted_log_hash @@ -75,6 +80,9 @@ struct FixtureBuilder { is_fee_payer: bool, fee_payer: AztecAddress, public_teardown_call_stack: BoundedVec, + transaction_fee: Field, + start_gas_left: Gas, + end_gas_left: Gas, // Constant data. historical_header: Header, @@ -95,10 +103,10 @@ struct FixtureBuilder { encrypted_log_preimages_length: Field, unencrypted_log_preimages_length: Field, public_data_update_requests: BoundedVec, + contract_storage_update_requests: BoundedVec, private_call_requests: BoundedVec, public_call_requests: BoundedVec, gas_used: Gas, - non_revertible_gas_used: Gas, revert_code: u8, // Validation requests. @@ -106,8 +114,10 @@ struct FixtureBuilder { note_hash_read_requests: BoundedVec, nullifier_read_requests: BoundedVec, nullifier_non_existent_read_requests: BoundedVec, + l1_to_l2_msg_read_requests: BoundedVec, scoped_key_validation_requests_and_generators: BoundedVec, public_data_reads: BoundedVec, + contract_storage_reads: BoundedVec, validation_requests_split_counter: Option, // Function. @@ -123,6 +133,11 @@ struct FixtureBuilder { function_leaf_membership_witness: MembershipWitness, acir_hash: Field, + // Public call. + is_execution_request: bool, + bytecode_hash: Field, + prover_address: AztecAddress, + // Proof. proof: NestedRecursiveProof, vk: VerificationKey, @@ -192,6 +207,13 @@ impl FixtureBuilder { *self } + pub fn is_public_function(&mut self) -> Self { + let contract_function = fixtures::contract_functions::default_public_function; + self.function_data = contract_function.data; + self.bytecode_hash = contract_function.acir_hash; + *self + } + pub fn is_delegate_call(&mut self) -> Self { self.is_delegate_call = true; self.storage_contract_address = fixtures::contracts::parent_contract.address; @@ -406,6 +428,49 @@ impl FixtureBuilder { PrivateKernelData { public_inputs, vk: self.vk, vk_index: self.vk_index, vk_path: self.vk_path } } + pub fn to_public_circuit_public_inputs(self) -> PublicCircuitPublicInputs { + PublicCircuitPublicInputs { + call_context: self.build_call_context(), + args_hash: self.args_hash, + returns_hash: self.returns_hash, + note_hash_read_requests: subarray(self.note_hash_read_requests.storage.map(|r: ScopedReadRequest| r.read_request)), + nullifier_read_requests: subarray(self.nullifier_read_requests.storage.map(|r: ScopedReadRequest| r.read_request)), + nullifier_non_existent_read_requests: subarray( + self.nullifier_non_existent_read_requests.storage.map(|r: ScopedReadRequest| r.read_request) + ), + l1_to_l2_msg_read_requests: subarray(self.l1_to_l2_msg_read_requests.storage.map(|r: ScopedReadRequest| r.read_request)), + contract_storage_update_requests: subarray(self.contract_storage_update_requests.storage), + contract_storage_reads: self.contract_storage_reads.storage, + public_call_requests: subarray(self.public_call_requests.storage), + note_hashes: subarray(self.note_hashes.storage.map(|n: ScopedNoteHash| n.note_hash)), + nullifiers: subarray(self.nullifiers.storage.map(|n: ScopedNullifier| n.nullifier)), + l2_to_l1_msgs: subarray(self.l2_to_l1_msgs.storage.map(|m: ScopedL2ToL1Message| m.message)), + start_side_effect_counter: self.counter_start, + end_side_effect_counter: self.counter, + unencrypted_logs_hashes: subarray(self.unencrypted_logs_hashes.storage.map(|l: ScopedLogHash| l.log_hash)), + historical_header: self.historical_header, + global_variables: self.global_variables, + prover_address: self.prover_address, + revert_code: self.revert_code, + start_gas_left: self.start_gas_left, + end_gas_left: self.end_gas_left, + transaction_fee: self.transaction_fee + } + } + + pub fn to_public_call_stack_item(self) -> PublicCallStackItem { + PublicCallStackItem { + contract_address: self.contract_address, + function_data: self.function_data, + is_execution_request: self.is_execution_request, + public_inputs: self.to_public_circuit_public_inputs() + } + } + + pub fn to_public_call_data(self) -> PublicCallData { + PublicCallData { call_stack_item: self.to_public_call_stack_item(), proof: Proof {}, bytecode_hash: self.bytecode_hash } + } + pub fn to_public_validation_requests(self) -> PublicValidationRequests { PublicValidationRequests { for_rollup: self.to_rollup_validation_requests(), @@ -613,6 +678,35 @@ impl FixtureBuilder { } } + pub fn add_contract_storage_read_request(&mut self, storage_slot: Field, value: Field) { + self.contract_storage_reads.push(StorageRead { storage_slot, current_value: value, counter: self.next_counter() }); + } + + pub fn append_contract_storage_read_requests(&mut self, num: u32) { + let index_offset = self.contract_storage_reads.len(); + for i in 0..self.contract_storage_reads.max_len() { + if i < num { + let (storage_slot, value) = self.mock_contract_storage_read(index_offset + i); + self.add_contract_storage_read_request(storage_slot, value); + } + } + } + + pub fn add_contract_storage_update_request(&mut self, storage_slot: Field, value: Field) { + let update_request = StorageUpdateRequest { storage_slot, new_value: value, counter: self.next_counter() }; + self.contract_storage_update_requests.push(update_request); + } + + pub fn append_contract_storage_update_requests(&mut self, num: u32) { + let index_offset = self.contract_storage_update_requests.len(); + for i in 0..self.contract_storage_update_requests.max_len() { + if i < num { + let (storage_slot, value) = self.mock_contract_storage_write(index_offset + i); + self.add_contract_storage_update_request(storage_slot, value); + } + } + } + pub fn add_public_data_update_request(&mut self, leaf_slot: Field, value: Field) { let update_request = PublicDataUpdateRequest { leaf_slot, new_value: value, counter: self.next_counter() }; self.public_data_update_requests.push(update_request); @@ -628,12 +722,16 @@ impl FixtureBuilder { } } + pub fn add_public_data_read_request(&mut self, leaf_slot: Field, value: Field) { + self.public_data_reads.push(PublicDataRead { leaf_slot, value }); + } + pub fn append_public_data_read_requests(&mut self, num_reads: u32) { let index_offset = self.public_data_reads.len(); for i in 0..self.public_data_reads.max_len() { if i < num_reads { let read_request = self.mock_public_data_read(index_offset + i); - self.public_data_reads.push(read_request); + self.add_public_data_read_request(read_request.leaf_slot, read_request.value); } } } @@ -681,6 +779,16 @@ impl FixtureBuilder { } } + pub fn append_nullifier_non_existent_read_requests(&mut self, num: u32) { + let index_offset = self.nullifier_non_existent_read_requests.len(); + for i in 0..self.nullifier_non_existent_read_requests.max_len() { + if i < num { + let value = self.mock_nullifier_read_value(index_offset + i); + self.add_non_existent_read_request_for_nullifier(value); + } + } + } + pub fn add_read_request_for_pending_public_data(&mut self, public_date_update_request_index: u32) -> u32 { let new_read_request_index = self.public_data_reads.len(); let public_write = self.public_data_update_requests.get(public_date_update_request_index); @@ -889,6 +997,16 @@ impl FixtureBuilder { self.push_public_teardown_call_request(item); } + pub fn append_public_teardown_call_requests(&mut self, num: u32) { + let index_offset = self.public_teardown_call_stack.len(); + for i in 0..self.public_teardown_call_stack.max_len() { + if i < num { + let item = self.mock_public_teardown_call_request_item(index_offset + i, true); + self.push_public_teardown_call_request(item); + } + } + } + pub fn end_setup(&mut self) { self.min_revertible_side_effect_counter = self.counter; } @@ -923,6 +1041,16 @@ impl FixtureBuilder { (leaf_slot, value) } + fn mock_contract_storage_read(self, index: u32) -> (Field, Field) { + let value_offset = 543543 + self.value_offset + index as Field; + (value_offset, value_offset + 1) + } + + fn mock_contract_storage_write(self, index: u32) -> (Field, Field) { + let value_offset = 336699 + self.value_offset + index as Field; + (value_offset, value_offset + 1) + } + fn mock_note_hash_value(self, index: u32) -> Field { 212121 + self.value_offset + index as Field } @@ -1037,14 +1165,17 @@ impl Empty for FixtureBuilder { encrypted_log_preimages_length: 0, unencrypted_log_preimages_length: 0, public_data_update_requests: BoundedVec::new(), + contract_storage_update_requests: BoundedVec::new(), private_call_requests: BoundedVec::new(), public_call_requests: BoundedVec::new(), max_block_number: MaxBlockNumber::empty(), note_hash_read_requests: BoundedVec::new(), nullifier_read_requests: BoundedVec::new(), nullifier_non_existent_read_requests: BoundedVec::new(), + l1_to_l2_msg_read_requests: BoundedVec::new(), scoped_key_validation_requests_and_generators: BoundedVec::new(), public_data_reads: BoundedVec::new(), + contract_storage_reads: BoundedVec::new(), validation_requests_split_counter: Option::none(), function_data: FunctionData::empty(), args_hash: 0, @@ -1055,6 +1186,9 @@ impl Empty for FixtureBuilder { contract_class_artifact_hash: 0, contract_class_public_bytecode_commitment: 0, acir_hash: 0, + is_execution_request: false, + bytecode_hash: 0, + prover_address: AztecAddress::zero(), proof: NestedRecursiveProof::empty(), vk: VerificationKey::empty(), vk_index: 0, @@ -1066,7 +1200,9 @@ impl Empty for FixtureBuilder { counter: 0, start_state: PartialStateReference::empty(), gas_used: Gas::empty(), - non_revertible_gas_used: Gas::empty(), + start_gas_left: Gas::empty(), + end_gas_left: Gas::empty(), + transaction_fee: 0, public_teardown_call_stack: BoundedVec::new(), value_offset: 0, } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/mod.nr index 7d57afca711..678a7be1cfe 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/mod.nr @@ -1,7 +1,5 @@ mod fixture_builder; mod fixtures; mod merkle_tree_utils; -mod public_call_data_builder; -mod public_circuit_public_inputs_builder; mod sort; mod utils; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr deleted file mode 100644 index b9d8b3ffb6b..00000000000 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr +++ /dev/null @@ -1,166 +0,0 @@ -use crate::{ - abis::{ - gas_settings::GasSettings, gas::Gas, call_context::CallContext, function_data::FunctionData, - public_call_data::{PublicCallData, Proof}, public_call_request::PublicCallRequest, - public_call_stack_item::PublicCallStackItem, - public_call_stack_item_compressed::PublicCallStackItemCompressed, log_hash::LogHash -}, - address::AztecAddress, - contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, - tests::{fixtures, public_circuit_public_inputs_builder::PublicCircuitPublicInputsBuilder} -}; -use crate::constants::{ - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, PUBLIC_CALL_STACK_ITEM_COMPRESSED_LENGTH -}; - -struct PublicCallDataBuilder { - contract_address: AztecAddress, - public_inputs: PublicCircuitPublicInputsBuilder, - is_execution_request: bool, - function_data: FunctionData, - proof: Proof, - bytecode_hash: Field, -} - -impl PublicCallDataBuilder { - pub fn new() -> Self { - let contract_data = fixtures::contracts::default_contract; - let contract_address = contract_data.address; - - let contract_function = fixtures::contract_functions::default_public_function; - let function_data = contract_function.data; - - let mut public_inputs = PublicCircuitPublicInputsBuilder::new(); - - public_inputs.call_context = CallContext { - msg_sender: fixtures::contracts::parent_contract.address, - storage_contract_address: contract_address, - function_selector: function_data.selector, - is_delegate_call: false, - is_static_call: false, - }; - - PublicCallDataBuilder { - contract_address, - public_inputs, - is_execution_request: false, - function_data, - proof: Proof {}, - bytecode_hash: contract_function.acir_hash - } - } - - pub fn is_delegate_call(&mut self) -> Self { - self.public_inputs.call_context.is_delegate_call = true; - self.public_inputs.call_context.storage_contract_address = fixtures::contracts::parent_contract.address; - self.public_inputs.call_context.msg_sender = fixtures::MSG_SENDER; - *self - } - - pub fn append_public_call_requests_for_regular_calls(&mut self, num_requests: u32) { - self.append_public_call_requests(num_requests, false); - } - - pub fn append_public_call_requests_for_delegate_calls(&mut self, num_requests: u32) { - self.append_public_call_requests(num_requests, true); - } - - fn append_public_call_requests(&mut self, num_requests: u32, is_delegate_call: bool) { - let index_offset = self.public_inputs.public_call_requests.len(); - for i in 0..MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL { - if i < num_requests { - let call_request = PublicCallRequest { item: self.mock_public_call_request_item(index_offset + i, is_delegate_call), counter: i }; - self.public_inputs.public_call_requests.push(call_request); - } - } - } - - fn mock_public_call_request_item(self, index: u32, is_delegate_call: bool) -> PublicCallStackItemCompressed { - let value_offset = 7788 + index as Field; - let mut fields = [0; PUBLIC_CALL_STACK_ITEM_COMPRESSED_LENGTH]; - for i in 0..fields.len() { - fields[i] = value_offset + i as Field; - } - let mut item = PublicCallStackItemCompressed::deserialize(fields); - item.call_context.msg_sender = if is_delegate_call { - self.public_inputs.call_context.msg_sender - } else { - self.public_inputs.call_context.storage_contract_address - }; - item.call_context.storage_contract_address = if is_delegate_call { - self.public_inputs.call_context.storage_contract_address - } else { - item.contract_address - }; - item.call_context.is_delegate_call = is_delegate_call; - item - } - - pub fn append_public_data_read_requests(&mut self, num_reads: u32) { - let value_offset = self.public_inputs.contract_storage_reads.len(); - for i in 0..MAX_PUBLIC_DATA_READS_PER_CALL { - if i < num_reads { - let read_request = StorageRead { - // The default storage slot is its index + 1. - storage_slot: (value_offset + i + 1) as Field, - // The default value is its index + 999. - current_value: (value_offset + i + 999) as Field, - counter: i as u32 - }; - self.public_inputs.contract_storage_reads.push(read_request); - } - } - } - - pub fn append_empty_public_data_read_requests(&mut self, num_reads: u32) { - for i in 0..MAX_PUBLIC_DATA_READS_PER_CALL { - if i < num_reads { - self.public_inputs.contract_storage_reads.push(StorageRead::empty()); - } - } - } - - pub fn append_update_requests(&mut self, num_updates: u32) { - let value_offset = self.public_inputs.contract_storage_update_requests.len(); - for i in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL { - if i < num_updates { - let update_request = StorageUpdateRequest { - // The default storage slot is its index + 1. - storage_slot: (value_offset + i + 1) as Field, - // The default value is its index + 890. - new_value: (value_offset + i + 890) as Field, - counter: i as u32 - }; - self.public_inputs.contract_storage_update_requests.push(update_request); - } - } - } - - pub fn append_empty_update_requests(&mut self, num_updates: u32) { - for i in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL { - if i < num_updates { - self.public_inputs.contract_storage_update_requests.push(StorageUpdateRequest::empty()); - } - } - } - - pub fn set_unencrypted_logs(&mut self, hash: Field, preimages_length: Field) { - // Counter set as 0 for testing, like note read requests - let side_effect = LogHash { value: hash, counter: 0, length: preimages_length }; - self.public_inputs.unencrypted_logs_hashes.push(side_effect); - } - - pub fn finish(self) -> PublicCallData { - PublicCallData { - call_stack_item: PublicCallStackItem { - contract_address: self.contract_address, - function_data: self.function_data, - is_execution_request: self.is_execution_request, - public_inputs: self.public_inputs.finish() - }, - proof: self.proof, - bytecode_hash: self.bytecode_hash - } - } -} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_circuit_public_inputs_builder.nr deleted file mode 100644 index 25ceeb39868..00000000000 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_circuit_public_inputs_builder.nr +++ /dev/null @@ -1,112 +0,0 @@ -use crate::{ - abis::{ - gas::Gas, call_context::CallContext, note_hash::NoteHash, nullifier::Nullifier, - public_call_request::PublicCallRequest, public_circuit_public_inputs::PublicCircuitPublicInputs, - read_request::ReadRequest, log_hash::LogHash, global_variables::GlobalVariables -}, - address::AztecAddress, - contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, header::Header, - messaging::l2_to_l1_message::L2ToL1Message, tests::fixtures -}; -use crate::{ - constants::{ - MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_CALL, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, - MAX_NOTE_HASHES_PER_CALL, MAX_L2_TO_L1_MSGS_PER_CALL, MAX_NULLIFIERS_PER_CALL, - MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, MAX_UNENCRYPTED_LOGS_PER_CALL -}, - traits::Empty -}; - -struct PublicCircuitPublicInputsBuilder { - call_context: CallContext, - args_hash: Field, - returns_hash: Field, - note_hash_read_requests: BoundedVec, - nullifier_read_requests: BoundedVec, - nullifier_non_existent_read_requests: BoundedVec, - l1_to_l2_msg_read_requests: BoundedVec, - contract_storage_update_requests: BoundedVec, - contract_storage_reads: BoundedVec, - public_call_requests: BoundedVec, - note_hashes: BoundedVec, - nullifiers: BoundedVec, - l2_to_l1_msgs: BoundedVec, - start_side_effect_counter: u32, - end_side_effect_counter: u32, - unencrypted_logs_hashes: BoundedVec, - historical_header: Header, - global_variables: GlobalVariables, - prover_address: AztecAddress, - revert_code: u8, - start_gas_left: Gas, - end_gas_left: Gas, - transaction_fee: Field, -} - -impl PublicCircuitPublicInputsBuilder { - pub fn new() -> Self { - let mut public_inputs = PublicCircuitPublicInputsBuilder::empty(); - public_inputs.call_context.msg_sender = fixtures::MSG_SENDER; - public_inputs - } - - pub fn finish(self) -> PublicCircuitPublicInputs { - PublicCircuitPublicInputs { - call_context: self.call_context, - args_hash: self.args_hash, - returns_hash: self.returns_hash, - note_hash_read_requests: self.note_hash_read_requests.storage, - nullifier_read_requests: self.nullifier_read_requests.storage, - nullifier_non_existent_read_requests: self.nullifier_non_existent_read_requests.storage, - l1_to_l2_msg_read_requests: self.l1_to_l2_msg_read_requests.storage, - contract_storage_update_requests: self.contract_storage_update_requests.storage, - contract_storage_reads: self.contract_storage_reads.storage, - public_call_requests: self.public_call_requests.storage, - note_hashes: self.note_hashes.storage, - nullifiers: self.nullifiers.storage, - l2_to_l1_msgs: self.l2_to_l1_msgs.storage, - start_side_effect_counter: self.start_side_effect_counter, - end_side_effect_counter: self.end_side_effect_counter, - unencrypted_logs_hashes: self.unencrypted_logs_hashes.storage, - historical_header: self.historical_header, - global_variables: self.global_variables, - prover_address: self.prover_address, - revert_code: self.revert_code, - start_gas_left: self.start_gas_left, - end_gas_left: self.end_gas_left, - transaction_fee: self.transaction_fee - } - } -} - -impl Empty for PublicCircuitPublicInputsBuilder { - fn empty() -> Self { - PublicCircuitPublicInputsBuilder { - call_context: CallContext::empty(), - args_hash: 0, - returns_hash: 0, - note_hash_read_requests: BoundedVec::new(), - nullifier_read_requests: BoundedVec::new(), - nullifier_non_existent_read_requests: BoundedVec::new(), - l1_to_l2_msg_read_requests: BoundedVec::new(), - contract_storage_update_requests: BoundedVec::new(), - contract_storage_reads: BoundedVec::new(), - public_call_requests: BoundedVec::new(), - note_hashes: BoundedVec::new(), - nullifiers: BoundedVec::new(), - l2_to_l1_msgs: BoundedVec::new(), - start_side_effect_counter: 0 as u32, - end_side_effect_counter: 0 as u32, - unencrypted_logs_hashes: BoundedVec::new(), - historical_header: Header::empty(), - global_variables: GlobalVariables::empty(), - prover_address: AztecAddress::zero(), - revert_code: 0 as u8, - start_gas_left: Gas::empty(), - end_gas_left: Gas::empty(), - transaction_fee: 0 - } - } -}