Skip to main content

ethrex_rpc/clients/beacon/
mod.rs

1use errors::BeaconClientError;
2use ethrex_common::{H256, U256};
3use reqwest::{Client, Url};
4use serde::Deserialize;
5use serde_json::Value;
6use types::{BlobSidecar, GetBlockResponseData};
7
8pub mod errors;
9pub mod types;
10
11#[derive(Deserialize, Debug)]
12#[serde(untagged)]
13pub enum BeaconResponse {
14    Success(BeaconResponseSuccess),
15    Error(BeaconResponseError),
16}
17
18#[derive(Deserialize, Debug)]
19pub struct BeaconResponseSuccess {
20    data: Value,
21}
22
23#[derive(Deserialize, Debug)]
24pub struct BeaconResponseError {
25    code: u64,
26    message: String,
27}
28
29pub struct BeaconClient {
30    client: Client,
31    url: Url,
32}
33
34impl BeaconClient {
35    pub fn new(url: Url) -> Self {
36        Self {
37            client: Client::new(),
38            url,
39        }
40    }
41
42    async fn send_request<T>(&self, endpoint: &str) -> Result<T, BeaconClientError>
43    where
44        T: serde::de::DeserializeOwned,
45    {
46        println!("Sending request: {endpoint}");
47        let response = self
48            .client
49            .get(self.url.clone().join(endpoint).map_err(|error| {
50                BeaconClientError::FailedToSetURLEndpointError(error.to_string())
51            })?)
52            .header("content-type", "application/json")
53            .header("accept", "application/json")
54            .send()
55            .await?
56            .json::<BeaconResponse>()
57            .await
58            .map_err(BeaconClientError::from)?;
59
60        match response {
61            BeaconResponse::Success(res) => {
62                serde_json::from_value::<T>(res.data).map_err(BeaconClientError::DeserializeError)
63            }
64            BeaconResponse::Error(err) => Err(BeaconClientError::RpcError(err.code, err.message)),
65        }
66    }
67
68    pub async fn get_block_by_hash(
69        &self,
70        block_hash: H256,
71    ) -> Result<GetBlockResponseData, BeaconClientError> {
72        self.send_request(&format!("/eth/v2/beacon/blocks/{block_hash:#x}"))
73            .await
74    }
75
76    pub async fn get_blobs_by_slot(
77        &self,
78        slot: U256,
79    ) -> Result<Vec<BlobSidecar>, BeaconClientError> {
80        self.send_request(&format!("/eth/v1/beacon/blob_sidecars/{slot}"))
81            .await
82    }
83}