diff --git a/crates/primitives/src/constants/eip4844.rs b/crates/primitives/src/constants/eip4844.rs index 2cde1da775..cb971c9f18 100644 --- a/crates/primitives/src/constants/eip4844.rs +++ b/crates/primitives/src/constants/eip4844.rs @@ -1,6 +1,6 @@ -//! [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844#parameters) protocol constants for shard Blob Transactions. +//! [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844#parameters) protocol constants and utils for shard Blob Transactions. -use crate::kzg::KzgSettings; +use crate::{kzg::KzgSettings, U256}; use once_cell::sync::Lazy; use std::{io::Write, sync::Arc}; @@ -25,9 +25,12 @@ pub const MAX_BLOBS_PER_BLOCK: u64 = MAX_DATA_GAS_PER_BLOCK / DATA_GAS_PER_BLOB; /// Target number of data blobs in a single block. pub const TARGET_BLOBS_PER_BLOCK: u64 = TARGET_DATA_GAS_PER_BLOCK / DATA_GAS_PER_BLOB; // 393216 / 131072 = 3 -/// Used to determine the price for next data blob +/// Determines the maximum rate of change for blob fee pub const BLOB_GASPRICE_UPDATE_FRACTION: u64 = 3_338_477u64; // 3338477 +/// Minimum gas price for a data blob +pub const BLOB_TX_MIN_BLOB_GASPRICE: u64 = 1u64; + /// Commitment version of a KZG commitment pub const VERSIONED_HASH_VERSION_KZG: u8 = 0x01; @@ -63,6 +66,32 @@ pub enum LoadKzgSettingsError { KzgError(c_kzg::Error), } +/// Calculates the blob fee for the given excess blob gas. +pub fn blob_fee(excess_blob_gas: u64) -> U256 { + fake_exponential( + U256::from(BLOB_TX_MIN_BLOB_GASPRICE), + U256::from(excess_blob_gas), + U256::from(BLOB_GASPRICE_UPDATE_FRACTION), + ) +} + +/// Approximates factor * e ** (numerator / denominator) using Taylor expansion. +/// +/// This is used to calculate the blob price. +/// +/// See also +pub fn fake_exponential(factor: U256, numerator: U256, denominator: U256) -> U256 { + let mut output = U256::ZERO; + let mut numerator_accum = factor.saturating_mul(denominator); + let mut i = U256::from(1u64); + while numerator_accum > U256::ZERO { + output += numerator_accum; + numerator_accum = numerator_accum * numerator / (denominator * i); + i += U256::from(1u64); + } + output / denominator +} + #[cfg(test)] mod tests { use super::*; @@ -71,4 +100,29 @@ mod tests { fn ensure_load_kzg_settings() { let _settings = Arc::clone(&MAINNET_KZG_TRUSTED_SETUP); } + + #[test] + fn test_fake_exp() { + // + for (factor, num, denom, expected) in &[ + (1u64, 0u64, 1u64, 1u64), + (38493, 0, 1000, 38493), + (0, 1234, 2345, 0), + (1, 2, 1, 6), // approximate 7.389 + (1, 4, 2, 6), + (1, 3, 1, 16), // approximate 20.09 + (1, 6, 2, 18), + (1, 4, 1, 49), // approximate 54.60 + (1, 8, 2, 50), + (10, 8, 2, 542), // approximate 540.598 + (11, 8, 2, 596), // approximate 600.58 + (1, 5, 1, 136), // approximate 148.4 + (1, 5, 2, 11), // approximate 12.18 + (2, 5, 2, 23), // approximate 24.36 + (1, 50000000, 2225652, 5709098764), + ] { + let res = fake_exponential(U256::from(*factor), U256::from(*num), U256::from(*denom)); + assert_eq!(res, U256::from(*expected)); + } + } } diff --git a/crates/primitives/src/header.rs b/crates/primitives/src/header.rs index f74707844c..69a1516312 100644 --- a/crates/primitives/src/header.rs +++ b/crates/primitives/src/header.rs @@ -8,6 +8,7 @@ use crate::{ }; use bytes::{Buf, BufMut, BytesMut}; +use crate::constants::eip4844::blob_fee; use reth_codecs::{add_arbitrary_tests, derive_arbitrary, main_codec, Compact}; use reth_rlp::{length_of_length, Decodable, Encodable, EMPTY_LIST_CODE, EMPTY_STRING_CODE}; use serde::{Deserialize, Serialize}; @@ -183,6 +184,22 @@ impl Header { } } + /// Returns the blob fee for _this_ block according to the EIP-4844 spec. + /// + /// Returns `None` if `excess_blob_gas` is None + pub fn blob_fee(&self) -> Option { + self.excess_blob_gas.map(blob_fee) + } + + /// Returns the blob fee for the next block according to the EIP-4844 spec. + /// + /// Returns `None` if `excess_blob_gas` is None. + /// + /// See also [Self::next_block_excess_blob_gas] + pub fn next_block_blob_fee(&self) -> Option { + self.next_block_excess_blob_gas().map(blob_fee) + } + /// Calculate base fee for next block according to the EIP-1559 spec. /// /// Returns a `None` if no base fee is set, no EIP-1559 support