diff --git a/crates/blockifier/src/execution/native/syscall_handler.rs b/crates/blockifier/src/execution/native/syscall_handler.rs index cabaa3220f..3e11fe40a2 100644 --- a/crates/blockifier/src/execution/native/syscall_handler.rs +++ b/crates/blockifier/src/execution/native/syscall_handler.rs @@ -1,5 +1,6 @@ use std::collections::HashSet; use std::hash::RandomState; +use std::sync::Arc; use cairo_native::starknet::{ ExecutionInfo, @@ -11,14 +12,21 @@ use cairo_native::starknet::{ U256, }; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; +use starknet_api::contract_class::EntryPointType; use starknet_api::core::{ContractAddress, EntryPointSelector}; use starknet_api::state::StorageKey; +use starknet_api::transaction::Calldata; use starknet_types_core::felt::Felt; use crate::execution::call_info::{CallInfo, OrderedEvent, OrderedL2ToL1Message, Retdata}; -use crate::execution::entry_point::{CallEntryPoint, EntryPointExecutionContext}; +use crate::execution::common_hints::ExecutionMode; +use crate::execution::entry_point::{CallEntryPoint, CallType, EntryPointExecutionContext}; use crate::execution::native::utils::encode_str_as_felts; -use crate::execution::syscalls::hint_processor::{SyscallCounter, OUT_OF_GAS_ERROR}; +use crate::execution::syscalls::hint_processor::{ + SyscallCounter, + SyscallExecutionError, + OUT_OF_GAS_ERROR, +}; use crate::execution::syscalls::SyscallSelector; use crate::state::state_api::State; @@ -75,7 +83,6 @@ impl<'state> NativeSyscallHandler<'state> { *syscall_count += n } - #[allow(dead_code)] fn execute_inner_call( &mut self, entry_point: CallEntryPoint, @@ -181,12 +188,44 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { fn call_contract( &mut self, - _address: Felt, - _entry_point_selector: Felt, - _calldata: &[Felt], - _remaining_gas: &mut u128, + address: Felt, + entry_point_selector: Felt, + calldata: &[Felt], + remaining_gas: &mut u128, ) -> SyscallResult> { - todo!("Implement call_contract syscall."); + self.substract_syscall_gas_cost( + remaining_gas, + SyscallSelector::CallContract, + self.context.gas_costs().call_contract_gas_cost, + )?; + + let contract_address = ContractAddress::try_from(address) + .expect("Failed to convert address argument to a ContractAddress"); + if self.context.execution_mode == ExecutionMode::Validate + && self.contract_address != contract_address + { + let err = SyscallExecutionError::InvalidSyscallInExecutionMode { + syscall_name: "call_contract".to_string(), + execution_mode: self.context.execution_mode, + }; + return Err(encode_str_as_felts(&err.to_string())); + } + + let wrapper_calldata = Calldata(Arc::new(calldata.to_vec())); + + let entry_point = CallEntryPoint { + class_hash: None, + code_address: Some(contract_address), + entry_point_type: EntryPointType::External, + entry_point_selector: EntryPointSelector(entry_point_selector), + calldata: wrapper_calldata, + storage_address: contract_address, + caller_address: self.contract_address, + call_type: CallType::Call, + initial_gas: u64::try_from(*remaining_gas).unwrap(), + }; + + Ok(self.execute_inner_call(entry_point, remaining_gas)?.0) } fn storage_read( diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/call_contract.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/call_contract.rs index dbe54353e6..a8c4ee19d6 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/call_contract.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/call_contract.rs @@ -60,6 +60,12 @@ fn test_call_contract_that_panics() { ); } +#[test_case( + FeatureContract::TestContract(CairoVersion::Native), + FeatureContract::TestContract(CairoVersion::Native), + 191870; + "Call Contract between two contracts using Native" +)] #[test_case( FeatureContract::TestContract(CairoVersion::Cairo1), FeatureContract::TestContract(CairoVersion::Cairo1), @@ -102,8 +108,10 @@ fn test_call_contract( /// Cairo0 / Cairo1 calls to Cairo0 / Cairo1. #[rstest] fn test_track_resources( - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] outer_version: CairoVersion, - #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] inner_version: CairoVersion, + #[values(CairoVersion::Cairo0, CairoVersion::Cairo1, CairoVersion::Native)] + outer_version: CairoVersion, + #[values(CairoVersion::Cairo0, CairoVersion::Cairo1, CairoVersion::Native)] + inner_version: CairoVersion, ) { let outer_contract = FeatureContract::TestContract(outer_version); let inner_contract = FeatureContract::TestContract(inner_version); @@ -132,12 +140,9 @@ fn test_track_resources( }; assert_eq!(execution.tracked_resource, expected_outer_resource); - let expected_inner_resource = match (outer_version, inner_version) { - ( - CairoVersion::Cairo1 | CairoVersion::Native, - CairoVersion::Cairo1 | CairoVersion::Native, - ) => TrackedResource::SierraGas, - _ => TrackedResource::CairoSteps, + let expected_inner_resource = match inner_version { + CairoVersion::Cairo0 => TrackedResource::CairoSteps, + CairoVersion::Cairo1 | CairoVersion::Native => TrackedResource::SierraGas, }; assert_eq!(execution.inner_calls.first().unwrap().tracked_resource, expected_inner_resource); }