essential_rest_client/
node_client.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
use crate::handle_response;
use essential_types::{convert::bytes_from_word, Block, ContentAddress, Key, Value, Word};
use reqwest::{Client, ClientBuilder};
use std::ops::Range;

/// Client that binds to an Essential node address.
#[derive(Clone)]
pub struct EssentialNodeClient {
    /// Async reqwest client to make requests with.
    client: Client,
    /// The url to make requests to.
    url: reqwest::Url,
}

impl EssentialNodeClient {
    /// Create a new client with the given address.
    pub fn new(addr: String) -> anyhow::Result<Self> {
        let client = ClientBuilder::new().http2_prior_knowledge().build()?;
        let url = reqwest::Url::parse(&addr)?;
        Ok(Self { client, url })
    }

    /// List blocks in the given L2 block number range.
    ///
    /// Blocks are only created if there are valid solutions.
    /// Blocks are created on a regular interval.
    pub async fn list_blocks(&self, range: Range<Word>) -> anyhow::Result<Vec<Block>> {
        let url = self.url.join(&format!(
            "/list-blocks?start={}&end={}",
            range.start, range.end
        ))?;
        let response = handle_response(self.client.get(url).send().await?).await?;
        Ok(response.json::<Vec<Block>>().await?)
    }

    /// Query state in the given contract address and key.
    ///
    /// This is the main way the front end application will interact with state.
    /// It only really makes sense to query state where you know what the ABI of the contract is.
    /// The state that's returned is a list of words of variable size.
    /// The keys are also variable sized lists of words.
    /// To make use of this API you need to know what type of contract you are querying.
    pub async fn query_state(
        &self,
        contract_ca: ContentAddress,
        key: Key,
    ) -> anyhow::Result<Option<Value>> {
        let key_bytes: Vec<_> = key.iter().copied().flat_map(bytes_from_word).collect();
        let key = hex::encode(&key_bytes);
        let url = self
            .url
            .join(&format!("/query-state/{contract_ca}/{key}"))?;
        let response = handle_response(self.client.get(url).send().await?).await?;
        Ok(response.json::<Option<Value>>().await?)
    }
}