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
63#[deprecated(
65 since = "0.15.3",
66 note = "use hardfork specific MAX_DATA_GAS_PER_BLOCK_DENCUN constant or `BlobParams::max_blob_gas_per_block`"
67)]
68pub const MAX_DATA_GAS_PER_BLOCK: u64 = MAX_DATA_GAS_PER_BLOCK_DENCUN;
69
70pub const MAX_DATA_GAS_PER_BLOCK_DENCUN: u64 = 786_432u64; #[deprecated(
75 since = "0.15.3",
76 note = "use hardfork specific TARGET_DATA_GAS_PER_BLOCK_DENCUN constant or `BlobParams::target_blob_gas_per_block`"
77)]
78pub const TARGET_DATA_GAS_PER_BLOCK: u64 = TARGET_DATA_GAS_PER_BLOCK_DENCUN;
79
80pub const TARGET_DATA_GAS_PER_BLOCK_DENCUN: u64 = 393_216u64; #[deprecated(
85 since = "0.15.3",
86 note = "use hardfork specific MAX_BLOBS_PER_BLOCK_DENCUN constant or `BlobParams.max_blob_count`"
87)]
88pub const MAX_BLOBS_PER_BLOCK: usize = MAX_BLOBS_PER_BLOCK_DENCUN; pub const MAX_BLOBS_PER_BLOCK_DENCUN: usize =
92 (MAX_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) as usize; #[deprecated(
96 since = "0.15.3",
97 note = "use hardfork specific TARGET_BLOBS_PER_BLOCK_DENCUN constant or `BlobParams.target_blob_count`"
98)]
99pub const TARGET_BLOBS_PER_BLOCK: u64 = TARGET_BLOBS_PER_BLOCK_DENCUN; 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;
109
110pub const VERSIONED_HASH_VERSION_KZG: u8 = 0x01;
112
113pub const BYTES_PER_COMMITMENT: usize = 48;
115
116pub const BYTES_PER_PROOF: usize = 48;
118
119pub type Blob = FixedBytes<BYTES_PER_BLOB>;
121
122#[cfg(feature = "serde")]
124pub fn deserialize_blob<'de, D>(deserializer: D) -> Result<alloc::boxed::Box<Blob>, D::Error>
125where
126 D: serde::de::Deserializer<'de>,
127{
128 use serde::Deserialize;
129 let raw_blob = <alloy_primitives::Bytes>::deserialize(deserializer)?;
130 let blob = alloc::boxed::Box::new(
131 Blob::try_from(raw_blob.as_ref()).map_err(serde::de::Error::custom)?,
132 );
133 Ok(blob)
134}
135
136#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, alloy_rlp::RlpEncodableWrapper)]
138pub struct HeapBlob(Bytes);
139
140impl HeapBlob {
141 pub fn new(blob: &[u8]) -> Result<Self, InvalidBlobLength> {
143 if blob.len() != BYTES_PER_BLOB {
144 return Err(InvalidBlobLength(blob.len()));
145 }
146
147 Ok(Self(Bytes::copy_from_slice(blob)))
148 }
149
150 pub fn from_array(blob: [u8; BYTES_PER_BLOB]) -> Self {
152 Self(Bytes::from(blob))
153 }
154
155 pub fn from_bytes(bytes: Bytes) -> Result<Self, InvalidBlobLength> {
157 if bytes.len() != BYTES_PER_BLOB {
158 return Err(InvalidBlobLength(bytes.len()));
159 }
160
161 Ok(Self(bytes))
162 }
163
164 pub fn repeat_byte(byte: u8) -> Self {
166 Self(Bytes::from(vec![byte; BYTES_PER_BLOB]))
167 }
168
169 pub const fn inner(&self) -> &Bytes {
171 &self.0
172 }
173}
174
175impl Default for HeapBlob {
176 fn default() -> Self {
177 Self::repeat_byte(0)
178 }
179}
180
181#[derive(Debug, Clone)]
183pub struct InvalidBlobLength(usize);
184impl core::fmt::Display for InvalidBlobLength {
185 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
186 write!(f, "Invalid blob length: {}, expected: {BYTES_PER_BLOB}", self.0)
187 }
188}
189impl core::error::Error for InvalidBlobLength {}
190
191#[cfg(feature = "serde")]
192impl serde::Serialize for HeapBlob {
193 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
194 where
195 S: serde::Serializer,
196 {
197 self.inner().serialize(serializer)
198 }
199}
200
201#[cfg(any(test, feature = "arbitrary"))]
202impl<'a> arbitrary::Arbitrary<'a> for HeapBlob {
203 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
204 let mut blob = vec![0u8; BYTES_PER_BLOB];
205 u.fill_buffer(&mut blob)?;
206 Ok(Self(Bytes::from(blob)))
207 }
208}
209
210#[cfg(feature = "serde")]
211impl<'de> serde::Deserialize<'de> for HeapBlob {
212 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
213 where
214 D: serde::de::Deserializer<'de>,
215 {
216 let inner = <Bytes>::deserialize(deserializer)?;
217
218 Self::from_bytes(inner).map_err(serde::de::Error::custom)
219 }
220}
221
222impl alloy_rlp::Decodable for HeapBlob {
223 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
224 let bytes = <Bytes>::decode(buf)?;
225
226 Self::from_bytes(bytes).map_err(|_| alloy_rlp::Error::Custom("invalid blob length"))
227 }
228}
229
230pub type Bytes48 = FixedBytes<48>;
232
233#[cfg(feature = "sha2")]
241pub fn kzg_to_versioned_hash(commitment: &[u8]) -> B256 {
242 use sha2::Digest;
243
244 debug_assert_eq!(commitment.len(), 48, "commitment length is not 48");
245 let mut res = sha2::Sha256::digest(commitment);
246 res[0] = VERSIONED_HASH_VERSION_KZG;
247 B256::new(res.into())
248}
249
250#[inline]
255pub const fn calc_excess_blob_gas(parent_excess_blob_gas: u64, parent_blob_gas_used: u64) -> u64 {
256 eip7840::BlobParams::cancun()
257 .next_block_excess_blob_gas(parent_excess_blob_gas, parent_blob_gas_used)
258}
259
260#[inline]
265pub const fn calc_blob_gasprice(excess_blob_gas: u64) -> u128 {
266 eip7840::BlobParams::cancun().calc_blob_fee(excess_blob_gas)
267}
268
269#[inline]
280pub const fn fake_exponential(factor: u128, numerator: u128, denominator: u128) -> u128 {
281 assert!(denominator != 0, "attempt to divide by zero");
282
283 let mut i = 1;
284 let mut output = 0;
285 let mut numerator_accum = factor * denominator;
286 while numerator_accum > 0 {
287 output += numerator_accum;
288
289 numerator_accum = (numerator_accum * numerator) / (denominator * i);
291 i += 1;
292 }
293 output / denominator
294}
295
296#[cfg(test)]
297mod tests {
298 use super::*;
299
300 #[test]
302 fn test_calc_excess_blob_gas() {
303 for t @ &(excess, blobs, expected) in &[
304 (0, 0, 0),
307 (0, 1, 0),
308 (0, TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB, 0),
309 (0, (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) + 1, DATA_GAS_PER_BLOB),
312 (1, (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) + 1, DATA_GAS_PER_BLOB + 1),
313 (
314 1,
315 (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) + 2,
316 2 * DATA_GAS_PER_BLOB + 1,
317 ),
318 (
321 TARGET_DATA_GAS_PER_BLOCK_DENCUN,
322 TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB,
323 TARGET_DATA_GAS_PER_BLOCK_DENCUN,
324 ),
325 (
326 TARGET_DATA_GAS_PER_BLOCK_DENCUN,
327 (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) - 1,
328 TARGET_DATA_GAS_PER_BLOCK_DENCUN - DATA_GAS_PER_BLOB,
329 ),
330 (
331 TARGET_DATA_GAS_PER_BLOCK_DENCUN,
332 (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) - 2,
333 TARGET_DATA_GAS_PER_BLOCK_DENCUN - (2 * DATA_GAS_PER_BLOB),
334 ),
335 (DATA_GAS_PER_BLOB - 1, (TARGET_DATA_GAS_PER_BLOCK_DENCUN / DATA_GAS_PER_BLOB) - 1, 0),
336 ] {
337 let actual = calc_excess_blob_gas(excess, blobs * DATA_GAS_PER_BLOB);
338 assert_eq!(actual, expected, "test: {t:?}");
339 }
340 }
341
342 #[test]
344 fn test_calc_blob_fee() {
345 let blob_fee_vectors = &[
346 (0, 1),
347 (2314057, 1),
348 (2314058, 2),
349 (10 * 1024 * 1024, 23),
350 (148099578, 18446739238971471609), (148099579, 18446744762204311910), (161087488, 902580055246494526580),
359 ];
360
361 for &(excess, expected) in blob_fee_vectors {
362 let actual = calc_blob_gasprice(excess);
363 assert_eq!(actual, expected, "test: {excess}");
364 }
365 }
366
367 #[test]
369 fn fake_exp() {
370 for t @ &(factor, numerator, denominator, expected) in &[
371 (1u64, 0u64, 1u64, 1u128),
372 (38493, 0, 1000, 38493),
373 (0, 1234, 2345, 0),
374 (1, 2, 1, 6), (1, 4, 2, 6),
376 (1, 3, 1, 16), (1, 6, 2, 18),
378 (1, 4, 1, 49), (1, 8, 2, 50),
380 (10, 8, 2, 542), (11, 8, 2, 596), (1, 5, 1, 136), (1, 5, 2, 11), (2, 5, 2, 23), (1, 50000000, 2225652, 5709098764),
386 (1, 380928, BLOB_GASPRICE_UPDATE_FRACTION.try_into().unwrap(), 1),
387 ] {
388 let actual = fake_exponential(factor as u128, numerator as u128, denominator as u128);
389 assert_eq!(actual, expected, "test: {t:?}");
390 }
391 }
392
393 #[test]
394 #[cfg(feature = "serde")]
395 fn serde_heap_blob() {
396 let blob = HeapBlob::repeat_byte(0x42);
397 let serialized = serde_json::to_string(&blob).unwrap();
398
399 let deserialized: HeapBlob = serde_json::from_str(&serialized).unwrap();
400 assert_eq!(blob, deserialized);
401 }
402}