Skip to content

Commit

Permalink
feat(blockifier): add call_contract cairo native syscall
Browse files Browse the repository at this point in the history
  • Loading branch information
PearsonWhite authored and varex83 committed Nov 13, 2024
1 parent 2b4f533 commit 39f53e8
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 8 deletions.
47 changes: 40 additions & 7 deletions crates/blockifier/src/execution/native/syscall_handler.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::HashSet;
use std::hash::RandomState;
use std::sync::Arc;

use cairo_native::starknet::{
ExecutionInfo,
Expand All @@ -12,11 +13,15 @@ use cairo_native::starknet::{
};
use cairo_native::starknet_stub::encode_str_as_felts;
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::fields::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::syscalls::hint_processor::{SyscallExecutionError, OUT_OF_GAS_ERROR};
use crate::state::state_api::State;

Expand Down Expand Up @@ -57,7 +62,6 @@ impl<'state> NativeSyscallHandler<'state> {
}
}

#[allow(dead_code)]
fn execute_inner_call(
&mut self,
entry_point: CallEntryPoint,
Expand Down Expand Up @@ -168,12 +172,41 @@ 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<Vec<Felt>> {
todo!("Implement call_contract syscall.");
self.pre_execute_syscall(remaining_gas, self.context.gas_costs().call_contract_gas_cost)?;

let contract_address = ContractAddress::try_from(address)
.map_err(|error| self.handle_error(remaining_gas, error.into()))?;
if self.context.execution_mode == ExecutionMode::Validate
&& self.call.storage_address != contract_address
{
let err = SyscallExecutionError::InvalidSyscallInExecutionMode {
syscall_name: "call_contract".to_string(),
execution_mode: self.context.execution_mode,
};
return Err(self.handle_error(remaining_gas, err));
}

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.call.caller_address,
call_type: CallType::Call,
initial_gas: u64::try_from(*remaining_gas)
.expect("Failed to convert gas from u128 to u64."),
};

Ok(self.execute_inner_call(entry_point, remaining_gas)?.0)
}

fn storage_read(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,15 @@ fn test_call_contract_that_panics() {
);
}

#[cfg_attr(
feature = "cairo_native",
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),
Expand Down Expand Up @@ -106,7 +115,30 @@ fn test_call_contract(
);
}

/// Cairo0 / Old Cairo1 / Cairo1 calls to Cairo0 / Old Cairo1/ Cairo1.
/// Cairo0 / Old Cairo1 / Cairo1 / Native calls to Cairo0 / Old Cairo1 / Cairo1 / Native.
#[cfg(feature = "cairo_native")]
#[rstest]
fn test_tracked_resources(
#[values(
CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0),
CompilerBasedVersion::OldCairo1,
CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1),
CompilerBasedVersion::CairoVersion(CairoVersion::Native)
)]
outer_version: CompilerBasedVersion,
#[values(
CompilerBasedVersion::CairoVersion(CairoVersion::Cairo0),
CompilerBasedVersion::OldCairo1,
CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1),
CompilerBasedVersion::CairoVersion(CairoVersion::Native)
)]
inner_version: CompilerBasedVersion,
) {
test_tracked_resources_fn(outer_version, inner_version);
}

/// Cairo0 / Old Cairo1 / Cairo1 calls to Cairo0 / Old Cairo1 / Cairo1.
#[cfg(not(feature = "cairo_native"))]
#[rstest]
fn test_tracked_resources(
#[values(
Expand All @@ -121,6 +153,13 @@ fn test_tracked_resources(
CompilerBasedVersion::CairoVersion(CairoVersion::Cairo1)
)]
inner_version: CompilerBasedVersion,
) {
test_tracked_resources_fn(outer_version, inner_version);
}

fn test_tracked_resources_fn(
outer_version: CompilerBasedVersion,
inner_version: CompilerBasedVersion,
) {
let outer_contract = outer_version.get_test_contract();
let inner_contract = inner_version.get_test_contract();
Expand All @@ -139,12 +178,15 @@ fn test_tracked_resources(
let expected_outer_resource = outer_version.own_tracked_resource();
assert_eq!(execution.tracked_resource, expected_outer_resource);

// If the outer call uses CairoSteps, then use it for inner.
// See execute_entry_point_call_wrapper in crates/blockifier/src/execution/execution_utils.rs
let expected_inner_resource = if expected_outer_resource == inner_version.own_tracked_resource()
{
expected_outer_resource
} else {
TrackedResource::CairoSteps
};

assert_eq!(execution.inner_calls.first().unwrap().tracked_resource, expected_inner_resource);
}

Expand Down

0 comments on commit 39f53e8

Please sign in to comment.