Files
reth/crates/node-optimism/src/rpc.rs
Matthias Seitz 1c46e5ae7d feat: block executor provider and ethereum + op impl (#7594)
Co-authored-by: Oliver Nordbjerg <onbjerg@users.noreply.github.com>
Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
2024-04-19 09:41:51 +00:00

124 lines
3.6 KiB
Rust

//! Helpers for optimism specific RPC implementations.
use jsonrpsee::types::ErrorObject;
use reqwest::Client;
use reth_rpc::eth::{
error::{EthApiError, EthResult, ToRpcError},
traits::RawTransactionForwarder,
};
use std::sync::{atomic::AtomicUsize, Arc};
/// Error type when interacting with the Sequencer
#[derive(Debug, thiserror::Error)]
pub enum SequencerRpcError {
/// Wrapper around a [hyper::Error].
#[error(transparent)]
HyperError(#[from] hyper::Error),
/// Wrapper around an [reqwest::Error].
#[error(transparent)]
HttpError(#[from] reqwest::Error),
/// Thrown when serializing transaction to forward to sequencer
#[error("invalid sequencer transaction")]
InvalidSequencerTransaction,
}
impl ToRpcError for SequencerRpcError {
fn to_rpc_error(&self) -> ErrorObject<'static> {
ErrorObject::owned(
jsonrpsee::types::error::INTERNAL_ERROR_CODE,
self.to_string(),
None::<String>,
)
}
}
impl From<SequencerRpcError> for EthApiError {
fn from(err: SequencerRpcError) -> Self {
EthApiError::other(err)
}
}
/// A client to interact with a Sequencer
#[derive(Debug, Clone)]
pub struct SequencerClient {
inner: Arc<SequencerClientInner>,
}
impl SequencerClient {
/// Creates a new [SequencerClient].
pub fn new(sequencer_endpoint: impl Into<String>) -> Self {
let client = Client::builder().use_rustls_tls().build().unwrap();
Self::with_client(sequencer_endpoint, client)
}
/// Creates a new [SequencerClient].
pub fn with_client(sequencer_endpoint: impl Into<String>, http_client: Client) -> Self {
let inner = SequencerClientInner {
sequencer_endpoint: sequencer_endpoint.into(),
http_client,
id: AtomicUsize::new(0),
};
Self { inner: Arc::new(inner) }
}
/// Returns the network of the client
pub fn endpoint(&self) -> &str {
&self.inner.sequencer_endpoint
}
/// Returns the client
pub fn http_client(&self) -> &Client {
&self.inner.http_client
}
/// Returns the next id for the request
fn next_request_id(&self) -> usize {
self.inner.id.fetch_add(1, std::sync::atomic::Ordering::SeqCst)
}
/// Forwards a transaction to the sequencer endpoint.
pub async fn forward_raw_transaction(&self, tx: &[u8]) -> Result<(), SequencerRpcError> {
let body = serde_json::to_string(&serde_json::json!({
"jsonrpc": "2.0",
"method": "eth_sendRawTransaction",
"params": [format!("0x{}", reth_primitives::hex::encode(tx))],
"id": self.next_request_id()
}))
.map_err(|_| {
tracing::warn!(
target = "rpc::eth",
"Failed to serialize transaction for forwarding to sequencer"
);
SequencerRpcError::InvalidSequencerTransaction
})?;
self.http_client()
.post(self.endpoint())
.header(http::header::CONTENT_TYPE, "application/json")
.body(body)
.send()
.await
.map_err(SequencerRpcError::HttpError)?;
Ok(())
}
}
#[async_trait::async_trait]
impl RawTransactionForwarder for SequencerClient {
async fn forward_raw_transaction(&self, tx: &[u8]) -> EthResult<()> {
SequencerClient::forward_raw_transaction(self, tx).await?;
Ok(())
}
}
#[derive(Debug, Default)]
struct SequencerClientInner {
/// The endpoint of the sequencer
sequencer_endpoint: String,
/// The HTTP client
http_client: Client,
/// Keeps track of unique request ids
id: AtomicUsize,
}