Skip to content

Commit

Permalink
feat: Eip1559 params in extradata (#11887)
Browse files Browse the repository at this point in the history
Co-authored-by: Dan Cline <[email protected]>
Co-authored-by: Matthias Seitz <[email protected]>
  • Loading branch information
3 people authored Oct 30, 2024
1 parent 2778ba3 commit 93a9b8a
Show file tree
Hide file tree
Showing 16 changed files with 461 additions and 43 deletions.
2 changes: 1 addition & 1 deletion crates/ethereum/engine-primitives/src/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ impl From<EthBuiltPayload> for ExecutionPayloadEnvelopeV4 {
}

/// Container type for all components required to build a payload.
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct EthPayloadBuilderAttributes {
/// Id of the payload
pub id: PayloadId,
Expand Down
7 changes: 5 additions & 2 deletions crates/ethereum/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

extern crate alloc;

use core::convert::Infallible;

use alloc::{sync::Arc, vec::Vec};
use alloy_primitives::{Address, Bytes, TxKind, U256};
use reth_chainspec::{ChainSpec, Head};
Expand Down Expand Up @@ -59,6 +61,7 @@ impl EthEvmConfig {

impl ConfigureEvmEnv for EthEvmConfig {
type Header = Header;
type Error = Infallible;

fn fill_tx_env(&self, tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address) {
transaction.fill_tx_env(tx_env, sender);
Expand Down Expand Up @@ -131,7 +134,7 @@ impl ConfigureEvmEnv for EthEvmConfig {
&self,
parent: &Self::Header,
attributes: NextBlockEnvAttributes,
) -> (CfgEnvWithHandlerCfg, BlockEnv) {
) -> Result<(CfgEnvWithHandlerCfg, BlockEnv), Self::Error> {
// configure evm env based on parent block
let cfg = CfgEnv::default().with_chain_id(self.chain_spec.chain().id());

Expand Down Expand Up @@ -179,7 +182,7 @@ impl ConfigureEvmEnv for EthEvmConfig {
blob_excess_gas_and_price,
};

(CfgEnvWithHandlerCfg::new_with_spec_id(cfg, spec_id), block_env)
Ok((CfgEnvWithHandlerCfg::new_with_spec_id(cfg, spec_id), block_env))
}
}

Expand Down
10 changes: 7 additions & 3 deletions crates/ethereum/payload/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ where
&self,
config: &PayloadConfig<EthPayloadBuilderAttributes>,
parent: &Header,
) -> (CfgEnvWithHandlerCfg, BlockEnv) {
) -> Result<(CfgEnvWithHandlerCfg, BlockEnv), EvmConfig::Error> {
let next_attributes = NextBlockEnvAttributes {
timestamp: config.attributes.timestamp(),
suggested_fee_recipient: config.attributes.suggested_fee_recipient(),
Expand All @@ -97,7 +97,9 @@ where
&self,
args: BuildArguments<Pool, Client, EthPayloadBuilderAttributes, EthBuiltPayload>,
) -> Result<BuildOutcome<EthBuiltPayload>, PayloadBuilderError> {
let (cfg_env, block_env) = self.cfg_and_block_env(&args.config, &args.config.parent_header);
let (cfg_env, block_env) = self
.cfg_and_block_env(&args.config, &args.config.parent_header)
.map_err(PayloadBuilderError::other)?;

let pool = args.pool.clone();
default_ethereum_payload(self.evm_config.clone(), args, cfg_env, block_env, |attributes| {
Expand All @@ -120,7 +122,9 @@ where
None,
);

let (cfg_env, block_env) = self.cfg_and_block_env(&args.config, &args.config.parent_header);
let (cfg_env, block_env) = self
.cfg_and_block_env(&args.config, &args.config.parent_header)
.map_err(PayloadBuilderError::other)?;

let pool = args.pool.clone();

Expand Down
16 changes: 8 additions & 8 deletions crates/evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ std = [
"revm/std",
]
test-utils = [
"dep:parking_lot",
"reth-chainspec/test-utils",
"reth-consensus/test-utils",
"reth-primitives/test-utils",
"reth-primitives-traits/test-utils",
"reth-revm/test-utils",
"revm/test-utils",
"reth-prune-types/test-utils"
"dep:parking_lot",
"reth-chainspec/test-utils",
"reth-consensus/test-utils",
"reth-primitives/test-utils",
"reth-primitives-traits/test-utils",
"reth-revm/test-utils",
"revm/test-utils",
"reth-prune-types/test-utils"
]
5 changes: 4 additions & 1 deletion crates/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static {
/// The header type used by the EVM.
type Header: BlockHeader;

/// The error type that is returned by [`Self::next_cfg_and_block_env`].
type Error: core::error::Error + Send + Sync;

/// Returns a [`TxEnv`] from a [`TransactionSigned`] and [`Address`].
fn tx_env(&self, transaction: &TransactionSigned, signer: Address) -> TxEnv {
let mut tx_env = TxEnv::default();
Expand Down Expand Up @@ -192,7 +195,7 @@ pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static {
&self,
parent: &Self::Header,
attributes: NextBlockEnvAttributes,
) -> (CfgEnvWithHandlerCfg, BlockEnv);
) -> Result<(CfgEnvWithHandlerCfg, BlockEnv), Self::Error>;
}

/// Represents additional attributes required to configure the next block.
Expand Down
174 changes: 172 additions & 2 deletions crates/optimism/chainspec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ mod op_sepolia;
use alloc::{vec, vec::Vec};
use alloy_chains::Chain;
use alloy_genesis::Genesis;
use alloy_primitives::{B256, U256};
use alloy_primitives::{Bytes, Parity, Signature, B256, U256};
pub use base::BASE_MAINNET;
pub use base_sepolia::BASE_SEPOLIA;
use derive_more::{Constructor, Deref, From, Into};
use derive_more::{Constructor, Deref, Display, From, Into};
pub use dev::OP_DEV;
#[cfg(not(feature = "std"))]
pub(crate) use once_cell::sync::Lazy as LazyLock;
Expand Down Expand Up @@ -159,6 +159,16 @@ impl OpChainSpecBuilder {
self
}

/// Enable Holocene at genesis
pub fn holocene_activated(mut self) -> Self {
self = self.granite_activated();
self.inner = self.inner.with_fork(
reth_optimism_forks::OptimismHardfork::Holocene,
ForkCondition::Timestamp(0),
);
self
}

/// Build the resulting [`OpChainSpec`].
///
/// # Panics
Expand All @@ -177,6 +187,81 @@ pub struct OpChainSpec {
pub inner: ChainSpec,
}

impl OpChainSpec {
/// Read from parent to determine the base fee for the next block
pub fn next_block_base_fee(
&self,
parent: &Header,
timestamp: u64,
) -> Result<U256, DecodeError> {
let is_holocene_activated = self.inner.is_fork_active_at_timestamp(
reth_optimism_forks::OptimismHardfork::Holocene,
timestamp,
);
// If we are in the Holocene, we need to use the base fee params
// from the parent block's extra data.
// Else, use the base fee params (default values) from chainspec
if is_holocene_activated {
let (denominator, elasticity) = decode_holocene_1559_params(parent.extra_data.clone())?;
if elasticity == 0 && denominator == 0 {
return Ok(U256::from(
parent
.next_block_base_fee(self.base_fee_params_at_timestamp(timestamp))
.unwrap_or_default(),
));
}
let base_fee_params = BaseFeeParams::new(denominator as u128, elasticity as u128);
Ok(U256::from(parent.next_block_base_fee(base_fee_params).unwrap_or_default()))
} else {
Ok(U256::from(
parent
.next_block_base_fee(self.base_fee_params_at_timestamp(timestamp))
.unwrap_or_default(),
))
}
}
}

#[derive(Clone, Debug, Display, Eq, PartialEq)]
/// Error type for decoding Holocene 1559 parameters
pub enum DecodeError {
#[display("Insufficient data to decode")]
/// Insufficient data to decode
InsufficientData,
#[display("Invalid denominator parameter")]
/// Invalid denominator parameter
InvalidDenominator,
#[display("Invalid elasticity parameter")]
/// Invalid elasticity parameter
InvalidElasticity,
}

impl core::error::Error for DecodeError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
// None of the errors have sub-errors
None
}
}

/// Extracts the Holcene 1599 parameters from the encoded form:
/// <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#eip1559params-encoding>
pub fn decode_holocene_1559_params(extra_data: Bytes) -> Result<(u32, u32), DecodeError> {
if extra_data.len() < 9 {
return Err(DecodeError::InsufficientData);
}
let denominator: [u8; 4] =
extra_data[1..5].try_into().map_err(|_| DecodeError::InvalidDenominator)?;
let elasticity: [u8; 4] =
extra_data[5..9].try_into().map_err(|_| DecodeError::InvalidElasticity)?;
Ok((u32::from_be_bytes(denominator), u32::from_be_bytes(elasticity)))
}

/// Returns the signature for the optimism deposit transactions, which don't include a
/// signature.
pub fn optimism_deposit_tx_signature() -> Signature {
Signature::new(U256::ZERO, U256::ZERO, Parity::Parity(false))
}

impl EthChainSpec for OpChainSpec {
fn chain(&self) -> alloy_chains::Chain {
self.inner.chain()
Expand Down Expand Up @@ -405,6 +490,8 @@ impl OptimismGenesisInfo {

#[cfg(test)]
mod tests {
use std::sync::Arc;

use alloy_genesis::{ChainConfig, Genesis};
use alloy_primitives::b256;
use reth_chainspec::{test_fork_ids, BaseFeeParams, BaseFeeParamsKind};
Expand Down Expand Up @@ -919,4 +1006,87 @@ mod tests {
.all(|(expected, actual)| &**expected == *actual));
assert_eq!(expected_hardforks.len(), hardforks.len());
}

#[test]
fn test_get_base_fee_pre_holocene() {
let op_chain_spec = &BASE_SEPOLIA;
let parent = Header {
base_fee_per_gas: Some(1),
gas_used: 15763614,
gas_limit: 144000000,
..Default::default()
};
let base_fee = op_chain_spec.next_block_base_fee(&parent, 0);
assert_eq!(
base_fee.unwrap(),
U256::from(
parent
.next_block_base_fee(op_chain_spec.base_fee_params_at_timestamp(0))
.unwrap_or_default()
)
);
}

fn holocene_chainspec() -> Arc<OpChainSpec> {
let mut hardforks = OptimismHardfork::base_sepolia();
hardforks.insert(OptimismHardfork::Holocene.boxed(), ForkCondition::Timestamp(1800000000));
Arc::new(OpChainSpec {
inner: ChainSpec {
chain: BASE_SEPOLIA.inner.chain,
genesis: BASE_SEPOLIA.inner.genesis.clone(),
genesis_hash: BASE_SEPOLIA.inner.genesis_hash.clone(),
paris_block_and_final_difficulty: Some((0, U256::from(0))),
hardforks,
base_fee_params: BASE_SEPOLIA.inner.base_fee_params.clone(),
max_gas_limit: crate::constants::BASE_SEPOLIA_MAX_GAS_LIMIT,
prune_delete_limit: 10000,
..Default::default()
},
})
}

#[test]
fn test_get_base_fee_holocene_nonce_not_set() {
let op_chain_spec = holocene_chainspec();
let parent = Header {
base_fee_per_gas: Some(1),
gas_used: 15763614,
gas_limit: 144000000,
timestamp: 1800000003,
extra_data: Bytes::from_static(&[0, 0, 0, 0, 0, 0, 0, 0, 0]),
..Default::default()
};
let base_fee = op_chain_spec.next_block_base_fee(&parent, 1800000005);
assert_eq!(
base_fee.unwrap(),
U256::from(
parent
.next_block_base_fee(op_chain_spec.base_fee_params_at_timestamp(0))
.unwrap_or_default()
)
);
}

#[test]
fn test_get_base_fee_holocene_nonce_set() {
let op_chain_spec = holocene_chainspec();
let parent = Header {
base_fee_per_gas: Some(1),
gas_used: 15763614,
gas_limit: 144000000,
extra_data: Bytes::from_static(&[0, 0, 0, 0, 8, 0, 0, 0, 8]),
timestamp: 1800000003,
..Default::default()
};

let base_fee = op_chain_spec.next_block_base_fee(&parent, 1800000005);
assert_eq!(
base_fee.unwrap(),
U256::from(
parent
.next_block_base_fee(BaseFeeParams::new(0x00000008, 0x00000008))
.unwrap_or_default()
)
);
}
}
8 changes: 6 additions & 2 deletions crates/optimism/evm/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ pub fn revm_spec_by_timestamp_after_bedrock(
chain_spec: &OpChainSpec,
timestamp: u64,
) -> revm_primitives::SpecId {
if chain_spec.fork(OptimismHardfork::Granite).active_at_timestamp(timestamp) {
if chain_spec.fork(OptimismHardfork::Holocene).active_at_timestamp(timestamp) {
revm_primitives::HOLOCENE
} else if chain_spec.fork(OptimismHardfork::Granite).active_at_timestamp(timestamp) {
revm_primitives::GRANITE
} else if chain_spec.fork(OptimismHardfork::Fjord).active_at_timestamp(timestamp) {
revm_primitives::FJORD
Expand All @@ -29,7 +31,9 @@ pub fn revm_spec_by_timestamp_after_bedrock(

/// Map the latest active hardfork at the given block to a revm [`SpecId`](revm_primitives::SpecId).
pub fn revm_spec(chain_spec: &OpChainSpec, block: &Head) -> revm_primitives::SpecId {
if chain_spec.fork(OptimismHardfork::Granite).active_at_head(block) {
if chain_spec.fork(OptimismHardfork::Holocene).active_at_head(block) {
revm_primitives::HOLOCENE
} else if chain_spec.fork(OptimismHardfork::Granite).active_at_head(block) {
revm_primitives::GRANITE
} else if chain_spec.fork(OptimismHardfork::Fjord).active_at_head(block) {
revm_primitives::FJORD
Expand Down
15 changes: 5 additions & 10 deletions crates/optimism/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ extern crate alloc;
use alloc::{sync::Arc, vec::Vec};
use alloy_primitives::{Address, U256};
use reth_evm::{ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes};
use reth_optimism_chainspec::OpChainSpec;
use reth_optimism_chainspec::{DecodeError, OpChainSpec};
use reth_primitives::{
revm_primitives::{AnalysisKind, CfgEnvWithHandlerCfg, TxEnv},
transaction::FillTxEnv,
Expand Down Expand Up @@ -56,6 +56,7 @@ impl OptimismEvmConfig {

impl ConfigureEvmEnv for OptimismEvmConfig {
type Header = Header;
type Error = DecodeError;

fn fill_tx_env(&self, tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address) {
transaction.fill_tx_env(tx_env, sender);
Expand Down Expand Up @@ -134,7 +135,7 @@ impl ConfigureEvmEnv for OptimismEvmConfig {
&self,
parent: &Self::Header,
attributes: NextBlockEnvAttributes,
) -> (CfgEnvWithHandlerCfg, BlockEnv) {
) -> Result<(CfgEnvWithHandlerCfg, BlockEnv), Self::Error> {
// configure evm env based on parent block
let cfg = CfgEnv::default().with_chain_id(self.chain_spec.chain().id());

Expand All @@ -156,13 +157,7 @@ impl ConfigureEvmEnv for OptimismEvmConfig {
prevrandao: Some(attributes.prev_randao),
gas_limit: U256::from(parent.gas_limit),
// calculate basefee based on parent block's gas usage
basefee: U256::from(
parent
.next_block_base_fee(
self.chain_spec.base_fee_params_at_timestamp(attributes.timestamp),
)
.unwrap_or_default(),
),
basefee: self.chain_spec.next_block_base_fee(parent, attributes.timestamp)?,
// calculate excess gas based on parent block's blob gas usage
blob_excess_gas_and_price,
};
Expand All @@ -175,7 +170,7 @@ impl ConfigureEvmEnv for OptimismEvmConfig {
};
}

(cfg_with_handler_cfg, block_env)
Ok((cfg_with_handler_cfg, block_env))
}
}

Expand Down
Loading

0 comments on commit 93a9b8a

Please sign in to comment.