diff --git a/Cargo.lock b/Cargo.lock index 83c4dadcd..1471a80fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -138,6 +138,20 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +[[package]] +name = "alloy-chains" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a5f61137c31916542bb63cd70d0e0dd7a76f76b7f962f4337bc438612d45b2" +dependencies = [ + "alloy-rlp", + "arbitrary", + "num_enum 0.7.2", + "proptest", + "serde", + "strum", +] + [[package]] name = "alloy-dyn-abi" version = "0.6.0" @@ -4637,7 +4651,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate 3.0.0", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 2.0.48", @@ -5220,15 +5234,6 @@ dependencies = [ "toml_edit 0.20.7", ] -[[package]] -name = "proc-macro-crate" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b2685dd208a3771337d8d386a89840f0f43cd68be8dae90a5f8c2384effc9cd" -dependencies = [ - "toml_edit 0.21.0", -] - [[package]] name = "proc-macro-error" version = "1.0.4" @@ -5640,6 +5645,7 @@ dependencies = [ name = "reth" version = "0.1.0-alpha.14" dependencies = [ + "alloy-chains", "alloy-rlp", "aquamarine", "backon", @@ -5870,6 +5876,7 @@ dependencies = [ name = "reth-consensus-common" version = "0.1.0-alpha.14" dependencies = [ + "alloy-chains", "assert_matches", "cfg-if", "mockall", @@ -5951,6 +5958,7 @@ dependencies = [ name = "reth-dns-discovery" version = "0.1.0-alpha.14" dependencies = [ + "alloy-chains", "alloy-rlp", "async-trait", "data-encoding", @@ -6033,6 +6041,7 @@ dependencies = [ name = "reth-eth-wire" version = "0.1.0-alpha.14" dependencies = [ + "alloy-chains", "alloy-rlp", "arbitrary", "async-stream", @@ -6266,6 +6275,7 @@ dependencies = [ name = "reth-network-api" version = "0.1.0-alpha.14" dependencies = [ + "alloy-chains", "async-trait", "reth-discv4", "reth-eth-wire", @@ -6375,6 +6385,7 @@ name = "reth-primitives" version = "0.1.0-alpha.14" dependencies = [ "ahash", + "alloy-chains", "alloy-primitives", "alloy-rlp", "alloy-trie", @@ -6799,6 +6810,7 @@ name = "reth-trie" version = "0.1.0-alpha.14" dependencies = [ "ahash", + "alloy-chains", "alloy-rlp", "auto_impl", "criterion", diff --git a/Cargo.toml b/Cargo.toml index c6731c2dc..c4038780c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -164,6 +164,7 @@ revm-primitives = { git = "https://github.com/bluealloy/revm", branch = "reth_fr revm-inspectors = { git = "https://github.com/paradigmxyz/evm-inspectors" } # eth +alloy-chains = {version = "0.1", feature = ["serde", "rlp", "arbitrary"] } alloy-primitives = "0.6" alloy-dyn-abi = "0.6" alloy-sol-types = "0.6" diff --git a/bin/reth/Cargo.toml b/bin/reth/Cargo.toml index c0565117e..72914170b 100644 --- a/bin/reth/Cargo.toml +++ b/bin/reth/Cargo.toml @@ -59,6 +59,7 @@ reth-node-builder.workspace = true # crypto alloy-rlp.workspace = true +alloy-chains.workspace = true secp256k1 = { workspace = true, features = ["global-context", "rand-std", "recovery"] } revm-inspectors.workspace = true diff --git a/bin/reth/src/args/network_args.rs b/bin/reth/src/args/network_args.rs index 48863dafb..57f6149ec 100644 --- a/bin/reth/src/args/network_args.rs +++ b/bin/reth/src/args/network_args.rs @@ -88,7 +88,7 @@ impl NetworkArgs { secret_key: SecretKey, default_peers_file: PathBuf, ) -> NetworkConfigBuilder { - let chain_bootnodes = chain_spec.chain.bootnodes().unwrap_or_else(mainnet_nodes); + let chain_bootnodes = chain_spec.bootnodes().unwrap_or_else(mainnet_nodes); let peers_file = self.peers_file.clone().unwrap_or(default_peers_file); // Configure peer connections diff --git a/bin/reth/src/args/utils.rs b/bin/reth/src/args/utils.rs index c03f3ef85..080aa5c0a 100644 --- a/bin/reth/src/args/utils.rs +++ b/bin/reth/src/args/utils.rs @@ -17,7 +17,7 @@ use reth_primitives::{DEV, GOERLI, HOLESKY, MAINNET, SEPOLIA}; #[cfg(feature = "optimism")] /// Chains supported by op-reth. First value should be used as the default. -pub const SUPPORTED_CHAINS: &[&str] = &["base", "base_goerli", "base_sepolia"]; +pub const SUPPORTED_CHAINS: &[&str] = &["base", "base-goerli", "base-sepolia"]; #[cfg(not(feature = "optimism"))] /// Chains supported by reth. First value should be used as the default. pub const SUPPORTED_CHAINS: &[&str] = &["mainnet", "sepolia", "goerli", "holesky", "dev"]; diff --git a/bin/reth/src/cli/db_type.rs b/bin/reth/src/cli/db_type.rs index 8af7eb7a5..7b4318aed 100644 --- a/bin/reth/src/cli/db_type.rs +++ b/bin/reth/src/cli/db_type.rs @@ -1,13 +1,13 @@ //! A real or test database type use crate::dirs::{ChainPath, DataDirPath, MaybePlatformPath}; +use alloy_chains::Chain; use reth_db::{ init_db, test_utils::{create_test_rw_db, TempDatabase}, DatabaseEnv, }; use reth_interfaces::db::LogLevel; -use reth_primitives::Chain; use std::{str::FromStr, sync::Arc}; /// A type that represents either a _real_ (represented by a path), or _test_ database, which will @@ -101,7 +101,7 @@ impl DatabaseInstance { #[cfg(test)] mod tests { use super::*; - use reth_primitives::Chain; + use alloy_chains::Chain; #[test] fn test_database_db_dir() { diff --git a/bin/reth/src/commands/import.rs b/bin/reth/src/commands/import.rs index 317bcf535..35dc6a8bf 100644 --- a/bin/reth/src/commands/import.rs +++ b/bin/reth/src/commands/import.rs @@ -215,7 +215,11 @@ mod tests { fn parse_common_import_command_chain_args() { for chain in SUPPORTED_CHAINS { let args: ImportCommand = ImportCommand::parse_from(["reth", "--chain", chain, "."]); - assert_eq!(args.chain.chain, chain.parse().unwrap()); + assert_eq!( + Ok(args.chain.chain), + chain.parse::(), + "failed to parse chain {chain}" + ); } } } diff --git a/bin/reth/src/commands/node/mod.rs b/bin/reth/src/commands/node/mod.rs index 23840e557..29fc71f09 100644 --- a/bin/reth/src/commands/node/mod.rs +++ b/bin/reth/src/commands/node/mod.rs @@ -253,7 +253,7 @@ mod tests { fn parse_common_node_command_chain_args() { for chain in SUPPORTED_CHAINS { let args: NodeCommand = NodeCommand::<()>::parse_from(["reth", "--chain", chain]); - assert_eq!(args.chain.chain, chain.parse().unwrap()); + assert_eq!(args.chain.chain, chain.parse::().unwrap()); } } diff --git a/bin/reth/src/dirs.rs b/bin/reth/src/dirs.rs index 1a0bee8cb..e751ba50a 100644 --- a/bin/reth/src/dirs.rs +++ b/bin/reth/src/dirs.rs @@ -11,10 +11,7 @@ use std::{ /// Constructs a string to be used as a path for configuration and db paths. pub fn config_path_prefix(chain: Chain) -> String { - match chain { - Chain::Named(name) => name.to_string(), - Chain::Id(id) => id.to_string(), - } + chain.to_string() } /// Returns the path to the reth data directory. diff --git a/bin/reth/src/init.rs b/bin/reth/src/init.rs index 7c2111f07..77a7be950 100644 --- a/bin/reth/src/init.rs +++ b/bin/reth/src/init.rs @@ -294,7 +294,7 @@ mod tests { let address_with_storage = Address::with_last_byte(2); let storage_key = B256::with_last_byte(1); let chain_spec = Arc::new(ChainSpec { - chain: Chain::Id(1), + chain: Chain::from_id(1), genesis: Genesis { alloc: HashMap::from([ ( diff --git a/crates/consensus/beacon-core/src/lib.rs b/crates/consensus/beacon-core/src/lib.rs index a825ac62f..d2aad7b1c 100644 --- a/crates/consensus/beacon-core/src/lib.rs +++ b/crates/consensus/beacon-core/src/lib.rs @@ -16,7 +16,6 @@ use reth_primitives::{ Chain, ChainSpec, Hardfork, Header, SealedBlock, SealedHeader, EMPTY_OMMER_ROOT_HASH, U256, }; use std::{sync::Arc, time::SystemTime}; - /// Ethereum beacon consensus /// /// This consensus engine does basic checks as outlined in the execution specs. diff --git a/crates/consensus/common/Cargo.toml b/crates/consensus/common/Cargo.toml index c8690d02b..51c3134c0 100644 --- a/crates/consensus/common/Cargo.toml +++ b/crates/consensus/common/Cargo.toml @@ -15,7 +15,7 @@ workspace = true reth-primitives.workspace = true reth-interfaces.workspace = true reth-provider.workspace = true - +alloy-chains.workspace = true # misc cfg-if = "1.0.0" diff --git a/crates/consensus/common/src/calc.rs b/crates/consensus/common/src/calc.rs index 26974d6fc..addd4001d 100644 --- a/crates/consensus/common/src/calc.rs +++ b/crates/consensus/common/src/calc.rs @@ -1,5 +1,4 @@ use reth_primitives::{constants::ETH_TO_WEI, BlockNumber, Chain, ChainSpec, Hardfork, U256}; - /// Calculates the base block reward. /// /// The base block reward is defined as: diff --git a/crates/net/dns/Cargo.toml b/crates/net/dns/Cargo.toml index 3a0c2d3ec..6c64cfee9 100644 --- a/crates/net/dns/Cargo.toml +++ b/crates/net/dns/Cargo.toml @@ -18,6 +18,7 @@ reth-net-common.workspace = true # ethereum alloy-rlp.workspace = true +alloy-chains.workspace = true secp256k1 = { workspace = true, features = ["global-context", "rand-std", "recovery", "serde"] } enr = { workspace = true, default-features = false, features = ["rust-secp256k1"] } diff --git a/crates/net/dns/src/lib.rs b/crates/net/dns/src/lib.rs index f72ac4b2e..30d9588aa 100644 --- a/crates/net/dns/src/lib.rs +++ b/crates/net/dns/src/lib.rs @@ -409,9 +409,10 @@ fn convert_enr_node_record(enr: &Enr) -> Option mod tests { use super::*; use crate::tree::TreeRootEntry; + use alloy_chains::Chain; use alloy_rlp::Encodable; use enr::{EnrBuilder, EnrKey}; - use reth_primitives::{Chain, Hardfork, MAINNET}; + use reth_primitives::{Hardfork, MAINNET}; use secp256k1::rand::thread_rng; use std::{future::poll_fn, net::Ipv4Addr}; use tokio_stream::StreamExt; diff --git a/crates/net/eth-wire/Cargo.toml b/crates/net/eth-wire/Cargo.toml index 2030a280d..daf29b138 100644 --- a/crates/net/eth-wire/Cargo.toml +++ b/crates/net/eth-wire/Cargo.toml @@ -17,6 +17,7 @@ reth-codecs.workspace = true reth-primitives.workspace = true reth-ecies.workspace = true alloy-rlp = { workspace = true, features = ["derive"] } +alloy-chains = {workspace = true, features = ["serde", "rlp", "arbitrary"] } reth-discv4.workspace = true # metrics diff --git a/crates/net/eth-wire/src/builder.rs b/crates/net/eth-wire/src/builder.rs index df3e771cf..dbe48a441 100644 --- a/crates/net/eth-wire/src/builder.rs +++ b/crates/net/eth-wire/src/builder.rs @@ -1,7 +1,8 @@ //! Builder structs for messages. use crate::Status; -use reth_primitives::{Chain, ForkId, B256, U256}; +use alloy_chains::Chain; +use reth_primitives::{ForkId, B256, U256}; /// Builder for [`Status`] messages. /// diff --git a/crates/net/eth-wire/src/errors/eth.rs b/crates/net/eth-wire/src/errors/eth.rs index ede591c85..93869342e 100644 --- a/crates/net/eth-wire/src/errors/eth.rs +++ b/crates/net/eth-wire/src/errors/eth.rs @@ -5,7 +5,8 @@ use crate::{ version::ParseVersionError, DisconnectReason, EthMessageID, EthVersion, }; -use reth_primitives::{Chain, GotExpected, GotExpectedBoxed, ValidationError, B256}; +use alloy_chains::Chain; +use reth_primitives::{GotExpected, GotExpectedBoxed, ValidationError, B256}; use std::io; /// Errors when sending/receiving messages diff --git a/crates/net/eth-wire/src/ethstream.rs b/crates/net/eth-wire/src/ethstream.rs index 35ee8d276..9a4539693 100644 --- a/crates/net/eth-wire/src/ethstream.rs +++ b/crates/net/eth-wire/src/ethstream.rs @@ -335,10 +335,11 @@ mod tests { types::{broadcast::BlockHashNumber, EthMessage, EthVersion, Status}, EthStream, HelloMessageWithProtocols, PassthroughCodec, }; + use alloy_chains::NamedChain; use futures::{SinkExt, StreamExt}; use reth_discv4::DEFAULT_DISCOVERY_PORT; use reth_ecies::{stream::ECIESStream, util::pk2id}; - use reth_primitives::{ForkFilter, Head, NamedChain, B256, U256}; + use reth_primitives::{ForkFilter, Head, B256, U256}; use secp256k1::{SecretKey, SECP256K1}; use tokio::net::{TcpListener, TcpStream}; use tokio_util::codec::Decoder; diff --git a/crates/net/eth-wire/src/test_utils.rs b/crates/net/eth-wire/src/test_utils.rs index b9f9591a1..a085cfcc0 100644 --- a/crates/net/eth-wire/src/test_utils.rs +++ b/crates/net/eth-wire/src/test_utils.rs @@ -3,9 +3,10 @@ use crate::{ EthVersion, HelloMessageWithProtocols, P2PStream, ProtocolVersion, Status, UnauthedP2PStream, }; +use alloy_chains::Chain; use reth_discv4::DEFAULT_DISCOVERY_PORT; use reth_ecies::util::pk2id; -use reth_primitives::{Chain, ForkFilter, Head, B256, U256}; +use reth_primitives::{ForkFilter, Head, B256, U256}; use secp256k1::{SecretKey, SECP256K1}; use std::net::SocketAddr; use tokio::net::TcpStream; diff --git a/crates/net/eth-wire/src/types/status.rs b/crates/net/eth-wire/src/types/status.rs index 0925b7d97..805272bac 100644 --- a/crates/net/eth-wire/src/types/status.rs +++ b/crates/net/eth-wire/src/types/status.rs @@ -1,9 +1,8 @@ use crate::{EthVersion, StatusBuilder}; +use alloy_chains::{Chain, NamedChain}; use alloy_rlp::{RlpDecodable, RlpEncodable}; use reth_codecs::derive_arbitrary; -use reth_primitives::{ - hex, Chain, ChainSpec, ForkId, Genesis, Hardfork, Head, NamedChain, B256, MAINNET, U256, -}; +use reth_primitives::{hex, ChainSpec, ForkId, Genesis, Hardfork, Head, B256, MAINNET, U256}; use std::fmt::{Debug, Display}; #[cfg(feature = "serde")] @@ -51,7 +50,7 @@ impl From for Status { Status { version: EthVersion::Eth68 as u8, - chain: Chain::Id(chain), + chain: Chain::from_id(chain), total_difficulty, blockhash: chainspec.genesis_hash(), genesis: chainspec.genesis_hash(), @@ -138,7 +137,7 @@ impl Default for Status { let mainnet_genesis = MAINNET.genesis_hash(); Status { version: EthVersion::Eth68 as u8, - chain: Chain::Named(NamedChain::Mainnet), + chain: Chain::from_named(NamedChain::Mainnet), total_difficulty: U256::from(17_179_869_184u64), blockhash: mainnet_genesis, genesis: mainnet_genesis, @@ -152,11 +151,11 @@ impl Default for Status { #[cfg(test)] mod tests { use crate::types::{EthVersion, Status}; + use alloy_chains::{Chain, NamedChain}; use alloy_rlp::{Decodable, Encodable}; use rand::Rng; use reth_primitives::{ - hex, Chain, ChainSpec, ForkCondition, ForkHash, ForkId, Genesis, Hardfork, Head, - NamedChain, B256, U256, + hex, ChainSpec, ForkCondition, ForkHash, ForkId, Genesis, Hardfork, Head, B256, U256, }; use std::str::FromStr; @@ -165,7 +164,7 @@ mod tests { let expected = hex!("f85643018a07aac59dabcdd74bc567a0feb27336ca7923f8fab3bd617fcb6e75841538f71c1bcfc267d7838489d9e13da0d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3c684b715077d80"); let status = Status { version: EthVersion::Eth67 as u8, - chain: Chain::Named(NamedChain::Mainnet), + chain: Chain::from_named(NamedChain::Mainnet), total_difficulty: U256::from(36206751599115524359527u128), blockhash: B256::from_str( "feb27336ca7923f8fab3bd617fcb6e75841538f71c1bcfc267d7838489d9e13d", @@ -188,7 +187,7 @@ mod tests { let data = hex!("f85643018a07aac59dabcdd74bc567a0feb27336ca7923f8fab3bd617fcb6e75841538f71c1bcfc267d7838489d9e13da0d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3c684b715077d80"); let expected = Status { version: EthVersion::Eth67 as u8, - chain: Chain::Named(NamedChain::Mainnet), + chain: Chain::from_named(NamedChain::Mainnet), total_difficulty: U256::from(36206751599115524359527u128), blockhash: B256::from_str( "feb27336ca7923f8fab3bd617fcb6e75841538f71c1bcfc267d7838489d9e13d", @@ -209,7 +208,7 @@ mod tests { let expected = hex!("f850423884024190faa0f8514c4680ef27700751b08f37645309ce65a449616a3ea966bf39dd935bb27ba00d21840abff46b96c84b2ac9e10e4f5cdaeb5693cb665db62a2f3b02d2d57b5bc6845d43d2fd80"); let status = Status { version: EthVersion::Eth66 as u8, - chain: Chain::Named(NamedChain::BinanceSmartChain), + chain: Chain::from_named(NamedChain::BinanceSmartChain), total_difficulty: U256::from(37851386u64), blockhash: B256::from_str( "f8514c4680ef27700751b08f37645309ce65a449616a3ea966bf39dd935bb27b", @@ -232,7 +231,7 @@ mod tests { let data = hex!("f850423884024190faa0f8514c4680ef27700751b08f37645309ce65a449616a3ea966bf39dd935bb27ba00d21840abff46b96c84b2ac9e10e4f5cdaeb5693cb665db62a2f3b02d2d57b5bc6845d43d2fd80"); let expected = Status { version: EthVersion::Eth66 as u8, - chain: Chain::Named(NamedChain::BinanceSmartChain), + chain: Chain::from_named(NamedChain::BinanceSmartChain), total_difficulty: U256::from(37851386u64), blockhash: B256::from_str( "f8514c4680ef27700751b08f37645309ce65a449616a3ea966bf39dd935bb27b", @@ -253,7 +252,7 @@ mod tests { let data = hex!("f86142820834936d68fcffffffffffffffffffffffffdeab81b8a0523e8163a6d620a4cc152c547a05f28a03fec91a2a615194cb86df9731372c0ca06499dccdc7c7def3ebb1ce4c6ee27ec6bd02aee570625ca391919faf77ef27bdc6841a67ccd880"); let expected = Status { version: EthVersion::Eth66 as u8, - chain: Chain::Id(2100), + chain: Chain::from_id(2100), total_difficulty: U256::from_str( "0x000000000000000000000000006d68fcffffffffffffffffffffffffdeab81b8", ) @@ -300,7 +299,7 @@ mod tests { (Hardfork::Shanghai, ForkCondition::Timestamp(13)), ]; - let mut chainspec = ChainSpec::builder().genesis(genesis).chain(Chain::Id(1337)); + let mut chainspec = ChainSpec::builder().genesis(genesis).chain(Chain::from_id(1337)); for (fork, condition) in &hardforks { chainspec = chainspec.with_fork(*fork, *condition); @@ -323,7 +322,7 @@ mod tests { let status = Status::spec_builder(&spec, &head).build(); - assert_eq!(status.chain, Chain::Id(1337)); + assert_eq!(status.chain, Chain::from_id(1337)); assert_eq!(status.forkid, forkid); assert_eq!(status.total_difficulty, total_difficulty); assert_eq!(status.blockhash, head_hash); diff --git a/crates/net/network-api/Cargo.toml b/crates/net/network-api/Cargo.toml index 145826cd9..f66f37448 100644 --- a/crates/net/network-api/Cargo.toml +++ b/crates/net/network-api/Cargo.toml @@ -17,7 +17,7 @@ reth-primitives.workspace = true reth-eth-wire.workspace = true reth-rpc-types.workspace = true reth-discv4.workspace = true - +alloy-chains.workspace = true # io serde = { workspace = true, features = ["derive"], optional = true } diff --git a/crates/net/network-api/src/noop.rs b/crates/net/network-api/src/noop.rs index fee69c3ab..866010d4b 100644 --- a/crates/net/network-api/src/noop.rs +++ b/crates/net/network-api/src/noop.rs @@ -7,10 +7,11 @@ use crate::{ NetworkError, NetworkInfo, PeerInfo, PeerKind, Peers, PeersInfo, Reputation, ReputationChangeKind, }; +use alloy_chains::Chain; use async_trait::async_trait; use reth_discv4::DEFAULT_DISCOVERY_PORT; use reth_eth_wire::{DisconnectReason, ProtocolVersion}; -use reth_primitives::{Chain, NodeRecord, PeerId}; +use reth_primitives::{NodeRecord, PeerId}; use reth_rpc_types::{EthProtocolInfo, NetworkStatus}; use std::net::{IpAddr, SocketAddr}; diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 976990678..7d123e888 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -20,6 +20,7 @@ revm.workspace = true revm-primitives = { workspace = true, features = ["serde"] } # ethereum +alloy-chains = { workspace = true, features = ["serde", "rlp"] } alloy-primitives = { workspace = true, features = ["rand", "rlp"] } alloy-rlp = { workspace = true, features = ["arrayvec"] } alloy-trie = { workspace = true, features = ["serde"] } @@ -96,6 +97,7 @@ arbitrary = [ "reth-ethereum-forks/arbitrary", "nybbles/arbitrary", "alloy-trie/arbitrary", + "alloy-chains/arbitrary", "dep:arbitrary", "dep:proptest", "dep:proptest-derive", diff --git a/crates/primitives/src/chain/mod.rs b/crates/primitives/src/chain/mod.rs index 7c8cd3420..9cea4f427 100644 --- a/crates/primitives/src/chain/mod.rs +++ b/crates/primitives/src/chain/mod.rs @@ -1,439 +1,71 @@ -use crate::{ - holesky_nodes, - net::{goerli_nodes, mainnet_nodes, sepolia_nodes}, - NodeRecord, U256, U64, -}; -use alloy_rlp::{Decodable, Encodable}; -use num_enum::TryFromPrimitive; -use reth_codecs::add_arbitrary_tests; -use serde::{Deserialize, Serialize}; -use std::{fmt, str::FromStr}; -use strum::{AsRefStr, EnumCount, EnumIter, EnumString, EnumVariantNames}; - -// The chain spec module. -mod spec; +pub use alloy_chains::{Chain, NamedChain}; +pub use info::ChainInfo; pub use spec::{ AllGenesisFormats, BaseFeeParams, BaseFeeParamsKind, ChainSpec, ChainSpecBuilder, DisplayHardforks, ForkBaseFeeParams, ForkCondition, ForkTimestamps, DEV, GOERLI, HOLESKY, MAINNET, SEPOLIA, }; - #[cfg(feature = "optimism")] pub use spec::{BASE_GOERLI, BASE_MAINNET, BASE_SEPOLIA, OP_GOERLI}; +// The chain spec module. +mod spec; // The chain info module. mod info; -pub use info::ChainInfo; - -/// An Ethereum EIP-155 chain. -#[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - AsRefStr, // AsRef, fmt::Display - EnumVariantNames, // Chain::VARIANTS - EnumString, // FromStr, TryFrom<&str> - EnumIter, // Chain::iter - EnumCount, // Chain::COUNT - TryFromPrimitive, // TryFrom - Deserialize, - Serialize, -)] -#[serde(rename_all = "snake_case")] -#[strum(serialize_all = "snake_case")] -#[repr(u64)] -pub enum NamedChain { - /// Ethereum Mainnet. - Mainnet = 1, - /// Morden Testnet. - Morden = 2, - /// Ropsten Testnet. - Ropsten = 3, - /// Rinkeby Testnet. - Rinkeby = 4, - /// Goerli Testnet. - Goerli = 5, - /// Kovan Testnet. - Kovan = 42, - /// Holesky Testnet. - Holesky = 17000, - /// Sepolia Testnet. - Sepolia = 11155111, - - /// Optimism Mainnet. - Optimism = 10, - /// Optimism Kovan Testnet. - OptimismKovan = 69, - /// Optimism Goerli Testnet. - OptimismGoerli = 420, - - /// Base chain. - Base = 8453, - /// Base Goerli Testnet. - BaseGoerli = 84531, - /// Base Sepolia Testnet. - BaseSepolia = 84532, - - /// Arbitrum Mainnet. - Arbitrum = 42161, - /// Arbitrum Testnet. - ArbitrumTestnet = 421611, - /// Arbitrum Goerli Testnet. - ArbitrumGoerli = 421613, - /// Arbitrum Nova. - ArbitrumNova = 42170, - - /// Binance Smart Chain Mainnet. - #[serde(alias = "bsc")] - BinanceSmartChain = 56, - /// Binance Smart Chain Testnet. - #[serde(alias = "bsc_testnet")] - BinanceSmartChainTestnet = 97, - - /// Development Testnet. - Dev = 1337, -} - -impl From for u64 { - fn from(value: NamedChain) -> Self { - value as u64 - } -} - -impl fmt::Display for NamedChain { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.as_ref().fmt(f) - } -} - -/// Either a named or chain id or the actual id value -#[add_arbitrary_tests(rlp)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub enum Chain { - /// Contains a known chain - Named(NamedChain), - /// Contains the id of a chain - Id(u64), -} - -impl Chain { - /// Returns the mainnet chain. - pub const fn mainnet() -> Self { - Chain::Named(NamedChain::Mainnet) - } - - /// Returns the goerli chain. - pub const fn goerli() -> Self { - Chain::Named(NamedChain::Goerli) - } - - /// Returns the sepolia chain. - pub const fn sepolia() -> Self { - Chain::Named(NamedChain::Sepolia) - } - - /// Returns the holesky chain. - pub const fn holesky() -> Self { - Chain::Named(NamedChain::Holesky) - } - - /// Returns the optimism goerli chain. - pub const fn optimism_goerli() -> Self { - Chain::Named(NamedChain::OptimismGoerli) - } - - /// Returns the optimism mainnet chain. - pub const fn optimism_mainnet() -> Self { - Chain::Named(NamedChain::Optimism) - } - - /// Returns the base goerli chain. - pub const fn base_goerli() -> Self { - Chain::Named(NamedChain::BaseGoerli) - } - - /// Returns the base sepolia chain. - pub const fn base_sepolia() -> Self { - Chain::Named(NamedChain::BaseSepolia) - } - - /// Returns the base mainnet chain. - pub const fn base_mainnet() -> Self { - Chain::Named(NamedChain::Base) - } - - /// Returns the dev chain. - pub const fn dev() -> Self { - Chain::Named(NamedChain::Dev) - } - - /// Returns true if the chain contains Optimism configuration. - pub fn is_optimism(self) -> bool { - self.named().map_or(false, |c| { - matches!( - c, - NamedChain::Optimism | - NamedChain::OptimismGoerli | - NamedChain::OptimismKovan | - NamedChain::Base | - NamedChain::BaseGoerli | - NamedChain::BaseSepolia - ) - }) - } - - /// Attempts to convert the chain into a named chain. - pub fn named(&self) -> Option { - match self { - Chain::Named(chain) => Some(*chain), - Chain::Id(id) => NamedChain::try_from(*id).ok(), - } - } - - /// The id of the chain - pub fn id(&self) -> u64 { - match self { - Chain::Named(chain) => *chain as u64, - Chain::Id(id) => *id, - } - } - - /// Returns the address of the public DNS node list for the given chain. - /// - /// See also - pub fn public_dns_network_protocol(self) -> Option { - use NamedChain as C; - const DNS_PREFIX: &str = "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@"; - - let named: NamedChain = self.try_into().ok()?; - - if matches!(named, C::Mainnet | C::Goerli | C::Sepolia | C::Holesky) { - return Some(format!("{DNS_PREFIX}all.{}.ethdisco.net", named.as_ref().to_lowercase())) - } - None - } - - /// Returns bootnodes for the given chain. - pub fn bootnodes(self) -> Option> { - use NamedChain as C; - match self.try_into().ok()? { - C::Mainnet => Some(mainnet_nodes()), - C::Goerli => Some(goerli_nodes()), - C::Sepolia => Some(sepolia_nodes()), - C::Holesky => Some(holesky_nodes()), - _ => None, - } - } -} - -impl fmt::Display for Chain { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Chain::Named(chain) => chain.fmt(f), - Chain::Id(id) => { - if let Ok(chain) = NamedChain::try_from(*id) { - chain.fmt(f) - } else { - id.fmt(f) - } - } - } - } -} - -impl From for Chain { - fn from(id: NamedChain) -> Self { - Chain::Named(id) - } -} - -impl From for Chain { - fn from(id: u64) -> Self { - NamedChain::try_from(id).map(Chain::Named).unwrap_or_else(|_| Chain::Id(id)) - } -} - -impl From for Chain { - fn from(id: U256) -> Self { - id.to::().into() - } -} - -impl From for u64 { - fn from(c: Chain) -> Self { - match c { - Chain::Named(c) => c as u64, - Chain::Id(id) => id, - } - } -} - -impl From for U64 { - fn from(c: Chain) -> Self { - U64::from(u64::from(c)) - } -} - -impl From for U256 { - fn from(c: Chain) -> Self { - U256::from(u64::from(c)) - } -} - -impl TryFrom for NamedChain { - type Error = >::Error; - - fn try_from(chain: Chain) -> Result { - match chain { - Chain::Named(chain) => Ok(chain), - Chain::Id(id) => id.try_into(), - } - } -} - -impl FromStr for Chain { - type Err = String; - - fn from_str(s: &str) -> Result { - if let Ok(chain) = NamedChain::from_str(s) { - Ok(Chain::Named(chain)) - } else { - s.parse::() - .map(Chain::Id) - .map_err(|_| format!("Expected known chain or integer, found: {s}")) - } - } -} - -impl Encodable for Chain { - fn encode(&self, out: &mut dyn alloy_rlp::BufMut) { - match self { - Self::Named(chain) => u64::from(*chain).encode(out), - Self::Id(id) => id.encode(out), - } - } - fn length(&self) -> usize { - match self { - Self::Named(chain) => u64::from(*chain).length(), - Self::Id(id) => id.length(), - } - } -} - -impl Decodable for Chain { - fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { - Ok(u64::decode(buf)?.into()) - } -} - -impl Default for Chain { - fn default() -> Self { - NamedChain::Mainnet.into() - } -} - -#[cfg(any(test, feature = "arbitrary"))] -impl<'a> arbitrary::Arbitrary<'a> for Chain { - fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - if u.ratio(1, 2)? { - let chain = u.int_in_range(0..=(NamedChain::COUNT - 1))?; - - return Ok(Chain::Named(NamedChain::iter().nth(chain).expect("in range"))) - } - - Ok(Self::Id(u64::arbitrary(u)?)) - } -} - -#[cfg(any(test, feature = "arbitrary"))] -use strum::IntoEnumIterator; - -#[cfg(any(test, feature = "arbitrary"))] -use proptest::{ - arbitrary::ParamsFor, - prelude::{any, Strategy}, - sample::Selector, - strategy::BoxedStrategy, -}; - -#[cfg(any(test, feature = "arbitrary"))] -impl proptest::arbitrary::Arbitrary for Chain { - type Parameters = ParamsFor; - fn arbitrary_with(_: Self::Parameters) -> Self::Strategy { - let named = - any::().prop_map(move |sel| Chain::Named(sel.select(NamedChain::iter()))); - let id = any::().prop_map(Chain::from); - proptest::strategy::Union::new_weighted(vec![(50, named.boxed()), (50, id.boxed())]).boxed() - } - - type Strategy = BoxedStrategy; -} #[cfg(test)] mod tests { use super::*; + use crate::U256; + use alloy_rlp::Encodable; + use std::str::FromStr; #[test] fn test_id() { - let chain = Chain::Id(1234); + let chain = Chain::from(1234); assert_eq!(chain.id(), 1234); } #[test] fn test_named_id() { - let chain = Chain::Named(NamedChain::Goerli); + let chain = Chain::from_named(NamedChain::Goerli); assert_eq!(chain.id(), 5); } #[test] fn test_display_named_chain() { - let chain = Chain::Named(NamedChain::Mainnet); + let chain = Chain::from_named(NamedChain::Mainnet); assert_eq!(format!("{chain}"), "mainnet"); } #[test] fn test_display_id_chain() { - let chain = Chain::Id(1234); + let chain = Chain::from(1234); assert_eq!(format!("{chain}"), "1234"); } #[test] fn test_from_u256() { let n = U256::from(1234); - let chain = Chain::from(n); - let expected = Chain::Id(1234); + let chain = Chain::from(n.to::()); + let expected = Chain::from(1234); assert_eq!(chain, expected); } #[test] fn test_into_u256() { - let chain = Chain::Named(NamedChain::Goerli); - let n: U256 = chain.into(); + let chain = Chain::from_named(NamedChain::Goerli); + let n: U256 = U256::from(chain.id()); let expected = U256::from(5); assert_eq!(n, expected); } - #[test] - #[allow(non_snake_case)] - fn test_into_U64() { - let chain = Chain::Named(NamedChain::Goerli); - let n: U64 = chain.into(); - let expected = U64::from(5); - - assert_eq!(n, expected); - } - #[test] fn test_from_str_named_chain() { let result = Chain::from_str("mainnet"); - let expected = Chain::Named(NamedChain::Mainnet); + let expected = Chain::from_named(NamedChain::Mainnet); assert!(result.is_ok()); assert_eq!(result.unwrap(), expected); @@ -449,7 +81,7 @@ mod tests { #[test] fn test_from_str_id_chain() { let result = Chain::from_str("1234"); - let expected = Chain::Id(1234); + let expected = Chain::from(1234); assert!(result.is_ok()); assert_eq!(result.unwrap(), expected); @@ -458,14 +90,14 @@ mod tests { #[test] fn test_default() { let default = Chain::default(); - let expected = Chain::Named(NamedChain::Mainnet); + let expected = Chain::from_named(NamedChain::Mainnet); assert_eq!(default, expected); } #[test] fn test_id_chain_encodable_length() { - let chain = Chain::Id(1234); + let chain = Chain::from(1234); assert_eq!(chain.length(), 3); } diff --git a/crates/primitives/src/chain/spec.rs b/crates/primitives/src/chain/spec.rs index a514406b5..a3abff65d 100644 --- a/crates/primitives/src/chain/spec.rs +++ b/crates/primitives/src/chain/spec.rs @@ -3,11 +3,14 @@ use crate::{ EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR, EIP1559_DEFAULT_ELASTICITY_MULTIPLIER, EIP1559_INITIAL_BASE_FEE, EMPTY_RECEIPTS, EMPTY_TRANSACTIONS, EMPTY_WITHDRAWALS, }, + holesky_nodes, + net::{goerli_nodes, mainnet_nodes, sepolia_nodes}, proofs::state_root_ref_unhashed, revm_primitives::{address, b256}, - Address, BlockNumber, Chain, ForkFilter, ForkFilterKey, ForkHash, ForkId, Genesis, Hardfork, - Head, Header, SealedHeader, B256, EMPTY_OMMER_ROOT_HASH, U256, + Address, BlockNumber, ForkFilter, ForkFilterKey, ForkHash, ForkId, Genesis, Hardfork, Head, + Header, NodeRecord, SealedHeader, B256, EMPTY_OMMER_ROOT_HASH, U256, }; +use alloy_chains::{Chain, NamedChain}; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; use std::{ @@ -960,6 +963,19 @@ impl ChainSpec { pub fn builder() -> ChainSpecBuilder { ChainSpecBuilder::default() } + + /// Returns the known bootnode records for the given chain. + pub fn bootnodes(&self) -> Option> { + use NamedChain as C; + let chain = self.chain; + match chain.try_into().ok()? { + C::Mainnet => Some(mainnet_nodes()), + C::Goerli => Some(goerli_nodes()), + C::Sepolia => Some(sepolia_nodes()), + C::Holesky => Some(holesky_nodes()), + _ => None, + } + } } impl From for ChainSpec { @@ -1603,17 +1619,17 @@ impl DepositContract { #[cfg(test)] mod tests { use super::*; + #[cfg(feature = "optimism")] + use crate::OP_GOERLI; use crate::{ - b256, hex, trie::TrieAccount, ChainConfig, GenesisAccount, NamedChain, B256, DEV, GOERLI, - HOLESKY, MAINNET, SEPOLIA, U256, + b256, hex, trie::TrieAccount, ChainConfig, GenesisAccount, B256, DEV, GOERLI, HOLESKY, + MAINNET, SEPOLIA, U256, }; + use alloy_chains::NamedChain; use alloy_rlp::Encodable; use bytes::BytesMut; use std::{collections::HashMap, str::FromStr}; - #[cfg(feature = "optimism")] - use crate::OP_GOERLI; - fn test_fork_ids(spec: &ChainSpec, cases: &[(Head, ForkId)]) { for (block, expected_id) in cases { let computed_id = spec.fork_id(block); @@ -2494,7 +2510,7 @@ Post-merge hard forks (timestamp based): fn test_timestamp_fork_in_genesis() { let timestamp = 1690475657u64; let default_spec_builder = ChainSpecBuilder::default() - .chain(Chain::Id(1337)) + .chain(Chain::from_id(1337)) .genesis(Genesis::default().with_timestamp(timestamp)) .paris_activated(); @@ -2755,7 +2771,7 @@ Post-merge hard forks (timestamp based): let genesis = serde_json::from_str::(hive_json).unwrap(); let chainspec: ChainSpec = genesis.into(); assert_eq!(chainspec.genesis_hash, None); - assert_eq!(chainspec.chain, Chain::Named(NamedChain::Optimism)); + assert_eq!(chainspec.chain, Chain::from_named(NamedChain::Optimism)); let expected_state_root: B256 = hex!("9a6049ac535e3dc7436c189eaa81c73f35abd7f282ab67c32944ff0301d63360").into(); assert_eq!(chainspec.genesis_header().state_root, expected_state_root); @@ -2827,7 +2843,7 @@ Post-merge hard forks (timestamp based): // set the gas limit from the hive test genesis according to the hash let genesis = Genesis { gas_limit: 0x2fefd8u64, ..Default::default() }; let default_chainspec = ChainSpecBuilder::default() - .chain(Chain::Id(1337)) + .chain(Chain::from_id(1337)) .genesis(genesis) .cancun_activated() .build(); diff --git a/crates/primitives/src/revm/config.rs b/crates/primitives/src/revm/config.rs index 8e9619be4..5e6bef55a 100644 --- a/crates/primitives/src/revm/config.rs +++ b/crates/primitives/src/revm/config.rs @@ -138,7 +138,7 @@ mod tests { { #[inline(always)] fn op_cs(f: impl FnOnce(ChainSpecBuilder) -> ChainSpecBuilder) -> ChainSpec { - let cs = ChainSpecBuilder::mainnet().chain(crate::Chain::Id(10)); + let cs = ChainSpecBuilder::mainnet().chain(alloy_chains::Chain::from_id(10)); f(cs).build() } diff --git a/crates/trie/Cargo.toml b/crates/trie/Cargo.toml index 8593ad839..7f446a400 100644 --- a/crates/trie/Cargo.toml +++ b/crates/trie/Cargo.toml @@ -18,7 +18,7 @@ reth-interfaces.workspace = true reth-db.workspace = true alloy-rlp.workspace = true - +alloy-chains.workspace = true # tokio tokio = { workspace = true, default-features = false, features = ["sync"] } diff --git a/crates/trie/src/proof.rs b/crates/trie/src/proof.rs index 68f876759..ce73bcaf0 100644 --- a/crates/trie/src/proof.rs +++ b/crates/trie/src/proof.rs @@ -165,10 +165,11 @@ where mod tests { use super::*; use crate::StateRoot; + use alloy_chains::Chain; use once_cell::sync::Lazy; use reth_db::database::Database; use reth_interfaces::RethResult; - use reth_primitives::{Account, Bytes, Chain, ChainSpec, StorageEntry, HOLESKY, MAINNET, U256}; + use reth_primitives::{Account, Bytes, ChainSpec, StorageEntry, HOLESKY, MAINNET, U256}; use reth_provider::{test_utils::create_test_provider_factory, HashingWriter, ProviderFactory}; use std::{str::FromStr, sync::Arc}; @@ -185,7 +186,7 @@ mod tests { */ static TEST_SPEC: Lazy> = Lazy::new(|| { ChainSpec { - chain: Chain::Id(12345), + chain: Chain::from_id(12345), genesis: serde_json::from_str(include_str!("../testdata/proof-genesis.json")) .expect("Can't deserialize test genesis json"), ..Default::default() diff --git a/examples/manual-p2p/Cargo.toml b/examples/manual-p2p/Cargo.toml index 9e463ae8c..a7beb353e 100644 --- a/examples/manual-p2p/Cargo.toml +++ b/examples/manual-p2p/Cargo.toml @@ -14,7 +14,6 @@ reth-network.workspace = true reth-discv4.workspace = true reth-eth-wire.workspace = true reth-ecies.workspace = true - futures.workspace = true secp256k1.workspace = true tokio.workspace = true