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?)
}
}