Skip to content

Commit

Permalink
feat(mempool): impl calculate-gas-price according to EIP 1559
Browse files Browse the repository at this point in the history
  • Loading branch information
MohammadNassar1 committed Aug 29, 2024
1 parent 6f89ece commit 5b6af31
Showing 1 changed file with 49 additions and 0 deletions.
49 changes: 49 additions & 0 deletions crates/blockifier/src/blockifier/block.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::cmp::max;
use std::num::NonZeroU128;

use log::warn;
Expand All @@ -16,6 +17,12 @@ use crate::versioned_constants::VersionedConstants;
#[path = "block_test.rs"]
pub mod block_test;

// 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.

#[derive(Clone, Debug)]
pub struct BlockInfo {
pub block_number: BlockNumber,
Expand All @@ -27,6 +34,48 @@ pub struct BlockInfo {
pub use_kzg_da: bool,
}

impl BlockInfo {
/// 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 {
assert!(gas_target > 0, "Gas target must be positive");

// 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 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 new_price =
if gas_used > gas_target { price + price_change } else { price - price_change };
max(new_price, MIN_GAS_PRICE)
}
}

#[derive(Clone, Debug)]
pub struct GasPrices {
eth_l1_gas_price: NonZeroU128, // In wei.
Expand Down

0 comments on commit 5b6af31

Please sign in to comment.