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