From ecc2d058aa924876011903e9a7c6264c2a19d909 Mon Sep 17 00:00:00 2001 From: aner-starkware <147302140+aner-starkware@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:04:40 +0200 Subject: [PATCH] chore(blockifier): cap max_validate_gas and max_execute_gas (#2397) * chore(blockifier): cap max_validate_gas and max_execute_gas * fix(blockifier): fix tests for sierra_gas usage --- .../src/blockifier/stateful_validator.rs | 2 +- crates/blockifier/src/context.rs | 37 ++++++- .../src/execution/contract_address_test.rs | 2 +- .../blockifier/src/execution/entry_point.rs | 5 + .../src/execution/entry_point_test.rs | 2 +- .../src/execution/execution_utils.rs | 2 +- crates/blockifier/src/fee/fee_test.rs | 4 +- .../src/transaction/account_transaction.rs | 47 +++++--- .../transaction/account_transactions_test.rs | 13 ++- .../src/transaction/transaction_execution.rs | 2 +- .../src/transaction/transactions_test.rs | 100 +++++++++++++----- crates/blockifier/src/versioned_constants.rs | 17 ++- .../starknet_api/src/execution_resources.rs | 5 +- 13 files changed, 178 insertions(+), 60 deletions(-) diff --git a/crates/blockifier/src/blockifier/stateful_validator.rs b/crates/blockifier/src/blockifier/stateful_validator.rs index df1caf9edb..8683088833 100644 --- a/crates/blockifier/src/blockifier/stateful_validator.rs +++ b/crates/blockifier/src/blockifier/stateful_validator.rs @@ -74,7 +74,7 @@ impl StatefulValidator { // `__validate__` call. let (_optional_call_info, actual_cost) = - self.validate(&tx, tx_context.initial_sierra_gas())?; + self.validate(&tx, tx_context.initial_sierra_gas().0)?; // Post validations. PostValidationReport::verify(&tx_context, &actual_cost)?; diff --git a/crates/blockifier/src/context.rs b/crates/blockifier/src/context.rs index bd69be574f..152524f5c5 100644 --- a/crates/blockifier/src/context.rs +++ b/crates/blockifier/src/context.rs @@ -5,6 +5,7 @@ use papyrus_config::{ParamPath, ParamPrivacyInput, SerializedParam}; use serde::{Deserialize, Serialize}; use starknet_api::block::{BlockInfo, FeeType, GasPriceVector}; use starknet_api::core::{ChainId, ContractAddress}; +use starknet_api::execution_resources::GasAmount; use starknet_api::transaction::fields::{ AllResourceBounds, GasVectorComputationMode, @@ -12,6 +13,7 @@ use starknet_api::transaction::fields::{ }; use crate::bouncer::BouncerConfig; +use crate::execution::call_info::CallInfo; use crate::transaction::objects::{ CurrentTransactionInfo, HasRelatedFeeType, @@ -42,22 +44,49 @@ impl TransactionContext { /// Returns the initial Sierra gas of the transaction. /// This value is used to limit the transaction's run. - // TODO(tzahi): replace returned value from u64 to GasAmount. - pub fn initial_sierra_gas(&self) -> u64 { + pub fn initial_sierra_gas(&self) -> GasAmount { match &self.tx_info { TransactionInfo::Deprecated(_) | TransactionInfo::Current(CurrentTransactionInfo { resource_bounds: ValidResourceBounds::L1Gas(_), .. - }) => self.block_context.versioned_constants.default_initial_gas_cost(), + }) => self.block_context.versioned_constants.initial_gas_no_user_l2_bound(), TransactionInfo::Current(CurrentTransactionInfo { resource_bounds: ValidResourceBounds::AllResources(AllResourceBounds { l2_gas, .. }), .. - }) => l2_gas.max_amount.0, + }) => l2_gas.max_amount, } } } +pub(crate) struct GasCounter { + pub(crate) spent_gas: GasAmount, + pub(crate) remaining_gas: GasAmount, +} + +impl GasCounter { + pub(crate) fn new(initial_gas: GasAmount) -> Self { + GasCounter { spent_gas: GasAmount(0), remaining_gas: initial_gas } + } + + fn spend(&mut self, amount: GasAmount) { + self.spent_gas = self.spent_gas.checked_add(amount).expect("Gas overflow"); + self.remaining_gas = self + .remaining_gas + .checked_sub(amount) + .expect("Overuse of gas; should have been caught earlier"); + } + + /// Limits the amount of gas that can be used (in validate\execute) by the given global limit. + pub(crate) fn limit_usage(&self, amount: GasAmount) -> u64 { + self.remaining_gas.min(amount).0 + } + + pub(crate) fn subtract_used_gas(&mut self, call_info: &CallInfo) { + self.spend(GasAmount(call_info.execution.gas_consumed)); + } +} + #[derive(Clone, Debug)] pub struct BlockContext { // TODO(Yoni, 1/10/2024): consider making these fields public. diff --git a/crates/blockifier/src/execution/contract_address_test.rs b/crates/blockifier/src/execution/contract_address_test.rs index 7c0959e817..2b8f5927a8 100644 --- a/crates/blockifier/src/execution/contract_address_test.rs +++ b/crates/blockifier/src/execution/contract_address_test.rs @@ -34,7 +34,7 @@ fn test_calculate_contract_address() { calldata, entry_point_selector: selector_from_name("test_contract_address"), storage_address: deployer_address, - initial_gas: versioned_constants.default_initial_gas_cost(), + initial_gas: versioned_constants.inifite_gas_for_vm_mode(), ..Default::default() }; let contract_address = diff --git a/crates/blockifier/src/execution/entry_point.rs b/crates/blockifier/src/execution/entry_point.rs index fc6eeb3d5e..e7fd2e84a7 100644 --- a/crates/blockifier/src/execution/entry_point.rs +++ b/crates/blockifier/src/execution/entry_point.rs @@ -10,6 +10,7 @@ use starknet_api::abi::abi_utils::selector_from_name; use starknet_api::abi::constants::CONSTRUCTOR_ENTRY_POINT_NAME; use starknet_api::contract_class::EntryPointType; use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector}; +use starknet_api::execution_resources::GasAmount; use starknet_api::state::StorageKey; use starknet_api::transaction::fields::{ AllResourceBounds, @@ -375,6 +376,10 @@ impl EntryPointExecutionContext { &self.versioned_constants().os_constants.gas_costs } + pub fn mode_sierra_gas_limit(&self) -> GasAmount { + self.tx_context.block_context.versioned_constants.sierra_gas_limit(&self.execution_mode) + } + /// Reverts the state back to the way it was when self.revert_infos.0['revert_idx'] was created. pub fn revert(&mut self, revert_idx: usize, state: &mut dyn State) -> StateResult<()> { for contract_revert_info in self.revert_infos.0.drain(revert_idx..).rev() { diff --git a/crates/blockifier/src/execution/entry_point_test.rs b/crates/blockifier/src/execution/entry_point_test.rs index 3983d7dbab..6e7230742c 100644 --- a/crates/blockifier/src/execution/entry_point_test.rs +++ b/crates/blockifier/src/execution/entry_point_test.rs @@ -200,7 +200,7 @@ fn run_security_test( entry_point_selector: selector_from_name(entry_point_name), calldata, storage_address: security_contract.get_instance_address(0), - initial_gas: versioned_constants.default_initial_gas_cost(), + initial_gas: versioned_constants.inifite_gas_for_vm_mode(), ..Default::default() }; let error = match entry_point_call.execute_directly(state) { diff --git a/crates/blockifier/src/execution/execution_utils.rs b/crates/blockifier/src/execution/execution_utils.rs index b6ba81092e..860d91eb5e 100644 --- a/crates/blockifier/src/execution/execution_utils.rs +++ b/crates/blockifier/src/execution/execution_utils.rs @@ -63,7 +63,7 @@ pub fn execute_entry_point_call_wrapper( ); if current_tracked_resource == TrackedResource::CairoSteps { // Override the initial gas with a high value so it won't limit the run. - call.initial_gas = context.versioned_constants().default_initial_gas_cost(); + call.initial_gas = context.versioned_constants().inifite_gas_for_vm_mode(); } let orig_call = call.clone(); diff --git a/crates/blockifier/src/fee/fee_test.rs b/crates/blockifier/src/fee/fee_test.rs index 2719791e22..aa59e48f62 100644 --- a/crates/blockifier/src/fee/fee_test.rs +++ b/crates/blockifier/src/fee/fee_test.rs @@ -361,7 +361,7 @@ fn test_get_fee_by_gas_vector_overflow( #[rstest] #[case::default( - VersionedConstants::create_for_account_testing().default_initial_gas_cost(), + VersionedConstants::create_for_account_testing().initial_gas_no_user_l2_bound().0, GasVectorComputationMode::NoL2Gas )] #[case::from_l2_gas(4321, GasVectorComputationMode::All)] @@ -384,6 +384,6 @@ fn test_initial_sierra_gas( }), }; let account_tx = invoke_tx_with_default_flags(invoke_tx_args!(resource_bounds)); - let actual = block_context.to_tx_context(&account_tx).initial_sierra_gas(); + let actual = block_context.to_tx_context(&account_tx).initial_sierra_gas().0; assert_eq!(actual, expected) } diff --git a/crates/blockifier/src/transaction/account_transaction.rs b/crates/blockifier/src/transaction/account_transaction.rs index f5e02fed6c..4261c41066 100644 --- a/crates/blockifier/src/transaction/account_transaction.rs +++ b/crates/blockifier/src/transaction/account_transaction.rs @@ -21,7 +21,7 @@ use starknet_api::transaction::fields::{ use starknet_api::transaction::{constants, TransactionHash, TransactionVersion}; use starknet_types_core::felt::Felt; -use crate::context::{BlockContext, TransactionContext}; +use crate::context::{BlockContext, GasCounter, TransactionContext}; use crate::execution::call_info::CallInfo; use crate::execution::contract_class::RunnableCompiledClass; use crate::execution::entry_point::{CallEntryPoint, CallType, EntryPointExecutionContext}; @@ -372,11 +372,19 @@ impl AccountTransaction { &self, state: &mut dyn State, tx_context: Arc, - remaining_gas: &mut u64, + remaining_gas: &mut GasCounter, ) -> TransactionExecutionResult> { - let limit_steps_by_resources = self.execution_flags.charge_fee; if self.execution_flags.validate { - self.validate_tx(state, tx_context, remaining_gas, limit_steps_by_resources) + let limit_steps_by_resources = self.execution_flags.charge_fee; + // TODO(Aner): cap the gas for validation. + let remaining_validation_gas = &mut remaining_gas + .limit_usage(tx_context.block_context.versioned_constants.validate_max_sierra_gas); + Ok(self + .validate_tx(state, tx_context, remaining_validation_gas, limit_steps_by_resources)? + .inspect(|call_info| { + // TODO(Aner): Update the gas counter. + remaining_gas.subtract_used_gas(call_info); + })) } else { Ok(None) } @@ -503,20 +511,29 @@ impl AccountTransaction { &self, state: &mut S, context: &mut EntryPointExecutionContext, - remaining_gas: &mut u64, + remaining_gas: &mut GasCounter, ) -> TransactionExecutionResult> { - match &self.tx { - Transaction::Declare(tx) => tx.run_execute(state, context, remaining_gas), - Transaction::DeployAccount(tx) => tx.run_execute(state, context, remaining_gas), - Transaction::Invoke(tx) => tx.run_execute(state, context, remaining_gas), - } + // TODO(Aner): cap the gas usage for execution. + let remaining_execution_gas = + &mut remaining_gas.limit_usage(context.mode_sierra_gas_limit()); + Ok(match &self.tx { + Transaction::Declare(tx) => tx.run_execute(state, context, remaining_execution_gas), + Transaction::DeployAccount(tx) => { + tx.run_execute(state, context, remaining_execution_gas) + } + Transaction::Invoke(tx) => tx.run_execute(state, context, remaining_execution_gas), + }? + .inspect(|call_info| { + // TODO(Aner): Update the gas counter. + remaining_gas.subtract_used_gas(call_info); + })) } fn run_non_revertible( &self, state: &mut TransactionalState<'_, S>, tx_context: Arc, - remaining_gas: &mut u64, + remaining_gas: &mut GasCounter, ) -> TransactionExecutionResult { let validate_call_info: Option; let execute_call_info: Option; @@ -572,7 +589,7 @@ impl AccountTransaction { &self, state: &mut TransactionalState<'_, S>, tx_context: Arc, - remaining_gas: &mut u64, + remaining_gas: &mut GasCounter, ) -> TransactionExecutionResult { let mut execution_context = EntryPointExecutionContext::new_invoke( tx_context.clone(), @@ -717,7 +734,7 @@ impl AccountTransaction { fn run_or_revert( &self, state: &mut TransactionalState<'_, S>, - remaining_gas: &mut u64, + remaining_gas: &mut GasCounter, tx_context: Arc, ) -> TransactionExecutionResult { if self.is_non_revertible(&tx_context.tx_info) { @@ -743,7 +760,7 @@ impl ExecutableTransaction for AccountTransaction { self.perform_pre_validation_stage(state, &tx_context, strict_nonce_check)?; // Run validation and execution. - let mut remaining_gas = tx_context.initial_sierra_gas(); + let initial_gas = tx_context.initial_sierra_gas(); let ValidateExecuteCallInfo { validate_call_info, execute_call_info, @@ -755,7 +772,7 @@ impl ExecutableTransaction for AccountTransaction { resources: final_resources, gas: total_gas, }, - } = self.run_or_revert(state, &mut remaining_gas, tx_context.clone())?; + } = self.run_or_revert(state, &mut GasCounter::new(initial_gas), tx_context.clone())?; let fee_transfer_call_info = Self::handle_fee( state, tx_context, diff --git a/crates/blockifier/src/transaction/account_transactions_test.rs b/crates/blockifier/src/transaction/account_transactions_test.rs index c902dd7c70..9cccd6e89a 100644 --- a/crates/blockifier/src/transaction/account_transactions_test.rs +++ b/crates/blockifier/src/transaction/account_transactions_test.rs @@ -1691,18 +1691,25 @@ fn test_initial_gas( resource_bounds: default_all_resource_bounds, version: TransactionVersion::THREE }); + let user_gas_bound = block_context.to_tx_context(&account_tx).initial_sierra_gas(); let transaction_ex_info = account_tx.execute(state, &block_context).unwrap(); let validate_call_info = &transaction_ex_info.validate_call_info.unwrap(); let validate_initial_gas = validate_call_info.call.initial_gas; - assert_eq!(validate_initial_gas, DEFAULT_L2_GAS_MAX_AMOUNT.0); + assert_eq!(validate_initial_gas, block_context.versioned_constants.validate_max_sierra_gas.0); let validate_gas_consumed = validate_call_info.execution.gas_consumed; assert!(validate_gas_consumed > 0, "New Cairo1 contract should consume gas."); let default_call_info = CallInfo::default(); - let mut prev_initial_gas = validate_initial_gas; let mut execute_call_info = &transaction_ex_info.execute_call_info.unwrap(); + // Initial gas for execution is the minimum between the max execution gas and the initial gas + // minus the gas consumed by validate. Need to add 1 as the check is strictly less than. + let mut prev_initial_gas = block_context + .versioned_constants + .execute_max_sierra_gas + .min(user_gas_bound - GasAmount(validate_gas_consumed) + GasAmount(1)) + .0; let mut curr_initial_gas; let mut started_vm_mode = false; // The __validate__ call of a the account contract. @@ -1729,7 +1736,7 @@ fn test_initial_gas( ); assert_eq!( curr_initial_gas, - block_context.versioned_constants.default_initial_gas_cost() + block_context.versioned_constants.inifite_gas_for_vm_mode() ); started_vm_mode = true; } diff --git a/crates/blockifier/src/transaction/transaction_execution.rs b/crates/blockifier/src/transaction/transaction_execution.rs index 19f2675867..e6bf862ba9 100644 --- a/crates/blockifier/src/transaction/transaction_execution.rs +++ b/crates/blockifier/src/transaction/transaction_execution.rs @@ -144,7 +144,7 @@ impl ExecutableTransaction for L1HandlerTransaction { let limit_steps_by_resources = false; let mut context = EntryPointExecutionContext::new_invoke(tx_context.clone(), limit_steps_by_resources); - let mut remaining_gas = tx_context.initial_sierra_gas(); + let mut remaining_gas = tx_context.initial_sierra_gas().0; let execute_call_info = self.run_execute(state, &mut context, &mut remaining_gas)?; let l1_handler_payload_size = self.payload_size(); let TransactionReceipt { diff --git a/crates/blockifier/src/transaction/transactions_test.rs b/crates/blockifier/src/transaction/transactions_test.rs index 479ba7104a..dd68beeb52 100644 --- a/crates/blockifier/src/transaction/transactions_test.rs +++ b/crates/blockifier/src/transaction/transactions_test.rs @@ -1,3 +1,4 @@ +use std::cmp::min; use std::collections::{HashMap, HashSet}; use std::sync::{Arc, LazyLock}; @@ -162,7 +163,7 @@ static VERSIONED_CONSTANTS: LazyLock = #[fixture] fn default_initial_gas_cost() -> u64 { - VERSIONED_CONSTANTS.default_initial_gas_cost() + VERSIONED_CONSTANTS.inifite_gas_for_vm_mode() } #[fixture] @@ -170,6 +171,13 @@ fn versioned_constants_for_account_testing() -> VersionedConstants { VERSIONED_CONSTANTS.clone() } +fn initial_gas_amount_from_block_context(block_context: Option<&BlockContext>) -> GasAmount { + match block_context { + Some(block_context) => block_context.versioned_constants.initial_gas_no_user_l2_bound(), + None => VERSIONED_CONSTANTS.initial_gas_no_user_l2_bound(), + } +} + struct ExpectedResultTestInvokeTx { resources: ExecutionResources, validate_gas_consumed: u64, @@ -177,10 +185,13 @@ struct ExpectedResultTestInvokeTx { inner_call_initial_gas: u64, } -fn user_initial_gas_from_bounds(bounds: ValidResourceBounds) -> Option { +fn user_initial_gas_from_bounds( + bounds: ValidResourceBounds, + block_context: Option<&BlockContext>, +) -> GasAmount { match bounds { - ValidResourceBounds::L1Gas(_) => None, - ValidResourceBounds::AllResources(bounds) => Some(bounds.l2_gas.max_amount), + ValidResourceBounds::L1Gas(_) => initial_gas_amount_from_block_context(block_context), + ValidResourceBounds::AllResources(bounds) => bounds.l2_gas.max_amount, } } @@ -239,11 +250,17 @@ fn expected_validate_call_info( builtin_instance_counter: HashMap::from([(BuiltinName::range_check, n_range_checks)]), } .filter_unused_builtins(); - let initial_gas = match tracked_resource { - TrackedResource::CairoSteps => default_initial_gas_cost(), - TrackedResource::SierraGas => { - user_initial_gas.unwrap_or(GasAmount(default_initial_gas_cost())).0 - } + let initial_gas = match cairo_version { + CairoVersion::Cairo0 => default_initial_gas_cost(), + CairoVersion::Cairo1(_) => match tracked_resource { + TrackedResource::CairoSteps => initial_gas_amount_from_block_context(None).0, + TrackedResource::SierraGas => { + user_initial_gas + .unwrap_or(initial_gas_amount_from_block_context(None)) + .min(VERSIONED_CONSTANTS.validate_max_sierra_gas) + .0 + } + }, }; Some(CallInfo { @@ -432,7 +449,7 @@ fn add_kzg_da_resources_to_resources_mapping( }, validate_gas_consumed: 0, execute_gas_consumed: 0, - inner_call_initial_gas: versioned_constants_for_account_testing().default_initial_gas_cost(), + inner_call_initial_gas: versioned_constants_for_account_testing().inifite_gas_for_vm_mode(), }, CairoVersion::Cairo0)] #[case::with_cairo1_account( @@ -445,7 +462,7 @@ fn add_kzg_da_resources_to_resources_mapping( validate_gas_consumed: 4740, // The gas consumption results from parsing the input // arguments. execute_gas_consumed: 112080, - inner_call_initial_gas: versioned_constants_for_account_testing().default_initial_gas_cost(), + inner_call_initial_gas: versioned_constants_for_account_testing().inifite_gas_for_vm_mode(), }, CairoVersion::Cairo1(RunnableCairo1::Casm))] // TODO(Tzahi): Add calls to cairo1 test contracts (where gas flows to and from the inner call). @@ -497,14 +514,10 @@ fn test_invoke_tx( let tracked_resource = account_contract .get_runnable_class() .tracked_resource(&versioned_constants.min_compiler_version_for_sierra_gas, None); - if tracked_resource == TrackedResource::CairoSteps { - // In CairoSteps mode, the initial gas is set to the default once before the validate call. - expected_arguments.inner_call_initial_gas -= - expected_arguments.validate_gas_consumed + expected_arguments.execute_gas_consumed - } // Build expected validate call info. let expected_account_class_hash = account_contract.get_class_hash(); + let initial_gas = user_initial_gas_from_bounds(resource_bounds, Some(block_context)); let expected_validate_call_info = expected_validate_call_info( expected_account_class_hash, constants::VALIDATE_ENTRY_POINT_NAME, @@ -513,11 +526,37 @@ fn test_invoke_tx( sender_address, account_cairo_version, tracked_resource, - user_initial_gas_from_bounds(resource_bounds), + Some(initial_gas.min(versioned_constants.validate_max_sierra_gas)), ); // Build expected execute call info. let expected_return_result_calldata = vec![felt!(2_u8)]; + + let expected_validated_call = expected_validate_call_info.as_ref().unwrap().call.clone(); + let expected_initial_execution_gas = versioned_constants + .execute_max_sierra_gas + .min(initial_gas - GasAmount(expected_arguments.validate_gas_consumed)) + .0; + if account_cairo_version == CairoVersion::Cairo0 { + expected_arguments.inner_call_initial_gas = versioned_constants.inifite_gas_for_vm_mode(); + } + let expected_execute_call = CallEntryPoint { + entry_point_selector: selector_from_name(constants::EXECUTE_ENTRY_POINT_NAME), + initial_gas: if account_cairo_version == CairoVersion::Cairo0 { + versioned_constants.inifite_gas_for_vm_mode() + } else { + expected_initial_execution_gas + }, + ..expected_validated_call + }; + if tracked_resource == TrackedResource::CairoSteps { + expected_arguments.inner_call_initial_gas -= expected_arguments.validate_gas_consumed; + expected_arguments.inner_call_initial_gas = min( + expected_arguments.inner_call_initial_gas, + versioned_constants.execute_max_sierra_gas.0, + ); + expected_arguments.inner_call_initial_gas -= expected_arguments.execute_gas_consumed; + } let expected_return_result_call = CallEntryPoint { entry_point_selector: selector_from_name("return_result"), class_hash: Some(test_contract.get_class_hash()), @@ -527,13 +566,11 @@ fn test_invoke_tx( storage_address: test_contract_address, caller_address: sender_address, call_type: CallType::Call, - initial_gas: expected_arguments.inner_call_initial_gas, - }; - let expected_validated_call = expected_validate_call_info.as_ref().unwrap().call.clone(); - let expected_execute_call = CallEntryPoint { - entry_point_selector: selector_from_name(constants::EXECUTE_ENTRY_POINT_NAME), - initial_gas: expected_validated_call.initial_gas - expected_arguments.validate_gas_consumed, - ..expected_validated_call + initial_gas: if account_cairo_version == CairoVersion::Cairo0 { + versioned_constants.inifite_gas_for_vm_mode() + } else { + expected_arguments.inner_call_initial_gas + }, }; let expected_return_result_retdata = Retdata(expected_return_result_calldata); let expected_execute_call_info = Some(CallInfo { @@ -1571,7 +1608,7 @@ fn test_declare_tx( .get_runnable_class() .tracked_resource(&versioned_constants.min_compiler_version_for_sierra_gas, None), if tx_version >= TransactionVersion::THREE { - user_initial_gas_from_bounds(default_all_resource_bounds) + Some(user_initial_gas_from_bounds(default_all_resource_bounds, Some(block_context))) } else { None }, @@ -1740,7 +1777,8 @@ fn test_deploy_account_tx( // account transaction. let class_hash = deploy_account.class_hash().unwrap(); let deployed_account_address = deploy_account.sender_address(); - let user_initial_gas = user_initial_gas_from_bounds(default_all_resource_bounds); + let user_initial_gas = + user_initial_gas_from_bounds(default_all_resource_bounds, Some(block_context)); // Update the balance of the about to be deployed account contract in the erc20 contract, so it // can pay for the transaction execution. @@ -1785,10 +1823,14 @@ fn test_deploy_account_tx( account .get_runnable_class() .tracked_resource(&versioned_constants.min_compiler_version_for_sierra_gas, None), - user_initial_gas, + Some(user_initial_gas), ); // Build expected execute call info. + let expected_execute_initial_gas = user_initial_gas + // Note that in the case of deploy account, the initial gas in "execute" is limited by + // max_validation_sierra_gas. + .min(versioned_constants.validate_max_sierra_gas); let expected_execute_call_info = Some(CallInfo { call: CallEntryPoint { class_hash: Some(account_class_hash), @@ -1796,7 +1838,7 @@ fn test_deploy_account_tx( entry_point_type: EntryPointType::Constructor, entry_point_selector: selector_from_name(CONSTRUCTOR_ENTRY_POINT_NAME), storage_address: deployed_account_address, - initial_gas: user_initial_gas.unwrap_or(GasAmount(default_initial_gas_cost())).0, + initial_gas: expected_execute_initial_gas.0, ..Default::default() }, ..Default::default() @@ -2307,7 +2349,7 @@ fn test_l1_handler(#[values(false, true)] use_kzg_da: bool) { storage_address: contract_address, caller_address: ContractAddress::default(), call_type: CallType::Call, - initial_gas: default_initial_gas_cost(), + initial_gas: initial_gas_amount_from_block_context(Some(block_context)).0, }, execution: CallExecution { retdata: Retdata(vec![value]), diff --git a/crates/blockifier/src/versioned_constants.rs b/crates/blockifier/src/versioned_constants.rs index 1bf86ff6df..9e46492fa8 100644 --- a/crates/blockifier/src/versioned_constants.rs +++ b/crates/blockifier/src/versioned_constants.rs @@ -23,6 +23,7 @@ use starknet_api::transaction::fields::GasVectorComputationMode; use strum::IntoEnumIterator; use thiserror::Error; +use crate::execution::common_hints::ExecutionMode; use crate::execution::deprecated_syscalls::hint_processor::SyscallCounter; use crate::execution::execution_utils::poseidon_hash_many_cost; use crate::execution::syscalls::SyscallSelector; @@ -249,8 +250,22 @@ impl VersionedConstants { * self.vm_resource_fee_cost().n_steps } + /// Default initial gas amount when L2 gas is not provided. + pub fn initial_gas_no_user_l2_bound(&self) -> GasAmount { + (self.execute_max_sierra_gas.checked_add(self.validate_max_sierra_gas)) + .expect("The default initial gas cost should be less than the maximum gas amount.") + } + + /// Returns the maximum gas amount according to the given mode. + pub fn sierra_gas_limit(&self, mode: &ExecutionMode) -> GasAmount { + match mode { + ExecutionMode::Validate => self.validate_max_sierra_gas, + ExecutionMode::Execute => self.execute_max_sierra_gas, + } + } + /// Returns the default initial gas for VM mode transactions. - pub fn default_initial_gas_cost(&self) -> u64 { + pub fn inifite_gas_for_vm_mode(&self) -> u64 { self.os_constants.gas_costs.base.default_initial_gas_cost } diff --git a/crates/starknet_api/src/execution_resources.rs b/crates/starknet_api/src/execution_resources.rs index 6a81a05c9c..63577a1cce 100644 --- a/crates/starknet_api/src/execution_resources.rs +++ b/crates/starknet_api/src/execution_resources.rs @@ -7,7 +7,10 @@ use strum_macros::EnumIter; use crate::block::{GasPrice, GasPriceVector, NonzeroGasPrice}; use crate::transaction::fields::{Fee, Resource}; -#[cfg_attr(any(test, feature = "testing"), derive(derive_more::Sum, derive_more::Div))] +#[cfg_attr( + any(test, feature = "testing"), + derive(derive_more::Sum, derive_more::Div, derive_more::SubAssign) +)] #[derive( derive_more::Display, derive_more::Sub,