Merge pull request #33 from hl-archive-node/refactor/1.6.0-dev

chore: Upgrade to reth v1.6.0-dev
This commit is contained in:
sprites0
2025-08-22 18:40:25 +09:00
committed by GitHub
28 changed files with 1698 additions and 2056 deletions

1850
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -25,86 +25,86 @@ lto = "fat"
codegen-units = 1 codegen-units = 1
[dependencies] [dependencies]
reth = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-cli = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-cli = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-cli-commands = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-cli-commands = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-basic-payload-builder = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-basic-payload-builder = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-db = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-db = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-db-api = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-db-api = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-chainspec = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-chainspec = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-cli-util = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-cli-util = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-discv4 = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-discv4 = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-engine-primitives = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-engine-primitives = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-ethereum-forks = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-ethereum-forks = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-ethereum-payload-builder = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-ethereum-payload-builder = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-ethereum-primitives = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-ethereum-primitives = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-eth-wire = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-eth-wire = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-eth-wire-types = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-eth-wire-types = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-evm = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-evm = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-evm-ethereum = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-evm-ethereum = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-node-core = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-node-core = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-revm = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-revm = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-network = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-network = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-network-p2p = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-network-p2p = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-network-api = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-network-api = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-node-ethereum = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-node-ethereum = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-network-peers = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-network-peers = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-payload-primitives = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-payload-primitives = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-primitives = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-primitives = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-primitives-traits = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-primitives-traits = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-provider = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc", features = ["test-utils"] } reth-provider = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a", features = ["test-utils"] }
reth-rpc = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-rpc = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-rpc-eth-api = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-rpc-eth-api = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-rpc-engine-api = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-rpc-engine-api = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-tracing = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-tracing = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-trie-common = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-trie-common = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-trie-db = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-trie-db = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-codecs = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-codecs = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-transaction-pool = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-transaction-pool = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
reth-stages-types = { git = "https://github.com/sprites0/reth", rev = "fc754e5983f055365325dc9a04632d5ba2c4a8bc" } reth-stages-types = { git = "https://github.com/sprites0/reth", rev = "57f199982fe5911e11be126451b4ea6c1b0a5f4a" }
revm = { version = "26.0.1" } revm = { version = "28.0.1", default-features = false }
# alloy dependencies # alloy dependencies
alloy-genesis = "1.0.13" alloy-genesis = { version = "1.0.23", default-features = false }
alloy-consensus = { version = "1.0.13", features = ["serde"] } alloy-consensus = { version = "1.0.23", default-features = false }
alloy-chains = "0.2.0" alloy-chains = { version = "0.2.5", default-features = false }
alloy-eips = "1.0.13" alloy-eips = { version = "1.0.23", default-features = false }
alloy-evm = "0.12" alloy-evm = { version = "0.18.2", default-features = false }
alloy-json-abi = { version = "1.0.0", default-features = false } alloy-json-abi = { version = "1.3.1", default-features = false }
alloy-json-rpc = { version = "1.0.13", default-features = false } alloy-json-rpc = { version = "1.0.23", default-features = false }
alloy-dyn-abi = "1.2.0" alloy-dyn-abi = "1.3.1"
alloy-network = "1.0.13" alloy-network = { version = "1.0.23", default-features = false }
alloy-primitives = { version = "1.2.0", default-features = false, features = ["map-foldhash"] } alloy-primitives = { version = "1.3.1", default-features = false, features = ["map-foldhash"] }
alloy-rlp = { version = "0.3.10", default-features = false, features = ["core-net"] } alloy-rlp = { version = "0.3.10", default-features = false, features = ["core-net"] }
alloy-rpc-types = { version = "1.0.13", features = ["engine"] } alloy-rpc-types = { version = "1.0.23", features = ["eth"], default-features = false }
alloy-rpc-types-eth = "1.0.13" alloy-rpc-types-eth = { version = "1.0.23", default-features = false }
alloy-rpc-types-engine = "1.0.13" alloy-rpc-types-engine = { version = "1.0.23", default-features = false }
alloy-signer = "1.0.13" alloy-signer = { version = "1.0.23", default-features = false }
alloy-sol-macro = "1.2.0" alloy-sol-macro = "1.3.1"
alloy-sol-types = { version = "1.2.0", default-features = false } alloy-sol-types = { version = "1.3.1", default-features = false }
jsonrpsee = "0.25.1" jsonrpsee = "0.25.1"
jsonrpsee-core = { version = "0.25.1" } jsonrpsee-core = "0.25.1"
jsonrpsee-types = "0.25.1" jsonrpsee-types = "0.25.1"
# misc dependencies # misc dependencies
auto_impl = "1" auto_impl = "1"
async-trait = "0.1" async-trait = "0.1.68"
bytes = "1.5" bytes = { version = "1.5", default-features = false }
clap = { version = "4", features = ["derive"] } clap = { version = "4", features = ["derive"] }
cfg-if = { version = "1.0", default-features = false } cfg-if = { version = "1.0", default-features = false }
derive_more = { version = "2", default-features = false, features = ["full"] } derive_more = { version = "2", default-features = false, features = ["full"] }
eyre = "0.6" eyre = "0.6"
futures = "0.3" futures = "0.3"
lazy_static = "1.4.0" lazy_static = "1.4.0"
once_cell = { version = "1.19", default-features = false, features = ["alloc"] } once_cell = { version = "1.19", default-features = false, features = ["critical-section"] }
parking_lot = "0.12" parking_lot = "0.12"
serde = { version = "1.0", features = ["derive"], default-features = false } serde = { version = "1.0", features = ["derive"], default-features = false }
serde_json = "1.0" serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
thiserror = { version = "2.0.0", default-features = false } thiserror = { version = "2.0.0", default-features = false }
tokio = { version = "1.44.2", features = ["full"] } tokio = { version = "1.44.2", features = ["full"] }
tokio-stream = "0.1" tokio-stream = "0.1.11"
tracing = "0.1" tracing = { version = "0.1.0", default-features = false }
rmp-serde = "1.3" rmp-serde = "1.3"
lz4_flex = "0.11" lz4_flex = "0.11"
ureq = "3.0.12" ureq = "3.0.12"

View File

@ -1,8 +1,8 @@
use alloy_eips::BlockId; use alloy_eips::BlockId;
use alloy_json_rpc::RpcObject;
use alloy_primitives::{Bytes, U256}; use alloy_primitives::{Bytes, U256};
use alloy_rpc_types_eth::{ use alloy_rpc_types_eth::{
state::{EvmOverrides, StateOverride}, state::{EvmOverrides, StateOverride},
transaction::TransactionRequest,
BlockOverrides, BlockOverrides,
}; };
use jsonrpsee::{ use jsonrpsee::{
@ -12,16 +12,17 @@ use jsonrpsee::{
types::{error::INTERNAL_ERROR_CODE, ErrorObject}, types::{error::INTERNAL_ERROR_CODE, ErrorObject},
}; };
use jsonrpsee_core::{async_trait, client::ClientT, ClientError, RpcResult}; use jsonrpsee_core::{async_trait, client::ClientT, ClientError, RpcResult};
use reth_rpc_eth_api::helpers::EthCall; use reth_rpc::eth::EthApiTypes;
use reth_rpc_eth_api::{helpers::EthCall, RpcTxReq};
#[rpc(server, namespace = "eth")] #[rpc(server, namespace = "eth")]
pub(crate) trait CallForwarderApi { pub(crate) trait CallForwarderApi<TxReq: RpcObject> {
/// Executes a new message call immediately without creating a transaction on the block chain. /// Executes a new message call immediately without creating a transaction on the block chain.
#[method(name = "call")] #[method(name = "call")]
async fn call( async fn call(
&self, &self,
request: TransactionRequest, request: TxReq,
block_number: Option<BlockId>, block_id: Option<BlockId>,
state_overrides: Option<StateOverride>, state_overrides: Option<StateOverride>,
block_overrides: Option<Box<BlockOverrides>>, block_overrides: Option<Box<BlockOverrides>>,
) -> RpcResult<Bytes>; ) -> RpcResult<Bytes>;
@ -31,8 +32,8 @@ pub(crate) trait CallForwarderApi {
#[method(name = "estimateGas")] #[method(name = "estimateGas")]
async fn estimate_gas( async fn estimate_gas(
&self, &self,
request: TransactionRequest, request: TxReq,
block_number: Option<BlockId>, block_id: Option<BlockId>,
state_override: Option<StateOverride>, state_override: Option<StateOverride>,
) -> RpcResult<U256>; ) -> RpcResult<U256>;
} }
@ -52,23 +53,24 @@ impl<EthApi> CallForwarderExt<EthApi> {
} }
#[async_trait] #[async_trait]
impl<EthApi> CallForwarderApiServer for CallForwarderExt<EthApi> impl<EthApi> CallForwarderApiServer<RpcTxReq<<EthApi as EthApiTypes>::NetworkTypes>>
for CallForwarderExt<EthApi>
where where
EthApi: EthCall + Send + Sync + 'static, EthApi: EthCall + Send + Sync + 'static,
{ {
async fn call( async fn call(
&self, &self,
request: TransactionRequest, request: RpcTxReq<<EthApi as EthApiTypes>::NetworkTypes>,
block_number: Option<BlockId>, block_id: Option<BlockId>,
state_overrides: Option<StateOverride>, state_overrides: Option<StateOverride>,
block_overrides: Option<Box<BlockOverrides>>, block_overrides: Option<Box<BlockOverrides>>,
) -> RpcResult<Bytes> { ) -> RpcResult<Bytes> {
let is_latest = block_number.as_ref().map(|b| b.is_latest()).unwrap_or(true); let is_latest = block_id.as_ref().map(|b| b.is_latest()).unwrap_or(true);
let result = if is_latest { let result = if is_latest {
self.upstream_client self.upstream_client
.request( .request(
"eth_call", "eth_call",
rpc_params![request, block_number, state_overrides, block_overrides], rpc_params![request, block_id, state_overrides, block_overrides],
) )
.await .await
.map_err(|e| match e { .map_err(|e| match e {
@ -83,7 +85,7 @@ where
EthCall::call( EthCall::call(
&self.eth_api, &self.eth_api,
request, request,
block_number, block_id,
EvmOverrides::new(state_overrides, block_overrides), EvmOverrides::new(state_overrides, block_overrides),
) )
.await .await
@ -97,14 +99,14 @@ where
async fn estimate_gas( async fn estimate_gas(
&self, &self,
request: TransactionRequest, request: RpcTxReq<<EthApi as EthApiTypes>::NetworkTypes>,
block_number: Option<BlockId>, block_id: Option<BlockId>,
state_override: Option<StateOverride>, state_override: Option<StateOverride>,
) -> RpcResult<U256> { ) -> RpcResult<U256> {
let is_latest = block_number.as_ref().map(|b| b.is_latest()).unwrap_or(true); let is_latest = block_id.as_ref().map(|b| b.is_latest()).unwrap_or(true);
let result = if is_latest { let result = if is_latest {
self.upstream_client self.upstream_client
.request("eth_estimateGas", rpc_params![request, block_number, state_override]) .request("eth_estimateGas", rpc_params![request, block_id, state_override])
.await .await
.map_err(|e| match e { .map_err(|e| match e {
ClientError::Call(e) => e, ClientError::Call(e) => e,
@ -118,7 +120,7 @@ where
EthCall::estimate_gas_at( EthCall::estimate_gas_at(
&self.eth_api, &self.eth_api,
request, request,
block_number.unwrap_or_default(), block_id.unwrap_or_default(),
state_override, state_override,
) )
.await .await

View File

@ -15,6 +15,9 @@ use reth_discv4::NodeRecord;
use reth_evm::eth::spec::EthExecutorSpec; use reth_evm::eth::spec::EthExecutorSpec;
use std::{fmt::Display, sync::Arc}; use std::{fmt::Display, sync::Arc};
pub const MAINNET_CHAIN_ID: u64 = 999;
pub const TESTNET_CHAIN_ID: u64 = 998;
/// Hl chain spec type. /// Hl chain spec type.
#[derive(Debug, Default, Clone, PartialEq, Eq)] #[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct HlChainSpec { pub struct HlChainSpec {
@ -144,8 +147,8 @@ impl HlChainSpec {
pub fn official_rpc_url(&self) -> &'static str { pub fn official_rpc_url(&self) -> &'static str {
match self.inner.chain().id() { match self.inner.chain().id() {
999 => Self::MAINNET_RPC_URL, MAINNET_CHAIN_ID => Self::MAINNET_RPC_URL,
998 => Self::TESTNET_RPC_URL, TESTNET_CHAIN_ID => Self::TESTNET_RPC_URL,
_ => unreachable!("Unreachable since ChainSpecParser won't return other chains"), _ => unreachable!("Unreachable since ChainSpecParser won't return other chains"),
} }
} }

View File

@ -1,4 +1,5 @@
use revm::{ use revm::{
bytecode::opcode::BLOCKHASH,
context::{ContextSetters, Evm, FrameStack}, context::{ContextSetters, Evm, FrameStack},
context_interface::ContextTr, context_interface::ContextTr,
handler::{ handler::{
@ -7,13 +8,16 @@ use revm::{
EthFrame, EthPrecompiles, EvmTr, FrameInitOrResult, FrameTr, PrecompileProvider, EthFrame, EthPrecompiles, EvmTr, FrameInitOrResult, FrameTr, PrecompileProvider,
}, },
inspector::{InspectorEvmTr, JournalExt}, inspector::{InspectorEvmTr, JournalExt},
interpreter::{interpreter::EthInterpreter, InterpreterResult}, interpreter::{interpreter::EthInterpreter, Instruction, InterpreterResult},
Inspector, Inspector,
}; };
use crate::chainspec::MAINNET_CHAIN_ID;
pub mod builder; pub mod builder;
pub mod ctx; pub mod ctx;
mod exec; mod exec;
mod patch;
pub struct HlEvmInner< pub struct HlEvmInner<
CTX: ContextTr, CTX: ContextTr,
@ -26,10 +30,22 @@ impl<CTX: ContextTr, INSP>
HlEvmInner<CTX, INSP, EthInstructions<EthInterpreter, CTX>, EthPrecompiles> HlEvmInner<CTX, INSP, EthInstructions<EthInterpreter, CTX>, EthPrecompiles>
{ {
pub fn new(ctx: CTX, inspector: INSP) -> Self { pub fn new(ctx: CTX, inspector: INSP) -> Self {
let mut instruction = EthInstructions::new_mainnet();
const NON_PLACEHOLDER_BLOCK_HASH_HEIGHT: u64 = 243_538;
if ctx.chain_id() == MAINNET_CHAIN_ID &&
ctx.block_number() < NON_PLACEHOLDER_BLOCK_HASH_HEIGHT
{
instruction.insert_instruction(
BLOCKHASH,
Instruction::new(patch::blockhash_returning_placeholder, 20),
);
}
Self(Evm { Self(Evm {
ctx, ctx,
inspector, inspector,
instruction: EthInstructions::new_mainnet(), instruction,
precompiles: EthPrecompiles::default(), precompiles: EthPrecompiles::default(),
frame_stack: FrameStack::new(), frame_stack: FrameStack::new(),
}) })
@ -125,23 +141,3 @@ where
self.0.frame_return_result(result) self.0.frame_return_result(result)
} }
} }
// #[cfg(test)]
// mod test {
// use super::{builder::HlBuilder, ctx::DefaultHl};
// use revm::{
// inspector::{InspectEvm, NoOpInspector},
// Context, ExecuteEvm,
// };
// #[test]
// fn default_run_bsc() {
// let ctx = Context::bsc();
// let mut evm = ctx.build_bsc_with_inspector(NoOpInspector {});
// // execute
// let _ = evm.replay();
// // inspect
// let _ = evm.inspect_replay();
// }
// }

73
src/evm/api/patch.rs Normal file
View File

@ -0,0 +1,73 @@
//! Modified version of `blockhash` instruction before block `243538`.
//!
//! This is a mainnet-specific fix for the `blockhash` instruction,
//! copied and modified from revm-interpreter-25.0.1/src/instructions/host.rs.
use alloy_primitives::keccak256;
use revm::{
context::Host,
interpreter::{
as_u64_saturated, interpreter_types::StackTr, popn_top, InstructionContext,
InterpreterTypes,
},
primitives::{BLOCK_HASH_HISTORY, U256},
};
#[doc(hidden)]
#[macro_export]
#[collapse_debuginfo(yes)]
macro_rules! _count {
(@count) => { 0 };
(@count $head:tt $($tail:tt)*) => { 1 + _count!(@count $($tail)*) };
($($arg:tt)*) => { _count!(@count $($arg)*) };
}
/// Pops n values from the stack and returns the top value. Fails the instruction if n values can't
/// be popped.
#[macro_export]
#[collapse_debuginfo(yes)]
macro_rules! popn_top {
([ $($x:ident),* ], $top:ident, $interpreter:expr $(,$ret:expr)? ) => {
// Workaround for https://github.com/rust-lang/rust/issues/144329.
if $interpreter.stack.len() < (1 + $crate::_count!($($x)*)) {
$interpreter.halt_underflow();
return $($ret)?;
}
let ([$( $x ),*], $top) = unsafe { $interpreter.stack.popn_top().unwrap_unchecked() };
};
}
/// Implements the BLOCKHASH instruction.
///
/// Gets the hash of one of the 256 most recent complete blocks.
pub fn blockhash_returning_placeholder<WIRE: InterpreterTypes, H: Host + ?Sized>(
context: InstructionContext<'_, H, WIRE>,
) {
//gas!(context.interpreter, gas::BLOCKHASH);
popn_top!([], number, context.interpreter);
let requested_number = *number;
let block_number = context.host.block_number();
let Some(diff) = block_number.checked_sub(requested_number) else {
*number = U256::ZERO;
return;
};
let diff = as_u64_saturated!(diff);
// blockhash should push zero if number is same as current block number.
if diff == 0 {
*number = U256::ZERO;
return;
}
*number = if diff <= BLOCK_HASH_HISTORY {
// NOTE: This is HL-specific modifcation that returns the placeholder hash before specific
// block.
let hash = keccak256(as_u64_saturated!(requested_number).to_string().as_bytes());
U256::from_be_bytes(hash.0)
} else {
U256::ZERO
}
}

View File

@ -4,8 +4,6 @@ use std::str::FromStr;
#[repr(u8)] #[repr(u8)]
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Default)] #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[allow(non_camel_case_types)]
#[allow(clippy::upper_case_acronyms)]
pub enum HlSpecId { pub enum HlSpecId {
#[default] #[default]
V1, // V1 V1, // V1

View File

@ -13,7 +13,7 @@ use revm::{
#[auto_impl(&, &mut, Box, Arc)] #[auto_impl(&, &mut, Box, Arc)]
pub trait HlTxTr: Transaction {} pub trait HlTxTr: Transaction {}
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct HlTxEnv<T: Transaction> { pub struct HlTxEnv<T: Transaction> {
pub base: T, pub base: T,
@ -25,12 +25,6 @@ impl<T: Transaction> HlTxEnv<T> {
} }
} }
impl Default for HlTxEnv<TxEnv> {
fn default() -> Self {
Self { base: TxEnv::default() }
}
}
impl<T: Transaction> Transaction for HlTxEnv<T> { impl<T: Transaction> Transaction for HlTxEnv<T> {
type AccessListItem<'a> type AccessListItem<'a>
= T::AccessListItem<'a> = T::AccessListItem<'a>

View File

@ -1,36 +1,35 @@
/// We need to override the following methods:
/// Filter:
/// - eth_getLogs
/// - eth_subscribe
///
/// Block (handled by HlEthApi already):
/// - eth_getBlockByNumber/eth_getBlockByHash
/// - eth_getBlockReceipts
use crate::HlBlock;
use alloy_consensus::TxReceipt; use alloy_consensus::TxReceipt;
use alloy_eips::{BlockId, BlockNumberOrTag};
use alloy_json_rpc::RpcObject;
use alloy_network::ReceiptResponse;
use alloy_primitives::{B256, U256};
use alloy_rpc_types::{ use alloy_rpc_types::{
pubsub::{Params, SubscriptionKind}, pubsub::{Params, SubscriptionKind},
Filter, FilterChanges, FilterId, Log, PendingTransactionFilterKind, BlockTransactions, Filter, FilterChanges, FilterId, Log, PendingTransactionFilterKind,
}; };
use jsonrpsee::{PendingSubscriptionSink, SubscriptionMessage, SubscriptionSink}; use jsonrpsee::{proc_macros::rpc, PendingSubscriptionSink, SubscriptionMessage, SubscriptionSink};
use jsonrpsee_core::{async_trait, RpcResult}; use jsonrpsee_core::{async_trait, RpcResult};
use jsonrpsee_types::ErrorObject; use jsonrpsee_types::ErrorObject;
use reth::{ use reth::{
api::FullNodeComponents, builder::rpc::RpcContext, rpc::result::internal_rpc_err, api::FullNodeComponents, builder::rpc::RpcContext, rpc::result::internal_rpc_err,
tasks::TaskSpawner, tasks::TaskSpawner,
}; };
use reth_network::NetworkInfo; use reth_primitives_traits::BlockBody as _;
use reth_primitives::NodePrimitives; use reth_provider::{BlockIdReader, BlockReader, BlockReaderIdExt, ReceiptProvider};
use reth_provider::{BlockIdReader, BlockReader, ReceiptProvider, TransactionsProvider};
use reth_rpc::{EthFilter, EthPubSub}; use reth_rpc::{EthFilter, EthPubSub};
use reth_rpc_eth_api::{ use reth_rpc_eth_api::{
EthApiServer, EthFilterApiServer, EthPubSubApiServer, FullEthApiTypes, RpcBlock, RpcHeader, EthApiServer, EthApiTypes, EthFilterApiServer, EthPubSubApiServer, FullEthApiTypes, RpcBlock,
RpcNodeCore, RpcNodeCoreExt, RpcReceipt, RpcTransaction, RpcTxReq, RpcHeader, RpcNodeCore, RpcNodeCoreExt, RpcReceipt, RpcTransaction, RpcTxReq,
}; };
use serde::Serialize; use serde::Serialize;
use std::sync::Arc; use std::{marker::PhantomData, sync::Arc};
use tokio_stream::{Stream, StreamExt}; use tokio_stream::{Stream, StreamExt};
use tracing::trace; use tracing::{trace, Instrument};
use crate::{
node::primitives::{HlPrimitives, TransactionSigned},
HlBlock,
};
pub trait EthWrapper: pub trait EthWrapper:
EthApiServer< EthApiServer<
@ -39,34 +38,25 @@ pub trait EthWrapper:
RpcBlock<Self::NetworkTypes>, RpcBlock<Self::NetworkTypes>,
RpcReceipt<Self::NetworkTypes>, RpcReceipt<Self::NetworkTypes>,
RpcHeader<Self::NetworkTypes>, RpcHeader<Self::NetworkTypes>,
> + FullEthApiTypes > + FullEthApiTypes<Primitives = HlPrimitives>
+ RpcNodeCoreExt< + RpcNodeCoreExt<Provider: BlockReader<Block = HlBlock>>
Provider: BlockIdReader + BlockReader<Block = HlBlock>, + 'static
Primitives: NodePrimitives<
SignedTx = <<Self as RpcNodeCore>::Provider as TransactionsProvider>::Transaction,
>,
Network: NetworkInfo,
> + 'static
{ {
} }
impl< impl<
T: T: EthApiServer<
EthApiServer<
RpcTxReq<Self::NetworkTypes>, RpcTxReq<Self::NetworkTypes>,
RpcTransaction<Self::NetworkTypes>, RpcTransaction<Self::NetworkTypes>,
RpcBlock<Self::NetworkTypes>, RpcBlock<Self::NetworkTypes>,
RpcReceipt<Self::NetworkTypes>, RpcReceipt<Self::NetworkTypes>,
RpcHeader<Self::NetworkTypes>, RpcHeader<Self::NetworkTypes>,
> + FullEthApiTypes > + FullEthApiTypes<Primitives = HlPrimitives>
+ RpcNodeCoreExt< + RpcNodeCoreExt
Provider: BlockIdReader + BlockReader<Block = HlBlock>, + RpcNodeCore<Provider: BlockReader<Block = HlBlock>>
Primitives: NodePrimitives< + 'static,
SignedTx = <<Self as RpcNodeCore>::Provider as TransactionsProvider>::Transaction, > EthWrapper for T
>, {
Network: NetworkInfo,
> + 'static
> EthWrapper for T {
} }
pub struct HlNodeFilterHttp<Eth: EthWrapper> { pub struct HlNodeFilterHttp<Eth: EthWrapper> {
@ -283,6 +273,146 @@ where
} }
} }
pub struct HlNodeBlockFilterHttp<Eth: EthWrapper> {
eth_api: Arc<Eth>,
_marker: PhantomData<Eth>,
}
impl<Eth: EthWrapper> HlNodeBlockFilterHttp<Eth> {
pub fn new(eth_api: Arc<Eth>) -> Self {
Self { eth_api, _marker: PhantomData }
}
}
#[rpc(server, namespace = "eth")]
pub trait EthBlockApi<B: RpcObject, R: RpcObject> {
/// Returns information about a block by hash.
#[method(name = "getBlockByHash")]
async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult<Option<B>>;
/// Returns information about a block by number.
#[method(name = "getBlockByNumber")]
async fn block_by_number(&self, number: BlockNumberOrTag, full: bool) -> RpcResult<Option<B>>;
/// Returns all transaction receipts for a given block.
#[method(name = "getBlockReceipts")]
async fn block_receipts(&self, block_id: BlockId) -> RpcResult<Option<Vec<R>>>;
#[method(name = "getBlockTransactionCountByHash")]
async fn block_transaction_count_by_hash(&self, hash: B256) -> RpcResult<Option<U256>>;
#[method(name = "getBlockTransactionCountByNumber")]
async fn block_transaction_count_by_number(
&self,
number: BlockNumberOrTag,
) -> RpcResult<Option<U256>>;
}
macro_rules! engine_span {
() => {
tracing::trace_span!(target: "rpc", "engine")
};
}
fn is_system_tx(tx: &TransactionSigned) -> bool {
tx.is_system_transaction()
}
fn exclude_system_tx_from_block<Eth: EthWrapper>(
recovered_block: &RpcBlock<Eth::NetworkTypes>,
eth_api: &Eth,
) -> RpcBlock<Eth::NetworkTypes> {
let system_tx_count = system_tx_count_for_block(eth_api, recovered_block.number().into());
let mut new_block = recovered_block.clone();
new_block.transactions = match new_block.transactions {
BlockTransactions::Full(mut transactions) => {
transactions.drain(..system_tx_count);
BlockTransactions::Full(transactions)
}
BlockTransactions::Hashes(mut hashes) => {
hashes.drain(..system_tx_count);
BlockTransactions::Hashes(hashes)
}
BlockTransactions::Uncle => BlockTransactions::Uncle,
};
new_block
}
fn system_tx_count_for_block<Eth: EthWrapper>(eth_api: &Eth, number: BlockId) -> usize {
let provider = eth_api.provider();
let block = provider.block_by_id(number).unwrap().unwrap();
let system_tx_count = block.body.transactions().iter().filter(|tx| is_system_tx(tx)).count();
system_tx_count
}
#[async_trait]
impl<Eth: EthWrapper> EthBlockApiServer<RpcBlock<Eth::NetworkTypes>, RpcReceipt<Eth::NetworkTypes>>
for HlNodeBlockFilterHttp<Eth>
where
Eth: EthApiTypes + 'static,
{
/// Handler for: `eth_getBlockByHash`
async fn block_by_hash(
&self,
hash: B256,
full: bool,
) -> RpcResult<Option<RpcBlock<Eth::NetworkTypes>>> {
let res = self.eth_api.block_by_hash(hash, full).instrument(engine_span!()).await?;
Ok(res.map(|block| exclude_system_tx_from_block(&block, &*self.eth_api)))
}
/// Handler for: `eth_getBlockByNumber`
async fn block_by_number(
&self,
number: BlockNumberOrTag,
full: bool,
) -> RpcResult<Option<RpcBlock<Eth::NetworkTypes>>> {
trace!(target: "rpc::eth", ?number, ?full, "Serving eth_getBlockByNumber");
let res = self.eth_api.block_by_number(number, full).instrument(engine_span!()).await?;
Ok(res.map(|block| exclude_system_tx_from_block(&block, &*self.eth_api)))
}
/// Handler for: `eth_getBlockTransactionCountByHash`
async fn block_transaction_count_by_hash(&self, hash: B256) -> RpcResult<Option<U256>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getBlockTransactionCountByHash");
let res =
self.eth_api.block_transaction_count_by_hash(hash).instrument(engine_span!()).await?;
Ok(res.map(|count| {
count -
U256::from(system_tx_count_for_block(&*self.eth_api, BlockId::Hash(hash.into())))
}))
}
/// Handler for: `eth_getBlockTransactionCountByNumber`
async fn block_transaction_count_by_number(
&self,
number: BlockNumberOrTag,
) -> RpcResult<Option<U256>> {
trace!(target: "rpc::eth", ?number, "Serving eth_getBlockTransactionCountByNumber");
let res = self
.eth_api
.block_transaction_count_by_number(number)
.instrument(engine_span!())
.await?;
Ok(res.map(|count| {
count - U256::from(system_tx_count_for_block(&*self.eth_api, number.into()))
}))
}
/// Handler for: `eth_getBlockReceipts`
async fn block_receipts(
&self,
block_id: BlockId,
) -> RpcResult<Option<Vec<RpcReceipt<Eth::NetworkTypes>>>> {
trace!(target: "rpc::eth", ?block_id, "Serving eth_getBlockReceipts");
let res = self.eth_api.block_receipts(block_id).instrument(engine_span!()).await?;
Ok(res.map(|receipts| {
receipts.into_iter().filter(|receipt| receipt.cumulative_gas_used() > 0).collect()
}))
}
}
pub fn install_hl_node_compliance<Node, EthApi>( pub fn install_hl_node_compliance<Node, EthApi>(
ctx: RpcContext<Node, EthApi>, ctx: RpcContext<Node, EthApi>,
) -> Result<(), eyre::Error> ) -> Result<(), eyre::Error>
@ -306,5 +436,9 @@ where
) )
.into_rpc(), .into_rpc(),
)?; )?;
ctx.modules.replace_configured(
HlNodeBlockFilterHttp::new(Arc::new(ctx.registry.eth_api().clone())).into_rpc(),
)?;
Ok(()) Ok(())
} }

View File

@ -1,8 +1,11 @@
use std::sync::Arc;
use clap::Parser; use clap::Parser;
use reth::builder::NodeHandle; use reth::builder::{NodeBuilder, NodeHandle, WithLaunchContext};
use reth_db::DatabaseEnv;
use reth_hl::{ use reth_hl::{
call_forwarder::{self, CallForwarderApiServer}, call_forwarder::{self, CallForwarderApiServer},
chainspec::parser::HlChainSpecParser, chainspec::{parser::HlChainSpecParser, HlChainSpec},
hl_node_compliance::install_hl_node_compliance, hl_node_compliance::install_hl_node_compliance,
node::{ node::{
cli::{Cli, HlNodeArgs}, cli::{Cli, HlNodeArgs},
@ -26,12 +29,12 @@ fn main() -> eyre::Result<()> {
std::env::set_var("RUST_BACKTRACE", "1"); std::env::set_var("RUST_BACKTRACE", "1");
} }
Cli::<HlChainSpecParser, HlNodeArgs>::parse().run(|builder, ext| async move { Cli::<HlChainSpecParser, HlNodeArgs>::parse().run(
|builder: WithLaunchContext<NodeBuilder<Arc<DatabaseEnv>, HlChainSpec>>,
ext: HlNodeArgs| async move {
let default_upstream_rpc_url = builder.config().chain.official_rpc_url(); let default_upstream_rpc_url = builder.config().chain.official_rpc_url();
builder.builder.database.create_tables_for::<Tables>()?;
let (node, engine_handle_tx) = let (node, engine_handle_tx) = HlNode::new(ext.block_source_args.parse().await?);
HlNode::new(ext.block_source_args.parse().await?, ext.hl_node_compliant);
let NodeHandle { node, node_exit_future: exit_future } = builder let NodeHandle { node, node_exit_future: exit_future } = builder
.node(node) .node(node)
.extend_rpc_modules(move |ctx| { .extend_rpc_modules(move |ctx| {
@ -61,12 +64,17 @@ fn main() -> eyre::Result<()> {
Ok(()) Ok(())
}) })
.apply(|builder| {
builder.db().create_tables_for::<Tables>().expect("create tables");
builder
})
.launch() .launch()
.await?; .await?;
engine_handle_tx.send(node.beacon_engine_handle.clone()).unwrap(); engine_handle_tx.send(node.beacon_engine_handle.clone()).unwrap();
exit_future.await exit_future.await
})?; },
)?;
Ok(()) Ok(())
} }

View File

@ -1,8 +1,6 @@
use crate::{ use crate::{
chainspec::{parser::HlChainSpecParser, HlChainSpec}, chainspec::{parser::HlChainSpecParser, HlChainSpec},
node::{ node::{consensus::HlConsensus, evm::config::HlEvmConfig, HlNode},
consensus::HlConsensus, evm::config::HlEvmConfig, network::HlNetworkPrimitives, HlNode,
},
pseudo_peer::BlockSourceArgs, pseudo_peer::BlockSourceArgs,
}; };
use clap::{Args, Parser}; use clap::{Args, Parser};
@ -11,7 +9,7 @@ use reth::{
builder::{NodeBuilder, WithLaunchContext}, builder::{NodeBuilder, WithLaunchContext},
cli::Commands, cli::Commands,
prometheus_exporter::install_prometheus_recorder, prometheus_exporter::install_prometheus_recorder,
version::{LONG_VERSION, SHORT_VERSION}, version::version_metadata,
CliRunner, CliRunner,
}; };
use reth_chainspec::EthChainSpec; use reth_chainspec::EthChainSpec;
@ -21,11 +19,16 @@ use reth_db::DatabaseEnv;
use reth_tracing::FileWorkerGuard; use reth_tracing::FileWorkerGuard;
use std::{ use std::{
fmt::{self}, fmt::{self},
future::Future,
sync::Arc, sync::Arc,
}; };
use tracing::info; use tracing::info;
macro_rules! not_applicable {
($command:ident) => {
todo!("{} is not applicable for HL", stringify!($command))
};
}
#[derive(Debug, Clone, Args)] #[derive(Debug, Clone, Args)]
#[non_exhaustive] #[non_exhaustive]
pub struct HlNodeArgs { pub struct HlNodeArgs {
@ -58,7 +61,7 @@ pub struct HlNodeArgs {
/// ///
/// This is the entrypoint to the executable. /// This is the entrypoint to the executable.
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
#[command(author, version = SHORT_VERSION, long_version = LONG_VERSION, about = "Reth", long_about = None)] #[command(author, version =version_metadata().short_version.as_ref(), long_version = version_metadata().long_version.as_ref(), about = "Reth", long_about = None)]
pub struct Cli<Spec: ChainSpecParser = HlChainSpecParser, Ext: clap::Args + fmt::Debug = HlNodeArgs> pub struct Cli<Spec: ChainSpecParser = HlChainSpecParser, Ext: clap::Args + fmt::Debug = HlNodeArgs>
{ {
/// The command to run /// The command to run
@ -78,20 +81,25 @@ where
/// ///
/// This accepts a closure that is used to launch the node via the /// This accepts a closure that is used to launch the node via the
/// [`NodeCommand`](reth_cli_commands::node::NodeCommand). /// [`NodeCommand`](reth_cli_commands::node::NodeCommand).
pub fn run<L, Fut>(self, launcher: L) -> eyre::Result<()> pub fn run(
where self,
L: FnOnce(WithLaunchContext<NodeBuilder<Arc<DatabaseEnv>, C::ChainSpec>>, Ext) -> Fut, launcher: impl AsyncFnOnce(
Fut: Future<Output = eyre::Result<()>>, WithLaunchContext<NodeBuilder<Arc<DatabaseEnv>, C::ChainSpec>>,
{ Ext,
) -> eyre::Result<()>,
) -> eyre::Result<()> {
self.with_runner(CliRunner::try_default_runtime()?, launcher) self.with_runner(CliRunner::try_default_runtime()?, launcher)
} }
/// Execute the configured cli command with the provided [`CliRunner`]. /// Execute the configured cli command with the provided [`CliRunner`].
pub fn with_runner<L, Fut>(mut self, runner: CliRunner, launcher: L) -> eyre::Result<()> pub fn with_runner(
where mut self,
L: FnOnce(WithLaunchContext<NodeBuilder<Arc<DatabaseEnv>, C::ChainSpec>>, Ext) -> Fut, runner: CliRunner,
Fut: Future<Output = eyre::Result<()>>, launcher: impl AsyncFnOnce(
{ WithLaunchContext<NodeBuilder<Arc<DatabaseEnv>, C::ChainSpec>>,
Ext,
) -> eyre::Result<()>,
) -> eyre::Result<()> {
// Add network name if available to the logs dir // Add network name if available to the logs dir
if let Some(chain_spec) = self.command.chain_spec() { if let Some(chain_spec) = self.command.chain_spec() {
self.logs.log_file_directory = self.logs.log_file_directory =
@ -119,11 +127,8 @@ where
} }
Commands::DumpGenesis(command) => runner.run_blocking_until_ctrl_c(command.execute()), Commands::DumpGenesis(command) => runner.run_blocking_until_ctrl_c(command.execute()),
Commands::Db(command) => runner.run_blocking_until_ctrl_c(command.execute::<HlNode>()), Commands::Db(command) => runner.run_blocking_until_ctrl_c(command.execute::<HlNode>()),
Commands::Stage(command) => runner.run_command_until_exit(|ctx| { Commands::Stage(command) => {
command.execute::<HlNode, _, _, HlNetworkPrimitives>(ctx, components) runner.run_command_until_exit(|ctx| command.execute::<HlNode, _>(ctx, components))
}),
Commands::P2P(command) => {
runner.run_until_ctrl_c(command.execute::<HlNetworkPrimitives>())
} }
Commands::Config(command) => runner.run_until_ctrl_c(command.execute()), Commands::Config(command) => runner.run_until_ctrl_c(command.execute()),
Commands::Recover(command) => { Commands::Recover(command) => {
@ -131,17 +136,15 @@ where
} }
Commands::Prune(command) => runner.run_until_ctrl_c(command.execute::<HlNode>()), Commands::Prune(command) => runner.run_until_ctrl_c(command.execute::<HlNode>()),
Commands::Import(command) => { Commands::Import(command) => {
runner.run_blocking_until_ctrl_c(command.execute::<HlNode, _, _>(components)) runner.run_blocking_until_ctrl_c(command.execute::<HlNode, _>(components))
} }
Commands::Debug(_command) => todo!(), Commands::P2P(_command) => not_applicable!(P2P),
Commands::ImportEra(_command) => not_applicable!(ImportEra),
Commands::Download(_command) => not_applicable!(Download),
Commands::ExportEra(_) => not_applicable!(ExportEra),
Commands::ReExecute(_) => not_applicable!(ReExecute),
#[cfg(feature = "dev")] #[cfg(feature = "dev")]
Commands::TestVectors(_command) => todo!(), Commands::TestVectors(_command) => not_applicable!(TestVectors),
Commands::ImportEra(_command) => {
todo!()
}
Commands::Download(_command) => {
todo!()
}
} }
} }

View File

@ -1,4 +1,5 @@
use crate::{hardforks::HlHardforks, node::HlNode, HlBlock, HlBlockBody, HlPrimitives}; use crate::{hardforks::HlHardforks, node::HlNode, HlBlock, HlBlockBody, HlPrimitives};
use alloy_consensus::Header;
use reth::{ use reth::{
api::FullNodeTypes, api::FullNodeTypes,
beacon_consensus::EthBeaconConsensus, beacon_consensus::EthBeaconConsensus,
@ -39,7 +40,10 @@ pub struct HlConsensus<ChainSpec> {
chain_spec: Arc<ChainSpec>, chain_spec: Arc<ChainSpec>,
} }
impl<ChainSpec: EthChainSpec + HlHardforks> HlConsensus<ChainSpec> { impl<ChainSpec> HlConsensus<ChainSpec>
where
ChainSpec: EthChainSpec + HlHardforks,
{
/// Create a new instance of [`HlConsensus`] /// Create a new instance of [`HlConsensus`]
pub fn new(chain_spec: Arc<ChainSpec>) -> Self { pub fn new(chain_spec: Arc<ChainSpec>) -> Self {
Self { inner: EthBeaconConsensus::new(chain_spec.clone()), chain_spec } Self { inner: EthBeaconConsensus::new(chain_spec.clone()), chain_spec }
@ -62,15 +66,19 @@ pub fn validate_against_parent_timestamp<H: BlockHeader>(
Ok(()) Ok(())
} }
impl<ChainSpec: EthChainSpec + HlHardforks> HeaderValidator for HlConsensus<ChainSpec> { impl<H, ChainSpec> HeaderValidator<H> for HlConsensus<ChainSpec>
fn validate_header(&self, header: &SealedHeader) -> Result<(), ConsensusError> { where
H: BlockHeader,
ChainSpec: EthChainSpec<Header = H> + HlHardforks,
{
fn validate_header(&self, header: &SealedHeader<H>) -> Result<(), ConsensusError> {
self.inner.validate_header(header) self.inner.validate_header(header)
} }
fn validate_header_against_parent( fn validate_header_against_parent(
&self, &self,
header: &SealedHeader, header: &SealedHeader<H>,
parent: &SealedHeader, parent: &SealedHeader<H>,
) -> Result<(), ConsensusError> { ) -> Result<(), ConsensusError> {
validate_against_parent_hash_number(header.header(), parent)?; validate_against_parent_hash_number(header.header(), parent)?;
@ -83,7 +91,7 @@ impl<ChainSpec: EthChainSpec + HlHardforks> HeaderValidator for HlConsensus<Chai
// )?; // )?;
// ensure that the blob gas fields for this block // ensure that the blob gas fields for this block
if let Some(blob_params) = self.chain_spec.blob_params_at_timestamp(header.timestamp) { if let Some(blob_params) = self.chain_spec.blob_params_at_timestamp(header.timestamp()) {
validate_against_parent_4844(header.header(), parent.header(), blob_params)?; validate_against_parent_4844(header.header(), parent.header(), blob_params)?;
} }
@ -91,7 +99,10 @@ impl<ChainSpec: EthChainSpec + HlHardforks> HeaderValidator for HlConsensus<Chai
} }
} }
impl<ChainSpec: EthChainSpec + HlHardforks> Consensus<HlBlock> for HlConsensus<ChainSpec> { impl<ChainSpec> Consensus<HlBlock> for HlConsensus<ChainSpec>
where
ChainSpec: EthChainSpec<Header = Header> + HlHardforks,
{
type Error = ConsensusError; type Error = ConsensusError;
fn validate_body_against_header( fn validate_body_against_header(
@ -135,8 +146,9 @@ impl<ChainSpec: EthChainSpec + HlHardforks> Consensus<HlBlock> for HlConsensus<C
mod reth_copy; mod reth_copy;
impl<ChainSpec: EthChainSpec<Header = alloy_consensus::Header> + HlHardforks> impl<ChainSpec> FullConsensus<HlPrimitives> for HlConsensus<ChainSpec>
FullConsensus<HlPrimitives> for HlConsensus<ChainSpec> where
ChainSpec: EthChainSpec<Header = Header> + HlHardforks,
{ {
fn validate_block_post_execution( fn validate_block_post_execution(
&self, &self,

View File

@ -6,12 +6,13 @@ use crate::{
node::{ node::{
evm::{executor::is_system_transaction, receipt_builder::RethReceiptBuilder}, evm::{executor::is_system_transaction, receipt_builder::RethReceiptBuilder},
primitives::{BlockBody, TransactionSigned}, primitives::{BlockBody, TransactionSigned},
rpc::engine_api::validator::HlExecutionData,
types::HlExtras, types::HlExtras,
}, },
HlBlock, HlBlockBody, HlPrimitives, HlBlock, HlBlockBody, HlPrimitives,
}; };
use alloy_consensus::{BlockHeader, Header, Transaction as _, TxReceipt, EMPTY_OMMER_ROOT_HASH}; use alloy_consensus::{BlockHeader, Header, Transaction as _, TxReceipt, EMPTY_OMMER_ROOT_HASH};
use alloy_eips::merge::BEACON_NONCE; use alloy_eips::{merge::BEACON_NONCE, Encodable2718};
use alloy_primitives::{Log, U256}; use alloy_primitives::{Log, U256};
use reth_chainspec::{EthChainSpec, EthereumHardforks, Hardforks}; use reth_chainspec::{EthChainSpec, EthereumHardforks, Hardforks};
use reth_evm::{ use reth_evm::{
@ -19,12 +20,13 @@ use reth_evm::{
eth::{receipt_builder::ReceiptBuilder, EthBlockExecutionCtx}, eth::{receipt_builder::ReceiptBuilder, EthBlockExecutionCtx},
execute::{BlockAssembler, BlockAssemblerInput}, execute::{BlockAssembler, BlockAssemblerInput},
precompiles::PrecompilesMap, precompiles::PrecompilesMap,
ConfigureEvm, EvmEnv, EvmFactory, ExecutionCtxFor, FromRecoveredTx, FromTxWithEncoded, ConfigureEngineEvm, ConfigureEvm, EvmEnv, EvmEnvFor, EvmFactory, ExecutableTxIterator,
IntoTxEnv, NextBlockEnvAttributes, ExecutionCtxFor, FromRecoveredTx, FromTxWithEncoded, IntoTxEnv, NextBlockEnvAttributes,
}; };
use reth_evm_ethereum::EthBlockAssembler; use reth_evm_ethereum::EthBlockAssembler;
use reth_payload_primitives::NewPayloadError;
use reth_primitives::{logs_bloom, BlockTy, HeaderTy, Receipt, SealedBlock, SealedHeader}; use reth_primitives::{logs_bloom, BlockTy, HeaderTy, Receipt, SealedBlock, SealedHeader};
use reth_primitives_traits::proofs; use reth_primitives_traits::{proofs, SignerRecoverable, WithEncoded};
use reth_provider::BlockExecutionResult; use reth_provider::BlockExecutionResult;
use reth_revm::State; use reth_revm::State;
use revm::{ use revm::{
@ -407,6 +409,34 @@ where
} }
} }
impl ConfigureEngineEvm<HlExecutionData> for HlEvmConfig {
fn evm_env_for_payload(&self, payload: &HlExecutionData) -> EvmEnvFor<Self> {
self.evm_env(&payload.0.header)
}
fn context_for_payload<'a>(&self, payload: &'a HlExecutionData) -> ExecutionCtxFor<'a, Self> {
HlBlockExecutionCtx {
ctx: EthBlockExecutionCtx {
parent_hash: payload.0.header.parent_hash,
parent_beacon_block_root: payload.0.header.parent_beacon_block_root,
ommers: &payload.0.body.ommers,
withdrawals: payload.0.body.withdrawals.as_ref().map(Cow::Borrowed),
},
extras: HlExtras::default(),
}
}
fn tx_iterator_for_payload(
&self,
payload: &HlExecutionData,
) -> impl ExecutableTxIterator<Self> {
payload.0.body.transactions.clone().into_iter().map(move |tx| {
let recovered = tx.try_into_recovered().map_err(NewPayloadError::other)?;
Ok::<_, NewPayloadError>(WithEncoded::new(recovered.encoded_2718().into(), recovered))
})
}
}
/// Map the latest active hardfork at the given timestamp or block number to a [`HlSpecId`]. /// Map the latest active hardfork at the given timestamp or block number to a [`HlSpecId`].
pub fn revm_spec_by_timestamp_and_block_number( pub fn revm_spec_by_timestamp_and_block_number(
_chain_spec: impl HlHardforks, _chain_spec: impl HlHardforks,

View File

@ -72,7 +72,7 @@ fn run_precompile(
match *get { match *get {
ReadPrecompileResult::Ok { gas_used, ref bytes } => { ReadPrecompileResult::Ok { gas_used, ref bytes } => {
Ok(PrecompileOutput { gas_used, bytes: bytes.clone() }) Ok(PrecompileOutput { gas_used, bytes: bytes.clone(), reverted: false })
} }
ReadPrecompileResult::OutOfGas => { ReadPrecompileResult::OutOfGas => {
// Use all the gas passed to this precompile // Use all the gas passed to this precompile
@ -181,7 +181,7 @@ where
// Execute transaction. // Execute transaction.
let ResultAndState { result, mut state } = self let ResultAndState { result, mut state } = self
.evm .evm
.transact(tx) .transact(&tx)
.map_err(|err| BlockExecutionError::evm(err, tx.tx().trie_hash()))?; .map_err(|err| BlockExecutionError::evm(err, tx.tx().trie_hash()))?;
if !f(&result).should_commit() { if !f(&result).should_commit() {

View File

@ -12,7 +12,7 @@ use reth::{
api::FullNodeTypes, api::FullNodeTypes,
builder::{components::ExecutorBuilder, BuilderContext}, builder::{components::ExecutorBuilder, BuilderContext},
}; };
use reth_evm::{Evm, EvmEnv}; use reth_evm::{Database, Evm, EvmEnv};
use revm::{ use revm::{
context::{ context::{
result::{EVMError, ExecutionResult, HaltReason, Output, ResultAndState, SuccessReason}, result::{EVMError, ExecutionResult, HaltReason, Output, ResultAndState, SuccessReason},
@ -21,7 +21,7 @@ use revm::{
handler::{instructions::EthInstructions, EthPrecompiles, PrecompileProvider}, handler::{instructions::EthInstructions, EthPrecompiles, PrecompileProvider},
interpreter::{interpreter::EthInterpreter, InterpreterResult}, interpreter::{interpreter::EthInterpreter, InterpreterResult},
state::EvmState, state::EvmState,
Context, Database, ExecuteEvm, InspectEvm, Inspector, Context, ExecuteEvm, InspectEvm, Inspector,
}; };
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
@ -75,7 +75,6 @@ where
DB: Database, DB: Database,
I: Inspector<HlContext<DB>>, I: Inspector<HlContext<DB>>,
P: PrecompileProvider<HlContext<DB>, Output = InterpreterResult>, P: PrecompileProvider<HlContext<DB>, Output = InterpreterResult>,
<DB as revm::Database>::Error: std::marker::Send + std::marker::Sync + 'static,
{ {
type DB = DB; type DB = DB;
type Tx = HlTxEnv<TxEnv>; type Tx = HlTxEnv<TxEnv>;
@ -127,10 +126,6 @@ where
)) ))
} }
fn db_mut(&mut self) -> &mut Self::DB {
&mut self.journaled_state.database
}
fn finish(self) -> (Self::DB, EvmEnv<Self::Spec>) { fn finish(self) -> (Self::DB, EvmEnv<Self::Spec>) {
let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.0.ctx; let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.0.ctx;
@ -141,20 +136,20 @@ where
self.inspect = enabled; self.inspect = enabled;
} }
fn precompiles_mut(&mut self) -> &mut Self::Precompiles { fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) {
&mut self.inner.0.precompiles (
&self.inner.0.ctx.journaled_state.database,
&self.inner.0.inspector,
&self.inner.0.precompiles,
)
} }
fn inspector_mut(&mut self) -> &mut Self::Inspector { fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) {
&mut self.inner.0.inspector (
} &mut self.inner.0.ctx.journaled_state.database,
&mut self.inner.0.inspector,
fn precompiles(&self) -> &Self::Precompiles { &mut self.inner.0.precompiles,
&self.inner.0.precompiles )
}
fn inspector(&self) -> &Self::Inspector {
&self.inner.0.inspector
} }
} }

View File

@ -2,11 +2,11 @@ use crate::{
chainspec::HlChainSpec, chainspec::HlChainSpec,
node::{ node::{
pool::HlPoolBuilder, pool::HlPoolBuilder,
primitives::{BlockBody, HlBlock, HlBlockBody, HlPrimitives, TransactionSigned}, primitives::{HlBlock, HlPrimitives},
rpc::{ rpc::{
engine_api::{ engine_api::{
builder::HlEngineApiBuilder, payload::HlPayloadTypes, builder::HlEngineApiBuilder, payload::HlPayloadTypes,
validator::HlEngineValidatorBuilder, validator::HlPayloadValidatorBuilder,
}, },
HlEthApiBuilder, HlEthApiBuilder,
}, },
@ -19,15 +19,11 @@ use engine::HlPayloadServiceBuilder;
use evm::HlExecutorBuilder; use evm::HlExecutorBuilder;
use network::HlNetworkBuilder; use network::HlNetworkBuilder;
use reth::{ use reth::{
api::{FullNodeComponents, FullNodeTypes, NodeTypes}, api::{FullNodeTypes, NodeTypes},
builder::{ builder::{components::ComponentsBuilder, rpc::RpcAddOns, Node, NodeAdapter},
components::ComponentsBuilder, rpc::RpcAddOns, DebugNode, Node, NodeAdapter,
NodeComponentsBuilder,
},
}; };
use reth_engine_primitives::BeaconConsensusEngineHandle; use reth_engine_primitives::ConsensusEngineHandle;
use reth_trie_db::MerklePatriciaTrie; use std::{marker::PhantomData, sync::Arc};
use std::sync::Arc;
use tokio::sync::{oneshot, Mutex}; use tokio::sync::{oneshot, Mutex};
pub mod cli; pub mod cli;
@ -43,31 +39,21 @@ pub mod types;
/// Hl addons configuring RPC types /// Hl addons configuring RPC types
pub type HlNodeAddOns<N> = pub type HlNodeAddOns<N> =
RpcAddOns<N, HlEthApiBuilder, HlEngineValidatorBuilder, HlEngineApiBuilder>; RpcAddOns<N, HlEthApiBuilder, HlPayloadValidatorBuilder, HlEngineApiBuilder>;
/// Type configuration for a regular Hl node. /// Type configuration for a regular Hl node.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct HlNode { pub struct HlNode {
engine_handle_rx: engine_handle_rx: Arc<Mutex<Option<oneshot::Receiver<ConsensusEngineHandle<HlPayloadTypes>>>>>,
Arc<Mutex<Option<oneshot::Receiver<BeaconConsensusEngineHandle<HlPayloadTypes>>>>>,
block_source_config: BlockSourceConfig, block_source_config: BlockSourceConfig,
hl_node_compliant: bool,
} }
impl HlNode { impl HlNode {
pub fn new( pub fn new(
block_source_config: BlockSourceConfig, block_source_config: BlockSourceConfig,
hl_node_compliant: bool, ) -> (Self, oneshot::Sender<ConsensusEngineHandle<HlPayloadTypes>>) {
) -> (Self, oneshot::Sender<BeaconConsensusEngineHandle<HlPayloadTypes>>) {
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
( (Self { engine_handle_rx: Arc::new(Mutex::new(Some(rx))), block_source_config }, tx)
Self {
engine_handle_rx: Arc::new(Mutex::new(Some(rx))),
block_source_config,
hl_node_compliant,
},
tx,
)
} }
} }
@ -103,7 +89,6 @@ impl HlNode {
impl NodeTypes for HlNode { impl NodeTypes for HlNode {
type Primitives = HlPrimitives; type Primitives = HlPrimitives;
type ChainSpec = HlChainSpec; type ChainSpec = HlChainSpec;
type StateCommitment = MerklePatriciaTrie;
type Storage = HlStorage; type Storage = HlStorage;
type Payload = HlPayloadTypes; type Payload = HlPayloadTypes;
} }
@ -121,9 +106,7 @@ where
HlConsensusBuilder, HlConsensusBuilder,
>; >;
type AddOns = HlNodeAddOns< type AddOns = HlNodeAddOns<NodeAdapter<N>>;
NodeAdapter<N, <Self::ComponentsBuilder as NodeComponentsBuilder<N>>::Components>,
>;
fn components_builder(&self) -> Self::ComponentsBuilder { fn components_builder(&self) -> Self::ComponentsBuilder {
Self::components(self) Self::components(self)
@ -131,37 +114,11 @@ where
fn add_ons(&self) -> Self::AddOns { fn add_ons(&self) -> Self::AddOns {
HlNodeAddOns::new( HlNodeAddOns::new(
HlEthApiBuilder { hl_node_compliant: self.hl_node_compliant }, HlEthApiBuilder { _nt: PhantomData },
Default::default(),
Default::default(), Default::default(),
Default::default(), Default::default(),
Default::default(), Default::default(),
) )
} }
} }
impl<N> DebugNode<N> for HlNode
where
N: FullNodeComponents<Types = Self>,
{
type RpcBlock = alloy_rpc_types::Block;
fn rpc_to_primitive_block(rpc_block: Self::RpcBlock) -> HlBlock {
let alloy_rpc_types::Block { header, transactions, withdrawals, .. } = rpc_block;
HlBlock {
header: header.inner,
body: HlBlockBody {
inner: BlockBody {
transactions: transactions
.into_transactions()
.map(|tx| TransactionSigned::Default(tx.inner.into_inner().into()))
.collect(),
ommers: Default::default(),
withdrawals,
},
sidecars: None,
read_precompile_calls: None,
highest_precompile_address: None,
},
}
}
}

View File

@ -12,7 +12,7 @@ use alloy_consensus::{BlockBody, Header};
use alloy_primitives::U128; use alloy_primitives::U128;
use alloy_rpc_types::engine::{ForkchoiceState, PayloadStatusEnum}; use alloy_rpc_types::engine::{ForkchoiceState, PayloadStatusEnum};
use futures::{future::Either, stream::FuturesUnordered, StreamExt}; use futures::{future::Either, stream::FuturesUnordered, StreamExt};
use reth_engine_primitives::{BeaconConsensusEngineHandle, EngineTypes}; use reth_engine_primitives::{ConsensusEngineHandle, EngineTypes};
use reth_eth_wire::NewBlock; use reth_eth_wire::NewBlock;
use reth_network::{ use reth_network::{
import::{BlockImportError, BlockImportEvent, BlockImportOutcome, BlockValidation}, import::{BlockImportError, BlockImportEvent, BlockImportOutcome, BlockValidation},
@ -55,7 +55,7 @@ where
Provider: BlockNumReader + Clone, Provider: BlockNumReader + Clone,
{ {
/// The handle to communicate with the engine service /// The handle to communicate with the engine service
engine: BeaconConsensusEngineHandle<HlPayloadTypes>, engine: ConsensusEngineHandle<HlPayloadTypes>,
/// The consensus implementation /// The consensus implementation
consensus: Arc<HlConsensus<Provider>>, consensus: Arc<HlConsensus<Provider>>,
/// Receive the new block from the network /// Receive the new block from the network
@ -73,7 +73,7 @@ where
/// Create a new block import service /// Create a new block import service
pub fn new( pub fn new(
consensus: Arc<HlConsensus<Provider>>, consensus: Arc<HlConsensus<Provider>>,
engine: BeaconConsensusEngineHandle<HlPayloadTypes>, engine: ConsensusEngineHandle<HlPayloadTypes>,
from_network: UnboundedReceiver<IncomingBlock>, from_network: UnboundedReceiver<IncomingBlock>,
to_network: UnboundedSender<ImportEvent>, to_network: UnboundedSender<ImportEvent>,
) -> Self { ) -> Self {
@ -341,7 +341,7 @@ mod tests {
async fn new(responses: EngineResponses) -> Self { async fn new(responses: EngineResponses) -> Self {
let consensus = Arc::new(HlConsensus { provider: MockProvider }); let consensus = Arc::new(HlConsensus { provider: MockProvider });
let (to_engine, from_engine) = mpsc::unbounded_channel(); let (to_engine, from_engine) = mpsc::unbounded_channel();
let engine_handle = BeaconConsensusEngineHandle::new(to_engine); let engine_handle = ConsensusEngineHandle::new(to_engine);
handle_engine_msg(from_engine, responses).await; handle_engine_msg(from_engine, responses).await;

View File

@ -19,7 +19,7 @@ use reth::{
transaction_pool::{PoolTransaction, TransactionPool}, transaction_pool::{PoolTransaction, TransactionPool},
}; };
use reth_discv4::NodeRecord; use reth_discv4::NodeRecord;
use reth_engine_primitives::BeaconConsensusEngineHandle; use reth_engine_primitives::ConsensusEngineHandle;
use reth_eth_wire::{BasicNetworkPrimitives, NewBlock, NewBlockPayload}; use reth_eth_wire::{BasicNetworkPrimitives, NewBlock, NewBlockPayload};
use reth_ethereum_primitives::PooledTransactionVariant; use reth_ethereum_primitives::PooledTransactionVariant;
use reth_network::{NetworkConfig, NetworkHandle, NetworkManager}; use reth_network::{NetworkConfig, NetworkHandle, NetworkManager};
@ -31,8 +31,7 @@ use tokio::sync::{mpsc, oneshot, Mutex};
use tracing::info; use tracing::info;
pub mod block_import; pub mod block_import;
// pub mod handshake;
// pub(crate) mod upgrade_status;
/// HL `NewBlock` message value. /// HL `NewBlock` message value.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct HlNewBlock(pub NewBlock<HlBlock>); pub struct HlNewBlock(pub NewBlock<HlBlock>);
@ -157,7 +156,7 @@ pub type HlNetworkPrimitives =
#[derive(Debug)] #[derive(Debug)]
pub struct HlNetworkBuilder { pub struct HlNetworkBuilder {
pub(crate) engine_handle_rx: pub(crate) engine_handle_rx:
Arc<Mutex<Option<oneshot::Receiver<BeaconConsensusEngineHandle<HlPayloadTypes>>>>>, Arc<Mutex<Option<oneshot::Receiver<ConsensusEngineHandle<HlPayloadTypes>>>>>,
pub(crate) block_source_config: BlockSourceConfig, pub(crate) block_source_config: BlockSourceConfig,
} }
@ -237,9 +236,12 @@ where
let chain_spec = ctx.chain_spec(); let chain_spec = ctx.chain_spec();
info!(target: "reth::cli", enode=%local_node_record, "P2P networking initialized"); info!(target: "reth::cli", enode=%local_node_record, "P2P networking initialized");
let next_block_number = let next_block_number = ctx
ctx.provider().get_stage_checkpoint(StageId::Finish)?.unwrap_or_default().block_number .provider()
+ 1; .get_stage_checkpoint(StageId::Finish)?
.unwrap_or_default()
.block_number +
1;
ctx.task_executor().spawn_critical("pseudo peer", async move { ctx.task_executor().spawn_critical("pseudo peer", async move {
let block_source = let block_source =

View File

@ -10,43 +10,30 @@ use crate::node::{primitives::TransactionSigned, HlNode};
use alloy_consensus::{ use alloy_consensus::{
error::ValueError, EthereumTxEnvelope, Transaction as TransactionTrait, TxEip4844, error::ValueError, EthereumTxEnvelope, Transaction as TransactionTrait, TxEip4844,
}; };
use alloy_eips::{ use alloy_eips::{eip7702::SignedAuthorization, Typed2718};
eip4844::BlobAndProofV2, eip7594::BlobTransactionSidecarVariant, eip7702::SignedAuthorization,
Typed2718,
};
use alloy_primitives::{Address, Bytes, ChainId, TxHash, TxKind, B256, U256}; use alloy_primitives::{Address, Bytes, ChainId, TxHash, TxKind, B256, U256};
use alloy_rpc_types::AccessList; use alloy_rpc_types::AccessList;
use alloy_rpc_types_engine::BlobAndProofV1;
use reth::{ use reth::{
api::FullNodeTypes, api::FullNodeTypes, builder::components::PoolBuilder, transaction_pool::PoolTransaction,
builder::components::PoolBuilder,
transaction_pool::{PoolResult, PoolSize, PoolTransaction, TransactionOrigin, TransactionPool},
}; };
use reth_eth_wire::HandleMempoolData;
use reth_ethereum_primitives::PooledTransactionVariant; use reth_ethereum_primitives::PooledTransactionVariant;
use reth_primitives::Recovered; use reth_primitives::Recovered;
use reth_primitives_traits::InMemorySize; use reth_primitives_traits::InMemorySize;
use reth_transaction_pool::{ use reth_transaction_pool::{noop::NoopTransactionPool, EthPoolTransaction};
error::InvalidPoolTransactionError, AllPoolTransactions, AllTransactionsEvents, use std::sync::Arc;
BestTransactions, BestTransactionsAttributes, BlobStoreError, BlockInfo, EthPoolTransaction,
GetPooledTransactionLimit, NewBlobSidecar, NewTransactionEvent, PropagatedTransactions,
TransactionEvents, TransactionListenerKind, ValidPoolTransaction,
};
use std::{collections::HashSet, sync::Arc};
use tokio::sync::mpsc::{self, Receiver};
pub struct HlPoolBuilder; pub struct HlPoolBuilder;
impl<Node> PoolBuilder<Node> for HlPoolBuilder impl<Node> PoolBuilder<Node> for HlPoolBuilder
where where
Node: FullNodeTypes<Types = HlNode>, Node: FullNodeTypes<Types = HlNode>,
{ {
type Pool = HlTransactionPool; type Pool = NoopTransactionPool<HlPooledTransaction>;
async fn build_pool( async fn build_pool(
self, self,
_ctx: &reth::builder::BuilderContext<Node>, _ctx: &reth::builder::BuilderContext<Node>,
) -> eyre::Result<Self::Pool> { ) -> eyre::Result<Self::Pool> {
Ok(HlTransactionPool) Ok(NoopTransactionPool::new())
} }
} }
@ -124,16 +111,6 @@ impl PoolTransaction for HlPooledTransaction {
type Consensus = TransactionSigned; type Consensus = TransactionSigned;
type Pooled = PooledTransactionVariant; type Pooled = PooledTransactionVariant;
fn try_from_consensus(
_tx: Recovered<Self::Consensus>,
) -> Result<Self, Self::TryFromConsensusError> {
unreachable!()
}
fn clone_into_consensus(&self) -> Recovered<Self::Consensus> {
unreachable!()
}
fn into_consensus(self) -> Recovered<Self::Consensus> { fn into_consensus(self) -> Recovered<Self::Consensus> {
unreachable!() unreachable!()
} }
@ -161,13 +138,6 @@ impl PoolTransaction for HlPooledTransaction {
fn encoded_length(&self) -> usize { fn encoded_length(&self) -> usize {
0 0
} }
fn ensure_max_init_code_size(
&self,
_max_init_code_size: usize,
) -> Result<(), InvalidPoolTransactionError> {
Ok(())
}
} }
impl EthPoolTransaction for HlPooledTransaction { impl EthPoolTransaction for HlPooledTransaction {
@ -197,243 +167,3 @@ impl EthPoolTransaction for HlPooledTransaction {
Ok(()) Ok(())
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HlTransactionPool;
impl TransactionPool for HlTransactionPool {
type Transaction = HlPooledTransaction;
fn pool_size(&self) -> PoolSize {
PoolSize::default()
}
fn block_info(&self) -> BlockInfo {
BlockInfo::default()
}
async fn add_transaction_and_subscribe(
&self,
_origin: TransactionOrigin,
_transaction: Self::Transaction,
) -> PoolResult<TransactionEvents> {
unreachable!()
}
async fn add_transaction(
&self,
_origin: TransactionOrigin,
_transaction: Self::Transaction,
) -> PoolResult<TxHash> {
Ok(TxHash::default())
}
async fn add_transactions(
&self,
_origin: TransactionOrigin,
_transactions: Vec<Self::Transaction>,
) -> Vec<PoolResult<TxHash>> {
vec![]
}
fn transaction_event_listener(&self, _tx_hash: TxHash) -> Option<TransactionEvents> {
None
}
fn all_transactions_event_listener(&self) -> AllTransactionsEvents<Self::Transaction> {
unreachable!()
}
fn pending_transactions_listener_for(
&self,
_kind: TransactionListenerKind,
) -> Receiver<TxHash> {
mpsc::channel(1).1
}
fn blob_transaction_sidecars_listener(&self) -> Receiver<NewBlobSidecar> {
mpsc::channel(1).1
}
fn new_transactions_listener_for(
&self,
_kind: TransactionListenerKind,
) -> Receiver<NewTransactionEvent<Self::Transaction>> {
mpsc::channel(1).1
}
fn pooled_transaction_hashes(&self) -> Vec<TxHash> {
vec![]
}
fn pooled_transaction_hashes_max(&self, _max: usize) -> Vec<TxHash> {
vec![]
}
fn pooled_transactions(&self) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
vec![]
}
fn pooled_transactions_max(
&self,
_max: usize,
) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
vec![]
}
fn get_pooled_transaction_elements(
&self,
_tx_hashes: Vec<TxHash>,
_limit: GetPooledTransactionLimit,
) -> Vec<<Self::Transaction as PoolTransaction>::Pooled> {
vec![]
}
fn get_pooled_transaction_element(
&self,
_tx_hash: TxHash,
) -> Option<Recovered<<Self::Transaction as PoolTransaction>::Pooled>> {
None
}
fn best_transactions(
&self,
) -> Box<dyn BestTransactions<Item = Arc<ValidPoolTransaction<Self::Transaction>>>> {
Box::new(std::iter::empty())
}
fn best_transactions_with_attributes(
&self,
_best_transactions_attributes: BestTransactionsAttributes,
) -> Box<dyn BestTransactions<Item = Arc<ValidPoolTransaction<Self::Transaction>>>> {
Box::new(std::iter::empty())
}
fn pending_transactions(&self) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
vec![]
}
fn pending_transactions_max(
&self,
_max: usize,
) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
vec![]
}
fn queued_transactions(&self) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
vec![]
}
fn all_transactions(&self) -> AllPoolTransactions<Self::Transaction> {
AllPoolTransactions::default()
}
fn remove_transactions(
&self,
_hashes: Vec<TxHash>,
) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
vec![]
}
fn remove_transactions_and_descendants(
&self,
_hashes: Vec<TxHash>,
) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
vec![]
}
fn remove_transactions_by_sender(
&self,
_sender: Address,
) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
vec![]
}
fn retain_unknown<A>(&self, _announcement: &mut A)
where
A: HandleMempoolData,
{
// do nothing
}
fn get(&self, _tx_hash: &TxHash) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
None
}
fn get_all(&self, _txs: Vec<TxHash>) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
vec![]
}
fn on_propagated(&self, _txs: PropagatedTransactions) {
// do nothing
}
fn get_transactions_by_sender(
&self,
_sender: Address,
) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
vec![]
}
fn get_pending_transactions_with_predicate(
&self,
_predicate: impl FnMut(&ValidPoolTransaction<Self::Transaction>) -> bool,
) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
vec![]
}
fn get_pending_transactions_by_sender(
&self,
_sender: Address,
) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
vec![]
}
fn get_queued_transactions_by_sender(
&self,
_sender: Address,
) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
unreachable!()
}
fn get_highest_transaction_by_sender(
&self,
_sender: Address,
) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
None
}
fn get_highest_consecutive_transaction_by_sender(
&self,
_sender: Address,
_on_chain_nonce: u64,
) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
None
}
fn get_transaction_by_sender_and_nonce(
&self,
_sender: Address,
_nonce: u64,
) -> Option<Arc<ValidPoolTransaction<Self::Transaction>>> {
None
}
fn get_transactions_by_origin(
&self,
_origin: TransactionOrigin,
) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
unreachable!()
}
fn get_pending_transactions_by_origin(
&self,
_origin: TransactionOrigin,
) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
unreachable!()
}
fn unique_senders(&self) -> HashSet<Address> {
unreachable!()
}
fn get_blob(
&self,
_tx_hash: TxHash,
) -> Result<Option<Arc<BlobTransactionSidecarVariant>>, BlobStoreError> {
unreachable!()
}
fn get_all_blobs(
&self,
_tx_hashes: Vec<TxHash>,
) -> Result<Vec<(TxHash, Arc<BlobTransactionSidecarVariant>)>, BlobStoreError> {
unreachable!()
}
fn get_all_blobs_exact(
&self,
_tx_hashes: Vec<TxHash>,
) -> Result<Vec<Arc<BlobTransactionSidecarVariant>>, BlobStoreError> {
unreachable!()
}
fn get_blobs_for_versioned_hashes_v1(
&self,
_versioned_hashes: &[B256],
) -> Result<Vec<Option<BlobAndProofV1>>, BlobStoreError> {
unreachable!()
}
fn get_blobs_for_versioned_hashes_v2(
&self,
_versioned_hashes: &[B256],
) -> Result<Option<Vec<BlobAndProofV2>>, BlobStoreError> {
unreachable!()
}
}

View File

@ -1,11 +1,12 @@
//! HlNodePrimitives::TransactionSigned; it's the same as ethereum transaction type, //! HlNodePrimitives::TransactionSigned; it's the same as ethereum transaction type,
//! except that it supports pseudo signer for system transactions. //! except that it supports pseudo signer for system transactions.
use alloy_consensus::{ use alloy_consensus::{
crypto::RecoveryError, error::ValueError, EthereumTxEnvelope, SignableTransaction, Signed, crypto::RecoveryError, error::ValueError, EthereumTxEnvelope, EthereumTypedTransaction,
Transaction as TransactionTrait, TransactionEnvelope, TxEip1559, TxEip2930, TxEip4844, SignableTransaction, Signed, Transaction as TransactionTrait, TransactionEnvelope, TxEip1559,
TxEip4844WithSidecar, TxEip7702, TxLegacy, TxType, TypedTransaction, TxEip2930, TxEip4844, TxEip4844WithSidecar, TxEip7702, TxLegacy, TxType, TypedTransaction,
}; };
use alloy_eips::{eip7594::BlobTransactionSidecarVariant, Encodable2718}; use alloy_eips::{eip7594::BlobTransactionSidecarVariant, Encodable2718};
use alloy_network::TxSigner;
use alloy_primitives::{address, Address, TxHash, U256}; use alloy_primitives::{address, Address, TxHash, U256};
use alloy_rpc_types::{Transaction, TransactionInfo, TransactionRequest}; use alloy_rpc_types::{Transaction, TransactionInfo, TransactionRequest};
use alloy_signer::Signature; use alloy_signer::Signature;
@ -21,7 +22,7 @@ use reth_primitives_traits::{
}; };
use reth_rpc_eth_api::{ use reth_rpc_eth_api::{
transaction::{FromConsensusTx, TryIntoTxEnv}, transaction::{FromConsensusTx, TryIntoTxEnv},
EthTxEnvError, TryIntoSimTx, EthTxEnvError, SignTxRequestError, SignableTxRequest, TryIntoSimTx,
}; };
use revm::context::{BlockEnv, CfgEnv, TxEnv}; use revm::context::{BlockEnv, CfgEnv, TxEnv};
@ -59,22 +60,19 @@ impl SignerRecoverable for TransactionSigned {
} }
self.inner().recover_signer_unchecked() self.inner().recover_signer_unchecked()
} }
fn recover_unchecked_with_buf(&self, buf: &mut Vec<u8>) -> Result<Address, RecoveryError> {
if self.is_system_transaction() {
return Ok(s_to_address(self.signature().s()));
}
self.inner().recover_unchecked_with_buf(buf)
}
} }
impl SignedTransaction for TransactionSigned { impl SignedTransaction for TransactionSigned {
fn tx_hash(&self) -> &TxHash { fn tx_hash(&self) -> &TxHash {
self.inner().tx_hash() self.inner().tx_hash()
} }
fn recover_signer_unchecked_with_buf(
&self,
buf: &mut Vec<u8>,
) -> Result<Address, RecoveryError> {
if self.is_system_transaction() {
return Ok(s_to_address(self.signature().s()));
}
self.inner().recover_signer_unchecked_with_buf(buf)
}
} }
// ------------------------------------------------------------ // ------------------------------------------------------------
@ -296,3 +294,32 @@ impl FromConsensusTx<TransactionSigned> for Transaction {
Self::from_transaction(Recovered::new_unchecked(tx.into_inner().into(), signer), tx_info) Self::from_transaction(Recovered::new_unchecked(tx.into_inner().into(), signer), tx_info)
} }
} }
impl SignableTxRequest<TransactionSigned> for TransactionRequest {
async fn try_build_and_sign(
self,
signer: impl TxSigner<Signature> + Send,
) -> Result<TransactionSigned, SignTxRequestError> {
let mut tx =
self.build_typed_tx().map_err(|_| SignTxRequestError::InvalidTransactionRequest)?;
let signature = signer.sign_transaction(&mut tx).await?;
let signed = match tx {
EthereumTypedTransaction::Legacy(tx) => {
EthereumTxEnvelope::Legacy(tx.into_signed(signature))
}
EthereumTypedTransaction::Eip2930(tx) => {
EthereumTxEnvelope::Eip2930(tx.into_signed(signature))
}
EthereumTypedTransaction::Eip1559(tx) => {
EthereumTxEnvelope::Eip1559(tx.into_signed(signature))
}
EthereumTypedTransaction::Eip4844(tx) => {
EthereumTxEnvelope::Eip4844(TxEip4844::from(tx).into_signed(signature))
}
EthereumTypedTransaction::Eip7702(tx) => {
EthereumTxEnvelope::Eip7702(tx.into_signed(signature))
}
};
Ok(TransactionSigned::Default(signed))
}
}

View File

@ -1,263 +1,56 @@
use std::{future::Future, sync::Arc}; use crate::node::rpc::HlEthApi;
use reth::rpc::server_types::eth::{
use crate::{ builder::config::PendingBlockKind, error::FromEvmError, EthApiError, PendingBlock,
chainspec::HlChainSpec,
node::{
primitives::TransactionSigned,
rpc::{HlEthApi, HlNodeCore},
},
HlBlock,
};
use alloy_consensus::{BlockHeader, ReceiptEnvelope, TxType};
use alloy_primitives::B256;
use reth::{
api::NodeTypes,
builder::FullNodeComponents,
primitives::{Receipt, SealedHeader, TransactionMeta},
providers::{BlockReaderIdExt, ProviderHeader, ReceiptProvider, TransactionsProvider},
rpc::{
eth::EthApiTypes,
server_types::eth::{
error::FromEvmError, receipt::build_receipt, EthApiError, PendingBlock,
},
types::{BlockId, TransactionReceipt},
},
transaction_pool::{PoolTransaction, TransactionPool},
};
use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_evm::{ConfigureEvm, NextBlockEnvAttributes};
use reth_primitives::{NodePrimitives, SealedBlock};
use reth_primitives_traits::{BlockBody as _, RecoveredBlock, SignedTransaction as _};
use reth_provider::{
BlockIdReader, BlockReader, ChainSpecProvider, HeaderProvider, ProviderBlock, ProviderReceipt,
ProviderTx, StateProviderFactory,
}; };
use reth_rpc_eth_api::{ use reth_rpc_eth_api::{
helpers::{EthBlocks, LoadBlock, LoadPendingBlock, LoadReceipt, SpawnBlocking}, helpers::{
types::RpcTypes, pending_block::PendingEnvBuilder, EthBlocks, LoadBlock, LoadPendingBlock, LoadReceipt,
FromEthApiError, RpcConvert, RpcNodeCore, RpcNodeCoreExt, RpcReceipt, },
RpcConvert, RpcNodeCore,
}; };
fn is_system_tx(tx: &TransactionSigned) -> bool { impl<N, Rpc> EthBlocks for HlEthApi<N, Rpc>
tx.is_system_transaction()
}
impl<N> EthBlocks for HlEthApi<N>
where where
Self: LoadBlock< N: RpcNodeCore,
Error = EthApiError, EthApiError: FromEvmError<N::Evm>,
NetworkTypes: RpcTypes<Receipt = TransactionReceipt>, Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError>,
Provider: BlockReader<Transaction = TransactionSigned, Receipt = Receipt>,
>,
N: HlNodeCore<Provider: ChainSpecProvider<ChainSpec = HlChainSpec> + HeaderProvider>,
{ {
async fn block_receipts( }
&self,
block_id: BlockId, impl<N, Rpc> LoadBlock for HlEthApi<N, Rpc>
) -> Result<Option<Vec<RpcReceipt<Self::NetworkTypes>>>, Self::Error>
where where
Self: LoadReceipt, N: RpcNodeCore,
EthApiError: FromEvmError<N::Evm>,
Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError>,
{ {
if let Some((block, receipts)) = self.load_block_and_receipts(block_id).await? {
let block_number = block.number();
let base_fee = block.base_fee_per_gas();
let block_hash = block.hash();
let excess_blob_gas = block.excess_blob_gas();
let timestamp = block.timestamp();
let blob_params = self.provider().chain_spec().blob_params_at_timestamp(timestamp);
return block
.body()
.transactions()
.iter()
.zip(receipts.iter())
.filter(|(tx, _)| !is_system_tx(tx))
.enumerate()
.map(|(idx, (tx, receipt))| {
let meta = TransactionMeta {
tx_hash: *tx.tx_hash(),
index: idx as u64,
block_hash,
block_number,
base_fee,
excess_blob_gas,
timestamp,
};
build_receipt(tx, meta, receipt, &receipts, blob_params, |receipt_with_bloom| {
match receipt.tx_type {
TxType::Legacy => ReceiptEnvelope::Legacy(receipt_with_bloom),
TxType::Eip2930 => ReceiptEnvelope::Eip2930(receipt_with_bloom),
TxType::Eip1559 => ReceiptEnvelope::Eip1559(receipt_with_bloom),
TxType::Eip4844 => ReceiptEnvelope::Eip4844(receipt_with_bloom),
TxType::Eip7702 => ReceiptEnvelope::Eip7702(receipt_with_bloom),
}
})
})
.collect::<Result<Vec<_>, Self::Error>>()
.map(Some);
} }
Ok(None) impl<N, Rpc> LoadPendingBlock for HlEthApi<N, Rpc>
}
}
impl<N> LoadBlock for HlEthApi<N>
where where
Self: LoadPendingBlock N: RpcNodeCore,
+ SpawnBlocking EthApiError: FromEvmError<N::Evm>,
+ RpcNodeCoreExt< Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError>,
Pool: TransactionPool<
Transaction: PoolTransaction<Consensus = ProviderTx<Self::Provider>>,
>,
> + RpcNodeCore<Provider: BlockReader<Block = crate::HlBlock>>,
N: HlNodeCore,
{
fn recovered_block(
&self,
block_id: BlockId,
) -> impl Future<
Output = Result<
Option<Arc<RecoveredBlock<<Self::Provider as BlockReader>::Block>>>,
Self::Error,
>,
> + Send {
let hl_node_compliant = self.hl_node_compliant;
async move {
// Copy of LoadBlock::recovered_block, but with --hl-node-compliant support
if block_id.is_pending() {
return Ok(None);
}
let block_hash = match self
.provider()
.block_hash_for_id(block_id)
.map_err(Self::Error::from_eth_err)?
{
Some(block_hash) => block_hash,
None => return Ok(None),
};
let recovered_block = self
.cache()
.get_recovered_block(block_hash)
.await
.map_err(Self::Error::from_eth_err)?;
if let Some(recovered_block) = recovered_block {
let recovered_block = if hl_node_compliant {
filter_if_hl_node_compliant(&recovered_block)
} else {
(*recovered_block).clone()
};
return Ok(Some(std::sync::Arc::new(recovered_block)));
}
Ok(None)
}
}
}
fn filter_if_hl_node_compliant(
recovered_block: &RecoveredBlock<HlBlock>,
) -> RecoveredBlock<HlBlock> {
let sealed_block = recovered_block.sealed_block();
let transactions = sealed_block.body().transactions();
let to_skip = transactions
.iter()
.position(|tx| !tx.is_system_transaction())
.unwrap_or(transactions.len());
let mut new_block: HlBlock = sealed_block.clone_block();
new_block.body.transactions.drain(..to_skip);
let new_sealed_block = SealedBlock::new_unchecked(new_block, sealed_block.hash());
let new_senders = recovered_block.senders()[to_skip..].to_vec();
RecoveredBlock::new_sealed(new_sealed_block, new_senders)
}
impl<N> LoadPendingBlock for HlEthApi<N>
where
Self: SpawnBlocking
+ EthApiTypes<
NetworkTypes: RpcTypes<
Header = alloy_rpc_types_eth::Header<ProviderHeader<Self::Provider>>,
>,
Error: FromEvmError<Self::Evm>,
RpcConvert: RpcConvert<Network = Self::NetworkTypes>,
>,
N: RpcNodeCore<
Provider: BlockReaderIdExt
+ ChainSpecProvider<ChainSpec: EthChainSpec + EthereumHardforks>
+ StateProviderFactory,
Pool: TransactionPool<Transaction: PoolTransaction<Consensus = ProviderTx<N::Provider>>>,
Evm: ConfigureEvm<
Primitives = <Self as RpcNodeCore>::Primitives,
NextBlockEnvCtx: From<NextBlockEnvAttributes>,
>,
Primitives: NodePrimitives<
BlockHeader = ProviderHeader<Self::Provider>,
SignedTx = ProviderTx<Self::Provider>,
Receipt = ProviderReceipt<Self::Provider>,
Block = ProviderBlock<Self::Provider>,
>,
>,
{ {
#[inline] #[inline]
fn pending_block( fn pending_block(&self) -> &tokio::sync::Mutex<Option<PendingBlock<N::Primitives>>> {
&self,
) -> &tokio::sync::Mutex<
Option<PendingBlock<ProviderBlock<Self::Provider>, ProviderReceipt<Self::Provider>>>,
> {
self.inner.eth_api.pending_block() self.inner.eth_api.pending_block()
} }
fn next_env_attributes( #[inline]
&self, fn pending_env_builder(&self) -> &dyn PendingEnvBuilder<Self::Evm> {
parent: &SealedHeader<ProviderHeader<Self::Provider>>, self.inner.eth_api.pending_env_builder()
) -> Result<<Self::Evm as reth_evm::ConfigureEvm>::NextBlockEnvCtx, Self::Error> {
Ok(NextBlockEnvAttributes {
timestamp: parent.timestamp().saturating_add(12),
suggested_fee_recipient: parent.beneficiary(),
prev_randao: B256::random(),
gas_limit: parent.gas_limit(),
parent_beacon_block_root: parent.parent_beacon_block_root(),
withdrawals: None,
} }
.into())
#[inline]
fn pending_block_kind(&self) -> PendingBlockKind {
self.inner.eth_api.pending_block_kind()
} }
} }
impl<N> LoadReceipt for HlEthApi<N> impl<N, Rpc> LoadReceipt for HlEthApi<N, Rpc>
where where
Self: Send + Sync, N: RpcNodeCore,
N: FullNodeComponents<Types: NodeTypes<ChainSpec = HlChainSpec>>, EthApiError: FromEvmError<N::Evm>,
Self::Provider: Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError>,
TransactionsProvider<Transaction = TransactionSigned> + ReceiptProvider<Receipt = Receipt>,
{ {
async fn build_transaction_receipt(
&self,
tx: TransactionSigned,
meta: TransactionMeta,
receipt: Receipt,
) -> Result<RpcReceipt<Self::NetworkTypes>, Self::Error> {
let hash = meta.block_hash;
// get all receipts for the block
let all_receipts = self
.cache()
.get_receipts(hash)
.await
.map_err(Self::Error::from_eth_err)?
.ok_or(EthApiError::HeaderNotFound(hash.into()))?;
let blob_params = self.provider().chain_spec().blob_params_at_timestamp(meta.timestamp);
build_receipt(&tx, meta, &receipt, &all_receipts, blob_params, |receipt_with_bloom| {
match receipt.tx_type {
TxType::Legacy => ReceiptEnvelope::Legacy(receipt_with_bloom),
TxType::Eip2930 => ReceiptEnvelope::Eip2930(receipt_with_bloom),
TxType::Eip1559 => ReceiptEnvelope::Eip1559(receipt_with_bloom),
TxType::Eip4844 => ReceiptEnvelope::Eip4844(receipt_with_bloom),
TxType::Eip7702 => ReceiptEnvelope::Eip7702(receipt_with_bloom),
}
})
}
} }

View File

@ -1,51 +1,32 @@
use super::{HlEthApi, HlNodeCore}; use super::HlEthApi;
use crate::evm::transaction::HlTxEnv;
use alloy_rpc_types::TransactionRequest;
use reth::rpc::server_types::eth::EthApiError; use reth::rpc::server_types::eth::EthApiError;
use reth_evm::{block::BlockExecutorFactory, ConfigureEvm, EvmFactory, TxEnvFor}; use reth_evm::TxEnvFor;
use reth_primitives::NodePrimitives;
use reth_provider::{ProviderError, ProviderHeader, ProviderTx};
use reth_rpc_eth_api::{ use reth_rpc_eth_api::{
helpers::{estimate::EstimateCall, Call, EthCall, LoadBlock, LoadState, SpawnBlocking}, helpers::{estimate::EstimateCall, Call, EthCall},
FromEvmError, FullEthApiTypes, RpcConvert, RpcTypes, FromEvmError, RpcConvert, RpcNodeCore,
}; };
use revm::context::TxEnv;
impl<N> EthCall for HlEthApi<N> impl<N, Rpc> EthCall for HlEthApi<N, Rpc>
where where
Self: EstimateCall + LoadBlock + FullEthApiTypes, N: RpcNodeCore,
N: HlNodeCore, EthApiError: FromEvmError<N::Evm>,
Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError, TxEnv = TxEnvFor<N::Evm>>,
{ {
} }
impl<N> EstimateCall for HlEthApi<N> impl<N, Rpc> EstimateCall for HlEthApi<N, Rpc>
where where
Self: Call, N: RpcNodeCore,
Self::Error: From<EthApiError>, EthApiError: FromEvmError<N::Evm>,
N: HlNodeCore, Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError, TxEnv = TxEnvFor<N::Evm>>,
{ {
} }
impl<N> Call for HlEthApi<N> impl<N, Rpc> Call for HlEthApi<N, Rpc>
where where
Self: LoadState< N: RpcNodeCore,
Evm: ConfigureEvm< EthApiError: FromEvmError<N::Evm>,
Primitives: NodePrimitives< Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError, TxEnv = TxEnvFor<N::Evm>>,
BlockHeader = ProviderHeader<Self::Provider>,
SignedTx = ProviderTx<Self::Provider>,
>,
BlockExecutorFactory: BlockExecutorFactory<
EvmFactory: EvmFactory<Tx = HlTxEnv<TxEnv>>,
>,
>,
RpcConvert: RpcConvert<TxEnv = TxEnvFor<Self::Evm>, Network = Self::NetworkTypes>,
NetworkTypes: RpcTypes<TransactionRequest: From<TransactionRequest>>,
Error: FromEvmError<Self::Evm>
+ From<<Self::RpcConvert as RpcConvert>::Error>
+ From<ProviderError>,
> + SpawnBlocking,
Self::Error: From<EthApiError>,
N: HlNodeCore,
{ {
#[inline] #[inline]
fn call_gas_limit(&self) -> u64 { fn call_gas_limit(&self) -> u64 {

View File

@ -6,20 +6,15 @@ use crate::{
use alloy_consensus::BlockHeader; use alloy_consensus::BlockHeader;
use alloy_eips::eip4895::Withdrawal; use alloy_eips::eip4895::Withdrawal;
use alloy_primitives::B256; use alloy_primitives::B256;
use alloy_rpc_types_engine::{PayloadAttributes, PayloadError}; use alloy_rpc_types_engine::PayloadError;
use reth::{ use reth::{
api::{FullNodeComponents, NodeTypes}, api::{FullNodeComponents, NodeTypes},
builder::{rpc::EngineValidatorBuilder, AddOnsContext}, builder::{rpc::PayloadValidatorBuilder, AddOnsContext},
consensus::ConsensusError,
};
use reth_engine_primitives::{EngineValidator, ExecutionPayload, PayloadValidator};
use reth_payload_primitives::{
EngineApiMessageVersion, EngineObjectValidationError, NewPayloadError, PayloadOrAttributes,
PayloadTypes,
}; };
use reth_engine_primitives::{ExecutionPayload, PayloadValidator};
use reth_payload_primitives::NewPayloadError;
use reth_primitives::{RecoveredBlock, SealedBlock}; use reth_primitives::{RecoveredBlock, SealedBlock};
use reth_primitives_traits::Block as _; use reth_primitives_traits::Block as _;
use reth_trie_common::HashedPostState;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc; use std::sync::Arc;
@ -27,27 +22,27 @@ use super::payload::HlPayloadTypes;
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
#[non_exhaustive] #[non_exhaustive]
pub struct HlEngineValidatorBuilder; pub struct HlPayloadValidatorBuilder;
impl<Node, Types> EngineValidatorBuilder<Node> for HlEngineValidatorBuilder impl<Node, Types> PayloadValidatorBuilder<Node> for HlPayloadValidatorBuilder
where where
Types: NodeTypes<ChainSpec = HlChainSpec, Payload = HlPayloadTypes, Primitives = HlPrimitives>, Types: NodeTypes<ChainSpec = HlChainSpec, Payload = HlPayloadTypes, Primitives = HlPrimitives>,
Node: FullNodeComponents<Types = Types>, Node: FullNodeComponents<Types = Types>,
{ {
type Validator = HlEngineValidator; type Validator = HlPayloadValidator;
async fn build(self, ctx: &AddOnsContext<'_, Node>) -> eyre::Result<Self::Validator> { async fn build(self, ctx: &AddOnsContext<'_, Node>) -> eyre::Result<Self::Validator> {
Ok(HlEngineValidator::new(Arc::new(ctx.config.chain.clone().as_ref().clone()))) Ok(HlPayloadValidator::new(Arc::new(ctx.config.chain.clone().as_ref().clone())))
} }
} }
/// Validator for Optimism engine API. /// Validator for Optimism engine API.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct HlEngineValidator { pub struct HlPayloadValidator {
inner: HlExecutionPayloadValidator<HlChainSpec>, inner: HlExecutionPayloadValidator<HlChainSpec>,
} }
impl HlEngineValidator { impl HlPayloadValidator {
/// Instantiates a new validator. /// Instantiates a new validator.
pub fn new(chain_spec: Arc<HlChainSpec>) -> Self { pub fn new(chain_spec: Arc<HlChainSpec>) -> Self {
Self { inner: HlExecutionPayloadValidator { inner: chain_spec } } Self { inner: HlExecutionPayloadValidator { inner: chain_spec } }
@ -87,47 +82,17 @@ impl ExecutionPayload for HlExecutionData {
} }
} }
impl PayloadValidator for HlEngineValidator { impl PayloadValidator<HlPayloadTypes> for HlPayloadValidator {
type Block = HlBlock; type Block = HlBlock;
type ExecutionData = HlExecutionData;
fn ensure_well_formed_payload( fn ensure_well_formed_payload(
&self, &self,
payload: Self::ExecutionData, payload: HlExecutionData,
) -> Result<RecoveredBlock<Self::Block>, NewPayloadError> { ) -> Result<RecoveredBlock<Self::Block>, NewPayloadError> {
let sealed_block = let sealed_block =
self.inner.ensure_well_formed_payload(payload).map_err(NewPayloadError::other)?; self.inner.ensure_well_formed_payload(payload).map_err(NewPayloadError::other)?;
sealed_block.try_recover().map_err(|e| NewPayloadError::Other(e.into())) sealed_block.try_recover().map_err(|e| NewPayloadError::Other(e.into()))
} }
fn validate_block_post_execution_with_hashed_state(
&self,
_state_updates: &HashedPostState,
_block: &RecoveredBlock<Self::Block>,
) -> Result<(), ConsensusError> {
Ok(())
}
}
impl<Types> EngineValidator<Types> for HlEngineValidator
where
Types: PayloadTypes<PayloadAttributes = PayloadAttributes, ExecutionData = HlExecutionData>,
{
fn validate_version_specific_fields(
&self,
_version: EngineApiMessageVersion,
_payload_or_attrs: PayloadOrAttributes<'_, Self::ExecutionData, PayloadAttributes>,
) -> Result<(), EngineObjectValidationError> {
Ok(())
}
fn ensure_well_formed_attributes(
&self,
_version: EngineApiMessageVersion,
_attributes: &PayloadAttributes,
) -> Result<(), EngineObjectValidationError> {
Ok(())
}
} }
/// Execution payload validator. /// Execution payload validator.

View File

@ -1,104 +1,92 @@
use alloy_network::Ethereum; use alloy_network::Ethereum;
use alloy_primitives::U256; use alloy_primitives::U256;
use reth::{ use reth::{
api::{FullNodeTypes, HeaderTy, NodeTypes, PrimitivesTy},
builder::{ builder::{
rpc::{EthApiBuilder, EthApiCtx}, rpc::{EthApiBuilder, EthApiCtx},
FullNodeComponents, FullNodeComponents,
}, },
chainspec::EthChainSpec,
primitives::EthereumHardforks,
providers::ChainSpecProvider,
rpc::{ rpc::{
eth::{core::EthApiInner, DevSigner, FullEthApiServer}, eth::{core::EthApiInner, DevSigner, FullEthApiServer},
server_types::eth::{EthApiError, EthStateCache, FeeHistoryCache, GasPriceOracle}, server_types::eth::{
receipt::EthReceiptConverter, EthApiError, EthStateCache, FeeHistoryCache,
GasPriceOracle,
},
}, },
tasks::{ tasks::{
pool::{BlockingTaskGuard, BlockingTaskPool}, pool::{BlockingTaskGuard, BlockingTaskPool},
TaskSpawner, TaskSpawner,
}, },
transaction_pool::TransactionPool,
}; };
use reth_evm::ConfigureEvm; use reth_evm::ConfigureEvm;
use reth_network::NetworkInfo; use reth_provider::{ChainSpecProvider, ProviderHeader, ProviderTx};
use reth_primitives::NodePrimitives; use reth_rpc::RpcTypes;
use reth_provider::{
BlockNumReader, BlockReader, BlockReaderIdExt, ProviderBlock, ProviderHeader, ProviderReceipt,
ProviderTx, StageCheckpointReader, StateProviderFactory,
};
use reth_rpc_eth_api::{ use reth_rpc_eth_api::{
helpers::{ helpers::{
AddDevSigners, EthApiSpec, EthFees, EthSigner, EthState, LoadBlock, LoadFee, LoadState, pending_block::BuildPendingEnv, spec::SignersForApi, AddDevSigners, EthApiSpec, EthFees,
SpawnBlocking, Trace, EthState, LoadFee, LoadState, SpawnBlocking, Trace,
}, },
EthApiTypes, FromEvmError, RpcConverter, RpcNodeCore, RpcNodeCoreExt, EthApiTypes, FromEvmError, RpcConvert, RpcConverter, RpcNodeCore, RpcNodeCoreExt,
SignableTxRequest,
}; };
use std::{fmt, sync::Arc}; use std::{fmt, marker::PhantomData, sync::Arc};
use crate::chainspec::HlChainSpec;
mod block; mod block;
mod call; mod call;
pub mod engine_api; pub mod engine_api;
mod transaction; mod transaction;
/// A helper trait with requirements for [`RpcNodeCore`] to be used in [`HlEthApi`].
pub trait HlNodeCore: RpcNodeCore<Provider: BlockReader> {}
impl<T> HlNodeCore for T where T: RpcNodeCore<Provider: BlockReader> {}
/// Adapter for [`EthApiInner`], which holds all the data required to serve core `eth_` API.
pub type EthApiNodeBackend<N> = EthApiInner<
<N as RpcNodeCore>::Provider,
<N as RpcNodeCore>::Pool,
<N as RpcNodeCore>::Network,
<N as RpcNodeCore>::Evm,
>;
/// Container type `HlEthApi` /// Container type `HlEthApi`
#[allow(missing_debug_implementations)] pub(crate) struct HlEthApiInner<N: RpcNodeCore, Rpc: RpcConvert> {
pub(crate) struct HlEthApiInner<N: HlNodeCore> {
/// Gateway to node's core components. /// Gateway to node's core components.
pub(crate) eth_api: EthApiNodeBackend<N>, pub(crate) eth_api: EthApiInner<N, Rpc>,
} }
type HlRpcConvert<N, NetworkT> =
RpcConverter<NetworkT, <N as FullNodeComponents>::Evm, EthReceiptConverter<HlChainSpec>>;
#[derive(Clone)] #[derive(Clone)]
pub struct HlEthApi<N: HlNodeCore> { pub struct HlEthApi<N: RpcNodeCore, Rpc: RpcConvert> {
/// Gateway to node's core components. /// Gateway to node's core components.
pub(crate) inner: Arc<HlEthApiInner<N>>, pub(crate) inner: Arc<HlEthApiInner<N, Rpc>>,
/// Converter for RPC types.
tx_resp_builder: RpcConverter<Ethereum, N::Evm, EthApiError, ()>,
/// Whether the node is in HL node compliant mode.
pub(crate) hl_node_compliant: bool,
} }
impl<N: HlNodeCore> fmt::Debug for HlEthApi<N> { impl<N, Rpc> fmt::Debug for HlEthApi<N, Rpc>
where
N: RpcNodeCore,
Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("HlEthApi").finish_non_exhaustive() f.debug_struct("HlEthApi").finish_non_exhaustive()
} }
} }
impl<N> EthApiTypes for HlEthApi<N> impl<N, Rpc> EthApiTypes for HlEthApi<N, Rpc>
where where
Self: Send + Sync, N: RpcNodeCore,
N: HlNodeCore, Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError>,
N::Evm: std::fmt::Debug,
{ {
type Error = EthApiError; type Error = EthApiError;
type NetworkTypes = Ethereum; type NetworkTypes = Rpc::Network;
type RpcConvert = RpcConverter<Ethereum, N::Evm, EthApiError, ()>; type RpcConvert = Rpc;
fn tx_resp_builder(&self) -> &Self::RpcConvert { fn tx_resp_builder(&self) -> &Self::RpcConvert {
&self.tx_resp_builder self.inner.eth_api.tx_resp_builder()
} }
} }
impl<N> RpcNodeCore for HlEthApi<N> impl<N, Rpc> RpcNodeCore for HlEthApi<N, Rpc>
where where
N: HlNodeCore, N: RpcNodeCore,
Rpc: RpcConvert<Primitives = N::Primitives>,
{ {
type Primitives = N::Primitives; type Primitives = N::Primitives;
type Provider = N::Provider; type Provider = N::Provider;
type Pool = N::Pool; type Pool = N::Pool;
type Evm = <N as RpcNodeCore>::Evm; type Evm = N::Evm;
type Network = <N as RpcNodeCore>::Network; type Network = N::Network;
type PayloadBuilder = ();
#[inline] #[inline]
fn pool(&self) -> &Self::Pool { fn pool(&self) -> &Self::Pool {
@ -115,37 +103,30 @@ where
self.inner.eth_api.network() self.inner.eth_api.network()
} }
#[inline]
fn payload_builder(&self) -> &Self::PayloadBuilder {
&()
}
#[inline] #[inline]
fn provider(&self) -> &Self::Provider { fn provider(&self) -> &Self::Provider {
self.inner.eth_api.provider() self.inner.eth_api.provider()
} }
} }
impl<N> RpcNodeCoreExt for HlEthApi<N> impl<N, Rpc> RpcNodeCoreExt for HlEthApi<N, Rpc>
where where
N: HlNodeCore, N: RpcNodeCore,
Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError>,
{ {
#[inline] #[inline]
fn cache(&self) -> &EthStateCache<ProviderBlock<N::Provider>, ProviderReceipt<N::Provider>> { fn cache(&self) -> &EthStateCache<N::Primitives> {
self.inner.eth_api.cache() self.inner.eth_api.cache()
} }
} }
impl<N> EthApiSpec for HlEthApi<N> impl<N, Rpc> EthApiSpec for HlEthApi<N, Rpc>
where where
N: HlNodeCore< N: RpcNodeCore,
Provider: ChainSpecProvider<ChainSpec: EthereumHardforks> Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError>,
+ BlockNumReader
+ StageCheckpointReader,
Network: NetworkInfo,
>,
{ {
type Transaction = ProviderTx<Self::Provider>; type Transaction = ProviderTx<Self::Provider>;
type Rpc = Rpc::Network;
#[inline] #[inline]
fn starting_block(&self) -> U256 { fn starting_block(&self) -> U256 {
@ -153,16 +134,15 @@ where
} }
#[inline] #[inline]
fn signers(&self) -> &parking_lot::RwLock<Vec<Box<dyn EthSigner<ProviderTx<Self::Provider>>>>> { fn signers(&self) -> &SignersForApi<Self> {
self.inner.eth_api.signers() self.inner.eth_api.signers()
} }
} }
impl<N> SpawnBlocking for HlEthApi<N> impl<N, Rpc> SpawnBlocking for HlEthApi<N, Rpc>
where where
Self: Send + Sync + Clone + 'static, N: RpcNodeCore,
N: HlNodeCore, Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError>,
N::Evm: std::fmt::Debug,
{ {
#[inline] #[inline]
fn io_task_spawner(&self) -> impl TaskSpawner { fn io_task_spawner(&self) -> impl TaskSpawner {
@ -180,14 +160,11 @@ where
} }
} }
impl<N> LoadFee for HlEthApi<N> impl<N, Rpc> LoadFee for HlEthApi<N, Rpc>
where where
Self: LoadBlock<Provider = N::Provider>, N: RpcNodeCore,
N: HlNodeCore< EthApiError: FromEvmError<N::Evm>,
Provider: BlockReaderIdExt Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError>,
+ ChainSpecProvider<ChainSpec: EthChainSpec + EthereumHardforks>
+ StateProviderFactory,
>,
{ {
#[inline] #[inline]
fn gas_oracle(&self) -> &GasPriceOracle<Self::Provider> { fn gas_oracle(&self) -> &GasPriceOracle<Self::Provider> {
@ -195,25 +172,22 @@ where
} }
#[inline] #[inline]
fn fee_history_cache(&self) -> &FeeHistoryCache { fn fee_history_cache(&self) -> &FeeHistoryCache<ProviderHeader<N::Provider>> {
self.inner.eth_api.fee_history_cache() self.inner.eth_api.fee_history_cache()
} }
} }
impl<N> LoadState for HlEthApi<N> impl<N, Rpc> LoadState for HlEthApi<N, Rpc>
where where
N: HlNodeCore< N: RpcNodeCore,
Provider: StateProviderFactory + ChainSpecProvider<ChainSpec: EthereumHardforks>, Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError>,
Pool: TransactionPool,
>,
N::Evm: std::fmt::Debug,
{ {
} }
impl<N> EthState for HlEthApi<N> impl<N, Rpc> EthState for HlEthApi<N, Rpc>
where where
Self: LoadState + SpawnBlocking, N: RpcNodeCore,
N: HlNodeCore, Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError>,
{ {
#[inline] #[inline]
fn max_proof_window(&self) -> u64 { fn max_proof_window(&self) -> u64 {
@ -221,36 +195,28 @@ where
} }
} }
impl<N> EthFees for HlEthApi<N> impl<N, Rpc> EthFees for HlEthApi<N, Rpc>
where where
Self: LoadFee< N: RpcNodeCore,
Provider: ChainSpecProvider< EthApiError: FromEvmError<N::Evm>,
ChainSpec: EthChainSpec<Header = ProviderHeader<Self::Provider>>, Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError>,
>,
>,
N: HlNodeCore,
{ {
} }
impl<N> Trace for HlEthApi<N> impl<N, Rpc> Trace for HlEthApi<N, Rpc>
where where
Self: RpcNodeCore<Provider: BlockReader> N: RpcNodeCore,
+ LoadState< EthApiError: FromEvmError<N::Evm>,
Evm: ConfigureEvm< Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError>,
Primitives: NodePrimitives<
BlockHeader = ProviderHeader<Self::Provider>,
SignedTx = ProviderTx<Self::Provider>,
>,
>,
Error: FromEvmError<Self::Evm>,
>,
N: HlNodeCore,
{ {
} }
impl<N> AddDevSigners for HlEthApi<N> impl<N, Rpc> AddDevSigners for HlEthApi<N, Rpc>
where where
N: HlNodeCore, N: RpcNodeCore,
Rpc: RpcConvert<
Network: RpcTypes<TransactionRequest: SignableTxRequest<ProviderTx<N::Provider>>>,
>,
{ {
fn with_dev_accounts(&self) { fn with_dev_accounts(&self) {
*self.inner.eth_api.signers().write() = DevSigner::random_signers(20) *self.inner.eth_api.signers().write() = DevSigner::random_signers(20)
@ -258,40 +224,41 @@ where
} }
/// Builds [`HlEthApi`] for HL. /// Builds [`HlEthApi`] for HL.
#[derive(Debug, Default)] #[derive(Debug)]
#[non_exhaustive] #[non_exhaustive]
pub struct HlEthApiBuilder { pub struct HlEthApiBuilder<NetworkT = Ethereum> {
/// Whether the node is in HL node compliant mode. /// Marker for network types.
pub(crate) hl_node_compliant: bool, pub(crate) _nt: PhantomData<NetworkT>,
} }
impl<N> EthApiBuilder<N> for HlEthApiBuilder impl<NetworkT> Default for HlEthApiBuilder<NetworkT> {
fn default() -> Self {
Self { _nt: PhantomData }
}
}
impl<N, NetworkT> EthApiBuilder<N> for HlEthApiBuilder<NetworkT>
where where
N: FullNodeComponents, N: FullNodeComponents<Types: NodeTypes<ChainSpec = HlChainSpec>>
HlEthApi<N>: FullEthApiServer<Provider = N::Provider, Pool = N::Pool>, + RpcNodeCore<
Primitives = PrimitivesTy<N::Types>,
Evm: ConfigureEvm<NextBlockEnvCtx: BuildPendingEnv<HeaderTy<N::Types>>>,
>,
NetworkT: RpcTypes,
HlRpcConvert<N, NetworkT>: RpcConvert<Network = NetworkT, Primitives = PrimitivesTy<N::Types>>,
HlEthApi<N, HlRpcConvert<N, NetworkT>>: FullEthApiServer<
Provider = <N as FullNodeTypes>::Provider,
Pool = <N as FullNodeComponents>::Pool,
> + AddDevSigners,
{ {
type EthApi = HlEthApi<N>; type EthApi = HlEthApi<N, HlRpcConvert<N, NetworkT>>;
async fn build_eth_api(self, ctx: EthApiCtx<'_, N>) -> eyre::Result<Self::EthApi> { async fn build_eth_api(self, ctx: EthApiCtx<'_, N>) -> eyre::Result<Self::EthApi> {
let eth_api = reth::rpc::eth::EthApiBuilder::new( let provider = FullNodeComponents::provider(ctx.components);
ctx.components.provider().clone(), let rpc_converter =
ctx.components.pool().clone(), RpcConverter::new(EthReceiptConverter::<HlChainSpec>::new(provider.chain_spec()));
ctx.components.network().clone(), let eth_api = ctx.eth_api_builder().with_rpc_converter(rpc_converter).build_inner();
ctx.components.evm_config().clone(),
)
.eth_cache(ctx.cache)
.task_spawner(ctx.components.task_executor().clone())
.gas_cap(ctx.config.rpc_gas_cap.into())
.max_simulate_blocks(ctx.config.rpc_max_simulate_blocks)
.eth_proof_window(ctx.config.eth_proof_window)
.fee_history_cache_config(ctx.config.fee_history_cache)
.proof_permits(ctx.config.proof_permits)
.build_inner();
Ok(HlEthApi { Ok(HlEthApi { inner: Arc::new(HlEthApiInner { eth_api }) })
inner: Arc::new(HlEthApiInner { eth_api }),
tx_resp_builder: Default::default(),
hl_node_compliant: self.hl_node_compliant,
})
} }
} }

View File

@ -1,51 +1,28 @@
use super::HlNodeCore;
use crate::node::rpc::HlEthApi; use crate::node::rpc::HlEthApi;
use alloy_primitives::{Bytes, B256}; use alloy_primitives::{Bytes, B256};
use reth::{ use reth::rpc::server_types::eth::EthApiError;
rpc::server_types::eth::utils::recover_raw_transaction,
transaction_pool::{PoolTransaction, TransactionOrigin, TransactionPool},
};
use reth_provider::{BlockReader, BlockReaderIdExt, ProviderTx, TransactionsProvider};
use reth_rpc_eth_api::{ use reth_rpc_eth_api::{
helpers::{EthSigner, EthTransactions, LoadTransaction, SpawnBlocking}, helpers::{spec::SignersForRpc, EthTransactions, LoadTransaction},
FromEthApiError, FullEthApiTypes, RpcNodeCore, RpcNodeCoreExt, RpcConvert, RpcNodeCore,
}; };
impl<N> LoadTransaction for HlEthApi<N> impl<N, Rpc> LoadTransaction for HlEthApi<N, Rpc>
where where
Self: SpawnBlocking + FullEthApiTypes + RpcNodeCoreExt, N: RpcNodeCore,
N: HlNodeCore<Provider: TransactionsProvider, Pool: TransactionPool>, Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError>,
Self::Pool: TransactionPool,
{ {
} }
impl<N> EthTransactions for HlEthApi<N> impl<N, Rpc> EthTransactions for HlEthApi<N, Rpc>
where where
Self: LoadTransaction<Provider: BlockReaderIdExt>, N: RpcNodeCore,
N: HlNodeCore<Provider: BlockReader<Transaction = ProviderTx<Self::Provider>>>, Rpc: RpcConvert<Primitives = N::Primitives, Error = EthApiError>,
{ {
fn signers(&self) -> &parking_lot::RwLock<Vec<Box<dyn EthSigner<ProviderTx<Self::Provider>>>>> { fn signers(&self) -> &SignersForRpc<Self::Provider, Self::NetworkTypes> {
self.inner.eth_api.signers() self.inner.eth_api.signers()
} }
/// Decodes and recovers the transaction and submits it to the pool. async fn send_raw_transaction(&self, _tx: Bytes) -> Result<B256, Self::Error> {
/// unreachable!()
/// Returns the hash of the transaction.
async fn send_raw_transaction(&self, tx: Bytes) -> Result<B256, Self::Error> {
let recovered = recover_raw_transaction(&tx)?;
// broadcast raw transaction to subscribers if there is any.
self.inner.eth_api.broadcast_raw_transaction(tx);
let pool_transaction = <Self::Pool as TransactionPool>::Transaction::from_pooled(recovered);
// submit the transaction to the pool with a `Local` origin
let hash = self
.pool()
.add_transaction(TransactionOrigin::Local, pool_transaction)
.await
.map_err(Self::Error::from_eth_err)?;
Ok(hash)
} }
} }

View File

@ -3,8 +3,7 @@ use eyre::{Error, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::BTreeMap; use std::collections::BTreeMap;
pub(crate) const MAINNET_CHAIN_ID: u64 = 999; use crate::chainspec::{MAINNET_CHAIN_ID, TESTNET_CHAIN_ID};
pub(crate) const TESTNET_CHAIN_ID: u64 = 998;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
struct EvmContract { struct EvmContract {

View File

@ -91,7 +91,8 @@ impl BlockSourceConfig {
pub async fn create_cached_block_source(&self, next_block_number: u64) -> BlockSourceBoxed { pub async fn create_cached_block_source(&self, next_block_number: u64) -> BlockSourceBoxed {
let block_source = self.create_block_source().await; let block_source = self.create_block_source().await;
let block_source = self.create_block_source_from_node(next_block_number, block_source).await; let block_source =
self.create_block_source_from_node(next_block_number, block_source).await;
Arc::new(Box::new(CachedBlockSource::new(block_source))) Arc::new(Box::new(CachedBlockSource::new(block_source)))
} }
} }

View File

@ -138,7 +138,8 @@ pub struct HlNodeBlockSource {
pub fallback: BlockSourceBoxed, pub fallback: BlockSourceBoxed,
pub local_ingest_dir: PathBuf, pub local_ingest_dir: PathBuf,
pub local_blocks_cache: Arc<Mutex<LocalBlocksCache>>, // height → block pub local_blocks_cache: Arc<Mutex<LocalBlocksCache>>, // height → block
pub last_local_fetch: Arc<Mutex<Option<(u64, OffsetDateTime)>>>, // for rate limiting requests to fallback // for rate limiting requests to fallback
pub last_local_fetch: Arc<Mutex<Option<(u64, OffsetDateTime)>>>,
} }
impl BlockSource for HlNodeBlockSource { impl BlockSource for HlNodeBlockSource {
@ -217,9 +218,7 @@ fn read_last_complete_line<R: Read + Seek>(read: &mut R) -> Option<(BlockAndRece
if let Some(idx) = last_line.iter().rposition(|&b| b == b'\n') { if let Some(idx) = last_line.iter().rposition(|&b| b == b'\n') {
let candidate = &last_line[idx + 1..]; let candidate = &last_line[idx + 1..];
if let Ok((evm_block, height)) = if let Ok((evm_block, height)) = line_to_evm_block(str::from_utf8(candidate).unwrap()) {
line_to_evm_block(str::from_utf8(candidate).unwrap())
{
return Some((evm_block, height)); return Some((evm_block, height));
} }
// Incomplete line; truncate and continue // Incomplete line; truncate and continue
@ -241,7 +240,8 @@ impl HlNodeBlockSource {
/// requests to S3 while it'll return 404. /// requests to S3 while it'll return 404.
/// ///
/// To avoid unnecessary fallback, we set a short threshold period. /// To avoid unnecessary fallback, we set a short threshold period.
/// This threshold is several times longer than the expected block time, reducing redundant fallback attempts. /// This threshold is several times longer than the expected block time, reducing redundant
/// fallback attempts.
pub(crate) const MAX_ALLOWED_THRESHOLD_BEFORE_FALLBACK: Duration = Duration::milliseconds(5000); pub(crate) const MAX_ALLOWED_THRESHOLD_BEFORE_FALLBACK: Duration = Duration::milliseconds(5000);
async fn update_last_fetch(&self, height: u64, now: OffsetDateTime) { async fn update_last_fetch(&self, height: u64, now: OffsetDateTime) {
@ -327,7 +327,8 @@ impl HlNodeBlockSource {
&mut 0, &mut 0,
ScanOptions { start_height: cutoff_height, only_load_ranges: true }, ScanOptions { start_height: cutoff_height, only_load_ranges: true },
); );
// Only store the block ranges for now; actual block data will be loaded lazily later to optimize memory usage // Only store the block ranges for now; actual block data will be loaded lazily later to
// optimize memory usage
scan_result.new_blocks.clear(); scan_result.new_blocks.clear();
u_cache.load_scan_result(scan_result); u_cache.load_scan_result(scan_result);
} }
@ -434,13 +435,13 @@ impl HlNodeBlockSource {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::node::types::reth_compat; use crate::{
use crate::node::types::ReadPrecompileCalls; node::types::{reth_compat, ReadPrecompileCalls},
use crate::pseudo_peer::sources::LocalBlockSource; pseudo_peer::sources::LocalBlockSource,
};
use alloy_consensus::{BlockBody, Header}; use alloy_consensus::{BlockBody, Header};
use alloy_primitives::{Address, Bloom, Bytes, B256, B64, U256}; use alloy_primitives::{Address, Bloom, Bytes, B256, B64, U256};
use std::io::Write; use std::{io::Write, time::Duration};
use std::time::Duration;
#[test] #[test]
fn test_datetime_from_path() { fn test_datetime_from_path() {