use alloy_dyn_abi::TypedData;
use alloy_eips::{eip2930::AccessListResult, BlockId, BlockNumberOrTag};
use alloy_json_rpc::RpcObject;
use alloy_primitives::{Address, Bytes, B256, B64, U256, U64};
use alloy_rpc_types_eth::{
simulate::{SimulatePayload, SimulatedBlock},
state::{EvmOverrides, StateOverride},
transaction::TransactionRequest,
BlockOverrides, Bundle, EIP1186AccountProofResponse, EthCallResponse, FeeHistory, Index,
StateContext, SyncStatus, Work,
};
use alloy_serde::JsonStorageKey;
use jsonrpsee::{core::RpcResult, proc_macros::rpc};
use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
use tracing::trace;
use crate::{
helpers::{EthApiSpec, EthBlocks, EthCall, EthFees, EthState, EthTransactions, FullEthApi},
RpcBlock, RpcHeader, RpcReceipt, RpcTransaction,
};
pub trait FullEthApiServer:
EthApiServer<
RpcTransaction<Self::NetworkTypes>,
RpcBlock<Self::NetworkTypes>,
RpcReceipt<Self::NetworkTypes>,
RpcHeader<Self::NetworkTypes>,
> + FullEthApi
+ Clone
{
}
impl<T> FullEthApiServer for T where
T: EthApiServer<
RpcTransaction<T::NetworkTypes>,
RpcBlock<T::NetworkTypes>,
RpcReceipt<T::NetworkTypes>,
RpcHeader<T::NetworkTypes>,
> + FullEthApi
+ Clone
{
}
#[cfg_attr(not(feature = "client"), rpc(server, namespace = "eth"))]
#[cfg_attr(feature = "client", rpc(server, client, namespace = "eth"))]
pub trait EthApi<T: RpcObject, B: RpcObject, R: RpcObject, H: RpcObject> {
#[method(name = "protocolVersion")]
async fn protocol_version(&self) -> RpcResult<U64>;
#[method(name = "syncing")]
fn syncing(&self) -> RpcResult<SyncStatus>;
#[method(name = "coinbase")]
async fn author(&self) -> RpcResult<Address>;
#[method(name = "accounts")]
fn accounts(&self) -> RpcResult<Vec<Address>>;
#[method(name = "blockNumber")]
fn block_number(&self) -> RpcResult<U256>;
#[method(name = "chainId")]
async fn chain_id(&self) -> RpcResult<Option<U64>>;
#[method(name = "getBlockByHash")]
async fn block_by_hash(&self, hash: B256, full: bool) -> RpcResult<Option<B>>;
#[method(name = "getBlockByNumber")]
async fn block_by_number(&self, number: BlockNumberOrTag, full: bool) -> RpcResult<Option<B>>;
#[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>>;
#[method(name = "getUncleCountByBlockHash")]
async fn block_uncles_count_by_hash(&self, hash: B256) -> RpcResult<Option<U256>>;
#[method(name = "getUncleCountByBlockNumber")]
async fn block_uncles_count_by_number(
&self,
number: BlockNumberOrTag,
) -> RpcResult<Option<U256>>;
#[method(name = "getBlockReceipts")]
async fn block_receipts(&self, block_id: BlockId) -> RpcResult<Option<Vec<R>>>;
#[method(name = "getUncleByBlockHashAndIndex")]
async fn uncle_by_block_hash_and_index(&self, hash: B256, index: Index)
-> RpcResult<Option<B>>;
#[method(name = "getUncleByBlockNumberAndIndex")]
async fn uncle_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> RpcResult<Option<B>>;
#[method(name = "getRawTransactionByHash")]
async fn raw_transaction_by_hash(&self, hash: B256) -> RpcResult<Option<Bytes>>;
#[method(name = "getTransactionByHash")]
async fn transaction_by_hash(&self, hash: B256) -> RpcResult<Option<T>>;
#[method(name = "getRawTransactionByBlockHashAndIndex")]
async fn raw_transaction_by_block_hash_and_index(
&self,
hash: B256,
index: Index,
) -> RpcResult<Option<Bytes>>;
#[method(name = "getTransactionByBlockHashAndIndex")]
async fn transaction_by_block_hash_and_index(
&self,
hash: B256,
index: Index,
) -> RpcResult<Option<T>>;
#[method(name = "getRawTransactionByBlockNumberAndIndex")]
async fn raw_transaction_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> RpcResult<Option<Bytes>>;
#[method(name = "getTransactionByBlockNumberAndIndex")]
async fn transaction_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> RpcResult<Option<T>>;
#[method(name = "getTransactionBySenderAndNonce")]
async fn transaction_by_sender_and_nonce(
&self,
address: Address,
nonce: U64,
) -> RpcResult<Option<T>>;
#[method(name = "getTransactionReceipt")]
async fn transaction_receipt(&self, hash: B256) -> RpcResult<Option<R>>;
#[method(name = "getBalance")]
async fn balance(&self, address: Address, block_number: Option<BlockId>) -> RpcResult<U256>;
#[method(name = "getStorageAt")]
async fn storage_at(
&self,
address: Address,
index: JsonStorageKey,
block_number: Option<BlockId>,
) -> RpcResult<B256>;
#[method(name = "getTransactionCount")]
async fn transaction_count(
&self,
address: Address,
block_number: Option<BlockId>,
) -> RpcResult<U256>;
#[method(name = "getCode")]
async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> RpcResult<Bytes>;
#[method(name = "getHeaderByNumber")]
async fn header_by_number(&self, hash: BlockNumberOrTag) -> RpcResult<Option<H>>;
#[method(name = "getHeaderByHash")]
async fn header_by_hash(&self, hash: B256) -> RpcResult<Option<H>>;
#[method(name = "simulateV1")]
async fn simulate_v1(
&self,
opts: SimulatePayload,
block_number: Option<BlockId>,
) -> RpcResult<Vec<SimulatedBlock<B>>>;
#[method(name = "call")]
async fn call(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
state_overrides: Option<StateOverride>,
block_overrides: Option<Box<BlockOverrides>>,
) -> RpcResult<Bytes>;
#[method(name = "callMany")]
async fn call_many(
&self,
bundle: Bundle,
state_context: Option<StateContext>,
state_override: Option<StateOverride>,
) -> RpcResult<Vec<EthCallResponse>>;
#[method(name = "createAccessList")]
async fn create_access_list(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
) -> RpcResult<AccessListResult>;
#[method(name = "estimateGas")]
async fn estimate_gas(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
state_override: Option<StateOverride>,
) -> RpcResult<U256>;
#[method(name = "gasPrice")]
async fn gas_price(&self) -> RpcResult<U256>;
#[method(name = "getAccount")]
async fn get_account(
&self,
address: Address,
block: BlockId,
) -> RpcResult<Option<alloy_rpc_types_eth::Account>>;
#[method(name = "maxPriorityFeePerGas")]
async fn max_priority_fee_per_gas(&self) -> RpcResult<U256>;
#[method(name = "blobBaseFee")]
async fn blob_base_fee(&self) -> RpcResult<U256>;
#[method(name = "feeHistory")]
async fn fee_history(
&self,
block_count: U64,
newest_block: BlockNumberOrTag,
reward_percentiles: Option<Vec<f64>>,
) -> RpcResult<FeeHistory>;
#[method(name = "mining")]
async fn is_mining(&self) -> RpcResult<bool>;
#[method(name = "hashrate")]
async fn hashrate(&self) -> RpcResult<U256>;
#[method(name = "getWork")]
async fn get_work(&self) -> RpcResult<Work>;
#[method(name = "submitHashrate")]
async fn submit_hashrate(&self, hashrate: U256, id: B256) -> RpcResult<bool>;
#[method(name = "submitWork")]
async fn submit_work(&self, nonce: B64, pow_hash: B256, mix_digest: B256) -> RpcResult<bool>;
#[method(name = "sendTransaction")]
async fn send_transaction(&self, request: TransactionRequest) -> RpcResult<B256>;
#[method(name = "sendRawTransaction")]
async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult<B256>;
#[method(name = "sign")]
async fn sign(&self, address: Address, message: Bytes) -> RpcResult<Bytes>;
#[method(name = "signTransaction")]
async fn sign_transaction(&self, transaction: TransactionRequest) -> RpcResult<Bytes>;
#[method(name = "signTypedData")]
async fn sign_typed_data(&self, address: Address, data: TypedData) -> RpcResult<Bytes>;
#[method(name = "getProof")]
async fn get_proof(
&self,
address: Address,
keys: Vec<JsonStorageKey>,
block_number: Option<BlockId>,
) -> RpcResult<EIP1186AccountProofResponse>;
}
#[async_trait::async_trait]
impl<T>
EthApiServer<
RpcTransaction<T::NetworkTypes>,
RpcBlock<T::NetworkTypes>,
RpcReceipt<T::NetworkTypes>,
RpcHeader<T::NetworkTypes>,
> for T
where
T: FullEthApi,
jsonrpsee_types::error::ErrorObject<'static>: From<T::Error>,
{
async fn protocol_version(&self) -> RpcResult<U64> {
trace!(target: "rpc::eth", "Serving eth_protocolVersion");
EthApiSpec::protocol_version(self).await.to_rpc_result()
}
fn syncing(&self) -> RpcResult<SyncStatus> {
trace!(target: "rpc::eth", "Serving eth_syncing");
EthApiSpec::sync_status(self).to_rpc_result()
}
async fn author(&self) -> RpcResult<Address> {
Err(internal_rpc_err("unimplemented"))
}
fn accounts(&self) -> RpcResult<Vec<Address>> {
trace!(target: "rpc::eth", "Serving eth_accounts");
Ok(EthApiSpec::accounts(self))
}
fn block_number(&self) -> RpcResult<U256> {
trace!(target: "rpc::eth", "Serving eth_blockNumber");
Ok(U256::from(
EthApiSpec::chain_info(self).with_message("failed to read chain info")?.best_number,
))
}
async fn chain_id(&self) -> RpcResult<Option<U64>> {
trace!(target: "rpc::eth", "Serving eth_chainId");
Ok(Some(EthApiSpec::chain_id(self)))
}
async fn block_by_hash(
&self,
hash: B256,
full: bool,
) -> RpcResult<Option<RpcBlock<T::NetworkTypes>>> {
trace!(target: "rpc::eth", ?hash, ?full, "Serving eth_getBlockByHash");
Ok(EthBlocks::rpc_block(self, hash.into(), full).await?)
}
async fn block_by_number(
&self,
number: BlockNumberOrTag,
full: bool,
) -> RpcResult<Option<RpcBlock<T::NetworkTypes>>> {
trace!(target: "rpc::eth", ?number, ?full, "Serving eth_getBlockByNumber");
Ok(EthBlocks::rpc_block(self, number.into(), full).await?)
}
async fn block_transaction_count_by_hash(&self, hash: B256) -> RpcResult<Option<U256>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getBlockTransactionCountByHash");
Ok(EthBlocks::block_transaction_count(self, hash.into()).await?.map(U256::from))
}
async fn block_transaction_count_by_number(
&self,
number: BlockNumberOrTag,
) -> RpcResult<Option<U256>> {
trace!(target: "rpc::eth", ?number, "Serving eth_getBlockTransactionCountByNumber");
Ok(EthBlocks::block_transaction_count(self, number.into()).await?.map(U256::from))
}
async fn block_uncles_count_by_hash(&self, hash: B256) -> RpcResult<Option<U256>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getUncleCountByBlockHash");
Ok(EthBlocks::ommers(self, hash.into())?.map(|ommers| U256::from(ommers.len())))
}
async fn block_uncles_count_by_number(
&self,
number: BlockNumberOrTag,
) -> RpcResult<Option<U256>> {
trace!(target: "rpc::eth", ?number, "Serving eth_getUncleCountByBlockNumber");
Ok(EthBlocks::ommers(self, number.into())?.map(|ommers| U256::from(ommers.len())))
}
async fn block_receipts(
&self,
block_id: BlockId,
) -> RpcResult<Option<Vec<RpcReceipt<T::NetworkTypes>>>> {
trace!(target: "rpc::eth", ?block_id, "Serving eth_getBlockReceipts");
Ok(EthBlocks::block_receipts(self, block_id).await?)
}
async fn uncle_by_block_hash_and_index(
&self,
hash: B256,
index: Index,
) -> RpcResult<Option<RpcBlock<T::NetworkTypes>>> {
trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getUncleByBlockHashAndIndex");
Ok(EthBlocks::ommer_by_block_and_index(self, hash.into(), index).await?)
}
async fn uncle_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> RpcResult<Option<RpcBlock<T::NetworkTypes>>> {
trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getUncleByBlockNumberAndIndex");
Ok(EthBlocks::ommer_by_block_and_index(self, number.into(), index).await?)
}
async fn raw_transaction_by_hash(&self, hash: B256) -> RpcResult<Option<Bytes>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getRawTransactionByHash");
Ok(EthTransactions::raw_transaction_by_hash(self, hash).await?)
}
async fn transaction_by_hash(
&self,
hash: B256,
) -> RpcResult<Option<RpcTransaction<T::NetworkTypes>>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionByHash");
Ok(EthTransactions::transaction_by_hash(self, hash)
.await?
.map(|tx| tx.into_transaction(self.tx_resp_builder()))
.transpose()?)
}
async fn raw_transaction_by_block_hash_and_index(
&self,
hash: B256,
index: Index,
) -> RpcResult<Option<Bytes>> {
trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getRawTransactionByBlockHashAndIndex");
Ok(EthTransactions::raw_transaction_by_block_and_tx_index(self, hash.into(), index.into())
.await?)
}
async fn transaction_by_block_hash_and_index(
&self,
hash: B256,
index: Index,
) -> RpcResult<Option<RpcTransaction<T::NetworkTypes>>> {
trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getTransactionByBlockHashAndIndex");
Ok(EthTransactions::transaction_by_block_and_tx_index(self, hash.into(), index.into())
.await?)
}
async fn raw_transaction_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> RpcResult<Option<Bytes>> {
trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getRawTransactionByBlockNumberAndIndex");
Ok(EthTransactions::raw_transaction_by_block_and_tx_index(
self,
number.into(),
index.into(),
)
.await?)
}
async fn transaction_by_block_number_and_index(
&self,
number: BlockNumberOrTag,
index: Index,
) -> RpcResult<Option<RpcTransaction<T::NetworkTypes>>> {
trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getTransactionByBlockNumberAndIndex");
Ok(EthTransactions::transaction_by_block_and_tx_index(self, number.into(), index.into())
.await?)
}
async fn transaction_by_sender_and_nonce(
&self,
sender: Address,
nonce: U64,
) -> RpcResult<Option<RpcTransaction<T::NetworkTypes>>> {
trace!(target: "rpc::eth", ?sender, ?nonce, "Serving eth_getTransactionBySenderAndNonce");
Ok(EthTransactions::get_transaction_by_sender_and_nonce(self, sender, nonce.to(), true)
.await?)
}
async fn transaction_receipt(
&self,
hash: B256,
) -> RpcResult<Option<RpcReceipt<T::NetworkTypes>>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionReceipt");
Ok(EthTransactions::transaction_receipt(self, hash).await?)
}
async fn balance(&self, address: Address, block_number: Option<BlockId>) -> RpcResult<U256> {
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getBalance");
Ok(EthState::balance(self, address, block_number).await?)
}
async fn storage_at(
&self,
address: Address,
index: JsonStorageKey,
block_number: Option<BlockId>,
) -> RpcResult<B256> {
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getStorageAt");
Ok(EthState::storage_at(self, address, index, block_number).await?)
}
async fn transaction_count(
&self,
address: Address,
block_number: Option<BlockId>,
) -> RpcResult<U256> {
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getTransactionCount");
Ok(EthState::transaction_count(self, address, block_number).await?)
}
async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> RpcResult<Bytes> {
trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getCode");
Ok(EthState::get_code(self, address, block_number).await?)
}
async fn header_by_number(
&self,
block_number: BlockNumberOrTag,
) -> RpcResult<Option<RpcHeader<T::NetworkTypes>>> {
trace!(target: "rpc::eth", ?block_number, "Serving eth_getHeaderByNumber");
Ok(EthBlocks::rpc_block_header(self, block_number.into()).await?)
}
async fn header_by_hash(&self, hash: B256) -> RpcResult<Option<RpcHeader<T::NetworkTypes>>> {
trace!(target: "rpc::eth", ?hash, "Serving eth_getHeaderByHash");
Ok(EthBlocks::rpc_block_header(self, hash.into()).await?)
}
async fn simulate_v1(
&self,
payload: SimulatePayload,
block_number: Option<BlockId>,
) -> RpcResult<Vec<SimulatedBlock<RpcBlock<T::NetworkTypes>>>> {
trace!(target: "rpc::eth", ?block_number, "Serving eth_simulateV1");
let _permit = self.tracing_task_guard().clone().acquire_owned().await;
Ok(EthCall::simulate_v1(self, payload, block_number).await?)
}
async fn call(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
state_overrides: Option<StateOverride>,
block_overrides: Option<Box<BlockOverrides>>,
) -> RpcResult<Bytes> {
trace!(target: "rpc::eth", ?request, ?block_number, ?state_overrides, ?block_overrides, "Serving eth_call");
Ok(EthCall::call(
self,
request,
block_number,
EvmOverrides::new(state_overrides, block_overrides),
)
.await?)
}
async fn call_many(
&self,
bundle: Bundle,
state_context: Option<StateContext>,
state_override: Option<StateOverride>,
) -> RpcResult<Vec<EthCallResponse>> {
trace!(target: "rpc::eth", ?bundle, ?state_context, ?state_override, "Serving eth_callMany");
Ok(EthCall::call_many(self, bundle, state_context, state_override).await?)
}
async fn create_access_list(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
) -> RpcResult<AccessListResult> {
trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_createAccessList");
Ok(EthCall::create_access_list_at(self, request, block_number).await?)
}
async fn estimate_gas(
&self,
request: TransactionRequest,
block_number: Option<BlockId>,
state_override: Option<StateOverride>,
) -> RpcResult<U256> {
trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_estimateGas");
Ok(EthCall::estimate_gas_at(
self,
request,
block_number.unwrap_or_default(),
state_override,
)
.await?)
}
async fn gas_price(&self) -> RpcResult<U256> {
trace!(target: "rpc::eth", "Serving eth_gasPrice");
Ok(EthFees::gas_price(self).await?)
}
async fn get_account(
&self,
address: Address,
block: BlockId,
) -> RpcResult<Option<alloy_rpc_types_eth::Account>> {
trace!(target: "rpc::eth", "Serving eth_getAccount");
Ok(EthState::get_account(self, address, block).await?)
}
async fn max_priority_fee_per_gas(&self) -> RpcResult<U256> {
trace!(target: "rpc::eth", "Serving eth_maxPriorityFeePerGas");
Ok(EthFees::suggested_priority_fee(self).await?)
}
async fn blob_base_fee(&self) -> RpcResult<U256> {
trace!(target: "rpc::eth", "Serving eth_blobBaseFee");
Ok(EthFees::blob_base_fee(self).await?)
}
async fn fee_history(
&self,
block_count: U64,
newest_block: BlockNumberOrTag,
reward_percentiles: Option<Vec<f64>>,
) -> RpcResult<FeeHistory> {
trace!(target: "rpc::eth", ?block_count, ?newest_block, ?reward_percentiles, "Serving eth_feeHistory");
Ok(EthFees::fee_history(self, block_count.to(), newest_block, reward_percentiles).await?)
}
async fn is_mining(&self) -> RpcResult<bool> {
Err(internal_rpc_err("unimplemented"))
}
async fn hashrate(&self) -> RpcResult<U256> {
Ok(U256::ZERO)
}
async fn get_work(&self) -> RpcResult<Work> {
Err(internal_rpc_err("unimplemented"))
}
async fn submit_hashrate(&self, _hashrate: U256, _id: B256) -> RpcResult<bool> {
Ok(false)
}
async fn submit_work(
&self,
_nonce: B64,
_pow_hash: B256,
_mix_digest: B256,
) -> RpcResult<bool> {
Err(internal_rpc_err("unimplemented"))
}
async fn send_transaction(&self, request: TransactionRequest) -> RpcResult<B256> {
trace!(target: "rpc::eth", ?request, "Serving eth_sendTransaction");
Ok(EthTransactions::send_transaction(self, request).await?)
}
async fn send_raw_transaction(&self, tx: Bytes) -> RpcResult<B256> {
trace!(target: "rpc::eth", ?tx, "Serving eth_sendRawTransaction");
Ok(EthTransactions::send_raw_transaction(self, tx).await?)
}
async fn sign(&self, address: Address, message: Bytes) -> RpcResult<Bytes> {
trace!(target: "rpc::eth", ?address, ?message, "Serving eth_sign");
Ok(EthTransactions::sign(self, address, message).await?)
}
async fn sign_transaction(&self, request: TransactionRequest) -> RpcResult<Bytes> {
trace!(target: "rpc::eth", ?request, "Serving eth_signTransaction");
Ok(EthTransactions::sign_transaction(self, request).await?)
}
async fn sign_typed_data(&self, address: Address, data: TypedData) -> RpcResult<Bytes> {
trace!(target: "rpc::eth", ?address, ?data, "Serving eth_signTypedData");
Ok(EthTransactions::sign_typed_data(self, &data, address)?)
}
async fn get_proof(
&self,
address: Address,
keys: Vec<JsonStorageKey>,
block_number: Option<BlockId>,
) -> RpcResult<EIP1186AccountProofResponse> {
trace!(target: "rpc::eth", ?address, ?keys, ?block_number, "Serving eth_getProof");
Ok(EthState::get_proof(self, address, keys, block_number)?.await?)
}
}