From 4c0a5bd19fb23d8ed8cc052fb8a3a7d2b5e8d78e Mon Sep 17 00:00:00 2001 From: Pearson White Date: Wed, 23 Oct 2024 12:36:38 -0400 Subject: [PATCH] feat(blockifier): add library_call cairo native syscall --- .../src/execution/native/syscall_handler.rs | 43 +++++++++++++++---- .../syscalls/syscall_tests/library_call.rs | 16 +++++-- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/crates/blockifier/src/execution/native/syscall_handler.rs b/crates/blockifier/src/execution/native/syscall_handler.rs index cabaa3220f..f5e8c7f0ea 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,12 +12,14 @@ use cairo_native::starknet::{ U256, }; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; -use starknet_api::core::{ContractAddress, EntryPointSelector}; +use starknet_api::contract_class::EntryPointType; +use starknet_api::core::{ClassHash, 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::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::SyscallSelector; @@ -69,13 +72,11 @@ impl<'state> NativeSyscallHandler<'state> { } } - #[allow(dead_code)] fn increment_syscall_count_by(&mut self, selector: &SyscallSelector, n: usize) { let syscall_count = self.syscall_counter.entry(*selector).or_default(); *syscall_count += n } - #[allow(dead_code)] fn execute_inner_call( &mut self, entry_point: CallEntryPoint, @@ -171,12 +172,36 @@ impl<'state> StarknetSyscallHandler for &mut NativeSyscallHandler<'state> { fn library_call( &mut self, - _class_hash: Felt, - _function_selector: Felt, - _calldata: &[Felt], - _remaining_gas: &mut u128, + class_hash: Felt, + function_selector: Felt, + calldata: &[Felt], + remaining_gas: &mut u128, ) -> SyscallResult> { - todo!("Implement library_call syscall."); + self.substract_syscall_gas_cost( + remaining_gas, + SyscallSelector::LibraryCall, + self.context.gas_costs().library_call_gas_cost, + )?; + + let class_hash = ClassHash(class_hash); + + let wrapper_calldata = Calldata(Arc::new(calldata.to_vec())); + + let entry_point = CallEntryPoint { + class_hash: Some(class_hash), + code_address: None, + entry_point_type: EntryPointType::External, + entry_point_selector: EntryPointSelector(function_selector), + calldata: wrapper_calldata, + // The call context remains the same in a library call. + storage_address: self.contract_address, + caller_address: self.caller_address, + call_type: CallType::Delegate, + initial_gas: u64::try_from(*remaining_gas) + .expect("Failed to convert gas (u128 -> u64)"), + }; + + Ok(self.execute_inner_call(entry_point, remaining_gas)?.0) } fn call_contract( diff --git a/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs b/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs index e6eda072d6..c0d590d094 100644 --- a/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs +++ b/crates/blockifier/src/execution/syscalls/syscall_tests/library_call.rs @@ -29,6 +29,7 @@ use crate::test_utils::{ }; use crate::versioned_constants::VersionedConstants; +#[test_case(FeatureContract::TestContract(CairoVersion::Native), 189470; "Native")] #[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), REQUIRED_GAS_LIBRARY_CALL_TEST; "VM")] fn test_library_call(test_contract: FeatureContract, expected_gas: u64) { let chain_info = &ChainInfo::create_for_testing(); @@ -60,6 +61,7 @@ fn test_library_call(test_contract: FeatureContract, expected_gas: u64) { ); } +#[test_case(FeatureContract::TestContract(CairoVersion::Native); "Native")] #[test_case(FeatureContract::TestContract(CairoVersion::Cairo1); "VM")] fn test_library_call_assert_fails(test_contract: FeatureContract) { let chain_info = &ChainInfo::create_for_testing(); @@ -81,12 +83,18 @@ fn test_library_call_assert_fails(test_contract: FeatureContract) { let call_info = entry_point_call.execute_directly(&mut state).unwrap(); assert!(call_info.execution.failed); - assert_eq!( - format_panic_data(&call_info.execution.retdata.0), - "(0x7820213d2079 ('x != y'), 0x454e545259504f494e545f4641494c4544 ('ENTRYPOINT_FAILED'))" - ); + + let expected_err = match test_contract.cairo_version() { + CairoVersion::Cairo0 | CairoVersion::Cairo1 => { + "(0x7820213d2079 ('x != y'), 0x454e545259504f494e545f4641494c4544 \ + ('ENTRYPOINT_FAILED'))" + } + CairoVersion::Native => "0x7820213d2079 ('x != y')", + }; + assert_eq!(format_panic_data(&call_info.execution.retdata.0), expected_err); } +#[test_case(FeatureContract::TestContract(CairoVersion::Native), 518110; "Native")] #[test_case(FeatureContract::TestContract(CairoVersion::Cairo1), 478110; "VM")] fn test_nested_library_call(test_contract: FeatureContract, expected_gas: u64) { let chain_info = &ChainInfo::create_for_testing();