From 3e3c03886dc7294b564b6c9f2fd2af76b24765f2 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 3 Oct 2024 18:49:31 -0400 Subject: [PATCH] feat: entry point execution logic --- crates/blockifier/src/execution/errors.rs | 8 ++ .../src/execution/execution_utils.rs | 16 ++- crates/blockifier/src/execution/native.rs | 1 + .../execution/native/entry_point_execution.rs | 111 ++++++++++++++++++ 4 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 crates/blockifier/src/execution/native/entry_point_execution.rs diff --git a/crates/blockifier/src/execution/errors.rs b/crates/blockifier/src/execution/errors.rs index 5098506c62..7f9f5d66d5 100644 --- a/crates/blockifier/src/execution/errors.rs +++ b/crates/blockifier/src/execution/errors.rs @@ -1,5 +1,6 @@ use std::collections::HashSet; +use cairo_native::error::Error as NativeRunnerError; use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::types::errors::math_errors::MathError; use cairo_vm::vm::errors::cairo_run_errors::CairoRunError; @@ -87,6 +88,13 @@ pub enum EntryPointExecutionError { InternalError(String), #[error("Invalid input: {input_descriptor}; {info}")] InvalidExecutionInput { input_descriptor: String, info: String }, + #[error("Native execution error: {info}")] + NativeExecutionError { info: String }, + #[error("Native unexpected error: {source}")] + NativeUnexpectedError { + #[source] + source: NativeRunnerError, + }, #[error(transparent)] PostExecutionError(#[from] PostExecutionError), #[error(transparent)] diff --git a/crates/blockifier/src/execution/execution_utils.rs b/crates/blockifier/src/execution/execution_utils.rs index 56d8e14893..712f94fa83 100644 --- a/crates/blockifier/src/execution/execution_utils.rs +++ b/crates/blockifier/src/execution/execution_utils.rs @@ -22,18 +22,18 @@ use starknet_api::deprecated_contract_class::Program as DeprecatedProgram; use starknet_api::transaction::Calldata; use starknet_types_core::felt::Felt; -use super::entry_point::ConstructorEntryPointExecutionResult; -use super::errors::ConstructorEntryPointExecutionError; use crate::execution::call_info::{CallInfo, Retdata}; use crate::execution::contract_class::{ContractClass, TrackedResource}; use crate::execution::entry_point::{ execute_constructor_entry_point, CallEntryPoint, ConstructorContext, + ConstructorEntryPointExecutionResult, EntryPointExecutionContext, EntryPointExecutionResult, }; -use crate::execution::errors::PostExecutionError; +use crate::execution::errors::{ConstructorEntryPointExecutionError, PostExecutionError}; +use crate::execution::native::entry_point_execution as native_entry_point_execution; use crate::execution::{deprecated_entry_point_execution, entry_point_execution}; use crate::state::errors::StateError; use crate::state::state_api::State; @@ -93,8 +93,14 @@ pub fn execute_entry_point_call( resources, context, ), - ContractClass::V1Native(_contract_class) => { - unimplemented!("Native contract entry point execution is not yet implemented.") + ContractClass::V1Native(contract_class) => { + native_entry_point_execution::execute_entry_point_call( + call, + contract_class, + state, + resources, + context, + ) } } } diff --git a/crates/blockifier/src/execution/native.rs b/crates/blockifier/src/execution/native.rs index 7c3dd35b21..b5d4461247 100644 --- a/crates/blockifier/src/execution/native.rs +++ b/crates/blockifier/src/execution/native.rs @@ -1,3 +1,4 @@ +pub mod entry_point_execution; pub mod syscall_handler; pub mod utils; diff --git a/crates/blockifier/src/execution/native/entry_point_execution.rs b/crates/blockifier/src/execution/native/entry_point_execution.rs new file mode 100644 index 0000000000..070dc22cb9 --- /dev/null +++ b/crates/blockifier/src/execution/native/entry_point_execution.rs @@ -0,0 +1,111 @@ +use std::collections::HashMap; + +use cairo_lang_sierra::ids::FunctionId; +use cairo_native::execution_result::ContractExecutionResult; +use cairo_native::executor::AotNativeExecutor; +use cairo_vm::vm::runners::cairo_runner::ExecutionResources; + +use super::utils::decode_felts_as_str; +// use c::utils::run_native_executor; +use crate::execution::call_info::{CallExecution, CallInfo, Retdata}; +use crate::execution::contract_class::{NativeContractClassV1, TrackedResource}; +use crate::execution::entry_point::{ + CallEntryPoint, + EntryPointExecutionContext, + EntryPointExecutionResult, +}; +use crate::execution::errors::EntryPointExecutionError; +use crate::execution::native::syscall_handler::NativeSyscallHandler; +use crate::state::state_api::State; + +pub fn execute_entry_point_call( + call: CallEntryPoint, + contract_class: NativeContractClassV1, + state: &mut dyn State, + resources: &mut ExecutionResources, + context: &mut EntryPointExecutionContext, +) -> EntryPointExecutionResult { + let function_id = contract_class.get_entry_point(&call)?; + + let syscall_handler: NativeSyscallHandler<'_> = NativeSyscallHandler::new( + state, + call.caller_address, + call.storage_address, + call.entry_point_selector, + resources, + context, + ); + + run_native_executor(&contract_class.executor, function_id, call, syscall_handler) +} + +fn run_native_executor( + native_executor: &AotNativeExecutor, + function_id: &FunctionId, + call: CallEntryPoint, + mut syscall_handler: NativeSyscallHandler<'_>, +) -> EntryPointExecutionResult { + let execution_result = native_executor.invoke_contract_dynamic( + function_id, + &call.calldata.0, + Some(call.initial_gas.into()), + &mut syscall_handler, + ); + + let run_result = match execution_result { + Err(runner_err) => { + Err(EntryPointExecutionError::NativeUnexpectedError { source: runner_err }) + } + Ok(res) if res.failure_flag => Err(EntryPointExecutionError::NativeExecutionError { + info: if !res.return_values.is_empty() { + decode_felts_as_str(&res.return_values) + } else { + String::from("Unknown error") + }, + }), + Ok(res) => Ok(res), + }?; + + create_callinfo(call.clone(), run_result, syscall_handler) +} + +fn create_callinfo( + call: CallEntryPoint, + run_result: ContractExecutionResult, + syscall_handler: NativeSyscallHandler<'_>, +) -> Result { + let gas_consumed = { + // We can use `.unwrap()` directly in both cases because the most significant bit is could + // be only 63 here (128 = 64 + 64). + let low: u64 = (run_result.remaining_gas & ((1u128 << 64) - 1)).try_into().unwrap(); + let high: u64 = (run_result.remaining_gas >> 64).try_into().unwrap(); + if high != 0 { + return Err(EntryPointExecutionError::NativeExecutionError { + info: "Overflow: gas consumed bigger than 64 bit".into(), + }); + } + call.initial_gas - low + }; + + Ok(CallInfo { + call, + execution: CallExecution { + retdata: Retdata(run_result.return_values), + events: syscall_handler.events, + l2_to_l1_messages: syscall_handler.l2_to_l1_messages, + failed: run_result.failure_flag, + gas_consumed, + }, + // todo(rodrigo): execution resources rely heavily on how the VM work, therefore + // the dummy values + resources: ExecutionResources { + n_steps: 0, + n_memory_holes: 0, + builtin_instance_counter: HashMap::default(), + }, + inner_calls: syscall_handler.inner_calls, + storage_read_values: syscall_handler.read_values, + accessed_storage_keys: syscall_handler.accessed_keys, + tracked_resource: TrackedResource::SierraGas, + }) +}