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