mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-28 16:48:13 -05:00
feat(rpc): add eth transactions trait (#1751)
This commit is contained in:
@@ -87,9 +87,9 @@ impl Transaction {
|
||||
tx
|
||||
}
|
||||
|
||||
/// Create a new rpc transaction result for a pending signed transaction, setting block
|
||||
/// Create a new rpc transaction result for a _pending_ signed transaction, setting block
|
||||
/// environment related fields to `None`.
|
||||
pub(crate) fn from_recovered(tx: TransactionSignedEcRecovered) -> Self {
|
||||
pub fn from_recovered(tx: TransactionSignedEcRecovered) -> Self {
|
||||
let signer = tx.signer();
|
||||
let signed_tx = tx.into_signed();
|
||||
|
||||
|
||||
@@ -3,29 +3,25 @@
|
||||
//! The entire implementation of the namespace is quite large, hence it is divided across several
|
||||
//! files.
|
||||
|
||||
use crate::eth::signer::EthSigner;
|
||||
use crate::eth::{cache::EthStateCache, error::EthResult, signer::EthSigner};
|
||||
use async_trait::async_trait;
|
||||
use reth_interfaces::Result;
|
||||
use reth_network_api::NetworkInfo;
|
||||
use reth_primitives::{
|
||||
Address, BlockId, BlockNumberOrTag, ChainInfo, TransactionSigned, H256, U64,
|
||||
};
|
||||
use reth_primitives::{Address, BlockId, BlockNumberOrTag, ChainInfo, H256, U64};
|
||||
use reth_provider::{
|
||||
BlockProvider, EvmEnvProvider, StateProvider as StateProviderTrait, StateProviderFactory,
|
||||
providers::ChainState, BlockProvider, EvmEnvProvider, StateProvider as StateProviderTrait,
|
||||
StateProviderFactory,
|
||||
};
|
||||
use std::{num::NonZeroUsize, ops::Deref};
|
||||
|
||||
use crate::eth::{cache::EthStateCache, error::EthResult};
|
||||
use reth_provider::providers::ChainState;
|
||||
use reth_rpc_types::FeeHistoryCache;
|
||||
use reth_transaction_pool::TransactionPool;
|
||||
use std::sync::Arc;
|
||||
use std::{num::NonZeroUsize, ops::Deref, sync::Arc};
|
||||
|
||||
mod block;
|
||||
mod call;
|
||||
mod server;
|
||||
mod state;
|
||||
mod transactions;
|
||||
pub use transactions::{EthTransactions, TransactionSource};
|
||||
|
||||
/// Cache limit of block-level fee history for `eth_feeHistory` RPC method.
|
||||
const FEE_HISTORY_CACHE_LIMIT: usize = 2048;
|
||||
@@ -34,7 +30,7 @@ const FEE_HISTORY_CACHE_LIMIT: usize = 2048;
|
||||
///
|
||||
/// Defines core functionality of the `eth` API implementation.
|
||||
#[async_trait]
|
||||
pub trait EthApiSpec: Send + Sync {
|
||||
pub trait EthApiSpec: EthTransactions + Send + Sync {
|
||||
/// Returns the current ethereum protocol version.
|
||||
async fn protocol_version(&self) -> Result<U64>;
|
||||
|
||||
@@ -46,9 +42,6 @@ pub trait EthApiSpec: Send + Sync {
|
||||
|
||||
/// Returns a list of addresses owned by client.
|
||||
fn accounts(&self) -> Vec<Address>;
|
||||
|
||||
/// Returns the transaction by hash
|
||||
async fn transaction_by_hash(&self, hash: H256) -> Result<Option<TransactionSigned>>;
|
||||
}
|
||||
|
||||
/// `Eth` API implementation.
|
||||
@@ -243,10 +236,6 @@ where
|
||||
fn accounts(&self) -> Vec<Address> {
|
||||
self.inner.signers.iter().flat_map(|s| s.accounts()).collect()
|
||||
}
|
||||
|
||||
async fn transaction_by_hash(&self, hash: H256) -> Result<Option<TransactionSigned>> {
|
||||
self.client().transaction_by_hash(hash)
|
||||
}
|
||||
}
|
||||
|
||||
/// Container type `EthApi`
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
|
||||
use super::EthApiSpec;
|
||||
use crate::{
|
||||
eth::{api::EthApi, error::EthApiError},
|
||||
eth::{
|
||||
api::{EthApi, EthTransactions},
|
||||
error::EthApiError,
|
||||
},
|
||||
result::{internal_rpc_err, ToRpcResult},
|
||||
};
|
||||
use jsonrpsee::core::RpcResult as Result;
|
||||
@@ -118,7 +121,7 @@ where
|
||||
|
||||
/// Handler for: `eth_getTransactionByHash`
|
||||
async fn transaction_by_hash(&self, hash: H256) -> Result<Option<reth_rpc_types::Transaction>> {
|
||||
Ok(EthApi::transaction_by_hash(self, hash).await?)
|
||||
Ok(EthTransactions::transaction_by_hash(self, hash).await?.map(Into::into))
|
||||
}
|
||||
|
||||
/// Handler for: `eth_getTransactionByBlockHashAndIndex`
|
||||
|
||||
@@ -3,12 +3,62 @@ use crate::{
|
||||
eth::error::{EthApiError, EthResult},
|
||||
EthApi,
|
||||
};
|
||||
use reth_primitives::{BlockId, Bytes, FromRecoveredTransaction, TransactionSigned, H256};
|
||||
use reth_provider::{BlockProvider, EvmEnvProvider, StateProviderFactory};
|
||||
use async_trait::async_trait;
|
||||
use reth_primitives::{
|
||||
BlockId, Bytes, FromRecoveredTransaction, IntoRecoveredTransaction, TransactionSigned,
|
||||
TransactionSignedEcRecovered, H256, U256,
|
||||
};
|
||||
use reth_provider::{BlockProvider, EvmEnvProvider, StateProviderFactory, TransactionsProvider};
|
||||
use reth_rlp::Decodable;
|
||||
use reth_rpc_types::{Index, Transaction, TransactionRequest};
|
||||
use reth_transaction_pool::{TransactionOrigin, TransactionPool};
|
||||
|
||||
/// Commonly used transaction related functions for the [EthApi] type in the `eth_` namespace
|
||||
#[async_trait::async_trait]
|
||||
pub trait EthTransactions: Send + Sync {
|
||||
/// Returns the transaction by hash.
|
||||
///
|
||||
/// Checks the pool and state.
|
||||
///
|
||||
/// Returns `Ok(None)` if no matching transaction was found.
|
||||
async fn transaction_by_hash(&self, hash: H256) -> EthResult<Option<TransactionSource>>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<Client, Pool, Network> EthTransactions for EthApi<Client, Pool, Network>
|
||||
where
|
||||
Pool: TransactionPool + Clone + 'static,
|
||||
Client: TransactionsProvider + 'static,
|
||||
Network: Send + Sync + 'static,
|
||||
{
|
||||
async fn transaction_by_hash(&self, hash: H256) -> EthResult<Option<TransactionSource>> {
|
||||
if let Some(tx) = self.pool().get(&hash).map(|tx| tx.transaction.to_recovered_transaction())
|
||||
{
|
||||
return Ok(Some(TransactionSource::Pool(tx)))
|
||||
}
|
||||
|
||||
match self.client().transaction_by_hash(hash)? {
|
||||
None => Ok(None),
|
||||
Some(tx) => {
|
||||
let transaction =
|
||||
tx.into_ecrecovered().ok_or(EthApiError::InvalidTransactionSignature)?;
|
||||
|
||||
let tx = TransactionSource::Database {
|
||||
transaction,
|
||||
// TODO: this is just stubbed out for now still need to fully implement tx =>
|
||||
// block
|
||||
index: 0,
|
||||
block_hash: Default::default(),
|
||||
block_number: 0,
|
||||
};
|
||||
Ok(Some(tx))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// === impl EthApi ===
|
||||
|
||||
impl<Client, Pool, Network> EthApi<Client, Pool, Network>
|
||||
where
|
||||
Pool: TransactionPool + 'static,
|
||||
@@ -19,28 +69,6 @@ where
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Finds a given [Transaction] by its hash.
|
||||
///
|
||||
/// Returns `Ok(None)` if no matching transaction was found.
|
||||
pub(crate) async fn transaction_by_hash(&self, hash: H256) -> EthResult<Option<Transaction>> {
|
||||
match self.client().transaction_by_hash(hash)? {
|
||||
None => Ok(None),
|
||||
Some(tx) => {
|
||||
let tx = tx.into_ecrecovered().ok_or(EthApiError::InvalidTransactionSignature)?;
|
||||
|
||||
let tx = Transaction::from_recovered_with_block_context(
|
||||
tx,
|
||||
// TODO: this is just stubbed out for now still need to fully implement tx =>
|
||||
// block
|
||||
H256::default(),
|
||||
u64::default(),
|
||||
Index::default().into(),
|
||||
);
|
||||
Ok(Some(tx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get Transaction by [BlockId] and the index of the transaction within that Block.
|
||||
///
|
||||
/// Returns `Ok(None)` if the block does not exist, or the block as fewer transactions
|
||||
@@ -94,6 +122,40 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents from where a transaction was fetched.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum TransactionSource {
|
||||
/// Transaction exists in the pool (Pending)
|
||||
Pool(TransactionSignedEcRecovered),
|
||||
/// Transaction already executed
|
||||
Database {
|
||||
/// Transaction fetched via provider
|
||||
transaction: TransactionSignedEcRecovered,
|
||||
/// Index of the transaction in the block
|
||||
index: usize,
|
||||
/// Hash of the block.
|
||||
block_hash: H256,
|
||||
/// Number of the block.
|
||||
block_number: u64,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<TransactionSource> for Transaction {
|
||||
fn from(value: TransactionSource) -> Self {
|
||||
match value {
|
||||
TransactionSource::Pool(tx) => Transaction::from_recovered(tx),
|
||||
TransactionSource::Database { transaction, index, block_hash, block_number } => {
|
||||
Transaction::from_recovered_with_block_context(
|
||||
transaction,
|
||||
block_hash,
|
||||
block_number,
|
||||
U256::from(index),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::eth::cache::EthStateCache;
|
||||
|
||||
@@ -8,12 +8,12 @@ use reth_transaction_pool::error::{InvalidPoolTransactionError, PoolError};
|
||||
use revm::primitives::{EVMError, Halt};
|
||||
|
||||
/// Result alias
|
||||
pub(crate) type EthResult<T> = Result<T, EthApiError>;
|
||||
pub type EthResult<T> = Result<T, EthApiError>;
|
||||
|
||||
/// Errors that can occur when interacting with the `eth_` namespace
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[allow(missing_docs)]
|
||||
pub(crate) enum EthApiError {
|
||||
pub enum EthApiError {
|
||||
/// When a raw transaction is empty
|
||||
#[error("Empty transaction data")]
|
||||
EmptyRawTransactionData,
|
||||
@@ -161,6 +161,7 @@ pub enum InvalidTransactionError {
|
||||
/// Unspecific evm halt error
|
||||
#[error("EVM error {0:?}")]
|
||||
EvmHalt(Halt),
|
||||
/// Invalid chain id set for the transaction.
|
||||
#[error("Invalid chain id")]
|
||||
InvalidChainId,
|
||||
}
|
||||
@@ -268,7 +269,8 @@ impl std::error::Error for RevertError {}
|
||||
|
||||
/// A helper error type that's mainly used to mirror `geth` Txpool's error messages
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub(crate) enum RpcPoolError {
|
||||
#[allow(missing_docs)]
|
||||
pub enum RpcPoolError {
|
||||
#[error("already known")]
|
||||
AlreadyKnown,
|
||||
#[error("invalid sender")]
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
mod api;
|
||||
pub mod cache;
|
||||
pub(crate) mod error;
|
||||
pub mod error;
|
||||
mod filter;
|
||||
mod id_provider;
|
||||
mod pubsub;
|
||||
pub(crate) mod revm_utils;
|
||||
mod signer;
|
||||
|
||||
pub use api::{EthApi, EthApiSpec};
|
||||
pub use api::{EthApi, EthApiSpec, EthTransactions, TransactionSource};
|
||||
pub use filter::EthFilter;
|
||||
pub use id_provider::EthSubscriptionIdProvider;
|
||||
pub use pubsub::EthPubSub;
|
||||
|
||||
Reference in New Issue
Block a user