Skip to content

Commit

Permalink
refactor(blockifier,starknet_api): add GasAmount (u128) type and use …
Browse files Browse the repository at this point in the history
…in blockifier's GasVector
  • Loading branch information
dorimedini-starkware committed Oct 6, 2024
1 parent 37c08f5 commit eccb0e4
Show file tree
Hide file tree
Showing 22 changed files with 311 additions and 227 deletions.
5 changes: 3 additions & 2 deletions crates/blockifier/src/blockifier/transaction_executor_test.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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()),
)
Expand All @@ -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(),
Expand Down
2 changes: 1 addition & 1 deletion crates/blockifier/src/bouncer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ pub fn get_tx_weights<S: StateReader>(
state_changes_keys: &StateChangesKeys,
) -> TransactionExecutionResult<BouncerWeights> {
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)?;
Expand Down
3 changes: 2 additions & 1 deletion crates/blockifier/src/concurrency/versioned_state_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use starknet_api::core::{
Nonce,
PatriciaKey,
};
use starknet_api::execution_resources::GasAmount;
use starknet_api::test_utils::NonceManager;
use starknet_api::transaction::{Calldata, ContractAddressSalt, ValidResourceBounds};
use starknet_api::{
Expand Down Expand Up @@ -238,7 +239,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(GasAmount(u128::from(!zero_bounds)), DEFAULT_STRK_L1_GAS_PRICE),
},
&mut NonceManager::default(),
);
Expand Down
23 changes: 15 additions & 8 deletions crates/blockifier/src/fee/fee_checks.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -14,9 +15,9 @@ use crate::transaction::objects::{FeeType, TransactionExecutionResult, Transacti
#[derive(Clone, Copy, Debug, Error)]
pub enum FeeCheckError {
#[error(
"Insufficient max {resource}: max amount: {max_amount}, actual used: {actual_amount}."
"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(
Expand Down Expand Up @@ -75,7 +76,9 @@ impl FeeCheckReport {
match &tx_context.tx_info {
TransactionInfo::Current(info) => get_fee_by_gas_vector(
&tx_context.block_context.block_info,
GasVector::from_l1_gas(info.l1_resource_bounds().max_amount.into()),
GasVector::from_l1_gas(GasAmount(
info.l1_resource_bounds().max_amount.into(),
)),
&FeeType::Strk,
),
TransactionInfo::Deprecated(context) => context.max_fee,
Expand Down Expand Up @@ -152,9 +155,13 @@ impl FeeCheckReport {
gas_vector: &GasVector,
) -> FeeCheckResult<()> {
for (resource, max_amount, actual_amount) in [
(L1Gas, all_resource_bounds.l1_gas.max_amount.into(), gas_vector.l1_gas),
(L2Gas, all_resource_bounds.l2_gas.max_amount.into(), gas_vector.l2_gas),
(L1DataGas, all_resource_bounds.l1_data_gas.max_amount.into(), gas_vector.l1_data_gas),
(L1Gas, GasAmount(all_resource_bounds.l1_gas.max_amount.into()), gas_vector.l1_gas),
(L2Gas, GasAmount(all_resource_bounds.l2_gas.max_amount.into()), gas_vector.l2_gas),
(
L1DataGas,
GasAmount(all_resource_bounds.l1_data_gas.max_amount.into()),
gas_vector.l1_data_gas,
),
] {
if max_amount < actual_amount {
return Err(FeeCheckError::MaxGasAmountExceeded {
Expand All @@ -174,10 +181,10 @@ impl FeeCheckReport {
tx_context: &TransactionContext,
) -> FeeCheckResult<()> {
let total_discounted_gas_used = gas_vector.to_discounted_l1_gas(tx_context);
if total_discounted_gas_used > l1_bounds.max_amount.into() {
if total_discounted_gas_used > GasAmount(l1_bounds.max_amount.into()) {
return Err(FeeCheckError::MaxGasAmountExceeded {
resource: L1Gas,
max_amount: l1_bounds.max_amount.into(),
max_amount: GasAmount(l1_bounds.max_amount.into()),
actual_amount: total_discounted_gas_used,
});
}
Expand Down
53 changes: 32 additions & 21 deletions crates/blockifier/src/fee/fee_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -55,10 +56,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,
Expand All @@ -78,9 +81,9 @@ fn test_simple_get_vm_resource_usage(
let n_reverted_steps = 0;
vm_resource_usage.n_steps =
vm_resource_usage.builtin_instance_counter.get(&BuiltinName::range_check).unwrap() - 1;
let vm_usage_in_l1_gas = u128_from_usize(
let vm_usage_in_l1_gas = GasAmount(u128_from_usize(
*vm_resource_usage.builtin_instance_counter.get(&BuiltinName::range_check).unwrap(),
);
));
let expected_gas_vector = gas_vector_from_vm_usage(
vm_usage_in_l1_gas,
&gas_vector_computation_mode,
Expand Down Expand Up @@ -108,10 +111,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,
Expand All @@ -129,13 +134,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,
Expand Down Expand Up @@ -166,9 +172,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(),
Expand Down Expand Up @@ -196,8 +203,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: GasAmount(u128_from_usize(l1_gas_used)),
l1_data_gas: GasAmount(u128_from_usize(l1_data_gas_used)),
..Default::default()
},
..Default::default()
Expand All @@ -213,11 +220,15 @@ 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 = GasAmount(
u128_from_usize(l1_gas_used)
+ (u128_from_usize(l1_data_gas_used) * data_gas_price) / gas_price,
);
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);
Expand Down Expand Up @@ -256,9 +267,9 @@ fn test_post_execution_gas_overdraft_all_resource_bounds(
let tx_receipt = TransactionReceipt {
fee: Fee(0),
gas: GasVector {
l1_gas: l1_gas_used.into(),
l2_gas: l2_gas_used.into(),
l1_data_gas: l1_data_gas_used.into(),
l1_gas: GasAmount(l1_gas_used.into()),
l2_gas: GasAmount(l2_gas_used.into()),
l1_data_gas: GasAmount(l1_data_gas_used.into()),
},
..Default::default()
};
Expand Down
7 changes: 5 additions & 2 deletions crates/blockifier/src/fee/fee_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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.
Expand All @@ -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),
Expand Down
13 changes: 7 additions & 6 deletions crates/blockifier/src/fee/gas_usage.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use cairo_vm::vm::runners::cairo_runner::ExecutionResources;
use starknet_api::execution_resources::GasAmount;
use starknet_api::transaction::GasVectorComputationMode;

use super::fee_utils::get_vm_resources_cost;
Expand Down Expand Up @@ -42,10 +43,10 @@ pub fn get_da_gas_cost(state_changes_count: &StateChangesCount, use_kzg_da: bool

let (l1_gas, blob_gas) = if use_kzg_da {
(
0,
u128_from_usize(
GasAmount(0),
GasAmount(u128_from_usize(
onchain_data_segment_length * eth_gas_constants::DATA_GAS_PER_FIELD_ELEMENT,
),
)),
)
} else {
// TODO(Yoni, 1/5/2024): count the exact amount of nonzero bytes for each DA entry.
Expand All @@ -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)
(GasAmount(u128_from_usize(gas)), GasAmount(0))
};

GasVector { l1_gas, l1_data_gas: blob_gas, ..Default::default() }
Expand Down Expand Up @@ -134,11 +135,11 @@ 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(
GasVector::from_l1_gas(GasAmount(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,
))
)))
}

/// Returns an estimated lower bound for the gas required by the given account transaction.
Expand Down
31 changes: 18 additions & 13 deletions crates/blockifier/src/fee/gas_usage_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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(GasAmount(u128_from_usize(manual_blob_gas_usage))),
computed_gas_vector
);
}
Expand All @@ -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 {
Expand Down Expand Up @@ -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()
GasAmount(expected_cost.try_into().unwrap())
);

// Test 10% discount.
Expand All @@ -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));
}
Expand Down Expand Up @@ -227,21 +229,24 @@ 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,
+ GasAmount(u128_div_ceil(
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;
));
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)
);
}
Loading

0 comments on commit eccb0e4

Please sign in to comment.