mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-08 03:01:12 -04:00
feat(ethereum-forks): remove total difficulty for hardfork check (#13362)
Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
This commit is contained in:
@@ -265,7 +265,7 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
|
||||
EthExecutorProvider::ethereum(provider_factory.chain_spec()).executor(db);
|
||||
|
||||
let block_execution_output =
|
||||
executor.execute((&block_with_senders.clone().unseal(), U256::MAX).into())?;
|
||||
executor.execute(&block_with_senders.clone().unseal())?;
|
||||
let execution_outcome =
|
||||
ExecutionOutcome::from((block_execution_output, block.number));
|
||||
debug!(target: "reth::cli", ?execution_outcome, "Executed block");
|
||||
|
||||
@@ -24,9 +24,8 @@ use reth_node_ethereum::EthExecutorProvider;
|
||||
use reth_primitives::BlockExt;
|
||||
use reth_provider::{
|
||||
providers::ProviderNodeTypes, AccountExtReader, ChainSpecProvider, DatabaseProviderFactory,
|
||||
HashedPostStateProvider, HashingWriter, HeaderProvider, LatestStateProviderRef,
|
||||
OriginalValuesKnown, ProviderFactory, StageCheckpointReader, StateWriter, StorageLocation,
|
||||
StorageReader,
|
||||
HashedPostStateProvider, HashingWriter, LatestStateProviderRef, OriginalValuesKnown,
|
||||
ProviderFactory, StageCheckpointReader, StateWriter, StorageLocation, StorageReader,
|
||||
};
|
||||
use reth_revm::database::StateProviderDatabase;
|
||||
use reth_stages::StageId;
|
||||
@@ -148,19 +147,12 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
|
||||
let db = StateProviderDatabase::new(&state_provider);
|
||||
|
||||
let executor = EthExecutorProvider::ethereum(provider_factory.chain_spec()).executor(db);
|
||||
|
||||
let merkle_block_td =
|
||||
provider.header_td_by_number(merkle_block_number)?.unwrap_or_default();
|
||||
let block_execution_output = executor.execute(
|
||||
(
|
||||
&block
|
||||
.clone()
|
||||
.unseal::<BlockTy<N>>()
|
||||
.with_recovered_senders()
|
||||
.ok_or(BlockValidationError::SenderRecoveryError)?,
|
||||
merkle_block_td + block.difficulty,
|
||||
)
|
||||
.into(),
|
||||
&block
|
||||
.clone()
|
||||
.unseal::<BlockTy<N>>()
|
||||
.with_recovered_senders()
|
||||
.ok_or(BlockValidationError::SenderRecoveryError)?,
|
||||
)?;
|
||||
let execution_outcome = ExecutionOutcome::from((block_execution_output, block.number));
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
|
||||
let mut executor = executor_provider.batch_executor(StateProviderDatabase::new(
|
||||
LatestStateProviderRef::new(&provider_rw),
|
||||
));
|
||||
executor.execute_and_verify_one((&sealed_block.clone().unseal(), td).into())?;
|
||||
executor.execute_and_verify_one(&sealed_block.clone().unseal())?;
|
||||
let execution_outcome = executor.finalize();
|
||||
|
||||
provider_rw.write_state(
|
||||
|
||||
@@ -397,7 +397,6 @@ where
|
||||
.header_td(&block.parent_hash)?
|
||||
.ok_or_else(|| BlockchainTreeError::CanonicalChain { block_hash: block.parent_hash })?;
|
||||
|
||||
// Pass the parent total difficulty to short-circuit unnecessary calculations.
|
||||
if !self
|
||||
.externals
|
||||
.provider_factory
|
||||
@@ -1037,6 +1036,7 @@ where
|
||||
})
|
||||
},
|
||||
)?;
|
||||
|
||||
if !self
|
||||
.externals
|
||||
.provider_factory
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
use super::externals::TreeExternals;
|
||||
use crate::BundleStateDataRef;
|
||||
use alloy_eips::ForkBlock;
|
||||
use alloy_primitives::{BlockHash, BlockNumber, U256};
|
||||
use alloy_primitives::{BlockHash, BlockNumber};
|
||||
use reth_blockchain_tree_api::{
|
||||
error::{BlockchainTreeError, InsertBlockErrorKind},
|
||||
BlockAttachment, BlockValidationKind,
|
||||
@@ -209,7 +209,7 @@ impl AppendableChain {
|
||||
let block_hash = block.hash();
|
||||
let block = block.unseal();
|
||||
|
||||
let state = executor.execute((&block, U256::MAX).into())?;
|
||||
let state = executor.execute(&block)?;
|
||||
externals.consensus.validate_block_post_execution(
|
||||
&block,
|
||||
PostExecutionInput::new(&state.receipts, &state.requests),
|
||||
|
||||
@@ -240,6 +240,12 @@ impl ChainSpec {
|
||||
self.chain == Chain::optimism_mainnet()
|
||||
}
|
||||
|
||||
/// Returns the known paris block, if it exists.
|
||||
#[inline]
|
||||
pub fn paris_block(&self) -> Option<u64> {
|
||||
self.paris_block_and_final_difficulty.map(|(block, _)| block)
|
||||
}
|
||||
|
||||
/// Get the genesis block specification.
|
||||
///
|
||||
/// To get the header for the genesis block, use [`Self::genesis_header`] instead.
|
||||
@@ -389,7 +395,7 @@ impl ChainSpec {
|
||||
|
||||
/// Returns the hardfork display helper.
|
||||
pub fn display_hardforks(&self) -> DisplayHardforks {
|
||||
DisplayHardforks::new(&self, self.paris_block_and_final_difficulty.map(|(block, _)| block))
|
||||
DisplayHardforks::new(&self)
|
||||
}
|
||||
|
||||
/// Get the fork id for the given hardfork.
|
||||
@@ -603,12 +609,20 @@ impl From<Genesis> for ChainSpec {
|
||||
.filter_map(|(hardfork, opt)| opt.map(|block| (hardfork, ForkCondition::Block(block))))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Paris
|
||||
// We expect no new networks to be configured with the merge, so we ignore the TTD field
|
||||
// and merge netsplit block from external genesis files. All existing networks that have
|
||||
// merged should have a static ChainSpec already (namely mainnet and sepolia).
|
||||
let paris_block_and_final_difficulty =
|
||||
if let Some(ttd) = genesis.config.terminal_total_difficulty {
|
||||
hardforks.push((
|
||||
EthereumHardfork::Paris.boxed(),
|
||||
ForkCondition::TTD {
|
||||
// NOTE: this will not work properly if the merge is not activated at
|
||||
// genesis, and there is no merge netsplit block
|
||||
activation_block_number: genesis
|
||||
.config
|
||||
.merge_netsplit_block
|
||||
.unwrap_or_default(),
|
||||
total_difficulty: ttd,
|
||||
fork_block: genesis.config.merge_netsplit_block,
|
||||
},
|
||||
@@ -765,10 +779,10 @@ impl ChainSpecBuilder {
|
||||
/// Enable the Paris hardfork at the given TTD.
|
||||
///
|
||||
/// Does not set the merge netsplit block.
|
||||
pub fn paris_at_ttd(self, ttd: U256) -> Self {
|
||||
pub fn paris_at_ttd(self, ttd: U256, activation_block_number: BlockNumber) -> Self {
|
||||
self.with_fork(
|
||||
EthereumHardfork::Paris,
|
||||
ForkCondition::TTD { total_difficulty: ttd, fork_block: None },
|
||||
ForkCondition::TTD { activation_block_number, total_difficulty: ttd, fork_block: None },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -846,7 +860,11 @@ impl ChainSpecBuilder {
|
||||
self = self.london_activated();
|
||||
self.hardforks.insert(
|
||||
EthereumHardfork::Paris,
|
||||
ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO },
|
||||
ForkCondition::TTD {
|
||||
activation_block_number: 0,
|
||||
total_difficulty: U256::ZERO,
|
||||
fork_block: None,
|
||||
},
|
||||
);
|
||||
self
|
||||
}
|
||||
@@ -888,8 +906,8 @@ impl ChainSpecBuilder {
|
||||
pub fn build(self) -> ChainSpec {
|
||||
let paris_block_and_final_difficulty = {
|
||||
self.hardforks.get(EthereumHardfork::Paris).and_then(|cond| {
|
||||
if let ForkCondition::TTD { fork_block, total_difficulty } = cond {
|
||||
fork_block.map(|fork_block| (fork_block, total_difficulty))
|
||||
if let ForkCondition::TTD { total_difficulty, activation_block_number, .. } = cond {
|
||||
Some((activation_block_number, total_difficulty))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -1133,6 +1151,7 @@ Post-merge hard forks (timestamp based):
|
||||
.with_fork(
|
||||
EthereumHardfork::Paris,
|
||||
ForkCondition::TTD {
|
||||
activation_block_number: 101,
|
||||
fork_block: Some(101),
|
||||
total_difficulty: U256::from(10_790_000),
|
||||
},
|
||||
@@ -1166,6 +1185,7 @@ Post-merge hard forks (timestamp based):
|
||||
// Fork::ConditionTTD test case without a new chain spec to demonstrate ChainSpec::satisfy
|
||||
// is independent of ChainSpec for this(these - including ForkCondition::Block) match arm(s)
|
||||
let fork_cond_ttd_no_new_spec = fork_cond_block_only_case.satisfy(ForkCondition::TTD {
|
||||
activation_block_number: 101,
|
||||
fork_block: None,
|
||||
total_difficulty: U256::from(10_790_000),
|
||||
});
|
||||
|
||||
@@ -2460,7 +2460,7 @@ mod tests {
|
||||
.chain(MAINNET.chain)
|
||||
.genesis(MAINNET.genesis.clone())
|
||||
.london_activated()
|
||||
.paris_at_ttd(U256::from(3))
|
||||
.paris_at_ttd(U256::from(3), 3)
|
||||
.build(),
|
||||
);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use alloy_consensus::constants::ETH_TO_WEI;
|
||||
use alloy_primitives::{BlockNumber, U256};
|
||||
use reth_chainspec::{EthereumHardfork, Hardforks};
|
||||
use alloy_primitives::BlockNumber;
|
||||
use reth_chainspec::{EthereumHardfork, EthereumHardforks, Hardforks};
|
||||
|
||||
/// Calculates the base block reward.
|
||||
///
|
||||
@@ -21,13 +21,11 @@ use reth_chainspec::{EthereumHardfork, Hardforks};
|
||||
/// - Definition: [Yellow Paper][yp] (page 15, 11.3)
|
||||
///
|
||||
/// [yp]: https://ethereum.github.io/yellowpaper/paper.pdf
|
||||
pub fn base_block_reward(
|
||||
chain_spec: impl Hardforks,
|
||||
pub fn base_block_reward<ChainSpec: EthereumHardforks>(
|
||||
chain_spec: &ChainSpec,
|
||||
block_number: BlockNumber,
|
||||
block_difficulty: U256,
|
||||
total_difficulty: U256,
|
||||
) -> Option<u128> {
|
||||
if chain_spec.fork(EthereumHardfork::Paris).active_at_ttd(total_difficulty, block_difficulty) {
|
||||
if chain_spec.is_paris_active_at_block(block_number).is_some_and(|active| active) {
|
||||
None
|
||||
} else {
|
||||
Some(base_block_reward_pre_merge(chain_spec, block_number))
|
||||
@@ -62,12 +60,9 @@ pub fn base_block_reward_pre_merge(chain_spec: impl Hardforks, block_number: Blo
|
||||
/// #
|
||||
/// // This is block 126 on mainnet.
|
||||
/// let block_number = 126;
|
||||
/// let block_difficulty = U256::from(18_145_285_642usize);
|
||||
/// let total_difficulty = U256::from(2_235_668_675_900usize);
|
||||
/// let number_of_ommers = 1;
|
||||
///
|
||||
/// let reward = base_block_reward(&*MAINNET, block_number, block_difficulty, total_difficulty)
|
||||
/// .map(|reward| block_reward(reward, 1));
|
||||
/// let reward = base_block_reward(&*MAINNET, block_number).map(|reward| block_reward(reward, 1));
|
||||
///
|
||||
/// // The base block reward is 5 ETH, and the ommer inclusion reward is 1/32th of 5 ETH.
|
||||
/// assert_eq!(reward.unwrap(), ETH_TO_WEI * 5 + ((ETH_TO_WEI * 5) >> 5));
|
||||
@@ -113,6 +108,7 @@ pub const fn ommer_reward(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use alloy_primitives::U256;
|
||||
use reth_chainspec::MAINNET;
|
||||
|
||||
#[test]
|
||||
@@ -126,11 +122,11 @@ mod tests {
|
||||
// Petersburg
|
||||
((7280000, U256::ZERO), Some(ETH_TO_WEI * 2)),
|
||||
// Merge
|
||||
((10000000, U256::from(58_750_000_000_000_000_000_000_u128)), None),
|
||||
((15537394, U256::from(58_750_000_000_000_000_000_000_u128)), None),
|
||||
];
|
||||
|
||||
for ((block_number, td), expected_reward) in cases {
|
||||
assert_eq!(base_block_reward(&*MAINNET, block_number, U256::ZERO, td), expected_reward);
|
||||
for ((block_number, _td), expected_reward) in cases {
|
||||
assert_eq!(base_block_reward(&*MAINNET, block_number), expected_reward);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use alloy_consensus::BlockHeader;
|
||||
use alloy_primitives::{keccak256, B256, U256};
|
||||
use alloy_primitives::{keccak256, B256};
|
||||
use alloy_rpc_types_debug::ExecutionWitness;
|
||||
use eyre::OptionExt;
|
||||
use pretty_assertions::Comparison;
|
||||
@@ -79,7 +79,7 @@ where
|
||||
|
||||
// Setup environment for the execution.
|
||||
let EvmEnv { cfg_env_with_handler_cfg, block_env } =
|
||||
self.evm_config.cfg_and_block_env(block.header(), U256::MAX);
|
||||
self.evm_config.cfg_and_block_env(block.header());
|
||||
|
||||
// Setup EVM
|
||||
let mut evm = self.evm_config.evm_with_env(
|
||||
@@ -116,7 +116,6 @@ where
|
||||
let balance_increments = post_block_balance_increments(
|
||||
self.provider.chain_spec().as_ref(),
|
||||
&block.clone().unseal().block,
|
||||
U256::MAX,
|
||||
);
|
||||
|
||||
// increment balances
|
||||
|
||||
@@ -2261,11 +2261,7 @@ where
|
||||
// };
|
||||
let state_hook = Box::new(|_state: &EvmState| {});
|
||||
|
||||
let output = self.metrics.executor.execute_metered(
|
||||
executor,
|
||||
(&block, U256::MAX).into(),
|
||||
state_hook,
|
||||
)?;
|
||||
let output = self.metrics.executor.execute_metered(executor, &block, state_hook)?;
|
||||
|
||||
trace!(target: "engine::tree", elapsed=?exec_time.elapsed(), ?block_number, "Executed block");
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
//! Stream wrapper that simulates reorgs.
|
||||
|
||||
use alloy_consensus::{Header, Transaction};
|
||||
use alloy_primitives::U256;
|
||||
use alloy_rpc_types_engine::{
|
||||
CancunPayloadFields, ExecutionPayload, ExecutionPayloadSidecar, ForkchoiceState, PayloadStatus,
|
||||
};
|
||||
@@ -299,7 +298,7 @@ where
|
||||
|
||||
// Configure environments
|
||||
let EvmEnv { cfg_env_with_handler_cfg, block_env } =
|
||||
evm_config.cfg_and_block_env(&reorg_target.header, U256::MAX);
|
||||
evm_config.cfg_and_block_env(&reorg_target.header);
|
||||
let env = EnvWithHandlerCfg::new_with_cfg_env(
|
||||
cfg_env_with_handler_cfg,
|
||||
block_env,
|
||||
|
||||
@@ -38,17 +38,12 @@ impl core::fmt::Display for DisplayFork {
|
||||
ForkCondition::Block(at) | ForkCondition::Timestamp(at) => {
|
||||
write!(f, "{name_with_eip:32} @{at}")?;
|
||||
}
|
||||
ForkCondition::TTD { fork_block, total_difficulty } => {
|
||||
ForkCondition::TTD { total_difficulty, .. } => {
|
||||
// All networks that have merged are finalized.
|
||||
write!(
|
||||
f,
|
||||
"{:32} @{} ({})",
|
||||
name_with_eip,
|
||||
total_difficulty,
|
||||
if fork_block.is_some() {
|
||||
"network is known to be merged"
|
||||
} else {
|
||||
"network is not known to be merged"
|
||||
}
|
||||
"{:32} @{} (network is known to be merged)",
|
||||
name_with_eip, total_difficulty,
|
||||
)?;
|
||||
}
|
||||
ForkCondition::Never => unreachable!(),
|
||||
@@ -141,7 +136,7 @@ impl core::fmt::Display for DisplayHardforks {
|
||||
|
||||
impl DisplayHardforks {
|
||||
/// Creates a new [`DisplayHardforks`] from an iterator of hardforks.
|
||||
pub fn new<H: Hardforks>(hardforks: &H, known_paris_block: Option<u64>) -> Self {
|
||||
pub fn new<H: Hardforks>(hardforks: &H) -> Self {
|
||||
let mut pre_merge = Vec::new();
|
||||
let mut with_merge = Vec::new();
|
||||
let mut post_merge = Vec::new();
|
||||
@@ -154,9 +149,12 @@ impl DisplayHardforks {
|
||||
ForkCondition::Block(_) => {
|
||||
pre_merge.push(display_fork);
|
||||
}
|
||||
ForkCondition::TTD { total_difficulty, .. } => {
|
||||
display_fork.activated_at =
|
||||
ForkCondition::TTD { fork_block: known_paris_block, total_difficulty };
|
||||
ForkCondition::TTD { activation_block_number, total_difficulty, fork_block } => {
|
||||
display_fork.activated_at = ForkCondition::TTD {
|
||||
activation_block_number,
|
||||
fork_block,
|
||||
total_difficulty,
|
||||
};
|
||||
with_merge.push(display_fork);
|
||||
}
|
||||
ForkCondition::Timestamp(_) => {
|
||||
|
||||
@@ -9,6 +9,12 @@ pub enum ForkCondition {
|
||||
Block(BlockNumber),
|
||||
/// The fork is activated after a total difficulty has been reached.
|
||||
TTD {
|
||||
/// The activation block number for the merge.
|
||||
///
|
||||
/// This should represent the first post-merge block for the given network. Sepolia and
|
||||
/// mainnet are the only networks that have merged, and they have both finalized
|
||||
/// post-merge, so total difficulty is effectively deprecated.
|
||||
activation_block_number: BlockNumber,
|
||||
/// The block number at which TTD is reached, if it is known.
|
||||
///
|
||||
/// This should **NOT** be set unless you want this block advertised as [EIP-2124][eip2124]
|
||||
@@ -127,16 +133,22 @@ mod tests {
|
||||
);
|
||||
|
||||
// Test if TTD-based condition with known block activates
|
||||
let fork_condition =
|
||||
ForkCondition::TTD { fork_block: Some(10), total_difficulty: U256::from(1000) };
|
||||
let fork_condition = ForkCondition::TTD {
|
||||
activation_block_number: 10,
|
||||
fork_block: Some(10),
|
||||
total_difficulty: U256::from(1000),
|
||||
};
|
||||
assert!(
|
||||
fork_condition.active_at_block(10),
|
||||
"The TTD condition should be active at block 10"
|
||||
);
|
||||
|
||||
// Test if TTD-based condition with unknown block does not activate
|
||||
let fork_condition =
|
||||
ForkCondition::TTD { fork_block: None, total_difficulty: U256::from(1000) };
|
||||
let fork_condition = ForkCondition::TTD {
|
||||
activation_block_number: 10,
|
||||
fork_block: None,
|
||||
total_difficulty: U256::from(1000),
|
||||
};
|
||||
assert!(
|
||||
!fork_condition.active_at_block(10),
|
||||
"The TTD condition should not be active at block 10 with an unknown block number"
|
||||
@@ -166,8 +178,11 @@ mod tests {
|
||||
#[test]
|
||||
fn test_active_at_ttd() {
|
||||
// Test if the condition activates at the correct total difficulty
|
||||
let fork_condition =
|
||||
ForkCondition::TTD { fork_block: Some(10), total_difficulty: U256::from(1000) };
|
||||
let fork_condition = ForkCondition::TTD {
|
||||
activation_block_number: 10,
|
||||
fork_block: Some(10),
|
||||
total_difficulty: U256::from(1000),
|
||||
};
|
||||
assert!(
|
||||
fork_condition.active_at_ttd(U256::from(1000000), U256::from(100)),
|
||||
"The TTD condition should be active when the total difficulty matches"
|
||||
@@ -258,26 +273,38 @@ mod tests {
|
||||
);
|
||||
|
||||
// Test if the condition activates based on total difficulty and block number
|
||||
let fork_condition =
|
||||
ForkCondition::TTD { fork_block: Some(9), total_difficulty: U256::from(900) };
|
||||
let fork_condition = ForkCondition::TTD {
|
||||
activation_block_number: 10,
|
||||
fork_block: Some(9),
|
||||
total_difficulty: U256::from(900),
|
||||
};
|
||||
assert!(
|
||||
fork_condition.active_at_head(&head),
|
||||
"The condition should be active at the given head total difficulty"
|
||||
);
|
||||
let fork_condition =
|
||||
ForkCondition::TTD { fork_block: None, total_difficulty: U256::from(900) };
|
||||
let fork_condition = ForkCondition::TTD {
|
||||
activation_block_number: 10,
|
||||
fork_block: None,
|
||||
total_difficulty: U256::from(900),
|
||||
};
|
||||
assert!(
|
||||
fork_condition.active_at_head(&head),
|
||||
"The condition should be active at the given head total difficulty as the block number is unknown"
|
||||
);
|
||||
let fork_condition =
|
||||
ForkCondition::TTD { fork_block: Some(11), total_difficulty: U256::from(900) };
|
||||
let fork_condition = ForkCondition::TTD {
|
||||
activation_block_number: 10,
|
||||
fork_block: Some(11),
|
||||
total_difficulty: U256::from(900),
|
||||
};
|
||||
assert!(
|
||||
fork_condition.active_at_head(&head),
|
||||
"The condition should be active as the total difficulty is higher"
|
||||
);
|
||||
let fork_condition =
|
||||
ForkCondition::TTD { fork_block: Some(10), total_difficulty: U256::from(9000) };
|
||||
let fork_condition = ForkCondition::TTD {
|
||||
activation_block_number: 10,
|
||||
fork_block: Some(10),
|
||||
total_difficulty: U256::from(9000),
|
||||
};
|
||||
assert!(
|
||||
fork_condition.active_at_head(&head),
|
||||
"The condition should be active as the total difficulty is higher than head"
|
||||
|
||||
@@ -26,7 +26,11 @@ pub static DEV_HARDFORKS: LazyLock<ChainHardforks> = LazyLock::new(|| {
|
||||
(EthereumHardfork::London.boxed(), ForkCondition::Block(0)),
|
||||
(
|
||||
EthereumHardfork::Paris.boxed(),
|
||||
ForkCondition::TTD { fork_block: None, total_difficulty: U256::ZERO },
|
||||
ForkCondition::TTD {
|
||||
activation_block_number: 0,
|
||||
fork_block: None,
|
||||
total_difficulty: U256::ZERO,
|
||||
},
|
||||
),
|
||||
(EthereumHardfork::Shanghai.boxed(), ForkCondition::Timestamp(0)),
|
||||
(EthereumHardfork::Cancun.boxed(), ForkCondition::Timestamp(0)),
|
||||
|
||||
@@ -352,6 +352,7 @@ impl EthereumHardfork {
|
||||
(
|
||||
Self::Paris,
|
||||
ForkCondition::TTD {
|
||||
activation_block_number: 15537394,
|
||||
fork_block: None,
|
||||
total_difficulty: uint!(58_750_000_000_000_000_000_000_U256),
|
||||
},
|
||||
@@ -379,6 +380,7 @@ impl EthereumHardfork {
|
||||
(
|
||||
Self::Paris,
|
||||
ForkCondition::TTD {
|
||||
activation_block_number: 1735371,
|
||||
fork_block: Some(1735371),
|
||||
total_difficulty: uint!(17_000_000_000_000_000_U256),
|
||||
},
|
||||
@@ -403,7 +405,14 @@ impl EthereumHardfork {
|
||||
(Self::MuirGlacier, ForkCondition::Block(0)),
|
||||
(Self::Berlin, ForkCondition::Block(0)),
|
||||
(Self::London, ForkCondition::Block(0)),
|
||||
(Self::Paris, ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO }),
|
||||
(
|
||||
Self::Paris,
|
||||
ForkCondition::TTD {
|
||||
activation_block_number: 0,
|
||||
fork_block: Some(0),
|
||||
total_difficulty: U256::ZERO,
|
||||
},
|
||||
),
|
||||
(Self::Shanghai, ForkCondition::Timestamp(1696000704)),
|
||||
(Self::Cancun, ForkCondition::Timestamp(1707305664)),
|
||||
]
|
||||
|
||||
@@ -50,8 +50,8 @@ pub trait EthereumHardforks: Hardforks {
|
||||
fn is_paris_active_at_block(&self, block_number: u64) -> Option<bool> {
|
||||
match self.fork(EthereumHardfork::Paris) {
|
||||
ForkCondition::Block(paris_block) => Some(block_number >= paris_block),
|
||||
ForkCondition::TTD { fork_block, .. } => {
|
||||
fork_block.map(|paris_block| block_number >= paris_block)
|
||||
ForkCondition::TTD { activation_block_number, .. } => {
|
||||
Some(block_number >= activation_block_number)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ pub struct Head {
|
||||
/// The timestamp of the head block.
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
impl Head {
|
||||
/// Creates a new `Head` instance.
|
||||
pub const fn new(
|
||||
|
||||
@@ -32,7 +32,7 @@ pub fn revm_spec(chain_spec: &ChainSpec, block: &Head) -> revm_primitives::SpecI
|
||||
revm_primitives::CANCUN
|
||||
} else if chain_spec.fork(EthereumHardfork::Shanghai).active_at_head(block) {
|
||||
revm_primitives::SHANGHAI
|
||||
} else if chain_spec.fork(EthereumHardfork::Paris).active_at_head(block) {
|
||||
} else if chain_spec.is_paris_active_at_block(block.number).is_some_and(|active| active) {
|
||||
revm_primitives::MERGE
|
||||
} else if chain_spec.fork(EthereumHardfork::London).active_at_head(block) {
|
||||
revm_primitives::LONDON
|
||||
@@ -166,19 +166,7 @@ mod tests {
|
||||
&Head {
|
||||
total_difficulty: U256::from(58_750_000_000_000_000_000_010_u128),
|
||||
difficulty: U256::from(10_u128),
|
||||
..Default::default()
|
||||
}
|
||||
),
|
||||
revm_primitives::MERGE
|
||||
);
|
||||
// TTD trumps the block number
|
||||
assert_eq!(
|
||||
revm_spec(
|
||||
&MAINNET,
|
||||
&Head {
|
||||
number: 15537394 - 10,
|
||||
total_difficulty: U256::from(58_750_000_000_000_000_000_010_u128),
|
||||
difficulty: U256::from(10_u128),
|
||||
number: 15537394,
|
||||
..Default::default()
|
||||
}
|
||||
),
|
||||
|
||||
@@ -26,7 +26,7 @@ use reth_primitives::{BlockWithSenders, EthPrimitives, Receipt};
|
||||
use reth_revm::db::State;
|
||||
use revm_primitives::{
|
||||
db::{Database, DatabaseCommit},
|
||||
EnvWithHandlerCfg, ResultAndState, U256,
|
||||
EnvWithHandlerCfg, ResultAndState,
|
||||
};
|
||||
|
||||
/// Factory for [`EthExecutionStrategy`].
|
||||
@@ -123,13 +123,9 @@ where
|
||||
/// # Caution
|
||||
///
|
||||
/// This does not initialize the tx environment.
|
||||
fn evm_env_for_block(
|
||||
&self,
|
||||
header: &alloy_consensus::Header,
|
||||
total_difficulty: U256,
|
||||
) -> EnvWithHandlerCfg {
|
||||
fn evm_env_for_block(&self, header: &alloy_consensus::Header) -> EnvWithHandlerCfg {
|
||||
let EvmEnv { cfg_env_with_handler_cfg, block_env } =
|
||||
self.evm_config.cfg_and_block_env(header, total_difficulty);
|
||||
self.evm_config.cfg_and_block_env(header);
|
||||
EnvWithHandlerCfg::new_with_cfg_env(cfg_env_with_handler_cfg, block_env, Default::default())
|
||||
}
|
||||
}
|
||||
@@ -151,17 +147,13 @@ where
|
||||
self.tx_env_overrides = Some(tx_env_overrides);
|
||||
}
|
||||
|
||||
fn apply_pre_execution_changes(
|
||||
&mut self,
|
||||
block: &BlockWithSenders,
|
||||
total_difficulty: U256,
|
||||
) -> Result<(), Self::Error> {
|
||||
fn apply_pre_execution_changes(&mut self, block: &BlockWithSenders) -> Result<(), Self::Error> {
|
||||
// Set state clear flag if the block is after the Spurious Dragon hardfork.
|
||||
let state_clear_flag =
|
||||
(*self.chain_spec).is_spurious_dragon_active_at_block(block.header.number);
|
||||
self.state.set_state_clear_flag(state_clear_flag);
|
||||
|
||||
let env = self.evm_env_for_block(&block.header, total_difficulty);
|
||||
let env = self.evm_env_for_block(&block.header);
|
||||
let mut evm = self.evm_config.evm_with_env(&mut self.state, env);
|
||||
|
||||
self.system_caller.apply_pre_execution_changes(&block.block, &mut evm)?;
|
||||
@@ -172,9 +164,8 @@ where
|
||||
fn execute_transactions(
|
||||
&mut self,
|
||||
block: &BlockWithSenders,
|
||||
total_difficulty: U256,
|
||||
) -> Result<ExecuteOutput<Receipt>, Self::Error> {
|
||||
let env = self.evm_env_for_block(&block.header, total_difficulty);
|
||||
let env = self.evm_env_for_block(&block.header);
|
||||
let mut evm = self.evm_config.evm_with_env(&mut self.state, env);
|
||||
|
||||
let mut cumulative_gas_used = 0;
|
||||
@@ -234,10 +225,9 @@ where
|
||||
fn apply_post_execution_changes(
|
||||
&mut self,
|
||||
block: &BlockWithSenders,
|
||||
total_difficulty: U256,
|
||||
receipts: &[Receipt],
|
||||
) -> Result<Requests, Self::Error> {
|
||||
let env = self.evm_env_for_block(&block.header, total_difficulty);
|
||||
let env = self.evm_env_for_block(&block.header);
|
||||
let mut evm = self.evm_config.evm_with_env(&mut self.state, env);
|
||||
|
||||
let requests = if self.chain_spec.is_prague_active_at_timestamp(block.timestamp) {
|
||||
@@ -258,8 +248,7 @@ where
|
||||
};
|
||||
drop(evm);
|
||||
|
||||
let mut balance_increments =
|
||||
post_block_balance_increments(&self.chain_spec, &block.block, total_difficulty);
|
||||
let mut balance_increments = post_block_balance_increments(&self.chain_spec, &block.block);
|
||||
|
||||
// Irregular state change at Ethereum DAO hardfork
|
||||
if self.chain_spec.fork(EthereumHardfork::Dao).transitions_at_block(block.number) {
|
||||
@@ -337,7 +326,7 @@ mod tests {
|
||||
eip7002::{WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS, WITHDRAWAL_REQUEST_PREDEPLOY_CODE},
|
||||
eip7685::EMPTY_REQUESTS_HASH,
|
||||
};
|
||||
use alloy_primitives::{b256, fixed_bytes, keccak256, Bytes, TxKind, B256};
|
||||
use alloy_primitives::{b256, fixed_bytes, keccak256, Bytes, TxKind, B256, U256};
|
||||
use reth_chainspec::{ChainSpecBuilder, ForkCondition};
|
||||
use reth_evm::execute::{
|
||||
BasicBlockExecutorProvider, BatchExecutor, BlockExecutorProvider, Executor,
|
||||
@@ -421,23 +410,13 @@ mod tests {
|
||||
|
||||
// attempt to execute a block without parent beacon block root, expect err
|
||||
let err = executor
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders::new_unchecked(
|
||||
Block {
|
||||
header: header.clone(),
|
||||
body: BlockBody {
|
||||
transactions: vec![],
|
||||
ommers: vec![],
|
||||
withdrawals: None,
|
||||
},
|
||||
},
|
||||
vec![],
|
||||
),
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
.execute_and_verify_one(&BlockWithSenders::new_unchecked(
|
||||
Block {
|
||||
header: header.clone(),
|
||||
body: BlockBody { transactions: vec![], ommers: vec![], withdrawals: None },
|
||||
},
|
||||
vec![],
|
||||
))
|
||||
.expect_err(
|
||||
"Executing cancun block without parent beacon block root field should fail",
|
||||
);
|
||||
@@ -452,23 +431,13 @@ mod tests {
|
||||
|
||||
// Now execute a block with the fixed header, ensure that it does not fail
|
||||
executor
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders::new_unchecked(
|
||||
Block {
|
||||
header: header.clone(),
|
||||
body: BlockBody {
|
||||
transactions: vec![],
|
||||
ommers: vec![],
|
||||
withdrawals: None,
|
||||
},
|
||||
},
|
||||
vec![],
|
||||
),
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
.execute_and_verify_one(&BlockWithSenders::new_unchecked(
|
||||
Block {
|
||||
header: header.clone(),
|
||||
body: BlockBody { transactions: vec![], ommers: vec![], withdrawals: None },
|
||||
},
|
||||
vec![],
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// check the actual storage of the contract - it should be:
|
||||
@@ -522,23 +491,13 @@ mod tests {
|
||||
// attempt to execute an empty block with parent beacon block root, this should not fail
|
||||
provider
|
||||
.batch_executor(StateProviderDatabase::new(&db))
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders::new_unchecked(
|
||||
Block {
|
||||
header,
|
||||
body: BlockBody {
|
||||
transactions: vec![],
|
||||
ommers: vec![],
|
||||
withdrawals: None,
|
||||
},
|
||||
},
|
||||
vec![],
|
||||
),
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
.execute_and_verify_one(&BlockWithSenders::new_unchecked(
|
||||
Block {
|
||||
header,
|
||||
body: BlockBody { transactions: vec![], ommers: vec![], withdrawals: None },
|
||||
},
|
||||
vec![],
|
||||
))
|
||||
.expect(
|
||||
"Executing a block with no transactions while cancun is active should not fail",
|
||||
);
|
||||
@@ -576,23 +535,13 @@ mod tests {
|
||||
|
||||
// attempt to execute an empty block with parent beacon block root, this should not fail
|
||||
executor
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders::new_unchecked(
|
||||
Block {
|
||||
header,
|
||||
body: BlockBody {
|
||||
transactions: vec![],
|
||||
ommers: vec![],
|
||||
withdrawals: None,
|
||||
},
|
||||
},
|
||||
vec![],
|
||||
),
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
.execute_and_verify_one(&BlockWithSenders::new_unchecked(
|
||||
Block {
|
||||
header,
|
||||
body: BlockBody { transactions: vec![], ommers: vec![], withdrawals: None },
|
||||
},
|
||||
vec![],
|
||||
))
|
||||
.expect(
|
||||
"Executing a block with no transactions while cancun is active should not fail",
|
||||
);
|
||||
@@ -622,16 +571,10 @@ mod tests {
|
||||
// attempt to execute the genesis block with non-zero parent beacon block root, expect err
|
||||
header.parent_beacon_block_root = Some(B256::with_last_byte(0x69));
|
||||
let _err = executor
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders::new_unchecked(
|
||||
Block { header: header.clone(), body: Default::default() },
|
||||
vec![],
|
||||
),
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
.execute_and_verify_one(&BlockWithSenders::new_unchecked(
|
||||
Block { header: header.clone(), body: Default::default() },
|
||||
vec![],
|
||||
))
|
||||
.expect_err(
|
||||
"Executing genesis cancun block with non-zero parent beacon block root field
|
||||
should fail",
|
||||
@@ -643,16 +586,10 @@ mod tests {
|
||||
// now try to process the genesis block again, this time ensuring that a system contract
|
||||
// call does not occur
|
||||
executor
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders::new_unchecked(
|
||||
Block { header, body: Default::default() },
|
||||
vec![],
|
||||
),
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
.execute_and_verify_one(&BlockWithSenders::new_unchecked(
|
||||
Block { header, body: Default::default() },
|
||||
vec![],
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// there is no system contract call so there should be NO STORAGE CHANGES
|
||||
@@ -697,16 +634,10 @@ mod tests {
|
||||
|
||||
// Now execute a block with the fixed header, ensure that it does not fail
|
||||
executor
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders::new_unchecked(
|
||||
Block { header: header.clone(), body: Default::default() },
|
||||
vec![],
|
||||
),
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
.execute_and_verify_one(&BlockWithSenders::new_unchecked(
|
||||
Block { header: header.clone(), body: Default::default() },
|
||||
vec![],
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// check the actual storage of the contract - it should be:
|
||||
@@ -773,16 +704,10 @@ mod tests {
|
||||
|
||||
// attempt to execute an empty block, this should not fail
|
||||
executor
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders::new_unchecked(
|
||||
Block { header, body: Default::default() },
|
||||
vec![],
|
||||
),
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
.execute_and_verify_one(&BlockWithSenders::new_unchecked(
|
||||
Block { header, body: Default::default() },
|
||||
vec![],
|
||||
))
|
||||
.expect(
|
||||
"Executing a block with no transactions while Prague is active should not fail",
|
||||
);
|
||||
@@ -816,16 +741,10 @@ mod tests {
|
||||
|
||||
// attempt to execute genesis block, this should not fail
|
||||
executor
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders::new_unchecked(
|
||||
Block { header, body: Default::default() },
|
||||
vec![],
|
||||
),
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
.execute_and_verify_one(&BlockWithSenders::new_unchecked(
|
||||
Block { header, body: Default::default() },
|
||||
vec![],
|
||||
))
|
||||
.expect(
|
||||
"Executing a block with no transactions while Prague is active should not fail",
|
||||
);
|
||||
@@ -866,16 +785,10 @@ mod tests {
|
||||
|
||||
// attempt to execute the fork activation block, this should not fail
|
||||
executor
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders::new_unchecked(
|
||||
Block { header, body: Default::default() },
|
||||
vec![],
|
||||
),
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
.execute_and_verify_one(&BlockWithSenders::new_unchecked(
|
||||
Block { header, body: Default::default() },
|
||||
vec![],
|
||||
))
|
||||
.expect(
|
||||
"Executing a block with no transactions while Prague is active should not fail",
|
||||
);
|
||||
@@ -922,16 +835,10 @@ mod tests {
|
||||
|
||||
// attempt to execute the fork activation block, this should not fail
|
||||
executor
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders::new_unchecked(
|
||||
Block { header, body: Default::default() },
|
||||
vec![],
|
||||
),
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
.execute_and_verify_one(&BlockWithSenders::new_unchecked(
|
||||
Block { header, body: Default::default() },
|
||||
vec![],
|
||||
))
|
||||
.expect(
|
||||
"Executing a block with no transactions while Prague is active should not fail",
|
||||
);
|
||||
@@ -970,16 +877,10 @@ mod tests {
|
||||
|
||||
// attempt to execute the genesis block, this should not fail
|
||||
executor
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders::new_unchecked(
|
||||
Block { header, body: Default::default() },
|
||||
vec![],
|
||||
),
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
.execute_and_verify_one(&BlockWithSenders::new_unchecked(
|
||||
Block { header, body: Default::default() },
|
||||
vec![],
|
||||
))
|
||||
.expect(
|
||||
"Executing a block with no transactions while Prague is active should not fail",
|
||||
);
|
||||
@@ -1005,16 +906,10 @@ mod tests {
|
||||
let header_hash = header.hash_slow();
|
||||
|
||||
executor
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders::new_unchecked(
|
||||
Block { header, body: Default::default() },
|
||||
vec![],
|
||||
),
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
.execute_and_verify_one(&BlockWithSenders::new_unchecked(
|
||||
Block { header, body: Default::default() },
|
||||
vec![],
|
||||
))
|
||||
.expect(
|
||||
"Executing a block with no transactions while Prague is active should not fail",
|
||||
);
|
||||
@@ -1043,16 +938,10 @@ mod tests {
|
||||
};
|
||||
|
||||
executor
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders::new_unchecked(
|
||||
Block { header, body: Default::default() },
|
||||
vec![],
|
||||
),
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
.execute_and_verify_one(&BlockWithSenders::new_unchecked(
|
||||
Block { header, body: Default::default() },
|
||||
vec![],
|
||||
))
|
||||
.expect(
|
||||
"Executing a block with no transactions while Prague is active should not fail",
|
||||
);
|
||||
@@ -1133,16 +1022,9 @@ mod tests {
|
||||
|
||||
let BlockExecutionOutput { receipts, requests, .. } = executor
|
||||
.execute(
|
||||
(
|
||||
&Block {
|
||||
header,
|
||||
body: BlockBody { transactions: vec![tx], ..Default::default() },
|
||||
}
|
||||
&Block { header, body: BlockBody { transactions: vec![tx], ..Default::default() } }
|
||||
.with_recovered_senders()
|
||||
.unwrap(),
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -1216,13 +1098,9 @@ mod tests {
|
||||
|
||||
// Execute the block and capture the result
|
||||
let exec_result = executor.execute(
|
||||
(
|
||||
&Block { header, body: BlockBody { transactions: vec![tx], ..Default::default() } }
|
||||
.with_recovered_senders()
|
||||
.unwrap(),
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
&Block { header, body: BlockBody { transactions: vec![tx], ..Default::default() } }
|
||||
.with_recovered_senders()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
// Check if the execution result is an error and assert the specific error type
|
||||
@@ -1282,7 +1160,7 @@ mod tests {
|
||||
let tx_clone = tx.clone();
|
||||
|
||||
let _output = executor
|
||||
.execute_with_state_hook((block, U256::ZERO).into(), move |state: &EvmState| {
|
||||
.execute_with_state_hook(block, move |state: &EvmState| {
|
||||
if let Some(account) = state.get(&withdrawal_recipient) {
|
||||
let _ = tx_clone.send(account.info.balance);
|
||||
}
|
||||
|
||||
@@ -109,19 +109,15 @@ impl ConfigureEvmEnv for EthEvmConfig {
|
||||
env.block.basefee = U256::ZERO;
|
||||
}
|
||||
|
||||
fn fill_cfg_env(
|
||||
&self,
|
||||
cfg_env: &mut CfgEnvWithHandlerCfg,
|
||||
header: &Header,
|
||||
total_difficulty: U256,
|
||||
) {
|
||||
fn fill_cfg_env(&self, cfg_env: &mut CfgEnvWithHandlerCfg, header: &Header) {
|
||||
let spec_id = config::revm_spec(
|
||||
self.chain_spec(),
|
||||
&Head {
|
||||
number: header.number,
|
||||
timestamp: header.timestamp,
|
||||
difficulty: header.difficulty,
|
||||
total_difficulty,
|
||||
// NOTE: this does nothing within revm_spec
|
||||
total_difficulty: U256::MIN,
|
||||
hash: Default::default(),
|
||||
},
|
||||
);
|
||||
@@ -226,14 +222,10 @@ mod tests {
|
||||
.shanghai_activated()
|
||||
.build();
|
||||
|
||||
// Define the total difficulty as zero (default)
|
||||
let total_difficulty = U256::ZERO;
|
||||
|
||||
// Use the `EthEvmConfig` to fill the `cfg_env` and `block_env` based on the ChainSpec,
|
||||
// Header, and total difficulty
|
||||
let EvmEnv { cfg_env_with_handler_cfg, .. } =
|
||||
EthEvmConfig::new(Arc::new(chain_spec.clone()))
|
||||
.cfg_and_block_env(&header, total_difficulty);
|
||||
EthEvmConfig::new(Arc::new(chain_spec.clone())).cfg_and_block_env(&header);
|
||||
|
||||
// Assert that the chain ID in the `cfg_env` is correctly set to the chain ID of the
|
||||
// ChainSpec
|
||||
|
||||
@@ -1,29 +1,6 @@
|
||||
use alloy_eips::eip7685::Requests;
|
||||
use alloy_primitives::U256;
|
||||
use revm::db::BundleState;
|
||||
|
||||
/// A helper type for ethereum block inputs that consists of a block and the total difficulty.
|
||||
#[derive(Debug)]
|
||||
pub struct BlockExecutionInput<'a, Block> {
|
||||
/// The block to execute.
|
||||
pub block: &'a Block,
|
||||
/// The total difficulty of the block.
|
||||
pub total_difficulty: U256,
|
||||
}
|
||||
|
||||
impl<'a, Block> BlockExecutionInput<'a, Block> {
|
||||
/// Creates a new input.
|
||||
pub const fn new(block: &'a Block, total_difficulty: U256) -> Self {
|
||||
Self { block, total_difficulty }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Block> From<(&'a Block, U256)> for BlockExecutionInput<'a, Block> {
|
||||
fn from((block, total_difficulty): (&'a Block, U256)) -> Self {
|
||||
Self::new(block, total_difficulty)
|
||||
}
|
||||
}
|
||||
|
||||
/// The output of an ethereum block.
|
||||
///
|
||||
/// Contains the state changes, transaction receipts, and total gas used in the block.
|
||||
|
||||
@@ -5,7 +5,7 @@ use alloy_consensus::BlockHeader;
|
||||
pub use reth_execution_errors::{
|
||||
BlockExecutionError, BlockValidationError, InternalBlockExecutionError,
|
||||
};
|
||||
pub use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput, ExecutionOutcome};
|
||||
pub use reth_execution_types::{BlockExecutionOutput, ExecutionOutcome};
|
||||
use reth_primitives_traits::Block as _;
|
||||
pub use reth_storage_errors::provider::ProviderError;
|
||||
|
||||
@@ -25,7 +25,7 @@ use revm::{
|
||||
db::{states::bundle_state::BundleRetention, BundleState},
|
||||
State,
|
||||
};
|
||||
use revm_primitives::{db::Database, Account, AccountStatus, EvmState, U256};
|
||||
use revm_primitives::{db::Database, Account, AccountStatus, EvmState};
|
||||
|
||||
/// A general purpose executor trait that executes an input (e.g. block) and produces an output
|
||||
/// (e.g. state changes and receipts).
|
||||
@@ -151,10 +151,7 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static {
|
||||
/// the returned state.
|
||||
type Executor<DB: Database<Error: Into<ProviderError> + Display>>: for<'a> Executor<
|
||||
DB,
|
||||
Input<'a> = BlockExecutionInput<
|
||||
'a,
|
||||
BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
|
||||
>,
|
||||
Input<'a> = &'a BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
|
||||
Output = BlockExecutionOutput<<Self::Primitives as NodePrimitives>::Receipt>,
|
||||
Error = BlockExecutionError,
|
||||
>;
|
||||
@@ -162,10 +159,7 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static {
|
||||
/// An executor that can execute a batch of blocks given a database.
|
||||
type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>>: for<'a> BatchExecutor<
|
||||
DB,
|
||||
Input<'a> = BlockExecutionInput<
|
||||
'a,
|
||||
BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
|
||||
>,
|
||||
Input<'a> = &'a BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
|
||||
Output = ExecutionOutcome<<Self::Primitives as NodePrimitives>::Receipt>,
|
||||
Error = BlockExecutionError,
|
||||
>;
|
||||
@@ -213,21 +207,18 @@ pub trait BlockExecutionStrategy {
|
||||
fn apply_pre_execution_changes(
|
||||
&mut self,
|
||||
block: &BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
|
||||
total_difficulty: U256,
|
||||
) -> Result<(), Self::Error>;
|
||||
|
||||
/// Executes all transactions in the block.
|
||||
fn execute_transactions(
|
||||
&mut self,
|
||||
block: &BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
|
||||
total_difficulty: U256,
|
||||
) -> Result<ExecuteOutput<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>;
|
||||
|
||||
/// Applies any necessary changes after executing the block's transactions.
|
||||
fn apply_post_execution_changes(
|
||||
&mut self,
|
||||
block: &BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
|
||||
total_difficulty: U256,
|
||||
receipts: &[<Self::Primitives as NodePrimitives>::Receipt],
|
||||
) -> Result<Requests, Self::Error>;
|
||||
|
||||
@@ -347,8 +338,7 @@ where
|
||||
S: BlockExecutionStrategy<DB = DB>,
|
||||
DB: Database<Error: Into<ProviderError> + Display>,
|
||||
{
|
||||
type Input<'a> =
|
||||
BlockExecutionInput<'a, BlockWithSenders<<S::Primitives as NodePrimitives>::Block>>;
|
||||
type Input<'a> = &'a BlockWithSenders<<S::Primitives as NodePrimitives>::Block>;
|
||||
type Output = BlockExecutionOutput<<S::Primitives as NodePrimitives>::Receipt>;
|
||||
type Error = S::Error;
|
||||
|
||||
@@ -356,14 +346,10 @@ where
|
||||
self.strategy.init(env_overrides);
|
||||
}
|
||||
|
||||
fn execute(mut self, input: Self::Input<'_>) -> Result<Self::Output, Self::Error> {
|
||||
let BlockExecutionInput { block, total_difficulty } = input;
|
||||
|
||||
self.strategy.apply_pre_execution_changes(block, total_difficulty)?;
|
||||
let ExecuteOutput { receipts, gas_used } =
|
||||
self.strategy.execute_transactions(block, total_difficulty)?;
|
||||
let requests =
|
||||
self.strategy.apply_post_execution_changes(block, total_difficulty, &receipts)?;
|
||||
fn execute(mut self, block: Self::Input<'_>) -> Result<Self::Output, Self::Error> {
|
||||
self.strategy.apply_pre_execution_changes(block)?;
|
||||
let ExecuteOutput { receipts, gas_used } = self.strategy.execute_transactions(block)?;
|
||||
let requests = self.strategy.apply_post_execution_changes(block, &receipts)?;
|
||||
let state = self.strategy.finish();
|
||||
|
||||
Ok(BlockExecutionOutput { state, receipts, requests, gas_used })
|
||||
@@ -371,19 +357,15 @@ where
|
||||
|
||||
fn execute_with_state_closure<F>(
|
||||
mut self,
|
||||
input: Self::Input<'_>,
|
||||
block: Self::Input<'_>,
|
||||
mut state: F,
|
||||
) -> Result<Self::Output, Self::Error>
|
||||
where
|
||||
F: FnMut(&State<DB>),
|
||||
{
|
||||
let BlockExecutionInput { block, total_difficulty } = input;
|
||||
|
||||
self.strategy.apply_pre_execution_changes(block, total_difficulty)?;
|
||||
let ExecuteOutput { receipts, gas_used } =
|
||||
self.strategy.execute_transactions(block, total_difficulty)?;
|
||||
let requests =
|
||||
self.strategy.apply_post_execution_changes(block, total_difficulty, &receipts)?;
|
||||
self.strategy.apply_pre_execution_changes(block)?;
|
||||
let ExecuteOutput { receipts, gas_used } = self.strategy.execute_transactions(block)?;
|
||||
let requests = self.strategy.apply_post_execution_changes(block, &receipts)?;
|
||||
|
||||
state(self.strategy.state_ref());
|
||||
|
||||
@@ -394,21 +376,17 @@ where
|
||||
|
||||
fn execute_with_state_hook<H>(
|
||||
mut self,
|
||||
input: Self::Input<'_>,
|
||||
block: Self::Input<'_>,
|
||||
state_hook: H,
|
||||
) -> Result<Self::Output, Self::Error>
|
||||
where
|
||||
H: OnStateHook + 'static,
|
||||
{
|
||||
let BlockExecutionInput { block, total_difficulty } = input;
|
||||
|
||||
self.strategy.with_state_hook(Some(Box::new(state_hook)));
|
||||
|
||||
self.strategy.apply_pre_execution_changes(block, total_difficulty)?;
|
||||
let ExecuteOutput { receipts, gas_used } =
|
||||
self.strategy.execute_transactions(block, total_difficulty)?;
|
||||
let requests =
|
||||
self.strategy.apply_post_execution_changes(block, total_difficulty, &receipts)?;
|
||||
self.strategy.apply_pre_execution_changes(block)?;
|
||||
let ExecuteOutput { receipts, gas_used } = self.strategy.execute_transactions(block)?;
|
||||
let requests = self.strategy.apply_post_execution_changes(block, &receipts)?;
|
||||
|
||||
let state = self.strategy.finish();
|
||||
|
||||
@@ -447,23 +425,18 @@ where
|
||||
S: BlockExecutionStrategy<DB = DB, Error = BlockExecutionError>,
|
||||
DB: Database<Error: Into<ProviderError> + Display>,
|
||||
{
|
||||
type Input<'a> =
|
||||
BlockExecutionInput<'a, BlockWithSenders<<S::Primitives as NodePrimitives>::Block>>;
|
||||
type Input<'a> = &'a BlockWithSenders<<S::Primitives as NodePrimitives>::Block>;
|
||||
type Output = ExecutionOutcome<<S::Primitives as NodePrimitives>::Receipt>;
|
||||
type Error = BlockExecutionError;
|
||||
|
||||
fn execute_and_verify_one(&mut self, input: Self::Input<'_>) -> Result<(), Self::Error> {
|
||||
let BlockExecutionInput { block, total_difficulty } = input;
|
||||
|
||||
fn execute_and_verify_one(&mut self, block: Self::Input<'_>) -> Result<(), Self::Error> {
|
||||
if self.batch_record.first_block().is_none() {
|
||||
self.batch_record.set_first_block(block.header().number());
|
||||
}
|
||||
|
||||
self.strategy.apply_pre_execution_changes(block, total_difficulty)?;
|
||||
let ExecuteOutput { receipts, .. } =
|
||||
self.strategy.execute_transactions(block, total_difficulty)?;
|
||||
let requests =
|
||||
self.strategy.apply_post_execution_changes(block, total_difficulty, &receipts)?;
|
||||
self.strategy.apply_pre_execution_changes(block)?;
|
||||
let ExecuteOutput { receipts, .. } = self.strategy.execute_transactions(block)?;
|
||||
let requests = self.strategy.apply_post_execution_changes(block, &receipts)?;
|
||||
|
||||
self.strategy.validate_block_post_execution(block, &receipts, &requests)?;
|
||||
|
||||
@@ -575,7 +548,7 @@ mod tests {
|
||||
struct TestExecutor<DB>(PhantomData<DB>);
|
||||
|
||||
impl<DB> Executor<DB> for TestExecutor<DB> {
|
||||
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
|
||||
type Input<'a> = &'a BlockWithSenders;
|
||||
type Output = BlockExecutionOutput<Receipt>;
|
||||
type Error = BlockExecutionError;
|
||||
|
||||
@@ -607,7 +580,7 @@ mod tests {
|
||||
}
|
||||
|
||||
impl<DB> BatchExecutor<DB> for TestExecutor<DB> {
|
||||
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
|
||||
type Input<'a> = &'a BlockWithSenders;
|
||||
type Output = ExecutionOutcome;
|
||||
type Error = BlockExecutionError;
|
||||
|
||||
@@ -689,7 +662,6 @@ mod tests {
|
||||
fn apply_pre_execution_changes(
|
||||
&mut self,
|
||||
_block: &BlockWithSenders,
|
||||
_total_difficulty: U256,
|
||||
) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
@@ -697,7 +669,6 @@ mod tests {
|
||||
fn execute_transactions(
|
||||
&mut self,
|
||||
_block: &BlockWithSenders,
|
||||
_total_difficulty: U256,
|
||||
) -> Result<ExecuteOutput<Receipt>, Self::Error> {
|
||||
Ok(self.execute_transactions_result.clone())
|
||||
}
|
||||
@@ -705,7 +676,6 @@ mod tests {
|
||||
fn apply_post_execution_changes(
|
||||
&mut self,
|
||||
_block: &BlockWithSenders,
|
||||
_total_difficulty: U256,
|
||||
_receipts: &[Receipt],
|
||||
) -> Result<Requests, Self::Error> {
|
||||
Ok(self.apply_post_execution_changes_result.clone())
|
||||
@@ -743,7 +713,7 @@ mod tests {
|
||||
let provider = TestExecutorProvider;
|
||||
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
|
||||
let executor = provider.executor(db);
|
||||
let _ = executor.execute(BlockExecutionInput::new(&Default::default(), U256::ZERO));
|
||||
let _ = executor.execute(&Default::default());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -766,7 +736,7 @@ mod tests {
|
||||
let provider = BasicBlockExecutorProvider::new(strategy_factory);
|
||||
let db = CacheDB::<EmptyDBTyped<ProviderError>>::default();
|
||||
let executor = provider.executor(db);
|
||||
let result = executor.execute(BlockExecutionInput::new(&Default::default(), U256::ZERO));
|
||||
let result = executor.execute(&Default::default());
|
||||
|
||||
assert!(result.is_ok());
|
||||
let block_execution_output = result.unwrap();
|
||||
@@ -792,11 +762,10 @@ mod tests {
|
||||
// if we want to apply tx env overrides the executor must be mut.
|
||||
let mut executor = provider.executor(db);
|
||||
// execute consumes the executor, so we can only call it once.
|
||||
// let result = executor.execute(BlockExecutionInput::new(&Default::default(), U256::ZERO));
|
||||
executor.init(Box::new(|tx_env: &mut TxEnv| {
|
||||
tx_env.nonce.take();
|
||||
}));
|
||||
let result = executor.execute(BlockExecutionInput::new(&Default::default(), U256::ZERO));
|
||||
let result = executor.execute(&Default::default());
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
||||
|
||||
@@ -145,9 +145,9 @@ pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static {
|
||||
);
|
||||
|
||||
/// Returns a [`CfgEnvWithHandlerCfg`] for the given header.
|
||||
fn cfg_env(&self, header: &Self::Header, total_difficulty: U256) -> CfgEnvWithHandlerCfg {
|
||||
fn cfg_env(&self, header: &Self::Header) -> CfgEnvWithHandlerCfg {
|
||||
let mut cfg = CfgEnvWithHandlerCfg::new(Default::default(), Default::default());
|
||||
self.fill_cfg_env(&mut cfg, header, total_difficulty);
|
||||
self.fill_cfg_env(&mut cfg, header);
|
||||
cfg
|
||||
}
|
||||
|
||||
@@ -155,12 +155,7 @@ pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static {
|
||||
///
|
||||
/// This __must__ set the corresponding spec id in the handler cfg, based on timestamp or total
|
||||
/// difficulty
|
||||
fn fill_cfg_env(
|
||||
&self,
|
||||
cfg_env: &mut CfgEnvWithHandlerCfg,
|
||||
header: &Self::Header,
|
||||
total_difficulty: U256,
|
||||
);
|
||||
fn fill_cfg_env(&self, cfg_env: &mut CfgEnvWithHandlerCfg, header: &Self::Header);
|
||||
|
||||
/// Fill [`BlockEnv`] field according to the chain spec and given header
|
||||
fn fill_block_env(&self, block_env: &mut BlockEnv, header: &Self::Header, after_merge: bool) {
|
||||
@@ -184,10 +179,10 @@ pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static {
|
||||
}
|
||||
|
||||
/// Creates a new [`EvmEnv`] for the given header.
|
||||
fn cfg_and_block_env(&self, header: &Self::Header, total_difficulty: U256) -> EvmEnv {
|
||||
fn cfg_and_block_env(&self, header: &Self::Header) -> EvmEnv {
|
||||
let mut cfg = CfgEnvWithHandlerCfg::new(Default::default(), Default::default());
|
||||
let mut block_env = BlockEnv::default();
|
||||
self.fill_cfg_and_block_env(&mut cfg, &mut block_env, header, total_difficulty);
|
||||
self.fill_cfg_and_block_env(&mut cfg, &mut block_env, header);
|
||||
EvmEnv::new(cfg, block_env)
|
||||
}
|
||||
|
||||
@@ -200,9 +195,8 @@ pub trait ConfigureEvmEnv: Send + Sync + Unpin + Clone + 'static {
|
||||
cfg: &mut CfgEnvWithHandlerCfg,
|
||||
block_env: &mut BlockEnv,
|
||||
header: &Self::Header,
|
||||
total_difficulty: U256,
|
||||
) {
|
||||
self.fill_cfg_env(cfg, header, total_difficulty);
|
||||
self.fill_cfg_env(cfg, header);
|
||||
let after_merge = cfg.handler_cfg.spec_id >= SpecId::MERGE;
|
||||
self.fill_block_env(block_env, header, after_merge);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
use crate::{execute::Executor, system_calls::OnStateHook};
|
||||
use alloy_consensus::BlockHeader;
|
||||
use metrics::{Counter, Gauge, Histogram};
|
||||
use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput};
|
||||
use reth_execution_types::BlockExecutionOutput;
|
||||
use reth_metrics::Metrics;
|
||||
use reth_primitives::BlockWithSenders;
|
||||
use revm_primitives::EvmState;
|
||||
@@ -97,13 +97,13 @@ impl ExecutorMetrics {
|
||||
pub fn execute_metered<'a, E, DB, O, Error, B>(
|
||||
&self,
|
||||
executor: E,
|
||||
input: BlockExecutionInput<'a, BlockWithSenders<B>>,
|
||||
input: &'a BlockWithSenders<B>,
|
||||
state_hook: Box<dyn OnStateHook>,
|
||||
) -> Result<BlockExecutionOutput<O>, Error>
|
||||
where
|
||||
E: Executor<
|
||||
DB,
|
||||
Input<'a> = BlockExecutionInput<'a, BlockWithSenders<B>>,
|
||||
Input<'a> = &'a BlockWithSenders<B>,
|
||||
Output = BlockExecutionOutput<O>,
|
||||
Error = Error,
|
||||
>,
|
||||
@@ -114,11 +114,8 @@ impl ExecutorMetrics {
|
||||
// be accessible.
|
||||
let wrapper = MeteredStateHook { metrics: self.clone(), inner_hook: state_hook };
|
||||
|
||||
// Store reference to block for metered
|
||||
let block = input.block;
|
||||
|
||||
// Use metered to execute and track timing/gas metrics
|
||||
let output = self.metered(block, || executor.execute_with_state_hook(input, wrapper))?;
|
||||
let output = self.metered(input, || executor.execute_with_state_hook(input, wrapper))?;
|
||||
|
||||
// Update the metrics for the number of accounts, storage slots and bytecodes updated
|
||||
let accounts = output.state.state.len();
|
||||
@@ -134,16 +131,12 @@ impl ExecutorMetrics {
|
||||
}
|
||||
|
||||
/// Execute the given block and update metrics for the execution.
|
||||
pub fn metered_one<F, R, B>(
|
||||
&self,
|
||||
input: BlockExecutionInput<'_, BlockWithSenders<B>>,
|
||||
f: F,
|
||||
) -> R
|
||||
pub fn metered_one<F, R, B>(&self, input: &BlockWithSenders<B>, f: F) -> R
|
||||
where
|
||||
F: FnOnce(BlockExecutionInput<'_, BlockWithSenders<B>>) -> R,
|
||||
F: FnOnce(&BlockWithSenders<B>) -> R,
|
||||
B: reth_primitives_traits::Block,
|
||||
{
|
||||
self.metered(input.block, || f(input))
|
||||
self.metered(input, || f(input))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +158,7 @@ mod tests {
|
||||
|
||||
impl Executor<()> for MockExecutor {
|
||||
type Input<'a>
|
||||
= BlockExecutionInput<'a, BlockWithSenders>
|
||||
= &'a BlockWithSenders
|
||||
where
|
||||
Self: 'a;
|
||||
type Output = BlockExecutionOutput<()>;
|
||||
@@ -236,11 +229,7 @@ mod tests {
|
||||
fn test_executor_metrics_hook_metrics_recorded() {
|
||||
let snapshotter = setup_test_recorder();
|
||||
let metrics = ExecutorMetrics::default();
|
||||
|
||||
let input = BlockExecutionInput {
|
||||
block: &BlockWithSenders::default(),
|
||||
total_difficulty: Default::default(),
|
||||
};
|
||||
let input = BlockWithSenders::default();
|
||||
|
||||
let (tx, _rx) = mpsc::channel();
|
||||
let expected_output = 42;
|
||||
@@ -266,7 +255,7 @@ mod tests {
|
||||
state
|
||||
};
|
||||
let executor = MockExecutor { state };
|
||||
let _result = metrics.execute_metered(executor, input, state_hook).unwrap();
|
||||
let _result = metrics.execute_metered(executor, &input, state_hook).unwrap();
|
||||
|
||||
let snapshot = snapshotter.snapshot().into_vec();
|
||||
|
||||
@@ -289,11 +278,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_executor_metrics_hook_called() {
|
||||
let metrics = ExecutorMetrics::default();
|
||||
|
||||
let input = BlockExecutionInput {
|
||||
block: &BlockWithSenders::default(),
|
||||
total_difficulty: Default::default(),
|
||||
};
|
||||
let input = BlockWithSenders::default();
|
||||
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let expected_output = 42;
|
||||
@@ -302,7 +287,7 @@ mod tests {
|
||||
let state = EvmState::default();
|
||||
|
||||
let executor = MockExecutor { state };
|
||||
let _result = metrics.execute_metered(executor, input, state_hook).unwrap();
|
||||
let _result = metrics.execute_metered(executor, &input, state_hook).unwrap();
|
||||
|
||||
let actual_output = rx.try_recv().unwrap();
|
||||
assert_eq!(actual_output, expected_output);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use alloy_primitives::BlockNumber;
|
||||
use core::fmt::Display;
|
||||
use reth_execution_errors::BlockExecutionError;
|
||||
use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput, ExecutionOutcome};
|
||||
use reth_execution_types::{BlockExecutionOutput, ExecutionOutcome};
|
||||
use reth_primitives::{BlockWithSenders, NodePrimitives};
|
||||
use reth_prune_types::PruneModes;
|
||||
use reth_storage_errors::provider::ProviderError;
|
||||
@@ -45,7 +45,7 @@ impl<P: NodePrimitives> BlockExecutorProvider for NoopBlockExecutorProvider<P> {
|
||||
}
|
||||
|
||||
impl<DB, P: NodePrimitives> Executor<DB> for NoopBlockExecutorProvider<P> {
|
||||
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders<P::Block>>;
|
||||
type Input<'a> = &'a BlockWithSenders<P::Block>;
|
||||
type Output = BlockExecutionOutput<P::Receipt>;
|
||||
type Error = BlockExecutionError;
|
||||
|
||||
@@ -77,7 +77,7 @@ impl<DB, P: NodePrimitives> Executor<DB> for NoopBlockExecutorProvider<P> {
|
||||
}
|
||||
|
||||
impl<DB, P: NodePrimitives> BatchExecutor<DB> for NoopBlockExecutorProvider<P> {
|
||||
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders<P::Block>>;
|
||||
type Input<'a> = &'a BlockWithSenders<P::Block>;
|
||||
type Output = ExecutionOutcome<P::Receipt>;
|
||||
type Error = BlockExecutionError;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use alloy_consensus::BlockHeader;
|
||||
use alloy_eips::eip4895::Withdrawal;
|
||||
use alloy_primitives::{map::HashMap, Address, U256};
|
||||
use alloy_primitives::{map::HashMap, Address};
|
||||
use reth_chainspec::EthereumHardforks;
|
||||
use reth_consensus_common::calc;
|
||||
use reth_primitives_traits::BlockBody;
|
||||
@@ -15,7 +15,6 @@ use reth_primitives_traits::BlockBody;
|
||||
pub fn post_block_balance_increments<ChainSpec, Block>(
|
||||
chain_spec: &ChainSpec,
|
||||
block: &Block,
|
||||
total_difficulty: U256,
|
||||
) -> HashMap<Address, u128>
|
||||
where
|
||||
ChainSpec: EthereumHardforks,
|
||||
@@ -24,12 +23,7 @@ where
|
||||
let mut balance_increments = HashMap::default();
|
||||
|
||||
// Add block rewards if they are enabled.
|
||||
if let Some(base_block_reward) = calc::base_block_reward(
|
||||
chain_spec,
|
||||
block.header().number(),
|
||||
block.header().difficulty(),
|
||||
total_difficulty,
|
||||
) {
|
||||
if let Some(base_block_reward) = calc::base_block_reward(chain_spec, block.header().number()) {
|
||||
// Ommer rewards
|
||||
if let Some(ommers) = block.body().ommers() {
|
||||
for ommer in ommers {
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
use crate::{
|
||||
env::EvmEnv,
|
||||
execute::{
|
||||
BasicBatchExecutor, BasicBlockExecutor, BatchExecutor, BlockExecutionInput,
|
||||
BlockExecutionOutput, BlockExecutionStrategy, BlockExecutorProvider, Executor,
|
||||
BasicBatchExecutor, BasicBlockExecutor, BatchExecutor, BlockExecutionOutput,
|
||||
BlockExecutionStrategy, BlockExecutorProvider, Executor,
|
||||
},
|
||||
provider::EvmEnvProvider,
|
||||
system_calls::OnStateHook,
|
||||
ConfigureEvmEnv,
|
||||
};
|
||||
use alloy_eips::eip7685::Requests;
|
||||
use alloy_primitives::{BlockNumber, U256};
|
||||
use alloy_primitives::BlockNumber;
|
||||
use parking_lot::Mutex;
|
||||
use reth_execution_errors::BlockExecutionError;
|
||||
use reth_execution_types::ExecutionOutcome;
|
||||
@@ -33,7 +33,7 @@ impl<C: Send + Sync, N: NodePrimitives> EvmEnvProvider<N::BlockHeader>
|
||||
where
|
||||
EvmConfig: ConfigureEvmEnv<Header = N::BlockHeader>,
|
||||
{
|
||||
Ok(evm_config.cfg_and_block_env(header, U256::MAX))
|
||||
Ok(evm_config.cfg_and_block_env(header))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ impl BlockExecutorProvider for MockExecutorProvider {
|
||||
}
|
||||
|
||||
impl<DB> Executor<DB> for MockExecutorProvider {
|
||||
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
|
||||
type Input<'a> = &'a BlockWithSenders;
|
||||
type Output = BlockExecutionOutput<Receipt>;
|
||||
type Error = BlockExecutionError;
|
||||
|
||||
@@ -115,7 +115,7 @@ impl<DB> Executor<DB> for MockExecutorProvider {
|
||||
}
|
||||
|
||||
impl<DB> BatchExecutor<DB> for MockExecutorProvider {
|
||||
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
|
||||
type Input<'a> = &'a BlockWithSenders;
|
||||
type Output = ExecutionOutcome;
|
||||
type Error = BlockExecutionError;
|
||||
|
||||
|
||||
@@ -90,11 +90,6 @@ where
|
||||
// Fetch the block
|
||||
let fetch_block_start = Instant::now();
|
||||
|
||||
let td = self
|
||||
.provider
|
||||
.header_td_by_number(block_number)?
|
||||
.ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?;
|
||||
|
||||
// we need the block's transactions along with their hashes
|
||||
let block = self
|
||||
.provider
|
||||
@@ -116,7 +111,7 @@ where
|
||||
let (unsealed_header, hash) = block.header.split();
|
||||
let block = P::Block::new(unsealed_header, block.body).with_senders_unchecked(senders);
|
||||
|
||||
executor.execute_and_verify_one((&block, td).into())?;
|
||||
executor.execute_and_verify_one(&block)?;
|
||||
execution_duration += execute_start.elapsed();
|
||||
|
||||
// TODO(alexey): report gas metrics using `block.header.gas_used`
|
||||
@@ -199,11 +194,6 @@ where
|
||||
BlockWithSenders<P::Block>,
|
||||
BlockExecutionOutput<<E::Primitives as NodePrimitives>::Receipt>,
|
||||
)> {
|
||||
let td = self
|
||||
.provider
|
||||
.header_td_by_number(block_number)?
|
||||
.ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?;
|
||||
|
||||
// Fetch the block with senders for execution.
|
||||
let block_with_senders = self
|
||||
.provider
|
||||
@@ -217,7 +207,7 @@ where
|
||||
|
||||
trace!(target: "exex::backfill", number = block_number, txs = block_with_senders.block.body().transactions().len(), "Executing block");
|
||||
|
||||
let block_execution_output = executor.execute((&block_with_senders, td).into())?;
|
||||
let block_execution_output = executor.execute(&block_with_senders)?;
|
||||
|
||||
Ok((block_with_senders, block_execution_output))
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ use alloy_genesis::{Genesis, GenesisAccount};
|
||||
use alloy_primitives::{b256, Address, TxKind, U256};
|
||||
use eyre::OptionExt;
|
||||
use reth_chainspec::{ChainSpec, ChainSpecBuilder, EthereumHardfork, MAINNET, MIN_TRANSACTION_GAS};
|
||||
use reth_evm::execute::{
|
||||
BatchExecutor, BlockExecutionInput, BlockExecutionOutput, BlockExecutorProvider, Executor,
|
||||
};
|
||||
use reth_evm::execute::{BatchExecutor, BlockExecutionOutput, BlockExecutorProvider, Executor};
|
||||
use reth_evm_ethereum::execute::EthExecutorProvider;
|
||||
use reth_node_api::FullNodePrimitives;
|
||||
use reth_primitives::{
|
||||
@@ -71,7 +69,7 @@ where
|
||||
// Execute the block to produce a block execution output
|
||||
let mut block_execution_output = EthExecutorProvider::ethereum(chain_spec)
|
||||
.executor(StateProviderDatabase::new(LatestStateProviderRef::new(&provider)))
|
||||
.execute(BlockExecutionInput { block, total_difficulty: U256::ZERO })?;
|
||||
.execute(block)?;
|
||||
block_execution_output.state.reverts.sort();
|
||||
|
||||
// Convert the block execution output to an execution outcome for committing to the database
|
||||
@@ -206,10 +204,7 @@ where
|
||||
let executor = EthExecutorProvider::ethereum(chain_spec)
|
||||
.batch_executor(StateProviderDatabase::new(LatestStateProviderRef::new(&provider)));
|
||||
|
||||
let mut execution_outcome = executor.execute_and_verify_batch(vec![
|
||||
(&block1, U256::ZERO).into(),
|
||||
(&block2, U256::ZERO).into(),
|
||||
])?;
|
||||
let mut execution_outcome = executor.execute_and_verify_batch(vec![&block1, &block2])?;
|
||||
execution_outcome.state_mut().reverts.sort();
|
||||
|
||||
let block1 = block1.seal_slow();
|
||||
|
||||
@@ -355,21 +355,15 @@ impl From<Genesis> for OpChainSpec {
|
||||
.filter_map(|(hardfork, opt)| opt.map(|block| (hardfork, ForkCondition::Block(block))))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Paris
|
||||
let paris_block_and_final_difficulty =
|
||||
if let Some(ttd) = genesis.config.terminal_total_difficulty {
|
||||
block_hardforks.push((
|
||||
EthereumHardfork::Paris.boxed(),
|
||||
ForkCondition::TTD {
|
||||
total_difficulty: ttd,
|
||||
fork_block: genesis.config.merge_netsplit_block,
|
||||
},
|
||||
));
|
||||
|
||||
genesis.config.merge_netsplit_block.map(|block| (block, ttd))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// We set the paris hardfork for OP networks to zero
|
||||
block_hardforks.push((
|
||||
EthereumHardfork::Paris.boxed(),
|
||||
ForkCondition::TTD {
|
||||
activation_block_number: 0,
|
||||
total_difficulty: U256::ZERO,
|
||||
fork_block: genesis.config.merge_netsplit_block,
|
||||
},
|
||||
));
|
||||
|
||||
// Time-based hardforks
|
||||
let time_hardfork_opts = [
|
||||
@@ -413,7 +407,9 @@ impl From<Genesis> for OpChainSpec {
|
||||
chain: genesis.config.chain_id.into(),
|
||||
genesis,
|
||||
hardforks: ChainHardforks::new(ordered_hardforks),
|
||||
paris_block_and_final_difficulty,
|
||||
// We assume no OP network merges, and set the paris block and total difficulty to
|
||||
// zero
|
||||
paris_block_and_final_difficulty: Some((0, U256::ZERO)),
|
||||
base_fee_params: optimism_genesis_info.base_fee_params,
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1006,10 +1002,10 @@ mod tests {
|
||||
// OpHardfork::Isthmus.boxed(),
|
||||
];
|
||||
|
||||
assert!(expected_hardforks
|
||||
.iter()
|
||||
.zip(hardforks.iter())
|
||||
.all(|(expected, actual)| &**expected == *actual));
|
||||
for (expected, actual) in expected_hardforks.iter().zip(hardforks.iter()) {
|
||||
println!("got {expected:?}, {actual:?}");
|
||||
assert_eq!(&**expected, &**actual);
|
||||
}
|
||||
assert_eq!(expected_hardforks.len(), hardforks.len());
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ use reth_optimism_forks::OpHardfork;
|
||||
use reth_optimism_primitives::OpPrimitives;
|
||||
use reth_primitives::{BlockWithSenders, Receipt, TransactionSigned, TxType};
|
||||
use reth_revm::{Database, State};
|
||||
use revm_primitives::{db::DatabaseCommit, EnvWithHandlerCfg, ResultAndState, U256};
|
||||
use revm_primitives::{db::DatabaseCommit, EnvWithHandlerCfg, ResultAndState};
|
||||
use tracing::trace;
|
||||
|
||||
/// Factory for [`OpExecutionStrategy`].
|
||||
@@ -111,8 +111,8 @@ where
|
||||
/// Configures a new evm configuration and block environment for the given block.
|
||||
///
|
||||
/// Caution: this does not initialize the tx environment.
|
||||
fn evm_env_for_block(&self, header: &Header, total_difficulty: U256) -> EnvWithHandlerCfg {
|
||||
let evm_env = self.evm_config.cfg_and_block_env(header, total_difficulty);
|
||||
fn evm_env_for_block(&self, header: &Header) -> EnvWithHandlerCfg {
|
||||
let evm_env = self.evm_config.cfg_and_block_env(header);
|
||||
let EvmEnv { cfg_env_with_handler_cfg, block_env } = evm_env;
|
||||
EnvWithHandlerCfg::new_with_cfg_env(cfg_env_with_handler_cfg, block_env, Default::default())
|
||||
}
|
||||
@@ -131,17 +131,13 @@ where
|
||||
self.tx_env_overrides = Some(tx_env_overrides);
|
||||
}
|
||||
|
||||
fn apply_pre_execution_changes(
|
||||
&mut self,
|
||||
block: &BlockWithSenders,
|
||||
total_difficulty: U256,
|
||||
) -> Result<(), Self::Error> {
|
||||
fn apply_pre_execution_changes(&mut self, block: &BlockWithSenders) -> Result<(), Self::Error> {
|
||||
// Set state clear flag if the block is after the Spurious Dragon hardfork.
|
||||
let state_clear_flag =
|
||||
(*self.chain_spec).is_spurious_dragon_active_at_block(block.header.number);
|
||||
self.state.set_state_clear_flag(state_clear_flag);
|
||||
|
||||
let env = self.evm_env_for_block(&block.header, total_difficulty);
|
||||
let env = self.evm_env_for_block(&block.header);
|
||||
let mut evm = self.evm_config.evm_with_env(&mut self.state, env);
|
||||
|
||||
self.system_caller.apply_beacon_root_contract_call(
|
||||
@@ -164,9 +160,8 @@ where
|
||||
fn execute_transactions(
|
||||
&mut self,
|
||||
block: &BlockWithSenders,
|
||||
total_difficulty: U256,
|
||||
) -> Result<ExecuteOutput<Receipt>, Self::Error> {
|
||||
let env = self.evm_env_for_block(&block.header, total_difficulty);
|
||||
let env = self.evm_env_for_block(&block.header);
|
||||
let mut evm = self.evm_config.evm_with_env(&mut self.state, env);
|
||||
|
||||
let is_regolith =
|
||||
@@ -260,11 +255,10 @@ where
|
||||
fn apply_post_execution_changes(
|
||||
&mut self,
|
||||
block: &BlockWithSenders,
|
||||
total_difficulty: U256,
|
||||
_receipts: &[Receipt],
|
||||
) -> Result<Requests, Self::Error> {
|
||||
let balance_increments =
|
||||
post_block_balance_increments(&self.chain_spec.clone(), &block.block, total_difficulty);
|
||||
post_block_balance_increments(&self.chain_spec.clone(), &block.block);
|
||||
// increment balances
|
||||
self.state
|
||||
.increment_balances(balance_increments.clone())
|
||||
@@ -317,7 +311,7 @@ mod tests {
|
||||
use crate::OpChainSpec;
|
||||
use alloy_consensus::TxEip1559;
|
||||
use alloy_primitives::{
|
||||
b256, Address, PrimitiveSignature as Signature, StorageKey, StorageValue,
|
||||
b256, Address, PrimitiveSignature as Signature, StorageKey, StorageValue, U256,
|
||||
};
|
||||
use op_alloy_consensus::TxDeposit;
|
||||
use reth_chainspec::MIN_TRANSACTION_GAS;
|
||||
@@ -417,22 +411,13 @@ mod tests {
|
||||
|
||||
// Attempt to execute a block with one deposit and one non-deposit transaction
|
||||
executor
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders {
|
||||
block: Block {
|
||||
header,
|
||||
body: BlockBody {
|
||||
transactions: vec![tx, tx_deposit],
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
senders: vec![addr, addr],
|
||||
},
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
.execute_and_verify_one(&BlockWithSenders {
|
||||
block: Block {
|
||||
header,
|
||||
body: BlockBody { transactions: vec![tx, tx_deposit], ..Default::default() },
|
||||
},
|
||||
senders: vec![addr, addr],
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let receipts = executor.receipts();
|
||||
@@ -501,22 +486,13 @@ mod tests {
|
||||
|
||||
// attempt to execute an empty block with parent beacon block root, this should not fail
|
||||
executor
|
||||
.execute_and_verify_one(
|
||||
(
|
||||
&BlockWithSenders {
|
||||
block: Block {
|
||||
header,
|
||||
body: BlockBody {
|
||||
transactions: vec![tx, tx_deposit],
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
senders: vec![addr, addr],
|
||||
},
|
||||
U256::ZERO,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
.execute_and_verify_one(&BlockWithSenders {
|
||||
block: Block {
|
||||
header,
|
||||
body: BlockBody { transactions: vec![tx, tx_deposit], ..Default::default() },
|
||||
},
|
||||
senders: vec![addr, addr],
|
||||
})
|
||||
.expect("Executing a block while canyon is active should not fail");
|
||||
|
||||
let receipts = executor.receipts();
|
||||
|
||||
@@ -110,19 +110,16 @@ impl ConfigureEvmEnv for OpEvmConfig {
|
||||
env.block.basefee = U256::ZERO;
|
||||
}
|
||||
|
||||
fn fill_cfg_env(
|
||||
&self,
|
||||
cfg_env: &mut CfgEnvWithHandlerCfg,
|
||||
header: &Self::Header,
|
||||
total_difficulty: U256,
|
||||
) {
|
||||
fn fill_cfg_env(&self, cfg_env: &mut CfgEnvWithHandlerCfg, header: &Self::Header) {
|
||||
let spec_id = revm_spec(
|
||||
self.chain_spec(),
|
||||
&Head {
|
||||
number: header.number,
|
||||
timestamp: header.timestamp,
|
||||
difficulty: header.difficulty,
|
||||
total_difficulty,
|
||||
// NOTE: this does not matter within revm_spec as it uses paris hardfork block
|
||||
// activation
|
||||
total_difficulty: U256::MIN,
|
||||
hash: Default::default(),
|
||||
},
|
||||
);
|
||||
@@ -246,14 +243,11 @@ mod tests {
|
||||
.shanghai_activated()
|
||||
.build();
|
||||
|
||||
// Define the total difficulty as zero (default)
|
||||
let total_difficulty = U256::ZERO;
|
||||
|
||||
// Use the `OpEvmConfig` to create the `cfg_env` and `block_env` based on the ChainSpec,
|
||||
// Header, and total difficulty
|
||||
let EvmEnv { cfg_env_with_handler_cfg, .. } =
|
||||
OpEvmConfig::new(Arc::new(OpChainSpec { inner: chain_spec.clone() }))
|
||||
.cfg_and_block_env(&header, total_difficulty);
|
||||
.cfg_and_block_env(&header);
|
||||
|
||||
// Assert that the chain ID in the `cfg_env` is correctly set to the chain ID of the
|
||||
// ChainSpec
|
||||
|
||||
@@ -23,7 +23,11 @@ pub static DEV_HARDFORKS: LazyLock<ChainHardforks> = LazyLock::new(|| {
|
||||
(EthereumHardfork::London.boxed(), ForkCondition::Block(0)),
|
||||
(
|
||||
EthereumHardfork::Paris.boxed(),
|
||||
ForkCondition::TTD { fork_block: None, total_difficulty: U256::ZERO },
|
||||
ForkCondition::TTD {
|
||||
activation_block_number: 0,
|
||||
fork_block: None,
|
||||
total_difficulty: U256::ZERO,
|
||||
},
|
||||
),
|
||||
(crate::OpHardfork::Bedrock.boxed(), ForkCondition::Block(0)),
|
||||
(crate::OpHardfork::Regolith.boxed(), ForkCondition::Timestamp(0)),
|
||||
|
||||
@@ -220,7 +220,11 @@ impl OpHardfork {
|
||||
(EthereumHardfork::GrayGlacier.boxed(), ForkCondition::Block(105235063)),
|
||||
(
|
||||
EthereumHardfork::Paris.boxed(),
|
||||
ForkCondition::TTD { fork_block: Some(105235063), total_difficulty: U256::ZERO },
|
||||
ForkCondition::TTD {
|
||||
activation_block_number: 105235063,
|
||||
fork_block: Some(105235063),
|
||||
total_difficulty: U256::ZERO,
|
||||
},
|
||||
),
|
||||
(Self::Bedrock.boxed(), ForkCondition::Block(105235063)),
|
||||
(Self::Regolith.boxed(), ForkCondition::Timestamp(0)),
|
||||
@@ -252,7 +256,11 @@ impl OpHardfork {
|
||||
(EthereumHardfork::GrayGlacier.boxed(), ForkCondition::Block(0)),
|
||||
(
|
||||
EthereumHardfork::Paris.boxed(),
|
||||
ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO },
|
||||
ForkCondition::TTD {
|
||||
activation_block_number: 0,
|
||||
fork_block: Some(0),
|
||||
total_difficulty: U256::ZERO,
|
||||
},
|
||||
),
|
||||
(Self::Bedrock.boxed(), ForkCondition::Block(0)),
|
||||
(Self::Regolith.boxed(), ForkCondition::Timestamp(0)),
|
||||
@@ -284,7 +292,11 @@ impl OpHardfork {
|
||||
(EthereumHardfork::GrayGlacier.boxed(), ForkCondition::Block(0)),
|
||||
(
|
||||
EthereumHardfork::Paris.boxed(),
|
||||
ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO },
|
||||
ForkCondition::TTD {
|
||||
activation_block_number: 0,
|
||||
fork_block: Some(0),
|
||||
total_difficulty: U256::ZERO,
|
||||
},
|
||||
),
|
||||
(Self::Bedrock.boxed(), ForkCondition::Block(0)),
|
||||
(Self::Regolith.boxed(), ForkCondition::Timestamp(0)),
|
||||
@@ -316,7 +328,11 @@ impl OpHardfork {
|
||||
(EthereumHardfork::GrayGlacier.boxed(), ForkCondition::Block(0)),
|
||||
(
|
||||
EthereumHardfork::Paris.boxed(),
|
||||
ForkCondition::TTD { fork_block: Some(0), total_difficulty: U256::ZERO },
|
||||
ForkCondition::TTD {
|
||||
activation_block_number: 0,
|
||||
fork_block: Some(0),
|
||||
total_difficulty: U256::ZERO,
|
||||
},
|
||||
),
|
||||
(Self::Bedrock.boxed(), ForkCondition::Block(0)),
|
||||
(Self::Regolith.boxed(), ForkCondition::Timestamp(0)),
|
||||
|
||||
@@ -641,12 +641,9 @@ where
|
||||
let mut witness_record = ExecutionWitnessRecord::default();
|
||||
|
||||
let _ = block_executor
|
||||
.execute_with_state_closure(
|
||||
(&(*block).clone().unseal(), block.difficulty()).into(),
|
||||
|statedb: &State<_>| {
|
||||
witness_record.record_executed_state(statedb);
|
||||
},
|
||||
)
|
||||
.execute_with_state_closure(&(*block).clone().unseal(), |statedb: &State<_>| {
|
||||
witness_record.record_executed_state(statedb);
|
||||
})
|
||||
.map_err(|err| EthApiError::Internal(err.into()))?;
|
||||
|
||||
let ExecutionWitnessRecord { hashed_state, codes, keys } = witness_record;
|
||||
|
||||
@@ -14,13 +14,11 @@ use alloy_rpc_types_trace::{
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use jsonrpsee::core::RpcResult;
|
||||
use reth_chainspec::EthereumHardforks;
|
||||
use reth_consensus_common::calc::{
|
||||
base_block_reward, base_block_reward_pre_merge, block_reward, ommer_reward,
|
||||
};
|
||||
use reth_chainspec::{EthChainSpec, EthereumHardfork, MAINNET, SEPOLIA};
|
||||
use reth_consensus_common::calc::{base_block_reward_pre_merge, block_reward, ommer_reward};
|
||||
use reth_evm::{env::EvmEnv, ConfigureEvmEnv};
|
||||
use reth_primitives_traits::{BlockBody, BlockHeader};
|
||||
use reth_provider::{BlockNumReader, BlockReader, ChainSpecProvider, HeaderProvider};
|
||||
use reth_provider::{BlockNumReader, BlockReader, ChainSpecProvider};
|
||||
use reth_revm::database::StateProviderDatabase;
|
||||
use reth_rpc_api::TraceApiServer;
|
||||
use reth_rpc_eth_api::{helpers::TraceExt, FromEthApiError, RpcNodeCore};
|
||||
@@ -313,9 +311,7 @@ where
|
||||
|
||||
// add reward traces for all blocks
|
||||
for block in &blocks {
|
||||
if let Some(base_block_reward) =
|
||||
self.calculate_base_block_reward(block.header.header())?
|
||||
{
|
||||
if let Some(base_block_reward) = self.calculate_base_block_reward(block.header())? {
|
||||
all_traces.extend(
|
||||
self.extract_reward_traces(
|
||||
block.header.header(),
|
||||
@@ -509,30 +505,19 @@ where
|
||||
header: &H,
|
||||
) -> Result<Option<u128>, Eth::Error> {
|
||||
let chain_spec = self.provider().chain_spec();
|
||||
let is_paris_activated = chain_spec.is_paris_active_at_block(header.number());
|
||||
let is_paris_activated = if chain_spec.chain() == MAINNET.chain() {
|
||||
Some(header.number()) >= EthereumHardfork::Paris.mainnet_activation_block()
|
||||
} else if chain_spec.chain() == SEPOLIA.chain() {
|
||||
Some(header.number()) >= EthereumHardfork::Paris.sepolia_activation_block()
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
Ok(match is_paris_activated {
|
||||
Some(true) => None,
|
||||
Some(false) => Some(base_block_reward_pre_merge(&chain_spec, header.number())),
|
||||
None => {
|
||||
// if Paris hardfork is unknown, we need to fetch the total difficulty at the
|
||||
// block's height and check if it is pre-merge to calculate the base block reward
|
||||
if let Some(header_td) = self
|
||||
.provider()
|
||||
.header_td_by_number(header.number())
|
||||
.map_err(Eth::Error::from_eth_err)?
|
||||
{
|
||||
base_block_reward(
|
||||
chain_spec.as_ref(),
|
||||
header.number(),
|
||||
header.difficulty(),
|
||||
header_td,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
if is_paris_activated {
|
||||
return Ok(None)
|
||||
}
|
||||
|
||||
Ok(Some(base_block_reward_pre_merge(&chain_spec, header.number())))
|
||||
}
|
||||
|
||||
/// Extracts the reward traces for the given block:
|
||||
|
||||
@@ -19,9 +19,7 @@ use reth_errors::{BlockExecutionError, ConsensusError, ProviderError};
|
||||
use reth_evm::execute::{BlockExecutorProvider, Executor};
|
||||
use reth_primitives::{GotExpected, NodePrimitives, SealedBlockWithSenders, SealedHeader};
|
||||
use reth_primitives_traits::{constants::GAS_LIMIT_BOUND_DIVISOR, Block as _, BlockBody};
|
||||
use reth_provider::{
|
||||
BlockExecutionInput, BlockExecutionOutput, BlockReaderIdExt, StateProviderFactory,
|
||||
};
|
||||
use reth_provider::{BlockExecutionOutput, BlockReaderIdExt, StateProviderFactory};
|
||||
use reth_revm::{cached::CachedReads, database::StateProviderDatabase};
|
||||
use reth_rpc_api::BlockSubmissionValidationApiServer;
|
||||
use reth_rpc_server_types::result::internal_rpc_err;
|
||||
@@ -152,18 +150,15 @@ where
|
||||
|
||||
let block = block.unseal();
|
||||
let mut accessed_blacklisted = None;
|
||||
let output = executor.execute_with_state_closure(
|
||||
BlockExecutionInput::new(&block, U256::MAX),
|
||||
|state| {
|
||||
if !self.disallow.is_empty() {
|
||||
for account in state.cache.accounts.keys() {
|
||||
if self.disallow.contains(account) {
|
||||
accessed_blacklisted = Some(*account);
|
||||
}
|
||||
let output = executor.execute_with_state_closure(&block, |state| {
|
||||
if !self.disallow.is_empty() {
|
||||
for account in state.cache.accounts.keys() {
|
||||
if self.disallow.contains(account) {
|
||||
accessed_blacklisted = Some(*account);
|
||||
}
|
||||
}
|
||||
},
|
||||
)?;
|
||||
}
|
||||
})?;
|
||||
|
||||
// update the cached reads
|
||||
self.update_cached_reads(latest_header_hash, request_cache).await;
|
||||
|
||||
@@ -337,10 +337,6 @@ where
|
||||
// Fetch the block
|
||||
let fetch_block_start = Instant::now();
|
||||
|
||||
let td = provider
|
||||
.header_td_by_number(block_number)?
|
||||
.ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?;
|
||||
|
||||
// we need the block's transactions but we don't need the transaction hashes
|
||||
let block = provider
|
||||
.block_with_senders(block_number.into(), TransactionVariant::NoHash)?
|
||||
@@ -356,7 +352,7 @@ where
|
||||
// Execute the block
|
||||
let execute_start = Instant::now();
|
||||
|
||||
self.metrics.metered_one((&block, td).into(), |input| {
|
||||
self.metrics.metered_one(&block, |input| {
|
||||
executor.execute_and_verify_one(input).map_err(|error| {
|
||||
let header = block.header();
|
||||
StageError::Block {
|
||||
|
||||
@@ -1241,10 +1241,7 @@ impl<N: ProviderNodeTypes> EvmEnvProvider<HeaderTy<N>> for ConsistentProvider<N>
|
||||
where
|
||||
EvmConfig: ConfigureEvmEnv<Header = HeaderTy<N>>,
|
||||
{
|
||||
let total_difficulty = self
|
||||
.header_td_by_number(header.number())?
|
||||
.ok_or_else(|| ProviderError::HeaderNotFound(header.number().into()))?;
|
||||
Ok(evm_config.cfg_and_block_env(header, total_difficulty))
|
||||
Ok(evm_config.cfg_and_block_env(header))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1651,10 +1651,7 @@ impl<TX: DbTx + 'static, N: NodeTypesForProvider> EvmEnvProvider<HeaderTy<N>>
|
||||
where
|
||||
EvmConfig: ConfigureEvmEnv<Header = HeaderTy<N>>,
|
||||
{
|
||||
let total_difficulty = self
|
||||
.header_td_by_number(header.number())?
|
||||
.ok_or_else(|| ProviderError::HeaderNotFound(header.number().into()))?;
|
||||
Ok(evm_config.cfg_and_block_env(header, total_difficulty))
|
||||
Ok(evm_config.cfg_and_block_env(header))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -716,7 +716,7 @@ impl EvmEnvProvider for MockEthProvider {
|
||||
where
|
||||
EvmConfig: ConfigureEvmEnv<Header = Header>,
|
||||
{
|
||||
Ok(evm_config.cfg_and_block_env(header, U256::MAX))
|
||||
Ok(evm_config.cfg_and_block_env(header))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -129,12 +129,8 @@ where
|
||||
/// # Caution
|
||||
///
|
||||
/// This does not initialize the tx environment.
|
||||
fn evm_env_for_block(
|
||||
&self,
|
||||
header: &alloy_consensus::Header,
|
||||
total_difficulty: U256,
|
||||
) -> EnvWithHandlerCfg {
|
||||
let evm_env = self.evm_config.cfg_and_block_env(header, total_difficulty);
|
||||
fn evm_env_for_block(&self, header: &alloy_consensus::Header) -> EnvWithHandlerCfg {
|
||||
let evm_env = self.evm_config.cfg_and_block_env(header);
|
||||
let EvmEnv { cfg_env_with_handler_cfg, block_env } = evm_env;
|
||||
EnvWithHandlerCfg::new_with_cfg_env(cfg_env_with_handler_cfg, block_env, Default::default())
|
||||
}
|
||||
@@ -148,11 +144,7 @@ where
|
||||
type Primitives = EthPrimitives;
|
||||
type Error = BlockExecutionError;
|
||||
|
||||
fn apply_pre_execution_changes(
|
||||
&mut self,
|
||||
block: &BlockWithSenders,
|
||||
_total_difficulty: U256,
|
||||
) -> Result<(), Self::Error> {
|
||||
fn apply_pre_execution_changes(&mut self, block: &BlockWithSenders) -> Result<(), Self::Error> {
|
||||
// Set state clear flag if the block is after the Spurious Dragon hardfork.
|
||||
let state_clear_flag =
|
||||
(*self.chain_spec).is_spurious_dragon_active_at_block(block.header.number);
|
||||
@@ -164,7 +156,6 @@ where
|
||||
fn execute_transactions(
|
||||
&mut self,
|
||||
_block: &BlockWithSenders,
|
||||
_total_difficulty: U256,
|
||||
) -> Result<ExecuteOutput<Receipt>, Self::Error> {
|
||||
Ok(ExecuteOutput { receipts: vec![], gas_used: 0 })
|
||||
}
|
||||
@@ -172,10 +163,9 @@ where
|
||||
fn apply_post_execution_changes(
|
||||
&mut self,
|
||||
block: &BlockWithSenders,
|
||||
total_difficulty: U256,
|
||||
_receipts: &[Receipt],
|
||||
) -> Result<Requests, Self::Error> {
|
||||
let env = self.evm_env_for_block(&block.header, total_difficulty);
|
||||
let env = self.evm_env_for_block(&block.header);
|
||||
let mut evm = self.evm_config.evm_with_env(&mut self.state, env);
|
||||
|
||||
if let Some(withdrawals) = block.body.withdrawals.as_ref() {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
use alloy_consensus::Header;
|
||||
use alloy_genesis::Genesis;
|
||||
use alloy_primitives::{address, Address, Bytes, U256};
|
||||
use alloy_primitives::{address, Address, Bytes};
|
||||
use reth::{
|
||||
builder::{
|
||||
components::{ExecutorBuilder, PayloadServiceBuilder},
|
||||
@@ -103,13 +103,8 @@ impl ConfigureEvmEnv for MyEvmConfig {
|
||||
self.inner.fill_tx_env_system_contract_call(env, caller, contract, data);
|
||||
}
|
||||
|
||||
fn fill_cfg_env(
|
||||
&self,
|
||||
cfg_env: &mut CfgEnvWithHandlerCfg,
|
||||
header: &Self::Header,
|
||||
total_difficulty: U256,
|
||||
) {
|
||||
self.inner.fill_cfg_env(cfg_env, header, total_difficulty);
|
||||
fn fill_cfg_env(&self, cfg_env: &mut CfgEnvWithHandlerCfg, header: &Self::Header) {
|
||||
self.inner.fill_cfg_env(cfg_env, header);
|
||||
}
|
||||
|
||||
fn next_cfg_and_block_env(
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
use alloy_consensus::Header;
|
||||
use alloy_genesis::Genesis;
|
||||
use alloy_primitives::{Address, Bytes, U256};
|
||||
use alloy_primitives::{Address, Bytes};
|
||||
use parking_lot::RwLock;
|
||||
use reth::{
|
||||
api::NextBlockEnvAttributes,
|
||||
@@ -165,13 +165,8 @@ impl ConfigureEvmEnv for MyEvmConfig {
|
||||
self.inner.fill_tx_env_system_contract_call(env, caller, contract, data)
|
||||
}
|
||||
|
||||
fn fill_cfg_env(
|
||||
&self,
|
||||
cfg_env: &mut CfgEnvWithHandlerCfg,
|
||||
header: &Self::Header,
|
||||
total_difficulty: U256,
|
||||
) {
|
||||
self.inner.fill_cfg_env(cfg_env, header, total_difficulty)
|
||||
fn fill_cfg_env(&self, cfg_env: &mut CfgEnvWithHandlerCfg, header: &Self::Header) {
|
||||
self.inner.fill_cfg_env(cfg_env, header)
|
||||
}
|
||||
|
||||
fn next_cfg_and_block_env(
|
||||
|
||||
Reference in New Issue
Block a user