From bb23d4a4b8952baf220afb4fa98d4e09069d7948 Mon Sep 17 00:00:00 2001 From: Bohdan Ohorodnii Date: Tue, 20 Aug 2024 20:11:01 +0300 Subject: [PATCH] refactor: move out methods that won't be reviewed in this PR --- .../src/execution/execution_utils.rs | 13 +- crates/blockifier/src/execution/native.rs | 2 - .../execution/native/entry_point_execution.rs | 33 -- .../src/execution/native/syscall_handler.rs | 318 ------------------ .../blockifier/src/execution/native/utils.rs | 127 ------- .../src/execution/native/utils_test.rs | 42 --- 6 files changed, 3 insertions(+), 532 deletions(-) delete mode 100644 crates/blockifier/src/execution/native/entry_point_execution.rs delete mode 100644 crates/blockifier/src/execution/native/syscall_handler.rs delete mode 100644 crates/blockifier/src/execution/native/utils_test.rs diff --git a/crates/blockifier/src/execution/execution_utils.rs b/crates/blockifier/src/execution/execution_utils.rs index 9fc1e110d8..4620c76ffc 100644 --- a/crates/blockifier/src/execution/execution_utils.rs +++ b/crates/blockifier/src/execution/execution_utils.rs @@ -34,7 +34,6 @@ use crate::execution::entry_point::{ EntryPointExecutionResult, }; use crate::execution::errors::PostExecutionError; -use crate::execution::native::entry_point_execution as native_entry_point_execution; use crate::execution::{deprecated_entry_point_execution, entry_point_execution}; use crate::state::errors::StateError; use crate::state::state_api::State; @@ -69,14 +68,8 @@ pub fn execute_entry_point_call( resources, context, ), - ContractClass::V1Native(contract_class) => { - native_entry_point_execution::execute_entry_point_call( - call, - contract_class, - state, - resources, - context, - ) + ContractClass::V1Native(_contract_class) => { + unimplemented!("Native contract entry point execution is not yet implemented.") } } } @@ -274,7 +267,7 @@ pub fn max_fee_for_execution_info(tx_info: &TransactionInfo) -> Felt { TransactionInfo::Current(_) => 0, TransactionInfo::Deprecated(tx_info) => tx_info.max_fee.0, } - .into() + .into() } pub fn format_panic_data(felts: &[Felt]) -> String { diff --git a/crates/blockifier/src/execution/native.rs b/crates/blockifier/src/execution/native.rs index 5843e98914..b5614dd823 100644 --- a/crates/blockifier/src/execution/native.rs +++ b/crates/blockifier/src/execution/native.rs @@ -1,3 +1 @@ -pub mod entry_point_execution; -pub mod syscall_handler; pub mod utils; diff --git a/crates/blockifier/src/execution/native/entry_point_execution.rs b/crates/blockifier/src/execution/native/entry_point_execution.rs deleted file mode 100644 index 267fbc836c..0000000000 --- a/crates/blockifier/src/execution/native/entry_point_execution.rs +++ /dev/null @@ -1,33 +0,0 @@ -use cairo_vm::vm::runners::cairo_runner::ExecutionResources; - -use super::syscall_handler::NativeSyscallHandler; -use super::utils::run_native_executor; -use crate::execution::call_info::CallInfo; -use crate::execution::contract_class::NativeContractClassV1; -use crate::execution::entry_point::{ - CallEntryPoint, - EntryPointExecutionContext, - EntryPointExecutionResult, -}; -use crate::state::state_api::State; - -pub fn execute_entry_point_call( - call: CallEntryPoint, - contract_class: NativeContractClassV1, - state: &mut dyn State, - resources: &mut ExecutionResources, - context: &mut EntryPointExecutionContext, -) -> EntryPointExecutionResult { - let function_id = contract_class.get_entry_point(&call)?; - - let syscall_handler: NativeSyscallHandler<'_> = NativeSyscallHandler::new( - state, - call.caller_address, - call.storage_address, - call.entry_point_selector, - resources, - context, - ); - - run_native_executor(&contract_class.executor, function_id, call, syscall_handler) -} diff --git a/crates/blockifier/src/execution/native/syscall_handler.rs b/crates/blockifier/src/execution/native/syscall_handler.rs deleted file mode 100644 index fa94c09676..0000000000 --- a/crates/blockifier/src/execution/native/syscall_handler.rs +++ /dev/null @@ -1,318 +0,0 @@ -use std::collections::HashSet; -use std::hash::RandomState; - -use cairo_native::starknet::{ - ExecutionInfo, - ExecutionInfoV2, - Secp256k1Point, - Secp256r1Point, - StarknetSyscallHandler, - SyscallResult, - U256, -}; -use cairo_vm::vm::runners::cairo_runner::ExecutionResources; -use starknet_api::core::{ContractAddress, EntryPointSelector}; -use starknet_api::state::StorageKey; -use starknet_types_core::felt::Felt; - -use super::utils::encode_str_as_felts; -use crate::execution::call_info::{CallInfo, OrderedEvent, OrderedL2ToL1Message}; -use crate::execution::entry_point::{CallEntryPoint, EntryPointExecutionContext}; -use crate::execution::syscalls::hint_processor::OUT_OF_GAS_ERROR; -use crate::state::state_api::State; -use crate::transaction::transaction_utils::update_remaining_gas; - -pub struct NativeSyscallHandler<'state> { - // Input for execution. - pub state: &'state mut dyn State, - pub execution_resources: &'state mut ExecutionResources, - pub execution_context: &'state mut EntryPointExecutionContext, - - // Call information. - pub caller_address: ContractAddress, - pub contract_address: ContractAddress, - pub entry_point_selector: Felt, - - // Execution results. - pub events: Vec, - pub l2_to_l1_messages: Vec, - pub inner_calls: Vec, - - // Additional execution result info. - pub storage_read_values: Vec, - pub accessed_storage_keys: HashSet, -} - -impl<'state> NativeSyscallHandler<'state> { - pub fn new( - state: &'state mut dyn State, - caller_address: ContractAddress, - contract_address: ContractAddress, - entry_point_selector: EntryPointSelector, - execution_resources: &'state mut ExecutionResources, - execution_context: &'state mut EntryPointExecutionContext, - ) -> NativeSyscallHandler<'state> { - NativeSyscallHandler { - state, - caller_address, - contract_address, - entry_point_selector: entry_point_selector.0, - execution_resources, - execution_context, - events: Vec::new(), - l2_to_l1_messages: Vec::new(), - inner_calls: Vec::new(), - storage_read_values: Vec::new(), - accessed_storage_keys: HashSet::new(), - } - } - - pub fn execute_inner_call( - &mut self, - entry_point: CallEntryPoint, - remaining_gas: &mut u128, - ) -> SyscallResult { - let call_info = entry_point - .execute(self.state, self.execution_resources, self.execution_context) - .map_err(|e| encode_str_as_felts(&e.to_string()))?; - let retdata = call_info.execution.retdata.0.clone(); - - if call_info.execution.failed { - // In VM it's wrapped into `SyscallExecutionError::SyscallError`. - return Err(retdata); - } - - self.update_remaining_gas(remaining_gas, &call_info); - - self.inner_calls.push(call_info.clone()); - - Ok(call_info) - } - - pub fn update_remaining_gas(&mut self, remaining_gas: &mut u128, call_info: &CallInfo) { - // Create a new variable with converted type. - let mut remaining_gas_u64 = u64::try_from(*remaining_gas).unwrap(); - - // Pass the reference to the function. - update_remaining_gas(&mut remaining_gas_u64, call_info); - - // Change the remaining gas value. - *remaining_gas = u128::from(remaining_gas_u64); - } - - // Handles gas related logic when executing a syscall. Required because Native calls the - // syscalls directly unlike the VM where the `execute_syscall` method perform this operation - // first. - pub fn substract_syscall_gas_cost( - &mut self, - remaining_gas: &mut u128, - syscall_gas_cost: u64, - ) -> SyscallResult<()> { - // Refund `SYSCALL_BASE_GAS_COST` as it was pre-charged. - let required_gas = - u128::from(syscall_gas_cost - self.execution_context.gas_costs().syscall_base_gas_cost); - - if *remaining_gas < required_gas { - // Out of gas failure. - return Err(vec![Felt::from_hex(OUT_OF_GAS_ERROR).unwrap()]); - } - - *remaining_gas -= required_gas; - - Ok(()) - } -} - -impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { - fn get_block_hash( - &mut self, - _block_number: u64, - _remaining_gas: &mut u128, - ) -> SyscallResult { - todo!("Implement get_block_hash syscall."); - } - - fn get_execution_info(&mut self, _remaining_gas: &mut u128) -> SyscallResult { - todo!("Implement get_execution_info syscall."); - } - - fn get_execution_info_v2( - &mut self, - _remaining_gas: &mut u128, - ) -> SyscallResult { - todo!("Implement get_execution_info_v2 syscall."); - } - - fn deploy( - &mut self, - _class_hash: Felt, - _contract_address_salt: Felt, - _calldata: &[Felt], - _deploy_from_zero: bool, - _remaining_gas: &mut u128, - ) -> SyscallResult<(Felt, Vec)> { - todo!("Implement deploy syscall."); - } - - fn replace_class(&mut self, _class_hash: Felt, _remaining_gas: &mut u128) -> SyscallResult<()> { - todo!("Implement replace_class syscall."); - } - - fn library_call( - &mut self, - _class_hash: Felt, - _function_selector: Felt, - _calldata: &[Felt], - _remaining_gas: &mut u128, - ) -> SyscallResult> { - todo!("Implement library_call syscall."); - } - - fn call_contract( - &mut self, - _address: Felt, - _entry_point_selector: Felt, - _calldata: &[Felt], - _remaining_gas: &mut u128, - ) -> SyscallResult> { - todo!("Implement call_contract syscall."); - } - - fn storage_read( - &mut self, - _address_domain: u32, - _address: Felt, - _remaining_gas: &mut u128, - ) -> SyscallResult { - todo!("Implement storage_read syscall."); - } - - fn storage_write( - &mut self, - _address_domain: u32, - _address: Felt, - _value: Felt, - _remaining_gas: &mut u128, - ) -> SyscallResult<()> { - todo!("Implement storage_write syscall."); - } - - fn emit_event( - &mut self, - _keys: &[Felt], - _data: &[Felt], - _remaining_gas: &mut u128, - ) -> SyscallResult<()> { - todo!("Implement emit_event syscall."); - } - - fn send_message_to_l1( - &mut self, - _to_address: Felt, - _payload: &[Felt], - _remaining_gas: &mut u128, - ) -> SyscallResult<()> { - todo!("Implement send_message_to_l1 syscall."); - } - - fn keccak(&mut self, _input: &[u64], _remaining_gas: &mut u128) -> SyscallResult { - todo!("Implement keccak syscall."); - } - - fn secp256k1_new( - &mut self, - _x: U256, - _y: U256, - _remaining_gas: &mut u128, - ) -> SyscallResult> { - todo!("Implement secp256k1_new syscall."); - } - - fn secp256k1_add( - &mut self, - _p0: Secp256k1Point, - _p1: Secp256k1Point, - _remaining_gas: &mut u128, - ) -> SyscallResult { - todo!("Implement secp256k1_add syscall."); - } - - fn secp256k1_mul( - &mut self, - _p: Secp256k1Point, - _m: U256, - _remaining_gas: &mut u128, - ) -> SyscallResult { - todo!("Implement secp256k1_mul syscall."); - } - - fn secp256k1_get_point_from_x( - &mut self, - _x: U256, - _y_parity: bool, - _remaining_gas: &mut u128, - ) -> SyscallResult> { - todo!("Implement secp256k1_get_point_from_x syscall."); - } - - fn secp256k1_get_xy( - &mut self, - _p: Secp256k1Point, - _remaining_gas: &mut u128, - ) -> SyscallResult<(U256, U256)> { - todo!("Implement secp256k1_get_xy syscall."); - } - - fn secp256r1_new( - &mut self, - _x: U256, - _y: U256, - _remaining_gas: &mut u128, - ) -> SyscallResult> { - todo!("Implement secp256r1_new syscall."); - } - - fn secp256r1_add( - &mut self, - _p0: Secp256r1Point, - _p1: Secp256r1Point, - _remaining_gas: &mut u128, - ) -> SyscallResult { - todo!("Implement secp256r1_add syscall."); - } - - fn secp256r1_mul( - &mut self, - _p: Secp256r1Point, - _m: U256, - _remaining_gas: &mut u128, - ) -> SyscallResult { - todo!("Implement secp256r1_mul syscall."); - } - - fn secp256r1_get_point_from_x( - &mut self, - _x: U256, - _y_parity: bool, - _remaining_gas: &mut u128, - ) -> SyscallResult> { - todo!("Implement secp256r1_get_point_from_x syscall."); - } - - fn secp256r1_get_xy( - &mut self, - _p: Secp256r1Point, - _remaining_gas: &mut u128, - ) -> SyscallResult<(U256, U256)> { - todo!("Implement secp256r1_get_xy syscall."); - } - - fn sha256_process_block( - &mut self, - _prev_state: &[u32; 8], - _current_block: &[u32; 16], - _remaining_gas: &mut u128, - ) -> SyscallResult<[u32; 8]> { - todo!("Implement sha256_process_block syscall."); - } -} diff --git a/crates/blockifier/src/execution/native/utils.rs b/crates/blockifier/src/execution/native/utils.rs index 2f8f744c19..263da4b90f 100644 --- a/crates/blockifier/src/execution/native/utils.rs +++ b/crates/blockifier/src/execution/native/utils.rs @@ -1,138 +1,11 @@ -use std::collections::{HashMap, HashSet}; -use std::hash::RandomState; - -use cairo_lang_sierra::ids::FunctionId; use cairo_lang_starknet_classes::contract_class::ContractEntryPoint; -use cairo_native::execution_result::ContractExecutionResult; -use cairo_native::executor::AotNativeExecutor; -use cairo_vm::vm::runners::cairo_runner::ExecutionResources; -use itertools::Itertools; use num_traits::ToBytes; use starknet_api::core::EntryPointSelector; -use starknet_api::state::StorageKey; use starknet_types_core::felt::Felt; -use crate::execution::call_info::{ - CallExecution, - CallInfo, - OrderedEvent, - OrderedL2ToL1Message, - Retdata, -}; -use crate::execution::entry_point::{CallEntryPoint, EntryPointExecutionResult}; -use crate::execution::errors::EntryPointExecutionError; -use crate::execution::native::syscall_handler::NativeSyscallHandler; - -#[cfg(test)] -#[path = "utils_test.rs"] -pub mod test; - -// An arbitrary number, chosen to avoid accidentally aligning with actually calculated gas -// To be deleted once cairo native gas handling can be used. -pub const NATIVE_GAS_PLACEHOLDER: u64 = 12; - pub fn contract_entrypoint_to_entrypoint_selector( entrypoint: &ContractEntryPoint, ) -> EntryPointSelector { let selector_felt = Felt::from_bytes_be_slice(&entrypoint.selector.to_be_bytes()); EntryPointSelector(selector_felt) } - -pub fn run_native_executor( - native_executor: &AotNativeExecutor, - function_id: &FunctionId, - call: CallEntryPoint, - mut syscall_handler: NativeSyscallHandler<'_>, -) -> EntryPointExecutionResult { - let execution_result = native_executor.invoke_contract_dynamic( - function_id, - &call.calldata.0, - Some(call.initial_gas.into()), - &mut syscall_handler, - ); - - let run_result = match execution_result { - Ok(res) if res.failure_flag => Err(EntryPointExecutionError::NativeExecutionError { - info: if !res.return_values.is_empty() { - decode_felts_as_str(&res.return_values) - } else { - String::from("Unknown error") - }, - }), - Err(runner_err) => { - Err(EntryPointExecutionError::NativeUnexpectedError { source: runner_err }) - } - Ok(res) => Ok(res), - }?; - - create_callinfo( - call.clone(), - run_result, - syscall_handler.events, - syscall_handler.l2_to_l1_messages, - syscall_handler.inner_calls, - syscall_handler.storage_read_values, - syscall_handler.accessed_storage_keys, - ) -} - -pub fn create_callinfo( - call: CallEntryPoint, - run_result: ContractExecutionResult, - events: Vec, - l2_to_l1_messages: Vec, - inner_calls: Vec, - storage_read_values: Vec, - accessed_storage_keys: HashSet, -) -> Result { - Ok(CallInfo { - call, - execution: CallExecution { - retdata: Retdata(run_result.return_values), - events, - l2_to_l1_messages, - failed: run_result.failure_flag, - gas_consumed: NATIVE_GAS_PLACEHOLDER, - }, - resources: ExecutionResources { - n_steps: 0, - n_memory_holes: 0, - builtin_instance_counter: HashMap::default(), - }, - inner_calls, - storage_read_values, - accessed_storage_keys, - }) -} - -pub fn encode_str_as_felts(msg: &str) -> Vec { - const CHUNK_SIZE: usize = 32; - - let data = msg.as_bytes().chunks(CHUNK_SIZE - 1); - let mut encoding = vec![Felt::default(); data.len()]; - for (i, data_chunk) in data.enumerate() { - let mut chunk = [0_u8; CHUNK_SIZE]; - chunk[1..data_chunk.len() + 1].copy_from_slice(data_chunk); - encoding[i] = Felt::from_bytes_be(&chunk); - } - encoding -} - -pub fn decode_felts_as_str(encoding: &[Felt]) -> String { - let bytes_err: Vec<_> = - encoding.iter().flat_map(|felt| felt.to_bytes_be()[1..32].to_vec()).collect(); - - match String::from_utf8(bytes_err) { - Ok(s) => s.trim_matches('\0').to_owned(), - Err(_) => { - let err_msgs = encoding - .iter() - .map(|felt| match String::from_utf8(felt.to_bytes_be()[1..32].to_vec()) { - Ok(s) => format!("{} ({})", s.trim_matches('\0'), felt), - Err(_) => felt.to_string(), - }) - .join(", "); - format!("[{}]", err_msgs) - } - } -} diff --git a/crates/blockifier/src/execution/native/utils_test.rs b/crates/blockifier/src/execution/native/utils_test.rs deleted file mode 100644 index 1f295fe74f..0000000000 --- a/crates/blockifier/src/execution/native/utils_test.rs +++ /dev/null @@ -1,42 +0,0 @@ -use cairo_lang_starknet_classes::contract_class::ContractEntryPoint; -use num_bigint::BigUint; -use pretty_assertions::assert_eq; -use starknet_api::core::EntryPointSelector; -use starknet_types_core::felt::Felt; - -use super::{contract_entrypoint_to_entrypoint_selector, decode_felts_as_str, encode_str_as_felts}; - -#[test] -fn test_encode_decode_str() { - const STR: &str = "Hello StarkNet!"; - - let encoded_felt_array = encode_str_as_felts(STR); - - let decoded_felt_array = decode_felts_as_str(encoded_felt_array.as_slice()); - - assert_eq!(&decoded_felt_array, STR); -} - -#[test] -fn test_decode_non_utf8_str() { - let v1 = Felt::from_dec_str("1234").unwrap(); - let v2_msg = "i am utf8"; - let v2 = Felt::from_bytes_be_slice(v2_msg.as_bytes()); - let v3 = Felt::from_dec_str("13299428").unwrap(); - let felts = [v1, v2, v3]; - - let res = decode_felts_as_str(&felts); - dbg!(res.as_bytes()); - assert_eq!(res, format!("[{}, {} ({}), {}]", v1, v2_msg, v2, v3)) -} - -#[test] -fn test_contract_entrypoint_to_entrypoint_selector() { - const NUM: u128 = 123; - - let entrypoint = ContractEntryPoint { selector: BigUint::from(NUM), function_idx: 0 }; - let expected_entrypoint_selector = EntryPointSelector(Felt::from(NUM)); - let actual_entrypoint_selector = contract_entrypoint_to_entrypoint_selector(&entrypoint); - - assert_eq!(actual_entrypoint_selector, expected_entrypoint_selector); -}