mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 19:09:54 +00:00
refactor: unify all chains confs (#747)
Co-authored-by: Bjerg <onbjerg@users.noreply.github.com>
This commit is contained in:
@ -1,100 +0,0 @@
|
||||
//! Reth block execution/validation configuration and constants
|
||||
use reth_executor::{Config as ExecutorConfig, SpecUpgrades};
|
||||
use reth_primitives::{BlockNumber, U256};
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Initial base fee as defined in: https://eips.ethereum.org/EIPS/eip-1559
|
||||
pub const EIP1559_INITIAL_BASE_FEE: u64 = 1_000_000_000;
|
||||
/// Base fee max change denominator as defined in: https://eips.ethereum.org/EIPS/eip-1559
|
||||
pub const EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR: u64 = 8;
|
||||
/// Elasticity multiplier as defined in: https://eips.ethereum.org/EIPS/eip-1559
|
||||
pub const EIP1559_ELASTICITY_MULTIPLIER: u64 = 2;
|
||||
|
||||
/// Common configuration for consensus algorithms.
|
||||
#[derive(Debug, Clone)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
|
||||
pub struct Config {
|
||||
/// Blockchain identifier introduced in EIP-155: Simple replay attack protection.
|
||||
pub chain_id: u64,
|
||||
|
||||
/// Homestead switch block.
|
||||
pub homestead_block: BlockNumber,
|
||||
|
||||
/// TheDAO hard-fork switch block.
|
||||
pub dao_fork_block: BlockNumber,
|
||||
/// Whether the node supports or opposes the DAO hard-fork
|
||||
pub dao_fork_support: bool,
|
||||
|
||||
/// EIP150 implements gas price changes.
|
||||
pub eip_150_block: BlockNumber,
|
||||
|
||||
/// EIP155 hard-fork block (Spurious Dragon)
|
||||
pub eip_155_block: BlockNumber,
|
||||
/// EIP158 hard-fork block.
|
||||
pub eip_158_block: BlockNumber,
|
||||
/// Byzantium switch block.
|
||||
pub byzantium_block: BlockNumber,
|
||||
/// Constantinople switch block.
|
||||
pub constantinople_block: BlockNumber,
|
||||
/// Petersburg switch block.
|
||||
pub petersburg_block: BlockNumber,
|
||||
/// Istanbul switch block.
|
||||
pub istanbul_block: BlockNumber,
|
||||
/// EIP-2728 switch block.
|
||||
pub berlin_block: BlockNumber,
|
||||
/// EIP-1559 switch block.
|
||||
pub london_block: BlockNumber,
|
||||
/// The Merge/Paris hard-fork block number.
|
||||
pub paris_block: BlockNumber,
|
||||
/// Terminal total difficulty after the paris hard-fork to reach before The Merge is considered
|
||||
/// activated.
|
||||
#[cfg_attr(feature = "serde", serde(rename = "terminalTotalDifficulty"))]
|
||||
pub merge_terminal_total_difficulty: u128,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
chain_id: 1,
|
||||
homestead_block: 1150000,
|
||||
dao_fork_block: 1920000,
|
||||
dao_fork_support: true,
|
||||
eip_150_block: 2463000,
|
||||
eip_155_block: 2675000,
|
||||
eip_158_block: 2675000,
|
||||
byzantium_block: 4370000,
|
||||
constantinople_block: 7280000,
|
||||
petersburg_block: 7280000,
|
||||
istanbul_block: 9069000,
|
||||
berlin_block: 12244000,
|
||||
london_block: 12965000,
|
||||
paris_block: 15537394,
|
||||
merge_terminal_total_difficulty: 58750000000000000000000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Config> for ExecutorConfig {
|
||||
fn from(value: &Config) -> Self {
|
||||
Self {
|
||||
chain_id: U256::from(value.chain_id),
|
||||
spec_upgrades: SpecUpgrades {
|
||||
frontier: 0,
|
||||
homestead: value.homestead_block,
|
||||
dao_fork: value.dao_fork_block,
|
||||
tangerine_whistle: value.eip_150_block,
|
||||
spurious_dragon: value.eip_158_block,
|
||||
byzantium: value.byzantium_block,
|
||||
petersburg: value.petersburg_block,
|
||||
istanbul: value.istanbul_block,
|
||||
berlin: value.berlin_block,
|
||||
london: value.london_block,
|
||||
paris: value.paris_block,
|
||||
shanghai: u64::MAX, // TODO: change once known
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
//! Consensus for ethereum network
|
||||
use crate::{verification, Config};
|
||||
use crate::verification;
|
||||
use reth_interfaces::consensus::{Consensus, Error, ForkchoiceState};
|
||||
use reth_primitives::{BlockNumber, SealedBlock, SealedHeader, H256};
|
||||
use reth_primitives::{BlockNumber, ChainSpec, SealedBlock, SealedHeader, H256};
|
||||
use tokio::sync::{watch, watch::error::SendError};
|
||||
|
||||
/// Ethereum beacon consensus
|
||||
@ -12,19 +12,19 @@ pub struct BeaconConsensus {
|
||||
/// Watcher over the forkchoice state
|
||||
channel: (watch::Sender<ForkchoiceState>, watch::Receiver<ForkchoiceState>),
|
||||
/// Configuration
|
||||
config: Config,
|
||||
chain_spec: ChainSpec,
|
||||
}
|
||||
|
||||
impl BeaconConsensus {
|
||||
/// Create a new instance of [BeaconConsensus]
|
||||
pub fn new(config: Config) -> Self {
|
||||
pub fn new(chain_spec: ChainSpec) -> Self {
|
||||
Self {
|
||||
channel: watch::channel(ForkchoiceState {
|
||||
head_block_hash: H256::zero(),
|
||||
finalized_block_hash: H256::zero(),
|
||||
safe_block_hash: H256::zero(),
|
||||
}),
|
||||
config,
|
||||
chain_spec,
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,10 +43,10 @@ impl Consensus for BeaconConsensus {
|
||||
}
|
||||
|
||||
fn validate_header(&self, header: &SealedHeader, parent: &SealedHeader) -> Result<(), Error> {
|
||||
verification::validate_header_standalone(header, &self.config)?;
|
||||
verification::validate_header_regarding_parent(parent, header, &self.config)?;
|
||||
verification::validate_header_standalone(header, &self.chain_spec)?;
|
||||
verification::validate_header_regarding_parent(parent, header, &self.chain_spec)?;
|
||||
|
||||
if header.number < self.config.paris_block {
|
||||
if Some(header.number) < self.chain_spec.paris_status().block_number() {
|
||||
// TODO Consensus checks for old blocks:
|
||||
// * difficulty, mix_hash & nonce aka PoW stuff
|
||||
// low priority as syncing is done in reverse order
|
||||
@ -59,6 +59,6 @@ impl Consensus for BeaconConsensus {
|
||||
}
|
||||
|
||||
fn has_block_reward(&self, block_num: BlockNumber) -> bool {
|
||||
block_num < self.config.paris_block
|
||||
Some(block_num) < self.chain_spec.paris_status().block_number()
|
||||
}
|
||||
}
|
||||
|
||||
8
crates/consensus/src/constants.rs
Normal file
8
crates/consensus/src/constants.rs
Normal file
@ -0,0 +1,8 @@
|
||||
//! Reth block execution/validation configuration and constants
|
||||
|
||||
/// Initial base fee as defined in: https://eips.ethereum.org/EIPS/eip-1559
|
||||
pub const EIP1559_INITIAL_BASE_FEE: u64 = 1_000_000_000;
|
||||
/// Base fee max change denominator as defined in: https://eips.ethereum.org/EIPS/eip-1559
|
||||
pub const EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR: u64 = 8;
|
||||
/// Elasticity multiplier as defined in: https://eips.ethereum.org/EIPS/eip-1559
|
||||
pub const EIP1559_ELASTICITY_MULTIPLIER: u64 = 2;
|
||||
@ -64,6 +64,9 @@ pub enum EngineApiError {
|
||||
/// Forkchoice zero hash head received.
|
||||
#[error("Received zero hash as forkchoice head")]
|
||||
ForkchoiceEmptyHead,
|
||||
/// Chain spec merge terminal total difficulty is not set
|
||||
#[error("The merge terminal total difficulty is not known")]
|
||||
UnknownMergeTerminalTotalDifficulty,
|
||||
/// Encountered decoding error.
|
||||
#[error(transparent)]
|
||||
Decode(#[from] reth_rlp::DecodeError),
|
||||
|
||||
@ -7,7 +7,7 @@ use reth_interfaces::consensus::ForkchoiceState;
|
||||
use reth_primitives::{
|
||||
proofs::{self, EMPTY_LIST_HASH},
|
||||
rpc::{BlockId, H256 as EthersH256},
|
||||
Header, SealedBlock, TransactionSigned, H64, U256,
|
||||
ChainSpec, Header, SealedBlock, TransactionSigned, H64, U256,
|
||||
};
|
||||
use reth_provider::{BlockProvider, HeaderProvider, StateProvider};
|
||||
use reth_rlp::Decodable;
|
||||
@ -25,8 +25,6 @@ use std::{
|
||||
use tokio::sync::oneshot;
|
||||
use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||
|
||||
use crate::Config;
|
||||
|
||||
mod error;
|
||||
pub use error::{EngineApiError, EngineApiResult};
|
||||
|
||||
@ -80,7 +78,7 @@ pub enum EngineMessage {
|
||||
pub struct EthConsensusEngine<Client> {
|
||||
client: Arc<Client>,
|
||||
/// Consensus configuration
|
||||
config: Config,
|
||||
chain_spec: ChainSpec,
|
||||
rx: UnboundedReceiverStream<EngineMessage>,
|
||||
// TODO: Placeholder for storing future blocks. Make cache bounded.
|
||||
// Use [lru](https://crates.io/crates/lru) crate
|
||||
@ -190,7 +188,7 @@ impl<Client: HeaderProvider + BlockProvider + StateProvider> ConsensusEngine
|
||||
};
|
||||
|
||||
if let Some(parent_td) = self.client.header_td(&block.parent_hash)? {
|
||||
if parent_td <= U256::from(self.config.merge_terminal_total_difficulty) {
|
||||
if Some(parent_td) <= self.chain_spec.paris_status().terminal_total_difficulty() {
|
||||
return Ok(PayloadStatus::from_status(PayloadStatusEnum::Invalid {
|
||||
validation_error: EngineApiError::PayloadPreMerge.to_string(),
|
||||
}))
|
||||
@ -216,12 +214,11 @@ impl<Client: HeaderProvider + BlockProvider + StateProvider> ConsensusEngine
|
||||
})
|
||||
.collect::<Result<Vec<_>, EngineApiError>>()?;
|
||||
let mut state_provider = SubState::new(State::new(&*self.client));
|
||||
let config = (&self.config).into();
|
||||
match executor::execute_and_verify_receipt(
|
||||
&header,
|
||||
&transactions,
|
||||
&[],
|
||||
&config,
|
||||
&self.chain_spec,
|
||||
&mut state_provider,
|
||||
) {
|
||||
Ok(_) => Ok(PayloadStatus::new(PayloadStatusEnum::Valid, header.hash())),
|
||||
@ -272,8 +269,13 @@ impl<Client: HeaderProvider + BlockProvider + StateProvider> ConsensusEngine
|
||||
terminal_block_number,
|
||||
} = config;
|
||||
|
||||
let merge_terminal_td = self
|
||||
.chain_spec
|
||||
.paris_status()
|
||||
.terminal_total_difficulty()
|
||||
.ok_or(EngineApiError::UnknownMergeTerminalTotalDifficulty)?;
|
||||
|
||||
// Compare total difficulty values
|
||||
let merge_terminal_td = U256::from(self.config.merge_terminal_total_difficulty);
|
||||
if merge_terminal_td != terminal_total_difficulty {
|
||||
return Err(EngineApiError::TerminalTD {
|
||||
execution: merge_terminal_td,
|
||||
@ -340,7 +342,7 @@ mod tests {
|
||||
use super::*;
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use reth_interfaces::test_utils::generators::random_header;
|
||||
use reth_primitives::Block;
|
||||
use reth_primitives::{Block, MAINNET};
|
||||
use reth_rlp::DecodeError;
|
||||
|
||||
fn transform_block<F: FnOnce(Block) -> Block>(src: SealedBlock, f: F) -> SealedBlock {
|
||||
@ -363,7 +365,7 @@ mod tests {
|
||||
let (_tx, rx) = unbounded_channel();
|
||||
let engine = EthConsensusEngine {
|
||||
client: Arc::new(MockEthProvider::default()),
|
||||
config: Config::default(),
|
||||
chain_spec: MAINNET.clone(),
|
||||
local_store: Default::default(),
|
||||
rx: UnboundedReceiverStream::new(rx),
|
||||
};
|
||||
@ -452,7 +454,7 @@ mod tests {
|
||||
let client = Arc::new(MockEthProvider::default());
|
||||
let engine = EthConsensusEngine {
|
||||
client: client.clone(),
|
||||
config: Config::default(),
|
||||
chain_spec: MAINNET.clone(),
|
||||
local_store: Default::default(),
|
||||
rx: UnboundedReceiverStream::new(rx),
|
||||
};
|
||||
@ -480,7 +482,7 @@ mod tests {
|
||||
let (tx, rx) = unbounded_channel();
|
||||
let engine = EthConsensusEngine {
|
||||
client: Arc::new(MockEthProvider::default()),
|
||||
config: Config::default(),
|
||||
chain_spec: MAINNET.clone(),
|
||||
local_store: Default::default(),
|
||||
rx: UnboundedReceiverStream::new(rx),
|
||||
};
|
||||
@ -501,11 +503,11 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn payload_pre_merge() {
|
||||
let (tx, rx) = unbounded_channel();
|
||||
let config = Config::default();
|
||||
let chain_spec = MAINNET.clone();
|
||||
let client = Arc::new(MockEthProvider::default());
|
||||
let engine = EthConsensusEngine {
|
||||
client: client.clone(),
|
||||
config: config.clone(),
|
||||
chain_spec: chain_spec.clone(),
|
||||
local_store: Default::default(),
|
||||
rx: UnboundedReceiverStream::new(rx),
|
||||
};
|
||||
@ -514,7 +516,8 @@ mod tests {
|
||||
|
||||
let (result_tx, result_rx) = oneshot::channel();
|
||||
let parent = transform_block(random_block(100, None, None, Some(0)), |mut b| {
|
||||
b.header.difficulty = U256::from(config.merge_terminal_total_difficulty);
|
||||
b.header.difficulty =
|
||||
chain_spec.paris_status().terminal_total_difficulty().unwrap();
|
||||
b
|
||||
});
|
||||
let block = random_block(101, Some(parent.hash()), None, Some(0));
|
||||
@ -535,11 +538,11 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn invalid_payload_timestamp() {
|
||||
let (tx, rx) = unbounded_channel();
|
||||
let config = Config::default();
|
||||
let chain_spec = MAINNET.clone();
|
||||
let client = Arc::new(MockEthProvider::default());
|
||||
let engine = EthConsensusEngine {
|
||||
client: client.clone(),
|
||||
config: config.clone(),
|
||||
chain_spec: chain_spec.clone(),
|
||||
local_store: Default::default(),
|
||||
rx: UnboundedReceiverStream::new(rx),
|
||||
};
|
||||
@ -551,7 +554,8 @@ mod tests {
|
||||
let parent_timestamp = block_timestamp + 10;
|
||||
let parent = transform_block(random_block(100, None, None, Some(0)), |mut b| {
|
||||
b.header.timestamp = parent_timestamp;
|
||||
b.header.difficulty = U256::from(config.merge_terminal_total_difficulty + 1);
|
||||
b.header.difficulty =
|
||||
chain_spec.paris_status().terminal_total_difficulty().unwrap() + U256::from(1);
|
||||
b
|
||||
});
|
||||
let block =
|
||||
@ -583,6 +587,8 @@ mod tests {
|
||||
// non exhaustive tests for engine_getPayload
|
||||
// TODO: amend when block building is implemented
|
||||
mod get_payload {
|
||||
use reth_primitives::MAINNET;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
@ -590,7 +596,7 @@ mod tests {
|
||||
let (tx, rx) = unbounded_channel();
|
||||
let engine = EthConsensusEngine {
|
||||
client: Arc::new(MockEthProvider::default()),
|
||||
config: Config::default(),
|
||||
chain_spec: MAINNET.clone(),
|
||||
local_store: Default::default(),
|
||||
rx: UnboundedReceiverStream::new(rx),
|
||||
};
|
||||
@ -609,15 +615,17 @@ mod tests {
|
||||
|
||||
// https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md#specification-3
|
||||
mod exchange_transition_configuration {
|
||||
use reth_primitives::MAINNET;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn terminal_td_mismatch() {
|
||||
let (tx, rx) = unbounded_channel();
|
||||
let config = Config::default();
|
||||
let chain_spec = MAINNET.clone();
|
||||
let engine = EthConsensusEngine {
|
||||
client: Arc::new(MockEthProvider::default()),
|
||||
config: config.clone(),
|
||||
chain_spec: chain_spec.clone(),
|
||||
local_store: Default::default(),
|
||||
rx: UnboundedReceiverStream::new(rx),
|
||||
};
|
||||
@ -625,7 +633,11 @@ mod tests {
|
||||
tokio::spawn(engine);
|
||||
|
||||
let transition_config = TransitionConfiguration {
|
||||
terminal_total_difficulty: U256::from(config.merge_terminal_total_difficulty + 1),
|
||||
terminal_total_difficulty: chain_spec
|
||||
.paris_status()
|
||||
.terminal_total_difficulty()
|
||||
.unwrap() +
|
||||
U256::from(1),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@ -639,7 +651,7 @@ mod tests {
|
||||
assert_matches!(
|
||||
result_rx.await,
|
||||
Ok(Err(EngineApiError::TerminalTD { execution, consensus }))
|
||||
if execution == U256::from(config.merge_terminal_total_difficulty)
|
||||
if execution == chain_spec.paris_status().terminal_total_difficulty().unwrap()
|
||||
&& consensus == U256::from(transition_config.terminal_total_difficulty)
|
||||
);
|
||||
}
|
||||
@ -648,10 +660,10 @@ mod tests {
|
||||
async fn terminal_block_hash_mismatch() {
|
||||
let (tx, rx) = unbounded_channel();
|
||||
let client = Arc::new(MockEthProvider::default());
|
||||
let config = Config::default();
|
||||
let chain_spec = MAINNET.clone();
|
||||
let engine = EthConsensusEngine {
|
||||
client: client.clone(),
|
||||
config: config.clone(),
|
||||
chain_spec: chain_spec.clone(),
|
||||
local_store: Default::default(),
|
||||
rx: UnboundedReceiverStream::new(rx),
|
||||
};
|
||||
@ -663,7 +675,10 @@ mod tests {
|
||||
let execution_terminal_block = random_block(terminal_block_number, None, None, None);
|
||||
|
||||
let transition_config = TransitionConfiguration {
|
||||
terminal_total_difficulty: U256::from(config.merge_terminal_total_difficulty),
|
||||
terminal_total_difficulty: chain_spec
|
||||
.paris_status()
|
||||
.terminal_total_difficulty()
|
||||
.unwrap(),
|
||||
terminal_block_hash: consensus_terminal_block.hash(),
|
||||
terminal_block_number: terminal_block_number.into(),
|
||||
};
|
||||
@ -708,10 +723,10 @@ mod tests {
|
||||
async fn configurations_match() {
|
||||
let (tx, rx) = unbounded_channel();
|
||||
let client = Arc::new(MockEthProvider::default());
|
||||
let config = Config::default();
|
||||
let chain_spec = MAINNET.clone();
|
||||
let engine = EthConsensusEngine {
|
||||
client: client.clone(),
|
||||
config: config.clone(),
|
||||
chain_spec: chain_spec.clone(),
|
||||
local_store: Default::default(),
|
||||
rx: UnboundedReceiverStream::new(rx),
|
||||
};
|
||||
@ -722,7 +737,10 @@ mod tests {
|
||||
let terminal_block = random_block(terminal_block_number, None, None, None);
|
||||
|
||||
let transition_config = TransitionConfiguration {
|
||||
terminal_total_difficulty: U256::from(config.merge_terminal_total_difficulty),
|
||||
terminal_total_difficulty: chain_spec
|
||||
.paris_status()
|
||||
.terminal_total_difficulty()
|
||||
.unwrap(),
|
||||
terminal_block_hash: terminal_block.hash(),
|
||||
terminal_block_number: terminal_block_number.into(),
|
||||
};
|
||||
|
||||
@ -9,13 +9,12 @@
|
||||
//! # Features
|
||||
//!
|
||||
//! - `serde`: Enable serde support for configuration types.
|
||||
pub mod config;
|
||||
pub mod consensus;
|
||||
pub mod constants;
|
||||
pub mod verification;
|
||||
|
||||
/// Engine API module.
|
||||
pub mod engine;
|
||||
|
||||
pub use config::Config;
|
||||
pub use consensus::BeaconConsensus;
|
||||
pub use reth_interfaces::consensus::Error;
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
//! ALl functions for verification of block
|
||||
use crate::{config, Config};
|
||||
use reth_interfaces::{consensus::Error, Result as RethResult};
|
||||
use reth_primitives::{
|
||||
BlockNumber, Header, SealedBlock, SealedHeader, Transaction, TransactionSignedEcRecovered,
|
||||
TxEip1559, TxEip2930, TxLegacy, EMPTY_OMMER_ROOT, U256,
|
||||
BlockNumber, ChainSpec, Hardfork, Header, SealedBlock, SealedHeader, Transaction,
|
||||
TransactionSignedEcRecovered, TxEip1559, TxEip2930, TxLegacy, EMPTY_OMMER_ROOT, U256,
|
||||
};
|
||||
use reth_provider::{AccountProvider, HeaderProvider};
|
||||
use std::{
|
||||
@ -11,10 +10,12 @@ use std::{
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
use crate::constants;
|
||||
|
||||
/// Validate header standalone
|
||||
pub fn validate_header_standalone(
|
||||
header: &SealedHeader,
|
||||
config: &config::Config,
|
||||
chain_spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
// Gas used needs to be less then gas limit. Gas used is going to be check after execution.
|
||||
if header.gas_used > header.gas_limit {
|
||||
@ -38,13 +39,14 @@ pub fn validate_header_standalone(
|
||||
}
|
||||
|
||||
// Check if base fee is set.
|
||||
if header.number >= config.london_block && header.base_fee_per_gas.is_none() {
|
||||
if chain_spec.fork_active(Hardfork::London, header.number) && header.base_fee_per_gas.is_none()
|
||||
{
|
||||
return Err(Error::BaseFeeMissing)
|
||||
}
|
||||
|
||||
// EIP-3675: Upgrade consensus to Proof-of-Stake:
|
||||
// https://eips.ethereum.org/EIPS/eip-3675#replacing-difficulty-with-0
|
||||
if header.number >= config.paris_block {
|
||||
if Some(header.number) >= chain_spec.paris_status().block_number() {
|
||||
if header.difficulty != U256::ZERO {
|
||||
return Err(Error::TheMergeDifficultyIsNotZero)
|
||||
}
|
||||
@ -69,21 +71,23 @@ pub fn validate_header_standalone(
|
||||
/// The only parameter from the header that affects the transaction is `base_fee`.
|
||||
pub fn validate_transaction_regarding_header(
|
||||
transaction: &Transaction,
|
||||
config: &Config,
|
||||
chain_spec: &ChainSpec,
|
||||
at_block_number: BlockNumber,
|
||||
base_fee: Option<u64>,
|
||||
) -> Result<(), Error> {
|
||||
let chain_id = match transaction {
|
||||
Transaction::Legacy(TxLegacy { chain_id, .. }) => {
|
||||
// EIP-155: Simple replay attack protection: https://eips.ethereum.org/EIPS/eip-155
|
||||
if config.eip_155_block <= at_block_number && chain_id.is_some() {
|
||||
if chain_spec.fork_active(Hardfork::SpuriousDragon, at_block_number) &&
|
||||
chain_id.is_some()
|
||||
{
|
||||
return Err(Error::TransactionOldLegacyChainId)
|
||||
}
|
||||
*chain_id
|
||||
}
|
||||
Transaction::Eip2930(TxEip2930 { chain_id, .. }) => {
|
||||
// EIP-2930: Optional access lists: https://eips.ethereum.org/EIPS/eip-2930 (New transaction type)
|
||||
if config.berlin_block > at_block_number {
|
||||
if !chain_spec.fork_active(Hardfork::Berlin, at_block_number) {
|
||||
return Err(Error::TransactionEip2930Disabled)
|
||||
}
|
||||
Some(*chain_id)
|
||||
@ -95,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
|
||||
if config.berlin_block > at_block_number {
|
||||
if !chain_spec.fork_active(Hardfork::Berlin, at_block_number) {
|
||||
return Err(Error::TransactionEip1559Disabled)
|
||||
}
|
||||
|
||||
@ -109,7 +113,7 @@ pub fn validate_transaction_regarding_header(
|
||||
}
|
||||
};
|
||||
if let Some(chain_id) = chain_id {
|
||||
if chain_id != config.chain_id {
|
||||
if chain_id != chain_spec.chain().id() {
|
||||
return Err(Error::TransactionChainId)
|
||||
}
|
||||
}
|
||||
@ -133,14 +137,14 @@ pub fn validate_all_transaction_regarding_block_and_nonces<
|
||||
transactions: impl Iterator<Item = &'a TransactionSignedEcRecovered>,
|
||||
header: &Header,
|
||||
provider: Provider,
|
||||
config: &Config,
|
||||
chain_spec: &ChainSpec,
|
||||
) -> RethResult<()> {
|
||||
let mut account_nonces = HashMap::new();
|
||||
|
||||
for transaction in transactions {
|
||||
validate_transaction_regarding_header(
|
||||
transaction,
|
||||
config,
|
||||
chain_spec,
|
||||
header.number,
|
||||
header.base_fee_per_gas,
|
||||
)?;
|
||||
@ -208,7 +212,7 @@ pub fn validate_block_standalone(block: &SealedBlock) -> Result<(), Error> {
|
||||
|
||||
/// Calculate base fee for next block. EIP-1559 spec
|
||||
pub fn calculate_next_block_base_fee(gas_used: u64, gas_limit: u64, base_fee: u64) -> u64 {
|
||||
let gas_target = gas_limit / config::EIP1559_ELASTICITY_MULTIPLIER;
|
||||
let gas_target = gas_limit / constants::EIP1559_ELASTICITY_MULTIPLIER;
|
||||
|
||||
if gas_used == gas_target {
|
||||
return base_fee
|
||||
@ -219,14 +223,14 @@ pub fn calculate_next_block_base_fee(gas_used: u64, gas_limit: u64, base_fee: u6
|
||||
1,
|
||||
base_fee as u128 * gas_used_delta as u128 /
|
||||
gas_target as u128 /
|
||||
config::EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR as u128,
|
||||
constants::EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR as u128,
|
||||
);
|
||||
base_fee + (base_fee_delta as u64)
|
||||
} else {
|
||||
let gas_used_delta = gas_target - gas_used;
|
||||
let base_fee_per_gas_delta = base_fee as u128 * gas_used_delta as u128 /
|
||||
gas_target as u128 /
|
||||
config::EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR as u128;
|
||||
constants::EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR as u128;
|
||||
|
||||
base_fee.saturating_sub(base_fee_per_gas_delta as u64)
|
||||
}
|
||||
@ -236,7 +240,7 @@ pub fn calculate_next_block_base_fee(gas_used: u64, gas_limit: u64, base_fee: u6
|
||||
pub fn validate_header_regarding_parent(
|
||||
parent: &SealedHeader,
|
||||
child: &SealedHeader,
|
||||
config: &config::Config,
|
||||
chain_spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
// Parent number is consistent.
|
||||
if parent.number + 1 != child.number {
|
||||
@ -255,7 +259,7 @@ pub fn validate_header_regarding_parent(
|
||||
}
|
||||
|
||||
// difficulty check is done by consensus.
|
||||
if config.paris_block > child.number {
|
||||
if chain_spec.paris_status().block_number() > Some(child.number) {
|
||||
// TODO how this needs to be checked? As ice age did increment it by some formula
|
||||
}
|
||||
|
||||
@ -263,8 +267,8 @@ pub fn validate_header_regarding_parent(
|
||||
|
||||
// By consensus, gas_limit is multiplied by elasticity (*2) on
|
||||
// on exact block that hardfork happens.
|
||||
if config.london_block == child.number {
|
||||
parent_gas_limit = parent.gas_limit * config::EIP1559_ELASTICITY_MULTIPLIER;
|
||||
if chain_spec.fork_block(Hardfork::London) == Some(child.number) {
|
||||
parent_gas_limit = parent.gas_limit * constants::EIP1559_ELASTICITY_MULTIPLIER;
|
||||
}
|
||||
|
||||
// Check gas limit, max diff between child/parent gas_limit should be max_diff=parent_gas/1024
|
||||
@ -283,11 +287,11 @@ pub fn validate_header_regarding_parent(
|
||||
}
|
||||
|
||||
// EIP-1559 check base fee
|
||||
if child.number >= config.london_block {
|
||||
if chain_spec.fork_active(Hardfork::London, child.number) {
|
||||
let base_fee = child.base_fee_per_gas.ok_or(Error::BaseFeeMissing)?;
|
||||
|
||||
let expected_base_fee = if config.london_block == child.number {
|
||||
config::EIP1559_INITIAL_BASE_FEE
|
||||
let expected_base_fee = if chain_spec.fork_block(Hardfork::London) == Some(child.number) {
|
||||
constants::EIP1559_INITIAL_BASE_FEE
|
||||
} else {
|
||||
// This BaseFeeMissing will not happen as previous blocks are checked to have them.
|
||||
calculate_next_block_base_fee(
|
||||
@ -335,12 +339,12 @@ pub fn validate_block_regarding_chain<PROV: HeaderProvider>(
|
||||
pub fn full_validation<Provider: HeaderProvider + AccountProvider>(
|
||||
block: &SealedBlock,
|
||||
provider: Provider,
|
||||
config: &Config,
|
||||
chain_spec: &ChainSpec,
|
||||
) -> RethResult<()> {
|
||||
validate_header_standalone(&block.header, config)?;
|
||||
validate_header_standalone(&block.header, chain_spec)?;
|
||||
validate_block_standalone(block)?;
|
||||
let parent = validate_block_regarding_chain(block, &provider)?;
|
||||
validate_header_regarding_parent(&parent, &block.header, config)?;
|
||||
validate_header_regarding_parent(&parent, &block.header, chain_spec)?;
|
||||
|
||||
// NOTE: depending on the need of the stages, recovery could be done in different place.
|
||||
let transactions = block
|
||||
@ -353,7 +357,7 @@ pub fn full_validation<Provider: HeaderProvider + AccountProvider>(
|
||||
transactions.iter(),
|
||||
&block.header,
|
||||
provider,
|
||||
config,
|
||||
chain_spec,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
@ -363,7 +367,7 @@ mod tests {
|
||||
use reth_interfaces::Result;
|
||||
use reth_primitives::{
|
||||
hex_literal::hex, Account, Address, BlockHash, Bytes, Header, Signature, TransactionKind,
|
||||
TransactionSigned,
|
||||
TransactionSigned, MAINNET,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
@ -495,19 +499,17 @@ mod tests {
|
||||
fn sanity_check() {
|
||||
let (block, parent) = mock_block();
|
||||
let provider = Provider::new(Some(parent));
|
||||
let config = Config::default();
|
||||
|
||||
assert_eq!(full_validation(&block, provider, &config), Ok(()), "Validation should pass");
|
||||
assert_eq!(full_validation(&block, provider, &MAINNET), Ok(()), "Validation should pass");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_known_block() {
|
||||
let (block, _) = mock_block();
|
||||
let provider = Provider::new_known();
|
||||
let config = Config::default();
|
||||
|
||||
assert_eq!(
|
||||
full_validation(&block, provider, &config),
|
||||
full_validation(&block, provider, &MAINNET),
|
||||
Err(Error::BlockKnown { hash: block.hash(), number: block.number }.into()),
|
||||
"Should fail with error"
|
||||
);
|
||||
@ -519,14 +521,13 @@ mod tests {
|
||||
let tx1 = mock_tx(0);
|
||||
let tx2 = mock_tx(1);
|
||||
let provider = Provider::new_known();
|
||||
let config = Config::default();
|
||||
|
||||
let txs = vec![tx1, tx2];
|
||||
validate_all_transaction_regarding_block_and_nonces(
|
||||
txs.iter(),
|
||||
&block.header,
|
||||
provider,
|
||||
&config,
|
||||
&MAINNET,
|
||||
)
|
||||
.expect("To Pass");
|
||||
}
|
||||
@ -536,7 +537,6 @@ mod tests {
|
||||
let (block, _) = mock_block();
|
||||
let tx1 = mock_tx(1);
|
||||
let provider = Provider::new_known();
|
||||
let config = Config::default();
|
||||
|
||||
let txs = vec![tx1];
|
||||
assert_eq!(
|
||||
@ -544,7 +544,7 @@ mod tests {
|
||||
txs.iter(),
|
||||
&block.header,
|
||||
provider,
|
||||
&config,
|
||||
&MAINNET,
|
||||
),
|
||||
Err(Error::TransactionNonceNotConsistent.into())
|
||||
)
|
||||
@ -556,7 +556,6 @@ mod tests {
|
||||
let tx1 = mock_tx(0);
|
||||
let tx2 = mock_tx(3);
|
||||
let provider = Provider::new_known();
|
||||
let config = Config::default();
|
||||
|
||||
let txs = vec![tx1, tx2];
|
||||
assert_eq!(
|
||||
@ -564,7 +563,7 @@ mod tests {
|
||||
txs.iter(),
|
||||
&block.header,
|
||||
provider,
|
||||
&config,
|
||||
&MAINNET,
|
||||
),
|
||||
Err(Error::TransactionNonceNotConsistent.into())
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user