Make it compilable (still bunch to fix!)

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

173
src/node/rpc/block.rs Normal file
View File

@ -0,0 +1,173 @@
use crate::{
chainspec::HlChainSpec,
node::rpc::{HlEthApi, HlNodeCore},
node::{HlBlock, HlPrimitives},
};
use alloy_consensus::BlockHeader;
use alloy_primitives::B256;
use reth::{
api::NodeTypes,
builder::FullNodeComponents,
primitives::{Receipt, SealedHeader, TransactionMeta, TransactionSigned},
providers::{BlockReaderIdExt, ProviderHeader, ReceiptProvider, TransactionsProvider},
rpc::{
eth::EthApiTypes,
server_types::eth::{error::FromEvmError, EthApiError, EthReceiptBuilder, PendingBlock},
types::{BlockId, TransactionReceipt},
},
transaction_pool::{PoolTransaction, TransactionPool},
};
use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_evm::{ConfigureEvm, NextBlockEnvAttributes};
use reth_primitives_traits::BlockBody as _;
use reth_provider::{
BlockReader, ChainSpecProvider, HeaderProvider, ProviderBlock, ProviderReceipt, ProviderTx,
StateProviderFactory,
};
use reth_rpc_eth_api::{
helpers::{EthBlocks, LoadBlock, LoadPendingBlock, LoadReceipt, SpawnBlocking},
types::RpcTypes,
FromEthApiError, RpcNodeCore, RpcNodeCoreExt, RpcReceipt,
};
impl<N> EthBlocks for HlEthApi<N>
where
Self: LoadBlock<
Error = EthApiError,
NetworkTypes: RpcTypes<Receipt = TransactionReceipt>,
Provider: BlockReader<Transaction = TransactionSigned, Receipt = Receipt>,
>,
N: HlNodeCore<Provider: ChainSpecProvider<ChainSpec = HlChainSpec> + HeaderProvider>,
{
async fn block_receipts(
&self,
block_id: BlockId,
) -> Result<Option<Vec<RpcReceipt<Self::NetworkTypes>>>, Self::Error>
where
Self: LoadReceipt,
{
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())
.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,
};
EthReceiptBuilder::new(tx, meta, receipt, &receipts, blob_params)
.map(|builder| builder.build())
})
.collect::<Result<Vec<_>, Self::Error>>()
.map(Some);
}
Ok(None)
}
}
impl<N> LoadBlock for HlEthApi<N>
where
Self: LoadPendingBlock
+ SpawnBlocking
+ RpcNodeCoreExt<
Pool: TransactionPool<
Transaction: PoolTransaction<Consensus = ProviderTx<Self::Provider>>,
>,
>,
N: HlNodeCore,
{
}
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>,
>,
N: RpcNodeCore<
Provider: BlockReaderIdExt<
Transaction = TransactionSigned,
Block = HlBlock,
Receipt = Receipt,
Header = alloy_consensus::Header,
> + ChainSpecProvider<ChainSpec: EthChainSpec + EthereumHardforks>
+ StateProviderFactory,
Pool: TransactionPool<Transaction: PoolTransaction<Consensus = ProviderTx<N::Provider>>>,
Evm: ConfigureEvm<Primitives = HlPrimitives, NextBlockEnvCtx = NextBlockEnvAttributes>,
>,
{
#[inline]
fn pending_block(
&self,
) -> &tokio::sync::Mutex<
Option<PendingBlock<ProviderBlock<Self::Provider>, ProviderReceipt<Self::Provider>>>,
> {
self.inner.eth_api.pending_block()
}
fn next_env_attributes(
&self,
parent: &SealedHeader<ProviderHeader<Self::Provider>>,
) -> 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,
})
}
}
impl<N> LoadReceipt for HlEthApi<N>
where
Self: Send + Sync,
N: FullNodeComponents<Types: NodeTypes<ChainSpec = HlChainSpec>>,
Self::Provider:
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);
Ok(EthReceiptBuilder::new(&tx, meta, &receipt, &all_receipts, blob_params)?.build())
}
}

164
src/node/rpc/call.rs Normal file
View File

@ -0,0 +1,164 @@
use super::{HlEthApi, HlNodeCore};
use crate::evm::transaction::HlTxEnv;
use alloy_consensus::TxType;
use alloy_primitives::{TxKind, U256};
use alloy_rpc_types::TransactionRequest;
use alloy_signer::Either;
use reth::rpc::server_types::eth::{revm_utils::CallFees, EthApiError, RpcInvalidTransactionError};
use reth_evm::{block::BlockExecutorFactory, ConfigureEvm, EvmEnv, EvmFactory, SpecFor};
use reth_primitives::NodePrimitives;
use reth_provider::{ProviderHeader, ProviderTx};
use reth_rpc_eth_api::{
helpers::{estimate::EstimateCall, Call, EthCall, LoadBlock, LoadState, SpawnBlocking},
FromEthApiError, FromEvmError, FullEthApiTypes, IntoEthApiError,
};
use revm::{
context::{Block as _, TxEnv},
Database,
};
impl<N> EthCall for HlEthApi<N>
where
Self: EstimateCall + LoadBlock + FullEthApiTypes,
N: HlNodeCore,
{
}
impl<N> EstimateCall for HlEthApi<N>
where
Self: Call,
Self::Error: From<EthApiError>,
N: HlNodeCore,
{
}
impl<N> Call for HlEthApi<N>
where
Self: LoadState<
Evm: ConfigureEvm<
Primitives: NodePrimitives<
BlockHeader = ProviderHeader<Self::Provider>,
SignedTx = ProviderTx<Self::Provider>,
>,
BlockExecutorFactory: BlockExecutorFactory<
EvmFactory: EvmFactory<Tx = HlTxEnv<TxEnv>>,
>,
>,
Error: FromEvmError<Self::Evm>,
> + SpawnBlocking,
Self::Error: From<EthApiError>,
N: HlNodeCore,
{
#[inline]
fn call_gas_limit(&self) -> u64 {
self.inner.eth_api.gas_cap()
}
#[inline]
fn max_simulate_blocks(&self) -> u64 {
self.inner.eth_api.max_simulate_blocks()
}
fn create_txn_env(
&self,
evm_env: &EvmEnv<SpecFor<Self::Evm>>,
request: TransactionRequest,
mut db: impl Database<Error: Into<EthApiError>>,
) -> Result<HlTxEnv<TxEnv>, Self::Error> {
// Ensure that if versioned hashes are set, they're not empty
if request.blob_versioned_hashes.as_ref().is_some_and(|hashes| hashes.is_empty()) {
return Err(RpcInvalidTransactionError::BlobTransactionMissingBlobHashes.into_eth_err())
}
let tx_type = if request.authorization_list.is_some() {
TxType::Eip7702
} else if request.sidecar.is_some() || request.max_fee_per_blob_gas.is_some() {
TxType::Eip4844
} else if request.max_fee_per_gas.is_some() || request.max_priority_fee_per_gas.is_some() {
TxType::Eip1559
} else if request.access_list.is_some() {
TxType::Eip2930
} else {
TxType::Legacy
} as u8;
let TransactionRequest {
from,
to,
gas_price,
max_fee_per_gas,
max_priority_fee_per_gas,
gas,
value,
input,
nonce,
access_list,
chain_id,
blob_versioned_hashes,
max_fee_per_blob_gas,
authorization_list,
transaction_type: _,
sidecar: _,
} = request;
let CallFees { max_priority_fee_per_gas, gas_price, max_fee_per_blob_gas } =
CallFees::ensure_fees(
gas_price.map(U256::from),
max_fee_per_gas.map(U256::from),
max_priority_fee_per_gas.map(U256::from),
U256::from(evm_env.block_env.basefee),
blob_versioned_hashes.as_deref(),
max_fee_per_blob_gas.map(U256::from),
evm_env.block_env.blob_gasprice().map(U256::from),
)?;
let gas_limit = gas.unwrap_or(
// Use maximum allowed gas limit. The reason for this
// is that both Erigon and Geth use pre-configured gas cap even if
// it's possible to derive the gas limit from the block:
// <https://github.com/ledgerwatch/erigon/blob/eae2d9a79cb70dbe30b3a6b79c436872e4605458/cmd/rpcdaemon/commands/trace_adhoc.go#L956
// https://github.com/ledgerwatch/erigon/blob/eae2d9a79cb70dbe30b3a6b79c436872e4605458/eth/ethconfig/config.go#L94>
evm_env.block_env.gas_limit,
);
let chain_id = chain_id.unwrap_or(evm_env.cfg_env.chain_id);
let caller = from.unwrap_or_default();
let nonce = if let Some(nonce) = nonce {
nonce
} else {
db.basic(caller).map_err(Into::into)?.map(|acc| acc.nonce).unwrap_or_default()
};
let env = TxEnv {
tx_type,
gas_limit,
nonce,
caller,
gas_price: gas_price.saturating_to(),
gas_priority_fee: max_priority_fee_per_gas.map(|v| v.saturating_to()),
kind: to.unwrap_or(TxKind::Create),
value: value.unwrap_or_default(),
data: input
.try_into_unique_input()
.map_err(Self::Error::from_eth_err)?
.unwrap_or_default(),
chain_id: Some(chain_id),
access_list: access_list.unwrap_or_default(),
// EIP-4844 fields
blob_hashes: blob_versioned_hashes.unwrap_or_default(),
max_fee_per_blob_gas: max_fee_per_blob_gas
.map(|v| v.saturating_to())
.unwrap_or_default(),
// EIP-7702 fields
authorization_list: authorization_list
.unwrap_or_default()
.into_iter()
.map(Either::Left)
.collect(),
};
Ok(HlTxEnv::new(env))
}
}

View File

@ -0,0 +1,20 @@
use super::HlEngineApi;
use reth::{
api::{AddOnsContext, FullNodeComponents},
builder::rpc::EngineApiBuilder,
};
/// Builder for mocked [`HlEngineApi`] implementation.
#[derive(Debug, Default)]
pub struct HlEngineApiBuilder;
impl<N> EngineApiBuilder<N> for HlEngineApiBuilder
where
N: FullNodeComponents,
{
type EngineApi = HlEngineApi;
async fn build_engine_api(self, _ctx: &AddOnsContext<'_, N>) -> eyre::Result<Self::EngineApi> {
Ok(HlEngineApi::default())
}
}

View File

@ -0,0 +1,16 @@
use jsonrpsee_core::server::RpcModule;
use reth::rpc::api::IntoEngineApiRpcModule;
pub mod builder;
pub mod payload;
pub mod validator;
impl IntoEngineApiRpcModule for HlEngineApi {
fn into_rpc_module(self) -> RpcModule<()> {
RpcModule::new(())
}
}
#[derive(Debug, Default)]
#[non_exhaustive]
pub struct HlEngineApi;

View File

@ -0,0 +1,27 @@
use crate::node::{engine::HlBuiltPayload, rpc::engine_api::validator::HlExecutionData};
use reth::{
payload::EthPayloadBuilderAttributes,
primitives::{NodePrimitives, SealedBlock},
};
use reth_node_ethereum::engine::EthPayloadAttributes;
use reth_payload_primitives::{BuiltPayload, PayloadTypes};
/// A default payload type for [`HlPayloadTypes`]
#[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)]
#[non_exhaustive]
pub struct HlPayloadTypes;
impl PayloadTypes for HlPayloadTypes {
type BuiltPayload = HlBuiltPayload;
type PayloadAttributes = EthPayloadAttributes;
type PayloadBuilderAttributes = EthPayloadBuilderAttributes;
type ExecutionData = HlExecutionData;
fn block_to_payload(
block: SealedBlock<
<<Self::BuiltPayload as BuiltPayload>::Primitives as NodePrimitives>::Block,
>,
) -> Self::ExecutionData {
HlExecutionData(block.into_block())
}
}

View File

@ -0,0 +1,174 @@
use crate::{
chainspec::HlChainSpec,
hardforks::HlHardforks,
node::{HlBlock, HlPrimitives},
};
use alloy_consensus::BlockHeader;
use alloy_eips::eip4895::Withdrawal;
use alloy_primitives::B256;
use alloy_rpc_types_engine::{PayloadAttributes, PayloadError};
use reth::{
api::{FullNodeComponents, NodeTypes},
builder::{rpc::EngineValidatorBuilder, AddOnsContext},
consensus::ConsensusError,
};
use reth_engine_primitives::{EngineValidator, ExecutionPayload, PayloadValidator};
use reth_payload_primitives::{
EngineApiMessageVersion, EngineObjectValidationError, NewPayloadError, PayloadOrAttributes,
PayloadTypes,
};
use reth_primitives::{RecoveredBlock, SealedBlock};
use reth_primitives_traits::Block as _;
use reth_trie_common::HashedPostState;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use super::payload::HlPayloadTypes;
#[derive(Debug, Default, Clone)]
#[non_exhaustive]
pub struct HlEngineValidatorBuilder;
impl<Node, Types> EngineValidatorBuilder<Node> for HlEngineValidatorBuilder
where
Types: NodeTypes<ChainSpec = HlChainSpec, Payload = HlPayloadTypes, Primitives = HlPrimitives>,
Node: FullNodeComponents<Types = Types>,
{
type Validator = HlEngineValidator;
async fn build(self, ctx: &AddOnsContext<'_, Node>) -> eyre::Result<Self::Validator> {
Ok(HlEngineValidator::new(Arc::new(
ctx.config.chain.clone().as_ref().clone(),
)))
}
}
/// Validator for Optimism engine API.
#[derive(Debug, Clone)]
pub struct HlEngineValidator {
inner: HlExecutionPayloadValidator<HlChainSpec>,
}
impl HlEngineValidator {
/// Instantiates a new validator.
pub fn new(chain_spec: Arc<HlChainSpec>) -> Self {
Self {
inner: HlExecutionPayloadValidator { inner: chain_spec },
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HlExecutionData(pub HlBlock);
impl ExecutionPayload for HlExecutionData {
fn parent_hash(&self) -> B256 {
self.0.header.parent_hash()
}
fn block_hash(&self) -> B256 {
self.0.header.hash_slow()
}
fn block_number(&self) -> u64 {
self.0.header.number()
}
fn withdrawals(&self) -> Option<&Vec<Withdrawal>> {
None
}
fn parent_beacon_block_root(&self) -> Option<B256> {
None
}
fn timestamp(&self) -> u64 {
self.0.header.timestamp()
}
fn gas_used(&self) -> u64 {
self.0.header.gas_used()
}
}
impl PayloadValidator for HlEngineValidator {
type Block = HlBlock;
type ExecutionData = HlExecutionData;
fn ensure_well_formed_payload(
&self,
payload: Self::ExecutionData,
) -> Result<RecoveredBlock<Self::Block>, NewPayloadError> {
let sealed_block = self
.inner
.ensure_well_formed_payload(payload)
.map_err(NewPayloadError::other)?;
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.
#[derive(Clone, Debug)]
pub struct HlExecutionPayloadValidator<ChainSpec> {
/// Chain spec to validate against.
#[allow(unused)]
inner: Arc<ChainSpec>,
}
impl<ChainSpec> HlExecutionPayloadValidator<ChainSpec>
where
ChainSpec: HlHardforks,
{
pub fn ensure_well_formed_payload(
&self,
payload: HlExecutionData,
) -> Result<SealedBlock<HlBlock>, PayloadError> {
let block = payload.0;
let expected_hash = block.header.hash_slow();
// First parse the block
let sealed_block = block.seal_slow();
// Ensure the hash included in the payload matches the block hash
if expected_hash != sealed_block.hash() {
return Err(PayloadError::BlockHash {
execution: sealed_block.hash(),
consensus: expected_hash,
})?;
}
Ok(sealed_block)
}
}

273
src/node/rpc/mod.rs Normal file
View File

@ -0,0 +1,273 @@
use alloy_network::Ethereum;
use alloy_primitives::U256;
use reth::{
builder::{
rpc::{EthApiBuilder, EthApiCtx},
FullNodeComponents,
},
chainspec::EthChainSpec,
primitives::EthereumHardforks,
providers::ChainSpecProvider,
rpc::{
eth::{DevSigner, FullEthApiServer},
server_types::eth::{EthApiError, EthStateCache, FeeHistoryCache, GasPriceOracle},
},
tasks::{
pool::{BlockingTaskGuard, BlockingTaskPool},
TaskSpawner,
},
transaction_pool::TransactionPool,
};
use reth_evm::ConfigureEvm;
use reth_network::NetworkInfo;
use reth_optimism_rpc::eth::EthApiNodeBackend;
use reth_primitives::NodePrimitives;
use reth_provider::{
BlockNumReader, BlockReader, BlockReaderIdExt, ProviderBlock, ProviderHeader, ProviderReceipt,
ProviderTx, StageCheckpointReader, StateProviderFactory,
};
use reth_rpc_eth_api::{
helpers::{
AddDevSigners, EthApiSpec, EthFees, EthSigner, EthState, LoadBlock, LoadFee, LoadState,
SpawnBlocking, Trace,
},
EthApiTypes, FromEvmError, RpcNodeCore, RpcNodeCoreExt,
};
use std::{fmt, sync::Arc};
use crate::HlPrimitives;
mod block;
mod call;
pub mod engine_api;
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> {}
/// Container type `HlEthApi`
#[allow(missing_debug_implementations)]
pub(crate) struct HlEthApiInner<N: HlNodeCore> {
/// Gateway to node's core components.
pub(crate) eth_api: EthApiNodeBackend<N>,
}
#[derive(Clone)]
pub struct HlEthApi<N: HlNodeCore> {
/// Gateway to node's core components.
pub(crate) inner: Arc<HlEthApiInner<N>>,
}
impl<N: HlNodeCore> fmt::Debug for HlEthApi<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("HlEthApi").finish_non_exhaustive()
}
}
impl<N> EthApiTypes for HlEthApi<N>
where
Self: Send + Sync,
N: HlNodeCore,
{
type Error = EthApiError;
type NetworkTypes = Ethereum;
type TransactionCompat = Self;
fn tx_resp_builder(&self) -> &Self::TransactionCompat {
self
}
}
impl<N> RpcNodeCore for HlEthApi<N>
where
N: HlNodeCore,
{
type Primitives = HlPrimitives;
type Provider = N::Provider;
type Pool = N::Pool;
type Evm = <N as RpcNodeCore>::Evm;
type Network = <N as RpcNodeCore>::Network;
type PayloadBuilder = ();
#[inline]
fn pool(&self) -> &Self::Pool {
self.inner.eth_api.pool()
}
#[inline]
fn evm_config(&self) -> &Self::Evm {
self.inner.eth_api.evm_config()
}
#[inline]
fn network(&self) -> &Self::Network {
self.inner.eth_api.network()
}
#[inline]
fn payload_builder(&self) -> &Self::PayloadBuilder {
&()
}
#[inline]
fn provider(&self) -> &Self::Provider {
self.inner.eth_api.provider()
}
}
impl<N> RpcNodeCoreExt for HlEthApi<N>
where
N: HlNodeCore,
{
#[inline]
fn cache(&self) -> &EthStateCache<ProviderBlock<N::Provider>, ProviderReceipt<N::Provider>> {
self.inner.eth_api.cache()
}
}
impl<N> EthApiSpec for HlEthApi<N>
where
N: HlNodeCore<
Provider: ChainSpecProvider<ChainSpec: EthereumHardforks>
+ BlockNumReader
+ StageCheckpointReader,
Network: NetworkInfo,
>,
{
type Transaction = ProviderTx<Self::Provider>;
#[inline]
fn starting_block(&self) -> U256 {
self.inner.eth_api.starting_block()
}
#[inline]
fn signers(&self) -> &parking_lot::RwLock<Vec<Box<dyn EthSigner<ProviderTx<Self::Provider>>>>> {
self.inner.eth_api.signers()
}
}
impl<N> SpawnBlocking for HlEthApi<N>
where
Self: Send + Sync + Clone + 'static,
N: HlNodeCore,
{
#[inline]
fn io_task_spawner(&self) -> impl TaskSpawner {
self.inner.eth_api.task_spawner()
}
#[inline]
fn tracing_task_pool(&self) -> &BlockingTaskPool {
self.inner.eth_api.blocking_task_pool()
}
#[inline]
fn tracing_task_guard(&self) -> &BlockingTaskGuard {
self.inner.eth_api.blocking_task_guard()
}
}
impl<N> LoadFee for HlEthApi<N>
where
Self: LoadBlock<Provider = N::Provider>,
N: HlNodeCore<
Provider: BlockReaderIdExt
+ ChainSpecProvider<ChainSpec: EthChainSpec + EthereumHardforks>
+ StateProviderFactory,
>,
{
#[inline]
fn gas_oracle(&self) -> &GasPriceOracle<Self::Provider> {
self.inner.eth_api.gas_oracle()
}
#[inline]
fn fee_history_cache(&self) -> &FeeHistoryCache {
self.inner.eth_api.fee_history_cache()
}
}
impl<N> LoadState for HlEthApi<N> where
N: HlNodeCore<
Provider: StateProviderFactory + ChainSpecProvider<ChainSpec: EthereumHardforks>,
Pool: TransactionPool,
>
{
}
impl<N> EthState for HlEthApi<N>
where
Self: LoadState + SpawnBlocking,
N: HlNodeCore,
{
#[inline]
fn max_proof_window(&self) -> u64 {
self.inner.eth_api.eth_proof_window()
}
}
impl<N> EthFees for HlEthApi<N>
where
Self: LoadFee,
N: HlNodeCore,
{
}
impl<N> Trace for HlEthApi<N>
where
Self: RpcNodeCore<Provider: BlockReader>
+ LoadState<
Evm: ConfigureEvm<
Primitives: NodePrimitives<
BlockHeader = ProviderHeader<Self::Provider>,
SignedTx = ProviderTx<Self::Provider>,
>,
>,
Error: FromEvmError<Self::Evm>,
>,
N: HlNodeCore,
{
}
impl<N> AddDevSigners for HlEthApi<N>
where
N: HlNodeCore,
{
fn with_dev_accounts(&self) {
*self.inner.eth_api.signers().write() = DevSigner::random_signers(20)
}
}
/// Builds [`HlEthApi`] for HL.
#[derive(Debug, Default)]
#[non_exhaustive]
pub struct HlEthApiBuilder;
impl<N> EthApiBuilder<N> for HlEthApiBuilder
where
N: FullNodeComponents,
HlEthApi<N>: FullEthApiServer<Provider = N::Provider, Pool = N::Pool>,
{
type EthApi = HlEthApi<N>;
async fn build_eth_api(self, ctx: EthApiCtx<'_, N>) -> eyre::Result<Self::EthApi> {
let eth_api = reth::rpc::eth::EthApiBuilder::new(
ctx.components.provider().clone(),
ctx.components.pool().clone(),
ctx.components.network().clone(),
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 { inner: Arc::new(HlEthApiInner { eth_api }) })
}
}

View File

@ -0,0 +1,90 @@
use super::HlNodeCore;
use crate::{node::rpc::HlEthApi, HlPrimitives};
use alloy_network::{Ethereum, Network};
use alloy_primitives::{Bytes, Signature, B256};
use reth::{
builder::FullNodeComponents,
primitives::{Receipt, Recovered, TransactionSigned},
providers::ReceiptProvider,
rpc::{
eth::helpers::types::EthRpcConverter,
server_types::eth::{utils::recover_raw_transaction, EthApiError},
types::{TransactionInfo, TransactionRequest},
},
transaction_pool::{PoolTransaction, TransactionOrigin, TransactionPool},
};
use reth_provider::{BlockReader, BlockReaderIdExt, ProviderTx, TransactionsProvider};
use reth_rpc_eth_api::{
helpers::{EthSigner, EthTransactions, LoadTransaction, SpawnBlocking},
FromEthApiError, FullEthApiTypes, RpcNodeCore, RpcNodeCoreExt, TransactionCompat,
};
impl<N> LoadTransaction for HlEthApi<N>
where
Self: SpawnBlocking + FullEthApiTypes + RpcNodeCoreExt,
N: HlNodeCore<Provider: TransactionsProvider, Pool: TransactionPool>,
Self::Pool: TransactionPool,
{
}
impl<N> TransactionCompat for HlEthApi<N>
where
N: FullNodeComponents<Provider: ReceiptProvider<Receipt = Receipt>>,
{
type Primitives = HlPrimitives;
type Transaction = <Ethereum as Network>::TransactionResponse;
type Error = EthApiError;
fn fill(
&self,
tx: Recovered<TransactionSigned>,
tx_info: TransactionInfo,
) -> Result<Self::Transaction, Self::Error> {
let builder = EthRpcConverter::default();
builder.fill(tx, tx_info)
}
fn build_simulate_v1_transaction(
&self,
request: TransactionRequest,
) -> Result<TransactionSigned, Self::Error> {
let Ok(tx) = request.build_typed_tx() else {
return Err(EthApiError::TransactionConversionError)
};
// Create an empty signature for the transaction.
let signature = Signature::new(Default::default(), Default::default(), false);
Ok(TransactionSigned::new_unhashed(tx.into(), signature))
}
}
impl<N> EthTransactions for HlEthApi<N>
where
Self: LoadTransaction<Provider: BlockReaderIdExt>,
N: HlNodeCore<Provider: BlockReader<Transaction = ProviderTx<Self::Provider>>>,
{
fn signers(&self) -> &parking_lot::RwLock<Vec<Box<dyn EthSigner<ProviderTx<Self::Provider>>>>> {
self.inner.eth_api.signers()
}
/// Decodes and recovers the transaction and submits it to the pool.
///
/// 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)
}
}