Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

Commit

Permalink
Get gas_consumed from the return values of the execution. (#555)
Browse files Browse the repository at this point in the history
  • Loading branch information
noaov1 authored Jun 10, 2023
1 parent 14ba5e6 commit ed7771f
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 43 deletions.
85 changes: 62 additions & 23 deletions crates/blockifier/src/execution/cairo1_execution.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use cairo_felt::Felt252;
use cairo_vm::types::relocatable::{MaybeRelocatable, Relocatable};
use cairo_vm::vm::errors::vm_errors::VirtualMachineError;
use cairo_vm::vm::runners::cairo_runner::{
Expand All @@ -9,14 +10,14 @@ use starknet_api::stark_felt;

use crate::execution::contract_class::{ContractClassV1, EntryPointV1};
use crate::execution::entry_point::{
CallEntryPoint, CallExecution, CallInfo, EntryPointExecutionResult, ExecutionContext,
CallEntryPoint, CallExecution, CallInfo, EntryPointExecutionResult, ExecutionContext, Retdata,
};
use crate::execution::errors::{
EntryPointExecutionError, PostExecutionError, PreExecutionError, VirtualMachineExecutionError,
};
use crate::execution::execution_utils::{
read_execution_retdata, stark_felt_to_felt, write_maybe_relocatable, write_stark_felt, Args,
ReadOnlySegments,
felt_to_stark_felt, read_execution_retdata, stark_felt_to_felt, write_maybe_relocatable,
write_stark_felt, Args, ReadOnlySegments,
};
use crate::execution::syscalls::hint_processor::SyscallHintProcessor;
use crate::state::state_api::State;
Expand All @@ -32,6 +33,12 @@ pub struct VmExecutionContext<'a> {
pub program_segment_size: usize,
}

pub struct CallResult {
pub failed: bool,
pub retdata: Retdata,
pub gas_consumed: StarkFelt,
}

/// Executes a specific call to a contract entry point and returns its output.
pub fn execute_entry_point_call(
call: CallEntryPoint,
Expand Down Expand Up @@ -133,7 +140,7 @@ fn prepare_builtin_costs(

// TODO(spapini): Put real costs here.
for _i in 0..20 {
data.push(0.into());
data.push(MaybeRelocatable::from(0));
}
let builtin_cost_segment_start = read_only_segments.allocate(vm, &data)?;

Expand Down Expand Up @@ -177,7 +184,7 @@ pub fn prepare_call_arguments(
write_stark_felt(vm, &mut ptr, n_constructed)?;
write_stark_felt(vm, &mut ptr, n_destructed)?;

args.push(CairoArg::Single(ptr.into()));
args.push(CairoArg::Single(MaybeRelocatable::from(ptr)));
continue;
}
return Err(PreExecutionError::InvalidBuiltin(builtin_name.clone()));
Expand All @@ -193,8 +200,8 @@ pub fn prepare_call_arguments(
calldata.iter().map(|&arg| MaybeRelocatable::from(stark_felt_to_felt(arg))).collect();

let calldata_start_ptr = read_only_segments.allocate(vm, &calldata)?;
let calldata_end_ptr = (calldata_start_ptr + calldata.len())?.into();
args.push(CairoArg::Single(calldata_start_ptr.into()));
let calldata_end_ptr = MaybeRelocatable::from((calldata_start_ptr + calldata.len())?);
args.push(CairoArg::Single(MaybeRelocatable::from(calldata_start_ptr)));
args.push(CairoArg::Single(calldata_end_ptr));

Ok(args)
Expand Down Expand Up @@ -238,18 +245,7 @@ pub fn finalize_execution(
vm.mark_address_range_as_accessed(args_ptr, n_total_args)?;
syscall_handler.read_only_segments.mark_as_accessed(&mut vm)?;

// Get retdata.
let [failure_flag, retdata_start, retdata_end]: [MaybeRelocatable; 3] =
vm.get_return_values(3)?.try_into().expect("Return values must be of size 2.");
let failed = if failure_flag == 0.into() {
false
} else if failure_flag == 1.into() {
true
} else {
return Err(PostExecutionError::MalformedReturnData);
};
let retdata_size = retdata_end.sub(&retdata_start)?;
// TODO(spapini): Validate implicits.
let call_result = get_call_result(&vm, &syscall_handler)?;

// Take into account the VM execution resources of the current call, without inner calls.
// Has to happen after marking holes in segments as accessed.
Expand All @@ -264,16 +260,59 @@ pub fn finalize_execution(
Ok(CallInfo {
call: syscall_handler.call,
execution: CallExecution {
retdata: read_execution_retdata(vm, retdata_size, retdata_start)?,
retdata: call_result.retdata,
events: syscall_handler.events,
l2_to_l1_messages: syscall_handler.l2_to_l1_messages,
failed,
// TODO(Noa,01/06/2023): Fill with actual values.
gas_consumed: StarkFelt::default(),
failed: call_result.failed,
gas_consumed: call_result.gas_consumed,
},
vm_resources: full_call_vm_resources.filter_unused_builtins(),
inner_calls: syscall_handler.inner_calls,
storage_read_values: syscall_handler.read_values,
accessed_storage_keys: syscall_handler.accessed_keys,
})
}

fn get_call_result(
vm: &VirtualMachine,
syscall_handler: &SyscallHintProcessor<'_>,
) -> Result<CallResult, PostExecutionError> {
let return_result = vm.get_return_values(5)?;
// Corresponds to the Cairo 1.0 enum:
// enum PanicResult<Array::<felt>> { Ok: Array::<felt>, Err: Array::<felt>, }.
let [failure_flag, retdata_start, retdata_end]: &[MaybeRelocatable; 3] =
(&return_result[2..]).try_into().expect("Return values must be of size 3.");

let failed = if *failure_flag == MaybeRelocatable::from(0) {
false
} else if *failure_flag == MaybeRelocatable::from(1) {
true
} else {
return Err(PostExecutionError::MalformedReturnData {
error_message: "Failure flag expected to be either 0 or 1.".to_string(),
});
};

let retdata_size = retdata_end.sub(retdata_start)?;
// TODO(spapini): Validate implicits.

let gas = &return_result[0];
let MaybeRelocatable::Int(gas) = gas
else {
return
Err(PostExecutionError::MalformedReturnData {
error_message: "Error extracting return data.".to_string()});
};
if gas < &Felt252::from(0) || gas > &syscall_handler.call.initial_gas {
return Err(PostExecutionError::MalformedReturnData {
error_message: format!("Unexpected remaining gas: {gas}."),
});
}

let gas_consumed = &syscall_handler.call.initial_gas - gas;
Ok(CallResult {
failed,
retdata: read_execution_retdata(vm, retdata_size, retdata_start)?,
gas_consumed: felt_to_stark_felt(&gas_consumed),
})
}
2 changes: 1 addition & 1 deletion crates/blockifier/src/execution/deprecated_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ pub fn finalize_execution(
Ok(CallInfo {
call,
execution: CallExecution {
retdata: read_execution_retdata(vm, retdata_size, retdata_ptr)?,
retdata: read_execution_retdata(&vm, retdata_size, &retdata_ptr)?,
events: syscall_handler.events,
l2_to_l1_messages: syscall_handler.l2_to_l1_messages,
failed: false,
Expand Down
4 changes: 2 additions & 2 deletions crates/blockifier/src/execution/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ pub enum PostExecutionError {
SecurityValidationError(String),
#[error(transparent)]
VirtualMachineError(#[from] VirtualMachineError),
#[error("Malformed return data.")]
MalformedReturnData,
#[error("Malformed return data : {error_message}.")]
MalformedReturnData { error_message: String },
}

impl From<RunnerError> for PostExecutionError {
Expand Down
6 changes: 3 additions & 3 deletions crates/blockifier/src/execution/execution_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ pub fn execute_entry_point_call(
}

pub fn read_execution_retdata(
vm: VirtualMachine,
vm: &VirtualMachine,
retdata_size: MaybeRelocatable,
retdata_ptr: MaybeRelocatable,
retdata_ptr: &MaybeRelocatable,
) -> Result<Retdata, PostExecutionError> {
let retdata_size = match retdata_size {
MaybeRelocatable::Int(retdata_size) => usize::try_from(retdata_size.to_bigint())
Expand All @@ -72,7 +72,7 @@ pub fn read_execution_retdata(
}
};

Ok(Retdata(felt_range_from_ptr(&vm, Relocatable::try_from(&retdata_ptr)?, retdata_size)?))
Ok(Retdata(felt_range_from_ptr(vm, Relocatable::try_from(retdata_ptr)?, retdata_size)?))
}

pub fn stark_felt_from_ptr(
Expand Down
71 changes: 57 additions & 14 deletions crates/blockifier/src/execution/syscalls/syscalls_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ fn test_storage_read_write() {
let storage_address = entry_point_call.storage_address;
assert_eq!(
entry_point_call.execute_directly(&mut state).unwrap().execution,
CallExecution::from_retdata(retdata![stark_felt!(value)])
CallExecution {
retdata: retdata![stark_felt!(value)],
gas_consumed: stark_felt!(35170_u64),
..CallExecution::default()
}
);
// Verify that the state has changed.
let value_from_state =
Expand Down Expand Up @@ -70,7 +74,11 @@ fn test_call_contract() {
};
assert_eq!(
entry_point_call.execute_directly(&mut state).unwrap().execution,
CallExecution::from_retdata(retdata![stark_felt!(48_u8)])
CallExecution {
retdata: retdata![stark_felt!(48_u8)],
gas_consumed: stark_felt!(129650_u64),
..CallExecution::default()
}
);
}

Expand Down Expand Up @@ -99,7 +107,11 @@ fn test_emit_event() {
EventContent { keys: keys.into_iter().map(EventKey).collect(), data: EventData(data) };
assert_eq!(
entry_point_call.execute_directly(&mut state).unwrap().execution,
CallExecution { events: vec![OrderedEvent { order: 0, event }], ..Default::default() }
CallExecution {
events: vec![OrderedEvent { order: 0, event }],
gas_consumed: stark_felt!(53940_u64),
..Default::default()
}
);
}

Expand Down Expand Up @@ -154,7 +166,11 @@ fn test_library_call() {

assert_eq!(
entry_point_call.execute_directly(&mut state).unwrap().execution,
CallExecution::from_retdata(retdata![stark_felt!(91_u16)])
CallExecution {
retdata: retdata![stark_felt!(91_u16)],
gas_consumed: stark_felt!(129650_u64),
..Default::default()
}
);
}

Expand Down Expand Up @@ -207,7 +223,7 @@ fn test_nested_library_call() {
};
let storage_entry_point = CallEntryPoint {
calldata: calldata![stark_felt!(key), stark_felt!(value)],
initial_gas: Felt252::from(9999752200_u64),
initial_gas: Felt252::from(9999622550_u64),
..nested_storage_entry_point
};
let storage_entry_point_vm_resources = VmExecutionResources {
Expand All @@ -217,7 +233,11 @@ fn test_nested_library_call() {
};
let nested_storage_call_info = CallInfo {
call: nested_storage_entry_point,
execution: CallExecution::from_retdata(retdata![stark_felt!(value + 1)]),
execution: CallExecution {
retdata: retdata![stark_felt!(value + 1)],
gas_consumed: stark_felt!(35170_u64),
..CallExecution::default()
},
vm_resources: storage_entry_point_vm_resources.clone(),
storage_read_values: vec![stark_felt!(value + 1)],
accessed_storage_keys: HashSet::from([StorageKey(patricia_key!(key + 1))]),
Expand All @@ -231,14 +251,22 @@ fn test_nested_library_call() {
library_call_vm_resources += &storage_entry_point_vm_resources;
let library_call_info = CallInfo {
call: library_entry_point,
execution: CallExecution::from_retdata(retdata![stark_felt!(value + 1)]),
execution: CallExecution {
retdata: retdata![stark_felt!(value + 1)],
gas_consumed: stark_felt!(129650_u64),
..CallExecution::default()
},
vm_resources: library_call_vm_resources.clone(),
inner_calls: vec![nested_storage_call_info],
..Default::default()
};
let storage_call_info = CallInfo {
call: storage_entry_point,
execution: CallExecution::from_retdata(retdata![stark_felt!(value)]),
execution: CallExecution {
retdata: retdata![stark_felt!(value)],
gas_consumed: stark_felt!(35170_u64),
..CallExecution::default()
},
vm_resources: storage_entry_point_vm_resources.clone(),
storage_read_values: vec![stark_felt!(value)],
accessed_storage_keys: HashSet::from([StorageKey(patricia_key!(key))]),
Expand All @@ -253,7 +281,11 @@ fn test_nested_library_call() {
main_call_vm_resources += &library_call_vm_resources;
let expected_call_info = CallInfo {
call: main_entry_point.clone(),
execution: CallExecution::from_retdata(retdata![stark_felt!(value)]),
execution: CallExecution {
retdata: retdata![stark_felt!(value)],
gas_consumed: stark_felt!(319220_u64),
..CallExecution::default()
},
vm_resources: main_call_vm_resources,
inner_calls: vec![library_call_info, storage_call_info],
..Default::default()
Expand Down Expand Up @@ -326,6 +358,7 @@ fn test_send_message_to_l1() {
entry_point_call.execute_directly(&mut state).unwrap().execution,
CallExecution {
l2_to_l1_messages: vec![OrderedL2ToL1Message { order: 0, message }],
gas_consumed: stark_felt!(39040_u64),
..Default::default()
}
);
Expand Down Expand Up @@ -420,10 +453,20 @@ fn test_deploy(
.unwrap();
let deploy_call = &entry_point_call.execute_directly(&mut state).unwrap().inner_calls[0];
assert_eq!(deploy_call.call.storage_address, contract_address);
let mut retdada = retdata![];
if !constructor_calldata.0.is_empty() {
retdada.0.push(constructor_calldata.0[0])
}
assert_eq!(deploy_call.execution, CallExecution::from_retdata(retdada));
let mut retdata = retdata![];
let gas_consumed = if constructor_calldata.0.is_empty() {
stark_felt!(0_u64)
} else {
retdata.0.push(constructor_calldata.0[0]);
stark_felt!(17260_u64)
};
assert_eq!(
deploy_call.execution,
CallExecution {
retdata,
gas_consumed: stark_felt!(gas_consumed),
..CallExecution::default()
}
);
assert_eq!(state.get_class_hash_at(contract_address).unwrap(), class_hash);
}

0 comments on commit ed7771f

Please sign in to comment.