Make it compilable (still bunch to fix!)

This commit is contained in:
sprites0
2025-06-17 18:06:53 -04:00
parent 5e531b7260
commit 821bf7a775
38 changed files with 3652 additions and 31 deletions

32
src/node/evm/assembler.rs Normal file
View File

@ -0,0 +1,32 @@
use crate::{
node::evm::config::{HlBlockExecutorFactory, HlEvmConfig},
HlBlock, HlBlockBody,
};
use alloy_consensus::{Block, Header};
use reth_evm::{
block::BlockExecutionError,
execute::{BlockAssembler, BlockAssemblerInput},
};
impl BlockAssembler<HlBlockExecutorFactory> for HlEvmConfig {
type Block = HlBlock;
fn assemble_block(
&self,
input: BlockAssemblerInput<'_, '_, HlBlockExecutorFactory, Header>,
) -> Result<Self::Block, BlockExecutionError> {
let Block { header, body: inner } = self.block_assembler.assemble_block(input)?;
Ok(HlBlock {
header,
body: HlBlockBody {
inner,
// HACK: we're setting sidecars to `None` here but ideally we should somehow get
// them from the payload builder.
//
// Payload building is out of scope of reth-bsc for now, so this is not critical
sidecars: None,
read_precompile_calls: None,
},
})
}
}

316
src/node/evm/config.rs Normal file
View 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
}

211
src/node/evm/executor.rs Normal file
View File

@ -0,0 +1,211 @@
use super::patch::patch_mainnet_after_tx;
use crate::{evm::transaction::HlTxEnv, hardforks::HlHardforks};
use alloy_consensus::{Transaction, TxReceipt};
use alloy_eips::{eip7685::Requests, Encodable2718};
use alloy_evm::{block::ExecutableTx, eth::receipt_builder::ReceiptBuilderCtx};
use alloy_primitives::Address;
use reth_chainspec::{EthChainSpec, EthereumHardforks, Hardforks};
use reth_evm::{
block::{BlockValidationError, CommitChanges},
eth::{receipt_builder::ReceiptBuilder, EthBlockExecutionCtx},
execute::{BlockExecutionError, BlockExecutor},
Database, Evm, FromRecoveredTx, FromTxWithEncoded, IntoTxEnv, OnStateHook, RecoveredTx,
};
use reth_primitives::TransactionSigned;
use reth_provider::BlockExecutionResult;
use reth_revm::State;
use revm::{
context::{
result::{ExecutionResult, ResultAndState},
TxEnv,
},
state::Bytecode,
Database as _, DatabaseCommit,
};
fn is_system_transaction(tx: &TransactionSigned) -> bool {
let Some(gas_price) = tx.gas_price() else {
return false;
};
gas_price == 0
}
pub struct HlBlockExecutor<'a, EVM, Spec, R: ReceiptBuilder>
where
Spec: EthChainSpec,
{
/// Reference to the specification object.
spec: Spec,
/// Inner EVM.
evm: EVM,
/// Gas used in the block.
gas_used: u64,
/// Receipts of executed transactions.
receipts: Vec<R::Receipt>,
/// System txs
system_txs: Vec<R::Transaction>,
/// Receipt builder.
receipt_builder: R,
/// System contracts used to trigger fork specific logic.
// system_contracts: SystemContract<Spec>,
/// Context for block execution.
_ctx: EthBlockExecutionCtx<'a>,
}
impl<'a, DB, EVM, Spec, R: ReceiptBuilder> HlBlockExecutor<'a, EVM, Spec, R>
where
DB: Database + 'a,
EVM: Evm<
DB = &'a mut State<DB>,
Tx: FromRecoveredTx<R::Transaction>
+ FromRecoveredTx<TransactionSigned>
+ FromTxWithEncoded<TransactionSigned>,
>,
Spec: EthereumHardforks + HlHardforks + EthChainSpec + Hardforks + Clone,
R: ReceiptBuilder<Transaction = TransactionSigned, Receipt: TxReceipt>,
<R as ReceiptBuilder>::Transaction: Unpin + From<TransactionSigned>,
<EVM as alloy_evm::Evm>::Tx: FromTxWithEncoded<<R as ReceiptBuilder>::Transaction>,
HlTxEnv<TxEnv>: IntoTxEnv<<EVM as alloy_evm::Evm>::Tx>,
R::Transaction: Into<TransactionSigned>,
{
/// Creates a new HlBlockExecutor.
pub fn new(
evm: EVM,
_ctx: EthBlockExecutionCtx<'a>,
spec: Spec,
receipt_builder: R,
// system_contracts: SystemContract<Spec>,
) -> Self {
Self {
spec,
evm,
gas_used: 0,
receipts: vec![],
system_txs: vec![],
receipt_builder,
// system_contracts,
_ctx,
}
}
/// Initializes the genesis contracts
fn deploy_genesis_contracts(
&mut self,
beneficiary: Address,
) -> Result<(), BlockExecutionError> {
todo!("Deploy WETH, System contract");
// Ok(())
}
}
impl<'a, DB, E, Spec, R> BlockExecutor for HlBlockExecutor<'a, E, Spec, R>
where
DB: Database + 'a,
E: Evm<
DB = &'a mut State<DB>,
Tx: FromRecoveredTx<R::Transaction>
+ FromRecoveredTx<TransactionSigned>
+ FromTxWithEncoded<TransactionSigned>,
>,
Spec: EthereumHardforks + HlHardforks + EthChainSpec + Hardforks,
R: ReceiptBuilder<Transaction = TransactionSigned, Receipt: TxReceipt>,
<R as ReceiptBuilder>::Transaction: Unpin + From<TransactionSigned>,
<E as alloy_evm::Evm>::Tx: FromTxWithEncoded<<R as ReceiptBuilder>::Transaction>,
HlTxEnv<TxEnv>: IntoTxEnv<<E as alloy_evm::Evm>::Tx>,
R::Transaction: Into<TransactionSigned>,
{
type Transaction = TransactionSigned;
type Receipt = R::Receipt;
type Evm = E;
fn apply_pre_execution_changes(&mut self) -> Result<(), BlockExecutionError> {
// If first block deploy genesis contracts
if self.evm.block().number == 1 {
self.deploy_genesis_contracts(self.evm.block().beneficiary)?;
}
Ok(())
}
fn execute_transaction_with_commit_condition(
&mut self,
_tx: impl ExecutableTx<Self>,
_f: impl FnOnce(&ExecutionResult<<Self::Evm as Evm>::HaltReason>) -> CommitChanges,
) -> Result<Option<u64>, BlockExecutionError> {
Ok(Some(0))
}
fn execute_transaction_with_result_closure(
&mut self,
tx: impl ExecutableTx<Self>
+ IntoTxEnv<<E as alloy_evm::Evm>::Tx>
+ RecoveredTx<TransactionSigned>,
f: impl for<'b> FnOnce(&'b ExecutionResult<<E as alloy_evm::Evm>::HaltReason>),
) -> Result<u64, BlockExecutionError> {
// Check if it's a system transaction
// let signer = tx.signer();
// let is_system_transaction = is_system_transaction(tx.tx());
let block_available_gas = self.evm.block().gas_limit - self.gas_used;
if tx.tx().gas_limit() > block_available_gas {
return Err(
BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas {
transaction_gas_limit: tx.tx().gas_limit(),
block_available_gas,
}
.into(),
);
}
let result_and_state = self
.evm
.transact(tx)
.map_err(|err| BlockExecutionError::evm(err, tx.tx().trie_hash()))?;
let ResultAndState { result, mut state } = result_and_state;
f(&result);
let gas_used = result.gas_used();
self.gas_used += gas_used;
self.receipts
.push(self.receipt_builder.build_receipt(ReceiptBuilderCtx {
tx: tx.tx(),
evm: &self.evm,
result,
state: &state,
cumulative_gas_used: self.gas_used,
}));
// apply patches after
patch_mainnet_after_tx(
self.evm.block().number,
self.receipts.len() as u64,
is_system_transaction(tx.tx()),
&mut state,
)?;
self.evm.db_mut().commit(state);
Ok(gas_used)
}
fn finish(
mut self,
) -> Result<(Self::Evm, BlockExecutionResult<R::Receipt>), BlockExecutionError> {
Ok((
self.evm,
BlockExecutionResult {
receipts: self.receipts,
requests: Requests::default(),
gas_used: self.gas_used,
},
))
}
fn set_state_hook(&mut self, _hook: Option<Box<dyn OnStateHook>>) {}
fn evm_mut(&mut self) -> &mut Self::Evm {
&mut self.evm
}
fn evm(&self) -> &Self::Evm {
&self.evm
}
}

74
src/node/evm/factory.rs Normal file
View File

@ -0,0 +1,74 @@
use super::HlEvm;
use crate::evm::{
api::{
builder::HlBuilder,
ctx::{HlContext, DefaultHl},
},
precompiles::HlPrecompiles,
spec::HlSpecId,
transaction::HlTxEnv,
};
use reth_evm::{precompiles::PrecompilesMap, EvmEnv, EvmFactory};
use reth_revm::{Context, Database};
use revm::{
context::{
result::{EVMError, HaltReason},
TxEnv,
},
inspector::NoOpInspector,
Inspector,
};
/// Factory producing [`HlEvm`].
#[derive(Debug, Default, Clone, Copy)]
#[non_exhaustive]
pub struct HlEvmFactory;
impl EvmFactory for HlEvmFactory {
type Evm<DB: Database<Error: Send + Sync + 'static>, I: Inspector<HlContext<DB>>> =
HlEvm<DB, I, Self::Precompiles>;
type Context<DB: Database<Error: Send + Sync + 'static>> = HlContext<DB>;
type Tx = HlTxEnv<TxEnv>;
type Error<DBError: core::error::Error + Send + Sync + 'static> = EVMError<DBError>;
type HaltReason = HaltReason;
type Spec = HlSpecId;
type Precompiles = PrecompilesMap;
fn create_evm<DB: Database<Error: Send + Sync + 'static>>(
&self,
db: DB,
input: EvmEnv<HlSpecId>,
) -> Self::Evm<DB, NoOpInspector> {
let precompiles = HlPrecompiles::new(input.cfg_env.spec).precompiles();
HlEvm {
inner: Context::hl()
.with_block(input.block_env)
.with_cfg(input.cfg_env)
.with_db(db)
.build_hl_with_inspector(NoOpInspector {})
.with_precompiles(PrecompilesMap::from_static(precompiles)),
inspect: false,
}
}
fn create_evm_with_inspector<
DB: Database<Error: Send + Sync + 'static>,
I: Inspector<Self::Context<DB>>,
>(
&self,
db: DB,
input: EvmEnv<HlSpecId>,
inspector: I,
) -> Self::Evm<DB, I> {
let precompiles = HlPrecompiles::new(input.cfg_env.spec).precompiles();
HlEvm {
inner: Context::hl()
.with_block(input.block_env)
.with_cfg(input.cfg_env)
.with_db(db)
.build_hl_with_inspector(inspector)
.with_precompiles(PrecompilesMap::from_static(precompiles)),
inspect: true,
}
}
}

165
src/node/evm/mod.rs Normal file
View File

@ -0,0 +1,165 @@
use crate::{
evm::{
api::{ctx::HlContext, HlEvmInner},
precompiles::HlPrecompiles,
spec::HlSpecId,
transaction::{HlTxEnv, HlTxTr},
},
node::HlNode,
};
use alloy_primitives::{Address, Bytes};
use config::HlEvmConfig;
use reth::{
api::FullNodeTypes,
builder::{components::ExecutorBuilder, BuilderContext},
};
use reth_evm::{Evm, EvmEnv};
use revm::{
context::{
result::{EVMError, HaltReason, ResultAndState},
BlockEnv, TxEnv,
},
handler::{instructions::EthInstructions, PrecompileProvider},
interpreter::{interpreter::EthInterpreter, InterpreterResult},
Context, Database, ExecuteEvm, InspectEvm, Inspector,
};
use std::ops::{Deref, DerefMut};
mod assembler;
pub mod config;
mod executor;
mod factory;
mod patch;
/// HL EVM implementation.
///
/// This is a wrapper type around the `revm` evm with optional [`Inspector`] (tracing)
/// support. [`Inspector`] support is configurable at runtime because it's part of the underlying
#[allow(missing_debug_implementations)]
pub struct HlEvm<DB: Database, I, P = HlPrecompiles> {
pub inner: HlEvmInner<HlContext<DB>, I, EthInstructions<EthInterpreter, HlContext<DB>>, P>,
pub inspect: bool,
}
impl<DB: Database, I, P> HlEvm<DB, I, P> {
/// Provides a reference to the EVM context.
pub const fn ctx(&self) -> &HlContext<DB> {
&self.inner.0.ctx
}
/// Provides a mutable reference to the EVM context.
pub fn ctx_mut(&mut self) -> &mut HlContext<DB> {
&mut self.inner.0.ctx
}
}
impl<DB: Database, I, P> Deref for HlEvm<DB, I, P> {
type Target = HlContext<DB>;
#[inline]
fn deref(&self) -> &Self::Target {
self.ctx()
}
}
impl<DB: Database, I, P> DerefMut for HlEvm<DB, I, P> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.ctx_mut()
}
}
impl<DB, I, P> Evm for HlEvm<DB, I, P>
where
DB: Database,
I: Inspector<HlContext<DB>>,
P: PrecompileProvider<HlContext<DB>, Output = InterpreterResult>,
<DB as revm::Database>::Error: std::marker::Send + std::marker::Sync + 'static,
{
type DB = DB;
type Tx = HlTxEnv<TxEnv>;
type Error = EVMError<DB::Error>;
type HaltReason = HaltReason;
type Spec = HlSpecId;
type Precompiles = P;
type Inspector = I;
fn chain_id(&self) -> u64 {
self.cfg.chain_id
}
fn block(&self) -> &BlockEnv {
&self.block
}
fn transact_raw(
&mut self,
tx: Self::Tx,
) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
if self.inspect {
self.inner.set_tx(tx);
self.inner.inspect_replay()
} else if tx.is_system_transaction() {
self.inner.set_tx(tx);
self.inner.inspect_replay()
} else {
self.inner.transact(tx)
}
}
fn transact_system_call(
&mut self,
_caller: Address,
_contract: Address,
_data: Bytes,
) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
unimplemented!()
}
fn db_mut(&mut self) -> &mut Self::DB {
&mut self.journaled_state.database
}
fn finish(self) -> (Self::DB, EvmEnv<Self::Spec>) {
let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.0.ctx;
(journaled_state.database, EvmEnv { block_env, cfg_env })
}
fn set_inspector_enabled(&mut self, enabled: bool) {
self.inspect = enabled;
}
fn precompiles_mut(&mut self) -> &mut Self::Precompiles {
&mut self.inner.0.precompiles
}
fn inspector_mut(&mut self) -> &mut Self::Inspector {
&mut self.inner.0.inspector
}
fn precompiles(&self) -> &Self::Precompiles {
&self.inner.0.precompiles
}
fn inspector(&self) -> &Self::Inspector {
&self.inner.0.inspector
}
}
/// A regular hl evm and executor builder.
#[derive(Debug, Default, Clone, Copy)]
#[non_exhaustive]
pub struct HlExecutorBuilder;
impl<Node> ExecutorBuilder<Node> for HlExecutorBuilder
where
Node: FullNodeTypes<Types = HlNode>,
{
type EVM = HlEvmConfig;
async fn build_evm(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::EVM> {
let evm_config = HlEvmConfig::hl(ctx.chain_spec());
Ok(evm_config)
}
}

145
src/node/evm/patch.rs Normal file
View File

@ -0,0 +1,145 @@
use alloy_primitives::{address, b256, Address, B256, U256};
use reth_evm::block::BlockExecutionError;
use reth_primitives_traits::SignedTransaction;
use reth_revm::{db::states::StorageSlot, State};
use revm::{primitives::HashMap, state::Account, Database};
use std::{str::FromStr, sync::LazyLock};
use tracing::trace;
/// Applies storage patches to the state after a transaction is executed.
/// See https://github.com/hyperliquid-dex/hyper-evm-sync/commit/39047242b6260f7764527a2f5057dd9c3a75aa89 for more details.
static MAINNET_PATCHES_AFTER_TX: &[(u64, u64, bool, Address)] = &[
(
1_467_569,
0,
false,
address!("0x33f6fe38c55cb100ce27b3138e5d2d041648364f"),
),
(
1_467_631,
0,
false,
address!("0x33f6fe38c55cb100ce27b3138e5d2d041648364f"),
),
(
1_499_313,
2,
false,
address!("0xe27bfc0a812b38927ff646f24af9149f45deb550"),
),
(
1_499_406,
0,
false,
address!("0xe27bfc0a812b38927ff646f24af9149f45deb550"),
),
(
1_499_685,
0,
false,
address!("0xfee3932b75a87e86930668a6ab3ed43b404c8a30"),
),
(
1_514_843,
0,
false,
address!("0x723e5fbbeed025772a91240fd0956a866a41a603"),
),
(
1_514_936,
0,
false,
address!("0x723e5fbbeed025772a91240fd0956a866a41a603"),
),
(
1_530_529,
2,
false,
address!("0xa694e8fd8f4a177dd23636d838e9f1fb2138d87a"),
),
(
1_530_622,
2,
false,
address!("0xa694e8fd8f4a177dd23636d838e9f1fb2138d87a"),
),
(
1_530_684,
3,
false,
address!("0xa694e8fd8f4a177dd23636d838e9f1fb2138d87a"),
),
(
1_530_777,
3,
false,
address!("0xa694e8fd8f4a177dd23636d838e9f1fb2138d87a"),
),
(
1_530_839,
2,
false,
address!("0x692a343fc401a7755f8fc2facf61af426adaf061"),
),
(
1_530_901,
0,
false,
address!("0xfd9716f16596715ce765dabaee11787870e04b8a"),
),
(
1_530_994,
3,
false,
address!("0xfd9716f16596715ce765dabaee11787870e04b8a"),
),
(
1_531_056,
4,
false,
address!("0xdc67c2b8349ca20f58760e08371fc9271e82b5a4"),
),
(
1_531_149,
0,
false,
address!("0xdc67c2b8349ca20f58760e08371fc9271e82b5a4"),
),
(
1_531_211,
3,
false,
address!("0xdc67c2b8349ca20f58760e08371fc9271e82b5a4"),
),
(
1_531_366,
1,
false,
address!("0x9a90a517d27a9e60e454c96fefbbe94ff244ed6f"),
),
];
pub(crate) fn patch_mainnet_after_tx(
block_number: u64,
tx_index: u64,
is_system_tx: bool,
changes: &mut HashMap<Address, Account>,
) -> Result<(), BlockExecutionError> {
if MAINNET_PATCHES_AFTER_TX.is_empty() {
return Ok(());
}
let first = MAINNET_PATCHES_AFTER_TX.first().unwrap().0;
let last = MAINNET_PATCHES_AFTER_TX.last().unwrap().0;
if first > block_number || last < block_number {
return Ok(());
}
for (block_num, idx, is_system, address) in MAINNET_PATCHES_AFTER_TX {
if block_number == *block_num && tx_index == *idx && is_system_tx == *is_system {
changes.remove(address);
}
}
Ok(())
}