Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: EIP-7742 #1600

Merged
merged 8 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions crates/consensus-any/src/block/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ pub struct AnyHeader {
/// EIP-7685 requests hash.
#[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
pub requests_hash: Option<B256>,
/// EIP-7744 target blob count.
#[cfg_attr(
feature = "serde",
serde(
default,
with = "alloy_serde::quantity::opt",
skip_serializing_if = "Option::is_none"
)
)]
pub target_blobs_per_block: Option<u64>,
}

impl BlockHeader for AnyHeader {
Expand Down Expand Up @@ -178,6 +188,10 @@ impl BlockHeader for AnyHeader {
self.requests_hash
}

fn target_blobs_per_block(&self) -> Option<u64> {
self.target_blobs_per_block
}

fn extra_data(&self) -> &Bytes {
&self.extra_data
}
Expand Down Expand Up @@ -207,6 +221,7 @@ impl From<Header> for AnyHeader {
excess_blob_gas,
parent_beacon_block_root,
requests_hash,
target_blobs_per_block,
} = value;

Self {
Expand All @@ -231,6 +246,7 @@ impl From<Header> for AnyHeader {
excess_blob_gas,
parent_beacon_block_root,
requests_hash,
target_blobs_per_block,
}
}
}
111 changes: 105 additions & 6 deletions crates/consensus/src/block/header.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use crate::constants::{EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH};
use alloc::vec::Vec;
use alloy_eips::{
calc_blob_gasprice,
eip1559::{calc_next_block_base_fee, BaseFeeParams},
eip1898::BlockWithParent,
eip4844::{calc_blob_gasprice, calc_excess_blob_gas},
eip4844::{self},
eip7742,
merge::ALLOWED_FUTURE_BLOCK_TIME_SECONDS,
BlockNumHash,
};
Expand Down Expand Up @@ -125,6 +127,18 @@ pub struct Header {
/// [EIP-7685]: https://eips.ethereum.org/EIPS/eip-7685
#[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
pub requests_hash: Option<B256>,
/// The target number of blobs in the block, introduced in [EIP-7742].
///
/// [EIP-7742]: https://eips.ethereum.org/EIPS/eip-7742
#[cfg_attr(
feature = "serde",
serde(
default,
with = "alloy_serde::quantity::opt",
skip_serializing_if = "Option::is_none"
)
)]
pub target_blobs_per_block: Option<u64>,
}

impl AsRef<Self> for Header {
Expand Down Expand Up @@ -157,6 +171,7 @@ impl Default for Header {
excess_blob_gas: None,
parent_beacon_block_root: None,
requests_hash: None,
target_blobs_per_block: None,
}
}
}
Expand Down Expand Up @@ -206,9 +221,18 @@ impl Header {
///
/// Returns `None` if `excess_blob_gas` is None.
///
/// If [`Self::target_blobs_per_block`] is [`Some`], uses EIP-7742 formula for calculating
/// the blob gas price, otherwise uses EIP-4844 formula.
///
/// See also [Self::next_block_excess_blob_gas]
pub fn next_block_blob_fee(&self) -> Option<u128> {
self.next_block_excess_blob_gas().map(calc_blob_gasprice)
let next_block_excess_blob_gas = self.next_block_excess_blob_gas()?;

if self.target_blobs_per_block().is_none() {
Some(eip4844::calc_blob_gasprice(next_block_excess_blob_gas))
} else {
Some(eip7742::calc_blob_gasprice(next_block_excess_blob_gas))
}
}

/// Calculate base fee for next block according to the EIP-1559 spec.
Expand All @@ -226,9 +250,27 @@ impl Header {
/// Calculate excess blob gas for the next block according to the EIP-4844
/// spec.
///
/// If [`Self::target_blobs_per_block`] is [`Some`], uses EIP-7742 formula for calculating
/// the excess blob gas, otherwise uses EIP-4844 formula.
///
/// Note: this function will return incorrect (unnormalized, lower) value at EIP-7742 activation
/// block. If this is undesired, consider using [`eip7742::calc_excess_blob_gas_at_transition`].
///
/// Returns a `None` if no excess blob gas is set, no EIP-4844 support
pub fn next_block_excess_blob_gas(&self) -> Option<u64> {
Some(calc_excess_blob_gas(self.excess_blob_gas?, self.blob_gas_used?))
let excess_blob_gas = self.excess_blob_gas?;
let blob_gas_used = self.blob_gas_used?;

Some(self.target_blobs_per_block.map_or_else(
|| eip4844::calc_excess_blob_gas(excess_blob_gas, blob_gas_used),
|target_blobs_per_block| {
eip7742::calc_excess_blob_gas(
excess_blob_gas,
blob_gas_used,
target_blobs_per_block,
)
},
))
}

/// Calculate a heuristic for the in-memory size of the [Header].
Expand Down Expand Up @@ -303,6 +345,10 @@ impl Header {
length += requests_hash.length();
}

if let Some(target_blobs_per_block) = self.target_blobs_per_block {
length += target_blobs_per_block.length();
}

length
}

Expand Down Expand Up @@ -403,6 +449,10 @@ impl Encodable for Header {
if let Some(ref requests_hash) = self.requests_hash {
requests_hash.encode(out);
}

if let Some(ref target_blobs_per_block) = self.target_blobs_per_block {
target_blobs_per_block.encode(out);
}
}

fn length(&self) -> usize {
Expand Down Expand Up @@ -442,6 +492,7 @@ impl Decodable for Header {
excess_blob_gas: None,
parent_beacon_block_root: None,
requests_hash: None,
target_blobs_per_block: None,
};
if started_len - buf.len() < rlp_head.payload_length {
this.base_fee_per_gas = Some(u64::decode(buf)?);
Expand Down Expand Up @@ -471,6 +522,11 @@ impl Decodable for Header {
this.requests_hash = Some(B256::decode(buf)?);
}

// Decode target blob count.
if started_len - buf.len() < rlp_head.payload_length {
this.target_blobs_per_block = Some(u64::decode(buf)?);
}

let consumed = started_len - buf.len();
if consumed != rlp_head.payload_length {
return Err(alloy_rlp::Error::ListLengthMismatch {
Expand Down Expand Up @@ -547,6 +603,7 @@ impl<'a> arbitrary::Arbitrary<'a> for Header {
parent_beacon_block_root: u.arbitrary()?,
requests_hash: u.arbitrary()?,
withdrawals_root: u.arbitrary()?,
target_blobs_per_block: u.arbitrary()?,
};

Ok(generate_valid_header(
Expand Down Expand Up @@ -622,24 +679,54 @@ pub trait BlockHeader {
/// Retrieves the requests hash of the block, if available
fn requests_hash(&self) -> Option<B256>;

/// Retrieves the target blob count of the block, if available
fn target_blobs_per_block(&self) -> Option<u64>;

/// Retrieves the block's extra data field
fn extra_data(&self) -> &Bytes;

/// Calculate excess blob gas for the next block according to the EIP-4844
/// spec.
///
/// If [`BlockHeader::target_blobs_per_block`] is [`Some`], uses EIP-7742 formula for
/// calculating the excess blob gas, otherwise uses EIP-4844 formula.
///
/// Note: this function will return incorrect (unnormalized, lower) value at EIP-7742 activation
/// block. If this is undesired, consider using [`eip7742::calc_excess_blob_gas_at_transition`].
Comment on lines +694 to +695
Copy link
Member Author

@klkvr klkvr Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be OK as I'd expect all consumers of this to not know whether the next block activates 7742 unless it's an EL

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this mean we need a special check for the transition block in reth?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep

///
/// Returns a `None` if no excess blob gas is set, no EIP-4844 support
fn next_block_excess_blob_gas(&self) -> Option<u64> {
Some(calc_excess_blob_gas(self.excess_blob_gas()?, self.blob_gas_used()?))
let excess_blob_gas = self.excess_blob_gas()?;
let blob_gas_used = self.blob_gas_used()?;

Some(self.target_blobs_per_block().map_or_else(
|| eip4844::calc_excess_blob_gas(excess_blob_gas, blob_gas_used),
|target_blobs_per_block| {
eip7742::calc_excess_blob_gas(
excess_blob_gas,
blob_gas_used,
target_blobs_per_block,
)
},
))
}

/// Returns the blob fee for the next block according to the EIP-4844 spec.
///
/// Returns `None` if `excess_blob_gas` is None.
///
/// See also [Self::next_block_excess_blob_gas]
/// If this header has `target_blobs_per_block` set, uses EIP-7742 formula for calculating
/// the blob gas price, otherwise uses EIP-4844 formula.
///
/// See also [BlockHeader::next_block_excess_blob_gas]
fn next_block_blob_fee(&self) -> Option<u128> {
self.next_block_excess_blob_gas().map(calc_blob_gasprice)
let next_block_excess_blob_gas = self.next_block_excess_blob_gas()?;

if self.target_blobs_per_block().is_none() {
Some(eip4844::calc_blob_gasprice(next_block_excess_blob_gas))
} else {
Some(eip7742::calc_blob_gasprice(next_block_excess_blob_gas))
}
}

/// Calculate base fee for next block according to the EIP-1559 spec.
Expand Down Expand Up @@ -743,6 +830,10 @@ impl BlockHeader for Header {
self.requests_hash
}

fn target_blobs_per_block(&self) -> Option<u64> {
self.target_blobs_per_block
}

fn extra_data(&self) -> &Bytes {
&self.extra_data
}
Expand Down Expand Up @@ -833,6 +924,10 @@ impl<T: BlockHeader> BlockHeader for alloy_serde::WithOtherFields<T> {
fn requests_hash(&self) -> Option<B256> {
self.inner.requests_hash()
}

fn target_blobs_per_block(&self) -> Option<u64> {
self.inner.target_blobs_per_block()
}
}

/// Bincode-compatibl [`Header`] serde implementation.
Expand Down Expand Up @@ -886,6 +981,8 @@ pub(crate) mod serde_bincode_compat {
parent_beacon_block_root: Option<B256>,
#[serde(default)]
requests_hash: Option<B256>,
#[serde(default)]
target_blobs_per_block: Option<u64>,
extra_data: Cow<'a, Bytes>,
}

Expand Down Expand Up @@ -913,6 +1010,7 @@ pub(crate) mod serde_bincode_compat {
parent_beacon_block_root: value.parent_beacon_block_root,
requests_hash: value.requests_hash,
extra_data: Cow::Borrowed(&value.extra_data),
target_blobs_per_block: value.target_blobs_per_block,
}
}
}
Expand Down Expand Up @@ -941,6 +1039,7 @@ pub(crate) mod serde_bincode_compat {
parent_beacon_block_root: value.parent_beacon_block_root,
requests_hash: value.requests_hash,
extra_data: value.extra_data.into_owned(),
target_blobs_per_block: value.target_blobs_per_block,
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/eips/src/eip4844/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ pub fn calc_blob_gasprice(excess_blob_gas: u64) -> u128 {
///
/// This function panics if `denominator` is zero.
#[inline]
fn fake_exponential(factor: u128, numerator: u128, denominator: u128) -> u128 {
pub fn fake_exponential(factor: u128, numerator: u128, denominator: u128) -> u128 {
assert_ne!(denominator, 0, "attempt to divide by zero");

let mut i = 1;
Expand Down
65 changes: 65 additions & 0 deletions crates/eips/src/eip7742.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//! Contains constants and utility functions for [EIP-7742](https://eips.ethereum.org/EIPS/eip-7742)

use crate::eip4844::{self, fake_exponential, BLOB_TX_MIN_BLOB_GASPRICE, DATA_GAS_PER_BLOB};

/// Controls the update rate of the blob base fee based on `target_blobs_per_block`.
pub const BLOB_BASE_FEE_UPDATE_FRACTION_PER_TARGET_BLOB: u128 = 1112825;

/// Controls the update rate of the blob base fee based on `target_blobs_per_block`.
pub const EXCESS_BLOB_GAS_NORMALIZATION_TARGET: u64 = 128;

/// Same as [`eip4844::BLOB_GASPRICE_UPDATE_FRACTION`], but normalized for the target of 128
/// blobs.
pub const BLOB_BASE_FEE_UPDATE_FRACTION_NORMALIZED: u128 =
BLOB_BASE_FEE_UPDATE_FRACTION_PER_TARGET_BLOB * EXCESS_BLOB_GAS_NORMALIZATION_TARGET as u128;

/// Calculates the `excess_blob_gas` for the header of the block enabling EIP-7742.
///
/// Normalizes the parent's excess blob gas as per EIP-7742.
#[inline]
pub const fn calc_excess_blob_gas_at_transition(
parent_excess_blob_gas: u64,
parent_blob_gas_used: u64,
parent_target_blobs_per_block: u64,
) -> u64 {
let normalized_parent_excess_blob_gas = parent_excess_blob_gas
* EXCESS_BLOB_GAS_NORMALIZATION_TARGET
/ eip4844::TARGET_BLOBS_PER_BLOCK;

calc_excess_blob_gas(
normalized_parent_excess_blob_gas,
parent_blob_gas_used,
parent_target_blobs_per_block,
)
}

/// Calculates the `excess_blob_gas` from the parent header's `blob_gas_used`, `excess_blob_gas` and
/// `target_blobs_per_block`.
///
/// Note: this function assumes that the parent block's excess blob gas is normalized as per
/// EIP-7742.
#[inline]
pub const fn calc_excess_blob_gas(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit concerned that this will be easy to misuse if the functions have the same name, but since this takes an additional param this is okay imo

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

those are now completely identical :/ EIP-7742 just expects a normalized excess gas

should we rename the new one?

parent_excess_blob_gas: u64,
parent_blob_gas_used: u64,
parent_target_blobs_per_block: u64,
) -> u64 {
let normalized_blob_gas_used =
parent_blob_gas_used * EXCESS_BLOB_GAS_NORMALIZATION_TARGET / parent_target_blobs_per_block;
let normalized_target_blob_gas = DATA_GAS_PER_BLOB * EXCESS_BLOB_GAS_NORMALIZATION_TARGET;

(parent_excess_blob_gas + normalized_blob_gas_used).saturating_sub(normalized_target_blob_gas)
}

/// Calculates the blob gas price from the header's excess blob gas field.
///
/// Similar to [crate::eip4844::calc_blob_gasprice], but adjusts the update rate based on
/// `target_blobs_per_block`.
#[inline]
pub fn calc_blob_gasprice(excess_blob_gas: u64) -> u128 {
fake_exponential(
BLOB_TX_MIN_BLOB_GASPRICE,
excess_blob_gas as u128,
BLOB_BASE_FEE_UPDATE_FRACTION_NORMALIZED,
)
}
2 changes: 2 additions & 0 deletions crates/eips/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,5 @@ pub mod eip7251;
pub mod eip7685;

pub mod eip7702;

pub mod eip7742;
10 changes: 6 additions & 4 deletions crates/provider/src/fillers/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,12 +226,14 @@ where
}
}

provider
let latest_block = provider
.get_block_by_number(BlockNumberOrTag::Latest, BlockTransactionsKind::Hashes)
.await?
.ok_or(RpcError::NullResp)?
.header()
.as_ref()
.ok_or(RpcError::NullResp)?;

let latest_header = latest_block.header().as_ref();

latest_header
.next_block_blob_fee()
.map(Into::into)
.ok_or(RpcError::UnsupportedFeature("eip4844"))
Expand Down
Loading