1#[cfg(feature = "kzg")]
7pub use c_kzg;
8
9#[cfg(feature = "kzg")]
11pub mod env_settings;
12#[cfg(feature = "kzg")]
14pub mod trusted_setup_points;
15
16pub mod builder;
18pub mod utils;
19
20mod engine;
21pub use engine::*;
22
23#[cfg(feature = "kzg-sidecar")]
25mod sidecar;
26#[cfg(feature = "kzg-sidecar")]
27pub use sidecar::*;
28
29use alloy_primitives::{b256, Bytes, FixedBytes, B256, U256};
30
31use crate::eip7840;
32
33pub const BLS_MODULUS_BYTES: B256 =
36 b256!("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001");
37
38pub const BLS_MODULUS: U256 = U256::from_be_bytes(BLS_MODULUS_BYTES.0);
41
42pub const FIELD_ELEMENT_BYTES: u64 = 32;
44
45pub const FIELD_ELEMENT_BYTES_USIZE: usize = FIELD_ELEMENT_BYTES as usize;
47
48pub const FIELD_ELEMENTS_PER_BLOB: u64 = 4096;
50
51pub const USABLE_BITS_PER_FIELD_ELEMENT: usize = 254;
53
54pub const USABLE_BYTES_PER_BLOB: usize =
58 USABLE_BITS_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB as usize / 8;
59
60pub const DATA_GAS_PER_BLOB: u64 = 131_072u64; pub const BYTES_PER_BLOB: usize = 131_072;
66
67pub 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 =
75 (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;
85
86pub const VERSIONED_HASH_VERSION_KZG: u8 = 0x01;
88
89pub const BYTES_PER_COMMITMENT: usize = 48;
91
92pub const BYTES_PER_PROOF: usize = 48;
94
95pub type Blob = FixedBytes<BYTES_PER_BLOB>;
97
98#[cfg(feature = "serde")]
100pub fn deserialize_blob<'de, D>(deserializer: D) -> Result<alloc::boxed::Box<Blob>, D::Error>
101where
102 D: serde::de::Deserializer<'de>,
103{
104 use serde::Deserialize;
105 let raw_blob = <alloy_primitives::Bytes>::deserialize(deserializer)?;
106 let blob = alloc::boxed::Box::new(
107 Blob::try_from(raw_blob.as_ref()).map_err(serde::de::Error::custom)?,
108 );
109 Ok(blob)
110}
111
112#[cfg(all(debug_assertions, feature = "serde"))]
114pub fn deserialize_blobs<'de, D>(deserializer: D) -> Result<alloc::vec::Vec<Blob>, D::Error>
115where
116 D: serde::de::Deserializer<'de>,
117{
118 use alloc::vec::Vec;
119 use serde::Deserialize;
120
121 let raw_blobs = Vec::<alloy_primitives::Bytes>::deserialize(deserializer)?;
122 let mut blobs = Vec::with_capacity(raw_blobs.len());
123 for blob in raw_blobs {
124 blobs.push(Blob::try_from(blob.as_ref()).map_err(serde::de::Error::custom)?);
125 }
126 Ok(blobs)
127}
128
129#[cfg(all(not(debug_assertions), feature = "serde"))]
130#[inline(always)]
131pub fn deserialize_blobs<'de, D>(deserializer: D) -> Result<alloc::vec::Vec<Blob>, D::Error>
132where
133 D: serde::de::Deserializer<'de>,
134{
135 serde::Deserialize::deserialize(deserializer)
136}
137
138#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, alloy_rlp::RlpEncodableWrapper)]
140pub struct HeapBlob(Bytes);
141
142impl HeapBlob {
143 pub fn new(blob: &[u8]) -> Result<Self, InvalidBlobLength> {
145 if blob.len() != BYTES_PER_BLOB {
146 return Err(InvalidBlobLength(blob.len()));
147 }
148
149 Ok(Self(Bytes::copy_from_slice(blob)))
150 }
151
152 pub fn from_array(blob: [u8; BYTES_PER_BLOB]) -> Self {
154 Self(Bytes::from(blob))
155 }
156
157 pub fn from_bytes(bytes: Bytes) -> Result<Self, InvalidBlobLength> {
159 if bytes.len() != BYTES_PER_BLOB {
160 return Err(InvalidBlobLength(bytes.len()));
161 }
162
163 Ok(Self(bytes))
164 }
165
166 pub fn repeat_byte(byte: u8) -> Self {
168 Self(Bytes::from(vec![byte; BYTES_PER_BLOB]))
169 }
170
171 pub const fn inner(&self) -> &Bytes {
173 &self.0
174 }
175}
176
177impl Default for HeapBlob {
178 fn default() -> Self {
179 Self::repeat_byte(0)
180 }
181}
182
183#[derive(Debug, Clone)]
185pub struct InvalidBlobLength(usize);
186impl core::fmt::Display for InvalidBlobLength {
187 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
188 write!(f, "Invalid blob length: {}, expected: {BYTES_PER_BLOB}", self.0)
189 }
190}
191impl core::error::Error for InvalidBlobLength {}
192
193#[cfg(feature = "serde")]
194impl serde::Serialize for HeapBlob {
195 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
196 where
197 S: serde::Serializer,
198 {
199 self.inner().serialize(serializer)
200 }
201}
202
203#[cfg(any(test, feature = "arbitrary"))]
204impl<'a> arbitrary::Arbitrary<'a> for HeapBlob {
205 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
206 let mut blob = vec![0u8; BYTES_PER_BLOB];
207 u.fill_buffer(&mut blob)?;
208 Ok(Self(Bytes::from(blob)))
209 }
210}
211
212#[cfg(feature = "serde")]
213impl<'de> serde::Deserialize<'de> for HeapBlob {
214 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
215 where
216 D: serde::de::Deserializer<'de>,
217 {
218 let inner = <Bytes>::deserialize(deserializer)?;
219
220 Self::from_bytes(inner).map_err(serde::de::Error::custom)
221 }
222}
223
224impl alloy_rlp::Decodable for HeapBlob {
225 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
226 let bytes = <Bytes>::decode(buf)?;
227
228 Self::from_bytes(bytes).map_err(|_| alloy_rlp::Error::Custom("invalid blob length"))
229 }
230}
231
232pub type Bytes48 = FixedBytes<48>;
234
235#[cfg(feature = "sha2")]
243pub fn kzg_to_versioned_hash(commitment: &[u8]) -> B256 {
244 use sha2::Digest;
245
246 debug_assert_eq!(commitment.len(), 48, "commitment length is not 48");
247 let mut res = sha2::Sha256::digest(commitment);
248 res[0] = VERSIONED_HASH_VERSION_KZG;
249 B256::new(res.into())
250}
251
252#[inline]
257pub const fn calc_excess_blob_gas(parent_excess_blob_gas: u64, parent_blob_gas_used: u64) -> u64 {
258 eip7840::BlobParams::cancun().next_block_excess_blob_gas_osaka(
259 parent_excess_blob_gas,
260 parent_blob_gas_used,
261 0,
263 )
264}
265
266#[inline]
271pub const fn calc_blob_gasprice(excess_blob_gas: u64) -> u128 {
272 eip7840::BlobParams::cancun().calc_blob_fee(excess_blob_gas)
273}
274
275#[inline]
286pub const fn fake_exponential(factor: u128, numerator: u128, denominator: u128) -> u128 {
287 assert!(denominator != 0, "attempt to divide by zero");
288
289 let mut i = 1;
290 let mut output = 0;
291 let mut numerator_accum = factor * denominator;
292 while numerator_accum > 0 {
293 output += numerator_accum;
294
295 let Some(val) = numerator_accum.checked_mul(numerator) else {
297 break;
298 };
299
300 numerator_accum = val / (denominator * i);
302 i += 1;
303 }
304 output / denominator
305}
306
307#[cfg(test)]
308mod tests {
309 use super::*;
310
311 #[test]
313 fn test_calc_excess_blob_gas() {
314 for t @ &(excess, blobs, expected) in &[
315 (0, 0, 0),
318 (0, 1, 0),
319 (0, TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB, 0),
320 (0, (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) + 1, DATA_GAS_PER_BLOB),
323 (1, (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) + 1, DATA_GAS_PER_BLOB + 1),
324 (
325 1,
326 (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) + 2,
327 2 * DATA_GAS_PER_BLOB + 1,
328 ),
329 (
332 TARGET_DATA_GAS_PER_BLOCK_DENCUN,
333 TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB,
334 TARGET_DATA_GAS_PER_BLOCK_DENCUN,
335 ),
336 (
337 TARGET_DATA_GAS_PER_BLOCK_DENCUN,
338 (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) - 1,
339 TARGET_DATA_GAS_PER_BLOCK_DENCUN - DATA_GAS_PER_BLOB,
340 ),
341 (
342 TARGET_DATA_GAS_PER_BLOCK_DENCUN,
343 (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) - 2,
344 TARGET_DATA_GAS_PER_BLOCK_DENCUN - (2 * DATA_GAS_PER_BLOB),
345 ),
346 (DATA_GAS_PER_BLOB - 1, (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) - 1, 0),
347 ] {
348 let actual = calc_excess_blob_gas(excess, blobs * DATA_GAS_PER_BLOB);
349 assert_eq!(actual, expected, "test: {t:?}");
350 }
351 }
352
353 #[test]
355 fn test_calc_blob_fee() {
356 let blob_fee_vectors = &[
357 (0, 1),
358 (2314057, 1),
359 (2314058, 2),
360 (10 * 1024 * 1024, 23),
361 (148099578, 18446739238971471609), (148099579, 18446744762204311910), (161087488, 902580055246494526580),
370 ];
371
372 for &(excess, expected) in blob_fee_vectors {
373 let actual = calc_blob_gasprice(excess);
374 assert_eq!(actual, expected, "test: {excess}");
375 }
376 }
377
378 #[test]
380 fn fake_exp() {
381 for t @ &(factor, numerator, denominator, expected) in &[
382 (1u64, 0u64, 1u64, 1u128),
383 (38493, 0, 1000, 38493),
384 (0, 1234, 2345, 0),
385 (1, 2, 1, 6), (1, 4, 2, 6),
387 (1, 3, 1, 16), (1, 6, 2, 18),
389 (1, 4, 1, 49), (1, 8, 2, 50),
391 (10, 8, 2, 542), (11, 8, 2, 596), (1, 5, 1, 136), (1, 5, 2, 11), (2, 5, 2, 23), (1, 50000000, 2225652, 5709098764),
397 (1, 380928, BLOB_GASPRICE_UPDATE_FRACTION.try_into().unwrap(), 1),
398 ] {
399 let actual = fake_exponential(factor as u128, numerator as u128, denominator as u128);
400 assert_eq!(actual, expected, "test: {t:?}");
401 }
402 }
403
404 #[test]
405 #[cfg(feature = "serde")]
406 fn serde_heap_blob() {
407 let blob = HeapBlob::repeat_byte(0x42);
408 let serialized = serde_json::to_string(&blob).unwrap();
409
410 let deserialized: HeapBlob = serde_json::from_str(&serialized).unwrap();
411 assert_eq!(blob, deserialized);
412 }
413
414 #[test]
415 fn fake_exp_handles_overflow() {
416 let factor = 1u128; let numerator = u64::MAX as u128; let denominator = 5007716u128; let result = fake_exponential(factor, numerator, denominator);
423
424 assert!(result > 0);
426
427 let prague_params = crate::eip7840::BlobParams::prague();
429 let _blob_fee = prague_params.calc_blob_fee(u64::MAX);
431 }
432}