reth_optimism_evm/
config.rs

1use alloy_consensus::BlockHeader;
2use op_revm::OpSpecId;
3use reth_optimism_forks::OpHardforks;
4use revm::primitives::{Address, Bytes, B256};
5
6/// Context relevant for execution of a next block w.r.t OP.
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct OpNextBlockEnvAttributes {
9    /// The timestamp of the next block.
10    pub timestamp: u64,
11    /// The suggested fee recipient for the next block.
12    pub suggested_fee_recipient: Address,
13    /// The randomness value for the next block.
14    pub prev_randao: B256,
15    /// Block gas limit.
16    pub gas_limit: u64,
17    /// The parent beacon block root.
18    pub parent_beacon_block_root: Option<B256>,
19    /// Encoded EIP-1559 parameters to include into block's `extra_data` field.
20    pub extra_data: Bytes,
21}
22
23/// Map the latest active hardfork at the given header to a revm [`OpSpecId`].
24pub fn revm_spec(chain_spec: impl OpHardforks, header: impl BlockHeader) -> OpSpecId {
25    revm_spec_by_timestamp_after_bedrock(chain_spec, header.timestamp())
26}
27
28/// Returns the revm [`OpSpecId`] at the given timestamp.
29///
30/// # Note
31///
32/// This is only intended to be used after the Bedrock, when hardforks are activated by
33/// timestamp.
34pub fn revm_spec_by_timestamp_after_bedrock(
35    chain_spec: impl OpHardforks,
36    timestamp: u64,
37) -> OpSpecId {
38    if chain_spec.is_interop_active_at_timestamp(timestamp) {
39        OpSpecId::INTEROP
40    } else if chain_spec.is_isthmus_active_at_timestamp(timestamp) {
41        OpSpecId::ISTHMUS
42    } else if chain_spec.is_holocene_active_at_timestamp(timestamp) {
43        OpSpecId::HOLOCENE
44    } else if chain_spec.is_granite_active_at_timestamp(timestamp) {
45        OpSpecId::GRANITE
46    } else if chain_spec.is_fjord_active_at_timestamp(timestamp) {
47        OpSpecId::FJORD
48    } else if chain_spec.is_ecotone_active_at_timestamp(timestamp) {
49        OpSpecId::ECOTONE
50    } else if chain_spec.is_canyon_active_at_timestamp(timestamp) {
51        OpSpecId::CANYON
52    } else if chain_spec.is_regolith_active_at_timestamp(timestamp) {
53        OpSpecId::REGOLITH
54    } else {
55        OpSpecId::BEDROCK
56    }
57}
58
59#[cfg(feature = "rpc")]
60impl<H: alloy_consensus::BlockHeader> reth_rpc_eth_api::helpers::pending_block::BuildPendingEnv<H>
61    for OpNextBlockEnvAttributes
62{
63    fn build_pending_env(parent: &crate::SealedHeader<H>) -> Self {
64        Self {
65            timestamp: parent.timestamp().saturating_add(12),
66            suggested_fee_recipient: parent.beneficiary(),
67            prev_randao: alloy_primitives::B256::random(),
68            gas_limit: parent.gas_limit(),
69            parent_beacon_block_root: parent.parent_beacon_block_root(),
70            extra_data: parent.extra_data().clone(),
71        }
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78    use alloy_consensus::Header;
79    use reth_chainspec::ChainSpecBuilder;
80    use reth_optimism_chainspec::{OpChainSpec, OpChainSpecBuilder};
81
82    #[test]
83    fn test_revm_spec_by_timestamp_after_merge() {
84        #[inline(always)]
85        fn op_cs(f: impl FnOnce(OpChainSpecBuilder) -> OpChainSpecBuilder) -> OpChainSpec {
86            let cs = ChainSpecBuilder::mainnet().chain(reth_chainspec::Chain::from_id(10)).into();
87            f(cs).build()
88        }
89        assert_eq!(
90            revm_spec_by_timestamp_after_bedrock(op_cs(|cs| cs.interop_activated()), 0),
91            OpSpecId::INTEROP
92        );
93        assert_eq!(
94            revm_spec_by_timestamp_after_bedrock(op_cs(|cs| cs.isthmus_activated()), 0),
95            OpSpecId::ISTHMUS
96        );
97        assert_eq!(
98            revm_spec_by_timestamp_after_bedrock(op_cs(|cs| cs.holocene_activated()), 0),
99            OpSpecId::HOLOCENE
100        );
101        assert_eq!(
102            revm_spec_by_timestamp_after_bedrock(op_cs(|cs| cs.granite_activated()), 0),
103            OpSpecId::GRANITE
104        );
105        assert_eq!(
106            revm_spec_by_timestamp_after_bedrock(op_cs(|cs| cs.fjord_activated()), 0),
107            OpSpecId::FJORD
108        );
109        assert_eq!(
110            revm_spec_by_timestamp_after_bedrock(op_cs(|cs| cs.ecotone_activated()), 0),
111            OpSpecId::ECOTONE
112        );
113        assert_eq!(
114            revm_spec_by_timestamp_after_bedrock(op_cs(|cs| cs.canyon_activated()), 0),
115            OpSpecId::CANYON
116        );
117        assert_eq!(
118            revm_spec_by_timestamp_after_bedrock(op_cs(|cs| cs.bedrock_activated()), 0),
119            OpSpecId::BEDROCK
120        );
121        assert_eq!(
122            revm_spec_by_timestamp_after_bedrock(op_cs(|cs| cs.regolith_activated()), 0),
123            OpSpecId::REGOLITH
124        );
125    }
126
127    #[test]
128    fn test_to_revm_spec() {
129        #[inline(always)]
130        fn op_cs(f: impl FnOnce(OpChainSpecBuilder) -> OpChainSpecBuilder) -> OpChainSpec {
131            let cs = ChainSpecBuilder::mainnet().chain(reth_chainspec::Chain::from_id(10)).into();
132            f(cs).build()
133        }
134        assert_eq!(
135            revm_spec(op_cs(|cs| cs.isthmus_activated()), Header::default()),
136            OpSpecId::ISTHMUS
137        );
138        assert_eq!(
139            revm_spec(op_cs(|cs| cs.holocene_activated()), Header::default()),
140            OpSpecId::HOLOCENE
141        );
142        assert_eq!(
143            revm_spec(op_cs(|cs| cs.granite_activated()), Header::default()),
144            OpSpecId::GRANITE
145        );
146        assert_eq!(revm_spec(op_cs(|cs| cs.fjord_activated()), Header::default()), OpSpecId::FJORD);
147        assert_eq!(
148            revm_spec(op_cs(|cs| cs.ecotone_activated()), Header::default()),
149            OpSpecId::ECOTONE
150        );
151        assert_eq!(
152            revm_spec(op_cs(|cs| cs.canyon_activated()), Header::default()),
153            OpSpecId::CANYON
154        );
155        assert_eq!(
156            revm_spec(op_cs(|cs| cs.bedrock_activated()), Header::default()),
157            OpSpecId::BEDROCK
158        );
159        assert_eq!(
160            revm_spec(op_cs(|cs| cs.regolith_activated()), Header::default()),
161            OpSpecId::REGOLITH
162        );
163    }
164}