1#[cfg(feature = "kzg")]
7pub mod env_settings;
8#[cfg(feature = "kzg")]
10pub mod trusted_setup_points;
11
12pub mod builder;
14pub mod utils;
15
16mod engine;
17pub use engine::*;
18
19#[cfg(feature = "kzg-sidecar")]
21mod sidecar;
22#[cfg(feature = "kzg-sidecar")]
23pub use sidecar::*;
24
25use alloy_primitives::{b256, Bytes, FixedBytes, B256, U256};
26
27use crate::eip7840;
28
29pub const BLS_MODULUS_BYTES: B256 =
32 b256!("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001");
33
34pub const BLS_MODULUS: U256 = U256::from_be_bytes(BLS_MODULUS_BYTES.0);
37
38pub const FIELD_ELEMENT_BYTES: u64 = 32;
40
41pub const FIELD_ELEMENT_BYTES_USIZE: usize = FIELD_ELEMENT_BYTES as usize;
43
44pub const FIELD_ELEMENTS_PER_BLOB: u64 = 4096;
46
47pub const USABLE_BITS_PER_FIELD_ELEMENT: usize = 254;
49
50pub const USABLE_BYTES_PER_BLOB: usize =
54 USABLE_BITS_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB as usize / 8;
55
56pub const DATA_GAS_PER_BLOB: u64 = 131_072u64; pub const BYTES_PER_BLOB: usize = 131_072;
62
63pub const MAX_DATA_GAS_PER_BLOCK_DENCUN: u64 = 786_432u64; pub const TARGET_DATA_GAS_PER_BLOCK_DENCUN: u64 = 393_216u64; pub const MAX_BLOBS_PER_BLOCK_DENCUN: usize =
71 (MAX_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) as usize; pub const TARGET_BLOBS_PER_BLOCK_DENCUN: u64 = TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB; pub const BLOB_GASPRICE_UPDATE_FRACTION: u128 = 3_338_477u128; pub const BLOB_TX_MIN_BLOB_GASPRICE: u128 = 1u128;
81
82pub const VERSIONED_HASH_VERSION_KZG: u8 = 0x01;
84
85pub const BYTES_PER_COMMITMENT: usize = 48;
87
88pub const BYTES_PER_PROOF: usize = 48;
90
91pub type Blob = FixedBytes<BYTES_PER_BLOB>;
93
94#[cfg(feature = "serde")]
96pub fn deserialize_blob<'de, D>(deserializer: D) -> Result<alloc::boxed::Box<Blob>, D::Error>
97where
98 D: serde::de::Deserializer<'de>,
99{
100 use serde::Deserialize;
101 let raw_blob = <alloy_primitives::Bytes>::deserialize(deserializer)?;
102 let blob = alloc::boxed::Box::new(
103 Blob::try_from(raw_blob.as_ref()).map_err(serde::de::Error::custom)?,
104 );
105 Ok(blob)
106}
107
108#[cfg(all(debug_assertions, feature = "serde"))]
110pub fn deserialize_blobs<'de, D>(deserializer: D) -> Result<alloc::vec::Vec<Blob>, D::Error>
111where
112 D: serde::de::Deserializer<'de>,
113{
114 use alloc::vec::Vec;
115 use serde::Deserialize;
116
117 let raw_blobs = Vec::<alloy_primitives::Bytes>::deserialize(deserializer)?;
118 let mut blobs = Vec::with_capacity(raw_blobs.len());
119 for blob in raw_blobs {
120 blobs.push(Blob::try_from(blob.as_ref()).map_err(serde::de::Error::custom)?);
121 }
122 Ok(blobs)
123}
124
125#[cfg(all(not(debug_assertions), feature = "serde"))]
126#[inline(always)]
127pub fn deserialize_blobs<'de, D>(deserializer: D) -> Result<alloc::vec::Vec<Blob>, D::Error>
128where
129 D: serde::de::Deserializer<'de>,
130{
131 serde::Deserialize::deserialize(deserializer)
132}
133
134#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, alloy_rlp::RlpEncodableWrapper)]
136pub struct HeapBlob(Bytes);
137
138impl HeapBlob {
139 pub fn new(blob: &[u8]) -> Result<Self, InvalidBlobLength> {
141 if blob.len() != BYTES_PER_BLOB {
142 return Err(InvalidBlobLength(blob.len()));
143 }
144
145 Ok(Self(Bytes::copy_from_slice(blob)))
146 }
147
148 pub fn from_array(blob: [u8; BYTES_PER_BLOB]) -> Self {
150 Self(Bytes::from(blob))
151 }
152
153 pub fn from_bytes(bytes: Bytes) -> Result<Self, InvalidBlobLength> {
155 if bytes.len() != BYTES_PER_BLOB {
156 return Err(InvalidBlobLength(bytes.len()));
157 }
158
159 Ok(Self(bytes))
160 }
161
162 pub fn repeat_byte(byte: u8) -> Self {
164 Self(Bytes::from(vec![byte; BYTES_PER_BLOB]))
165 }
166
167 pub const fn inner(&self) -> &Bytes {
169 &self.0
170 }
171}
172
173impl Default for HeapBlob {
174 fn default() -> Self {
175 Self::repeat_byte(0)
176 }
177}
178
179#[derive(Debug, Clone)]
181pub struct InvalidBlobLength(usize);
182impl core::fmt::Display for InvalidBlobLength {
183 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
184 write!(f, "Invalid blob length: {}, expected: {BYTES_PER_BLOB}", self.0)
185 }
186}
187impl core::error::Error for InvalidBlobLength {}
188
189#[cfg(feature = "serde")]
190impl serde::Serialize for HeapBlob {
191 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
192 where
193 S: serde::Serializer,
194 {
195 self.inner().serialize(serializer)
196 }
197}
198
199#[cfg(any(test, feature = "arbitrary"))]
200impl<'a> arbitrary::Arbitrary<'a> for HeapBlob {
201 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
202 let mut blob = vec![0u8; BYTES_PER_BLOB];
203 u.fill_buffer(&mut blob)?;
204 Ok(Self(Bytes::from(blob)))
205 }
206}
207
208#[cfg(feature = "serde")]
209impl<'de> serde::Deserialize<'de> for HeapBlob {
210 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
211 where
212 D: serde::de::Deserializer<'de>,
213 {
214 let inner = <Bytes>::deserialize(deserializer)?;
215
216 Self::from_bytes(inner).map_err(serde::de::Error::custom)
217 }
218}
219
220impl alloy_rlp::Decodable for HeapBlob {
221 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
222 let bytes = <Bytes>::decode(buf)?;
223
224 Self::from_bytes(bytes).map_err(|_| alloy_rlp::Error::Custom("invalid blob length"))
225 }
226}
227
228pub type Bytes48 = FixedBytes<48>;
230
231#[cfg(feature = "sha2")]
239pub fn kzg_to_versioned_hash(commitment: &[u8]) -> B256 {
240 use sha2::Digest;
241
242 debug_assert_eq!(commitment.len(), 48, "commitment length is not 48");
243 let mut res = sha2::Sha256::digest(commitment);
244 res[0] = VERSIONED_HASH_VERSION_KZG;
245 B256::new(res.into())
246}
247
248#[inline]
253pub const fn calc_excess_blob_gas(parent_excess_blob_gas: u64, parent_blob_gas_used: u64) -> u64 {
254 eip7840::BlobParams::cancun().next_block_excess_blob_gas_osaka(
255 parent_excess_blob_gas,
256 parent_blob_gas_used,
257 0,
259 )
260}
261
262#[inline]
267pub const fn calc_blob_gasprice(excess_blob_gas: u64) -> u128 {
268 eip7840::BlobParams::cancun().calc_blob_fee(excess_blob_gas)
269}
270
271#[inline]
282pub const fn fake_exponential(factor: u128, numerator: u128, denominator: u128) -> u128 {
283 assert!(denominator != 0, "attempt to divide by zero");
284
285 let mut i = 1;
286 let mut output = 0;
287 let mut numerator_accum = factor * denominator;
288 while numerator_accum > 0 {
289 output += numerator_accum;
290
291 let Some(val) = numerator_accum.checked_mul(numerator) else {
293 break;
294 };
295
296 numerator_accum = val / (denominator * i);
298 i += 1;
299 }
300 output / denominator
301}
302
303#[cfg(test)]
304mod tests {
305 use super::*;
306
307 #[test]
309 fn test_calc_excess_blob_gas() {
310 for t @ &(excess, blobs, expected) in &[
311 (0, 0, 0),
314 (0, 1, 0),
315 (0, TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB, 0),
316 (0, (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) + 1, DATA_GAS_PER_BLOB),
319 (1, (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) + 1, DATA_GAS_PER_BLOB + 1),
320 (
321 1,
322 (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) + 2,
323 2 * DATA_GAS_PER_BLOB + 1,
324 ),
325 (
328 TARGET_DATA_GAS_PER_BLOCK_DENCUN,
329 TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB,
330 TARGET_DATA_GAS_PER_BLOCK_DENCUN,
331 ),
332 (
333 TARGET_DATA_GAS_PER_BLOCK_DENCUN,
334 (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) - 1,
335 TARGET_DATA_GAS_PER_BLOCK_DENCUN - DATA_GAS_PER_BLOB,
336 ),
337 (
338 TARGET_DATA_GAS_PER_BLOCK_DENCUN,
339 (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) - 2,
340 TARGET_DATA_GAS_PER_BLOCK_DENCUN - (2 * DATA_GAS_PER_BLOB),
341 ),
342 (DATA_GAS_PER_BLOB - 1, (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) - 1, 0),
343 ] {
344 let actual = calc_excess_blob_gas(excess, blobs * DATA_GAS_PER_BLOB);
345 assert_eq!(actual, expected, "test: {t:?}");
346 }
347 }
348
349 #[test]
351 fn test_calc_blob_fee() {
352 let blob_fee_vectors = &[
353 (0, 1),
354 (2314057, 1),
355 (2314058, 2),
356 (10 * 1024 * 1024, 23),
357 (148099578, 18446739238971471609), (148099579, 18446744762204311910), (161087488, 902580055246494526580),
366 ];
367
368 for &(excess, expected) in blob_fee_vectors {
369 let actual = calc_blob_gasprice(excess);
370 assert_eq!(actual, expected, "test: {excess}");
371 }
372 }
373
374 #[test]
376 fn fake_exp() {
377 for t @ &(factor, numerator, denominator, expected) in &[
378 (1u64, 0u64, 1u64, 1u128),
379 (38493, 0, 1000, 38493),
380 (0, 1234, 2345, 0),
381 (1, 2, 1, 6), (1, 4, 2, 6),
383 (1, 3, 1, 16), (1, 6, 2, 18),
385 (1, 4, 1, 49), (1, 8, 2, 50),
387 (10, 8, 2, 542), (11, 8, 2, 596), (1, 5, 1, 136), (1, 5, 2, 11), (2, 5, 2, 23), (1, 50000000, 2225652, 5709098764),
393 (1, 380928, BLOB_GASPRICE_UPDATE_FRACTION.try_into().unwrap(), 1),
394 ] {
395 let actual = fake_exponential(factor as u128, numerator as u128, denominator as u128);
396 assert_eq!(actual, expected, "test: {t:?}");
397 }
398 }
399
400 #[test]
401 #[cfg(feature = "serde")]
402 fn serde_heap_blob() {
403 let blob = HeapBlob::repeat_byte(0x42);
404 let serialized = serde_json::to_string(&blob).unwrap();
405
406 let deserialized: HeapBlob = serde_json::from_str(&serialized).unwrap();
407 assert_eq!(blob, deserialized);
408 }
409
410 #[test]
411 fn fake_exp_handles_overflow() {
412 let factor = 1u128; let numerator = u64::MAX as u128; let denominator = 5007716u128; let result = fake_exponential(factor, numerator, denominator);
419
420 assert!(result > 0);
422
423 let prague_params = crate::eip7840::BlobParams::prague();
425 let _blob_fee = prague_params.calc_blob_fee(u64::MAX);
427 }
428}