Skip to content

Commit

Permalink
fix(blockifier): avoid negative consumed gas
Browse files Browse the repository at this point in the history
  • Loading branch information
avivg-starkware committed Dec 29, 2024
1 parent 8552dd5 commit fdfc493
Show file tree
Hide file tree
Showing 25 changed files with 153 additions and 67 deletions.
9 changes: 3 additions & 6 deletions crates/blockifier/resources/versioned_constants_0_13_0.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,11 @@
"syscall_gas_costs": {
"call_contract": {
"syscall_base_gas_cost": 1,
"step_gas_cost": 510,
"entry_point_initial_budget": 1
"step_gas_cost": 510
},
"deploy": {
"syscall_base_gas_cost": 1,
"step_gas_cost": 700,
"entry_point_initial_budget": 1
"step_gas_cost": 700
},
"get_block_hash": {
"syscall_base_gas_cost": 1,
Expand All @@ -132,8 +130,7 @@
},
"library_call": {
"syscall_base_gas_cost": 1,
"step_gas_cost": 510,
"entry_point_initial_budget": 1
"step_gas_cost": 510
},
"replace_class": {
"syscall_base_gas_cost": 1,
Expand Down
9 changes: 3 additions & 6 deletions crates/blockifier/resources/versioned_constants_0_13_1.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,11 @@
"syscall_gas_costs": {
"call_contract": {
"syscall_base_gas_cost": 1,
"step_gas_cost": 510,
"entry_point_initial_budget": 1
"step_gas_cost": 510
},
"deploy": {
"syscall_base_gas_cost": 1,
"step_gas_cost": 700,
"entry_point_initial_budget": 1
"step_gas_cost": 700
},
"get_block_hash": {
"syscall_base_gas_cost": 1,
Expand All @@ -136,8 +134,7 @@
},
"library_call": {
"syscall_base_gas_cost": 1,
"step_gas_cost": 510,
"entry_point_initial_budget": 1
"step_gas_cost": 510
},
"replace_class": {
"syscall_base_gas_cost": 1,
Expand Down
9 changes: 3 additions & 6 deletions crates/blockifier/resources/versioned_constants_0_13_1_1.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,11 @@
"syscall_gas_costs": {
"call_contract": {
"syscall_base_gas_cost": 1,
"step_gas_cost": 510,
"entry_point_initial_budget": 1
"step_gas_cost": 510
},
"deploy": {
"syscall_base_gas_cost": 1,
"step_gas_cost": 700,
"entry_point_initial_budget": 1
"step_gas_cost": 700
},
"get_block_hash": {
"syscall_base_gas_cost": 1,
Expand All @@ -136,8 +134,7 @@
},
"library_call": {
"syscall_base_gas_cost": 1,
"step_gas_cost": 510,
"entry_point_initial_budget": 1
"step_gas_cost": 510
},
"replace_class": {
"syscall_base_gas_cost": 1,
Expand Down
3 changes: 0 additions & 3 deletions crates/blockifier/resources/versioned_constants_0_13_2.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,10 @@
"validated": "VALID",
"syscall_gas_costs": {
"call_contract": {
"entry_point_initial_budget": 1,
"step_gas_cost": 510,
"syscall_base_gas_cost": 1
},
"deploy": {
"entry_point_initial_budget": 1,
"step_gas_cost": 700,
"syscall_base_gas_cost": 1
},
Expand All @@ -143,7 +141,6 @@
},
"keccak_round_cost": 180000,
"library_call": {
"entry_point_initial_budget": 1,
"step_gas_cost": 510,
"syscall_base_gas_cost": 1
},
Expand Down
3 changes: 0 additions & 3 deletions crates/blockifier/resources/versioned_constants_0_13_2_1.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,10 @@
"validated": "VALID",
"syscall_gas_costs": {
"call_contract": {
"entry_point_initial_budget": 1,
"step_gas_cost": 510,
"syscall_base_gas_cost": 1
},
"deploy": {
"entry_point_initial_budget": 1,
"step_gas_cost": 700,
"syscall_base_gas_cost": 1
},
Expand All @@ -143,7 +141,6 @@
},
"keccak_round_cost": 180000,
"library_call": {
"entry_point_initial_budget": 1,
"step_gas_cost": 510,
"syscall_base_gas_cost": 1
},
Expand Down
3 changes: 0 additions & 3 deletions crates/blockifier/resources/versioned_constants_0_13_3.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,10 @@
"validated": "VALID",
"syscall_gas_costs": {
"call_contract": {
"entry_point_initial_budget": 1,
"step_gas_cost": 510,
"syscall_base_gas_cost": 1
},
"deploy": {
"entry_point_initial_budget": 1,
"step_gas_cost": 700,
"syscall_base_gas_cost": 1
},
Expand All @@ -143,7 +141,6 @@
},
"keccak_round_cost": 180000,
"library_call": {
"entry_point_initial_budget": 1,
"step_gas_cost": 510,
"syscall_base_gas_cost": 1
},
Expand Down
3 changes: 0 additions & 3 deletions crates/blockifier/resources/versioned_constants_0_13_4.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,10 @@
"validated": "VALID",
"syscall_gas_costs": {
"call_contract": {
"entry_point_initial_budget": 1,
"step_gas_cost": 860,
"range_check": 15
},
"deploy": {
"entry_point_initial_budget": 1,
"step_gas_cost": 1128,
"range_check": 18,
"pedersen": 7
Expand All @@ -146,7 +144,6 @@
},
"keccak_round_cost": 180000,
"library_call": {
"entry_point_initial_budget": 1,
"step_gas_cost": 836,
"range_check": 15
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,15 @@ fn test_nested_library_call() {
felt!(key), // Calldata: address.
felt!(value) // Calldata: value.
];
let vesrioned_const = VersionedConstants::create_for_testing();
let initial_gas = vesrioned_const.os_constants.gas_costs.base.default_initial_gas_cost;

// Create expected call info tree.
let main_entry_point = CallEntryPoint {
entry_point_selector: selector_from_name("test_nested_library_call"),
calldata: main_entry_point_calldata,
class_hash: Some(test_contract.get_class_hash()),
initial_gas,
..trivial_external_entry_point_new(test_contract)
};
let nested_storage_entry_point = CallEntryPoint {
Expand All @@ -127,6 +130,7 @@ fn test_nested_library_call() {
class_hash: Some(test_contract.get_class_hash()),
code_address: None,
call_type: CallType::Delegate,
initial_gas,
..trivial_external_entry_point_new(test_contract)
};
let library_entry_point = CallEntryPoint {
Expand All @@ -141,6 +145,7 @@ fn test_nested_library_call() {
class_hash: Some(test_contract.get_class_hash()),
code_address: None,
call_type: CallType::Delegate,
initial_gas,
..trivial_external_entry_point_new(test_contract)
};
let storage_entry_point = CallEntryPoint {
Expand Down Expand Up @@ -235,13 +240,16 @@ fn test_call_contract() {
};
let call_info = entry_point_call.execute_directly(&mut state).unwrap();

let vesrioned_const = VersionedConstants::create_for_testing();
let initial_gas = vesrioned_const.os_constants.gas_costs.base.default_initial_gas_cost;
let expected_execution = CallExecution { retdata: retdata![value], ..Default::default() };
let expected_inner_call_info = CallInfo {
call: CallEntryPoint {
class_hash: Some(test_contract.get_class_hash()),
entry_point_selector: inner_entry_point_selector,
calldata: inner_calldata,
caller_address: test_address,
initial_gas,
..trivial_external_entry_point
},
execution: expected_execution.clone(),
Expand All @@ -260,6 +268,7 @@ fn test_call_contract() {
class_hash: Some(test_contract.get_class_hash()),
entry_point_selector: outer_entry_point_selector,
calldata,
initial_gas,
..trivial_external_entry_point
},
execution: expected_execution,
Expand Down
35 changes: 31 additions & 4 deletions crates/blockifier/src/execution/entry_point_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::execution::execution_utils::{
ReadOnlySegments,
SEGMENT_ARENA_BUILTIN_SIZE,
};
use crate::execution::syscalls::hint_processor::SyscallHintProcessor;
use crate::execution::syscalls::hint_processor::{SyscallHintProcessor, OUT_OF_GAS_ERROR};
use crate::state::state_api::State;
use crate::versioned_constants::GasCosts;

Expand Down Expand Up @@ -61,6 +61,8 @@ pub fn execute_entry_point_call(
) -> EntryPointExecutionResult<CallInfo> {
let tracked_resource =
*context.tracked_resource_stack.last().expect("Unexpected empty tracked resource.");
let enable_reverts = context.versioned_constants().enable_reverts;
let entry_point_initial_budget = context.gas_costs().base.entry_point_initial_budget;
let VmExecutionContext {
mut runner,
mut syscall_handler,
Expand All @@ -69,13 +71,31 @@ pub fn execute_entry_point_call(
program_extra_data_length,
} = initialize_execution_context(call, &compiled_class, state, context)?;

let args = prepare_call_arguments(
let args = match prepare_call_arguments(
&syscall_handler.base.call,
&mut runner,
initial_syscall_ptr,
&mut syscall_handler.read_only_segments,
&entry_point,
)?;
entry_point_initial_budget,
) {
Ok(args) => args,
Err(PreExecutionError::OutOfGas) if enable_reverts => {
return Ok(CallInfo {
call: syscall_handler.base.call,
execution: CallExecution {
retdata: Retdata(vec![Felt::from_hex(OUT_OF_GAS_ERROR).unwrap()]),
failed: true,
gas_consumed: 0,
..CallExecution::default()
},
tracked_resource,
..CallInfo::default()
});
}
Err(err) => return Err(err.into()),
};

let n_total_args = args.len();

// Execute.
Expand Down Expand Up @@ -180,6 +200,7 @@ pub fn prepare_call_arguments(
initial_syscall_ptr: Relocatable,
read_only_segments: &mut ReadOnlySegments,
entrypoint: &EntryPointV1,
entry_point_initial_budget: u64,
) -> Result<Args, PreExecutionError> {
let mut args: Args = vec![];

Expand Down Expand Up @@ -208,8 +229,14 @@ pub fn prepare_call_arguments(
}
return Err(PreExecutionError::InvalidBuiltin(*builtin_name));
}
// Include the initial entry point budget in the initial gas calculation.
if call.initial_gas < entry_point_initial_budget {
return Err(PreExecutionError::OutOfGas);
}
let initial_gas = call.initial_gas - entry_point_initial_budget;
assert!(call.initial_gas >= entry_point_initial_budget, "initial_gas must be non-negative");
// Push gas counter.
args.push(CairoArg::Single(MaybeRelocatable::from(Felt::from(call.initial_gas))));
args.push(CairoArg::Single(MaybeRelocatable::from(Felt::from(initial_gas))));
// Push syscall ptr.
args.push(CairoArg::Single(MaybeRelocatable::from(initial_syscall_ptr)));

Expand Down
2 changes: 2 additions & 0 deletions crates/blockifier/src/execution/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ pub enum PreExecutionError {
UninitializedStorageAddress(ContractAddress),
#[error("Called builtins: {0:?} are unsupported in a Cairo0 contract")]
UnsupportedCairo0Builtin(HashSet<BuiltinName>),
#[error("Out of gas.")]
OutOfGas,
}

impl From<RunnerError> for PreExecutionError {
Expand Down
27 changes: 26 additions & 1 deletion crates/blockifier/src/execution/native/entry_point_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use cairo_native::execution_result::ContractExecutionResult;
use cairo_native::utils::BuiltinCosts;
use cairo_vm::vm::runners::cairo_runner::ExecutionResources;
use stacker;
use starknet_types_core::felt::Felt;

use crate::execution::call_info::{CallExecution, CallInfo, ChargedResources, Retdata};
use crate::execution::contract_class::TrackedResource;
Expand All @@ -14,6 +15,7 @@ use crate::execution::entry_point_execution::gas_consumed_without_inner_calls;
use crate::execution::errors::{EntryPointExecutionError, PostExecutionError};
use crate::execution::native::contract_class::NativeCompiledClassV1;
use crate::execution::native::syscall_handler::NativeSyscallHandler;
use crate::execution::syscalls::hint_processor::OUT_OF_GAS_ERROR;
use crate::state::state_api::State;

// todo(rodrigo): add an `entry point not found` test for Native
Expand All @@ -23,6 +25,8 @@ pub fn execute_entry_point_call(
state: &mut dyn State,
context: &mut EntryPointExecutionContext,
) -> EntryPointExecutionResult<CallInfo> {
let orig_call = call.clone();

let entry_point = compiled_class.get_entry_point(&call)?;

let mut syscall_handler: NativeSyscallHandler<'_> =
Expand Down Expand Up @@ -56,13 +60,34 @@ pub fn execute_entry_point_call(
// TODO(Aviv/Yonatan): add these numbers to overridable VC.
let stack_size_red_zone = 160 * 1024 * 1024;
let target_stack_size = stack_size_red_zone + 10 * 1024 * 1024;
// Include the initial entry point budget in the initial gas calculation.
let entry_point_initial_budget =
syscall_handler.base.context.gas_costs().base.entry_point_initial_budget;
if syscall_handler.base.call.initial_gas < entry_point_initial_budget {
let current_tracked_resource = compiled_class
.casm()
.tracked_resource(&context.versioned_constants().min_sierra_version_for_sierra_gas);

return Ok(CallInfo {
call: orig_call,
execution: CallExecution {
retdata: Retdata(vec![Felt::from_hex(OUT_OF_GAS_ERROR).unwrap()]),
failed: true,
gas_consumed: 0,
..CallExecution::default()
},
tracked_resource: current_tracked_resource,
..CallInfo::default()
});
}
let initial_gas = syscall_handler.base.call.initial_gas - entry_point_initial_budget;
// Use `maybe_grow` and not `grow` for performance, since in happy flows, only the main call
// should trigger the growth.
let execution_result = stacker::maybe_grow(stack_size_red_zone, target_stack_size, || {
compiled_class.executor.run(
entry_point.selector.0,
&syscall_handler.base.call.calldata.0.clone(),
syscall_handler.base.call.initial_gas,
initial_gas,
Some(builtin_costs),
&mut syscall_handler,
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub const REQUIRED_GAS_CALL_CONTRACT_TEST: u64 = 120370;
pub const REQUIRED_GAS_STORAGE_READ_WRITE_TEST: u64 = 16990;
pub const REQUIRED_GAS_GET_CLASS_HASH_AT_TEST: u64 = 7830;
pub const REQUIRED_GAS_LIBRARY_CALL_TEST: u64 = 117970;
pub const REQUIRED_GAS_CALL_CONTRACT_TEST: u64 = 130370;
pub const REQUIRED_GAS_STORAGE_READ_WRITE_TEST: u64 = 26990;
pub const REQUIRED_GAS_GET_CLASS_HASH_AT_TEST: u64 = 17830;
pub const REQUIRED_GAS_LIBRARY_CALL_TEST: u64 = 127970;
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ fn with_constructor(runnable_version: RunnableCairo1) {
let deploy_call = &entry_point_call.execute_directly(&mut state).unwrap();
assert_eq!(
deploy_call.execution,
CallExecution { retdata: retdata![], gas_consumed: 164550, ..CallExecution::default() }
CallExecution { retdata: retdata![], gas_consumed: 174550, ..CallExecution::default() }
);

let constructor_call = &deploy_call.inner_calls[0];
Expand All @@ -136,7 +136,7 @@ fn with_constructor(runnable_version: RunnableCairo1) {
// The test contract constructor returns its first argument.
retdata: retdata![constructor_calldata[0]],
// This reflects the gas cost of storage write syscall.
gas_consumed: 4610,
gas_consumed: 14610,
..CallExecution::default()
}
);
Expand Down
Loading

0 comments on commit fdfc493

Please sign in to comment.