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