sui_bridge/
metered_eth_provider.rs1use crate::metrics::BridgeMetrics;
5use ethers::providers::{Http, HttpClientError, JsonRpcClient, Provider};
6use serde::{Serialize, de::DeserializeOwned};
7use std::fmt::Debug;
8use std::sync::Arc;
9use url::{ParseError, Url};
10
11#[derive(Debug, Clone)]
12pub struct MeteredEthHttpProvider {
13 inner: Http,
14 metrics: Arc<BridgeMetrics>,
15}
16
17#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
18#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
19impl JsonRpcClient for MeteredEthHttpProvider {
20 type Error = HttpClientError;
21
22 async fn request<T: Serialize + Send + Sync + Debug, R: DeserializeOwned + Send>(
23 &self,
24 method: &str,
25 params: T,
26 ) -> Result<R, HttpClientError> {
27 self.metrics
28 .eth_rpc_queries
29 .with_label_values(&[method])
30 .inc();
31 let _guard = self
32 .metrics
33 .eth_rpc_queries_latency
34 .with_label_values(&[method])
35 .start_timer();
36 self.inner.request(method, params).await
37 }
38}
39
40impl MeteredEthHttpProvider {
41 pub fn new(url: impl Into<Url>, metrics: Arc<BridgeMetrics>) -> Self {
42 let client = reqwest::Client::builder()
43 .timeout(std::time::Duration::from_secs(30))
44 .build()
45 .unwrap();
46 let inner = Http::new_with_client(url, client);
47 Self { inner, metrics }
48 }
49}
50
51pub fn new_metered_eth_provider(
52 url: &str,
53 metrics: Arc<BridgeMetrics>,
54) -> Result<Provider<MeteredEthHttpProvider>, ParseError> {
55 let http_provider = MeteredEthHttpProvider::new(Url::parse(url)?, metrics);
56 Ok(Provider::new(http_provider))
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62 use ethers::providers::Middleware;
63 use prometheus::Registry;
64
65 #[tokio::test]
66 async fn test_metered_eth_provider() {
67 let metrics = Arc::new(BridgeMetrics::new(&Registry::new()));
68 let provider = new_metered_eth_provider("http://localhost:9876", metrics.clone()).unwrap();
69
70 assert_eq!(
71 metrics
72 .eth_rpc_queries
73 .get_metric_with_label_values(&["eth_blockNumber"])
74 .unwrap()
75 .get(),
76 0
77 );
78 assert_eq!(
79 metrics
80 .eth_rpc_queries_latency
81 .get_metric_with_label_values(&["eth_blockNumber"])
82 .unwrap()
83 .get_sample_count(),
84 0
85 );
86
87 provider.get_block_number().await.unwrap_err(); assert_eq!(
90 metrics
91 .eth_rpc_queries
92 .get_metric_with_label_values(&["eth_blockNumber"])
93 .unwrap()
94 .get(),
95 1
96 );
97 assert_eq!(
98 metrics
99 .eth_rpc_queries_latency
100 .get_metric_with_label_values(&["eth_blockNumber"])
101 .unwrap()
102 .get_sample_count(),
103 1
104 );
105 }
106}