essential_rest_client/
node_client.rs

1use crate::handle_response;
2use essential_node_types::Block;
3use essential_types::{convert::bytes_from_word, ContentAddress, Key, Value, Word};
4use reqwest::{Client, ClientBuilder};
5use std::ops::Range;
6
7/// Client that binds to an Essential node address.
8#[derive(Clone)]
9pub struct EssentialNodeClient {
10    /// Async reqwest client to make requests with.
11    client: Client,
12    /// The url to make requests to.
13    url: reqwest::Url,
14}
15
16impl EssentialNodeClient {
17    /// Create a new client with the given address.
18    pub fn new(addr: String) -> anyhow::Result<Self> {
19        let client = ClientBuilder::new().http2_prior_knowledge().build()?;
20        let url = reqwest::Url::parse(&addr)?;
21        Ok(Self { client, url })
22    }
23
24    /// List blocks in the given L2 block number range.
25    ///
26    /// Blocks are only created if there are valid solutions.
27    /// Blocks are created on a regular interval.
28    pub async fn list_blocks(&self, range: Range<Word>) -> anyhow::Result<Vec<Block>> {
29        let url = self.url.join(&format!(
30            "/list-blocks?start={}&end={}",
31            range.start, range.end
32        ))?;
33        let response = handle_response(self.client.get(url).send().await?).await?;
34        Ok(response.json::<Vec<Block>>().await?)
35    }
36
37    /// Query state in the given contract address and key.
38    ///
39    /// This is the main way the front end application will interact with state.
40    /// It only really makes sense to query state where you know what the ABI of the contract is.
41    /// The state that's returned is a list of words of variable size.
42    /// The keys are also variable sized lists of words.
43    /// To make use of this API you need to know what type of contract you are querying.
44    pub async fn query_state(
45        &self,
46        contract_ca: ContentAddress,
47        key: Key,
48    ) -> anyhow::Result<Option<Value>> {
49        let key_bytes: Vec<_> = key.iter().copied().flat_map(bytes_from_word).collect();
50        let key = hex::encode(&key_bytes);
51        let url = self
52            .url
53            .join(&format!("/query-state/{contract_ca}/{key}"))?;
54        let response = handle_response(self.client.get(url).send().await?).await?;
55        Ok(response.json::<Option<Value>>().await?)
56    }
57}