mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: extract optimism sequencer client to node-optimism (#7482)
This commit is contained in:
@ -87,6 +87,7 @@ where
|
||||
BlockingTaskPool::build().expect("failed to build tracing pool"),
|
||||
fee_history_cache,
|
||||
evm_config,
|
||||
None,
|
||||
);
|
||||
let config = EthFilterConfig::default()
|
||||
.max_logs_per_response(DEFAULT_MAX_LOGS_PER_RESPONSE)
|
||||
|
||||
@ -27,7 +27,7 @@ pub struct EthHandlers<Provider, Pool, Network, Events, EvmConfig> {
|
||||
pub blocking_task_pool: BlockingTaskPool,
|
||||
}
|
||||
|
||||
/// Additional config values for the eth namespace
|
||||
/// Additional config values for the eth namespace.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct EthConfig {
|
||||
/// Settings for the caching layer
|
||||
|
||||
@ -180,6 +180,7 @@ use reth_rpc::{
|
||||
cache::{cache_new_blocks_task, EthStateCache},
|
||||
fee_history_cache_new_blocks_task,
|
||||
gas_oracle::GasPriceOracle,
|
||||
traits::RawTransactionForwarder,
|
||||
EthBundle, FeeHistoryCache,
|
||||
},
|
||||
AdminApi, AuthLayer, Claims, DebugApi, EngineEthApi, EthApi, EthFilter, EthPubSub,
|
||||
@ -198,6 +199,7 @@ use std::{
|
||||
fmt,
|
||||
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||
str::FromStr,
|
||||
sync::Arc,
|
||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
use strum::{AsRefStr, EnumIter, IntoStaticStr, ParseError, VariantArray, VariantNames};
|
||||
@ -949,6 +951,9 @@ pub struct RethModuleRegistry<Provider, Pool, Network, Tasks, Events, EvmConfig>
|
||||
blocking_pool_guard: BlockingTaskGuard,
|
||||
/// Contains the [Methods] of a module
|
||||
modules: HashMap<RethRpcModule, Methods>,
|
||||
/// Optional forwarder for `eth_sendRawTransaction`
|
||||
// TODO(mattsse): find a more ergonomic way to configure eth/rpc customizations
|
||||
eth_raw_transaction_forwarder: Option<Arc<dyn RawTransactionForwarder>>,
|
||||
}
|
||||
|
||||
// === impl RethModuleRegistry ===
|
||||
@ -977,9 +982,20 @@ impl<Provider, Pool, Network, Tasks, Events, EvmConfig>
|
||||
blocking_pool_guard: BlockingTaskGuard::new(config.eth.max_tracing_requests),
|
||||
config,
|
||||
events,
|
||||
eth_raw_transaction_forwarder: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a forwarder for `eth_sendRawTransaction`
|
||||
///
|
||||
/// Note: this might be removed in the future in favor of a more generic approach.
|
||||
pub fn set_eth_raw_transaction_forwarder(
|
||||
&mut self,
|
||||
forwarder: Arc<dyn RawTransactionForwarder>,
|
||||
) {
|
||||
self.eth_raw_transaction_forwarder = Some(forwarder);
|
||||
}
|
||||
|
||||
/// Returns a reference to the pool
|
||||
pub fn pool(&self) -> &Pool {
|
||||
&self.pool
|
||||
@ -1331,6 +1347,7 @@ where
|
||||
blocking_task_pool.clone(),
|
||||
fee_history_cache,
|
||||
self.evm_config.clone(),
|
||||
self.eth_raw_transaction_forwarder.clone(),
|
||||
);
|
||||
let filter = EthFilter::new(
|
||||
self.provider.clone(),
|
||||
|
||||
@ -47,11 +47,6 @@ http-body = "0.4.5"
|
||||
hyper.workspace = true
|
||||
jsonwebtoken = "8"
|
||||
|
||||
## required for optimism sequencer delegation
|
||||
reqwest = { version = "0.11", default-features = false, features = [
|
||||
"rustls-tls",
|
||||
], optional = true }
|
||||
|
||||
# async
|
||||
async-trait.workspace = true
|
||||
tokio = { workspace = true, features = ["sync"] }
|
||||
@ -90,9 +85,7 @@ reth-interfaces = { workspace = true, features = ["test-utils"] }
|
||||
|
||||
[features]
|
||||
optimism = [
|
||||
"dep:reqwest",
|
||||
"reth-primitives/optimism",
|
||||
"reth-rpc-types-compat/optimism",
|
||||
"reth-network-api/optimism",
|
||||
"reth-provider/optimism",
|
||||
]
|
||||
|
||||
@ -49,6 +49,7 @@ mod sign;
|
||||
mod state;
|
||||
mod transactions;
|
||||
|
||||
use crate::eth::traits::RawTransactionForwarder;
|
||||
pub use transactions::{EthTransactions, TransactionSource};
|
||||
|
||||
/// `Eth` API trait.
|
||||
@ -104,6 +105,7 @@ where
|
||||
blocking_task_pool: BlockingTaskPool,
|
||||
fee_history_cache: FeeHistoryCache,
|
||||
evm_config: EvmConfig,
|
||||
raw_transaction_forwarder: Option<Arc<dyn RawTransactionForwarder>>,
|
||||
) -> Self {
|
||||
Self::with_spawner(
|
||||
provider,
|
||||
@ -116,6 +118,7 @@ where
|
||||
blocking_task_pool,
|
||||
fee_history_cache,
|
||||
evm_config,
|
||||
raw_transaction_forwarder,
|
||||
)
|
||||
}
|
||||
|
||||
@ -132,6 +135,7 @@ where
|
||||
blocking_task_pool: BlockingTaskPool,
|
||||
fee_history_cache: FeeHistoryCache,
|
||||
evm_config: EvmConfig,
|
||||
raw_transaction_forwarder: Option<Arc<dyn RawTransactionForwarder>>,
|
||||
) -> Self {
|
||||
// get the block number of the latest block
|
||||
let latest_block = provider
|
||||
@ -155,8 +159,7 @@ where
|
||||
blocking_task_pool,
|
||||
fee_history_cache,
|
||||
evm_config,
|
||||
#[cfg(feature = "optimism")]
|
||||
http_client: reqwest::Client::builder().use_rustls_tls().build().unwrap(),
|
||||
raw_transaction_forwarder,
|
||||
};
|
||||
|
||||
Self { inner: Arc::new(inner) }
|
||||
@ -486,7 +489,6 @@ struct EthApiInner<Provider, Pool, Network, EvmConfig> {
|
||||
fee_history_cache: FeeHistoryCache,
|
||||
/// The type that defines how to configure the EVM
|
||||
evm_config: EvmConfig,
|
||||
/// An http client for communicating with sequencers.
|
||||
#[cfg(feature = "optimism")]
|
||||
http_client: reqwest::Client,
|
||||
/// Allows forwarding received raw transactions
|
||||
raw_transaction_forwarder: Option<Arc<dyn RawTransactionForwarder>>,
|
||||
}
|
||||
|
||||
@ -486,6 +486,7 @@ mod tests {
|
||||
BlockingTaskPool::build().expect("failed to build tracing pool"),
|
||||
fee_history_cache,
|
||||
evm_config,
|
||||
None,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -145,6 +145,7 @@ mod tests {
|
||||
BlockingTaskPool::build().expect("failed to build tracing pool"),
|
||||
FeeHistoryCache::new(cache, FeeHistoryCacheConfig::default()),
|
||||
evm_config,
|
||||
None,
|
||||
);
|
||||
let address = Address::random();
|
||||
let storage = eth_api.storage_at(address, U256::ZERO.into(), None).unwrap();
|
||||
@ -169,6 +170,7 @@ mod tests {
|
||||
BlockingTaskPool::build().expect("failed to build tracing pool"),
|
||||
FeeHistoryCache::new(cache, FeeHistoryCacheConfig::default()),
|
||||
evm_config,
|
||||
None,
|
||||
);
|
||||
|
||||
let storage_key: U256 = storage_key.into();
|
||||
|
||||
@ -848,8 +848,10 @@ where
|
||||
async fn send_raw_transaction(&self, tx: Bytes) -> EthResult<B256> {
|
||||
// On optimism, transactions are forwarded directly to the sequencer to be included in
|
||||
// blocks that it builds.
|
||||
#[cfg(feature = "optimism")]
|
||||
self.forward_to_sequencer(&tx).await?;
|
||||
if let Some(client) = self.inner.raw_transaction_forwarder.as_ref() {
|
||||
tracing::debug!( target: "rpc::eth", "forwarding raw transaction to");
|
||||
client.forward_raw_transaction(&tx).await?;
|
||||
}
|
||||
|
||||
let recovered = recover_raw_transaction(tx)?;
|
||||
let pool_transaction = <Pool::Transaction>::from_recovered_pooled_transaction(recovered);
|
||||
@ -1506,39 +1508,6 @@ where
|
||||
|
||||
Ok(OptimismTxMeta::new(Some(l1_block_info), l1_fee, l1_data_gas))
|
||||
}
|
||||
|
||||
/// Helper function for `eth_sendRawTransaction` for Optimism.
|
||||
///
|
||||
/// Forwards the raw transaction bytes to the configured sequencer endpoint.
|
||||
/// This is a no-op if the sequencer endpoint is not configured.
|
||||
#[cfg(feature = "optimism")]
|
||||
pub async fn forward_to_sequencer(&self, tx: &Bytes) -> EthResult<()> {
|
||||
if let Some(endpoint) = self.network().sequencer_endpoint() {
|
||||
let body = serde_json::to_string(&serde_json::json!({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_sendRawTransaction",
|
||||
"params": [format!("0x{}", alloy_primitives::hex::encode(tx))],
|
||||
"id": self.network().chain_id()
|
||||
}))
|
||||
.map_err(|_| {
|
||||
tracing::warn!(
|
||||
target = "rpc::eth",
|
||||
"Failed to serialize transaction for forwarding to sequencer"
|
||||
);
|
||||
OptimismEthApiError::InvalidSequencerTransaction
|
||||
})?;
|
||||
|
||||
self.inner
|
||||
.http_client
|
||||
.post(endpoint)
|
||||
.header(http::header::CONTENT_TYPE, "application/json")
|
||||
.body(body)
|
||||
.send()
|
||||
.await
|
||||
.map_err(OptimismEthApiError::HttpError)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, Pool, Network, EvmConfig> EthApi<Provider, Pool, Network, EvmConfig>
|
||||
@ -1843,6 +1812,7 @@ mod tests {
|
||||
BlockingTaskPool::build().expect("failed to build tracing pool"),
|
||||
fee_history_cache,
|
||||
evm_config,
|
||||
None,
|
||||
);
|
||||
|
||||
// https://etherscan.io/tx/0xa694b71e6c128a2ed8e2e0f6770bddbe52e3bb8f10e8472f9a79ab81497a8b5d
|
||||
|
||||
@ -11,6 +11,7 @@ mod logs_utils;
|
||||
mod pubsub;
|
||||
pub mod revm_utils;
|
||||
mod signer;
|
||||
pub mod traits;
|
||||
pub(crate) mod utils;
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
|
||||
@ -1,25 +1,16 @@
|
||||
//! Optimism specific types.
|
||||
|
||||
use jsonrpsee::types::ErrorObject;
|
||||
|
||||
use crate::{
|
||||
eth::error::{EthApiError, ToRpcError},
|
||||
result::internal_rpc_err,
|
||||
};
|
||||
use jsonrpsee::types::ErrorObject;
|
||||
use reqwest::Client;
|
||||
|
||||
/// Eth Optimism Api Error
|
||||
#[cfg(feature = "optimism")]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum OptimismEthApiError {
|
||||
/// 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,
|
||||
/// Thrown when calculating L1 gas fee
|
||||
#[error("failed to calculate l1 gas fee")]
|
||||
L1BlockFeeError,
|
||||
@ -31,11 +22,9 @@ pub enum OptimismEthApiError {
|
||||
impl ToRpcError for OptimismEthApiError {
|
||||
fn to_rpc_error(&self) -> ErrorObject<'static> {
|
||||
match self {
|
||||
OptimismEthApiError::HyperError(err) => internal_rpc_err(err.to_string()),
|
||||
OptimismEthApiError::HttpError(err) => internal_rpc_err(err.to_string()),
|
||||
OptimismEthApiError::InvalidSequencerTransaction |
|
||||
OptimismEthApiError::L1BlockFeeError |
|
||||
OptimismEthApiError::L1BlockGasError => internal_rpc_err(self.to_string()),
|
||||
OptimismEthApiError::L1BlockFeeError | OptimismEthApiError::L1BlockGasError => {
|
||||
internal_rpc_err(self.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -45,19 +34,3 @@ impl From<OptimismEthApiError> for EthApiError {
|
||||
EthApiError::other(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// A client to interact with a Sequencer
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct SequencerClient {
|
||||
/// The endpoint of the sequencer
|
||||
pub sequencer_endpoint: String,
|
||||
/// The HTTP client
|
||||
pub http_client: Client,
|
||||
}
|
||||
|
||||
impl SequencerClient {
|
||||
/// Creates a new [SequencerClient].
|
||||
pub fn new(sequencer_endpoint: impl Into<String>, http_client: Client) -> Self {
|
||||
Self { sequencer_endpoint: sequencer_endpoint.into(), http_client }
|
||||
}
|
||||
}
|
||||
|
||||
13
crates/rpc/rpc/src/eth/traits.rs
Normal file
13
crates/rpc/rpc/src/eth/traits.rs
Normal file
@ -0,0 +1,13 @@
|
||||
//! Additional helper traits that allow for more customization.
|
||||
|
||||
use crate::eth::error::EthResult;
|
||||
use std::fmt;
|
||||
|
||||
/// A trait that allows for forwarding raw transactions.
|
||||
///
|
||||
/// For example to a sequencer.
|
||||
#[async_trait::async_trait]
|
||||
pub trait RawTransactionForwarder: fmt::Debug + Send + Sync + 'static {
|
||||
/// Forwards raw transaction bytes for `eth_sendRawTransaction`
|
||||
async fn forward_raw_transaction(&self, raw: &[u8]) -> EthResult<()>;
|
||||
}
|
||||
@ -159,7 +159,6 @@ where
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use http::{header, Method, Request, StatusCode};
|
||||
use hyper::{body, Body};
|
||||
use jsonrpsee::{
|
||||
|
||||
Reference in New Issue
Block a user