From b3becf9c7b9689d6f907d2e3da39b978b1462488 Mon Sep 17 00:00:00 2001 From: sprites0 <199826320+sprites0@users.noreply.github.com> Date: Sat, 19 Jul 2025 21:16:54 +0000 Subject: [PATCH 1/3] feat: Support highest_precompile_address --- src/node/evm/config.rs | 20 +++++---- src/node/evm/executor.rs | 38 +++++++++++------ src/node/mod.rs | 1 + src/node/network/block_import/service.rs | 1 + src/node/network/mod.rs | 18 ++++---- src/node/primitives/mod.rs | 26 +++++++++++- src/node/storage/mod.rs | 53 +++++++++++++++--------- src/node/types/mod.rs | 22 +++------- src/node/types/reth_compat.rs | 2 + 9 files changed, 115 insertions(+), 66 deletions(-) diff --git a/src/node/evm/config.rs b/src/node/evm/config.rs index 13085fa03..c06e2bb6c 100644 --- a/src/node/evm/config.rs +++ b/src/node/evm/config.rs @@ -6,7 +6,7 @@ use crate::{ node::{ evm::{executor::is_system_transaction, receipt_builder::RethReceiptBuilder}, primitives::{BlockBody, TransactionSigned}, - types::ReadPrecompileMap, + types::HlExtras, }, HlBlock, HlBlockBody, HlPrimitives, }; @@ -137,7 +137,8 @@ where body: HlBlockBody { inner: BlockBody { transactions, ommers: Default::default(), withdrawals }, sidecars: None, - read_precompile_calls: Some(ctx.read_precompile_calls.clone().into()), + read_precompile_calls: ctx.extras.read_precompile_calls.clone(), + highest_precompile_address: ctx.extras.highest_precompile_address, }, }) } @@ -226,7 +227,7 @@ impl HlBlockExecutorFactory { #[derive(Debug, Clone)] pub struct HlBlockExecutionCtx<'a> { ctx: EthBlockExecutionCtx<'a>, - pub read_precompile_calls: ReadPrecompileMap, + pub extras: HlExtras, } impl BlockExecutorFactory for HlBlockExecutorFactory @@ -372,6 +373,11 @@ where &self, block: &'a SealedBlock>, ) -> ExecutionCtxFor<'a, Self> { + let block_body = block.body(); + let extras = HlExtras { + read_precompile_calls: block_body.read_precompile_calls.clone(), + highest_precompile_address: block_body.highest_precompile_address, + }; HlBlockExecutionCtx { ctx: EthBlockExecutionCtx { parent_hash: block.header().parent_hash, @@ -379,11 +385,7 @@ where ommers: &block.body().ommers, withdrawals: block.body().withdrawals.as_ref().map(Cow::Borrowed), }, - read_precompile_calls: block - .body() - .read_precompile_calls - .clone() - .map_or(ReadPrecompileMap::default(), |calls| calls.into()), + extras, } } @@ -400,7 +402,7 @@ where withdrawals: attributes.withdrawals.map(Cow::Owned), }, // TODO: hacky, double check if this is correct - read_precompile_calls: ReadPrecompileMap::default(), + extras: HlExtras::default(), } } } diff --git a/src/node/evm/executor.rs b/src/node/evm/executor.rs index 19fa4d6da..80a88b154 100644 --- a/src/node/evm/executor.rs +++ b/src/node/evm/executor.rs @@ -26,6 +26,7 @@ use revm::{ result::{ExecutionResult, ResultAndState}, TxEnv, }, + interpreter::instructions::utility::IntoU256, precompile::{PrecompileError, PrecompileOutput, PrecompileResult}, primitives::HashMap, state::Bytecode, @@ -254,30 +255,43 @@ where precompiles_mut.apply_precompile(&address, |_| None); } } - for (address, precompile) in ctx.read_precompile_calls.iter() { + for (address, precompile) in + ctx.extras.read_precompile_calls.clone().unwrap_or_default().0.iter() + { let precompile = precompile.clone(); precompiles_mut.apply_precompile(address, |_| { + let precompiles_map: HashMap = + precompile.iter().map(|(input, result)| (input.clone(), result.clone())).collect(); Some(DynPrecompile::from(move |input: PrecompileInput| -> PrecompileResult { - run_precompile(&precompile, input.data, input.gas) + run_precompile(&precompiles_map, input.data, input.gas) })) }); } - // NOTE: Hotfix for the precompile issue (#17). Remove this once the issue is fixed. - if block_number >= U256::from(7000000) { + // NOTE: This is adapted from hyperliquid-dex/hyper-evm-sync#5 + const WARM_PRECOMPILES_BLOCK_NUMBER: u64 = 8_197_684; + if block_number >= U256::from(WARM_PRECOMPILES_BLOCK_NUMBER) { fill_all_precompiles(ctx, precompiles_mut); } } +fn address_to_u64(address: Address) -> u64 { + address.into_u256().try_into().unwrap() +} + fn fill_all_precompiles<'a>(ctx: &HlBlockExecutionCtx<'a>, precompiles_mut: &mut PrecompilesMap) { - for address in 0x800..=0x80D { + let lowest_address = 0x800; + let highest_address = ctx.extras.highest_precompile_address.map_or(0x80D, address_to_u64); + for address in lowest_address..=highest_address { let address = Address::from(U160::from(address)); - if !ctx.read_precompile_calls.contains_key(&address) { - precompiles_mut.apply_precompile(&address, |_| { - Some(DynPrecompile::from(move |_: PrecompileInput| -> PrecompileResult { - Err(PrecompileError::OutOfGas) - })) - }); - } + precompiles_mut.apply_precompile(&address, |f| { + if let Some(precompile) = f { + return Some(precompile); + } + + Some(DynPrecompile::from(move |_: PrecompileInput| -> PrecompileResult { + Err(PrecompileError::OutOfGas) + })) + }); } } diff --git a/src/node/mod.rs b/src/node/mod.rs index 535592cc9..cfa9418d9 100644 --- a/src/node/mod.rs +++ b/src/node/mod.rs @@ -160,6 +160,7 @@ where }, sidecars: None, read_precompile_calls: None, + highest_precompile_address: None, }, } } diff --git a/src/node/network/block_import/service.rs b/src/node/network/block_import/service.rs index 55e4c42f2..43bb23bef 100644 --- a/src/node/network/block_import/service.rs +++ b/src/node/network/block_import/service.rs @@ -401,6 +401,7 @@ mod tests { }, sidecars: None, read_precompile_calls: None, + highest_precompile_address: None, }, }; let new_block = HlNewBlock(NewBlock { block, td: U128::from(1) }); diff --git a/src/node/network/mod.rs b/src/node/network/mod.rs index ef2e7eb1e..75b8f689a 100644 --- a/src/node/network/mod.rs +++ b/src/node/network/mod.rs @@ -42,7 +42,7 @@ mod rlp { HlBlockBody, }; use alloy_consensus::{BlobTransactionSidecar, Header}; - use alloy_primitives::U128; + use alloy_primitives::{Address, U128}; use alloy_rlp::{RlpDecodable, RlpEncodable}; use alloy_rpc_types::Withdrawals; use std::borrow::Cow; @@ -63,6 +63,7 @@ mod rlp { td: U128, sidecars: Option>>, read_precompile_calls: Option>, + highest_precompile_address: Option>, } impl<'a> From<&'a HlNewBlock> for HlNewBlockHelper<'a> { @@ -76,6 +77,7 @@ mod rlp { inner: BlockBody { transactions, ommers, withdrawals }, sidecars, read_precompile_calls, + highest_precompile_address, }, }, td, @@ -91,6 +93,7 @@ mod rlp { td: *td, sidecars: sidecars.as_ref().map(Cow::Borrowed), read_precompile_calls: read_precompile_calls.as_ref().map(Cow::Borrowed), + highest_precompile_address: highest_precompile_address.as_ref().map(Cow::Borrowed), } } } @@ -112,6 +115,7 @@ mod rlp { td, sidecars, read_precompile_calls, + highest_precompile_address, } = HlNewBlockHelper::decode(buf)?; Ok(HlNewBlock(NewBlock { @@ -125,6 +129,8 @@ mod rlp { }, sidecars: sidecars.map(|s| s.into_owned()), read_precompile_calls: read_precompile_calls.map(|s| s.into_owned()), + highest_precompile_address: highest_precompile_address + .map(|s| s.into_owned()), }, }, td, @@ -231,13 +237,9 @@ where ctx.task_executor().spawn_critical("pseudo peer", async move { let block_source = block_source_config.create_cached_block_source().await; - start_pseudo_peer( - chain_spec, - local_node_record.to_string(), - block_source, - ) - .await - .unwrap(); + start_pseudo_peer(chain_spec, local_node_record.to_string(), block_source) + .await + .unwrap(); }); Ok(handle) diff --git a/src/node/primitives/mod.rs b/src/node/primitives/mod.rs index 6068034a3..360ac0440 100644 --- a/src/node/primitives/mod.rs +++ b/src/node/primitives/mod.rs @@ -1,5 +1,6 @@ #![allow(clippy::owned_cow)] use alloy_consensus::{BlobTransactionSidecar, Header}; +use alloy_primitives::Address; use alloy_rlp::{Encodable, RlpDecodable, RlpEncodable}; use reth_ethereum_primitives::Receipt; use reth_primitives::NodePrimitives; @@ -45,6 +46,7 @@ pub struct HlBlockBody { pub inner: BlockBody, pub sidecars: Option>, pub read_precompile_calls: Option, + pub highest_precompile_address: Option
, } impl InMemorySize for HlBlockBody { @@ -135,6 +137,7 @@ impl Block for HlBlock { withdrawals: body.inner.withdrawals.as_ref().map(Cow::Borrowed), sidecars: body.sidecars.as_ref().map(Cow::Borrowed), read_precompile_calls: body.read_precompile_calls.as_ref().map(Cow::Borrowed), + highest_precompile_address: body.highest_precompile_address.as_ref().map(Cow::Borrowed), } .length() } @@ -153,6 +156,7 @@ mod rlp { withdrawals: Option>, sidecars: Option>>, read_precompile_calls: Option>, + highest_precompile_address: Option>, } #[derive(RlpEncodable, RlpDecodable)] @@ -164,6 +168,7 @@ mod rlp { pub(crate) withdrawals: Option>, pub(crate) sidecars: Option>>, pub(crate) read_precompile_calls: Option>, + pub(crate) highest_precompile_address: Option>, } impl<'a> From<&'a HlBlockBody> for BlockBodyHelper<'a> { @@ -172,6 +177,7 @@ mod rlp { inner: BlockBody { transactions, ommers, withdrawals }, sidecars, read_precompile_calls, + highest_precompile_address, } = value; Self { @@ -180,6 +186,7 @@ mod rlp { withdrawals: withdrawals.as_ref().map(Cow::Borrowed), sidecars: sidecars.as_ref().map(Cow::Borrowed), read_precompile_calls: read_precompile_calls.as_ref().map(Cow::Borrowed), + highest_precompile_address: highest_precompile_address.as_ref().map(Cow::Borrowed), } } } @@ -193,6 +200,7 @@ mod rlp { inner: BlockBody { transactions, ommers, withdrawals }, sidecars, read_precompile_calls, + highest_precompile_address, }, } = value; @@ -203,6 +211,7 @@ mod rlp { withdrawals: withdrawals.as_ref().map(Cow::Borrowed), sidecars: sidecars.as_ref().map(Cow::Borrowed), read_precompile_calls: read_precompile_calls.as_ref().map(Cow::Borrowed), + highest_precompile_address: highest_precompile_address.as_ref().map(Cow::Borrowed), } } } @@ -225,6 +234,7 @@ mod rlp { withdrawals, sidecars, read_precompile_calls, + highest_precompile_address, } = BlockBodyHelper::decode(buf)?; Ok(Self { inner: BlockBody { @@ -234,6 +244,7 @@ mod rlp { }, sidecars: sidecars.map(|s| s.into_owned()), read_precompile_calls: read_precompile_calls.map(|s| s.into_owned()), + highest_precompile_address: highest_precompile_address.map(|s| s.into_owned()), }) } } @@ -257,6 +268,7 @@ mod rlp { withdrawals, sidecars, read_precompile_calls, + highest_precompile_address, } = BlockHelper::decode(buf)?; Ok(Self { header: header.into_owned(), @@ -268,6 +280,7 @@ mod rlp { }, sidecars: sidecars.map(|s| s.into_owned()), read_precompile_calls: read_precompile_calls.map(|s| s.into_owned()), + highest_precompile_address: highest_precompile_address.map(|s| s.into_owned()), }, }) } @@ -283,6 +296,7 @@ pub mod serde_bincode_compat { inner: BincodeReprFor<'a, BlockBody>, sidecars: Option>>, read_precompile_calls: Option>, + highest_precompile_address: Option>, } #[derive(Debug, Serialize, Deserialize)] @@ -299,15 +313,25 @@ pub mod serde_bincode_compat { inner: self.inner.as_repr(), sidecars: self.sidecars.as_ref().map(Cow::Borrowed), read_precompile_calls: self.read_precompile_calls.as_ref().map(Cow::Borrowed), + highest_precompile_address: self + .highest_precompile_address + .as_ref() + .map(Cow::Borrowed), } } fn from_repr(repr: Self::BincodeRepr<'_>) -> Self { - let HlBlockBodyBincode { inner, sidecars, read_precompile_calls } = repr; + let HlBlockBodyBincode { + inner, + sidecars, + read_precompile_calls, + highest_precompile_address, + } = repr; Self { inner: BlockBody::from_repr(inner), sidecars: sidecars.map(|s| s.into_owned()), read_precompile_calls: read_precompile_calls.map(|s| s.into_owned()), + highest_precompile_address: highest_precompile_address.map(|s| s.into_owned()), } } } diff --git a/src/node/storage/mod.rs b/src/node/storage/mod.rs index 6540a78e8..3a1a992f3 100644 --- a/src/node/storage/mod.rs +++ b/src/node/storage/mod.rs @@ -1,7 +1,7 @@ use crate::{ node::{ primitives::tx_wrapper::{convert_to_eth_block_body, convert_to_hl_block_body}, - types::ReadPrecompileCalls, + types::HlExtras, }, HlBlock, HlBlockBody, HlPrimitives, }; @@ -29,23 +29,20 @@ impl HlStorage { fn write_precompile_calls( &self, provider: &Provider, - inputs: Vec<(u64, Option)>, + inputs: Vec<(u64, HlExtras)>, ) -> ProviderResult<()> where Provider: DBProvider, { - let mut precompile_calls_cursor = - provider.tx_ref().cursor_write::()?; + let mut precompile_calls_cursor: <::Tx as DbTxMut>::CursorMut< + tables::BlockReadPrecompileCalls, + > = provider.tx_ref().cursor_write::()?; - for (block_number, read_precompile_calls) in inputs { - let Some(read_precompile_calls) = read_precompile_calls else { - continue; - }; + for (block_number, extras) in inputs { precompile_calls_cursor.append( block_number, &Bytes::copy_from_slice( - &rmp_serde::to_vec(&read_precompile_calls) - .expect("Failed to serialize read precompile calls"), + &rmp_serde::to_vec(&extras).expect("Failed to serialize read precompile calls"), ), )?; } @@ -57,11 +54,11 @@ impl HlStorage { &self, provider: &Provider, inputs: &[ReadBodyInput<'_, HlBlock>], - ) -> ProviderResult>> + ) -> ProviderResult> where Provider: DBProvider, { - let mut read_precompile_calls = Vec::with_capacity(inputs.len()); + let mut extras: Vec = Vec::with_capacity(inputs.len()); let mut precompile_calls_cursor = provider.tx_ref().cursor_read::()?; @@ -69,11 +66,12 @@ impl HlStorage { let precompile_calls = precompile_calls_cursor .seek_exact(header.number())? .map(|(_, calls)| calls) - .map(|calls| rmp_serde::from_slice(&calls).unwrap()); - read_precompile_calls.push(precompile_calls); + .map(|calls| rmp_serde::from_slice(&calls).unwrap()) + .unwrap_or_default(); + extras.push(precompile_calls); } - Ok(read_precompile_calls) + Ok(extras) } } @@ -92,13 +90,27 @@ where for (block_number, body) in bodies { match body { - Some(HlBlockBody { inner, sidecars: _, read_precompile_calls: rpc }) => { + Some(HlBlockBody { + inner, + sidecars: _, + read_precompile_calls: rpc, + highest_precompile_address, + }) => { eth_bodies.push((block_number, Some(convert_to_eth_block_body(inner)))); - read_precompile_calls.push((block_number, rpc)); + read_precompile_calls.push(( + block_number, + HlExtras { read_precompile_calls: rpc, highest_precompile_address }, + )); } None => { eth_bodies.push((block_number, None)); - read_precompile_calls.push((block_number, None)); + read_precompile_calls.push(( + block_number, + HlExtras { + read_precompile_calls: Default::default(), + highest_precompile_address: None, + }, + )); } } } @@ -148,10 +160,11 @@ where Ok(eth_bodies .into_iter() .zip(read_precompile_calls) - .map(|(inner, read_precompile_calls)| HlBlockBody { + .map(|(inner, extra)| HlBlockBody { inner: convert_to_hl_block_body(inner), sidecars: None, - read_precompile_calls, + read_precompile_calls: extra.read_precompile_calls, + highest_precompile_address: extra.highest_precompile_address, }) .collect()) } diff --git a/src/node/types/mod.rs b/src/node/types/mod.rs index ed4f05220..93f9c072e 100644 --- a/src/node/types/mod.rs +++ b/src/node/types/mod.rs @@ -5,7 +5,6 @@ use alloy_primitives::{Address, Bytes, Log, B256}; use alloy_rlp::{Decodable, Encodable, RlpDecodable, RlpEncodable}; use bytes::BufMut; -use revm::primitives::HashMap; use serde::{Deserialize, Serialize}; use crate::{node::spot_meta::MAINNET_CHAIN_ID, HlBlock}; @@ -14,24 +13,13 @@ pub type ReadPrecompileCall = (Address, Vec<(ReadPrecompileInput, ReadPrecompile #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, Default)] pub struct ReadPrecompileCalls(pub Vec); -pub type ReadPrecompileMap = HashMap>; mod reth_compat; -impl From for ReadPrecompileMap { - fn from(calls: ReadPrecompileCalls) -> Self { - calls.0.into_iter().map(|(address, calls)| (address, calls.into_iter().collect())).collect() - } -} - -impl From for ReadPrecompileCalls { - fn from(map: ReadPrecompileMap) -> Self { - Self( - map.into_iter() - .map(|(address, calls)| (address, calls.into_iter().collect())) - .collect(), - ) - } +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct HlExtras { + pub read_precompile_calls: Option, + pub highest_precompile_address: Option
, } impl Encodable for ReadPrecompileCalls { @@ -58,6 +46,7 @@ pub struct BlockAndReceipts { pub system_txs: Vec, #[serde(default)] pub read_precompile_calls: ReadPrecompileCalls, + pub highest_precompile_address: Option
, } impl BlockAndReceipts { @@ -65,6 +54,7 @@ impl BlockAndReceipts { let EvmBlock::Reth115(block) = self.block; block.to_reth_block( self.read_precompile_calls.clone(), + self.highest_precompile_address, self.system_txs.clone(), MAINNET_CHAIN_ID, ) diff --git a/src/node/types/reth_compat.rs b/src/node/types/reth_compat.rs index 1d33472a6..9d35b8ff4 100644 --- a/src/node/types/reth_compat.rs +++ b/src/node/types/reth_compat.rs @@ -112,6 +112,7 @@ impl SealedBlock { pub fn to_reth_block( &self, read_precompile_calls: ReadPrecompileCalls, + highest_precompile_address: Option
, system_txs: Vec, chain_id: u64, ) -> HlBlock { @@ -126,6 +127,7 @@ impl SealedBlock { }, sidecars: None, read_precompile_calls: Some(read_precompile_calls), + highest_precompile_address, }; HlBlock { header: self.header.header.clone(), body: block_body } From 736e0da6203f4a3a144f941a958190de8233b11b Mon Sep 17 00:00:00 2001 From: sprites0 <199826320+sprites0@users.noreply.github.com> Date: Sat, 19 Jul 2025 21:21:48 +0000 Subject: [PATCH 2/3] remove: stale comments --- src/node/storage/tables.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/node/storage/tables.rs b/src/node/storage/tables.rs index 356f752cf..4fd17d76d 100644 --- a/src/node/storage/tables.rs +++ b/src/node/storage/tables.rs @@ -1,16 +1,3 @@ -//! Tables and data models. -//! -//! # Overview -//! -//! This module defines the tables in reth, as well as some table-related abstractions: -//! -//! - [`codecs`] integrates different codecs into [`Encode`] and [`Decode`] -//! - [`models`](crate::models) defines the values written to tables -//! -//! # Database Tour -//! -//! TODO(onbjerg): Find appropriate format for this... - use alloy_primitives::{BlockNumber, Bytes}; use reth_db::{table::TableInfo, tables, TableSet, TableType, TableViewer}; use std::fmt; From 209a806c835e0a4ca5de2f97c02af783eadd5c82 Mon Sep 17 00:00:00 2001 From: sprites0 <199826320+sprites0@users.noreply.github.com> Date: Sat, 19 Jul 2025 21:21:59 +0000 Subject: [PATCH 3/3] chore: lint --- src/hl_node_compliance.rs | 3 ++- src/lib.rs | 2 +- src/node/evm/mod.rs | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hl_node_compliance.rs b/src/hl_node_compliance.rs index 6f29e7d98..272831996 100644 --- a/src/hl_node_compliance.rs +++ b/src/hl_node_compliance.rs @@ -219,7 +219,8 @@ fn not_from_system_tx(log: &Log, provider: &Eth::Provider) -> b !transactions .iter() .filter(|tx| tx.is_system_transaction()) - .map(|tx| *tx.tx_hash()).any(|tx_hash| tx_hash == log.transaction_hash.unwrap()) + .map(|tx| *tx.tx_hash()) + .any(|tx_hash| tx_hash == log.transaction_hash.unwrap()) } /// Helper to convert a serde error into an [`ErrorObject`] diff --git a/src/lib.rs b/src/lib.rs index 1bc2958b1..bfd3fd42c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +pub mod call_forwarder; pub mod chainspec; pub mod consensus; mod evm; @@ -6,6 +7,5 @@ pub mod hl_node_compliance; pub mod node; pub mod pseudo_peer; pub mod tx_forwarder; -pub mod call_forwarder; pub use node::primitives::{HlBlock, HlBlockBody, HlPrimitives}; diff --git a/src/node/evm/mod.rs b/src/node/evm/mod.rs index 3ec468a52..1962969da 100644 --- a/src/node/evm/mod.rs +++ b/src/node/evm/mod.rs @@ -112,7 +112,8 @@ where ) -> Result, Self::Error> { // NOTE: This is used for block traces. // Per hyper-evm-sync, HyperEVM doesn't seem to call this method, so - // - we just return a success result with no changes, which gives the same semantics as HyperEVM. + // - we just return a success result with no changes, which gives the same semantics as + // HyperEVM. // - In a long term (ideally), consider implementing SystemCaller. Ok(ResultAndState::new( ExecutionResult::Success {