Files
reth/crates/primitives/src/hardfork.rs
2023-05-29 20:58:35 +00:00

182 lines
5.1 KiB
Rust

use serde::{Deserialize, Serialize};
use crate::{ChainSpec, ForkCondition, ForkFilter, ForkId};
use std::{fmt::Display, str::FromStr};
/// The name of an Ethereum hardfork.
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum Hardfork {
/// Frontier.
Frontier,
/// Homestead.
Homestead,
/// The DAO fork.
Dao,
/// Tangerine.
Tangerine,
/// Spurious Dragon.
SpuriousDragon,
/// Byzantium.
Byzantium,
/// Constantinople.
Constantinople,
/// Petersburg.
Petersburg,
/// Istanbul.
Istanbul,
/// Muir Glacier.
MuirGlacier,
/// Berlin.
Berlin,
/// London.
London,
/// Arrow Glacier.
ArrowGlacier,
/// Gray Glacier.
GrayGlacier,
/// Paris.
Paris,
/// Shanghai.
Shanghai,
}
impl Hardfork {
/// Get the [ForkId] for this hardfork in the given spec, if the fork is activated at any point.
pub fn fork_id(&self, spec: &ChainSpec) -> Option<ForkId> {
match spec.fork(*self) {
ForkCondition::Never => None,
_ => Some(spec.fork_id(&spec.fork(*self).satisfy())),
}
}
/// Get the [ForkFilter] for this hardfork in the given spec, if the fork is activated at any
/// point.
pub fn fork_filter(&self, spec: &ChainSpec) -> Option<ForkFilter> {
match spec.fork(*self) {
ForkCondition::Never => None,
_ => Some(spec.fork_filter(spec.fork(*self).satisfy())),
}
}
}
impl FromStr for Hardfork {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
let hardfork = match s.as_str() {
"frontier" => Hardfork::Frontier,
"homestead" => Hardfork::Homestead,
"dao" => Hardfork::Dao,
"tangerine" => Hardfork::Tangerine,
"spuriousdragon" => Hardfork::SpuriousDragon,
"byzantium" => Hardfork::Byzantium,
"constantinople" => Hardfork::Constantinople,
"petersburg" => Hardfork::Petersburg,
"istanbul" => Hardfork::Istanbul,
"muirglacier" => Hardfork::MuirGlacier,
"berlin" => Hardfork::Berlin,
"london" => Hardfork::London,
"arrowglacier" => Hardfork::ArrowGlacier,
"grayglacier" => Hardfork::GrayGlacier,
"paris" => Hardfork::Paris,
"shanghai" => Hardfork::Shanghai,
_ => return Err(format!("Unknown hardfork: {s}")),
};
Ok(hardfork)
}
}
impl Display for Hardfork {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Chain, Genesis};
use std::collections::BTreeMap;
#[test]
fn check_hardfork_from_str() {
let hardfork_str = [
"frOntier",
"homEstead",
"dao",
"tAngerIne",
"spurIousdrAgon",
"byzAntium",
"constantinople",
"petersburg",
"istanbul",
"muirglacier",
"bErlin",
"lonDon",
"arrowglacier",
"grayglacier",
"PARIS",
"ShAnGhAI",
];
let expected_hardforks = [
Hardfork::Frontier,
Hardfork::Homestead,
Hardfork::Dao,
Hardfork::Tangerine,
Hardfork::SpuriousDragon,
Hardfork::Byzantium,
Hardfork::Constantinople,
Hardfork::Petersburg,
Hardfork::Istanbul,
Hardfork::MuirGlacier,
Hardfork::Berlin,
Hardfork::London,
Hardfork::ArrowGlacier,
Hardfork::GrayGlacier,
Hardfork::Paris,
Hardfork::Shanghai,
];
let hardforks: Vec<Hardfork> =
hardfork_str.iter().map(|h| Hardfork::from_str(h).unwrap()).collect();
assert_eq!(hardforks, expected_hardforks);
}
#[test]
fn check_nonexistent_hardfork_from_str() {
assert!(Hardfork::from_str("not a hardfork").is_err());
}
#[test]
fn check_fork_id_chainspec_with_fork_condition_never() {
let spec = ChainSpec {
chain: Chain::mainnet(),
genesis: Genesis::default(),
genesis_hash: None,
hardforks: BTreeMap::from([(Hardfork::Frontier, ForkCondition::Never)]),
fork_timestamps: Default::default(),
paris_block_and_final_difficulty: None,
};
assert_eq!(Hardfork::Frontier.fork_id(&spec), None);
}
#[test]
fn check_fork_filter_chainspec_with_fork_condition_never() {
let spec = ChainSpec {
chain: Chain::mainnet(),
genesis: Genesis::default(),
genesis_hash: None,
hardforks: BTreeMap::from([(Hardfork::Shanghai, ForkCondition::Never)]),
fork_timestamps: Default::default(),
paris_block_and_final_difficulty: None,
};
assert_eq!(Hardfork::Shanghai.fork_filter(&spec), None);
}
}