Skip to main content

reth_chainspec/
lib.rs

1//! The spec of an Ethereum network
2
3#![doc(
4    html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
5    html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
6    issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
7)]
8#![cfg_attr(not(test), warn(unused_crate_dependencies))]
9#![cfg_attr(docsrs, feature(doc_cfg))]
10#![cfg_attr(not(feature = "std"), no_std)]
11
12extern crate alloc;
13
14/// Chain specific constants
15mod constants;
16pub use constants::*;
17
18mod api;
19/// The chain info module.
20mod info;
21/// The chain spec module.
22mod spec;
23
24pub use alloy_chains::{Chain, ChainKind, NamedChain};
25/// Re-export for convenience
26pub use reth_ethereum_forks::*;
27
28pub use alloy_evm::EvmLimitParams;
29pub use api::EthChainSpec;
30pub use info::ChainInfo;
31#[cfg(any(test, feature = "test-utils"))]
32pub use spec::test_fork_ids;
33pub use spec::{
34    blob_params_to_schedule, create_chain_config, mainnet_chain_config, make_genesis_header,
35    BaseFeeParams, BaseFeeParamsKind, ChainSpec, ChainSpecBuilder, ChainSpecProvider,
36    DepositContract, ForkBaseFeeParams, DEV, HOLESKY, HOODI, MAINNET, SEPOLIA,
37};
38
39use reth_primitives_traits::sync::OnceLock;
40
41/// Simple utility to create a thread-safe sync cell with a value set.
42pub fn once_cell_set<T>(value: T) -> OnceLock<T> {
43    let once = OnceLock::new();
44    let _ = once.set(value);
45    once
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51    use alloy_primitives::U256;
52    use alloy_rlp::Encodable;
53    use std::str::FromStr;
54
55    #[test]
56    fn test_id() {
57        let chain = Chain::from(1234);
58        assert_eq!(chain.id(), 1234);
59    }
60
61    #[test]
62    fn test_named_id() {
63        let chain = Chain::from_named(NamedChain::Holesky);
64        assert_eq!(chain.id(), 17000);
65    }
66
67    #[test]
68    fn test_display_named_chain() {
69        let chain = Chain::from_named(NamedChain::Mainnet);
70        assert_eq!(format!("{chain}"), "mainnet");
71    }
72
73    #[test]
74    fn test_display_id_chain() {
75        let chain = Chain::from(1234);
76        assert_eq!(format!("{chain}"), "1234");
77    }
78
79    #[test]
80    fn test_from_u256() {
81        let n = U256::from(1234);
82        let chain = Chain::from(n.to::<u64>());
83        let expected = Chain::from(1234);
84
85        assert_eq!(chain, expected);
86    }
87
88    #[test]
89    fn test_into_u256() {
90        let chain = Chain::from_named(NamedChain::Holesky);
91        let n: U256 = U256::from(chain.id());
92        let expected = U256::from(17000);
93
94        assert_eq!(n, expected);
95    }
96
97    #[test]
98    fn test_from_str_named_chain() {
99        let result = Chain::from_str("mainnet");
100        let expected = Chain::from_named(NamedChain::Mainnet);
101
102        assert!(result.is_ok());
103        assert_eq!(result.unwrap(), expected);
104    }
105
106    #[test]
107    fn test_from_str_named_chain_error() {
108        let result = Chain::from_str("chain");
109
110        assert!(result.is_err());
111    }
112
113    #[test]
114    fn test_from_str_id_chain() {
115        let result = Chain::from_str("1234");
116        let expected = Chain::from(1234);
117
118        assert!(result.is_ok());
119        assert_eq!(result.unwrap(), expected);
120    }
121
122    #[test]
123    fn test_default() {
124        let default = Chain::default();
125        let expected = Chain::from_named(NamedChain::Mainnet);
126
127        assert_eq!(default, expected);
128    }
129
130    #[test]
131    fn test_id_chain_encodable_length() {
132        let chain = Chain::from(1234);
133
134        assert_eq!(chain.length(), 3);
135    }
136
137    #[test]
138    fn test_dns_main_network() {
139        let s = "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.mainnet.ethdisco.net";
140        let chain: Chain = NamedChain::Mainnet.into();
141        assert_eq!(s, chain.public_dns_network_protocol().unwrap().as_str());
142    }
143
144    #[test]
145    fn test_dns_holesky_network() {
146        let s = "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.holesky.ethdisco.net";
147        let chain: Chain = NamedChain::Holesky.into();
148        assert_eq!(s, chain.public_dns_network_protocol().unwrap().as_str());
149    }
150
151    #[test]
152    fn test_centralized_base_fee_calculation() {
153        use crate::{ChainSpec, EthChainSpec};
154        use alloy_consensus::Header;
155        use alloy_eips::eip1559::INITIAL_BASE_FEE;
156
157        fn parent_header() -> Header {
158            Header {
159                gas_used: 15_000_000,
160                gas_limit: 30_000_000,
161                base_fee_per_gas: Some(INITIAL_BASE_FEE),
162                timestamp: 1_000,
163                ..Default::default()
164            }
165        }
166
167        let spec = ChainSpec::default();
168        let parent = parent_header();
169
170        // For testing, assume next block has timestamp 12 seconds later
171        let next_timestamp = parent.timestamp + 12;
172
173        let expected = parent
174            .next_block_base_fee(spec.base_fee_params_at_timestamp(next_timestamp))
175            .unwrap_or_default();
176
177        let got = spec.next_block_base_fee(&parent, next_timestamp).unwrap_or_default();
178        assert_eq!(expected, got, "Base fee calculation does not match expected value");
179    }
180}