feat: Forward/discard more RPC methods

This commit is contained in:
sprites0
2025-07-05 03:09:42 +00:00
parent 278d3608b1
commit 2943ba03a7
3 changed files with 62 additions and 13 deletions

1
Cargo.lock generated
View File

@ -9280,6 +9280,7 @@ dependencies = [
"alloy-evm",
"alloy-genesis",
"alloy-json-abi",
"alloy-json-rpc",
"alloy-network",
"alloy-primitives",
"alloy-rlp",

View File

@ -57,6 +57,7 @@ alloy-chains = "0.2.0"
alloy-eips = "1.0.13"
alloy-evm = "0.12"
alloy-json-abi = { version = "1.0.0", default-features = false }
alloy-json-rpc = { version = "1.0.13", default-features = false }
alloy-dyn-abi = "1.2.0"
alloy-network = "1.0.13"
alloy-primitives = { version = "1.2.0", default-features = false, features = ["map-foldhash"] }

View File

@ -1,15 +1,28 @@
use std::time::Duration;
use alloy_json_rpc::RpcObject;
use alloy_network::Ethereum;
use alloy_primitives::{Bytes, B256};
use alloy_rpc_types::TransactionRequest;
use jsonrpsee::{
http_client::{HttpClient, HttpClientBuilder},
proc_macros::rpc,
types::{error::INTERNAL_ERROR_CODE, ErrorObject},
};
use jsonrpsee_core::{async_trait, client::ClientT, ClientError, RpcResult};
use reth::rpc::{result::internal_rpc_err, server_types::eth::EthApiError};
use reth_rpc_eth_api::RpcReceipt;
#[rpc(server, namespace = "eth")]
pub trait EthForwarderApi {
pub trait EthForwarderApi<R: RpcObject> {
#[method(name = "sendRawTransaction")]
async fn send_raw_transaction(&self, tx: Bytes) -> RpcResult<B256>;
#[method(name = "eth_sendTransaction")]
async fn send_transaction(&self, _tx: TransactionRequest) -> RpcResult<B256>;
#[method(name = "eth_sendRawTransactionSync")]
async fn send_raw_transaction_sync(&self, tx: Bytes) -> RpcResult<R>;
}
pub struct EthForwarderExt {
@ -23,22 +36,56 @@ impl EthForwarderExt {
Self { client }
}
fn from_client_error(e: ClientError, internal_error_prefix: &str) -> ErrorObject {
match e {
ClientError::Call(e) => e,
_ => ErrorObject::owned(
INTERNAL_ERROR_CODE,
format!("{internal_error_prefix}: {e:?}"),
Some(()),
),
}
}
}
#[async_trait]
impl EthForwarderApiServer for EthForwarderExt {
impl EthForwarderApiServer<RpcReceipt<Ethereum>> for EthForwarderExt {
async fn send_raw_transaction(&self, tx: Bytes) -> RpcResult<B256> {
let txhash =
self.client.clone().request("eth_sendRawTransaction", vec![tx]).await.map_err(|e| {
match e {
ClientError::Call(e) => e,
_ => ErrorObject::owned(
INTERNAL_ERROR_CODE,
format!("Failed to send transaction: {e:?}"),
Some(()),
),
}
})?;
let txhash = self
.client
.clone()
.request("eth_sendRawTransaction", vec![tx])
.await
.map_err(|e| Self::from_client_error(e, "Failed to send transaction"))?;
Ok(txhash)
}
async fn send_transaction(&self, _tx: TransactionRequest) -> RpcResult<B256> {
Err(internal_rpc_err("Unimplemented"))
}
async fn send_raw_transaction_sync(&self, tx: Bytes) -> RpcResult<RpcReceipt<Ethereum>> {
let hash = self.send_raw_transaction(tx).await?;
const TIMEOUT_DURATION: Duration = Duration::from_secs(30);
const INTERVAL: Duration = Duration::from_secs(1);
tokio::time::timeout(TIMEOUT_DURATION, async {
loop {
let receipt =
self.client.request("eth_getTransactionReceipt", vec![hash]).await.map_err(
|e| Self::from_client_error(e, "Failed to get transaction receipt"),
)?;
if let Some(receipt) = receipt {
return Ok(receipt);
}
tokio::time::sleep(INTERVAL).await;
}
})
.await
.unwrap_or_else(|_elapsed| {
Err(EthApiError::TransactionConfirmationTimeout { hash, duration: TIMEOUT_DURATION }
.into())
})
}
}