Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(mempool): impl calculate-gas-price according to EIP 1559 #203

Merged
merged 1 commit into from
Sep 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions crates/batcher/src/fee_market.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use std::cmp::max;

// This constant is used to calculate the base gas price for the next block according to EIP-1559
// and serves as a sensitivity parameter that limits the maximum rate of change of the gas price
// between consecutive blocks.
const GAS_PRICE_MAX_CHANGE_DENOMINATOR: u128 = 48;
const MIN_GAS_PRICE: u64 = 100000; // In fri.
// TODO(Mohammad): Check the exact value for maximum block size in StarkNet.
const MAX_BLOCK_SIZE: u64 = 4000000000; // In gas units. It's equivalent to 40M gas steps, with 100 gas units per step.

/// Calculate the base gas price for the next block according to EIP-1559.
///
/// # Parameters
/// - `price`: The base fee of the current block.
/// - `gas_used`: The total gas used in the current block.
/// - `gas_target`: The target gas usage per block (usually half of the gas limit).
pub fn calculate_next_base_gas_price(price: u64, gas_used: u64, gas_target: u64) -> u64 {
// Setting the target at 50% of the max block size balances the rate of gas price changes,
// helping to prevent sudden spikes, particularly during increases, for a better user
// experience.
assert_eq!(
gas_target,
MAX_BLOCK_SIZE / 2,
"Gas target must be 50% of max block size to balance price changes."
);
// To prevent precision loss during multiplication and division, we set a minimum gas price.
// Additionally, a minimum gas price is established to prevent prolonged periods before the
// price reaches a higher value.
assert!(
price >= MIN_GAS_PRICE,
"The gas price must be at least the minimum to prevent precision loss during \
multiplication and division."
);

// We use unsigned integers (u64 and u128) to avoid overflow issues, as the input values are
// naturally unsigned and i256 is unstable in Rust. This approach allows safe handling of
// all inputs using u128 for intermediate calculations.

// The absolute difference between gas_used and gas_target is always u64.
let gas_delta = gas_used.abs_diff(gas_target);
// Convert to u128 to prevent overflow, as a product of two u64 fits inside a u128.
let price_u128 = u128::from(price);
let gas_delta_u128 = u128::from(gas_delta);
let gas_target_u128 = u128::from(gas_target);

// Calculate the gas change as u128 to handle potential overflow during multiplication.
let gas_delta_cost =
price_u128.checked_mul(gas_delta_u128).expect("Both variables originate from u64");
// Calculate the price change, maintaining precision by dividing after scaling up.
// This avoids significant precision loss that would occur if dividing before
// multiplication.
let price_change_u128 = gas_delta_cost / gas_target_u128 / GAS_PRICE_MAX_CHANGE_DENOMINATOR;

// Convert back to u64, as the price change should fit within the u64 range.
// Since the target is half the maximum block size (which fits within a u64), the gas delta
// is bounded by half the maximum block size. Therefore, after dividing by the gas target
// (which is half the maximum block size), the result is guaranteed to fit within a u64.
let price_change = u64::try_from(price_change_u128)
.expect("Result fits u64 after division of a bounded gas delta");

let adjusted_price =
if gas_used > gas_target { price + price_change } else { price - price_change };

assert!(
gas_used > gas_target && adjusted_price >= price
|| gas_used <= gas_target && adjusted_price <= price
);

max(adjusted_price, MIN_GAS_PRICE)
}
1 change: 1 addition & 0 deletions crates/batcher/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod batcher;
pub mod communication;
pub mod config;
pub mod fee_market;
pub mod proposals_manager;
#[cfg(test)]
mod proposals_manager_test;
Loading