diff --git a/crates/blockifier/src/blockifier/transaction_executor_test.rs b/crates/blockifier/src/blockifier/transaction_executor_test.rs index ac55aab4a0..5cf8f13260 100644 --- a/crates/blockifier/src/blockifier/transaction_executor_test.rs +++ b/crates/blockifier/src/blockifier/transaction_executor_test.rs @@ -1,6 +1,7 @@ use assert_matches::assert_matches; use pretty_assertions::assert_eq; use rstest::rstest; +use starknet_api::execution_resources::GasAmount; use starknet_api::test_utils::NonceManager; use starknet_api::transaction::{Fee, TransactionVersion}; use starknet_api::{declare_tx_args, deploy_account_tx_args, felt, invoke_tx_args, nonce}; @@ -120,7 +121,7 @@ fn test_declare( class_hash: declared_contract.get_class_hash(), compiled_class_hash: declared_contract.get_compiled_class_hash(), version: tx_version, - resource_bounds: l1_resource_bounds(0, DEFAULT_STRK_L1_GAS_PRICE), + resource_bounds: l1_resource_bounds(GasAmount(0), DEFAULT_STRK_L1_GAS_PRICE), }, calculate_class_info_for_testing(declared_contract.get_class()), ) @@ -140,7 +141,7 @@ fn test_deploy_account( let tx = deploy_account_tx( deploy_account_tx_args! { class_hash: account_contract.get_class_hash(), - resource_bounds: l1_resource_bounds(0, DEFAULT_STRK_L1_GAS_PRICE), + resource_bounds: l1_resource_bounds(GasAmount(0), DEFAULT_STRK_L1_GAS_PRICE), version, }, &mut NonceManager::default(), diff --git a/crates/blockifier/src/bouncer.rs b/crates/blockifier/src/bouncer.rs index b13ee81caf..4e778f94c2 100644 --- a/crates/blockifier/src/bouncer.rs +++ b/crates/blockifier/src/bouncer.rs @@ -296,7 +296,7 @@ pub fn get_tx_weights( state_changes_keys: &StateChangesKeys, ) -> TransactionExecutionResult { let message_resources = &tx_resources.starknet_resources.messages; - let message_starknet_gas = usize_from_u128(message_resources.get_starknet_gas_cost().l1_gas) + let message_starknet_gas = usize_from_u128(message_resources.get_starknet_gas_cost().l1_gas.0) .expect("This conversion should not fail as the value is a converted usize."); let mut additional_os_resources = get_casm_hash_calculation_resources(state_reader, executed_class_hashes)?; diff --git a/crates/blockifier/src/concurrency/versioned_state_test.rs b/crates/blockifier/src/concurrency/versioned_state_test.rs index 1093535a69..8932df1907 100644 --- a/crates/blockifier/src/concurrency/versioned_state_test.rs +++ b/crates/blockifier/src/concurrency/versioned_state_test.rs @@ -238,7 +238,7 @@ fn test_run_parallel_txs(max_l1_resource_bounds: ValidResourceBounds) { let deploy_account_tx_1 = deploy_account_tx( deploy_account_tx_args! { class_hash: account_without_validation.get_class_hash(), - resource_bounds: l1_resource_bounds(u64::from(!zero_bounds), DEFAULT_STRK_L1_GAS_PRICE), + resource_bounds: l1_resource_bounds(u128::from(!zero_bounds).into(), DEFAULT_STRK_L1_GAS_PRICE), }, &mut NonceManager::default(), ); diff --git a/crates/blockifier/src/fee/fee_checks.rs b/crates/blockifier/src/fee/fee_checks.rs index 0a14d27b56..a47d4e8d1b 100644 --- a/crates/blockifier/src/fee/fee_checks.rs +++ b/crates/blockifier/src/fee/fee_checks.rs @@ -1,3 +1,4 @@ +use starknet_api::execution_resources::GasAmount; use starknet_api::transaction::Resource::{self, L1DataGas, L1Gas, L2Gas}; use starknet_api::transaction::{AllResourceBounds, Fee, ResourceBounds, ValidResourceBounds}; use starknet_types_core::felt::Felt; @@ -16,7 +17,7 @@ pub enum FeeCheckError { #[error( "Insufficient max {resource}: max amount: {max_amount}, actual used: {actual_amount}." )] - MaxGasAmountExceeded { resource: Resource, max_amount: u128, actual_amount: u128 }, + MaxGasAmountExceeded { resource: Resource, max_amount: GasAmount, actual_amount: GasAmount }, #[error("Insufficient max fee: max fee: {}, actual fee: {}.", max_fee.0, actual_fee.0)] MaxFeeExceeded { max_fee: Fee, actual_fee: Fee }, #[error( diff --git a/crates/blockifier/src/fee/fee_test.rs b/crates/blockifier/src/fee/fee_test.rs index 04b6ba83bf..7223ca03ae 100644 --- a/crates/blockifier/src/fee/fee_test.rs +++ b/crates/blockifier/src/fee/fee_test.rs @@ -4,6 +4,7 @@ use assert_matches::assert_matches; use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use rstest::rstest; +use starknet_api::execution_resources::GasAmount; use starknet_api::invoke_tx_args; use starknet_api::transaction::{Fee, GasVectorComputationMode, Resource, ValidResourceBounds}; @@ -56,10 +57,12 @@ fn test_simple_get_vm_resource_usage( // Positive flow. // Verify calculation - in our case, n_steps is the heaviest resource. - let vm_usage_in_l1_gas = (versioned_constants.vm_resource_fee_cost().n_steps - * (u128_from_usize(vm_resource_usage.n_steps + n_reverted_steps))) - .ceil() - .to_integer(); + let vm_usage_in_l1_gas = GasAmount( + (versioned_constants.vm_resource_fee_cost().n_steps + * (u128_from_usize(vm_resource_usage.n_steps + n_reverted_steps))) + .ceil() + .to_integer(), + ); let expected_gas_vector = gas_vector_from_vm_usage( vm_usage_in_l1_gas, &gas_vector_computation_mode, @@ -81,7 +84,8 @@ fn test_simple_get_vm_resource_usage( vm_resource_usage.builtin_instance_counter.get(&BuiltinName::range_check).unwrap() - 1; let vm_usage_in_l1_gas = u128_from_usize( *vm_resource_usage.builtin_instance_counter.get(&BuiltinName::range_check).unwrap(), - ); + ) + .into(); let expected_gas_vector = gas_vector_from_vm_usage( vm_usage_in_l1_gas, &gas_vector_computation_mode, @@ -109,10 +113,12 @@ fn test_float_get_vm_resource_usage( // Positive flow. // Verify calculation - in our case, n_steps is the heaviest resource. let n_reverted_steps = 300; - let vm_usage_in_l1_gas = (versioned_constants.vm_resource_fee_cost().n_steps - * u128_from_usize(vm_resource_usage.n_steps + n_reverted_steps)) - .ceil() - .to_integer(); + let vm_usage_in_l1_gas = GasAmount( + (versioned_constants.vm_resource_fee_cost().n_steps + * u128_from_usize(vm_resource_usage.n_steps + n_reverted_steps)) + .ceil() + .to_integer(), + ); let expected_gas_vector = gas_vector_from_vm_usage( vm_usage_in_l1_gas, &gas_vector_computation_mode, @@ -130,13 +136,14 @@ fn test_float_get_vm_resource_usage( // Another positive flow, this time the heaviest resource is ecdsa_builtin. vm_resource_usage.n_steps = 200; - let vm_usage_in_l1_gas = + let vm_usage_in_l1_gas = GasAmount( ((*versioned_constants.vm_resource_fee_cost().builtins.get(&BuiltinName::ecdsa).unwrap()) * u128_from_usize( *vm_resource_usage.builtin_instance_counter.get(&BuiltinName::ecdsa).unwrap(), )) .ceil() - .to_integer(); + .to_integer(), + ); let expected_gas_vector = gas_vector_from_vm_usage( vm_usage_in_l1_gas, &gas_vector_computation_mode, @@ -167,9 +174,10 @@ fn test_discounted_gas_overdraft( #[case] data_gas_price: u128, #[case] l1_gas_used: usize, #[case] l1_data_gas_used: usize, - #[case] gas_bound: u64, + #[case] gas_bound: u128, #[case] expect_failure: bool, ) { + let gas_bound = GasAmount(gas_bound); let mut block_context = BlockContext::create_for_account_testing(); block_context.block_info.gas_prices = GasPrices::new( DEFAULT_ETH_L1_GAS_PRICE.try_into().unwrap(), @@ -197,8 +205,8 @@ fn test_discounted_gas_overdraft( let tx_receipt = TransactionReceipt { fee: Fee(7), gas: GasVector { - l1_gas: u128_from_usize(l1_gas_used), - l1_data_gas: u128_from_usize(l1_data_gas_used), + l1_gas: u128_from_usize(l1_gas_used).into(), + l1_data_gas: u128_from_usize(l1_data_gas_used).into(), ..Default::default() }, ..Default::default() @@ -214,11 +222,14 @@ fn test_discounted_gas_overdraft( if expect_failure { let error = report.error().unwrap(); - let expected_actual_amount = u128_from_usize(l1_gas_used) - + (u128_from_usize(l1_data_gas_used) * data_gas_price) / gas_price; + let expected_actual_amount = (u128_from_usize(l1_gas_used) + + (u128_from_usize(l1_data_gas_used) * data_gas_price) / gas_price) + .into(); assert_matches!( error, FeeCheckError::MaxGasAmountExceeded { resource, max_amount, actual_amount } - if max_amount == u128::from(gas_bound) && actual_amount == expected_actual_amount && resource == Resource::L1Gas + if max_amount == gas_bound + && actual_amount == expected_actual_amount + && resource == Resource::L1Gas ) } else { assert_matches!(report.error(), None); @@ -284,20 +295,14 @@ fn test_post_execution_gas_overdraft_all_resource_bounds( } #[rstest] -#[case::happy_flow_l1_gas_only( - GasVector { l1_gas: 10, ..Default::default() }, 10, 2*10 -)] -#[case::happy_flow_no_l2_gas( - GasVector { l1_gas: 10, l1_data_gas: 20, ..Default::default() }, 10 + 3*20, 2*10 + 4*20 -)] -#[case::saturating_l1_gas( - GasVector { l1_gas: u128::MAX, l1_data_gas: 1, ..Default::default() }, u128::MAX, u128::MAX -)] -#[case::saturating_l1_data_gas( - GasVector { l1_gas: 1, l1_data_gas: u128::MAX, ..Default::default() }, u128::MAX, u128::MAX -)] +#[case::happy_flow_l1_gas_only(10, 0, 0, 10, 2*10)] +#[case::happy_flow_no_l2_gas(10, 20, 0, 10 + 3*20, 2*10 + 4*20)] +#[case::saturating_l1_gas(u128::MAX, 1, 0, u128::MAX, u128::MAX)] +#[case::saturating_l1_data_gas(1, u128::MAX, 0, u128::MAX, u128::MAX)] fn test_get_fee_by_gas_vector_regression( - #[case] gas_vector: GasVector, + #[case] l1_gas: u128, + #[case] l1_data_gas: u128, + #[case] l2_gas: u128, #[case] expected_fee_eth: u128, #[case] expected_fee_strk: u128, ) { @@ -310,6 +315,8 @@ fn test_get_fee_by_gas_vector_regression( 5.try_into().unwrap(), 6.try_into().unwrap(), ); + let gas_vector = + GasVector { l1_gas: l1_gas.into(), l1_data_gas: l1_data_gas.into(), l2_gas: l2_gas.into() }; assert_eq!( get_fee_by_gas_vector(&block_info, gas_vector, &FeeType::Eth), Fee(expected_fee_eth) diff --git a/crates/blockifier/src/fee/fee_utils.rs b/crates/blockifier/src/fee/fee_utils.rs index 3208b14e45..eca01cecbf 100644 --- a/crates/blockifier/src/fee/fee_utils.rs +++ b/crates/blockifier/src/fee/fee_utils.rs @@ -4,6 +4,7 @@ use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use num_bigint::BigUint; use starknet_api::core::ContractAddress; +use starknet_api::execution_resources::GasAmount; use starknet_api::state::StorageKey; use starknet_api::transaction::ValidResourceBounds::{AllResources, L1Gas}; use starknet_api::transaction::{AllResourceBounds, Fee, GasVectorComputationMode, Resource}; @@ -50,7 +51,8 @@ pub fn get_vm_resources_cost( // Convert Cairo resource usage to L1 gas usage. // Do so by taking the maximum of the usage of each builtin + step usage. - let vm_l1_gas_usage = vm_resource_fee_costs + let vm_l1_gas_usage = GasAmount( + vm_resource_fee_costs .builtins .iter() // Builtin costs and usage. @@ -63,7 +65,8 @@ pub fn get_vm_resources_cost( vm_resource_usage.total_n_steps() + n_reverted_steps, )]) .map(|(cost, usage)| (cost * u128_from_usize(usage)).ceil().to_integer()) - .fold(0, u128::max); + .fold(0, u128::max), + ); match computation_mode { GasVectorComputationMode::NoL2Gas => GasVector::from_l1_gas(vm_l1_gas_usage), diff --git a/crates/blockifier/src/fee/gas_usage.rs b/crates/blockifier/src/fee/gas_usage.rs index d9052e4074..49d3896e78 100644 --- a/crates/blockifier/src/fee/gas_usage.rs +++ b/crates/blockifier/src/fee/gas_usage.rs @@ -42,10 +42,11 @@ pub fn get_da_gas_cost(state_changes_count: &StateChangesCount, use_kzg_da: bool let (l1_gas, blob_gas) = if use_kzg_da { ( - 0, + 0_u8.into(), u128_from_usize( onchain_data_segment_length * eth_gas_constants::DATA_GAS_PER_FIELD_ELEMENT, - ), + ) + .into(), ) } else { // TODO(Yoni, 1/5/2024): count the exact amount of nonzero bytes for each DA entry. @@ -70,7 +71,7 @@ pub fn get_da_gas_cost(state_changes_count: &StateChangesCount, use_kzg_da: bool naive_cost - discount }; - (u128_from_usize(gas), 0) + (u128_from_usize(gas).into(), 0_u8.into()) }; GasVector { l1_gas, l1_data_gas: blob_gas, ..Default::default() } @@ -134,11 +135,14 @@ pub fn get_log_message_to_l1_emissions_cost(l2_to_l1_payload_lengths: &[usize]) } fn get_event_emission_cost(n_topics: usize, data_length: usize) -> GasVector { - GasVector::from_l1_gas(u128_from_usize( - eth_gas_constants::GAS_PER_LOG - + (n_topics + constants::N_DEFAULT_TOPICS) * eth_gas_constants::GAS_PER_LOG_TOPIC - + data_length * eth_gas_constants::GAS_PER_LOG_DATA_WORD, - )) + GasVector::from_l1_gas( + u128_from_usize( + eth_gas_constants::GAS_PER_LOG + + (n_topics + constants::N_DEFAULT_TOPICS) * eth_gas_constants::GAS_PER_LOG_TOPIC + + data_length * eth_gas_constants::GAS_PER_LOG_DATA_WORD, + ) + .into(), + ) } /// Returns an estimated lower bound for the gas required by the given account transaction. diff --git a/crates/blockifier/src/fee/gas_usage_test.rs b/crates/blockifier/src/fee/gas_usage_test.rs index 2f1fc9df6b..bccfe881b6 100644 --- a/crates/blockifier/src/fee/gas_usage_test.rs +++ b/crates/blockifier/src/fee/gas_usage_test.rs @@ -2,6 +2,7 @@ use std::num::NonZeroU128; use pretty_assertions::assert_eq; use rstest::{fixture, rstest}; +use starknet_api::execution_resources::GasAmount; use starknet_api::invoke_tx_args; use starknet_api::transaction::{EventContent, EventData, EventKey, Fee, GasVectorComputationMode}; use starknet_types_core::felt::Felt; @@ -90,7 +91,8 @@ fn test_get_event_gas_cost( .collect(); let execution_summary = CallInfo::summarize_many(call_infos.iter()); // 8 keys and 11 data words overall. - let expected_gas = (data_word_cost * (event_key_factor * 8_u128 + 11_u128)).to_integer(); + let expected_gas = + GasAmount((data_word_cost * (event_key_factor * 8_u128 + 11_u128)).to_integer()); let expected_gas_vector = match gas_vector_computation_mode { GasVectorComputationMode::NoL2Gas => GasVector::from_l1_gas(expected_gas), GasVectorComputationMode::All => GasVector::from_l2_gas(expected_gas), @@ -146,7 +148,7 @@ fn test_get_da_gas_cost_basic(#[case] state_changes_count: StateChangesCount) { let computed_gas_vector = get_da_gas_cost(&state_changes_count, true); assert_eq!( - GasVector::from_l1_data_gas(u128_from_usize(manual_blob_gas_usage)), + GasVector::from_l1_data_gas(u128_from_usize(manual_blob_gas_usage).into()), computed_gas_vector ); } @@ -155,7 +157,7 @@ fn test_get_da_gas_cost_basic(#[case] state_changes_count: StateChangesCount) { fn test_onchain_data_discount() { let use_kzg_da = false; // Check that there's no negative cost. - assert_eq!(get_da_gas_cost(&StateChangesCount::default(), use_kzg_da).l1_gas, 0); + assert_eq!(get_da_gas_cost(&StateChangesCount::default(), use_kzg_da).l1_gas, GasAmount(0)); // Check discount: modified_contract_felt and fee balance discount. let state_changes_count = StateChangesCount { @@ -186,7 +188,7 @@ fn test_onchain_data_discount() { assert_eq!( get_da_gas_cost(&state_changes_count, use_kzg_da).l1_gas, - expected_cost.try_into().unwrap() + u64::try_from(expected_cost).unwrap().into() ); // Test 10% discount. @@ -195,7 +197,7 @@ fn test_onchain_data_discount() { let cost_without_discount = (state_changes_count.n_storage_updates * 2) * (512 + 100); let actual_cost = get_da_gas_cost(&state_changes_count, use_kzg_da).l1_gas; - let cost_ratio = ResourceCost::new(actual_cost, u128_from_usize(cost_without_discount)); + let cost_ratio = ResourceCost::new(actual_cost.0, u128_from_usize(cost_without_discount)); assert!(cost_ratio <= ResourceCost::new(9, 10)); assert!(cost_ratio >= ResourceCost::new(88, 100)); } @@ -227,21 +229,25 @@ fn test_get_message_segment_length( fn test_discounted_gas_from_gas_vector_computation() { let tx_context = BlockContext::create_for_testing().to_tx_context(&account_invoke_tx(invoke_tx_args! {})); - let gas_usage = GasVector { l1_gas: 100, l1_data_gas: 2, ..Default::default() }; + let gas_usage = + GasVector { l1_gas: GasAmount(100), l1_data_gas: GasAmount(2), ..Default::default() }; let actual_result = gas_usage.to_discounted_l1_gas(&tx_context); let result_div_ceil = gas_usage.l1_gas + u128_div_ceil( - gas_usage.l1_data_gas * DEFAULT_ETH_L1_DATA_GAS_PRICE, + gas_usage.l1_data_gas.0 * DEFAULT_ETH_L1_DATA_GAS_PRICE, NonZeroU128::new(DEFAULT_ETH_L1_GAS_PRICE).unwrap(), - ); - let result_div_floor = gas_usage.l1_gas - + (gas_usage.l1_data_gas * DEFAULT_ETH_L1_DATA_GAS_PRICE) / DEFAULT_ETH_L1_GAS_PRICE; + ) + .into(); + let result_div_floor = GasAmount( + gas_usage.l1_gas.0 + + (gas_usage.l1_data_gas.0 * DEFAULT_ETH_L1_DATA_GAS_PRICE) / DEFAULT_ETH_L1_GAS_PRICE, + ); assert_eq!(actual_result, result_div_ceil); - assert_eq!(actual_result, result_div_floor + 1); + assert_eq!(actual_result, result_div_floor + GasAmount(1)); assert!( get_fee_by_gas_vector(&tx_context.block_context.block_info, gas_usage, &FeeType::Eth) - <= Fee(actual_result * DEFAULT_ETH_L1_GAS_PRICE) + <= Fee(actual_result.0 * DEFAULT_ETH_L1_GAS_PRICE) ); } diff --git a/crates/blockifier/src/fee/receipt_test.rs b/crates/blockifier/src/fee/receipt_test.rs index 49af4e6915..4cbe47a677 100644 --- a/crates/blockifier/src/fee/receipt_test.rs +++ b/crates/blockifier/src/fee/receipt_test.rs @@ -1,4 +1,5 @@ use rstest::{fixture, rstest}; +use starknet_api::execution_resources::GasAmount; use starknet_api::transaction::{GasVectorComputationMode, L2ToL1Payload}; use starknet_api::{invoke_tx_args, nonce}; use starknet_types_core::felt::Felt; @@ -81,13 +82,15 @@ fn test_calculate_tx_gas_usage_basic<'a>( let gas_per_code_byte = versioned_constants .get_archival_data_gas_costs(&gas_vector_computation_mode) .gas_per_code_byte; - let code_gas_cost = (gas_per_code_byte - * u128_from_usize( - (class_info.bytecode_length() + class_info.sierra_program_length()) - * eth_gas_constants::WORD_WIDTH - + class_info.abi_length(), - )) - .to_integer(); + let code_gas_cost = GasAmount( + (gas_per_code_byte + * u128_from_usize( + (class_info.bytecode_length() + class_info.sierra_program_length()) + * eth_gas_constants::WORD_WIDTH + + class_info.abi_length(), + )) + .to_integer(), + ); let manual_gas_vector = match gas_vector_computation_mode { GasVectorComputationMode::NoL2Gas => GasVector::from_l1_gas(code_gas_cost), GasVectorComputationMode::All => GasVector::from_l2_gas(code_gas_cost), @@ -123,8 +126,10 @@ fn test_calculate_tx_gas_usage_basic<'a>( let gas_per_data_felt = versioned_constants .get_archival_data_gas_costs(&gas_vector_computation_mode) .gas_per_data_felt; - let calldata_and_signature_gas_cost = - (gas_per_data_felt * u128_from_usize(calldata_length + signature_length)).to_integer(); + let calldata_and_signature_gas_cost = (gas_per_data_felt + * u128_from_usize(calldata_length + signature_length)) + .to_integer() + .into(); let manual_starknet_gas_usage_vector = match gas_vector_computation_mode { GasVectorComputationMode::NoL2Gas => { GasVector::from_l1_gas(calldata_and_signature_gas_cost) @@ -162,7 +167,8 @@ fn test_calculate_tx_gas_usage_basic<'a>( let message_segment_length = get_message_segment_length(&[], Some(l1_handler_payload_size)); let calldata_and_signature_gas_cost = (gas_per_data_felt * u128_from_usize(l1_handler_payload_size + signature_length)) - .to_integer(); + .to_integer() + .into(); let calldata_and_signature_gas_cost_vector = match gas_vector_computation_mode { GasVectorComputationMode::NoL2Gas => { GasVector::from_l1_gas(calldata_and_signature_gas_cost) @@ -173,16 +179,17 @@ fn test_calculate_tx_gas_usage_basic<'a>( * eth_gas_constants::GAS_PER_MEMORY_WORD + eth_gas_constants::GAS_PER_COUNTER_DECREASE + usize_from_u128( - get_consumed_message_to_l2_emissions_cost(Some(l1_handler_payload_size)).l1_gas, + get_consumed_message_to_l2_emissions_cost(Some(l1_handler_payload_size)).l1_gas.0, ) .unwrap(); let manual_starknet_l1_gas_usage_vector = - GasVector::from_l1_gas(u128_from_usize(manual_starknet_l1_gas_usage)); + GasVector::from_l1_gas(u128_from_usize(manual_starknet_l1_gas_usage).into()); let manual_sharp_gas_usage = message_segment_length * eth_gas_constants::SHARP_GAS_PER_MEMORY_WORD; - let manual_gas_computation = GasVector::from_l1_gas(u128_from_usize(manual_sharp_gas_usage)) - + manual_starknet_l1_gas_usage_vector - + calldata_and_signature_gas_cost_vector; + let manual_gas_computation = + GasVector::from_l1_gas(u128_from_usize(manual_sharp_gas_usage).into()) + + manual_starknet_l1_gas_usage_vector + + calldata_and_signature_gas_cost_vector; assert_eq!(l1_handler_gas_usage_vector, manual_gas_computation); // Any transaction with L2-to-L1 messages. @@ -239,16 +246,16 @@ fn test_calculate_tx_gas_usage_basic<'a>( let n_l2_to_l1_messages = l2_to_l1_payload_lengths.len(); let manual_starknet_gas_usage = message_segment_length * eth_gas_constants::GAS_PER_MEMORY_WORD + n_l2_to_l1_messages * eth_gas_constants::GAS_PER_ZERO_TO_NONZERO_STORAGE_SET - + usize_from_u128(get_log_message_to_l1_emissions_cost(&l2_to_l1_payload_lengths).l1_gas) + + usize_from_u128(get_log_message_to_l1_emissions_cost(&l2_to_l1_payload_lengths).l1_gas.0) .unwrap(); let manual_sharp_gas_usage = message_segment_length * eth_gas_constants::SHARP_GAS_PER_MEMORY_WORD - + usize_from_u128(l2_to_l1_starknet_resources.state.to_gas_vector(use_kzg_da).l1_gas) + + usize_from_u128(l2_to_l1_starknet_resources.state.to_gas_vector(use_kzg_da).l1_gas.0) .unwrap(); let manual_sharp_blob_gas_usage = l2_to_l1_starknet_resources.state.to_gas_vector(use_kzg_da).l1_data_gas; let manual_gas_computation = GasVector { - l1_gas: u128_from_usize(manual_starknet_gas_usage + manual_sharp_gas_usage), + l1_gas: u128_from_usize(manual_starknet_gas_usage + manual_sharp_gas_usage).into(), l1_data_gas: manual_sharp_blob_gas_usage, ..Default::default() }; @@ -323,7 +330,7 @@ fn test_calculate_tx_gas_usage_basic<'a>( + storage_writings_gas_usage_vector.l1_gas // l2_to_l1_messages_gas_usage and storage_writings_gas_usage got a discount each, while // the combined calculation got it once. - + u128_from_usize(fee_balance_discount), + + u128_from_usize(fee_balance_discount).into(), // Expected blob gas usage is from data availability only. l1_data_gas: combined_cases_starknet_resources.state.to_gas_vector(use_kzg_da).l1_data_gas, l2_gas: l1_handler_gas_usage_vector.l2_gas, diff --git a/crates/blockifier/src/fee/resources.rs b/crates/blockifier/src/fee/resources.rs index 3d9fb138a7..f6d99bb607 100644 --- a/crates/blockifier/src/fee/resources.rs +++ b/crates/blockifier/src/fee/resources.rs @@ -1,6 +1,7 @@ use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use serde::Serialize; use starknet_api::core::ContractAddress; +use starknet_api::execution_resources::GasAmount; use starknet_api::transaction::{Fee, GasVectorComputationMode}; use crate::context::TransactionContext; @@ -199,24 +200,26 @@ impl ArchivalDataResources { fn get_calldata_and_signature_gas_cost( &self, archival_gas_costs: &ArchivalDataGasCosts, - ) -> u128 { + ) -> GasAmount { // TODO(Avi, 20/2/2024): Calculate the number of bytes instead of the number of felts. let total_data_size = u128_from_usize(self.calldata_length + self.signature_length); - (archival_gas_costs.gas_per_data_felt * total_data_size).to_integer() + GasAmount((archival_gas_costs.gas_per_data_felt * total_data_size).to_integer()) } /// Returns the cost of declared class codes in L1/L2 gas units, depending on the mode. - fn get_code_gas_cost(&self, archival_gas_costs: &ArchivalDataGasCosts) -> u128 { - (archival_gas_costs.gas_per_code_byte * u128_from_usize(self.code_size)).to_integer() + fn get_code_gas_cost(&self, archival_gas_costs: &ArchivalDataGasCosts) -> GasAmount { + (archival_gas_costs.gas_per_code_byte * u128_from_usize(self.code_size)).to_integer().into() } /// Returns the cost of the transaction's emmited events in L1/L2 gas units, depending on the /// mode. - fn get_events_gas_cost(&self, archival_gas_costs: &ArchivalDataGasCosts) -> u128 { - (archival_gas_costs.gas_per_data_felt - * (archival_gas_costs.event_key_factor * self.event_summary.total_event_keys - + self.event_summary.total_event_data_size)) - .to_integer() + fn get_events_gas_cost(&self, archival_gas_costs: &ArchivalDataGasCosts) -> GasAmount { + GasAmount( + (archival_gas_costs.gas_per_data_felt + * (archival_gas_costs.event_key_factor * self.event_summary.total_event_keys + + self.event_summary.total_event_data_size)) + .to_integer(), + ) } } @@ -242,9 +245,12 @@ impl MessageResources { /// both Starknet and SHARP contracts. pub fn to_gas_vector(&self) -> GasVector { let starknet_gas_usage = self.get_starknet_gas_cost(); - let sharp_gas_usage = GasVector::from_l1_gas(u128_from_usize( - self.message_segment_length * eth_gas_constants::SHARP_GAS_PER_MEMORY_WORD, - )); + let sharp_gas_usage = GasVector::from_l1_gas( + u128_from_usize( + self.message_segment_length * eth_gas_constants::SHARP_GAS_PER_MEMORY_WORD, + ) + .into(), + ); starknet_gas_usage + sharp_gas_usage } @@ -266,7 +272,8 @@ impl MessageResources { // message but we ignore it since refunded gas cannot be used for the current // transaction execution). + n_l1_to_l2_messages * eth_gas_constants::GAS_PER_COUNTER_DECREASE, - ), + ) + .into(), ) + get_consumed_message_to_l2_emissions_cost(self.l1_handler_payload_size) + get_log_message_to_l1_emissions_cost(&self.l2_to_l1_payload_lengths) } @@ -286,27 +293,27 @@ impl MessageResources { Serialize, )] pub struct GasVector { - pub l1_gas: u128, - pub l1_data_gas: u128, - pub l2_gas: u128, + pub l1_gas: GasAmount, + pub l1_data_gas: GasAmount, + pub l2_gas: GasAmount, } impl GasVector { - pub fn from_l1_gas(l1_gas: u128) -> Self { + pub fn from_l1_gas(l1_gas: GasAmount) -> Self { Self { l1_gas, ..Default::default() } } - pub fn from_l1_data_gas(l1_data_gas: u128) -> Self { + pub fn from_l1_data_gas(l1_data_gas: GasAmount) -> Self { Self { l1_data_gas, ..Default::default() } } - pub fn from_l2_gas(l2_gas: u128) -> Self { + pub fn from_l2_gas(l2_gas: GasAmount) -> Self { Self { l2_gas, ..Default::default() } } /// Computes the cost (in fee token units) of the gas vector (saturating on overflow). pub fn saturated_cost(&self, gas_price: u128, blob_gas_price: u128) -> Fee { - let l1_gas_cost = self.l1_gas.checked_mul(gas_price).unwrap_or_else(|| { + let l1_gas_cost = self.l1_gas.0.checked_mul(gas_price).unwrap_or_else(|| { log::warn!( "L1 gas cost overflowed: multiplication of {} by {} resulted in overflow.", self.l1_gas, @@ -314,14 +321,15 @@ impl GasVector { ); u128::MAX }); - let l1_data_gas_cost = self.l1_data_gas.checked_mul(blob_gas_price).unwrap_or_else(|| { - log::warn!( - "L1 blob gas cost overflowed: multiplication of {} by {} resulted in overflow.", - self.l1_data_gas, - blob_gas_price - ); - u128::MAX - }); + let l1_data_gas_cost = + self.l1_data_gas.0.checked_mul(blob_gas_price).unwrap_or_else(|| { + log::warn!( + "L1 blob gas cost overflowed: multiplication of {} by {} resulted in overflow.", + self.l1_data_gas, + blob_gas_price + ); + u128::MAX + }); let total = l1_gas_cost.checked_add(l1_data_gas_cost).unwrap_or_else(|| { log::warn!( "Total gas cost overflowed: addition of {} and {} resulted in overflow.", @@ -342,11 +350,12 @@ impl GasVector { /// summand, we get total_gas = (X + Y * DGP / GP). /// If this function is called with kzg_flag==false, then l1_data_gas==0, and this dicount /// function does nothing. - pub fn to_discounted_l1_gas(&self, tx_context: &TransactionContext) -> u128 { + pub fn to_discounted_l1_gas(&self, tx_context: &TransactionContext) -> GasAmount { let gas_prices = &tx_context.block_context.block_info.gas_prices; let fee_type = tx_context.tx_info.fee_type(); let gas_price = gas_prices.get_l1_gas_price_by_fee_type(&fee_type); let data_gas_price = gas_prices.get_l1_data_gas_price_by_fee_type(&fee_type); - self.l1_gas + u128_div_ceil(self.l1_data_gas * u128::from(data_gas_price), gas_price) + self.l1_gas + + u128_div_ceil(self.l1_data_gas.0 * u128::from(data_gas_price), gas_price).into() } } diff --git a/crates/blockifier/src/test_utils.rs b/crates/blockifier/src/test_utils.rs index 5b72bfd2af..684d0f8968 100644 --- a/crates/blockifier/src/test_utils.rs +++ b/crates/blockifier/src/test_utils.rs @@ -14,6 +14,7 @@ use std::path::PathBuf; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; use starknet_api::core::{ClassHash, ContractAddress, PatriciaKey}; +use starknet_api::execution_resources::GasAmount; use starknet_api::state::StorageKey; use starknet_api::transaction::{ Calldata, @@ -94,10 +95,10 @@ pub fn test_erc20_sequencer_balance_key() -> StorageKey { // The max_fee / resource bounds used for txs in this test. pub const MAX_L1_GAS_AMOUNT: u64 = 1000000; #[allow(clippy::as_conversions)] -pub const MAX_L1_GAS_AMOUNT_U128: u128 = MAX_L1_GAS_AMOUNT as u128; +pub const MAX_L1_GAS_AMOUNT_U128: GasAmount = GasAmount(MAX_L1_GAS_AMOUNT as u128); pub const MAX_L1_GAS_PRICE: u128 = DEFAULT_STRK_L1_GAS_PRICE; -pub const MAX_RESOURCE_COMMITMENT: u128 = MAX_L1_GAS_AMOUNT_U128 * MAX_L1_GAS_PRICE; -pub const MAX_FEE: u128 = MAX_L1_GAS_AMOUNT_U128 * DEFAULT_ETH_L1_GAS_PRICE; +pub const MAX_RESOURCE_COMMITMENT: u128 = MAX_L1_GAS_AMOUNT_U128.0 * MAX_L1_GAS_PRICE; +pub const MAX_FEE: u128 = MAX_L1_GAS_AMOUNT_U128.0 * DEFAULT_ETH_L1_GAS_PRICE; // The amount of test-token allocated to the account in this test, set to a multiple of the max // amount deprecated / non-deprecated transactions commit to paying. @@ -390,7 +391,7 @@ pub fn update_json_value(base: &mut serde_json::Value, update: serde_json::Value } pub fn gas_vector_from_vm_usage( - vm_usage_in_l1_gas: u128, + vm_usage_in_l1_gas: GasAmount, computation_mode: &GasVectorComputationMode, versioned_constants: &VersionedConstants, ) -> GasVector { diff --git a/crates/blockifier/src/transaction/account_transaction.rs b/crates/blockifier/src/transaction/account_transaction.rs index 960a05856a..5974ee2190 100644 --- a/crates/blockifier/src/transaction/account_transaction.rs +++ b/crates/blockifier/src/transaction/account_transaction.rs @@ -359,13 +359,10 @@ impl AccountTransaction { { // TODO(Aner): refactor to indicate both amount and price are too low. // TODO(Aner): refactor to return all amounts that are too low. - let minimal_gas_amount = minimal_gas_amount.try_into() - // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion works. - .expect("Failed to convert u128 to u64."); - if resource_bounds.max_amount < minimal_gas_amount { + if minimal_gas_amount > resource_bounds.max_amount.into() { return Err(TransactionFeeError::MaxGasAmountTooLow { resource, - max_gas_amount: resource_bounds.max_amount, + max_gas_amount: resource_bounds.max_amount.into(), minimal_gas_amount, })?; } diff --git a/crates/blockifier/src/transaction/account_transactions_test.rs b/crates/blockifier/src/transaction/account_transactions_test.rs index fd1222bd5d..3134d36798 100644 --- a/crates/blockifier/src/transaction/account_transactions_test.rs +++ b/crates/blockifier/src/transaction/account_transactions_test.rs @@ -6,6 +6,7 @@ use cairo_vm::vm::runners::cairo_runner::ResourceTracker; use pretty_assertions::assert_eq; use rstest::rstest; use starknet_api::core::{calculate_contract_address, ClassHash, ContractAddress, PatriciaKey}; +use starknet_api::execution_resources::GasAmount; use starknet_api::hash::StarkHash; use starknet_api::state::StorageKey; use starknet_api::test_utils::invoke::InvokeTxArgs; @@ -60,7 +61,6 @@ use crate::test_utils::{ create_trivial_calldata, get_syscall_resources, get_tx_resources, - u64_from_usize, CairoVersion, BALANCE, DEFAULT_STRK_L1_GAS_PRICE, @@ -86,6 +86,7 @@ use crate::transaction::test_utils::{ }; use crate::transaction::transaction_types::TransactionType; use crate::transaction::transactions::{DeclareTransaction, ExecutableTransaction, ExecutionFlags}; +use crate::utils::u128_from_usize; #[rstest] fn test_circuit(block_context: BlockContext, max_l1_resource_bounds: ValidResourceBounds) { @@ -170,7 +171,7 @@ fn test_fee_enforcement( deploy_account_tx_args! { class_hash: account.get_class_hash(), max_fee: Fee(u128::from(!zero_bounds)), - resource_bounds: l1_resource_bounds(u64::from(!zero_bounds), DEFAULT_STRK_L1_GAS_PRICE), + resource_bounds: l1_resource_bounds(u8::from(!zero_bounds).into(), DEFAULT_STRK_L1_GAS_PRICE), version, }, &mut NonceManager::default(), @@ -245,7 +246,7 @@ fn test_enforce_fee_false_works(block_context: BlockContext, #[case] version: Tr &block_context, invoke_tx_args! { max_fee: Fee(0), - resource_bounds: l1_resource_bounds(0, DEFAULT_STRK_L1_GAS_PRICE), + resource_bounds: l1_resource_bounds(GasAmount(0), DEFAULT_STRK_L1_GAS_PRICE), sender_address: account_address, calldata: create_trivial_calldata(contract_address), version, @@ -486,7 +487,7 @@ fn test_max_fee_limit_validate( // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion // works. resource_bounds: l1_resource_bounds( - estimated_min_l1_gas.try_into().expect("Failed to convert u128 to u64."), + estimated_min_l1_gas, block_info.gas_prices.get_l1_gas_price_by_fee_type(&account_tx.fee_type()).into() ), ..tx_args @@ -964,13 +965,13 @@ fn test_max_fee_to_max_steps_conversion( ) { let TestInitData { mut state, account_address, contract_address, mut nonce_manager } = create_test_init_data(&block_context.chain_info, CairoVersion::Cairo0); - let actual_gas_used: u64 = u64_from_usize( + let actual_gas_used: GasAmount = u128_from_usize( get_syscall_resources(SyscallSelector::CallContract).n_steps + get_tx_resources(TransactionType::InvokeFunction).n_steps + 1751, - ); - let actual_gas_used_as_u128: u128 = actual_gas_used.into(); - let actual_fee = actual_gas_used_as_u128 * 100000000000; + ) + .into(); + let actual_fee = actual_gas_used.0 * 100000000000; let actual_strk_gas_price = block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&FeeType::Strk); let execute_calldata = create_calldata( @@ -1005,7 +1006,8 @@ fn test_max_fee_to_max_steps_conversion( sender_address: account_address, calldata: execute_calldata, version, - resource_bounds: l1_resource_bounds(2 * actual_gas_used, actual_strk_gas_price.into()), + resource_bounds: + l1_resource_bounds((2 * actual_gas_used.0).into(), actual_strk_gas_price.into()), nonce: nonce_manager.next(account_address), }); let tx_context2 = Arc::new(block_context.to_tx_context(&account_tx2)); @@ -1024,10 +1026,7 @@ fn test_max_fee_to_max_steps_conversion( assert_eq!(tx_execution_info1.receipt.fee.0, tx_execution_info2.receipt.fee.0); // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion works. // TODO(Aner, 21/01/24): verify test compliant with 4844 (or modify accordingly). - assert_eq!( - actual_gas_used, - u64::try_from(gas_used_vector2.l1_gas).expect("Failed to convert u128 to u64.") - ); + assert_eq!(actual_gas_used, gas_used_vector2.l1_gas); assert_eq!(actual_fee, tx_execution_info2.receipt.fee.0); assert_eq!(n_steps1, n_steps2); assert_eq!(gas_used_vector1, gas_used_vector2); @@ -1064,7 +1063,7 @@ fn test_insufficient_max_fee_reverts( let gas_price = u128::from( block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&FeeType::Strk), ); - let gas_ammount = u64::try_from(actual_fee_depth1.0 / gas_price).unwrap(); + let gas_ammount = GasAmount(actual_fee_depth1.0 / gas_price); // Invoke the `recurse` function with depth of 2 and the actual fee of depth 1 as max_fee. // This call should fail due to insufficient max fee (steps bound based on max_fee is not so diff --git a/crates/blockifier/src/transaction/errors.rs b/crates/blockifier/src/transaction/errors.rs index b1454329a1..ae0c85cf54 100644 --- a/crates/blockifier/src/transaction/errors.rs +++ b/crates/blockifier/src/transaction/errors.rs @@ -1,6 +1,7 @@ use cairo_vm::types::errors::program_errors::ProgramError; use num_bigint::BigUint; use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector, Nonce}; +use starknet_api::execution_resources::GasAmount; use starknet_api::transaction::{Fee, Resource, TransactionVersion}; use starknet_api::StarknetApiError; use starknet_types_core::felt::FromStrError; @@ -62,7 +63,11 @@ pub enum TransactionFeeError { "Max {resource} amount ({max_gas_amount}) is lower than the minimal gas amount: \ {minimal_gas_amount}." )] - MaxGasAmountTooLow { resource: Resource, max_gas_amount: u64, minimal_gas_amount: u64 }, + MaxGasAmountTooLow { + resource: Resource, + max_gas_amount: GasAmount, + minimal_gas_amount: GasAmount, + }, #[error("Missing L1 gas bounds in resource bounds.")] MissingL1GasBounds, #[error(transparent)] diff --git a/crates/blockifier/src/transaction/execution_flavors_test.rs b/crates/blockifier/src/transaction/execution_flavors_test.rs index 3909ca2156..1e8d63eef9 100644 --- a/crates/blockifier/src/transaction/execution_flavors_test.rs +++ b/crates/blockifier/src/transaction/execution_flavors_test.rs @@ -2,6 +2,7 @@ use assert_matches::assert_matches; use pretty_assertions::assert_eq; use rstest::rstest; use starknet_api::core::ContractAddress; +use starknet_api::execution_resources::GasAmount; use starknet_api::test_utils::invoke::InvokeTxArgs; use starknet_api::test_utils::NonceManager; use starknet_api::transaction::{ @@ -30,7 +31,6 @@ use crate::test_utils::{ create_trivial_calldata, get_syscall_resources, get_tx_resources, - u64_from_usize, CairoVersion, BALANCE, MAX_FEE, @@ -51,7 +51,8 @@ use crate::transaction::test_utils::{ }; use crate::transaction::transaction_types::TransactionType; use crate::transaction::transactions::ExecutableTransaction; -const VALIDATE_GAS_OVERHEAD: u64 = 21; +use crate::utils::u128_from_usize; +const VALIDATE_GAS_OVERHEAD: GasAmount = GasAmount(21); struct FlavorTestInitialState { pub state: CachedState, @@ -105,14 +106,18 @@ fn check_balance( /// Returns the amount of L1 gas and derived fee, given base gas amount and a boolean indicating /// if validation is to be done. -fn gas_and_fee(base_gas: u64, add_validation_overhead: bool, fee_type: &FeeType) -> (u64, Fee) { +fn gas_and_fee( + base_gas: GasAmount, + add_validation_overhead: bool, + fee_type: &FeeType, +) -> (GasAmount, Fee) { // Validation incurs a constant gas overhead. - let gas = base_gas + if add_validation_overhead { VALIDATE_GAS_OVERHEAD } else { 0 }; + let gas = base_gas + if add_validation_overhead { VALIDATE_GAS_OVERHEAD } else { GasAmount(0) }; ( gas, get_fee_by_gas_vector( &BlockContext::create_for_account_testing().block_info, - GasVector::from_l1_gas(gas.into()), + GasVector::from_l1_gas(gas), fee_type, ), ) @@ -124,17 +129,20 @@ fn calculate_actual_gas( tx_execution_info: &TransactionExecutionInfo, block_context: &BlockContext, remove_validation_overhead: bool, -) -> u128 { - tx_execution_info - .receipt - .resources - .to_gas_vector( - &block_context.versioned_constants, - block_context.block_info.use_kzg_da, - &GasVectorComputationMode::NoL2Gas, - ) - .l1_gas - - if remove_validation_overhead { VALIDATE_GAS_OVERHEAD.into() } else { 0 } +) -> GasAmount { + GasAmount( + tx_execution_info + .receipt + .resources + .to_gas_vector( + &block_context.versioned_constants, + block_context.block_info.use_kzg_da, + &GasVectorComputationMode::NoL2Gas, + ) + .l1_gas + .0 + - if remove_validation_overhead { VALIDATE_GAS_OVERHEAD.0 } else { 0 }, + ) } /// Asserts gas used and reported fee are as expected. @@ -143,14 +151,11 @@ fn check_gas_and_fee( block_context: &BlockContext, tx_execution_info: &TransactionExecutionInfo, fee_type: &FeeType, - expected_actual_gas: u64, + expected_actual_gas: GasAmount, expected_actual_fee: Fee, expected_cost_of_resources: Fee, ) { - assert_eq!( - calculate_actual_gas(tx_execution_info, block_context, false), - expected_actual_gas.into() - ); + assert_eq!(calculate_actual_gas(tx_execution_info, block_context, false), expected_actual_gas); assert_eq!(tx_execution_info.receipt.fee, expected_actual_fee); // Future compatibility: resources other than the L1 gas usage may affect the fee (currently, @@ -179,7 +184,7 @@ fn get_pre_validate_test_args( let max_fee = Fee(MAX_FEE); // The max resource bounds fixture is not used here because this function already has the // maximum number of arguments. - let resource_bounds = l1_resource_bounds(MAX_L1_GAS_AMOUNT, MAX_L1_GAS_PRICE); + let resource_bounds = l1_resource_bounds(MAX_L1_GAS_AMOUNT.into(), MAX_L1_GAS_PRICE); let FlavorTestInitialState { state, account_address, test_contract_address, nonce_manager, .. } = create_flavors_test_state(&block_context.chain_info, cairo_version); @@ -253,7 +258,7 @@ fn test_simulate_validate_pre_validate_with_charge_fee( // First scenario: minimal fee not covered. Actual fee is precomputed. let err = account_invoke_tx(invoke_tx_args! { max_fee: Fee(10), - resource_bounds: l1_resource_bounds(10, 10), + resource_bounds: l1_resource_bounds(GasAmount(10), 10), nonce: nonce_manager.next(account_address), ..pre_validation_base_args.clone() }) @@ -287,7 +292,7 @@ fn test_simulate_validate_pre_validate_with_charge_fee( (BALANCE / gas_price).try_into().expect("Failed to convert u128 to u64."); let result = account_invoke_tx(invoke_tx_args! { max_fee: Fee(BALANCE + 1), - resource_bounds: l1_resource_bounds(balance_over_gas_price + 10, gas_price.into()), + resource_bounds: l1_resource_bounds(u128::from(balance_over_gas_price + 10).into(), gas_price.into()), nonce: nonce_manager.next(account_address), ..pre_validation_base_args.clone() }) @@ -318,7 +323,7 @@ fn test_simulate_validate_pre_validate_with_charge_fee( // Third scenario: L1 gas price bound lower than the price on the block. if !is_deprecated { let err = account_invoke_tx(invoke_tx_args! { - resource_bounds: l1_resource_bounds(MAX_L1_GAS_AMOUNT, u128::from(gas_price) - 1), + resource_bounds: l1_resource_bounds(MAX_L1_GAS_AMOUNT.into(), u128::from(gas_price) - 1), nonce: nonce_manager.next(account_address), ..pre_validation_base_args }) @@ -362,14 +367,14 @@ fn test_simulate_validate_pre_validate_not_charge_fee( }) .execute(&mut state, &block_context, charge_fee, false) .unwrap(); - let base_gas = - calculate_actual_gas(&tx_execution_info, &block_context, false).try_into().unwrap(); + let base_gas = calculate_actual_gas(&tx_execution_info, &block_context, false); assert!( base_gas - > u64_from_usize( + > u128_from_usize( get_syscall_resources(SyscallSelector::CallContract).n_steps + get_tx_resources(TransactionType::InvokeFunction).n_steps ) + .into() ); let (actual_gas_used, actual_fee) = gas_and_fee(base_gas, validate, &fee_type); @@ -395,7 +400,7 @@ fn test_simulate_validate_pre_validate_not_charge_fee( } // First scenario: minimal fee not covered. Actual fee is precomputed. - execute_and_check_gas_and_fee!(Fee(10), l1_resource_bounds(10, 10)); + execute_and_check_gas_and_fee!(Fee(10), l1_resource_bounds(GasAmount(10), 10)); // Second scenario: resource bounds greater than balance. let gas_price = block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&fee_type); @@ -403,14 +408,14 @@ fn test_simulate_validate_pre_validate_not_charge_fee( (BALANCE / gas_price).try_into().expect("Failed to convert u128 to u64."); execute_and_check_gas_and_fee!( Fee(BALANCE + 1), - l1_resource_bounds(balance_over_gas_price + 10, gas_price.into()) + l1_resource_bounds(u128::from(balance_over_gas_price + 10).into(), gas_price.into()) ); // Third scenario: L1 gas price bound lower than the price on the block. if !is_deprecated { execute_and_check_gas_and_fee!( pre_validation_base_args.max_fee, - l1_resource_bounds(MAX_L1_GAS_AMOUNT, u128::from(gas_price) - 1) + l1_resource_bounds(MAX_L1_GAS_AMOUNT.into(), u128::from(gas_price) - 1) ); } } @@ -505,9 +510,11 @@ fn test_simulate_charge_fee_no_validation_fail_validate( // Validation scenario: fallible validation. let block_context = BlockContext::create_for_account_testing(); - let base_gas = - calculate_actual_gas(&tx_execution_info, &block_context, validate).try_into().unwrap(); - assert!(base_gas > u64_from_usize(get_tx_resources(TransactionType::InvokeFunction).n_steps)); + let base_gas = calculate_actual_gas(&tx_execution_info, &block_context, validate); + assert!( + base_gas + > u128_from_usize(get_tx_resources(TransactionType::InvokeFunction).n_steps).into() + ); let (actual_gas_used, actual_fee) = gas_and_fee(base_gas, validate, &fee_type); // The reported fee should be the actual cost, regardless of whether or not fee is charged. @@ -571,10 +578,12 @@ fn test_simulate_validate_charge_fee_mid_execution( }) .execute(&mut state, &block_context, charge_fee, validate) .unwrap(); - let base_gas: u64 = - calculate_actual_gas(&tx_execution_info, &block_context, validate).try_into().unwrap(); + let base_gas = calculate_actual_gas(&tx_execution_info, &block_context, validate); let (revert_gas_used, revert_fee) = gas_and_fee(base_gas, validate, &fee_type); - assert!(base_gas > u64_from_usize(get_tx_resources(TransactionType::InvokeFunction).n_steps)); + assert!( + base_gas + > u128_from_usize(get_tx_resources(TransactionType::InvokeFunction).n_steps).into() + ); assert!(tx_execution_info.is_reverted()); check_gas_and_fee( &block_context, @@ -595,16 +604,17 @@ fn test_simulate_validate_charge_fee_mid_execution( // Second scenario: limit resources via sender bounds. Should revert if and only if step limit // is derived from sender bounds (`charge_fee` mode). - let (gas_bound, fee_bound) = gas_and_fee(6111, validate, &fee_type); + let (gas_bound, fee_bound) = gas_and_fee(GasAmount(6111), validate, &fee_type); // If `charge_fee` is true, execution is limited by sender bounds, so less resources will be // used. Otherwise, execution is limited by block bounds, so more resources will be used. - let (limited_gas_used, limited_fee) = gas_and_fee(7763, validate, &fee_type); + let (limited_gas_used, limited_fee) = gas_and_fee(GasAmount(7763), validate, &fee_type); let (unlimited_gas_used, unlimited_fee) = gas_and_fee( - u64_from_usize( + u128_from_usize( get_syscall_resources(SyscallSelector::CallContract).n_steps + get_tx_resources(TransactionType::InvokeFunction).n_steps + 5730, - ), + ) + .into(), validate, &fee_type, ); @@ -642,16 +652,16 @@ fn test_simulate_validate_charge_fee_mid_execution( // whether or not `charge_fee` is true. let mut low_step_block_context = block_context.clone(); low_step_block_context.versioned_constants.invoke_tx_max_n_steps = 10000; - let (huge_gas_limit, huge_fee) = gas_and_fee(100000, validate, &fee_type); + let (huge_gas_limit, huge_fee) = gas_and_fee(GasAmount(100000), validate, &fee_type); // Gas usage does not depend on `validate` flag in this scenario, because we reach the block // step limit during execution anyway. The actual limit when execution phase starts is slightly // lower when `validate` is true, but this is not reflected in the actual gas usage. let invoke_tx_max_n_steps_as_u64: u64 = low_step_block_context.versioned_constants.invoke_tx_max_n_steps.into(); - let block_limit_gas = invoke_tx_max_n_steps_as_u64 + 1652; + let block_limit_gas = u128::from(invoke_tx_max_n_steps_as_u64 + 1652).into(); let block_limit_fee = get_fee_by_gas_vector( &block_context.block_info, - GasVector::from_l1_gas(block_limit_gas.into()), + GasVector::from_l1_gas(block_limit_gas), &fee_type, ); let tx_execution_info = account_invoke_tx(invoke_tx_args! { @@ -716,22 +726,23 @@ fn test_simulate_validate_charge_fee_post_execution( // If `charge_fee` is false - we do not revert, and simply report the fee and resources as used. // If `charge_fee` is true, we revert, charge the maximal allowed fee (derived from sender // bounds), and report resources base on execution steps reverted + other overhead. - let base_gas_bound = 8010; + let base_gas_bound = GasAmount(8010); let (just_not_enough_gas_bound, just_not_enough_fee_bound) = gas_and_fee(base_gas_bound, validate, &fee_type); // `__validate__` and overhead resources + number of reverted steps, comes out slightly more // than the gas bound. let (revert_gas_usage, revert_fee) = gas_and_fee( - u64_from_usize(get_tx_resources(TransactionType::InvokeFunction).n_steps) + 5730, + (u128_from_usize(get_tx_resources(TransactionType::InvokeFunction).n_steps) + 5730).into(), validate, &fee_type, ); let (unlimited_gas_used, unlimited_fee) = gas_and_fee( - u64_from_usize( + u128_from_usize( get_syscall_resources(SyscallSelector::CallContract).n_steps + get_tx_resources(TransactionType::InvokeFunction).n_steps + 5730, - ), + ) + .into(), validate, &fee_type, ); @@ -771,16 +782,17 @@ fn test_simulate_validate_charge_fee_post_execution( // Second scenario: balance too low. // Execute a transfer, and make sure we get the expected result. let (success_actual_gas, actual_fee) = gas_and_fee( - u64_from_usize( + u128_from_usize( get_syscall_resources(SyscallSelector::CallContract).n_steps + get_tx_resources(TransactionType::InvokeFunction).n_steps + 4260, - ), + ) + .into(), validate, &fee_type, ); let (fail_actual_gas, fail_actual_fee) = gas_and_fee( - u64_from_usize(get_tx_resources(TransactionType::InvokeFunction).n_steps + 2252), + u128_from_usize(get_tx_resources(TransactionType::InvokeFunction).n_steps + 2252).into(), validate, &fee_type, ); diff --git a/crates/blockifier/src/transaction/post_execution_test.rs b/crates/blockifier/src/transaction/post_execution_test.rs index 8f95fc6ccb..6348900782 100644 --- a/crates/blockifier/src/transaction/post_execution_test.rs +++ b/crates/blockifier/src/transaction/post_execution_test.rs @@ -1,6 +1,7 @@ use assert_matches::assert_matches; use rstest::rstest; use starknet_api::core::{ContractAddress, PatriciaKey}; +use starknet_api::execution_resources::GasAmount; use starknet_api::state::StorageKey; use starknet_api::transaction::{ Calldata, @@ -259,7 +260,7 @@ fn test_revert_on_resource_overuse( assert_eq!(execution_info_measure.revert_error, None); let actual_fee = execution_info_measure.receipt.fee; // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion works. - let actual_gas_usage: u64 = execution_info_measure + let actual_gas_usage = execution_info_measure .receipt .resources .to_gas_vector( @@ -267,9 +268,7 @@ fn test_revert_on_resource_overuse( block_context.block_info.use_kzg_da, &GasVectorComputationMode::NoL2Gas, ) - .l1_gas - .try_into() - .expect("Failed to convert u128 to u64."); + .l1_gas; // Run the same function, with a different written value (to keep cost high), with the actual // resources used as upper bounds. Make sure execution does not revert. @@ -297,7 +296,7 @@ fn test_revert_on_resource_overuse( &block_context, invoke_tx_args! { max_fee: low_max_fee, - resource_bounds: l1_resource_bounds(actual_gas_usage - 1, MAX_L1_GAS_PRICE), + resource_bounds: l1_resource_bounds(GasAmount(actual_gas_usage.0 - 1), MAX_L1_GAS_PRICE), nonce: nonce_manager.next(account_address), calldata: write_a_lot_calldata(), ..base_args diff --git a/crates/blockifier/src/transaction/test_utils.rs b/crates/blockifier/src/transaction/test_utils.rs index fabe9324c0..b467c0c6e8 100644 --- a/crates/blockifier/src/transaction/test_utils.rs +++ b/crates/blockifier/src/transaction/test_utils.rs @@ -1,5 +1,6 @@ use rstest::fixture; use starknet_api::core::{ClassHash, ContractAddress, Nonce}; +use starknet_api::execution_resources::GasAmount; use starknet_api::test_utils::deploy_account::DeployAccountTxArgs; use starknet_api::test_utils::invoke::InvokeTxArgs; use starknet_api::test_utils::NonceManager; @@ -97,7 +98,7 @@ pub fn max_l1_resource_bounds() -> ValidResourceBounds { pub fn create_resource_bounds(computation_mode: &GasVectorComputationMode) -> ValidResourceBounds { match computation_mode { GasVectorComputationMode::NoL2Gas => { - l1_resource_bounds(MAX_L1_GAS_AMOUNT, MAX_L1_GAS_PRICE) + l1_resource_bounds(MAX_L1_GAS_AMOUNT.into(), MAX_L1_GAS_PRICE) } GasVectorComputationMode::All => create_all_resource_bounds( MAX_L1_GAS_AMOUNT, @@ -321,8 +322,11 @@ pub fn run_invoke_tx( /// Creates a `ResourceBoundsMapping` with the given `max_amount` and `max_price` for L1 gas limits. /// No guarantees on the values of the other resources bounds. -pub fn l1_resource_bounds(max_amount: u64, max_price: u128) -> ValidResourceBounds { - ValidResourceBounds::L1Gas(ResourceBounds { max_amount, max_price_per_unit: max_price }) +pub fn l1_resource_bounds(max_amount: GasAmount, max_price: u128) -> ValidResourceBounds { + ValidResourceBounds::L1Gas(ResourceBounds { + max_amount: max_amount.0.try_into().unwrap(), + max_price_per_unit: max_price, + }) } #[fixture] diff --git a/crates/blockifier/src/transaction/transactions_test.rs b/crates/blockifier/src/transaction/transactions_test.rs index c501610558..6e0c5d139b 100644 --- a/crates/blockifier/src/transaction/transactions_test.rs +++ b/crates/blockifier/src/transaction/transactions_test.rs @@ -10,6 +10,7 @@ use pretty_assertions::assert_eq; use rstest::{fixture, rstest}; use starknet_api::core::{ChainId, ClassHash, ContractAddress, EthAddress, Nonce, PatriciaKey}; use starknet_api::deprecated_contract_class::EntryPointType; +use starknet_api::execution_resources::GasAmount; use starknet_api::state::StorageKey; use starknet_api::test_utils::invoke::InvokeTxArgs; use starknet_api::test_utils::NonceManager; @@ -874,10 +875,13 @@ fn test_estimate_minimal_gas_vector( let minimal_l2_gas = minimal_gas_vector.l2_gas; let minimal_l1_data_gas = minimal_gas_vector.l1_data_gas; if gas_vector_computation_mode == GasVectorComputationMode::NoL2Gas || !use_kzg_da { - assert!(minimal_l1_gas > 0); + assert!(minimal_l1_gas > GasAmount(0)); } - assert_eq!(minimal_l2_gas > 0, gas_vector_computation_mode == GasVectorComputationMode::All); - assert_eq!(minimal_l1_data_gas > 0, use_kzg_da); + assert_eq!( + minimal_l2_gas > GasAmount(0), + gas_vector_computation_mode == GasVectorComputationMode::All + ); + assert_eq!(minimal_l1_data_gas > GasAmount(0), use_kzg_da); } #[rstest] @@ -902,9 +906,9 @@ fn test_max_fee_exceeds_balance( let invalid_max_fee = Fee(BALANCE + 1); // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion works. - let balance_over_gas_price: u64 = - (BALANCE / MAX_L1_GAS_PRICE).try_into().expect("Failed to convert u128 to u64."); - let invalid_resource_bounds = l1_resource_bounds(balance_over_gas_price + 1, MAX_L1_GAS_PRICE); + let balance_over_gas_price = BALANCE / MAX_L1_GAS_PRICE; + let invalid_resource_bounds = + l1_resource_bounds(GasAmount(balance_over_gas_price + 1), MAX_L1_GAS_PRICE); // V1 Invoke. let invalid_tx = account_invoke_tx(invoke_tx_args! { @@ -980,15 +984,15 @@ fn test_insufficient_new_resource_bounds( let default_resource_bounds = AllResourceBounds { l1_gas: ResourceBounds { - max_amount: minimal_gas_vector.l1_gas.try_into().unwrap(), + max_amount: minimal_gas_vector.l1_gas.0.try_into().unwrap(), max_price_per_unit: actual_strk_l1_gas_price.into(), }, l2_gas: ResourceBounds { - max_amount: minimal_gas_vector.l2_gas.try_into().unwrap(), + max_amount: minimal_gas_vector.l2_gas.0.try_into().unwrap(), max_price_per_unit: actual_strk_l2_gas_price.into(), }, l1_data_gas: ResourceBounds { - max_amount: minimal_gas_vector.l1_data_gas.try_into().unwrap(), + max_amount: minimal_gas_vector.l1_data_gas.0.try_into().unwrap(), max_price_per_unit: actual_strk_l1_data_gas_price.into(), }, }; @@ -1108,7 +1112,7 @@ fn test_insufficient_resource_bounds( let gas_prices = &block_context.block_info.gas_prices; // TODO(Aner, 21/01/24) change to linear combination. let minimal_fee = - Fee(minimal_l1_gas * u128::from(gas_prices.get_l1_gas_price_by_fee_type(&FeeType::Eth))); + Fee(minimal_l1_gas.0 * u128::from(gas_prices.get_l1_gas_price_by_fee_type(&FeeType::Eth))); // Max fee too low (lower than minimal estimated fee). let invalid_max_fee = Fee(minimal_fee.0 - 1); let invalid_v1_tx = account_invoke_tx( @@ -1130,16 +1134,12 @@ fn test_insufficient_resource_bounds( // Max L1 gas amount too low, old resource bounds. // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion works. - let insufficient_max_l1_gas_amount = - (minimal_l1_gas - 1).try_into().expect("Failed to convert u128 to u64."); + let insufficient_max_l1_gas_amount = GasAmount(minimal_l1_gas.0 - 1); let invalid_v3_tx = account_invoke_tx(invoke_tx_args! { resource_bounds: l1_resource_bounds(insufficient_max_l1_gas_amount, actual_strk_l1_gas_price.into()), ..valid_invoke_tx_args.clone() }); let execution_error = invalid_v3_tx.execute(state, block_context, true, true).unwrap_err(); - // TODO(Ori, 1/2/2024): Write an indicative expect message explaining why the conversion works. - let minimal_l1_gas_as_u64 = - u64::try_from(minimal_l1_gas).expect("Failed to convert u128 to u64."); assert_matches!( execution_error, TransactionExecutionError::TransactionPreValidationError( @@ -1149,12 +1149,11 @@ fn test_insufficient_resource_bounds( max_gas_amount, minimal_gas_amount})) if max_gas_amount == insufficient_max_l1_gas_amount && - minimal_gas_amount == minimal_l1_gas_as_u64 && resource == L1Gas + minimal_gas_amount == minimal_l1_gas && resource == L1Gas ); // Max L1 gas price too low, old resource bounds. let insufficient_max_l1_gas_price = u128::from(actual_strk_l1_gas_price) - 1; - let minimal_l1_gas = minimal_l1_gas.try_into().unwrap(); let invalid_v3_tx = account_invoke_tx(invoke_tx_args! { resource_bounds: l1_resource_bounds(minimal_l1_gas, insufficient_max_l1_gas_price), ..valid_invoke_tx_args.clone() @@ -1194,7 +1193,7 @@ fn test_actual_fee_gt_resource_bounds( let minimal_l1_gas = estimate_minimal_gas_vector(block_context, tx, &GasVectorComputationMode::NoL2Gas).l1_gas; let minimal_resource_bounds = l1_resource_bounds( - u64::try_from(minimal_l1_gas).unwrap(), + minimal_l1_gas, u128::from( block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&FeeType::Strk), ), @@ -1209,7 +1208,7 @@ fn test_actual_fee_gt_resource_bounds( // Test error. assert!(execution_error.starts_with(&format!("Insufficient max {resource}", resource = L1Gas))); // Test that fee was charged. - let minimal_fee = Fee(minimal_l1_gas + let minimal_fee = Fee(minimal_l1_gas.0 * u128::from( block_context.block_info.gas_prices.get_l1_gas_price_by_fee_type(&FeeType::Strk), )); @@ -2089,16 +2088,20 @@ fn test_l1_handler( // TODO(Nimrod, 1/5/2024): Change these hard coded values to match to the transaction resources // (currently matches only starknet resources). let mut expected_gas = match use_kzg_da { - true => GasVector { l1_gas: 16023, l1_data_gas: 128, l2_gas: 0 }, - false => GasVector::from_l1_gas(17675), + true => GasVector { + l1_gas: 16023_u32.into(), + l1_data_gas: 128_u32.into(), + l2_gas: 0_u32.into(), + }, + false => GasVector::from_l1_gas(17675_u32.into()), }; if gas_vector_computation_mode == GasVectorComputationMode::All { - expected_gas += GasVector::from_l2_gas(25); + expected_gas += GasVector::from_l2_gas(25_u32.into()); } let expected_da_gas = match use_kzg_da { - true => GasVector::from_l1_data_gas(128), - false => GasVector::from_l1_gas(1652), + true => GasVector::from_l1_data_gas(128_u32.into()), + false => GasVector::from_l1_gas(1652_u32.into()), }; let state_changes_count = StateChangesCount { diff --git a/crates/blockifier/src/versioned_constants.rs b/crates/blockifier/src/versioned_constants.rs index 9600d1a27f..dff21a000d 100644 --- a/crates/blockifier/src/versioned_constants.rs +++ b/crates/blockifier/src/versioned_constants.rs @@ -13,6 +13,7 @@ use semver::Version; use serde::de::Error as DeserializationError; use serde::{Deserialize, Deserializer}; use serde_json::{Map, Number, Value}; +use starknet_api::execution_resources::GasAmount; use starknet_api::transaction::GasVectorComputationMode; use strum::IntoEnumIterator; use strum_macros::{EnumCount, EnumIter}; @@ -224,9 +225,9 @@ impl VersionedConstants { } /// Converts from L1 gas amount to L2 gas amount with **upward rounding**. - pub fn convert_l1_to_l2_gas_amount_round_up(&self, l1_gas_amount: u128) -> u128 { + pub fn convert_l1_to_l2_gas_amount_round_up(&self, l1_gas_amount: GasAmount) -> GasAmount { // The amount ratio is the inverse of the price ratio. - *(self.l1_to_l2_gas_price_ratio().inv() * l1_gas_amount).ceil().numer() + GasAmount(*(self.l1_to_l2_gas_price_ratio().inv() * l1_gas_amount.0).ceil().numer()) } /// Returns the following ratio: L2_gas_price/L1_gas_price. diff --git a/crates/native_blockifier/src/py_block_executor.rs b/crates/native_blockifier/src/py_block_executor.rs index bd6eb608f1..0b9a96c552 100644 --- a/crates/native_blockifier/src/py_block_executor.rs +++ b/crates/native_blockifier/src/py_block_executor.rs @@ -93,17 +93,17 @@ impl ThinTransactionExecutionInfo { resources.extend(HashMap::from([ ( abi_constants::L1_GAS_USAGE.to_string(), - usize_from_u128(l1_gas) + usize_from_u128(l1_gas.0) .expect("This conversion should not fail as the value is a converted usize."), ), ( abi_constants::BLOB_GAS_USAGE.to_string(), - usize_from_u128(l1_data_gas) + usize_from_u128(l1_data_gas.0) .expect("This conversion should not fail as the value is a converted usize."), ), ( abi_constants::L2_GAS_USAGE.to_string(), - usize_from_u128(l2_gas) + usize_from_u128(l2_gas.0) .expect("This conversion should not fail as the value is a converted usize."), ), ])); diff --git a/crates/papyrus_execution/src/objects.rs b/crates/papyrus_execution/src/objects.rs index daac0dd71e..25caedbd1a 100644 --- a/crates/papyrus_execution/src/objects.rs +++ b/crates/papyrus_execution/src/objects.rs @@ -175,9 +175,9 @@ pub(crate) fn tx_execution_output_to_fee_estimation( let gas_vector = tx_execution_output.execution_info.receipt.gas; Ok(FeeEstimation { - gas_consumed: gas_vector.l1_gas.into(), + gas_consumed: gas_vector.l1_gas.0.into(), l1_gas_price, - data_gas_consumed: gas_vector.l1_data_gas.into(), + data_gas_consumed: gas_vector.l1_data_gas.0.into(), l1_data_gas_price, l2_gas_price, overall_fee: tx_execution_output.execution_info.receipt.fee, @@ -397,9 +397,10 @@ fn vm_resources_to_execution_resources( builtin_instance_counter, memory_holes: vm_resources.n_memory_holes as u64, da_gas_consumed: StarknetApiGasVector { - l1_gas: l1_gas.try_into().map_err(|_| ExecutionError::GasConsumedOutOfRange)?, - l2_gas: l2_gas.try_into().map_err(|_| ExecutionError::GasConsumedOutOfRange)?, + l1_gas: l1_gas.0.try_into().map_err(|_| ExecutionError::GasConsumedOutOfRange)?, + l2_gas: l2_gas.0.try_into().map_err(|_| ExecutionError::GasConsumedOutOfRange)?, l1_data_gas: l1_data_gas + .0 .try_into() .map_err(|_| ExecutionError::GasConsumedOutOfRange)?, }, diff --git a/crates/starknet_api/src/execution_resources.rs b/crates/starknet_api/src/execution_resources.rs index 9a49d291ea..07c5d20f25 100644 --- a/crates/starknet_api/src/execution_resources.rs +++ b/crates/starknet_api/src/execution_resources.rs @@ -3,6 +3,37 @@ use std::collections::HashMap; use serde::{Deserialize, Serialize}; use strum_macros::EnumIter; +#[derive( + derive_more::Add, + derive_more::AddAssign, + derive_more::Sum, + derive_more::Display, + Clone, + Copy, + Debug, + Default, + Eq, + PartialEq, + PartialOrd, + Serialize, + Deserialize, +)] +pub struct GasAmount(pub u128); + +macro_rules! impl_from_uint_for_gas_amount { + ($($uint:ty),*) => { + $( + impl From<$uint> for GasAmount { + fn from(value: $uint) -> Self { + Self(u128::from(value)) + } + } + )* + }; +} + +impl_from_uint_for_gas_amount!(u8, u16, u32, u64, u128); + #[derive(Debug, Default, Deserialize, Serialize, Clone, Eq, PartialEq)] pub struct GasVector { pub l1_gas: u64,