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>
133where
134 D: serde::de::Deserializer<'de>,
135{
136 serde::Deserialize::deserialize(deserializer)
137}
138
139#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, alloy_rlp::RlpEncodableWrapper)]
141pub struct HeapBlob(Bytes);
142
143impl HeapBlob {
144 pub fn new(blob: &[u8]) -> Result<Self, InvalidBlobLength> {
146 if blob.len() != BYTES_PER_BLOB {
147 return Err(InvalidBlobLength(blob.len()));
148 }
149
150 Ok(Self(Bytes::copy_from_slice(blob)))
151 }
152
153 pub fn from_array(blob: [u8; BYTES_PER_BLOB]) -> Self {
155 Self(Bytes::from(blob))
156 }
157
158 pub fn from_bytes(bytes: Bytes) -> Result<Self, InvalidBlobLength> {
160 if bytes.len() != BYTES_PER_BLOB {
161 return Err(InvalidBlobLength(bytes.len()));
162 }
163
164 Ok(Self(bytes))
165 }
166
167 pub fn repeat_byte(byte: u8) -> Self {
169 Self(Bytes::from(vec![byte; BYTES_PER_BLOB]))
170 }
171
172 pub const fn inner(&self) -> &Bytes {
174 &self.0
175 }
176}
177
178impl Default for HeapBlob {
179 fn default() -> Self {
180 Self::repeat_byte(0)
181 }
182}
183
184#[derive(Debug, Clone)]
186pub struct InvalidBlobLength(usize);
187impl core::fmt::Display for InvalidBlobLength {
188 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
189 write!(f, "Invalid blob length: {}, expected: {BYTES_PER_BLOB}", self.0)
190 }
191}
192impl core::error::Error for InvalidBlobLength {}
193
194#[cfg(feature = "serde")]
195impl serde::Serialize for HeapBlob {
196 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
197 where
198 S: serde::Serializer,
199 {
200 self.inner().serialize(serializer)
201 }
202}
203
204#[cfg(any(test, feature = "arbitrary"))]
205impl<'a> arbitrary::Arbitrary<'a> for HeapBlob {
206 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
207 let mut blob = vec![0u8; BYTES_PER_BLOB];
208 u.fill_buffer(&mut blob)?;
209 Ok(Self(Bytes::from(blob)))
210 }
211}
212
213#[cfg(feature = "serde")]
214impl<'de> serde::Deserialize<'de> for HeapBlob {
215 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
216 where
217 D: serde::de::Deserializer<'de>,
218 {
219 let inner = <Bytes>::deserialize(deserializer)?;
220
221 Self::from_bytes(inner).map_err(serde::de::Error::custom)
222 }
223}
224
225impl alloy_rlp::Decodable for HeapBlob {
226 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
227 let bytes = <Bytes>::decode(buf)?;
228
229 Self::from_bytes(bytes).map_err(|_| alloy_rlp::Error::Custom("invalid blob length"))
230 }
231}
232
233pub type Bytes48 = FixedBytes<48>;
235
236#[cfg(feature = "sha2")]
244pub fn kzg_to_versioned_hash(commitment: &[u8]) -> B256 {
245 use sha2::Digest;
246
247 debug_assert_eq!(commitment.len(), 48, "commitment length is not 48");
248 let mut res = sha2::Sha256::digest(commitment);
249 res[0] = VERSIONED_HASH_VERSION_KZG;
250 B256::new(res.into())
251}
252
253#[inline]
258pub const fn calc_excess_blob_gas(parent_excess_blob_gas: u64, parent_blob_gas_used: u64) -> u64 {
259 eip7840::BlobParams::cancun().next_block_excess_blob_gas_osaka(
260 parent_excess_blob_gas,
261 parent_blob_gas_used,
262 0,
264 )
265}
266
267#[inline]
272pub const fn calc_blob_gasprice(excess_blob_gas: u64) -> u128 {
273 eip7840::BlobParams::cancun().calc_blob_fee(excess_blob_gas)
274}
275
276#[inline]
287pub const fn fake_exponential(factor: u128, numerator: u128, denominator: u128) -> u128 {
288 assert!(denominator != 0, "attempt to divide by zero");
289
290 let mut i = 1;
291 let mut output = 0;
292 let mut numerator_accum = factor * denominator;
293 while numerator_accum > 0 {
294 output += numerator_accum;
295
296 let Some(val) = numerator_accum.checked_mul(numerator) else {
298 break;
299 };
300
301 numerator_accum = val / (denominator * i);
303 i += 1;
304 }
305 output / denominator
306}
307
308#[cfg(test)]
309mod tests {
310 use super::*;
311
312 #[test]
314 fn test_calc_excess_blob_gas() {
315 for t @ &(excess, blobs, expected) in &[
316 (0, 0, 0),
319 (0, 1, 0),
320 (0, TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB, 0),
321 (0, (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) + 1, DATA_GAS_PER_BLOB),
324 (1, (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) + 1, DATA_GAS_PER_BLOB + 1),
325 (
326 1,
327 (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) + 2,
328 2 * DATA_GAS_PER_BLOB + 1,
329 ),
330 (
333 TARGET_DATA_GAS_PER_BLOCK_DENCUN,
334 TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB,
335 TARGET_DATA_GAS_PER_BLOCK_DENCUN,
336 ),
337 (
338 TARGET_DATA_GAS_PER_BLOCK_DENCUN,
339 (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) - 1,
340 TARGET_DATA_GAS_PER_BLOCK_DENCUN - DATA_GAS_PER_BLOB,
341 ),
342 (
343 TARGET_DATA_GAS_PER_BLOCK_DENCUN,
344 (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) - 2,
345 TARGET_DATA_GAS_PER_BLOCK_DENCUN - (2 * DATA_GAS_PER_BLOB),
346 ),
347 (DATA_GAS_PER_BLOB - 1, (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) - 1, 0),
348 ] {
349 let actual = calc_excess_blob_gas(excess, blobs * DATA_GAS_PER_BLOB);
350 assert_eq!(actual, expected, "test: {t:?}");
351 }
352 }
353
354 #[test]
356 fn test_calc_blob_fee() {
357 let blob_fee_vectors = &[
358 (0, 1),
359 (2314057, 1),
360 (2314058, 2),
361 (10 * 1024 * 1024, 23),
362 (148099578, 18446739238971471609), (148099579, 18446744762204311910), (161087488, 902580055246494526580),
371 ];
372
373 for &(excess, expected) in blob_fee_vectors {
374 let actual = calc_blob_gasprice(excess);
375 assert_eq!(actual, expected, "test: {excess}");
376 }
377 }
378
379 #[test]
381 fn fake_exp() {
382 for t @ &(factor, numerator, denominator, expected) in &[
383 (1u64, 0u64, 1u64, 1u128),
384 (38493, 0, 1000, 38493),
385 (0, 1234, 2345, 0),
386 (1, 2, 1, 6), (1, 4, 2, 6),
388 (1, 3, 1, 16), (1, 6, 2, 18),
390 (1, 4, 1, 49), (1, 8, 2, 50),
392 (10, 8, 2, 542), (11, 8, 2, 596), (1, 5, 1, 136), (1, 5, 2, 11), (2, 5, 2, 23), (1, 50000000, 2225652, 5709098764),
398 (1, 380928, BLOB_GASPRICE_UPDATE_FRACTION.try_into().unwrap(), 1),
399 ] {
400 let actual = fake_exponential(factor as u128, numerator as u128, denominator as u128);
401 assert_eq!(actual, expected, "test: {t:?}");
402 }
403 }
404
405 #[test]
406 #[cfg(feature = "serde")]
407 fn serde_heap_blob() {
408 let blob = HeapBlob::repeat_byte(0x42);
409 let serialized = serde_json::to_string(&blob).unwrap();
410
411 let deserialized: HeapBlob = serde_json::from_str(&serialized).unwrap();
412 assert_eq!(blob, deserialized);
413 }
414
415 #[test]
416 fn fake_exp_handles_overflow() {
417 let factor = 1u128; let numerator = u64::MAX as u128; let denominator = 5007716u128; let result = fake_exponential(factor, numerator, denominator);
424
425 assert!(result > 0);
427
428 let prague_params = crate::eip7840::BlobParams::prague();
430 let _blob_fee = prague_params.calc_blob_fee(u64::MAX);
432 }
433}