Skip to main content

alloy_eips/
eip7840.rs

1//! Contains constants and utility functions for [EIP-7840](https://github.com/ethereum/EIPs/tree/master/EIPS/eip-7840.md)
2
3use crate::{
4    eip4844::{self, DATA_GAS_PER_BLOB},
5    eip7594, eip7691, eip7892,
6};
7use alloy_primitives::U256;
8
9/// BLOB_BASE_COST represents the minimum execution gas required to include a blob in a block,
10/// as defined by [EIP-7918 (Decoupling Blob Gas from Execution Gas)](https://eips.ethereum.org/EIPS/eip-7918).
11/// This ensures that even though blob gas and execution gas are decoupled, there is still a base
12/// cost in execution gas to include blobs.
13pub const BLOB_BASE_COST: u64 = 2_u64.pow(13);
14
15/// Configuration for the blob-related calculations.
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
18#[cfg_attr(
19    feature = "serde",
20    serde(from = "serde_impl::SerdeHelper", into = "serde_impl::SerdeHelper")
21)]
22#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
23pub struct BlobParams {
24    /// Target blob count for the block.
25    pub target_blob_count: u64,
26    /// Max blob count for the block.
27    pub max_blob_count: u64,
28    /// Update fraction for excess blob gas calculation.
29    pub update_fraction: u128,
30    /// Minimum gas price for a data blob.
31    ///
32    /// Not required per EIP-7840 and assumed to be the default
33    /// [`eip4844::BLOB_TX_MIN_BLOB_GASPRICE`] if not set.
34    pub min_blob_fee: u128,
35    /// Maximum number of blobs per transaction.
36    ///
37    /// Defaults to `max_blob_count` unless set otherwise.
38    pub max_blobs_per_tx: u64,
39    /// Minimum execution gas required to include a blob in a block.
40    ///
41    /// Defaults to `0` for Cancun and Prague hardforks, and [`BLOB_BASE_COST`] for Osaka and
42    /// later.
43    pub blob_base_cost: u64,
44}
45
46impl BlobParams {
47    /// Returns [`BlobParams`] configuration activated with Cancun hardfork.
48    pub const fn cancun() -> Self {
49        Self {
50            target_blob_count: eip4844::TARGET_BLOBS_PER_BLOCK_DENCUN,
51            max_blob_count: eip4844::MAX_BLOBS_PER_BLOCK_DENCUN as u64,
52            update_fraction: eip4844::BLOB_GASPRICE_UPDATE_FRACTION,
53            min_blob_fee: eip4844::BLOB_TX_MIN_BLOB_GASPRICE,
54            max_blobs_per_tx: eip4844::MAX_BLOBS_PER_BLOCK_DENCUN as u64,
55            blob_base_cost: 0,
56        }
57    }
58
59    /// Returns [`BlobParams`] configuration activated with Prague hardfork.
60    pub const fn prague() -> Self {
61        Self {
62            target_blob_count: eip7691::TARGET_BLOBS_PER_BLOCK_ELECTRA,
63            max_blob_count: eip7691::MAX_BLOBS_PER_BLOCK_ELECTRA,
64            update_fraction: eip7691::BLOB_GASPRICE_UPDATE_FRACTION_PECTRA,
65            min_blob_fee: eip4844::BLOB_TX_MIN_BLOB_GASPRICE,
66            max_blobs_per_tx: eip7691::MAX_BLOBS_PER_BLOCK_ELECTRA,
67            blob_base_cost: 0,
68        }
69    }
70
71    /// Returns [`BlobParams`] configuration activated with Osaka hardfork.
72    pub const fn osaka() -> Self {
73        Self {
74            target_blob_count: eip7691::TARGET_BLOBS_PER_BLOCK_ELECTRA,
75            max_blob_count: eip7691::MAX_BLOBS_PER_BLOCK_ELECTRA,
76            update_fraction: eip7691::BLOB_GASPRICE_UPDATE_FRACTION_PECTRA,
77            min_blob_fee: eip4844::BLOB_TX_MIN_BLOB_GASPRICE,
78            max_blobs_per_tx: eip7594::MAX_BLOBS_PER_TX_FUSAKA,
79            blob_base_cost: BLOB_BASE_COST,
80        }
81    }
82
83    /// [`BlobParams`] for the [EIP-7892](https://eips.ethereum.org/EIPS/eip-7892) Blob parameter only hardfork BPO1.
84    pub const fn bpo1() -> Self {
85        Self {
86            target_blob_count: eip7892::BPO1_TARGET_BLOBS_PER_BLOCK,
87            max_blob_count: eip7892::BPO1_MAX_BLOBS_PER_BLOCK,
88            update_fraction: eip7892::BPO1_BASE_UPDATE_FRACTION as u128,
89            ..Self::osaka()
90        }
91    }
92
93    /// [`BlobParams`] for the [EIP-7892](https://eips.ethereum.org/EIPS/eip-7892) Blob parameter only hardfork BPO2
94    pub const fn bpo2() -> Self {
95        Self {
96            target_blob_count: eip7892::BPO2_TARGET_BLOBS_PER_BLOCK,
97            max_blob_count: eip7892::BPO2_MAX_BLOBS_PER_BLOCK,
98            update_fraction: eip7892::BPO2_BASE_UPDATE_FRACTION as u128,
99            ..Self::osaka()
100        }
101    }
102
103    /// Set max blobs per transaction on [`BlobParams`].
104    pub const fn with_max_blobs_per_tx(mut self, max_blobs_per_tx: u64) -> Self {
105        self.max_blobs_per_tx = max_blobs_per_tx;
106        self
107    }
108
109    /// Set blob base cost on [`BlobParams`].
110    pub const fn with_blob_base_cost(mut self, blob_base_cost: u64) -> Self {
111        self.blob_base_cost = blob_base_cost;
112        self
113    }
114
115    /// Returns the maximum available blob gas in a block.
116    ///
117    /// This is `max blob count * DATA_GAS_PER_BLOB`
118    pub const fn max_blob_gas_per_block(&self) -> u64 {
119        self.max_blob_count * DATA_GAS_PER_BLOB
120    }
121
122    /// Returns the blob gas target per block.
123    ///
124    /// This is `target blob count * DATA_GAS_PER_BLOB`
125    pub const fn target_blob_gas_per_block(&self) -> u64 {
126        self.target_blob_count * DATA_GAS_PER_BLOB
127    }
128
129    /// Calculates the `excess_blob_gas` value for the next block based on the current block
130    /// `excess_blob_gas`, `blob_gas_used` and `base_fee_per_gas`.
131    #[inline]
132    pub fn next_block_excess_blob_gas_osaka(
133        &self,
134        excess_blob_gas: u64,
135        blob_gas_used: u64,
136        base_fee_per_gas: u64,
137    ) -> u64 {
138        let next_excess_blob_gas = excess_blob_gas + blob_gas_used;
139        let target_blob_gas = self.target_blob_gas_per_block();
140        if next_excess_blob_gas < target_blob_gas {
141            return 0;
142        }
143
144        if U256::from(self.blob_base_cost) * U256::from(base_fee_per_gas)
145            > U256::from(DATA_GAS_PER_BLOB) * U256::from(self.calc_blob_fee(excess_blob_gas))
146        {
147            let scaled_excess = blob_gas_used * (self.max_blob_count - self.target_blob_count)
148                / self.max_blob_count;
149            excess_blob_gas + scaled_excess
150        } else {
151            next_excess_blob_gas - target_blob_gas
152        }
153    }
154
155    /// Calculates the blob fee for block based on its `excess_blob_gas`.
156    #[inline]
157    pub fn calc_blob_fee(&self, excess_blob_gas: u64) -> u128 {
158        eip4844::fake_exponential(self.min_blob_fee, excess_blob_gas as u128, self.update_fraction)
159    }
160}
161
162#[cfg(feature = "serde")]
163mod serde_impl {
164    use crate::{eip4844, eip7840::BlobParams};
165
166    #[derive(serde::Serialize, serde::Deserialize, Clone, Copy)]
167    #[serde(rename_all = "camelCase")]
168    pub(crate) struct SerdeHelper {
169        #[serde(rename = "baseFeeUpdateFraction")]
170        update_fraction: u128,
171        #[serde(rename = "max")]
172        max_blob_count: u64,
173        #[serde(rename = "target")]
174        target_blob_count: u64,
175        #[serde(skip)]
176        min_blob_fee: Option<u128>,
177    }
178
179    impl From<BlobParams> for SerdeHelper {
180        fn from(params: BlobParams) -> Self {
181            let BlobParams {
182                target_blob_count,
183                max_blob_count,
184                update_fraction,
185                min_blob_fee,
186                max_blobs_per_tx: _,
187                blob_base_cost: _,
188            } = params;
189
190            Self {
191                target_blob_count,
192                max_blob_count,
193                update_fraction,
194                min_blob_fee: (min_blob_fee != eip4844::BLOB_TX_MIN_BLOB_GASPRICE)
195                    .then_some(min_blob_fee),
196            }
197        }
198    }
199
200    impl From<SerdeHelper> for BlobParams {
201        fn from(helper: SerdeHelper) -> Self {
202            let SerdeHelper { target_blob_count, max_blob_count, update_fraction, min_blob_fee } =
203                helper;
204
205            Self {
206                target_blob_count,
207                max_blob_count,
208                update_fraction,
209                min_blob_fee: min_blob_fee.unwrap_or(eip4844::BLOB_TX_MIN_BLOB_GASPRICE),
210                max_blobs_per_tx: max_blob_count,
211                blob_base_cost: 0,
212            }
213        }
214    }
215}