use crate::{
eip4844::{self, DATA_GAS_PER_BLOB},
eip7594, eip7691, eip7892,
};
pub const BLOB_BASE_COST: u64 = 2_u64.pow(13);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
feature = "serde",
serde(from = "serde_impl::SerdeHelper", into = "serde_impl::SerdeHelper")
)]
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
pub struct BlobParams {
pub target_blob_count: u64,
pub max_blob_count: u64,
pub update_fraction: u128,
pub min_blob_fee: u128,
pub max_blobs_per_tx: u64,
pub blob_base_cost: u64,
}
impl BlobParams {
pub const fn cancun() -> Self {
Self {
target_blob_count: eip4844::TARGET_BLOBS_PER_BLOCK_DENCUN,
max_blob_count: eip4844::MAX_BLOBS_PER_BLOCK_DENCUN as u64,
update_fraction: eip4844::BLOB_GASPRICE_UPDATE_FRACTION,
min_blob_fee: eip4844::BLOB_TX_MIN_BLOB_GASPRICE,
max_blobs_per_tx: eip4844::MAX_BLOBS_PER_BLOCK_DENCUN as u64,
blob_base_cost: 0,
}
}
pub const fn prague() -> Self {
Self {
target_blob_count: eip7691::TARGET_BLOBS_PER_BLOCK_ELECTRA,
max_blob_count: eip7691::MAX_BLOBS_PER_BLOCK_ELECTRA,
update_fraction: eip7691::BLOB_GASPRICE_UPDATE_FRACTION_PECTRA,
min_blob_fee: eip4844::BLOB_TX_MIN_BLOB_GASPRICE,
max_blobs_per_tx: eip7691::MAX_BLOBS_PER_BLOCK_ELECTRA,
blob_base_cost: 0,
}
}
pub const fn osaka() -> Self {
Self {
target_blob_count: eip7691::TARGET_BLOBS_PER_BLOCK_ELECTRA,
max_blob_count: eip7691::MAX_BLOBS_PER_BLOCK_ELECTRA,
update_fraction: eip7691::BLOB_GASPRICE_UPDATE_FRACTION_PECTRA,
min_blob_fee: eip4844::BLOB_TX_MIN_BLOB_GASPRICE,
max_blobs_per_tx: eip7594::MAX_BLOBS_PER_TX_FUSAKA,
blob_base_cost: BLOB_BASE_COST,
}
}
pub const fn bpo1() -> Self {
Self {
target_blob_count: eip7892::BPO1_TARGET_BLOBS_PER_BLOCK,
max_blob_count: eip7892::BPO1_MAX_BLOBS_PER_BLOCK,
update_fraction: eip7892::BPO1_BASE_UPDATE_FRACTION as u128,
..Self::osaka()
}
}
pub const fn bpo2() -> Self {
Self {
target_blob_count: eip7892::BPO2_TARGET_BLOBS_PER_BLOCK,
max_blob_count: eip7892::BPO2_MAX_BLOBS_PER_BLOCK,
update_fraction: eip7892::BPO2_BASE_UPDATE_FRACTION as u128,
..Self::osaka()
}
}
pub const fn with_max_blobs_per_tx(mut self, max_blobs_per_tx: u64) -> Self {
self.max_blobs_per_tx = max_blobs_per_tx;
self
}
pub const fn with_blob_base_cost(mut self, blob_base_cost: u64) -> Self {
self.blob_base_cost = blob_base_cost;
self
}
pub const fn max_blob_gas_per_block(&self) -> u64 {
self.max_blob_count * DATA_GAS_PER_BLOB
}
pub const fn target_blob_gas_per_block(&self) -> u64 {
self.target_blob_count * DATA_GAS_PER_BLOB
}
#[inline]
pub const fn next_block_excess_blob_gas_osaka(
&self,
excess_blob_gas: u64,
blob_gas_used: u64,
base_fee_per_gas: u64,
) -> u64 {
let next_excess_blob_gas = excess_blob_gas + blob_gas_used;
let target_blob_gas = self.target_blob_gas_per_block();
if next_excess_blob_gas < target_blob_gas {
return 0;
}
if self.blob_base_cost as u128 * base_fee_per_gas as u128
> DATA_GAS_PER_BLOB as u128 * self.calc_blob_fee(excess_blob_gas)
{
let scaled_excess = blob_gas_used * (self.max_blob_count - self.target_blob_count)
/ self.max_blob_count;
excess_blob_gas + scaled_excess
} else {
next_excess_blob_gas - target_blob_gas
}
}
#[inline]
pub const fn calc_blob_fee(&self, excess_blob_gas: u64) -> u128 {
eip4844::fake_exponential(self.min_blob_fee, excess_blob_gas as u128, self.update_fraction)
}
}
#[cfg(feature = "serde")]
mod serde_impl {
use crate::{eip4844, eip7840::BlobParams};
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy)]
#[serde(rename_all = "camelCase")]
pub(crate) struct SerdeHelper {
#[serde(rename = "baseFeeUpdateFraction")]
update_fraction: u128,
#[serde(rename = "max")]
max_blob_count: u64,
#[serde(rename = "target")]
target_blob_count: u64,
#[serde(skip)]
min_blob_fee: Option<u128>,
}
impl From<BlobParams> for SerdeHelper {
fn from(params: BlobParams) -> Self {
let BlobParams {
target_blob_count,
max_blob_count,
update_fraction,
min_blob_fee,
max_blobs_per_tx: _,
blob_base_cost: _,
} = params;
Self {
target_blob_count,
max_blob_count,
update_fraction,
min_blob_fee: (min_blob_fee != eip4844::BLOB_TX_MIN_BLOB_GASPRICE)
.then_some(min_blob_fee),
}
}
}
impl From<SerdeHelper> for BlobParams {
fn from(helper: SerdeHelper) -> Self {
let SerdeHelper { target_blob_count, max_blob_count, update_fraction, min_blob_fee } =
helper;
Self {
target_blob_count,
max_blob_count,
update_fraction,
min_blob_fee: min_blob_fee.unwrap_or(eip4844::BLOB_TX_MIN_BLOB_GASPRICE),
max_blobs_per_tx: max_blob_count,
blob_base_cost: 0,
}
}
}
}