mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-30 03:01:58 -04:00
feat: continue opchainspec support (#17422)
Co-authored-by: rose2221 <rose.jethani@nethermind.io> Co-authored-by: Arsenii Kulikov <klkvrr@gmail.com>
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -9130,6 +9130,7 @@ dependencies = [
|
||||
"alloy-primitives",
|
||||
"derive_more",
|
||||
"miniz_oxide",
|
||||
"op-alloy-consensus",
|
||||
"op-alloy-rpc-types",
|
||||
"paste",
|
||||
"reth-chainspec",
|
||||
|
||||
@@ -44,6 +44,7 @@ miniz_oxide = { workspace = true, features = ["with-alloc"], optional = true }
|
||||
derive_more.workspace = true
|
||||
paste = { workspace = true, optional = true }
|
||||
thiserror = { workspace = true, optional = true }
|
||||
op-alloy-consensus.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
reth-chainspec = { workspace = true, features = ["test-utils"] }
|
||||
@@ -71,6 +72,7 @@ std = [
|
||||
"serde?/std",
|
||||
"miniz_oxide?/std",
|
||||
"thiserror?/std",
|
||||
"op-alloy-consensus/std",
|
||||
]
|
||||
serde = [
|
||||
"alloy-chains/serde",
|
||||
@@ -84,4 +86,5 @@ serde = [
|
||||
"reth-optimism-forks/serde",
|
||||
"reth-optimism-primitives/serde",
|
||||
"reth-primitives-traits/serde",
|
||||
"op-alloy-consensus/serde",
|
||||
]
|
||||
|
||||
29
crates/optimism/chainspec/src/basefee.rs
Normal file
29
crates/optimism/chainspec/src/basefee.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
//! Base fee related utilities for Optimism chains.
|
||||
|
||||
use alloy_consensus::BlockHeader;
|
||||
use op_alloy_consensus::{decode_holocene_extra_data, EIP1559ParamError};
|
||||
use reth_chainspec::{BaseFeeParams, EthChainSpec};
|
||||
use reth_optimism_forks::OpHardforks;
|
||||
|
||||
/// Extracts the Holocene 1599 parameters from the encoded extra data from the parent header.
|
||||
///
|
||||
/// Caution: Caller must ensure that holocene is active in the parent header.
|
||||
///
|
||||
/// See also [Base fee computation](https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#base-fee-computation)
|
||||
pub fn decode_holocene_base_fee<H>(
|
||||
chain_spec: impl EthChainSpec + OpHardforks,
|
||||
parent: &H,
|
||||
timestamp: u64,
|
||||
) -> Result<u64, EIP1559ParamError>
|
||||
where
|
||||
H: BlockHeader,
|
||||
{
|
||||
let (elasticity, denominator) = decode_holocene_extra_data(parent.extra_data())?;
|
||||
let base_fee_params = if elasticity == 0 && denominator == 0 {
|
||||
chain_spec.base_fee_params_at_timestamp(timestamp)
|
||||
} else {
|
||||
BaseFeeParams::new(denominator as u128, elasticity as u128)
|
||||
};
|
||||
|
||||
Ok(parent.next_block_base_fee(base_fee_params).unwrap_or_default())
|
||||
}
|
||||
@@ -34,6 +34,7 @@ extern crate alloc;
|
||||
|
||||
mod base;
|
||||
mod base_sepolia;
|
||||
mod basefee;
|
||||
|
||||
pub mod constants;
|
||||
mod dev;
|
||||
@@ -47,6 +48,7 @@ pub use superchain::*;
|
||||
|
||||
pub use base::BASE_MAINNET;
|
||||
pub use base_sepolia::BASE_SEPOLIA;
|
||||
pub use basefee::*;
|
||||
pub use dev::OP_DEV;
|
||||
pub use op::OP_MAINNET;
|
||||
pub use op_sepolia::OP_SEPOLIA;
|
||||
@@ -56,7 +58,7 @@ pub use reth_optimism_forks::*;
|
||||
|
||||
use alloc::{boxed::Box, vec, vec::Vec};
|
||||
use alloy_chains::Chain;
|
||||
use alloy_consensus::{proofs::storage_root_unhashed, Header};
|
||||
use alloy_consensus::{proofs::storage_root_unhashed, BlockHeader, Header};
|
||||
use alloy_eips::eip7840::BlobParams;
|
||||
use alloy_genesis::Genesis;
|
||||
use alloy_hardforks::Hardfork;
|
||||
@@ -286,6 +288,14 @@ impl EthChainSpec for OpChainSpec {
|
||||
fn final_paris_total_difficulty(&self) -> Option<U256> {
|
||||
self.inner.final_paris_total_difficulty()
|
||||
}
|
||||
|
||||
fn next_block_base_fee(&self, parent: &Header, target_timestamp: u64) -> Option<u64> {
|
||||
if self.is_holocene_active_at_timestamp(parent.timestamp()) {
|
||||
decode_holocene_base_fee(self, parent, parent.timestamp()).ok()
|
||||
} else {
|
||||
self.inner.next_block_base_fee(parent, target_timestamp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Hardforks for OpChainSpec {
|
||||
|
||||
@@ -32,11 +32,11 @@ alloy-primitives.workspace = true
|
||||
alloy-consensus.workspace = true
|
||||
alloy-trie.workspace = true
|
||||
revm.workspace = true
|
||||
op-alloy-consensus.workspace = true
|
||||
|
||||
# misc
|
||||
tracing.workspace = true
|
||||
thiserror.workspace = true
|
||||
reth-optimism-chainspec.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
reth-provider = { workspace = true, features = ["test-utils"] }
|
||||
@@ -49,6 +49,7 @@ reth-db-api = { workspace = true, features = ["op"] }
|
||||
|
||||
alloy-chains.workspace = true
|
||||
alloy-primitives.workspace = true
|
||||
|
||||
op-alloy-consensus.workspace = true
|
||||
|
||||
[features]
|
||||
@@ -69,10 +70,10 @@ std = [
|
||||
"alloy-primitives/std",
|
||||
"alloy-consensus/std",
|
||||
"alloy-trie/std",
|
||||
"op-alloy-consensus/std",
|
||||
"reth-revm/std",
|
||||
"revm/std",
|
||||
"tracing/std",
|
||||
"thiserror/std",
|
||||
"reth-execution-types/std",
|
||||
"op-alloy-consensus/std",
|
||||
]
|
||||
|
||||
@@ -34,9 +34,7 @@ mod proof;
|
||||
pub use proof::calculate_receipt_root_no_memo_optimism;
|
||||
|
||||
pub mod validation;
|
||||
pub use validation::{
|
||||
canyon, decode_holocene_base_fee, isthmus, next_block_base_fee, validate_block_post_execution,
|
||||
};
|
||||
pub use validation::{canyon, isthmus, validate_block_post_execution};
|
||||
|
||||
pub mod error;
|
||||
pub use error::OpConsensusError;
|
||||
@@ -178,29 +176,11 @@ where
|
||||
validate_against_parent_timestamp(header.header(), parent.header())?;
|
||||
}
|
||||
|
||||
// EIP1559 base fee validation
|
||||
// <https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#base-fee-computation>
|
||||
// > if Holocene is active in parent_header.timestamp, then the parameters from
|
||||
// > parent_header.extraData are used.
|
||||
if self.chain_spec.is_holocene_active_at_timestamp(parent.timestamp()) {
|
||||
let header_base_fee =
|
||||
header.base_fee_per_gas().ok_or(ConsensusError::BaseFeeMissing)?;
|
||||
let expected_base_fee =
|
||||
decode_holocene_base_fee(&self.chain_spec, parent.header(), header.timestamp())
|
||||
.map_err(|_| ConsensusError::BaseFeeMissing)?;
|
||||
if expected_base_fee != header_base_fee {
|
||||
return Err(ConsensusError::BaseFeeDiff(GotExpected {
|
||||
expected: expected_base_fee,
|
||||
got: header_base_fee,
|
||||
}))
|
||||
}
|
||||
} else {
|
||||
validate_against_parent_eip1559_base_fee(
|
||||
header.header(),
|
||||
parent.header(),
|
||||
&self.chain_spec,
|
||||
)?;
|
||||
}
|
||||
validate_against_parent_eip1559_base_fee(
|
||||
header.header(),
|
||||
parent.header(),
|
||||
&self.chain_spec,
|
||||
)?;
|
||||
|
||||
// ensure that the blob gas fields for this block
|
||||
if let Some(blob_params) = self.chain_spec.blob_params_at_timestamp(header.timestamp()) {
|
||||
|
||||
@@ -3,14 +3,15 @@
|
||||
pub mod canyon;
|
||||
pub mod isthmus;
|
||||
|
||||
// Re-export the decode_holocene_base_fee function for compatibility
|
||||
pub use reth_optimism_chainspec::decode_holocene_base_fee;
|
||||
|
||||
use crate::proof::calculate_receipt_root_optimism;
|
||||
use alloc::vec::Vec;
|
||||
use alloy_consensus::{BlockHeader, TxReceipt, EMPTY_OMMER_ROOT_HASH};
|
||||
use alloy_eips::Encodable2718;
|
||||
use alloy_primitives::{Bloom, Bytes, B256};
|
||||
use alloy_trie::EMPTY_ROOT_HASH;
|
||||
use op_alloy_consensus::{decode_holocene_extra_data, EIP1559ParamError};
|
||||
use reth_chainspec::{BaseFeeParams, EthChainSpec};
|
||||
use reth_consensus::ConsensusError;
|
||||
use reth_optimism_forks::OpHardforks;
|
||||
use reth_optimism_primitives::DepositReceipt;
|
||||
@@ -171,51 +172,13 @@ fn compare_receipts_root_and_logs_bloom(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Extracts the Holocene 1599 parameters from the encoded extra data from the parent header.
|
||||
///
|
||||
/// Caution: Caller must ensure that holocene is active in the parent header.
|
||||
///
|
||||
/// See also [Base fee computation](https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#base-fee-computation)
|
||||
pub fn decode_holocene_base_fee(
|
||||
chain_spec: impl EthChainSpec + OpHardforks,
|
||||
parent: impl BlockHeader,
|
||||
timestamp: u64,
|
||||
) -> Result<u64, EIP1559ParamError> {
|
||||
let (elasticity, denominator) = decode_holocene_extra_data(parent.extra_data())?;
|
||||
let base_fee_params = if elasticity == 0 && denominator == 0 {
|
||||
chain_spec.base_fee_params_at_timestamp(timestamp)
|
||||
} else {
|
||||
BaseFeeParams::new(denominator as u128, elasticity as u128)
|
||||
};
|
||||
|
||||
Ok(parent.next_block_base_fee(base_fee_params).unwrap_or_default())
|
||||
}
|
||||
|
||||
/// Read from parent to determine the base fee for the next block
|
||||
///
|
||||
/// See also [Base fee computation](https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/holocene/exec-engine.md#base-fee-computation)
|
||||
pub fn next_block_base_fee<H: BlockHeader>(
|
||||
chain_spec: impl EthChainSpec<Header = H> + OpHardforks,
|
||||
parent: &H,
|
||||
timestamp: u64,
|
||||
) -> Result<u64, EIP1559ParamError> {
|
||||
// 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 chain_spec.is_holocene_active_at_timestamp(parent.timestamp()) {
|
||||
Ok(decode_holocene_base_fee(chain_spec, parent, timestamp)?)
|
||||
} else {
|
||||
Ok(chain_spec.next_block_base_fee(parent, timestamp).unwrap_or_default())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use alloy_consensus::Header;
|
||||
use alloy_primitives::{b256, hex, Bytes, U256};
|
||||
use op_alloy_consensus::OpTxEnvelope;
|
||||
use reth_chainspec::{ChainSpec, ForkCondition, Hardfork};
|
||||
use reth_chainspec::{BaseFeeParams, ChainSpec, EthChainSpec, ForkCondition, Hardfork};
|
||||
use reth_optimism_chainspec::{OpChainSpec, BASE_SEPOLIA};
|
||||
use reth_optimism_forks::{OpHardfork, BASE_SEPOLIA_HARDFORKS};
|
||||
use std::sync::Arc;
|
||||
@@ -255,7 +218,8 @@ mod tests {
|
||||
gas_limit: 144000000,
|
||||
..Default::default()
|
||||
};
|
||||
let base_fee = next_block_base_fee(&op_chain_spec, &parent, 0);
|
||||
let base_fee =
|
||||
reth_optimism_chainspec::OpChainSpec::next_block_base_fee(&op_chain_spec, &parent, 0);
|
||||
assert_eq!(
|
||||
base_fee.unwrap(),
|
||||
op_chain_spec.next_block_base_fee(&parent, 0).unwrap_or_default()
|
||||
@@ -273,7 +237,11 @@ mod tests {
|
||||
extra_data: Bytes::from_static(&[0, 0, 0, 0, 0, 0, 0, 0, 0]),
|
||||
..Default::default()
|
||||
};
|
||||
let base_fee = next_block_base_fee(&op_chain_spec, &parent, 1800000005);
|
||||
let base_fee = reth_optimism_chainspec::OpChainSpec::next_block_base_fee(
|
||||
&op_chain_spec,
|
||||
&parent,
|
||||
1800000005,
|
||||
);
|
||||
assert_eq!(
|
||||
base_fee.unwrap(),
|
||||
op_chain_spec.next_block_base_fee(&parent, 0).unwrap_or_default()
|
||||
@@ -291,7 +259,11 @@ mod tests {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let base_fee = next_block_base_fee(holocene_chainspec(), &parent, 1800000005);
|
||||
let base_fee = reth_optimism_chainspec::OpChainSpec::next_block_base_fee(
|
||||
&holocene_chainspec(),
|
||||
&parent,
|
||||
1800000005,
|
||||
);
|
||||
assert_eq!(
|
||||
base_fee.unwrap(),
|
||||
parent
|
||||
@@ -312,7 +284,12 @@ mod tests {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let base_fee = next_block_base_fee(&*BASE_SEPOLIA, &parent, 1735315546).unwrap();
|
||||
let base_fee = reth_optimism_chainspec::OpChainSpec::next_block_base_fee(
|
||||
&*BASE_SEPOLIA,
|
||||
&parent,
|
||||
1735315546,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(base_fee, 507);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ use op_revm::{OpSpecId, OpTransaction};
|
||||
use reth_chainspec::EthChainSpec;
|
||||
use reth_evm::{ConfigureEvm, EvmEnv};
|
||||
use reth_optimism_chainspec::OpChainSpec;
|
||||
use reth_optimism_consensus::next_block_base_fee;
|
||||
use reth_optimism_forks::OpHardforks;
|
||||
use reth_optimism_primitives::{DepositReceipt, OpPrimitives};
|
||||
use reth_primitives_traits::{NodePrimitives, SealedBlock, SealedHeader, SignedTransaction};
|
||||
@@ -187,7 +186,10 @@ where
|
||||
prevrandao: Some(attributes.prev_randao),
|
||||
gas_limit: attributes.gas_limit,
|
||||
// calculate basefee based on parent block's gas usage
|
||||
basefee: next_block_base_fee(self.chain_spec(), parent, attributes.timestamp)?,
|
||||
basefee: self
|
||||
.chain_spec()
|
||||
.next_block_base_fee(parent, attributes.timestamp)
|
||||
.unwrap_or_default(),
|
||||
// calculate excess gas based on parent block's blob gas usage
|
||||
blob_excess_gas_and_price,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user