iota_bridge/
metered_eth_provider.rs1use std::{fmt::Debug, sync::Arc};
6
7use ethers::providers::{Http, HttpClientError, JsonRpcClient, Provider};
8use serde::{Serialize, de::DeserializeOwned};
9use url::{ParseError, Url};
10
11use crate::metrics::BridgeMetrics;
12
13#[derive(Debug, Clone)]
14pub struct MeteredEthHttpProvider {
15 inner: Http,
16 metrics: Arc<BridgeMetrics>,
17}
18
19#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
20#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
21impl JsonRpcClient for MeteredEthHttpProvider {
22 type Error = HttpClientError;
23
24 async fn request<T: Serialize + Send + Sync + Debug, R: DeserializeOwned + Send>(
25 &self,
26 method: &str,
27 params: T,
28 ) -> Result<R, HttpClientError> {
29 self.metrics
30 .eth_rpc_queries
31 .with_label_values(&[method])
32 .inc();
33 let _guard = self
34 .metrics
35 .eth_rpc_queries_latency
36 .with_label_values(&[method])
37 .start_timer();
38 self.inner.request(method, params).await
39 }
40}
41
42impl MeteredEthHttpProvider {
43 pub fn new(url: impl Into<Url>, metrics: Arc<BridgeMetrics>) -> Self {
44 let inner = Http::new(url);
45 Self { inner, metrics }
46 }
47}
48
49pub fn new_metered_eth_provider(
50 url: &str,
51 metrics: Arc<BridgeMetrics>,
52) -> Result<Provider<MeteredEthHttpProvider>, ParseError> {
53 let http_provider = MeteredEthHttpProvider::new(Url::parse(url)?, metrics);
54 Ok(Provider::new(http_provider))
55}
56
57#[cfg(test)]
58mod tests {
59 use ethers::providers::Middleware;
60 use prometheus::Registry;
61
62 use super::*;
63
64 #[tokio::test]
65 #[ignore = "https://github.com/iotaledger/iota/issues/3224"]
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}