Revert "feat: support time-based forking" (#1090)

This commit is contained in:
Georgios Konstantopoulos
2023-01-30 10:58:55 -08:00
committed by GitHub
parent b7b978fdea
commit 0c341ed9ce
17 changed files with 312 additions and 453 deletions

View File

@ -10,8 +10,8 @@ use reth_db::{
Error as DbError, Error as DbError,
}; };
use reth_primitives::{ use reth_primitives::{
keccak256, Account as RethAccount, Address, ChainSpec, Hardfork, JsonU256, SealedBlock, keccak256, Account as RethAccount, Address, ChainSpec, JsonU256, SealedBlock, SealedHeader,
SealedHeader, StorageEntry, H256, U256, StorageEntry, H256, U256,
}; };
use reth_rlp::Decodable; use reth_rlp::Decodable;
use reth_stages::{stages::ExecutionStage, ExecInput, Stage, StageId, Transaction}; use reth_stages::{stages::ExecutionStage, ExecInput, Stage, StageId, Transaction};
@ -20,7 +20,7 @@ use std::{
ffi::OsStr, ffi::OsStr,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use tracing::{debug, trace, warn}; use tracing::{debug, trace};
/// The outcome of a test. /// The outcome of a test.
#[derive(Debug)] #[derive(Debug)]
@ -125,7 +125,7 @@ pub async fn run_test(path: PathBuf) -> eyre::Result<TestOutcome> {
let chain_spec: ChainSpec = suite.network.into(); let chain_spec: ChainSpec = suite.network.into();
// if paris aka merge is not activated we dont have block rewards; // if paris aka merge is not activated we dont have block rewards;
let has_block_reward = chain_spec.fork_block(Hardfork::Paris).is_some(); let has_block_reward = chain_spec.paris_status().block_number().is_some();
// Create db and acquire transaction // Create db and acquire transaction
let db = create_test_rw_db(); let db = create_test_rw_db();
@ -198,9 +198,8 @@ pub async fn run_test(path: PathBuf) -> eyre::Result<TestOutcome> {
{ {
let mut transaction = Transaction::new(db.as_ref())?; let mut transaction = Transaction::new(db.as_ref())?;
if let Err(err) = stage.execute(&mut transaction, input).await { // ignore error
warn!("{:#}", err); let _ = stage.execute(&mut transaction, input).await;
}
transaction.commit()?; transaction.commit()?;
} }

View File

@ -1,9 +1,7 @@
//! Consensus for ethereum network //! Consensus for ethereum network
use crate::verification; use crate::verification;
use reth_interfaces::consensus::{Consensus, Error, ForkchoiceState}; use reth_interfaces::consensus::{Consensus, Error, ForkchoiceState};
use reth_primitives::{ use reth_primitives::{BlockNumber, ChainSpec, SealedBlock, SealedHeader, H256};
BlockNumber, ChainSpec, ForkDiscriminant, Hardfork, SealedBlock, SealedHeader, H256,
};
use tokio::sync::{watch, watch::error::SendError}; use tokio::sync::{watch, watch::error::SendError};
/// Ethereum beacon consensus /// Ethereum beacon consensus
@ -48,13 +46,7 @@ impl Consensus for BeaconConsensus {
verification::validate_header_standalone(header, &self.chain_spec)?; verification::validate_header_standalone(header, &self.chain_spec)?;
verification::validate_header_regarding_parent(parent, header, &self.chain_spec)?; verification::validate_header_regarding_parent(parent, header, &self.chain_spec)?;
if !self.chain_spec.fork_active( if Some(header.number) < self.chain_spec.paris_status().block_number() {
Hardfork::Paris,
ForkDiscriminant::ttd(
self.chain_spec.terminal_total_difficulty().unwrap_or_default(),
Some(header.number),
),
) {
// TODO Consensus checks for old blocks: // TODO Consensus checks for old blocks:
// * difficulty, mix_hash & nonce aka PoW stuff // * difficulty, mix_hash & nonce aka PoW stuff
// low priority as syncing is done in reverse order // low priority as syncing is done in reverse order
@ -67,12 +59,6 @@ impl Consensus for BeaconConsensus {
} }
fn has_block_reward(&self, block_num: BlockNumber) -> bool { fn has_block_reward(&self, block_num: BlockNumber) -> bool {
!self.chain_spec.fork_active( Some(block_num) < self.chain_spec.paris_status().block_number()
Hardfork::Paris,
ForkDiscriminant::ttd(
self.chain_spec.terminal_total_difficulty().unwrap_or_default(),
Some(block_num),
),
)
} }
} }

View File

@ -198,7 +198,7 @@ impl<Client: HeaderProvider + BlockProvider + StateProvider> ConsensusEngine
}; };
if let Some(parent_td) = self.client.header_td(&block.parent_hash)? { if let Some(parent_td) = self.client.header_td(&block.parent_hash)? {
if Some(parent_td) <= self.chain_spec.terminal_total_difficulty() { if Some(parent_td) <= self.chain_spec.paris_status().terminal_total_difficulty() {
return Ok(PayloadStatus::from_status(PayloadStatusEnum::Invalid { return Ok(PayloadStatus::from_status(PayloadStatusEnum::Invalid {
validation_error: EngineApiError::PayloadPreMerge.to_string(), validation_error: EngineApiError::PayloadPreMerge.to_string(),
})) }))
@ -281,6 +281,7 @@ impl<Client: HeaderProvider + BlockProvider + StateProvider> ConsensusEngine
let merge_terminal_td = self let merge_terminal_td = self
.chain_spec .chain_spec
.paris_status()
.terminal_total_difficulty() .terminal_total_difficulty()
.ok_or(EngineApiError::UnknownMergeTerminalTotalDifficulty)?; .ok_or(EngineApiError::UnknownMergeTerminalTotalDifficulty)?;
@ -525,7 +526,8 @@ mod tests {
let (result_tx, result_rx) = oneshot::channel(); let (result_tx, result_rx) = oneshot::channel();
let parent = transform_block(random_block(100, None, None, Some(0)), |mut b| { let parent = transform_block(random_block(100, None, None, Some(0)), |mut b| {
b.header.difficulty = chain_spec.terminal_total_difficulty().unwrap(); b.header.difficulty =
chain_spec.paris_status().terminal_total_difficulty().unwrap();
b b
}); });
let block = random_block(101, Some(parent.hash()), None, Some(0)); let block = random_block(101, Some(parent.hash()), None, Some(0));
@ -563,7 +565,7 @@ mod tests {
let parent = transform_block(random_block(100, None, None, Some(0)), |mut b| { let parent = transform_block(random_block(100, None, None, Some(0)), |mut b| {
b.header.timestamp = parent_timestamp; b.header.timestamp = parent_timestamp;
b.header.difficulty = b.header.difficulty =
chain_spec.terminal_total_difficulty().unwrap() + U256::from(1); chain_spec.paris_status().terminal_total_difficulty().unwrap() + U256::from(1);
b b
}); });
let block = let block =
@ -641,7 +643,10 @@ mod tests {
tokio::spawn(engine); tokio::spawn(engine);
let transition_config = TransitionConfiguration { let transition_config = TransitionConfiguration {
terminal_total_difficulty: chain_spec.terminal_total_difficulty().unwrap() + terminal_total_difficulty: chain_spec
.paris_status()
.terminal_total_difficulty()
.unwrap() +
U256::from(1), U256::from(1),
..Default::default() ..Default::default()
}; };
@ -656,7 +661,7 @@ mod tests {
assert_matches!( assert_matches!(
result_rx.await, result_rx.await,
Ok(Err(EngineApiError::TerminalTD { execution, consensus })) Ok(Err(EngineApiError::TerminalTD { execution, consensus }))
if execution == chain_spec.terminal_total_difficulty().unwrap() if execution == chain_spec.paris_status().terminal_total_difficulty().unwrap()
&& consensus == U256::from(transition_config.terminal_total_difficulty) && consensus == U256::from(transition_config.terminal_total_difficulty)
); );
} }
@ -680,7 +685,10 @@ mod tests {
let execution_terminal_block = random_block(terminal_block_number, None, None, None); let execution_terminal_block = random_block(terminal_block_number, None, None, None);
let transition_config = TransitionConfiguration { let transition_config = TransitionConfiguration {
terminal_total_difficulty: chain_spec.terminal_total_difficulty().unwrap(), terminal_total_difficulty: chain_spec
.paris_status()
.terminal_total_difficulty()
.unwrap(),
terminal_block_hash: consensus_terminal_block.hash(), terminal_block_hash: consensus_terminal_block.hash(),
terminal_block_number: terminal_block_number.into(), terminal_block_number: terminal_block_number.into(),
}; };
@ -739,7 +747,10 @@ mod tests {
let terminal_block = random_block(terminal_block_number, None, None, None); let terminal_block = random_block(terminal_block_number, None, None, None);
let transition_config = TransitionConfiguration { let transition_config = TransitionConfiguration {
terminal_total_difficulty: chain_spec.terminal_total_difficulty().unwrap(), terminal_total_difficulty: chain_spec
.paris_status()
.terminal_total_difficulty()
.unwrap(),
terminal_block_hash: terminal_block.hash(), terminal_block_hash: terminal_block.hash(),
terminal_block_number: terminal_block_number.into(), terminal_block_number: terminal_block_number.into(),
}; };

View File

@ -1,9 +1,8 @@
//! ALl functions for verification of block //! ALl functions for verification of block
use reth_interfaces::{consensus::Error, Result as RethResult}; use reth_interfaces::{consensus::Error, Result as RethResult};
use reth_primitives::{ use reth_primitives::{
BlockNumber, ChainSpec, ForkDiscriminant, Hardfork, Header, SealedBlock, SealedHeader, BlockNumber, ChainSpec, Hardfork, Header, SealedBlock, SealedHeader, Transaction,
Transaction, TransactionSignedEcRecovered, TxEip1559, TxEip2930, TxLegacy, EMPTY_OMMER_ROOT, TransactionSignedEcRecovered, TxEip1559, TxEip2930, TxLegacy, EMPTY_OMMER_ROOT, U256,
U256,
}; };
use reth_provider::{AccountProvider, HeaderProvider}; use reth_provider::{AccountProvider, HeaderProvider};
use std::{ use std::{
@ -40,21 +39,14 @@ pub fn validate_header_standalone(
} }
// Check if base fee is set. // Check if base fee is set.
if chain_spec.fork_active(Hardfork::London, header.number.into()) && if chain_spec.fork_active(Hardfork::London, header.number) && header.base_fee_per_gas.is_none()
header.base_fee_per_gas.is_none()
{ {
return Err(Error::BaseFeeMissing) return Err(Error::BaseFeeMissing)
} }
// EIP-3675: Upgrade consensus to Proof-of-Stake: // EIP-3675: Upgrade consensus to Proof-of-Stake:
// https://eips.ethereum.org/EIPS/eip-3675#replacing-difficulty-with-0 // https://eips.ethereum.org/EIPS/eip-3675#replacing-difficulty-with-0
if chain_spec.fork_active( if Some(header.number) >= chain_spec.paris_status().block_number() {
Hardfork::Paris,
ForkDiscriminant::ttd(
chain_spec.terminal_total_difficulty().unwrap_or_default(),
Some(header.number),
),
) {
if header.difficulty != U256::ZERO { if header.difficulty != U256::ZERO {
return Err(Error::TheMergeDifficultyIsNotZero) return Err(Error::TheMergeDifficultyIsNotZero)
} }
@ -86,7 +78,7 @@ pub fn validate_transaction_regarding_header(
let chain_id = match transaction { let chain_id = match transaction {
Transaction::Legacy(TxLegacy { chain_id, .. }) => { Transaction::Legacy(TxLegacy { chain_id, .. }) => {
// EIP-155: Simple replay attack protection: https://eips.ethereum.org/EIPS/eip-155 // EIP-155: Simple replay attack protection: https://eips.ethereum.org/EIPS/eip-155
if chain_spec.fork_active(Hardfork::SpuriousDragon, at_block_number.into()) && if chain_spec.fork_active(Hardfork::SpuriousDragon, at_block_number) &&
chain_id.is_some() chain_id.is_some()
{ {
return Err(Error::TransactionOldLegacyChainId) return Err(Error::TransactionOldLegacyChainId)
@ -95,7 +87,7 @@ pub fn validate_transaction_regarding_header(
} }
Transaction::Eip2930(TxEip2930 { chain_id, .. }) => { Transaction::Eip2930(TxEip2930 { chain_id, .. }) => {
// EIP-2930: Optional access lists: https://eips.ethereum.org/EIPS/eip-2930 (New transaction type) // EIP-2930: Optional access lists: https://eips.ethereum.org/EIPS/eip-2930 (New transaction type)
if !chain_spec.fork_active(Hardfork::Berlin, at_block_number.into()) { if !chain_spec.fork_active(Hardfork::Berlin, at_block_number) {
return Err(Error::TransactionEip2930Disabled) return Err(Error::TransactionEip2930Disabled)
} }
Some(*chain_id) Some(*chain_id)
@ -107,7 +99,7 @@ pub fn validate_transaction_regarding_header(
.. ..
}) => { }) => {
// EIP-1559: Fee market change for ETH 1.0 chain https://eips.ethereum.org/EIPS/eip-1559 // EIP-1559: Fee market change for ETH 1.0 chain https://eips.ethereum.org/EIPS/eip-1559
if !chain_spec.fork_active(Hardfork::Berlin, at_block_number.into()) { if !chain_spec.fork_active(Hardfork::Berlin, at_block_number) {
return Err(Error::TransactionEip1559Disabled) return Err(Error::TransactionEip1559Disabled)
} }
@ -267,13 +259,7 @@ pub fn validate_header_regarding_parent(
} }
// difficulty check is done by consensus. // difficulty check is done by consensus.
if !chain_spec.fork_active( if chain_spec.paris_status().block_number() > Some(child.number) {
Hardfork::Paris,
ForkDiscriminant::ttd(
chain_spec.terminal_total_difficulty().unwrap_or_default(),
Some(child.number),
),
) {
// TODO how this needs to be checked? As ice age did increment it by some formula // TODO how this needs to be checked? As ice age did increment it by some formula
} }
@ -301,7 +287,7 @@ pub fn validate_header_regarding_parent(
} }
// EIP-1559 check base fee // EIP-1559 check base fee
if chain_spec.fork_active(Hardfork::London, child.number.into()) { if chain_spec.fork_active(Hardfork::London, child.number) {
let base_fee = child.base_fee_per_gas.ok_or(Error::BaseFeeMissing)?; let base_fee = child.base_fee_per_gas.ok_or(Error::BaseFeeMissing)?;
let expected_base_fee = if chain_spec.fork_block(Hardfork::London) == Some(child.number) { let expected_base_fee = if chain_spec.fork_block(Hardfork::London) == Some(child.number) {

View File

@ -1,6 +1,6 @@
//! Reth block execution/validation configuration and constants //! Reth block execution/validation configuration and constants
use reth_primitives::{ChainSpec, ForkDiscriminant, Hardfork}; use reth_primitives::{BlockNumber, ChainSpec, Hardfork};
/// Two ethereum worth of wei /// Two ethereum worth of wei
pub const WEI_2ETH: u128 = 2000000000000000000u128; pub const WEI_2ETH: u128 = 2000000000000000000u128;
@ -10,19 +10,19 @@ pub const WEI_3ETH: u128 = 3000000000000000000u128;
pub const WEI_5ETH: u128 = 5000000000000000000u128; pub const WEI_5ETH: u128 = 5000000000000000000u128;
/// return revm_spec from spec configuration. /// return revm_spec from spec configuration.
pub fn revm_spec(chain_spec: &ChainSpec, discriminant: ForkDiscriminant) -> revm::SpecId { pub fn revm_spec(chain_spec: &ChainSpec, for_block: BlockNumber) -> revm::SpecId {
match discriminant { match for_block {
d if chain_spec.fork_active(Hardfork::Shanghai, d) => revm::MERGE_EOF, b if chain_spec.fork_active(Hardfork::Shanghai, b) => revm::MERGE_EOF,
d if chain_spec.fork_active(Hardfork::Paris, d) => revm::MERGE, b if Some(b) >= chain_spec.paris_status().block_number() => revm::MERGE,
d if chain_spec.fork_active(Hardfork::London, d) => revm::LONDON, b if chain_spec.fork_active(Hardfork::London, b) => revm::LONDON,
d if chain_spec.fork_active(Hardfork::Berlin, d) => revm::BERLIN, b if chain_spec.fork_active(Hardfork::Berlin, b) => revm::BERLIN,
d if chain_spec.fork_active(Hardfork::Istanbul, d) => revm::ISTANBUL, b if chain_spec.fork_active(Hardfork::Istanbul, b) => revm::ISTANBUL,
d if chain_spec.fork_active(Hardfork::Petersburg, d) => revm::PETERSBURG, b if chain_spec.fork_active(Hardfork::Petersburg, b) => revm::PETERSBURG,
d if chain_spec.fork_active(Hardfork::Byzantium, d) => revm::BYZANTIUM, b if chain_spec.fork_active(Hardfork::Byzantium, b) => revm::BYZANTIUM,
d if chain_spec.fork_active(Hardfork::SpuriousDragon, d) => revm::SPURIOUS_DRAGON, b if chain_spec.fork_active(Hardfork::SpuriousDragon, b) => revm::SPURIOUS_DRAGON,
d if chain_spec.fork_active(Hardfork::Tangerine, d) => revm::TANGERINE, b if chain_spec.fork_active(Hardfork::Tangerine, b) => revm::TANGERINE,
d if chain_spec.fork_active(Hardfork::Homestead, d) => revm::HOMESTEAD, b if chain_spec.fork_active(Hardfork::Homestead, b) => revm::HOMESTEAD,
d if chain_spec.fork_active(Hardfork::Frontier, d) => revm::FRONTIER, b if chain_spec.fork_active(Hardfork::Frontier, b) => revm::FRONTIER,
_ => panic!("wrong configuration"), _ => panic!("wrong configuration"),
} }
} }
@ -30,106 +30,62 @@ pub fn revm_spec(chain_spec: &ChainSpec, discriminant: ForkDiscriminant) -> revm
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::config::revm_spec; use crate::config::revm_spec;
use reth_primitives::{ChainSpecBuilder, ForkDiscriminant, MAINNET, U256}; use reth_primitives::{ChainSpecBuilder, MAINNET};
#[test] #[test]
fn test_to_revm_spec() { fn test_to_revm_spec() {
let discriminant = ForkDiscriminant::new(1, U256::from(1), 1);
assert_eq!( assert_eq!(
revm_spec(&ChainSpecBuilder::mainnet().shangai_activated().build(), discriminant), revm_spec(&ChainSpecBuilder::mainnet().paris_activated().build(), 1),
revm::MERGE_EOF
);
assert_eq!(
revm_spec(&ChainSpecBuilder::mainnet().paris_activated().build(), discriminant),
revm::MERGE revm::MERGE
); );
assert_eq!( assert_eq!(
revm_spec(&ChainSpecBuilder::mainnet().london_activated().build(), discriminant), revm_spec(&ChainSpecBuilder::mainnet().london_activated().build(), 1),
revm::LONDON revm::LONDON
); );
assert_eq!( assert_eq!(
revm_spec(&ChainSpecBuilder::mainnet().berlin_activated().build(), discriminant), revm_spec(&ChainSpecBuilder::mainnet().berlin_activated().build(), 1),
revm::BERLIN revm::BERLIN
); );
assert_eq!( assert_eq!(
revm_spec(&ChainSpecBuilder::mainnet().istanbul_activated().build(), discriminant), revm_spec(&ChainSpecBuilder::mainnet().istanbul_activated().build(), 1),
revm::ISTANBUL revm::ISTANBUL
); );
assert_eq!( assert_eq!(
revm_spec(&ChainSpecBuilder::mainnet().petersburg_activated().build(), discriminant), revm_spec(&ChainSpecBuilder::mainnet().petersburg_activated().build(), 1),
revm::PETERSBURG revm::PETERSBURG
); );
assert_eq!( assert_eq!(
revm_spec(&ChainSpecBuilder::mainnet().byzantium_activated().build(), discriminant), revm_spec(&ChainSpecBuilder::mainnet().byzantium_activated().build(), 1),
revm::BYZANTIUM revm::BYZANTIUM
); );
assert_eq!( assert_eq!(
revm_spec( revm_spec(&ChainSpecBuilder::mainnet().spurious_dragon_activated().build(), 1),
&ChainSpecBuilder::mainnet().spurious_dragon_activated().build(),
discriminant
),
revm::SPURIOUS_DRAGON revm::SPURIOUS_DRAGON
); );
assert_eq!( assert_eq!(
revm_spec( revm_spec(&ChainSpecBuilder::mainnet().tangerine_whistle_activated().build(), 1),
&ChainSpecBuilder::mainnet().tangerine_whistle_activated().build(),
discriminant
),
revm::TANGERINE revm::TANGERINE
); );
assert_eq!( assert_eq!(
revm_spec(&ChainSpecBuilder::mainnet().homestead_activated().build(), discriminant), revm_spec(&ChainSpecBuilder::mainnet().homestead_activated().build(), 1),
revm::HOMESTEAD revm::HOMESTEAD
); );
assert_eq!( assert_eq!(
revm_spec(&ChainSpecBuilder::mainnet().frontier_activated().build(), discriminant), revm_spec(&ChainSpecBuilder::mainnet().frontier_activated().build(), 1),
revm::FRONTIER revm::FRONTIER
); );
} }
#[test] #[test]
fn test_eth_spec() { fn test_eth_spec() {
let post_merge_td = MAINNET.terminal_total_difficulty().unwrap(); assert_eq!(revm_spec(&MAINNET, 15537394 + 10), revm::MERGE);
let pre_merge_td = post_merge_td.saturating_sub(U256::from(10)); assert_eq!(revm_spec(&MAINNET, 15537394 - 10), revm::LONDON);
assert_eq!(revm_spec(&MAINNET, 12244000 + 10), revm::BERLIN);
assert_eq!( assert_eq!(revm_spec(&MAINNET, 12244000 - 10), revm::ISTANBUL);
revm_spec(&MAINNET, ForkDiscriminant::new(15537394 + 10, post_merge_td, 1674477448)), assert_eq!(revm_spec(&MAINNET, 7280000 + 10), revm::PETERSBURG);
revm::MERGE assert_eq!(revm_spec(&MAINNET, 7280000 - 10), revm::BYZANTIUM);
); assert_eq!(revm_spec(&MAINNET, 2675000 + 10), revm::SPURIOUS_DRAGON);
assert_eq!( assert_eq!(revm_spec(&MAINNET, 2675000 - 10), revm::TANGERINE);
revm_spec(&MAINNET, ForkDiscriminant::new(15537394 - 10, pre_merge_td, 1674477448)), assert_eq!(revm_spec(&MAINNET, 1150000 + 10), revm::HOMESTEAD);
revm::LONDON assert_eq!(revm_spec(&MAINNET, 1150000 - 10), revm::FRONTIER);
);
assert_eq!(
revm_spec(&MAINNET, ForkDiscriminant::new(12244000 + 10, pre_merge_td, 1674477448)),
revm::BERLIN
);
assert_eq!(
revm_spec(&MAINNET, ForkDiscriminant::new(12244000 - 10, pre_merge_td, 1674477448)),
revm::ISTANBUL
);
assert_eq!(
revm_spec(&MAINNET, ForkDiscriminant::new(7280000 + 10, pre_merge_td, 1674477448)),
revm::PETERSBURG
);
assert_eq!(
revm_spec(&MAINNET, ForkDiscriminant::new(7280000 - 10, pre_merge_td, 1674477448)),
revm::BYZANTIUM
);
assert_eq!(
revm_spec(&MAINNET, ForkDiscriminant::new(2675000 + 10, pre_merge_td, 1674477448)),
revm::SPURIOUS_DRAGON
);
assert_eq!(
revm_spec(&MAINNET, ForkDiscriminant::new(2675000 - 10, pre_merge_td, 1674477448)),
revm::TANGERINE
);
assert_eq!(
revm_spec(&MAINNET, ForkDiscriminant::new(1150000 + 10, pre_merge_td, 1674477448)),
revm::HOMESTEAD
);
assert_eq!(
revm_spec(&MAINNET, ForkDiscriminant::new(1150000 - 10, pre_merge_td, 1674477448)),
revm::FRONTIER
);
} }
} }

View File

@ -302,7 +302,7 @@ pub fn execute<DB: StateProvider>(
let mut evm = EVM::new(); let mut evm = EVM::new();
evm.database(db); evm.database(db);
let spec_id = revm_spec(chain_spec, header.into()); let spec_id = revm_spec(chain_spec, header.number);
evm.env.cfg.chain_id = U256::from(chain_spec.chain().id()); evm.env.cfg.chain_id = U256::from(chain_spec.chain().id());
evm.env.cfg.spec_id = spec_id; evm.env.cfg.spec_id = spec_id;
evm.env.cfg.perf_all_precompiles_have_balance = false; evm.env.cfg.perf_all_precompiles_have_balance = false;
@ -451,10 +451,10 @@ pub fn block_reward_changeset<DB: StateProvider>(
// amount. We raise the blocks beneficiary account by Rblock; for each ommer, we raise the // amount. We raise the blocks beneficiary account by Rblock; for each ommer, we raise the
// blocks beneficiary by an additional 1/32 of the block reward and the beneficiary of the // blocks beneficiary by an additional 1/32 of the block reward and the beneficiary of the
// ommer gets rewarded depending on the blocknumber. Formally we define the function Ω: // ommer gets rewarded depending on the blocknumber. Formally we define the function Ω:
match header.into() { match header.number {
d if chain_spec.fork_active(Hardfork::Paris, d) => None, n if Some(n) >= chain_spec.paris_status().block_number() => None,
d if chain_spec.fork_active(Hardfork::Petersburg, d) => Some(WEI_2ETH), n if Some(n) >= chain_spec.fork_block(Hardfork::Petersburg) => Some(WEI_2ETH),
d if chain_spec.fork_active(Hardfork::Byzantium, d) => Some(WEI_3ETH), n if Some(n) >= chain_spec.fork_block(Hardfork::Byzantium) => Some(WEI_3ETH),
_ => Some(WEI_5ETH), _ => Some(WEI_5ETH),
} }
.map(|reward| -> Result<_, _> { .map(|reward| -> Result<_, _> {
@ -538,8 +538,8 @@ mod tests {
transaction::DbTx, transaction::DbTx,
}; };
use reth_primitives::{ use reth_primitives::{
hex_literal::hex, keccak256, Account, Address, Bytes, ChainSpecBuilder, ForkKind, hex_literal::hex, keccak256, Account, Address, Bytes, ChainSpecBuilder, SealedBlock,
SealedBlock, StorageKey, H160, H256, MAINNET, U256, StorageKey, H160, H256, MAINNET, U256,
}; };
use reth_provider::{AccountProvider, BlockHashProvider, StateProvider}; use reth_provider::{AccountProvider, BlockHashProvider, StateProvider};
use reth_rlp::Decodable; use reth_rlp::Decodable;
@ -776,7 +776,7 @@ mod tests {
let chain_spec = ChainSpecBuilder::from(&*MAINNET) let chain_spec = ChainSpecBuilder::from(&*MAINNET)
.homestead_activated() .homestead_activated()
.with_fork(Hardfork::Dao, ForkKind::Block(1)) .with_fork(Hardfork::Dao, 1)
.build(); .build();
let mut db = SubState::new(State::new(db)); let mut db = SubState::new(State::new(db));

View File

@ -21,7 +21,7 @@ use reth_primitives::{Chain, ForkId, PeerId, H256, U256};
/// .total_difficulty(U256::from(100)) /// .total_difficulty(U256::from(100))
/// .blockhash(H256::from(MAINNET_GENESIS)) /// .blockhash(H256::from(MAINNET_GENESIS))
/// .genesis(H256::from(MAINNET_GENESIS)) /// .genesis(H256::from(MAINNET_GENESIS))
/// .forkid(Hardfork::London.fork_id(&MAINNET).unwrap()) /// .forkid(Hardfork::Latest.fork_id(&MAINNET).unwrap())
/// .build(); /// .build();
/// ///
/// assert_eq!( /// assert_eq!(
@ -32,7 +32,7 @@ use reth_primitives::{Chain, ForkId, PeerId, H256, U256};
/// total_difficulty: U256::from(100), /// total_difficulty: U256::from(100),
/// blockhash: H256::from(MAINNET_GENESIS), /// blockhash: H256::from(MAINNET_GENESIS),
/// genesis: H256::from(MAINNET_GENESIS), /// genesis: H256::from(MAINNET_GENESIS),
/// forkid: Hardfork::London.fork_id(&MAINNET).unwrap(), /// forkid: Hardfork::Latest.fork_id(&MAINNET).unwrap(),
/// } /// }
/// ); /// );
/// ``` /// ```

View File

@ -1,6 +1,6 @@
//! Types for broadcasting new data. //! Types for broadcasting new data.
use reth_codecs::derive_arbitrary; use reth_codecs::derive_arbitrary;
use reth_primitives::{BlockNumber, Header, TransactionSigned, H256, U128}; use reth_primitives::{Header, TransactionSigned, H256, U128};
use reth_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper}; use reth_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc; use std::sync::Arc;
@ -47,7 +47,7 @@ pub struct BlockHashNumber {
/// The block hash /// The block hash
pub hash: H256, pub hash: H256,
/// The block number /// The block number
pub number: BlockNumber, pub number: u64,
} }
impl From<Vec<BlockHashNumber>> for NewBlockHashes { impl From<Vec<BlockHashNumber>> for NewBlockHashes {

View File

@ -50,8 +50,10 @@ impl From<Genesis> for Status {
let mut chainspec = ChainSpec::from(genesis); let mut chainspec = ChainSpec::from(genesis);
let mut header = Header::from(chainspec.genesis().clone()); let mut header = Header::from(chainspec.genesis().clone());
let hardforks = chainspec.hardforks();
// set initial base fee depending on eip-1559 // set initial base fee depending on eip-1559
if Some(0u64) == chainspec.fork_block(Hardfork::London) { if Some(&0u64) == hardforks.get(&Hardfork::London) {
header.base_fee_per_gas = Some(EIP1559_INITIAL_BASE_FEE); header.base_fee_per_gas = Some(EIP1559_INITIAL_BASE_FEE);
} }
@ -62,7 +64,7 @@ impl From<Genesis> for Status {
chainspec.genesis_hash = sealed_header.hash(); chainspec.genesis_hash = sealed_header.hash();
// we need to calculate the fork id AFTER re-setting the genesis hash // we need to calculate the fork id AFTER re-setting the genesis hash
let forkid = chainspec.fork_id(0.into()); let forkid = chainspec.fork_id(0);
Status { Status {
version: EthVersion::Eth67 as u8, version: EthVersion::Eth67 as u8,
@ -95,7 +97,7 @@ impl Status {
.chain(spec.chain) .chain(spec.chain)
.genesis(spec.genesis_hash()) .genesis(spec.genesis_hash())
.blockhash(head.hash) .blockhash(head.hash)
.forkid(spec.fork_id(head.number.into())) .forkid(spec.fork_id(head.number))
} }
} }

View File

@ -297,7 +297,7 @@ impl NetworkConfigBuilder {
let status = Status::spec_builder(&chain_spec, &head).build(); let status = Status::spec_builder(&chain_spec, &head).build();
// set a fork filter based on the chain spec and head // set a fork filter based on the chain spec and head
let fork_filter = chain_spec.fork_filter(head.number.into()); let fork_filter = chain_spec.fork_filter(head.number);
// If default DNS config is used then we add the known dns network to bootstrap from // If default DNS config is used then we add the known dns network to bootstrap from
if let Some(dns_networks) = if let Some(dns_networks) =

View File

@ -7,7 +7,7 @@ use std::{fmt, str::FromStr};
// The chain spec module. // The chain spec module.
mod spec; mod spec;
pub use spec::{ChainSpec, ChainSpecBuilder, GOERLI, MAINNET, SEPOLIA}; pub use spec::{ChainSpec, ChainSpecBuilder, ParisStatus, GOERLI, MAINNET, SEPOLIA};
// The chain info module. // The chain info module.
mod info; mod info;

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
BlockNumber, Chain, ForkDiscriminant, ForkFilter, ForkHash, ForkId, ForkKind, Genesis, BlockNumber, Chain, ForkFilter, ForkHash, ForkId, Genesis, GenesisAccount, Hardfork, Header,
GenesisAccount, Hardfork, Header, H160, H256, U256, H160, H256, U256,
}; };
use ethers_core::utils::Genesis as EthersGenesis; use ethers_core::utils::Genesis as EthersGenesis;
use hex_literal::hex; use hex_literal::hex;
@ -15,24 +15,25 @@ pub static MAINNET: Lazy<ChainSpec> = Lazy::new(|| ChainSpec {
.expect("Can't deserialize Mainnet genesis json"), .expect("Can't deserialize Mainnet genesis json"),
genesis_hash: H256(hex!("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")), genesis_hash: H256(hex!("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")),
hardforks: BTreeMap::from([ hardforks: BTreeMap::from([
(Hardfork::Frontier, ForkKind::Block(0)), (Hardfork::Frontier, 0),
(Hardfork::Homestead, ForkKind::Block(1150000)), (Hardfork::Homestead, 1150000),
(Hardfork::Dao, ForkKind::Block(1920000)), (Hardfork::Dao, 1920000),
(Hardfork::Tangerine, ForkKind::Block(2463000)), (Hardfork::Tangerine, 2463000),
(Hardfork::SpuriousDragon, ForkKind::Block(2675000)), (Hardfork::SpuriousDragon, 2675000),
(Hardfork::Byzantium, ForkKind::Block(4370000)), (Hardfork::Byzantium, 4370000),
(Hardfork::Constantinople, ForkKind::Block(7280000)), (Hardfork::Constantinople, 7280000),
(Hardfork::Petersburg, ForkKind::Block(7280000)), (Hardfork::Petersburg, 7280000),
(Hardfork::Istanbul, ForkKind::Block(9069000)), (Hardfork::Istanbul, 9069000),
(Hardfork::Muirglacier, ForkKind::Block(9200000)), (Hardfork::Muirglacier, 9200000),
(Hardfork::Berlin, ForkKind::Block(12244000)), (Hardfork::Berlin, 12244000),
(Hardfork::London, ForkKind::Block(12965000)), (Hardfork::London, 12965000),
(Hardfork::ArrowGlacier, ForkKind::Block(13773000)), (Hardfork::ArrowGlacier, 13773000),
(Hardfork::GrayGlacier, ForkKind::Block(15050000)), (Hardfork::GrayGlacier, 15050000),
(Hardfork::Paris, ForkKind::TTD(Some(15537394))), (Hardfork::Latest, 15050000),
]), ]),
dao_fork_support: true, dao_fork_support: true,
paris_ttd: Some(U256::from(58_750_000_000_000_000_000_000_u128)), paris_block: Some(15537394),
paris_ttd: Some(U256::from(58750000000000000000000_u128)),
}); });
/// The Goerli spec /// The Goerli spec
@ -42,14 +43,14 @@ pub static GOERLI: Lazy<ChainSpec> = Lazy::new(|| ChainSpec {
.expect("Can't deserialize Goerli genesis json"), .expect("Can't deserialize Goerli genesis json"),
genesis_hash: H256(hex!("bf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a")), genesis_hash: H256(hex!("bf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a")),
hardforks: BTreeMap::from([ hardforks: BTreeMap::from([
(Hardfork::Frontier, ForkKind::Block(0)), (Hardfork::Frontier, 0),
(Hardfork::Istanbul, ForkKind::Block(1561651)), (Hardfork::Istanbul, 1561651),
(Hardfork::Berlin, ForkKind::Block(4460644)), (Hardfork::Berlin, 4460644),
(Hardfork::London, ForkKind::Block(5062605)), (Hardfork::London, 5062605),
(Hardfork::Paris, ForkKind::TTD(Some(7382818))),
]), ]),
dao_fork_support: true, dao_fork_support: true,
paris_ttd: Some(U256::from(10_790_000)), paris_block: Some(7382818),
paris_ttd: Some(U256::from(10790000)),
}); });
/// The Sepolia spec /// The Sepolia spec
@ -59,22 +60,23 @@ pub static SEPOLIA: Lazy<ChainSpec> = Lazy::new(|| ChainSpec {
.expect("Can't deserialize Sepolia genesis json"), .expect("Can't deserialize Sepolia genesis json"),
genesis_hash: H256(hex!("25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9")), genesis_hash: H256(hex!("25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9")),
hardforks: BTreeMap::from([ hardforks: BTreeMap::from([
(Hardfork::Frontier, ForkKind::Block(0)), (Hardfork::Frontier, 0),
(Hardfork::Homestead, ForkKind::Block(0)), (Hardfork::Homestead, 0),
(Hardfork::Dao, ForkKind::Block(0)), (Hardfork::Dao, 0),
(Hardfork::Tangerine, ForkKind::Block(0)), (Hardfork::Tangerine, 0),
(Hardfork::SpuriousDragon, ForkKind::Block(0)), (Hardfork::SpuriousDragon, 0),
(Hardfork::Byzantium, ForkKind::Block(0)), (Hardfork::Byzantium, 0),
(Hardfork::Constantinople, ForkKind::Block(0)), (Hardfork::Constantinople, 0),
(Hardfork::Petersburg, ForkKind::Block(0)), (Hardfork::Petersburg, 0),
(Hardfork::Istanbul, ForkKind::Block(0)), (Hardfork::Istanbul, 0),
(Hardfork::Muirglacier, ForkKind::Block(0)), (Hardfork::Muirglacier, 0),
(Hardfork::Berlin, ForkKind::Block(0)), (Hardfork::Berlin, 0),
(Hardfork::London, ForkKind::Block(0)), (Hardfork::London, 0),
(Hardfork::Paris, ForkKind::Block(1735371)), (Hardfork::MergeNetsplit, 1735371),
]), ]),
dao_fork_support: true, dao_fork_support: true,
paris_ttd: Some(U256::from(17_000_000_000_000_000_u64)), paris_block: Some(1450408),
paris_ttd: Some(U256::from(17000000000000000_u64)),
}); });
/// The Ethereum chain spec /// The Ethereum chain spec
@ -90,11 +92,14 @@ pub struct ChainSpec {
pub genesis_hash: H256, pub genesis_hash: H256,
/// The active hard forks and their block numbers /// The active hard forks and their block numbers
pub hardforks: BTreeMap<Hardfork, ForkKind>, pub hardforks: BTreeMap<Hardfork, BlockNumber>,
/// Whether or not the DAO fork is supported /// Whether or not the DAO fork is supported
pub dao_fork_support: bool, pub dao_fork_support: bool,
/// The block number of the merge
pub paris_block: Option<u64>,
/// The merge terminal total difficulty /// The merge terminal total difficulty
pub paris_ttd: Option<U256>, pub paris_ttd: Option<U256>,
} }
@ -115,42 +120,19 @@ impl ChainSpec {
self.genesis_hash self.genesis_hash
} }
/// Returns the supported hardforks and their [ForkKind] /// Returns the supported hardforks and their fork block numbers
pub fn hardforks(&self) -> &BTreeMap<Hardfork, ForkKind> { pub fn hardforks(&self) -> &BTreeMap<Hardfork, BlockNumber> {
&self.hardforks &self.hardforks
} }
/// Get the first block number of the given hardfork. This method returns `None` for /// Get the first block number of the hardfork.
/// timestamp-based forks and if the merge netsplit block is not known (when the given fork
/// is TTD-based)
pub fn fork_block(&self, fork: Hardfork) -> Option<BlockNumber> { pub fn fork_block(&self, fork: Hardfork) -> Option<BlockNumber> {
self.hardforks.get(&fork).and_then(|kind| match kind {
ForkKind::Block(block_number) => Some(*block_number),
ForkKind::TTD(block_number) => *block_number,
_ => None,
})
}
/// Get the first block number/timestamp of the hardfork.
pub fn fork_kind(&self, fork: Hardfork) -> Option<ForkKind> {
self.hardforks.get(&fork).copied() self.hardforks.get(&fork).copied()
} }
/// Returns `true` if the given fork is active on the given should update docs here to reflect /// Returns `true` if the given fork is active on the given block
/// that this returns true if the fork is active on the given block / ttd / timestamp contained pub fn fork_active(&self, fork: Hardfork, current_block: BlockNumber) -> bool {
/// in the [ForkDiscriminant] self.fork_block(fork).map(|target| target <= current_block).unwrap_or_default()
pub fn fork_active(&self, fork: Hardfork, discriminant: ForkDiscriminant) -> bool {
match self.hardforks.get(&fork) {
Some(kind) => match kind {
ForkKind::Block(block_number) => *block_number <= discriminant.block_number,
ForkKind::TTD(block_number) => {
self.paris_ttd <= Some(discriminant.total_difficulty) ||
*block_number <= Some(discriminant.block_number)
}
ForkKind::Time(timestamp) => *timestamp <= discriminant.timestamp,
},
None => false,
}
} }
/// Returns `true` if the DAO fork is supported /// Returns `true` if the DAO fork is supported
@ -158,56 +140,42 @@ impl ChainSpec {
self.dao_fork_support self.dao_fork_support
} }
/// The merge terminal total difficulty /// Get the Paris status
pub fn terminal_total_difficulty(&self) -> Option<U256> { pub fn paris_status(&self) -> ParisStatus {
self.paris_ttd match self.paris_ttd {
Some(terminal_total_difficulty) => {
ParisStatus::Supported { terminal_total_difficulty, block: self.paris_block }
}
None => ParisStatus::NotSupported,
}
} }
/// Get an iterator of all harforks with theirs respectives [ForkKind] /// Get an iterator of all harforks with theirs respectives block number
pub fn forks_iter(&self) -> impl Iterator<Item = (Hardfork, ForkKind)> + '_ { pub fn forks_iter(&self) -> impl Iterator<Item = (Hardfork, BlockNumber)> + '_ {
self.hardforks.iter().map(|(f, b)| (*f, *b)) self.hardforks.iter().map(|(f, b)| (*f, *b))
} }
/// Creates a [`ForkFilter`](crate::ForkFilter) for the given [ForkDiscriminant]. /// Creates a [`ForkFilter`](crate::ForkFilter) for the given [BlockNumber].
pub fn fork_filter(&self, discriminant: ForkDiscriminant) -> ForkFilter { pub fn fork_filter(&self, block: BlockNumber) -> ForkFilter {
let future_forks = self let future_forks =
.forks_iter() self.forks_iter().map(|(_, b)| b).filter(|b| *b > block).collect::<Vec<_>>();
.filter(|(f, _)| !self.fork_active(*f, discriminant))
.filter_map(|(_, k)| match k {
ForkKind::Block(block_number) => Some(block_number),
ForkKind::TTD(_) => None,
ForkKind::Time(timestamp) => Some(timestamp),
})
.collect::<Vec<_>>();
ForkFilter::new(discriminant.block_number, self.genesis_hash(), future_forks) ForkFilter::new(block, self.genesis_hash(), future_forks)
} }
/// Compute the forkid for the given [ForkDiscriminant] /// Compute the forkid for the given [BlockNumber]
pub fn fork_id(&self, discriminant: ForkDiscriminant) -> ForkId { pub fn fork_id(&self, block: BlockNumber) -> ForkId {
let mut curr_forkhash = ForkHash::from(self.genesis_hash()); let mut curr_forkhash = ForkHash::from(self.genesis_hash());
let mut forks = let mut curr_block_number = 0;
self.forks_iter().filter(|(_, k)| !k.is_active_at_genesis()).collect::<Vec<_>>();
forks.dedup_by(|a, b| a.1 == b.1); for (_, b) in self.forks_iter() {
if block >= b {
for (_, kind) in forks { if b != curr_block_number {
match kind { curr_forkhash += b;
ForkKind::Block(b) => { curr_block_number = b;
if discriminant.block_number >= b {
curr_forkhash += b;
} else {
return ForkId { hash: curr_forkhash, next: b }
}
} }
ForkKind::Time(t) => { } else {
if discriminant.timestamp >= t { return ForkId { hash: curr_forkhash, next: b }
curr_forkhash += t;
} else {
return ForkId { hash: curr_forkhash, next: t }
}
}
_ => {}
} }
} }
ForkId { hash: curr_forkhash, next: 0 } ForkId { hash: curr_forkhash, next: 0 }
@ -240,7 +208,7 @@ impl From<EthersGenesis> for ChainSpec {
let genesis_hash = Header::from(genesis_block.clone()).seal().hash(); let genesis_hash = Header::from(genesis_block.clone()).seal().hash();
let paris_ttd = genesis.config.terminal_total_difficulty.map(|ttd| ttd.into()); let paris_ttd = genesis.config.terminal_total_difficulty.map(|ttd| ttd.into());
let mut hardfork_opts = vec![ let hardfork_opts = vec![
(Hardfork::Homestead, genesis.config.homestead_block), (Hardfork::Homestead, genesis.config.homestead_block),
(Hardfork::Dao, genesis.config.dao_fork_block), (Hardfork::Dao, genesis.config.dao_fork_block),
(Hardfork::Tangerine, genesis.config.eip150_block), (Hardfork::Tangerine, genesis.config.eip150_block),
@ -254,17 +222,12 @@ impl From<EthersGenesis> for ChainSpec {
(Hardfork::London, genesis.config.london_block), (Hardfork::London, genesis.config.london_block),
(Hardfork::ArrowGlacier, genesis.config.arrow_glacier_block), (Hardfork::ArrowGlacier, genesis.config.arrow_glacier_block),
(Hardfork::GrayGlacier, genesis.config.gray_glacier_block), (Hardfork::GrayGlacier, genesis.config.gray_glacier_block),
(Hardfork::MergeNetsplit, genesis.config.merge_netsplit_block),
]; ];
// Paris block is not used to fork, and is not used in genesis.json
// except in Sepolia
if genesis.config.chain_id == Chain::sepolia().id() {
hardfork_opts.push((Hardfork::Paris, genesis.config.merge_netsplit_block))
}
let configured_hardforks = hardfork_opts let configured_hardforks = hardfork_opts
.iter() .iter()
.filter_map(|(hardfork, opt)| opt.map(|block| (*hardfork, ForkKind::Block(block)))) .filter_map(|(hardfork, opt)| opt.map(|block| (*hardfork, block)))
.collect::<BTreeMap<_, _>>(); .collect::<BTreeMap<_, _>>();
Self { Self {
@ -274,6 +237,8 @@ impl From<EthersGenesis> for ChainSpec {
hardforks: configured_hardforks, hardforks: configured_hardforks,
genesis_hash, genesis_hash,
paris_ttd, paris_ttd,
// paris block is not used to fork, and is not used in genesis.json
paris_block: None,
} }
} }
} }
@ -284,8 +249,9 @@ pub struct ChainSpecBuilder {
chain: Option<Chain>, chain: Option<Chain>,
genesis: Option<Genesis>, genesis: Option<Genesis>,
genesis_hash: Option<H256>, genesis_hash: Option<H256>,
hardforks: BTreeMap<Hardfork, ForkKind>, hardforks: BTreeMap<Hardfork, BlockNumber>,
dao_fork_support: bool, dao_fork_support: bool,
paris_block: Option<u64>,
paris_ttd: Option<U256>, paris_ttd: Option<U256>,
} }
@ -298,6 +264,7 @@ impl ChainSpecBuilder {
genesis_hash: Some(MAINNET.genesis_hash), genesis_hash: Some(MAINNET.genesis_hash),
hardforks: MAINNET.hardforks.clone(), hardforks: MAINNET.hardforks.clone(),
dao_fork_support: MAINNET.dao_fork_support, dao_fork_support: MAINNET.dao_fork_support,
paris_block: MAINNET.paris_block,
paris_ttd: MAINNET.paris_ttd, paris_ttd: MAINNET.paris_ttd,
} }
} }
@ -320,92 +287,71 @@ impl ChainSpecBuilder {
self self
} }
/// Remove all [Hardfork]s from the spec. Useful when the builder has been created from a /// Insert the given fork at the given block number
/// existing chain spec. pub fn with_fork(mut self, fork: Hardfork, block: BlockNumber) -> Self {
pub fn clear_forks(mut self) -> Self { self.hardforks.insert(fork, block);
self.hardforks.clear();
self
}
/// Insert the given fork at the given [ForkKind]
pub fn with_fork(mut self, fork: Hardfork, kind: ForkKind) -> Self {
self.hardforks.insert(fork, kind);
self self
} }
/// Enables Frontier /// Enables Frontier
pub fn frontier_activated(mut self) -> Self { pub fn frontier_activated(mut self) -> Self {
self.hardforks.insert(Hardfork::Frontier, ForkKind::Block(0)); self.hardforks.insert(Hardfork::Frontier, 0);
self self
} }
/// Enables Homestead /// Enables Homestead
pub fn homestead_activated(mut self) -> Self { pub fn homestead_activated(mut self) -> Self {
self = self.frontier_activated(); self = self.frontier_activated();
self.hardforks.insert(Hardfork::Homestead, ForkKind::Block(0)); self.hardforks.insert(Hardfork::Homestead, 0);
self self
} }
/// Enables Tangerine /// Enables Tangerine
pub fn tangerine_whistle_activated(mut self) -> Self { pub fn tangerine_whistle_activated(mut self) -> Self {
self = self.homestead_activated(); self = self.homestead_activated();
self.hardforks.insert(Hardfork::Tangerine, ForkKind::Block(0)); self.hardforks.insert(Hardfork::Tangerine, 0);
self self
} }
/// Enables SpuriousDragon /// Enables SpuriousDragon
pub fn spurious_dragon_activated(mut self) -> Self { pub fn spurious_dragon_activated(mut self) -> Self {
self = self.tangerine_whistle_activated(); self = self.tangerine_whistle_activated();
self.hardforks.insert(Hardfork::SpuriousDragon, ForkKind::Block(0)); self.hardforks.insert(Hardfork::SpuriousDragon, 0);
self self
} }
/// Enables Byzantium /// Enables Byzantium
pub fn byzantium_activated(mut self) -> Self { pub fn byzantium_activated(mut self) -> Self {
self = self.spurious_dragon_activated(); self = self.spurious_dragon_activated();
self.hardforks.insert(Hardfork::Byzantium, ForkKind::Block(0)); self.hardforks.insert(Hardfork::Byzantium, 0);
self self
} }
/// Enables Petersburg /// Enables Petersburg
pub fn petersburg_activated(mut self) -> Self { pub fn petersburg_activated(mut self) -> Self {
self = self.byzantium_activated(); self = self.byzantium_activated();
self.hardforks.insert(Hardfork::Petersburg, ForkKind::Block(0)); self.hardforks.insert(Hardfork::Petersburg, 0);
self self
} }
/// Enables Istanbul /// Enables Istanbul
pub fn istanbul_activated(mut self) -> Self { pub fn istanbul_activated(mut self) -> Self {
self = self.petersburg_activated(); self = self.petersburg_activated();
self.hardforks.insert(Hardfork::Istanbul, ForkKind::Block(0)); self.hardforks.insert(Hardfork::Istanbul, 0);
self self
} }
/// Enables Berlin /// Enables Berlin
pub fn berlin_activated(mut self) -> Self { pub fn berlin_activated(mut self) -> Self {
self = self.istanbul_activated(); self = self.istanbul_activated();
self.hardforks.insert(Hardfork::Berlin, ForkKind::Block(0)); self.hardforks.insert(Hardfork::Berlin, 0);
self self
} }
/// Enables London /// Enables London
pub fn london_activated(mut self) -> Self { pub fn london_activated(mut self) -> Self {
self = self.berlin_activated(); self = self.berlin_activated();
self.hardforks.insert(Hardfork::London, ForkKind::Block(0)); self.hardforks.insert(Hardfork::London, 0);
self
}
/// Enables Paris
pub fn paris_activated(mut self) -> Self {
self = self.berlin_activated();
self.hardforks.insert(Hardfork::Paris, ForkKind::TTD(Some(0)));
self
}
/// Enables Shangai
pub fn shangai_activated(mut self) -> Self {
self = self.paris_activated();
self.hardforks.insert(Hardfork::Shanghai, ForkKind::Time(0));
self self
} }
@ -415,6 +361,13 @@ impl ChainSpecBuilder {
self self
} }
/// Enables Paris
pub fn paris_activated(mut self) -> Self {
self = self.berlin_activated();
self.paris_block = Some(0);
self
}
/// Build a [ChainSpec] /// Build a [ChainSpec]
pub fn build(self) -> ChainSpec { pub fn build(self) -> ChainSpec {
ChainSpec { ChainSpec {
@ -423,6 +376,7 @@ impl ChainSpecBuilder {
genesis_hash: self.genesis_hash.expect("The genesis hash is required"), genesis_hash: self.genesis_hash.expect("The genesis hash is required"),
hardforks: self.hardforks, hardforks: self.hardforks,
dao_fork_support: self.dao_fork_support, dao_fork_support: self.dao_fork_support,
paris_block: self.paris_block,
paris_ttd: self.paris_ttd, paris_ttd: self.paris_ttd,
} }
} }
@ -436,17 +390,51 @@ impl From<&ChainSpec> for ChainSpecBuilder {
genesis_hash: Some(value.genesis_hash), genesis_hash: Some(value.genesis_hash),
hardforks: value.hardforks.clone(), hardforks: value.hardforks.clone(),
dao_fork_support: value.dao_fork_support, dao_fork_support: value.dao_fork_support,
paris_block: value.paris_block,
paris_ttd: value.paris_ttd, paris_ttd: value.paris_ttd,
} }
} }
} }
/// Merge Status
#[derive(Debug)]
pub enum ParisStatus {
/// Paris is not supported
NotSupported,
/// Paris settings has been set in the chain spec
Supported {
/// The merge terminal total difficulty
terminal_total_difficulty: U256,
/// The Paris block number
block: Option<BlockNumber>,
},
}
impl ParisStatus {
/// Returns the Paris block number if it is known ahead of time.
///
/// This is only the case for chains that have already activated the merge.
pub fn block_number(&self) -> Option<BlockNumber> {
match &self {
ParisStatus::NotSupported => None,
ParisStatus::Supported { block, .. } => *block,
}
}
/// Returns the merge terminal total difficulty
pub fn terminal_total_difficulty(&self) -> Option<U256> {
match &self {
ParisStatus::NotSupported => None,
ParisStatus::Supported { terminal_total_difficulty, .. } => {
Some(*terminal_total_difficulty)
}
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::{Chain, ChainSpec, ForkHash, Genesis, Hardfork, Header, GOERLI, MAINNET, SEPOLIA};
Chain, ChainSpec, ForkDiscriminant, ForkHash, ForkKind, Genesis, Hardfork, Header, GOERLI,
MAINNET, SEPOLIA,
};
#[test] #[test]
fn test_empty_forkid() { fn test_empty_forkid() {
@ -458,23 +446,22 @@ mod tests {
.chain(Chain::mainnet()) .chain(Chain::mainnet())
.genesis(empty_genesis) .genesis(empty_genesis)
.genesis_hash(empty_sealed.hash()) .genesis_hash(empty_sealed.hash())
.clear_forks() .with_fork(Hardfork::Frontier, 0)
.with_fork(Hardfork::Frontier, ForkKind::Block(0)) .with_fork(Hardfork::Homestead, 0)
.with_fork(Hardfork::Homestead, ForkKind::Block(0)) .with_fork(Hardfork::Tangerine, 0)
.with_fork(Hardfork::Tangerine, ForkKind::Block(0)) .with_fork(Hardfork::SpuriousDragon, 0)
.with_fork(Hardfork::SpuriousDragon, ForkKind::Block(0)) .with_fork(Hardfork::Byzantium, 0)
.with_fork(Hardfork::Byzantium, ForkKind::Block(0)) .with_fork(Hardfork::Constantinople, 0)
.with_fork(Hardfork::Constantinople, ForkKind::Block(0)) .with_fork(Hardfork::Istanbul, 0)
.with_fork(Hardfork::Istanbul, ForkKind::Block(0)) .with_fork(Hardfork::Muirglacier, 0)
.with_fork(Hardfork::Muirglacier, ForkKind::Block(0)) .with_fork(Hardfork::Berlin, 0)
.with_fork(Hardfork::Berlin, ForkKind::Block(0)) .with_fork(Hardfork::London, 0)
.with_fork(Hardfork::London, ForkKind::Block(0)) .with_fork(Hardfork::ArrowGlacier, 0)
.with_fork(Hardfork::ArrowGlacier, ForkKind::Block(0)) .with_fork(Hardfork::GrayGlacier, 0)
.with_fork(Hardfork::GrayGlacier, ForkKind::Block(0))
.build(); .build();
// test at block one - all forks should be active // test at block one - all forks should be active
let res_forkid = spec.fork_id(1_u64.into()); let res_forkid = spec.fork_id(1);
let expected_forkhash = ForkHash::from(spec.genesis_hash()); let expected_forkhash = ForkHash::from(spec.genesis_hash());
// if blocks get activated at genesis then they should not be accumulated into the forkhash // if blocks get activated at genesis then they should not be accumulated into the forkhash
@ -491,96 +478,96 @@ mod tests {
.chain(Chain::mainnet()) .chain(Chain::mainnet())
.genesis(empty_genesis.clone()) .genesis(empty_genesis.clone())
.genesis_hash(empty_sealed.hash()) .genesis_hash(empty_sealed.hash())
.with_fork(Hardfork::Frontier, ForkKind::Block(0)) .with_fork(Hardfork::Frontier, 0)
.with_fork(Hardfork::Homestead, ForkKind::Block(1)) .with_fork(Hardfork::Homestead, 1)
.build(); .build();
let duplicate_spec = ChainSpec::builder() let duplicate_spec = ChainSpec::builder()
.chain(Chain::mainnet()) .chain(Chain::mainnet())
.genesis(empty_genesis) .genesis(empty_genesis)
.genesis_hash(empty_sealed.hash()) .genesis_hash(empty_sealed.hash())
.with_fork(Hardfork::Frontier, ForkKind::Block(0)) .with_fork(Hardfork::Frontier, 0)
.with_fork(Hardfork::Homestead, ForkKind::Block(1)) .with_fork(Hardfork::Homestead, 1)
.with_fork(Hardfork::Tangerine, ForkKind::Block(1)) .with_fork(Hardfork::Tangerine, 1)
.build(); .build();
assert_eq!(unique_spec.fork_id(2.into()), duplicate_spec.fork_id(2.into())); assert_eq!(unique_spec.fork_id(2), duplicate_spec.fork_id(2));
} }
// these tests check that the forkid computation is accurate // these tests check that the forkid computation is accurate
#[test] #[test]
fn test_mainnet_forkids() { fn test_mainnet_forkids() {
let frontier_forkid = MAINNET.fork_id(0.into()); let frontier_forkid = MAINNET.fork_id(0);
assert_eq!([0xfc, 0x64, 0xec, 0x04], frontier_forkid.hash.0); assert_eq!([0xfc, 0x64, 0xec, 0x04], frontier_forkid.hash.0);
assert_eq!(1150000, frontier_forkid.next); assert_eq!(1150000, frontier_forkid.next);
let homestead_forkid = MAINNET.fork_id(1150000.into()); let homestead_forkid = MAINNET.fork_id(1150000);
assert_eq!([0x97, 0xc2, 0xc3, 0x4c], homestead_forkid.hash.0); assert_eq!([0x97, 0xc2, 0xc3, 0x4c], homestead_forkid.hash.0);
assert_eq!(1920000, homestead_forkid.next); assert_eq!(1920000, homestead_forkid.next);
let dao_forkid = MAINNET.fork_id(1920000.into()); let dao_forkid = MAINNET.fork_id(1920000);
assert_eq!([0x91, 0xd1, 0xf9, 0x48], dao_forkid.hash.0); assert_eq!([0x91, 0xd1, 0xf9, 0x48], dao_forkid.hash.0);
assert_eq!(2463000, dao_forkid.next); assert_eq!(2463000, dao_forkid.next);
let tangerine_forkid = MAINNET.fork_id(2463000.into()); let tangerine_forkid = MAINNET.fork_id(2463000);
assert_eq!([0x7a, 0x64, 0xda, 0x13], tangerine_forkid.hash.0); assert_eq!([0x7a, 0x64, 0xda, 0x13], tangerine_forkid.hash.0);
assert_eq!(2675000, tangerine_forkid.next); assert_eq!(2675000, tangerine_forkid.next);
let spurious_forkid = MAINNET.fork_id(2675000.into()); let spurious_forkid = MAINNET.fork_id(2675000);
assert_eq!([0x3e, 0xdd, 0x5b, 0x10], spurious_forkid.hash.0); assert_eq!([0x3e, 0xdd, 0x5b, 0x10], spurious_forkid.hash.0);
assert_eq!(4370000, spurious_forkid.next); assert_eq!(4370000, spurious_forkid.next);
let byzantium_forkid = MAINNET.fork_id(4370000.into()); let byzantium_forkid = MAINNET.fork_id(4370000);
assert_eq!([0xa0, 0x0b, 0xc3, 0x24], byzantium_forkid.hash.0); assert_eq!([0xa0, 0x0b, 0xc3, 0x24], byzantium_forkid.hash.0);
assert_eq!(7280000, byzantium_forkid.next); assert_eq!(7280000, byzantium_forkid.next);
let constantinople_forkid = MAINNET.fork_id(7280000.into()); let constantinople_forkid = MAINNET.fork_id(7280000);
assert_eq!([0x66, 0x8d, 0xb0, 0xaf], constantinople_forkid.hash.0); assert_eq!([0x66, 0x8d, 0xb0, 0xaf], constantinople_forkid.hash.0);
assert_eq!(9069000, constantinople_forkid.next); assert_eq!(9069000, constantinople_forkid.next);
let istanbul_forkid = MAINNET.fork_id(9069000.into()); let istanbul_forkid = MAINNET.fork_id(9069000);
assert_eq!([0x87, 0x9d, 0x6e, 0x30], istanbul_forkid.hash.0); assert_eq!([0x87, 0x9d, 0x6e, 0x30], istanbul_forkid.hash.0);
assert_eq!(9200000, istanbul_forkid.next); assert_eq!(9200000, istanbul_forkid.next);
let muir_glacier_forkid = MAINNET.fork_id(9200000.into()); let muir_glacier_forkid = MAINNET.fork_id(9200000);
assert_eq!([0xe0, 0x29, 0xe9, 0x91], muir_glacier_forkid.hash.0); assert_eq!([0xe0, 0x29, 0xe9, 0x91], muir_glacier_forkid.hash.0);
assert_eq!(12244000, muir_glacier_forkid.next); assert_eq!(12244000, muir_glacier_forkid.next);
let berlin_forkid = MAINNET.fork_id(12244000.into()); let berlin_forkid = MAINNET.fork_id(12244000);
assert_eq!([0x0e, 0xb4, 0x40, 0xf6], berlin_forkid.hash.0); assert_eq!([0x0e, 0xb4, 0x40, 0xf6], berlin_forkid.hash.0);
assert_eq!(12965000, berlin_forkid.next); assert_eq!(12965000, berlin_forkid.next);
let london_forkid = MAINNET.fork_id(12965000.into()); let london_forkid = MAINNET.fork_id(12965000);
assert_eq!([0xb7, 0x15, 0x07, 0x7d], london_forkid.hash.0); assert_eq!([0xb7, 0x15, 0x07, 0x7d], london_forkid.hash.0);
assert_eq!(13773000, london_forkid.next); assert_eq!(13773000, london_forkid.next);
let arrow_glacier_forkid = MAINNET.fork_id(13773000.into()); let arrow_glacier_forkid = MAINNET.fork_id(13773000);
assert_eq!([0x20, 0xc3, 0x27, 0xfc], arrow_glacier_forkid.hash.0); assert_eq!([0x20, 0xc3, 0x27, 0xfc], arrow_glacier_forkid.hash.0);
assert_eq!(15050000, arrow_glacier_forkid.next); assert_eq!(15050000, arrow_glacier_forkid.next);
let gray_glacier_forkid = MAINNET.fork_id(15050000.into()); let gray_glacier_forkid = MAINNET.fork_id(15050000);
assert_eq!([0xf0, 0xaf, 0xd0, 0xe3], gray_glacier_forkid.hash.0); assert_eq!([0xf0, 0xaf, 0xd0, 0xe3], gray_glacier_forkid.hash.0);
assert_eq!(0, gray_glacier_forkid.next); // TODO: update post-gray glacier assert_eq!(0, gray_glacier_forkid.next); // TODO: update post-gray glacier
let latest_forkid = MAINNET.fork_id(15050000.into()); let latest_forkid = MAINNET.fork_id(15050000);
assert_eq!(0, latest_forkid.next); assert_eq!(0, latest_forkid.next);
} }
#[test] #[test]
fn test_goerli_forkids() { fn test_goerli_forkids() {
let frontier_forkid = GOERLI.fork_id(ForkDiscriminant::block(0)); let frontier_forkid = GOERLI.fork_id(0);
assert_eq!([0xa3, 0xf5, 0xab, 0x08], frontier_forkid.hash.0); assert_eq!([0xa3, 0xf5, 0xab, 0x08], frontier_forkid.hash.0);
assert_eq!(1561651, frontier_forkid.next); assert_eq!(1561651, frontier_forkid.next);
let istanbul_forkid = GOERLI.fork_id(ForkDiscriminant::block(1561651)); let istanbul_forkid = GOERLI.fork_id(1561651);
assert_eq!([0xc2, 0x5e, 0xfa, 0x5c], istanbul_forkid.hash.0); assert_eq!([0xc2, 0x5e, 0xfa, 0x5c], istanbul_forkid.hash.0);
assert_eq!(4460644, istanbul_forkid.next); assert_eq!(4460644, istanbul_forkid.next);
let berlin_forkid = GOERLI.fork_id(ForkDiscriminant::block(4460644)); let berlin_forkid = GOERLI.fork_id(4460644);
assert_eq!([0x75, 0x7a, 0x1c, 0x47], berlin_forkid.hash.0); assert_eq!([0x75, 0x7a, 0x1c, 0x47], berlin_forkid.hash.0);
assert_eq!(5062605, berlin_forkid.next); assert_eq!(5062605, berlin_forkid.next);
let london_forkid = GOERLI.fork_id(ForkDiscriminant::block(12965000)); let london_forkid = GOERLI.fork_id(12965000);
assert_eq!([0xb8, 0xc6, 0x29, 0x9d], london_forkid.hash.0); assert_eq!([0xb8, 0xc6, 0x29, 0x9d], london_forkid.hash.0);
assert_eq!(0, london_forkid.next); assert_eq!(0, london_forkid.next);
} }
@ -588,7 +575,7 @@ mod tests {
#[test] #[test]
fn test_sepolia_forkids() { fn test_sepolia_forkids() {
// Test vector is from <https://github.com/ethereum/go-ethereum/blob/59a48e0289b1a7470a8285e665cab12b29117a70/core/forkid/forkid_test.go#L146-L151> // Test vector is from <https://github.com/ethereum/go-ethereum/blob/59a48e0289b1a7470a8285e665cab12b29117a70/core/forkid/forkid_test.go#L146-L151>
let mergenetsplit_forkid = SEPOLIA.fork_id(ForkDiscriminant::block(1735371)); let mergenetsplit_forkid = SEPOLIA.fork_id(1735371);
assert_eq!([0xb9, 0x6c, 0xbd, 0x13], mergenetsplit_forkid.hash.0); assert_eq!([0xb9, 0x6c, 0xbd, 0x13], mergenetsplit_forkid.hash.0);
assert_eq!(0, mergenetsplit_forkid.next); assert_eq!(0, mergenetsplit_forkid.next);
} }

View File

@ -84,8 +84,8 @@ impl Add<BlockNumber> for ForkHash {
pub struct ForkId { pub struct ForkId {
/// CRC32 checksum of the all fork blocks from genesis. /// CRC32 checksum of the all fork blocks from genesis.
pub hash: ForkHash, pub hash: ForkHash,
/// Next upcoming fork block number or timestamp, 0 if not yet known. /// Next upcoming fork block number, 0 if not yet known.
pub next: u64, pub next: BlockNumber,
} }
/// Reason for rejecting provided `ForkId`. /// Reason for rejecting provided `ForkId`.
@ -128,7 +128,7 @@ impl ForkFilter {
pub fn new<F, B>(head: BlockNumber, genesis: H256, forks: F) -> Self pub fn new<F, B>(head: BlockNumber, genesis: H256, forks: F) -> Self
where where
F: IntoIterator<Item = B>, F: IntoIterator<Item = B>,
B: Into<u64>, B: Into<BlockNumber>,
{ {
let genesis_fork_hash = ForkHash::from(genesis); let genesis_fork_hash = ForkHash::from(genesis);
let mut forks = forks.into_iter().map(Into::into).collect::<BTreeSet<_>>(); let mut forks = forks.into_iter().map(Into::into).collect::<BTreeSet<_>>();

View File

@ -1,92 +0,0 @@
use serde::{Deserialize, Serialize};
use crate::{BlockNumber, ChainSpec, Header, U256};
/// Hardforks can be based on block numbers (pre-merge), TTD (Paris)
/// or timestamp (post-merge)
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub enum ForkKind {
/// A fork's block number
Block(BlockNumber),
/// The terminal total difficulty (used by Paris fork)
TTD(Option<BlockNumber>),
/// The unix timestamp of a fork
Time(u64),
}
impl ForkKind {
/// Returns `true` is the fork is active at genesis
pub fn is_active_at_genesis(&self) -> bool {
match self {
ForkKind::Block(block_number) => *block_number == 0_u64,
ForkKind::TTD(_) => false,
ForkKind::Time(_) => false,
}
}
}
/// This struct is used when it's needed to determine is a hardfork is active
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
pub struct ForkDiscriminant {
/// The block number
pub block_number: BlockNumber,
/// The total difficulty
pub total_difficulty: U256,
/// The timestamp
pub timestamp: u64,
}
impl ForkDiscriminant {
/// Returns a new [ForkDiscriminant]
pub fn new(block_number: BlockNumber, total_difficulty: U256, timestamp: u64) -> Self {
Self { block_number, total_difficulty, timestamp }
}
/// Return a [ForkDiscriminant] with the given block
pub fn block(block_number: BlockNumber) -> Self {
Self { block_number, ..Default::default() }
}
/// Return a [ForkDiscriminant] with the given ttd
pub fn ttd(total_difficulty: U256, block_number: Option<BlockNumber>) -> Self {
Self {
block_number: block_number.unwrap_or_default(),
total_difficulty,
..Default::default()
}
}
/// Return a [ForkDiscriminant] with the given timestamp
pub fn timestamp(timestamp: u64) -> Self {
Self { timestamp, ..Default::default() }
}
/// Return a [ForkDiscriminant] from the given [ForkKind]
pub fn from_kind(kind: ForkKind, chain_spec: &ChainSpec) -> Self {
match kind {
ForkKind::Block(block_number) => ForkDiscriminant::block(block_number),
ForkKind::TTD(block_number) => {
ForkDiscriminant::ttd(chain_spec.paris_ttd.unwrap_or_default(), block_number)
}
ForkKind::Time(timestamp) => ForkDiscriminant::timestamp(timestamp),
}
}
}
impl From<BlockNumber> for ForkDiscriminant {
fn from(value: BlockNumber) -> Self {
Self { block_number: value, ..Default::default() }
}
}
impl From<&Header> for ForkDiscriminant {
fn from(value: &Header) -> Self {
Self {
block_number: value.number,
total_difficulty: value.difficulty,
timestamp: value.timestamp,
}
}
}

View File

@ -2,10 +2,12 @@ use serde::{Deserialize, Serialize};
use std::{fmt::Display, str::FromStr}; use std::{fmt::Display, str::FromStr};
use crate::{forkkind::ForkDiscriminant, ChainSpec, ForkFilter, ForkId}; use crate::{BlockNumber, ChainSpec, ForkFilter, ForkHash, ForkId};
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[derive(
Debug, Default, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize,
)]
pub enum Hardfork { pub enum Hardfork {
Frontier, Frontier,
Homestead, Homestead,
@ -21,8 +23,10 @@ pub enum Hardfork {
London, London,
ArrowGlacier, ArrowGlacier,
GrayGlacier, GrayGlacier,
Paris, MergeNetsplit,
Shanghai, Shanghai,
#[default]
Latest,
} }
impl Hardfork { impl Hardfork {
@ -33,10 +37,24 @@ impl Hardfork {
/// ///
/// If the hard fork is not present in the [`ChainSpec`] then `None` is returned. /// If the hard fork is not present in the [`ChainSpec`] then `None` is returned.
pub fn fork_id(&self, chain_spec: &ChainSpec) -> Option<ForkId> { pub fn fork_id(&self, chain_spec: &ChainSpec) -> Option<ForkId> {
chain_spec if let Some(fork_block) = chain_spec.fork_block(*self) {
.fork_kind(*self) let mut curr_forkhash = ForkHash::from(chain_spec.genesis_hash());
.map(|k| ForkDiscriminant::from_kind(k, chain_spec)) let mut curr_block_number = 0;
.map(|d| chain_spec.fork_id(d))
for (_, b) in chain_spec.forks_iter() {
if fork_block >= b {
if b != curr_block_number {
curr_forkhash += b;
curr_block_number = b;
}
} else {
return Some(ForkId { hash: curr_forkhash, next: b })
}
}
Some(ForkId { hash: curr_forkhash, next: 0 })
} else {
None
}
} }
/// Creates a [`ForkFilter`](crate::ForkFilter) for the given hardfork. /// Creates a [`ForkFilter`](crate::ForkFilter) for the given hardfork.
@ -46,10 +64,15 @@ impl Hardfork {
/// ///
/// This returns `None` if the hardfork is not present in the given [`ChainSpec`]. /// This returns `None` if the hardfork is not present in the given [`ChainSpec`].
pub fn fork_filter(&self, chain_spec: &ChainSpec) -> Option<ForkFilter> { pub fn fork_filter(&self, chain_spec: &ChainSpec) -> Option<ForkFilter> {
chain_spec if let Some(fork_block) = chain_spec.fork_block(*self) {
.fork_kind(*self) let future_forks: Vec<BlockNumber> =
.map(|k| ForkDiscriminant::from_kind(k, chain_spec)) chain_spec.forks_iter().filter(|(_, b)| b > &fork_block).map(|(_, b)| b).collect();
.map(|d| chain_spec.fork_filter(d))
// pass in the chain spec's genesis hash to initialize the fork filter
Some(ForkFilter::new(fork_block, chain_spec.genesis_hash(), future_forks))
} else {
None
}
} }
} }
@ -72,7 +95,8 @@ impl FromStr for Hardfork {
"berlin" | "11" => Hardfork::Berlin, "berlin" | "11" => Hardfork::Berlin,
"london" | "12" => Hardfork::London, "london" | "12" => Hardfork::London,
"arrowglacier" | "13" => Hardfork::ArrowGlacier, "arrowglacier" | "13" => Hardfork::ArrowGlacier,
"grayglacier" | "14" => Hardfork::GrayGlacier, "grayglacier" => Hardfork::GrayGlacier,
"latest" | "14" => Hardfork::Latest,
_ => return Err(format!("Unknown hardfork {s}")), _ => return Err(format!("Unknown hardfork {s}")),
}; };
Ok(hardfork) Ok(hardfork)

View File

@ -17,7 +17,6 @@ mod chain;
pub mod constants; pub mod constants;
mod error; mod error;
mod forkid; mod forkid;
mod forkkind;
mod genesis; mod genesis;
mod hardfork; mod hardfork;
mod header; mod header;
@ -38,12 +37,13 @@ pub use account::Account;
pub use bits::H512; pub use bits::H512;
pub use block::{Block, BlockHashOrNumber, SealedBlock}; pub use block::{Block, BlockHashOrNumber, SealedBlock};
pub use bloom::Bloom; pub use bloom::Bloom;
pub use chain::{Chain, ChainInfo, ChainSpec, ChainSpecBuilder, GOERLI, MAINNET, SEPOLIA}; pub use chain::{
Chain, ChainInfo, ChainSpec, ChainSpecBuilder, ParisStatus, GOERLI, MAINNET, SEPOLIA,
};
pub use constants::{ pub use constants::{
EMPTY_OMMER_ROOT, GOERLI_GENESIS, KECCAK_EMPTY, MAINNET_GENESIS, SEPOLIA_GENESIS, EMPTY_OMMER_ROOT, GOERLI_GENESIS, KECCAK_EMPTY, MAINNET_GENESIS, SEPOLIA_GENESIS,
}; };
pub use forkid::{ForkFilter, ForkHash, ForkId, ForkTransition, ValidationError}; pub use forkid::{ForkFilter, ForkHash, ForkId, ForkTransition, ValidationError};
pub use forkkind::{ForkDiscriminant, ForkKind};
pub use genesis::{Genesis, GenesisAccount}; pub use genesis::{Genesis, GenesisAccount};
pub use hardfork::Hardfork; pub use hardfork::Hardfork;
pub use header::{Header, HeadersDirection, SealedHeader}; pub use header::{Header, HeadersDirection, SealedHeader};

View File

@ -53,7 +53,7 @@ pub fn init_genesis<DB: Database>(db: Arc<DB>, chain: ChainSpec) -> Result<H256,
let mut header: Header = genesis.clone().into(); let mut header: Header = genesis.clone().into();
// set base fee if EIP-1559 is enabled // set base fee if EIP-1559 is enabled
if chain.fork_active(Hardfork::London, 0.into()) { if chain.fork_active(Hardfork::London, 0) {
header.base_fee_per_gas = Some(EIP1559_INITIAL_BASE_FEE); header.base_fee_per_gas = Some(EIP1559_INITIAL_BASE_FEE);
} }