mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
Make it compilable (still bunch to fix!)
This commit is contained in:
316
src/node/evm/config.rs
Normal file
316
src/node/evm/config.rs
Normal file
@ -0,0 +1,316 @@
|
||||
use super::{executor::HlBlockExecutor, factory::HlEvmFactory};
|
||||
use crate::{
|
||||
chainspec::HlChainSpec,
|
||||
evm::{spec::HlSpecId, transaction::HlTxEnv},
|
||||
hardforks::HlHardforks,
|
||||
HlPrimitives,
|
||||
};
|
||||
use alloy_consensus::{BlockHeader, Header, TxReceipt};
|
||||
use alloy_primitives::{Log, U256};
|
||||
use reth_chainspec::{EthChainSpec, EthereumHardforks, Hardforks};
|
||||
use reth_ethereum_forks::EthereumHardfork;
|
||||
use reth_evm::{
|
||||
block::{BlockExecutorFactory, BlockExecutorFor},
|
||||
eth::{receipt_builder::ReceiptBuilder, EthBlockExecutionCtx},
|
||||
ConfigureEvm, EvmEnv, EvmFactory, ExecutionCtxFor, FromRecoveredTx, FromTxWithEncoded,
|
||||
IntoTxEnv, NextBlockEnvAttributes,
|
||||
};
|
||||
use reth_evm_ethereum::{EthBlockAssembler, RethReceiptBuilder};
|
||||
use reth_primitives::{BlockTy, HeaderTy, SealedBlock, SealedHeader, TransactionSigned};
|
||||
use reth_revm::State;
|
||||
use revm::{
|
||||
context::{BlockEnv, CfgEnv, TxEnv},
|
||||
context_interface::block::BlobExcessGasAndPrice,
|
||||
primitives::hardfork::SpecId,
|
||||
Inspector,
|
||||
};
|
||||
use std::{borrow::Cow, convert::Infallible, sync::Arc};
|
||||
|
||||
/// Ethereum-related EVM configuration.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HlEvmConfig {
|
||||
/// Inner [`HlBlockExecutorFactory`].
|
||||
pub executor_factory:
|
||||
HlBlockExecutorFactory<RethReceiptBuilder, Arc<HlChainSpec>, HlEvmFactory>,
|
||||
/// Ethereum block assembler.
|
||||
pub block_assembler: EthBlockAssembler<HlChainSpec>,
|
||||
}
|
||||
|
||||
impl HlEvmConfig {
|
||||
/// Creates a new Ethereum EVM configuration with the given chain spec.
|
||||
pub fn new(chain_spec: Arc<HlChainSpec>) -> Self {
|
||||
Self::hl(chain_spec)
|
||||
}
|
||||
|
||||
/// Creates a new Ethereum EVM configuration.
|
||||
pub fn hl(chain_spec: Arc<HlChainSpec>) -> Self {
|
||||
Self::new_with_evm_factory(chain_spec, HlEvmFactory::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl HlEvmConfig {
|
||||
/// Creates a new Ethereum EVM configuration with the given chain spec and EVM factory.
|
||||
pub fn new_with_evm_factory(chain_spec: Arc<HlChainSpec>, evm_factory: HlEvmFactory) -> Self {
|
||||
Self {
|
||||
block_assembler: EthBlockAssembler::new(chain_spec.clone()),
|
||||
executor_factory: HlBlockExecutorFactory::new(
|
||||
RethReceiptBuilder::default(),
|
||||
chain_spec,
|
||||
evm_factory,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the chain spec associated with this configuration.
|
||||
pub const fn chain_spec(&self) -> &Arc<HlChainSpec> {
|
||||
self.executor_factory.spec()
|
||||
}
|
||||
}
|
||||
|
||||
/// Ethereum block executor factory.
|
||||
#[derive(Debug, Clone, Default, Copy)]
|
||||
pub struct HlBlockExecutorFactory<
|
||||
R = RethReceiptBuilder,
|
||||
Spec = Arc<HlChainSpec>,
|
||||
EvmFactory = HlEvmFactory,
|
||||
> {
|
||||
/// Receipt builder.
|
||||
receipt_builder: R,
|
||||
/// Chain specification.
|
||||
spec: Spec,
|
||||
/// EVM factory.
|
||||
evm_factory: EvmFactory,
|
||||
}
|
||||
|
||||
impl<R, Spec, EvmFactory> HlBlockExecutorFactory<R, Spec, EvmFactory> {
|
||||
/// Creates a new [`HlBlockExecutorFactory`] with the given spec, [`EvmFactory`], and
|
||||
/// [`ReceiptBuilder`].
|
||||
pub const fn new(receipt_builder: R, spec: Spec, evm_factory: EvmFactory) -> Self {
|
||||
Self {
|
||||
receipt_builder,
|
||||
spec,
|
||||
evm_factory,
|
||||
}
|
||||
}
|
||||
|
||||
/// Exposes the receipt builder.
|
||||
pub const fn receipt_builder(&self) -> &R {
|
||||
&self.receipt_builder
|
||||
}
|
||||
|
||||
/// Exposes the chain specification.
|
||||
pub const fn spec(&self) -> &Spec {
|
||||
&self.spec
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, Spec, EvmF> BlockExecutorFactory for HlBlockExecutorFactory<R, Spec, EvmF>
|
||||
where
|
||||
R: ReceiptBuilder<Transaction = TransactionSigned, Receipt: TxReceipt<Log = Log>>,
|
||||
Spec: EthereumHardforks + HlHardforks + EthChainSpec + Hardforks + Clone,
|
||||
EvmF: EvmFactory<Tx: FromRecoveredTx<TransactionSigned> + FromTxWithEncoded<TransactionSigned>>,
|
||||
R::Transaction: From<TransactionSigned> + Clone,
|
||||
Self: 'static,
|
||||
HlTxEnv<TxEnv>: IntoTxEnv<<EvmF as EvmFactory>::Tx>,
|
||||
{
|
||||
type EvmFactory = EvmF;
|
||||
type ExecutionCtx<'a> = EthBlockExecutionCtx<'a>;
|
||||
type Transaction = TransactionSigned;
|
||||
type Receipt = R::Receipt;
|
||||
|
||||
fn evm_factory(&self) -> &Self::EvmFactory {
|
||||
&self.evm_factory
|
||||
}
|
||||
|
||||
fn create_executor<'a, DB, I>(
|
||||
&'a self,
|
||||
evm: <Self::EvmFactory as EvmFactory>::Evm<&'a mut State<DB>, I>,
|
||||
ctx: Self::ExecutionCtx<'a>,
|
||||
) -> impl BlockExecutorFor<'a, Self, DB, I>
|
||||
where
|
||||
DB: alloy_evm::Database + 'a,
|
||||
I: Inspector<<Self::EvmFactory as EvmFactory>::Context<&'a mut State<DB>>> + 'a,
|
||||
{
|
||||
HlBlockExecutor::new(evm, ctx, self.spec().clone(), self.receipt_builder())
|
||||
}
|
||||
}
|
||||
|
||||
const EIP1559_INITIAL_BASE_FEE: u64 = 0;
|
||||
|
||||
impl ConfigureEvm for HlEvmConfig
|
||||
where
|
||||
Self: Send + Sync + Unpin + Clone + 'static,
|
||||
{
|
||||
type Primitives = HlPrimitives;
|
||||
type Error = Infallible;
|
||||
type NextBlockEnvCtx = NextBlockEnvAttributes;
|
||||
type BlockExecutorFactory = HlBlockExecutorFactory;
|
||||
type BlockAssembler = Self;
|
||||
|
||||
fn block_executor_factory(&self) -> &Self::BlockExecutorFactory {
|
||||
&self.executor_factory
|
||||
}
|
||||
|
||||
fn block_assembler(&self) -> &Self::BlockAssembler {
|
||||
self
|
||||
}
|
||||
|
||||
fn evm_env(&self, header: &Header) -> EvmEnv<HlSpecId> {
|
||||
let blob_params = self.chain_spec().blob_params_at_timestamp(header.timestamp);
|
||||
let spec = revm_spec_by_timestamp_and_block_number(
|
||||
self.chain_spec().clone(),
|
||||
header.timestamp(),
|
||||
header.number(),
|
||||
);
|
||||
|
||||
// configure evm env based on parent block
|
||||
let mut cfg_env = CfgEnv::new()
|
||||
.with_chain_id(self.chain_spec().chain().id())
|
||||
.with_spec(spec);
|
||||
|
||||
if let Some(blob_params) = &blob_params {
|
||||
cfg_env.set_blob_max_count(blob_params.max_blob_count);
|
||||
}
|
||||
|
||||
// derive the EIP-4844 blob fees from the header's `excess_blob_gas` and the current
|
||||
// blobparams
|
||||
let blob_excess_gas_and_price =
|
||||
header
|
||||
.excess_blob_gas
|
||||
.zip(blob_params)
|
||||
.map(|(excess_blob_gas, params)| {
|
||||
let blob_gasprice = params.calc_blob_fee(excess_blob_gas);
|
||||
BlobExcessGasAndPrice {
|
||||
excess_blob_gas,
|
||||
blob_gasprice,
|
||||
}
|
||||
});
|
||||
|
||||
let eth_spec = spec.into_eth_spec();
|
||||
|
||||
let block_env = BlockEnv {
|
||||
number: header.number(),
|
||||
beneficiary: header.beneficiary(),
|
||||
timestamp: header.timestamp(),
|
||||
difficulty: if eth_spec >= SpecId::MERGE {
|
||||
U256::ZERO
|
||||
} else {
|
||||
header.difficulty()
|
||||
},
|
||||
prevrandao: if eth_spec >= SpecId::MERGE {
|
||||
header.mix_hash()
|
||||
} else {
|
||||
None
|
||||
},
|
||||
gas_limit: header.gas_limit(),
|
||||
basefee: header.base_fee_per_gas().unwrap_or_default(),
|
||||
blob_excess_gas_and_price,
|
||||
};
|
||||
|
||||
EvmEnv { cfg_env, block_env }
|
||||
}
|
||||
|
||||
fn next_evm_env(
|
||||
&self,
|
||||
parent: &Header,
|
||||
attributes: &Self::NextBlockEnvCtx,
|
||||
) -> Result<EvmEnv<HlSpecId>, Self::Error> {
|
||||
// ensure we're not missing any timestamp based hardforks
|
||||
let spec_id = revm_spec_by_timestamp_and_block_number(
|
||||
self.chain_spec().clone(),
|
||||
attributes.timestamp,
|
||||
parent.number() + 1,
|
||||
);
|
||||
|
||||
// configure evm env based on parent block
|
||||
let cfg_env = CfgEnv::new()
|
||||
.with_chain_id(self.chain_spec().chain().id())
|
||||
.with_spec(spec_id);
|
||||
|
||||
// if the parent block did not have excess blob gas (i.e. it was pre-cancun), but it is
|
||||
// cancun now, we need to set the excess blob gas to the default value(0)
|
||||
let blob_excess_gas_and_price = parent
|
||||
.maybe_next_block_excess_blob_gas(
|
||||
self.chain_spec()
|
||||
.blob_params_at_timestamp(attributes.timestamp),
|
||||
)
|
||||
.or_else(|| (spec_id.into_eth_spec().is_enabled_in(SpecId::CANCUN)).then_some(0))
|
||||
.map(|gas| BlobExcessGasAndPrice::new(gas, false));
|
||||
|
||||
let mut basefee = parent.next_block_base_fee(
|
||||
self.chain_spec()
|
||||
.base_fee_params_at_timestamp(attributes.timestamp),
|
||||
);
|
||||
|
||||
let mut gas_limit = U256::from(parent.gas_limit);
|
||||
|
||||
// If we are on the London fork boundary, we need to multiply the parent's gas limit by the
|
||||
// elasticity multiplier to get the new gas limit.
|
||||
if self
|
||||
.chain_spec()
|
||||
.inner
|
||||
.fork(EthereumHardfork::London)
|
||||
.transitions_at_block(parent.number + 1)
|
||||
{
|
||||
let elasticity_multiplier = self
|
||||
.chain_spec()
|
||||
.base_fee_params_at_timestamp(attributes.timestamp)
|
||||
.elasticity_multiplier;
|
||||
|
||||
// multiply the gas limit by the elasticity multiplier
|
||||
gas_limit *= U256::from(elasticity_multiplier);
|
||||
|
||||
// set the base fee to the initial base fee from the EIP-1559 spec
|
||||
basefee = Some(EIP1559_INITIAL_BASE_FEE)
|
||||
}
|
||||
|
||||
let block_env = BlockEnv {
|
||||
number: parent.number() + 1,
|
||||
beneficiary: attributes.suggested_fee_recipient,
|
||||
timestamp: attributes.timestamp,
|
||||
difficulty: U256::ZERO,
|
||||
prevrandao: Some(attributes.prev_randao),
|
||||
gas_limit: attributes.gas_limit,
|
||||
// calculate basefee based on parent block's gas usage
|
||||
basefee: basefee.unwrap_or_default(),
|
||||
// calculate excess gas based on parent block's blob gas usage
|
||||
blob_excess_gas_and_price,
|
||||
};
|
||||
|
||||
Ok(EvmEnv { cfg_env, block_env })
|
||||
}
|
||||
|
||||
fn context_for_block<'a>(
|
||||
&self,
|
||||
block: &'a SealedBlock<BlockTy<Self::Primitives>>,
|
||||
) -> ExecutionCtxFor<'a, Self> {
|
||||
EthBlockExecutionCtx {
|
||||
parent_hash: block.header().parent_hash,
|
||||
parent_beacon_block_root: block.header().parent_beacon_block_root,
|
||||
ommers: &block.body().ommers,
|
||||
withdrawals: block.body().withdrawals.as_ref().map(Cow::Borrowed),
|
||||
}
|
||||
}
|
||||
|
||||
fn context_for_next_block(
|
||||
&self,
|
||||
parent: &SealedHeader<HeaderTy<Self::Primitives>>,
|
||||
attributes: Self::NextBlockEnvCtx,
|
||||
) -> ExecutionCtxFor<'_, Self> {
|
||||
EthBlockExecutionCtx {
|
||||
parent_hash: parent.hash(),
|
||||
parent_beacon_block_root: attributes.parent_beacon_block_root,
|
||||
ommers: &[],
|
||||
withdrawals: attributes.withdrawals.map(Cow::Owned),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Map the latest active hardfork at the given timestamp or block number to a [`HlSpecId`].
|
||||
pub fn revm_spec_by_timestamp_and_block_number(
|
||||
chain_spec: impl HlHardforks,
|
||||
timestamp: u64,
|
||||
block_number: u64,
|
||||
) -> HlSpecId {
|
||||
HlSpecId::V1
|
||||
}
|
||||
Reference in New Issue
Block a user