Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions crates/cheatnet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ camino.workspace = true
starknet_api.workspace = true
starknet-types-core.workspace = true
cairo-lang-casm.workspace = true
cairo-lang-sierra.workspace = true
cairo-lang-utils.workspace = true
cairo-lang-starknet-classes.workspace = true
cairo-vm.workspace = true
cairo-native.workspace = true
cairo-annotations.workspace = true
regex.workspace = true
indoc.workspace = true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::cairo1_execution::execute_entry_point_call_cairo1;
use super::native_execution::execute_entry_point_call_native;
use crate::runtime_extensions::call_to_blockifier_runtime_extension::execution::deprecated::cairo0_execution::execute_entry_point_call_cairo0;
use crate::runtime_extensions::call_to_blockifier_runtime_extension::rpc::{AddressOrClassHash, CallResult};
use crate::runtime_extensions::call_to_blockifier_runtime_extension::CheatnetState;
Expand Down Expand Up @@ -172,8 +173,14 @@ pub fn execute_call_entry_point(
cheatnet_state,
context,
),
RunnableCompiledClass::V1Native(_) => {
todo!("execute inner call with Cairo Native")
RunnableCompiledClass::V1Native(native_compiled_class_v1) => {
execute_entry_point_call_native(
entry_point.clone(),
&native_compiled_class_v1,
state,
cheatnet_state,
context,
)
}
};
context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ pub mod cheated_syscalls;
pub mod deprecated;
pub mod entry_point;
pub mod execution_info;
pub mod native_execution;
pub mod syscall_hooks;
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
use std::collections::HashMap;

use blockifier::{
execution::{
call_info::{CallExecution, CallInfo, Retdata},
contract_class::TrackedResource,
entry_point::{EntryPointExecutionContext, ExecutableCallEntryPoint},
errors::{EntryPointExecutionError, PostExecutionError, PreExecutionError},
native::{contract_class::NativeCompiledClassV1, syscall_handler::NativeSyscallHandler},
syscalls::vm_syscall_utils::SyscallUsageMap,
},
state::state_api::State,
};
use cairo_native::{execution_result::ContractExecutionResult, utils::BuiltinCosts};
use runtime::native::{NativeExtendedRuntime, NativeStarknetRuntime};

use crate::{
runtime_extensions::cheatable_starknet_runtime_extension::CheatableStarknetRuntimeExtension,
state::CheatnetState,
};

use super::entry_point::{CallInfoWithExecutionData, ContractClassEntryPointExecutionResult};

// blockifier/src/execution/native/entry_point_execution.rs:20 (execute_entry_point_call)
#[expect(clippy::result_large_err)]
pub(crate) fn execute_entry_point_call_native(
call: ExecutableCallEntryPoint,
compiled_class: &NativeCompiledClassV1,
state: &mut dyn State,
cheatnet_state: &mut CheatnetState, // Added parameter
context: &mut EntryPointExecutionContext,
) -> ContractClassEntryPointExecutionResult {
let entry_point = compiled_class.get_entry_point(&call.type_and_selector())?;

let syscall_handler: NativeSyscallHandler<'_> = NativeSyscallHandler::new(call, state, context);

let gas_costs = syscall_handler.base.context.gas_costs();
let builtin_costs = BuiltinCosts {
r#const: 1,
pedersen: gas_costs.builtins.pedersen,
bitwise: gas_costs.builtins.bitwise,
ecop: gas_costs.builtins.ecop,
poseidon: gas_costs.builtins.poseidon,
add_mod: gas_costs.builtins.add_mod,
mul_mod: gas_costs.builtins.mul_mod,
};

let initial_budget = syscall_handler
.base
.context
.gas_costs()
.base
.entry_point_initial_budget;
let call_initial_gas = syscall_handler
.base
.call
.initial_gas
.checked_sub(initial_budget)
.ok_or(PreExecutionError::InsufficientEntryPointGas)?;

// region: Modified blockifier code
let mut cheatable_runtime = NativeExtendedRuntime {
extension: CheatableStarknetRuntimeExtension { cheatnet_state },
runtime: NativeStarknetRuntime { syscall_handler },
};
let execution_result = compiled_class.executor.run(
entry_point.selector.0,
&cheatable_runtime
.runtime
.syscall_handler
.base
.call
.calldata
.0
.clone(),
call_initial_gas,
Some(builtin_costs),
&mut cheatable_runtime,
);
let mut syscall_handler = cheatable_runtime.runtime.syscall_handler;
// endregion

syscall_handler.finalize();

let call_result = execution_result.map_err(EntryPointExecutionError::NativeUnexpectedError)?;

if let Some(error) = syscall_handler.unrecoverable_error {
return Err(EntryPointExecutionError::NativeUnrecoverableError(Box::new(error)).into());
}

let call_info_result = create_callinfo(call_result, syscall_handler);

// region: Modified blockifier code
Ok(CallInfoWithExecutionData {
call_info: call_info_result?,
syscall_usage_vm_resources: SyscallUsageMap::default(),
syscall_usage_sierra_gas: SyscallUsageMap::default(),
vm_trace: None,
})
// endregion
}

#[allow(clippy::result_large_err)]
fn create_callinfo(
call_result: ContractExecutionResult,
syscall_handler: NativeSyscallHandler<'_>,
) -> Result<CallInfo, EntryPointExecutionError> {
let remaining_gas = call_result.remaining_gas;

if remaining_gas > syscall_handler.base.call.initial_gas {
return Err(PostExecutionError::MalformedReturnData {
error_message: format!(
"Unexpected remaining gas. Used gas is greater than initial gas: {} > {}",
remaining_gas, syscall_handler.base.call.initial_gas
),
}
.into());
}

let gas_consumed = syscall_handler.base.call.initial_gas - remaining_gas;
let vm_resources = CallInfo::summarize_vm_resources(syscall_handler.base.inner_calls.iter());

Ok(CallInfo {
call: syscall_handler.base.call.into(),
execution: CallExecution {
retdata: Retdata(call_result.return_values),
events: syscall_handler.base.events,
cairo_native: true,
l2_to_l1_messages: syscall_handler.base.l2_to_l1_messages,
failed: call_result.failure_flag,
gas_consumed,
},
resources: vm_resources,
inner_calls: syscall_handler.base.inner_calls,
storage_access_tracker: syscall_handler.base.storage_access_tracker,
tracked_resource: TrackedResource::SierraGas,
builtin_counters: HashMap::default(),
})
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::marker::PhantomData;
use std::sync::Arc;

use blockifier::execution::entry_point::{CallEntryPoint, CallType};
use blockifier::execution::execution_utils::felt_from_ptr;
Expand All @@ -11,12 +12,15 @@ use blockifier::execution::{
execution_utils::ReadOnlySegment,
syscalls::vm_syscall_utils::{SyscallRequest, SyscallResponse, SyscallResponseWrapper},
};
use cairo_native::starknet::SyscallResult;
use cairo_vm::types::relocatable::MaybeRelocatable;
use cairo_vm::vm::{errors::hint_errors::HintError, vm_core::VirtualMachine};
use runtime::native::{NativeExtendedRuntime, NativeExtensionLogic};
use conversions::serde::serialize::SerializeToFeltVec;
use runtime::native::{NativeExtendedRuntime, NativeExtensionLogic, NativeSyscallHandlingResult};
use runtime::{ExtendedRuntime, ExtensionLogic, SyscallHandlingResult, SyscallPtrAccess};
use starknet_api::contract_class::EntryPointType;
use starknet_api::core::ContractAddress;
use starknet_api::core::{ContractAddress, EntryPointSelector};
use starknet_api::transaction::fields::Calldata;

use crate::state::CheatnetState;

Expand Down Expand Up @@ -86,6 +90,46 @@ impl<'a> ExtensionLogic for CallToBlockifierExtension<'a> {

impl<'a> NativeExtensionLogic for CallToBlockifierExtension<'a> {
type Runtime = &'a mut NativeExtendedRuntime<CheatableStarknetRuntimeExtension<'a>>;

fn handle_call_contract(
&mut self,
address: cairo_vm::Felt252,
entry_point_selector: cairo_vm::Felt252,
calldata: &[cairo_vm::Felt252],
_remaining_gas: &mut u64,
runtime: &mut Self::Runtime,
) -> NativeSyscallHandlingResult<SyscallResult<Vec<cairo_vm::Felt252>>> {
let contract_address = ContractAddress::try_from(address).unwrap();

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: Calldata(Arc::new(calldata.to_vec())),
storage_address: contract_address,
caller_address: TryFromHexStr::try_from_hex_str(TEST_ADDRESS).unwrap(),
call_type: CallType::Call,
initial_gas: i64::MAX as u64,
};

let result = call_entry_point(
&mut runtime.runtime.syscall_handler.base,
runtime.extension.cheatnet_state,
entry_point,
&AddressOrClassHash::ContractAddress(contract_address),
);

match result {
CallResult::Success { ret_data } => NativeSyscallHandlingResult::Handled(Ok(ret_data)),
CallResult::Failure(call_failure) => {
NativeSyscallHandlingResult::Handled(Err(match call_failure {
CallFailure::Panic { panic_data } => panic_data,
CallFailure::Error { msg } => msg.serialize_to_vec(),
}))
}
}
}
}

trait ExecuteCall
Expand Down Expand Up @@ -120,7 +164,7 @@ impl ExecuteCall for CallContractRequest {
};

call_entry_point(
syscall_handler,
&mut syscall_handler.base,
cheatnet_state,
entry_point,
&AddressOrClassHash::ContractAddress(contract_address),
Expand Down Expand Up @@ -149,7 +193,7 @@ impl ExecuteCall for LibraryCallRequest {
};

call_entry_point(
syscall_handler,
&mut syscall_handler.base,
cheatnet_state,
entry_point,
&AddressOrClassHash::ClassHash(class_hash),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use blockifier::execution::{
call_info::CallInfo,
entry_point::{CallType, EntryPointExecutionResult},
errors::{EntryPointExecutionError, PreExecutionError},
syscalls::hint_processor::SyscallHintProcessor,
syscalls::{hint_processor::SyscallHintProcessor, syscall_base::SyscallHandlerBase},
};
use blockifier::execution::{
entry_point::CallEntryPoint, syscalls::vm_syscall_utils::SyscallUsageMap,
Expand Down Expand Up @@ -192,31 +192,31 @@ pub fn call_l1_handler(
};

call_entry_point(
syscall_handler,
&mut syscall_handler.base,
cheatnet_state,
entry_point,
&AddressOrClassHash::ContractAddress(*contract_address),
)
}

pub fn call_entry_point(
syscall_handler: &mut SyscallHintProcessor,
syscall_handler: &mut SyscallHandlerBase,
cheatnet_state: &mut CheatnetState,
mut entry_point: CallEntryPoint,
starknet_identifier: &AddressOrClassHash,
) -> CallResult {
let exec_result = execute_call_entry_point(
&mut entry_point,
syscall_handler.base.state,
syscall_handler.state,
cheatnet_state,
syscall_handler.base.context,
syscall_handler.context,
false,
);

let result = CallResult::from_execution_result(&exec_result, starknet_identifier);

if let Ok(call_info) = exec_result {
syscall_handler.base.inner_calls.push(call_info);
syscall_handler.inner_calls.push(call_info);
}

result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ use crate::runtime_extensions::forge_runtime_extension::{
};
use anyhow::{Context, Result};
use blockifier::execution::contract_class::{CompiledClassV1, RunnableCompiledClass};
use blockifier::execution::native::contract_class::NativeCompiledClassV1;
use blockifier::state::{errors::StateError, state_api::State};
use cairo_lang_starknet_classes::contract_class::{
ContractClass, version_id_from_serialized_sierra_program,
};
use cairo_native::executor::AotContractExecutor;
use conversions::IntoConv;
use conversions::serde::serialize::CairoSerialize;
use starknet::core::types::contract::SierraClass;
Expand All @@ -32,7 +37,33 @@ pub fn declare(
get_current_sierra_version(),
)
.expect("Failed to read contract class from json");
let contract_class = RunnableCompiledClass::V1(contract_class);

// TODO: We are compiling a contract class with Native each time its
// declared. We should compile it once, like we do with CASM.

let sierra_contract_class: ContractClass =
serde_json::from_str(&contract_artifact.sierra).map_err(EnhancedHintError::from)?;

let (sierra_version, _) =
version_id_from_serialized_sierra_program(&sierra_contract_class.sierra_program)
.map_err(anyhow::Error::from)
.map_err(EnhancedHintError::from)?;

let aot_executor = AotContractExecutor::new(
&sierra_contract_class
.extract_sierra_program()
.map_err(anyhow::Error::from)
.map_err(EnhancedHintError::from)?,
&sierra_contract_class.entry_points_by_type,
sierra_version,
cairo_native::OptLevel::Default,
None,
)
.map_err(anyhow::Error::from)
.map_err(EnhancedHintError::from)?;

let contract_class =
RunnableCompiledClass::V1Native(NativeCompiledClassV1::new(aot_executor, contract_class));

let class_hash = *contracts_data
.get_class_hash(contract_name)
Expand Down
Loading
Loading