Skip to main content

reth_e2e_test_utils/
rpc.rs

1use alloy_consensus::TxEnvelope;
2use alloy_network::eip2718::Decodable2718;
3use alloy_primitives::{Bytes, B256};
4use futures_util::future::BoxFuture;
5use reth_chainspec::EthereumHardforks;
6use reth_node_api::{BlockTy, FullNodeComponents};
7use reth_node_builder::{rpc::RpcRegistry, NodeTypes};
8use reth_provider::BlockReader;
9use reth_rpc_api::DebugApiServer;
10use reth_rpc_eth_api::{
11    helpers::{EthApiSpec, EthTransactions, LoadReceipt, TraceExt},
12    EthApiTypes, RpcReceipt,
13};
14
15#[expect(missing_debug_implementations)]
16pub struct RpcTestContext<Node: FullNodeComponents, EthApi: EthApiTypes> {
17    pub inner: RpcRegistry<Node, EthApi>,
18}
19
20impl<Node, EthApi> RpcTestContext<Node, EthApi>
21where
22    Node: FullNodeComponents<Types: NodeTypes<ChainSpec: EthereumHardforks>>,
23    EthApi: EthApiSpec<Provider: BlockReader<Block = BlockTy<Node::Types>>>
24        + EthTransactions
25        + TraceExt,
26{
27    /// Injects a raw transaction into the node tx pool via RPC server
28    ///
29    /// Boxed like [`NodeTestContext::mine`](crate::node::NodeTestContext::mine), to keep callers
30    /// from borrow-checking the eth API future.
31    pub fn inject_tx(&self, raw_tx: Bytes) -> BoxFuture<'_, Result<B256, EthApi::Error>> {
32        Box::pin(async move { self.inner.eth_api().send_raw_transaction(raw_tx).await })
33    }
34
35    /// Retrieves an Ethereum transaction envelope by its hash, including its blob sidecar if the
36    /// transaction is still pooled.
37    pub async fn envelope_by_hash(&self, hash: B256) -> eyre::Result<TxEnvelope> {
38        self.decoded_transaction_by_hash(hash).await
39    }
40
41    /// Retrieves the raw transaction with the given hash via `debug_getRawTransaction` and decodes
42    /// it as `T`.
43    ///
44    /// Returns an error if the node does not know the transaction.
45    pub async fn decoded_transaction_by_hash<T: Decodable2718>(
46        &self,
47        hash: B256,
48    ) -> eyre::Result<T> {
49        let tx = self
50            .inner
51            .debug_api()
52            .raw_transaction(hash)
53            .await?
54            .ok_or_else(|| eyre::eyre!("transaction {hash} not found"))?;
55        Ok(T::decode_2718_exact(&tx)?)
56    }
57
58    /// Returns the RPC receipt of the transaction with the given hash, if it is included in a
59    /// canonical block.
60    pub async fn transaction_receipt(
61        &self,
62        hash: B256,
63    ) -> Result<Option<RpcReceipt<EthApi::NetworkTypes>>, EthApi::Error>
64    where
65        EthApi: LoadReceipt + 'static,
66    {
67        self.inner.eth_api().transaction_receipt(hash).await
68    }
69}