openzeppelin_monitor/services/blockchain/transports/
mod.rs

1//! Network transport implementations for blockchain clients.
2//!
3//! Provides concrete implementations for different blockchain network protocols:
4//!
5//! - Generic HTTP transport for all chains
6
7mod evm {
8	pub mod http;
9}
10mod stellar {
11	pub mod http;
12}
13mod midnight {
14	pub mod ws;
15}
16mod solana {
17	pub mod http;
18}
19
20mod http {
21	pub mod endpoint_manager;
22	pub mod transport;
23}
24
25mod ws {
26	pub mod config;
27	pub mod connection;
28	pub mod endpoint_manager;
29	pub mod transport;
30}
31
32mod error;
33
34pub use http::{
35	endpoint_manager::EndpointManager as HttpEndpointManager, transport::HttpTransportClient,
36};
37pub use ws::{
38	config::WsConfig, endpoint_manager::EndpointManager as WsEndpointManager,
39	transport::WsTransportClient,
40};
41
42pub use error::TransportError;
43pub use evm::http::EVMTransportClient;
44pub use midnight::ws::MidnightTransportClient as MidnightWsTransportClient;
45pub use solana::http::{
46	Commitment as SolanaCommitment, GetBlockConfig as SolanaGetBlockConfig,
47	GetTransactionConfig as SolanaGetTransactionConfig, SolanaTransportClient,
48};
49pub use stellar::http::StellarTransportClient;
50
51use reqwest_middleware::ClientWithMiddleware;
52use reqwest_retry::{
53	default_on_request_failure, default_on_request_success, Retryable, RetryableStrategy,
54};
55use serde::Serialize;
56use serde_json::{json, Value};
57
58/// HTTP status codes that trigger RPC endpoint rotation
59/// - 429: Too Many Requests - indicates rate limiting from the current endpoint
60pub const ROTATE_ON_ERROR_CODES: [u16; 1] = [429];
61
62/// Base trait for all blockchain transport clients
63#[async_trait::async_trait]
64pub trait BlockchainTransport: Send + Sync {
65	/// Get the current URL being used by the transport
66	async fn get_current_url(&self) -> String;
67
68	/// Send a raw request to the blockchain
69	async fn send_raw_request<P>(
70		&self,
71		method: &str,
72		params: Option<P>,
73	) -> Result<Value, TransportError>
74	where
75		P: Into<Value> + Send + Clone + Serialize;
76
77	/// Customizes the request for specific blockchain requirements
78	async fn customize_request<P>(&self, method: &str, params: Option<P>) -> Value
79	where
80		P: Into<Value> + Send + Clone + Serialize,
81	{
82		// Default implementation for JSON-RPC
83		json!({
84			"jsonrpc": "2.0",
85			"id": 1,
86			"method": method,
87			"params": params.map(|p| p.into())
88		})
89	}
90
91	/// Update endpoint manager with a new client
92	fn update_endpoint_manager_client(
93		&mut self,
94		client: ClientWithMiddleware,
95	) -> Result<(), anyhow::Error>;
96}
97
98/// Extension trait for transports that support URL rotation
99#[async_trait::async_trait]
100pub trait RotatingTransport: BlockchainTransport {
101	/// Attempts to establish a connection with a new URL
102	async fn try_connect(&self, url: &str) -> Result<(), anyhow::Error>;
103
104	/// Updates the client with a new URL
105	async fn update_client(&self, url: &str) -> Result<(), anyhow::Error>;
106}
107
108/// A default retry strategy that retries on requests based on the status code
109/// This can be used to customise the retry strategy
110pub struct TransientErrorRetryStrategy;
111impl RetryableStrategy for TransientErrorRetryStrategy {
112	fn handle(
113		&self,
114		res: &Result<reqwest::Response, reqwest_middleware::Error>,
115	) -> Option<Retryable> {
116		match res {
117			Ok(success) => default_on_request_success(success),
118			Err(error) => default_on_request_failure(error),
119		}
120	}
121}