sui_bridge/
metered_eth_provider.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use 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 MeteredEthHttpProvier {
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 MeteredEthHttpProvier {
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 MeteredEthHttpProvier {
41    pub fn new(url: impl Into<Url>, metrics: Arc<BridgeMetrics>) -> Self {
42        let inner = Http::new(url);
43        Self { inner, metrics }
44    }
45}
46
47pub fn new_metered_eth_provider(
48    url: &str,
49    metrics: Arc<BridgeMetrics>,
50) -> Result<Provider<MeteredEthHttpProvier>, ParseError> {
51    let http_provider = MeteredEthHttpProvier::new(Url::parse(url)?, metrics);
52    Ok(Provider::new(http_provider))
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58    use ethers::providers::Middleware;
59    use prometheus::Registry;
60
61    #[tokio::test]
62    async fn test_metered_eth_provider() {
63        let metrics = Arc::new(BridgeMetrics::new(&Registry::new()));
64        let provider = new_metered_eth_provider("http://localhost:9876", metrics.clone()).unwrap();
65
66        assert_eq!(
67            metrics
68                .eth_rpc_queries
69                .get_metric_with_label_values(&["eth_blockNumber"])
70                .unwrap()
71                .get(),
72            0
73        );
74        assert_eq!(
75            metrics
76                .eth_rpc_queries_latency
77                .get_metric_with_label_values(&["eth_blockNumber"])
78                .unwrap()
79                .get_sample_count(),
80            0
81        );
82
83        provider.get_block_number().await.unwrap_err(); // the rpc cal will fail but we don't care
84
85        assert_eq!(
86            metrics
87                .eth_rpc_queries
88                .get_metric_with_label_values(&["eth_blockNumber"])
89                .unwrap()
90                .get(),
91            1
92        );
93        assert_eq!(
94            metrics
95                .eth_rpc_queries_latency
96                .get_metric_with_label_values(&["eth_blockNumber"])
97                .unwrap()
98                .get_sample_count(),
99            1
100        );
101    }
102}