1use crate::{
4 eip4844::{self, DATA_GAS_PER_BLOB},
5 eip7594, eip7691,
6};
7
8pub const BLOB_BASE_COST: u64 = 2_u64.pow(13);
13
14#[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)]
21pub struct BlobParams {
22 pub target_blob_count: u64,
24 pub max_blob_count: u64,
26 pub update_fraction: u128,
28 pub min_blob_fee: u128,
33 pub max_blobs_per_tx: u64,
37 pub blob_base_cost: u64,
41}
42
43impl BlobParams {
44 pub const fn cancun() -> Self {
46 Self {
47 target_blob_count: eip4844::TARGET_BLOBS_PER_BLOCK_DENCUN,
48 max_blob_count: eip4844::MAX_BLOBS_PER_BLOCK_DENCUN as u64,
49 update_fraction: eip4844::BLOB_GASPRICE_UPDATE_FRACTION,
50 min_blob_fee: eip4844::BLOB_TX_MIN_BLOB_GASPRICE,
51 max_blobs_per_tx: eip4844::MAX_BLOBS_PER_BLOCK_DENCUN as u64,
52 blob_base_cost: 0,
53 }
54 }
55
56 pub const fn prague() -> Self {
58 Self {
59 target_blob_count: eip7691::TARGET_BLOBS_PER_BLOCK_ELECTRA,
60 max_blob_count: eip7691::MAX_BLOBS_PER_BLOCK_ELECTRA,
61 update_fraction: eip7691::BLOB_GASPRICE_UPDATE_FRACTION_PECTRA,
62 min_blob_fee: eip4844::BLOB_TX_MIN_BLOB_GASPRICE,
63 max_blobs_per_tx: eip7691::MAX_BLOBS_PER_BLOCK_ELECTRA,
64 blob_base_cost: 0,
65 }
66 }
67
68 pub const fn osaka() -> Self {
70 Self {
71 target_blob_count: eip7691::TARGET_BLOBS_PER_BLOCK_ELECTRA,
72 max_blob_count: eip7691::MAX_BLOBS_PER_BLOCK_ELECTRA,
73 update_fraction: eip7691::BLOB_GASPRICE_UPDATE_FRACTION_PECTRA,
74 min_blob_fee: eip4844::BLOB_TX_MIN_BLOB_GASPRICE,
75 max_blobs_per_tx: eip7594::MAX_BLOBS_PER_TX_FUSAKA,
76 blob_base_cost: BLOB_BASE_COST,
77 }
78 }
79
80 pub const fn with_max_blobs_per_tx(mut self, max_blobs_per_tx: u64) -> Self {
82 self.max_blobs_per_tx = max_blobs_per_tx;
83 self
84 }
85
86 pub const fn with_blob_base_cost(mut self, blob_base_cost: u64) -> Self {
88 self.blob_base_cost = blob_base_cost;
89 self
90 }
91
92 pub const fn max_blob_gas_per_block(&self) -> u64 {
96 self.max_blob_count * DATA_GAS_PER_BLOB
97 }
98
99 pub const fn target_blob_gas_per_block(&self) -> u64 {
103 self.target_blob_count * DATA_GAS_PER_BLOB
104 }
105
106 #[inline]
109 pub const fn next_block_excess_blob_gas(
111 &self,
112 excess_blob_gas: u64,
113 blob_gas_used: u64,
114 ) -> u64 {
115 self.next_block_excess_blob_gas_osaka(excess_blob_gas, blob_gas_used, 0)
116 }
117
118 #[inline]
121 pub const fn next_block_excess_blob_gas_osaka(
122 &self,
123 excess_blob_gas: u64,
124 blob_gas_used: u64,
125 base_fee_per_gas: u64,
126 ) -> u64 {
127 let next_excess_blob_gas = excess_blob_gas + blob_gas_used;
128 let target_blob_gas = self.target_blob_gas_per_block();
129 if next_excess_blob_gas < target_blob_gas {
130 return 0;
131 }
132
133 if self.blob_base_cost as u128 * base_fee_per_gas as u128
134 > DATA_GAS_PER_BLOB as u128 * self.calc_blob_fee(excess_blob_gas)
135 {
136 let scaled_excess = blob_gas_used * (self.max_blob_count - self.target_blob_count)
137 / self.max_blob_count;
138 excess_blob_gas + scaled_excess
139 } else {
140 next_excess_blob_gas - target_blob_gas
141 }
142 }
143
144 #[inline]
146 pub const fn calc_blob_fee(&self, excess_blob_gas: u64) -> u128 {
147 eip4844::fake_exponential(self.min_blob_fee, excess_blob_gas as u128, self.update_fraction)
148 }
149}
150
151#[cfg(feature = "serde")]
152mod serde_impl {
153 use crate::{eip4844, eip7840::BlobParams};
154
155 #[derive(serde::Serialize, serde::Deserialize, Clone, Copy)]
156 #[serde(rename_all = "camelCase")]
157 pub(crate) struct SerdeHelper {
158 #[serde(rename = "baseFeeUpdateFraction")]
159 update_fraction: u128,
160 #[serde(rename = "max")]
161 max_blob_count: u64,
162 #[serde(rename = "target")]
163 target_blob_count: u64,
164 #[serde(skip_serializing)]
165 min_blob_fee: Option<u128>,
166 }
167
168 impl From<BlobParams> for SerdeHelper {
169 fn from(params: BlobParams) -> Self {
170 let BlobParams {
171 target_blob_count,
172 max_blob_count,
173 update_fraction,
174 min_blob_fee,
175 max_blobs_per_tx: _,
176 blob_base_cost: _,
177 } = params;
178
179 Self {
180 target_blob_count,
181 max_blob_count,
182 update_fraction,
183 min_blob_fee: (min_blob_fee != eip4844::BLOB_TX_MIN_BLOB_GASPRICE)
184 .then_some(min_blob_fee),
185 }
186 }
187 }
188
189 impl From<SerdeHelper> for BlobParams {
190 fn from(helper: SerdeHelper) -> Self {
191 let SerdeHelper { target_blob_count, max_blob_count, update_fraction, min_blob_fee } =
192 helper;
193
194 Self {
195 target_blob_count,
196 max_blob_count,
197 update_fraction,
198 min_blob_fee: min_blob_fee.unwrap_or(eip4844::BLOB_TX_MIN_BLOB_GASPRICE),
199 max_blobs_per_tx: max_blob_count,
200 blob_base_cost: 0,
201 }
202 }
203 }
204}