feat: abstract OpBeaconConsensus over primitives and chainspec (#14171)

This commit is contained in:
Arsenii Kulikov
2025-02-04 16:55:51 +04:00
committed by GitHub
parent 740bf04351
commit 07090b315c
9 changed files with 237 additions and 221 deletions

View File

@ -19,7 +19,7 @@ mod op_sepolia;
use alloc::{boxed::Box, vec, vec::Vec};
use alloy_chains::Chain;
use alloy_consensus::{BlockHeader, Header};
use alloy_consensus::Header;
use alloy_eips::eip7840::BlobParams;
use alloy_genesis::Genesis;
use alloy_primitives::{B256, U256};
@ -28,7 +28,6 @@ pub use base_sepolia::BASE_SEPOLIA;
use derive_more::{Constructor, Deref, Display, From, Into};
pub use dev::OP_DEV;
pub use op::OP_MAINNET;
use op_alloy_consensus::{decode_holocene_extra_data, EIP1559ParamError};
pub use op_sepolia::OP_SEPOLIA;
use reth_chainspec::{
BaseFeeParams, BaseFeeParamsKind, ChainSpec, ChainSpecBuilder, DepositContract, EthChainSpec,
@ -195,55 +194,6 @@ impl OpChainSpec {
pub fn from_genesis(genesis: Genesis) -> Self {
genesis.into()
}
/// 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: BlockHeader>(
&self,
parent: &H,
timestamp: u64,
) -> Result<u64, EIP1559ParamError> {
let (elasticity, denominator) = decode_holocene_extra_data(parent.extra_data())?;
let base_fee = if elasticity == 0 && denominator == 0 {
parent
.next_block_base_fee(self.base_fee_params_at_timestamp(timestamp))
.unwrap_or_default()
} else {
let base_fee_params = BaseFeeParams::new(denominator as u128, elasticity as u128);
parent.next_block_base_fee(base_fee_params).unwrap_or_default()
};
Ok(base_fee)
}
/// 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>(
&self,
parent: &H,
timestamp: u64,
) -> Result<U256, EIP1559ParamError> {
// > if Holocene is active in parent_header.timestamp, then the parameters from
// > parent_header.extraData are used.
let is_holocene_activated =
self.inner.is_fork_active_at_timestamp(OpHardfork::Holocene, parent.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 {
Ok(U256::from(self.decode_holocene_base_fee(parent, timestamp)?))
} else {
Ok(U256::from(
parent
.next_block_base_fee(self.base_fee_params_at_timestamp(timestamp))
.unwrap_or_default(),
))
}
}
}
impl EthChainSpec for OpChainSpec {
@ -483,10 +433,8 @@ impl OpGenesisInfo {
#[cfg(test)]
mod tests {
use std::sync::Arc;
use alloy_genesis::{ChainConfig, Genesis};
use alloy_primitives::{b256, hex, Bytes};
use alloy_primitives::b256;
use reth_chainspec::{test_fork_ids, BaseFeeParams, BaseFeeParamsKind};
use reth_ethereum_forks::{EthereumHardfork, ForkCondition, ForkHash, ForkId, Head};
use reth_optimism_forks::{OpHardfork, OpHardforks};
@ -1026,105 +974,6 @@ mod tests {
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 = OpHardfork::base_sepolia();
hardforks.insert(OpHardfork::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(),
prune_delete_limit: 10000,
..Default::default()
},
})
}
#[test]
fn test_get_base_fee_holocene_extra_data_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_extra_data_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()
)
);
}
// <https://sepolia.basescan.org/block/19773628>
#[test]
fn test_get_base_fee_holocene_extra_data_set_base_sepolia() {
let op_chain_spec = BASE_SEPOLIA.clone();
let parent = Header {
base_fee_per_gas: Some(507),
gas_used: 4847634,
gas_limit: 60000000,
extra_data: hex!("00000000fa0000000a").into(),
timestamp: 1735315544,
..Default::default()
};
let base_fee = op_chain_spec.next_block_base_fee(&parent, 1735315546).unwrap();
assert_eq!(base_fee, U256::from(507));
}
#[test]
fn json_genesis() {
let geth_genesis = r#"