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 committed Nov 1, 2024
1 parent 4d4f0d3 commit 7b1f51d
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 15 deletions.
57 changes: 49 additions & 8 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 @@ -11,13 +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;

Expand Down Expand Up @@ -67,7 +76,6 @@ impl<'state> NativeSyscallHandler<'state> {
*syscall_count += n
}

#[allow(dead_code)]
fn execute_inner_call(
&mut self,
entry_point: CallEntryPoint,
Expand Down Expand Up @@ -173,12 +181,45 @@ 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.substract_syscall_gas_cost(
remaining_gas,
SyscallSelector::CallContract,
self.context.gas_costs().call_contract_gas_cost,
)?;

let contract_address = ContractAddress::try_from(address)
.map_err(|error| encode_str_as_felts(&error.to_string()))?;
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(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.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,26 @@ fn test_tracked_resources(
let expected_outer_resource = outer_version.own_tracked_resource();
assert_eq!(execution.tracked_resource, expected_outer_resource);

let expected_inner_resource = if expected_outer_resource == inner_version.own_tracked_resource()
{
expected_outer_resource
} else {
TrackedResource::CairoSteps
};
// For native, this logic will be modified below.
let expected_inner_resource =
// If outer and inner are the same, we expect the tracked resource to be the same.
if expected_outer_resource == inner_version.own_tracked_resource() {
expected_outer_resource
} else {
// If outer and inner are not the same, and inner is not Native, we expect CairoSteps.
TrackedResource::CairoSteps
};

#[cfg(feature = "cairo_native")]
// If inner is Native, we expect inner to use SierraGas.
// This overrides previous logic.
let expected_inner_resource =
if inner_version == CompilerBasedVersion::CairoVersion(CairoVersion::Native) {
TrackedResource::SierraGas
} else {
expected_inner_resource
};

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

Expand Down

0 comments on commit 7b1f51d

Please sign in to comment.