2020-09-29 03:46:54 +00:00
|
|
|
//! This crate provides two major things:
|
|
|
|
//!
|
|
|
|
//! 1. The types served by the `http_api` crate.
|
|
|
|
//! 2. A wrapper around `reqwest` that forms a HTTP client, able of consuming the endpoints served
|
|
|
|
//! by the `http_api` crate.
|
|
|
|
//!
|
|
|
|
//! Eventually it would be ideal to publish this crate on crates.io, however we have some local
|
|
|
|
//! dependencies preventing this presently.
|
|
|
|
|
|
|
|
#[cfg(feature = "lighthouse")]
|
|
|
|
pub mod lighthouse;
|
2020-10-02 09:42:19 +00:00
|
|
|
pub mod lighthouse_vc;
|
2020-09-29 03:46:54 +00:00
|
|
|
pub mod types;
|
|
|
|
|
2021-08-06 00:47:31 +00:00
|
|
|
use self::types::{Error as ResponseError, *};
|
2020-12-04 00:18:58 +00:00
|
|
|
use eth2_libp2p::PeerId;
|
|
|
|
use futures::Stream;
|
|
|
|
use futures_util::StreamExt;
|
|
|
|
pub use reqwest;
|
2020-09-29 03:46:54 +00:00
|
|
|
use reqwest::{IntoUrl, Response};
|
2020-12-04 00:18:58 +00:00
|
|
|
pub use reqwest::{StatusCode, Url};
|
2021-05-04 01:59:51 +00:00
|
|
|
use sensitive_url::SensitiveUrl;
|
2020-09-29 03:46:54 +00:00
|
|
|
use serde::{de::DeserializeOwned, Serialize};
|
|
|
|
use std::convert::TryFrom;
|
|
|
|
use std::fmt;
|
2020-12-04 00:18:58 +00:00
|
|
|
use std::iter::Iterator;
|
2021-07-12 01:47:48 +00:00
|
|
|
use std::time::Duration;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
2021-08-06 00:47:31 +00:00
|
|
|
pub const V1: EndpointVersion = EndpointVersion(1);
|
|
|
|
pub const V2: EndpointVersion = EndpointVersion(2);
|
|
|
|
|
2020-09-29 03:46:54 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Error {
|
|
|
|
/// The `reqwest` client raised an error.
|
|
|
|
Reqwest(reqwest::Error),
|
|
|
|
/// The server returned an error message where the body was able to be parsed.
|
|
|
|
ServerMessage(ErrorMessage),
|
2020-11-09 23:13:56 +00:00
|
|
|
/// The server returned an error message with an array of errors.
|
|
|
|
ServerIndexedMessage(IndexedErrorMessage),
|
2020-09-29 03:46:54 +00:00
|
|
|
/// The server returned an error message where the body was unable to be parsed.
|
|
|
|
StatusCode(StatusCode),
|
|
|
|
/// The supplied URL is badly formatted. It should look something like `http://127.0.0.1:5052`.
|
2021-05-04 01:59:51 +00:00
|
|
|
InvalidUrl(SensitiveUrl),
|
2020-10-02 09:42:19 +00:00
|
|
|
/// The supplied validator client secret is invalid.
|
|
|
|
InvalidSecret(String),
|
|
|
|
/// The server returned a response with an invalid signature. It may be an impostor.
|
|
|
|
InvalidSignatureHeader,
|
|
|
|
/// The server returned a response without a signature header. It may be an impostor.
|
|
|
|
MissingSignatureHeader,
|
|
|
|
/// The server returned an invalid JSON response.
|
|
|
|
InvalidJson(serde_json::Error),
|
2020-12-04 00:18:58 +00:00
|
|
|
/// The server returned an invalid server-sent event.
|
|
|
|
InvalidServerSentEvent(String),
|
2020-10-22 06:05:49 +00:00
|
|
|
/// The server returned an invalid SSZ response.
|
|
|
|
InvalidSsz(ssz::DecodeError),
|
2020-09-29 03:46:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Error {
|
|
|
|
/// If the error has a HTTP status code, return it.
|
|
|
|
pub fn status(&self) -> Option<StatusCode> {
|
|
|
|
match self {
|
|
|
|
Error::Reqwest(error) => error.status(),
|
|
|
|
Error::ServerMessage(msg) => StatusCode::try_from(msg.code).ok(),
|
2020-11-09 23:13:56 +00:00
|
|
|
Error::ServerIndexedMessage(msg) => StatusCode::try_from(msg.code).ok(),
|
2020-09-29 03:46:54 +00:00
|
|
|
Error::StatusCode(status) => Some(*status),
|
|
|
|
Error::InvalidUrl(_) => None,
|
2020-10-02 09:42:19 +00:00
|
|
|
Error::InvalidSecret(_) => None,
|
|
|
|
Error::InvalidSignatureHeader => None,
|
|
|
|
Error::MissingSignatureHeader => None,
|
|
|
|
Error::InvalidJson(_) => None,
|
2020-12-04 00:18:58 +00:00
|
|
|
Error::InvalidServerSentEvent(_) => None,
|
2020-10-22 06:05:49 +00:00
|
|
|
Error::InvalidSsz(_) => None,
|
2020-09-29 03:46:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for Error {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
write!(f, "{:?}", self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-12 01:47:48 +00:00
|
|
|
/// A struct to define a variety of different timeouts for different validator tasks to ensure
|
|
|
|
/// proper fallback behaviour.
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Timeouts {
|
|
|
|
pub attestation: Duration,
|
|
|
|
pub attester_duties: Duration,
|
2021-07-31 03:50:52 +00:00
|
|
|
pub liveness: Duration,
|
2021-07-12 01:47:48 +00:00
|
|
|
pub proposal: Duration,
|
|
|
|
pub proposer_duties: Duration,
|
2021-08-06 00:47:31 +00:00
|
|
|
pub sync_duties: Duration,
|
2021-07-12 01:47:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Timeouts {
|
|
|
|
pub fn set_all(timeout: Duration) -> Self {
|
|
|
|
Timeouts {
|
|
|
|
attestation: timeout,
|
|
|
|
attester_duties: timeout,
|
2021-07-31 03:50:52 +00:00
|
|
|
liveness: timeout,
|
2021-07-12 01:47:48 +00:00
|
|
|
proposal: timeout,
|
|
|
|
proposer_duties: timeout,
|
2021-08-06 00:47:31 +00:00
|
|
|
sync_duties: timeout,
|
2021-07-12 01:47:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-29 03:46:54 +00:00
|
|
|
/// A wrapper around `reqwest::Client` which provides convenience methods for interfacing with a
|
|
|
|
/// Lighthouse Beacon Node HTTP server (`http_api`).
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct BeaconNodeHttpClient {
|
|
|
|
client: reqwest::Client,
|
2021-05-04 01:59:51 +00:00
|
|
|
server: SensitiveUrl,
|
2021-07-12 01:47:48 +00:00
|
|
|
timeouts: Timeouts,
|
2020-09-29 03:46:54 +00:00
|
|
|
}
|
|
|
|
|
2020-12-18 09:17:03 +00:00
|
|
|
impl fmt::Display for BeaconNodeHttpClient {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
self.server.fmt(f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsRef<str> for BeaconNodeHttpClient {
|
|
|
|
fn as_ref(&self) -> &str {
|
2021-05-04 01:59:51 +00:00
|
|
|
self.server.as_ref()
|
2020-12-18 09:17:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-29 03:46:54 +00:00
|
|
|
impl BeaconNodeHttpClient {
|
2021-07-12 01:47:48 +00:00
|
|
|
pub fn new(server: SensitiveUrl, timeouts: Timeouts) -> Self {
|
2020-09-29 03:46:54 +00:00
|
|
|
Self {
|
|
|
|
client: reqwest::Client::new(),
|
|
|
|
server,
|
2021-07-12 01:47:48 +00:00
|
|
|
timeouts,
|
2020-09-29 03:46:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-12 01:47:48 +00:00
|
|
|
pub fn from_components(
|
|
|
|
server: SensitiveUrl,
|
|
|
|
client: reqwest::Client,
|
|
|
|
timeouts: Timeouts,
|
|
|
|
) -> Self {
|
|
|
|
Self {
|
|
|
|
client,
|
|
|
|
server,
|
|
|
|
timeouts,
|
|
|
|
}
|
2020-09-29 03:46:54 +00:00
|
|
|
}
|
|
|
|
|
2021-08-06 00:47:31 +00:00
|
|
|
/// Return the path with the standard `/eth/vX` prefix applied.
|
|
|
|
fn eth_path(&self, version: EndpointVersion) -> Result<Url, Error> {
|
2021-05-04 01:59:51 +00:00
|
|
|
let mut path = self.server.full.clone();
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("eth")
|
2021-08-06 00:47:31 +00:00
|
|
|
.push(&version.to_string());
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
Ok(path)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Perform a HTTP GET request.
|
|
|
|
async fn get<T: DeserializeOwned, U: IntoUrl>(&self, url: U) -> Result<T, Error> {
|
|
|
|
let response = self.client.get(url).send().await.map_err(Error::Reqwest)?;
|
|
|
|
ok_or_error(response)
|
|
|
|
.await?
|
|
|
|
.json()
|
|
|
|
.await
|
|
|
|
.map_err(Error::Reqwest)
|
|
|
|
}
|
|
|
|
|
2021-07-12 01:47:48 +00:00
|
|
|
/// Perform a HTTP GET request with a custom timeout.
|
|
|
|
async fn get_with_timeout<T: DeserializeOwned, U: IntoUrl>(
|
|
|
|
&self,
|
|
|
|
url: U,
|
|
|
|
timeout: Duration,
|
|
|
|
) -> Result<T, Error> {
|
|
|
|
let response = self
|
|
|
|
.client
|
|
|
|
.get(url)
|
|
|
|
.timeout(timeout)
|
|
|
|
.send()
|
|
|
|
.await
|
|
|
|
.map_err(Error::Reqwest)?;
|
|
|
|
ok_or_error(response)
|
|
|
|
.await?
|
|
|
|
.json()
|
|
|
|
.await
|
|
|
|
.map_err(Error::Reqwest)
|
|
|
|
}
|
|
|
|
|
2020-09-29 03:46:54 +00:00
|
|
|
/// Perform a HTTP GET request, returning `None` on a 404 error.
|
|
|
|
async fn get_opt<T: DeserializeOwned, U: IntoUrl>(&self, url: U) -> Result<Option<T>, Error> {
|
|
|
|
let response = self.client.get(url).send().await.map_err(Error::Reqwest)?;
|
|
|
|
match ok_or_error(response).await {
|
|
|
|
Ok(resp) => resp.json().await.map(Option::Some).map_err(Error::Reqwest),
|
|
|
|
Err(err) => {
|
|
|
|
if err.status() == Some(StatusCode::NOT_FOUND) {
|
|
|
|
Ok(None)
|
|
|
|
} else {
|
|
|
|
Err(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-12 01:47:48 +00:00
|
|
|
/// Perform a HTTP GET request with a custom timeout, returning `None` on a 404 error.
|
|
|
|
async fn get_opt_with_timeout<T: DeserializeOwned, U: IntoUrl>(
|
|
|
|
&self,
|
|
|
|
url: U,
|
|
|
|
timeout: Duration,
|
|
|
|
) -> Result<Option<T>, Error> {
|
|
|
|
let response = self
|
|
|
|
.client
|
|
|
|
.get(url)
|
|
|
|
.timeout(timeout)
|
|
|
|
.send()
|
|
|
|
.await
|
|
|
|
.map_err(Error::Reqwest)?;
|
|
|
|
match ok_or_error(response).await {
|
|
|
|
Ok(resp) => resp.json().await.map(Option::Some).map_err(Error::Reqwest),
|
|
|
|
Err(err) => {
|
|
|
|
if err.status() == Some(StatusCode::NOT_FOUND) {
|
|
|
|
Ok(None)
|
|
|
|
} else {
|
|
|
|
Err(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-06 03:01:46 +00:00
|
|
|
/// Perform a HTTP GET request using an 'accept' header, returning `None` on a 404 error.
|
|
|
|
pub async fn get_bytes_opt_accept_header<U: IntoUrl>(
|
|
|
|
&self,
|
|
|
|
url: U,
|
|
|
|
accept_header: Accept,
|
|
|
|
) -> Result<Option<Vec<u8>>, Error> {
|
|
|
|
let response = self
|
|
|
|
.client
|
|
|
|
.get(url)
|
|
|
|
.header(ACCEPT, accept_header.to_string())
|
|
|
|
.send()
|
|
|
|
.await
|
|
|
|
.map_err(Error::Reqwest)?;
|
|
|
|
match ok_or_error(response).await {
|
|
|
|
Ok(resp) => Ok(Some(
|
|
|
|
resp.bytes()
|
|
|
|
.await
|
|
|
|
.map_err(Error::Reqwest)?
|
|
|
|
.into_iter()
|
|
|
|
.collect::<Vec<_>>(),
|
|
|
|
)),
|
|
|
|
Err(err) => {
|
|
|
|
if err.status() == Some(StatusCode::NOT_FOUND) {
|
|
|
|
Ok(None)
|
|
|
|
} else {
|
|
|
|
Err(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-29 03:46:54 +00:00
|
|
|
/// Perform a HTTP POST request.
|
|
|
|
async fn post<T: Serialize, U: IntoUrl>(&self, url: U, body: &T) -> Result<(), Error> {
|
|
|
|
let response = self
|
|
|
|
.client
|
|
|
|
.post(url)
|
|
|
|
.json(body)
|
|
|
|
.send()
|
|
|
|
.await
|
|
|
|
.map_err(Error::Reqwest)?;
|
|
|
|
ok_or_error(response).await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-07-12 01:47:48 +00:00
|
|
|
/// Perform a HTTP POST request with a custom timeout.
|
|
|
|
async fn post_with_timeout<T: Serialize, U: IntoUrl>(
|
|
|
|
&self,
|
|
|
|
url: U,
|
|
|
|
body: &T,
|
|
|
|
timeout: Duration,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
let response = self
|
|
|
|
.client
|
|
|
|
.post(url)
|
|
|
|
.timeout(timeout)
|
|
|
|
.json(body)
|
|
|
|
.send()
|
|
|
|
.await
|
|
|
|
.map_err(Error::Reqwest)?;
|
|
|
|
ok_or_error(response).await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Perform a HTTP POST request with a custom timeout, returning a JSON response.
|
|
|
|
async fn post_with_timeout_and_response<T: DeserializeOwned, U: IntoUrl, V: Serialize>(
|
2020-11-09 23:13:56 +00:00
|
|
|
&self,
|
|
|
|
url: U,
|
|
|
|
body: &V,
|
2021-07-12 01:47:48 +00:00
|
|
|
timeout: Duration,
|
2020-11-09 23:13:56 +00:00
|
|
|
) -> Result<T, Error> {
|
|
|
|
let response = self
|
|
|
|
.client
|
|
|
|
.post(url)
|
2021-07-12 01:47:48 +00:00
|
|
|
.timeout(timeout)
|
2020-11-09 23:13:56 +00:00
|
|
|
.json(body)
|
|
|
|
.send()
|
|
|
|
.await
|
|
|
|
.map_err(Error::Reqwest)?;
|
|
|
|
ok_or_error(response)
|
|
|
|
.await?
|
|
|
|
.json()
|
|
|
|
.await
|
|
|
|
.map_err(Error::Reqwest)
|
|
|
|
}
|
|
|
|
|
2020-09-29 03:46:54 +00:00
|
|
|
/// `GET beacon/genesis`
|
|
|
|
///
|
|
|
|
/// ## Errors
|
|
|
|
///
|
|
|
|
/// May return a `404` if beacon chain genesis has not yet occurred.
|
|
|
|
pub async fn get_beacon_genesis(&self) -> Result<GenericResponse<GenesisData>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("genesis");
|
|
|
|
|
|
|
|
self.get(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET beacon/states/{state_id}/root`
|
|
|
|
///
|
|
|
|
/// Returns `Ok(None)` on a 404 error.
|
|
|
|
pub async fn get_beacon_states_root(
|
|
|
|
&self,
|
|
|
|
state_id: StateId,
|
|
|
|
) -> Result<Option<GenericResponse<RootData>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("states")
|
|
|
|
.push(&state_id.to_string())
|
|
|
|
.push("root");
|
|
|
|
|
|
|
|
self.get_opt(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET beacon/states/{state_id}/fork`
|
|
|
|
///
|
|
|
|
/// Returns `Ok(None)` on a 404 error.
|
|
|
|
pub async fn get_beacon_states_fork(
|
|
|
|
&self,
|
|
|
|
state_id: StateId,
|
|
|
|
) -> Result<Option<GenericResponse<Fork>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("states")
|
|
|
|
.push(&state_id.to_string())
|
|
|
|
.push("fork");
|
|
|
|
|
|
|
|
self.get_opt(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET beacon/states/{state_id}/finality_checkpoints`
|
|
|
|
///
|
|
|
|
/// Returns `Ok(None)` on a 404 error.
|
|
|
|
pub async fn get_beacon_states_finality_checkpoints(
|
|
|
|
&self,
|
|
|
|
state_id: StateId,
|
|
|
|
) -> Result<Option<GenericResponse<FinalityCheckpointsData>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("states")
|
|
|
|
.push(&state_id.to_string())
|
|
|
|
.push("finality_checkpoints");
|
|
|
|
|
|
|
|
self.get_opt(path).await
|
|
|
|
}
|
|
|
|
|
2020-11-09 23:13:56 +00:00
|
|
|
/// `GET beacon/states/{state_id}/validator_balances?id`
|
|
|
|
///
|
|
|
|
/// Returns `Ok(None)` on a 404 error.
|
|
|
|
pub async fn get_beacon_states_validator_balances(
|
|
|
|
&self,
|
|
|
|
state_id: StateId,
|
|
|
|
ids: Option<&[ValidatorId]>,
|
|
|
|
) -> Result<Option<GenericResponse<Vec<ValidatorBalanceData>>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-11-09 23:13:56 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("states")
|
|
|
|
.push(&state_id.to_string())
|
|
|
|
.push("validator_balances");
|
|
|
|
|
|
|
|
if let Some(ids) = ids {
|
|
|
|
let id_string = ids
|
|
|
|
.iter()
|
|
|
|
.map(|i| i.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(",");
|
|
|
|
path.query_pairs_mut().append_pair("id", &id_string);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.get_opt(path).await
|
|
|
|
}
|
|
|
|
|
2020-10-29 05:13:04 +00:00
|
|
|
/// `GET beacon/states/{state_id}/validators?id,status`
|
2020-09-29 03:46:54 +00:00
|
|
|
///
|
|
|
|
/// Returns `Ok(None)` on a 404 error.
|
|
|
|
pub async fn get_beacon_states_validators(
|
|
|
|
&self,
|
|
|
|
state_id: StateId,
|
2020-10-29 05:13:04 +00:00
|
|
|
ids: Option<&[ValidatorId]>,
|
|
|
|
statuses: Option<&[ValidatorStatus]>,
|
2020-09-29 03:46:54 +00:00
|
|
|
) -> Result<Option<GenericResponse<Vec<ValidatorData>>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("states")
|
|
|
|
.push(&state_id.to_string())
|
|
|
|
.push("validators");
|
|
|
|
|
2020-10-29 05:13:04 +00:00
|
|
|
if let Some(ids) = ids {
|
|
|
|
let id_string = ids
|
|
|
|
.iter()
|
|
|
|
.map(|i| i.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(",");
|
|
|
|
path.query_pairs_mut().append_pair("id", &id_string);
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(statuses) = statuses {
|
|
|
|
let status_string = statuses
|
|
|
|
.iter()
|
|
|
|
.map(|i| i.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(",");
|
|
|
|
path.query_pairs_mut().append_pair("status", &status_string);
|
|
|
|
}
|
|
|
|
|
2020-09-29 03:46:54 +00:00
|
|
|
self.get_opt(path).await
|
|
|
|
}
|
|
|
|
|
2020-11-18 23:31:39 +00:00
|
|
|
/// `GET beacon/states/{state_id}/committees?slot,index,epoch`
|
2020-09-29 03:46:54 +00:00
|
|
|
///
|
|
|
|
/// Returns `Ok(None)` on a 404 error.
|
|
|
|
pub async fn get_beacon_states_committees(
|
|
|
|
&self,
|
|
|
|
state_id: StateId,
|
|
|
|
slot: Option<Slot>,
|
|
|
|
index: Option<u64>,
|
2020-11-18 23:31:39 +00:00
|
|
|
epoch: Option<Epoch>,
|
2020-09-29 03:46:54 +00:00
|
|
|
) -> Result<Option<GenericResponse<Vec<CommitteeData>>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("states")
|
|
|
|
.push(&state_id.to_string())
|
2020-11-18 23:31:39 +00:00
|
|
|
.push("committees");
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
if let Some(slot) = slot {
|
|
|
|
path.query_pairs_mut()
|
|
|
|
.append_pair("slot", &slot.to_string());
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(index) = index {
|
|
|
|
path.query_pairs_mut()
|
|
|
|
.append_pair("index", &index.to_string());
|
|
|
|
}
|
|
|
|
|
2020-11-18 23:31:39 +00:00
|
|
|
if let Some(epoch) = epoch {
|
|
|
|
path.query_pairs_mut()
|
|
|
|
.append_pair("epoch", &epoch.to_string());
|
|
|
|
}
|
|
|
|
|
2020-09-29 03:46:54 +00:00
|
|
|
self.get_opt(path).await
|
|
|
|
}
|
|
|
|
|
2021-08-06 00:47:31 +00:00
|
|
|
/// `GET beacon/states/{state_id}/sync_committees?epoch`
|
|
|
|
pub async fn get_beacon_states_sync_committees(
|
|
|
|
&self,
|
|
|
|
state_id: StateId,
|
|
|
|
epoch: Option<Epoch>,
|
|
|
|
) -> Result<GenericResponse<SyncCommitteeByValidatorIndices>, Error> {
|
|
|
|
let mut path = self.eth_path(V1)?;
|
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("states")
|
|
|
|
.push(&state_id.to_string())
|
|
|
|
.push("sync_committees");
|
|
|
|
|
|
|
|
if let Some(epoch) = epoch {
|
|
|
|
path.query_pairs_mut()
|
|
|
|
.append_pair("epoch", &epoch.to_string());
|
|
|
|
}
|
|
|
|
|
|
|
|
self.get(path).await
|
|
|
|
}
|
|
|
|
|
2020-09-29 03:46:54 +00:00
|
|
|
/// `GET beacon/states/{state_id}/validators/{validator_id}`
|
|
|
|
///
|
|
|
|
/// Returns `Ok(None)` on a 404 error.
|
|
|
|
pub async fn get_beacon_states_validator_id(
|
|
|
|
&self,
|
|
|
|
state_id: StateId,
|
|
|
|
validator_id: &ValidatorId,
|
|
|
|
) -> Result<Option<GenericResponse<ValidatorData>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("states")
|
|
|
|
.push(&state_id.to_string())
|
|
|
|
.push("validators")
|
|
|
|
.push(&validator_id.to_string());
|
|
|
|
|
|
|
|
self.get_opt(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET beacon/headers?slot,parent_root`
|
|
|
|
///
|
|
|
|
/// Returns `Ok(None)` on a 404 error.
|
|
|
|
pub async fn get_beacon_headers(
|
|
|
|
&self,
|
|
|
|
slot: Option<Slot>,
|
|
|
|
parent_root: Option<Hash256>,
|
|
|
|
) -> Result<Option<GenericResponse<Vec<BlockHeaderData>>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("headers");
|
|
|
|
|
|
|
|
if let Some(slot) = slot {
|
|
|
|
path.query_pairs_mut()
|
|
|
|
.append_pair("slot", &slot.to_string());
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(root) = parent_root {
|
|
|
|
path.query_pairs_mut()
|
|
|
|
.append_pair("parent_root", &format!("{:?}", root));
|
|
|
|
}
|
|
|
|
|
|
|
|
self.get_opt(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET beacon/headers/{block_id}`
|
|
|
|
///
|
|
|
|
/// Returns `Ok(None)` on a 404 error.
|
|
|
|
pub async fn get_beacon_headers_block_id(
|
|
|
|
&self,
|
|
|
|
block_id: BlockId,
|
|
|
|
) -> Result<Option<GenericResponse<BlockHeaderData>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("headers")
|
|
|
|
.push(&block_id.to_string());
|
|
|
|
|
|
|
|
self.get_opt(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `POST beacon/blocks`
|
|
|
|
///
|
|
|
|
/// Returns `Ok(None)` on a 404 error.
|
|
|
|
pub async fn post_beacon_blocks<T: EthSpec>(
|
|
|
|
&self,
|
|
|
|
block: &SignedBeaconBlock<T>,
|
|
|
|
) -> Result<(), Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("blocks");
|
|
|
|
|
2021-07-12 01:47:48 +00:00
|
|
|
self.post_with_timeout(path, block, self.timeouts.proposal)
|
|
|
|
.await?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-08-06 00:47:31 +00:00
|
|
|
/// `GET v2/beacon/blocks`
|
2020-09-29 03:46:54 +00:00
|
|
|
///
|
|
|
|
/// Returns `Ok(None)` on a 404 error.
|
|
|
|
pub async fn get_beacon_blocks<T: EthSpec>(
|
|
|
|
&self,
|
|
|
|
block_id: BlockId,
|
2021-08-06 00:47:31 +00:00
|
|
|
) -> Result<Option<ForkVersionedResponse<SignedBeaconBlock<T>>>, Error> {
|
|
|
|
let mut path = self.eth_path(V2)?;
|
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("blocks")
|
|
|
|
.push(&block_id.to_string());
|
|
|
|
|
|
|
|
self.get_opt(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET v1/beacon/blocks` (LEGACY)
|
|
|
|
///
|
|
|
|
/// Returns `Ok(None)` on a 404 error.
|
|
|
|
pub async fn get_beacon_blocks_v1<T: EthSpec>(
|
|
|
|
&self,
|
|
|
|
block_id: BlockId,
|
|
|
|
) -> Result<Option<ForkVersionedResponse<SignedBeaconBlock<T>>>, Error> {
|
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("blocks")
|
|
|
|
.push(&block_id.to_string());
|
|
|
|
|
|
|
|
self.get_opt(path).await
|
|
|
|
}
|
|
|
|
|
2021-02-24 04:15:14 +00:00
|
|
|
/// `GET beacon/blocks` as SSZ
|
|
|
|
///
|
|
|
|
/// Returns `Ok(None)` on a 404 error.
|
|
|
|
pub async fn get_beacon_blocks_ssz<T: EthSpec>(
|
|
|
|
&self,
|
|
|
|
block_id: BlockId,
|
2021-07-09 06:15:32 +00:00
|
|
|
spec: &ChainSpec,
|
2021-02-24 04:15:14 +00:00
|
|
|
) -> Result<Option<SignedBeaconBlock<T>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V2)?;
|
2021-02-24 04:15:14 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("blocks")
|
|
|
|
.push(&block_id.to_string());
|
|
|
|
|
|
|
|
self.get_bytes_opt_accept_header(path, Accept::Ssz)
|
|
|
|
.await?
|
2021-07-09 06:15:32 +00:00
|
|
|
.map(|bytes| SignedBeaconBlock::from_ssz_bytes(&bytes, spec).map_err(Error::InvalidSsz))
|
2021-02-24 04:15:14 +00:00
|
|
|
.transpose()
|
|
|
|
}
|
|
|
|
|
2020-09-29 03:46:54 +00:00
|
|
|
/// `GET beacon/blocks/{block_id}/root`
|
|
|
|
///
|
|
|
|
/// Returns `Ok(None)` on a 404 error.
|
|
|
|
pub async fn get_beacon_blocks_root(
|
|
|
|
&self,
|
|
|
|
block_id: BlockId,
|
|
|
|
) -> Result<Option<GenericResponse<RootData>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("blocks")
|
|
|
|
.push(&block_id.to_string())
|
|
|
|
.push("root");
|
|
|
|
|
|
|
|
self.get_opt(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET beacon/blocks/{block_id}/attestations`
|
|
|
|
///
|
|
|
|
/// Returns `Ok(None)` on a 404 error.
|
|
|
|
pub async fn get_beacon_blocks_attestations<T: EthSpec>(
|
|
|
|
&self,
|
|
|
|
block_id: BlockId,
|
|
|
|
) -> Result<Option<GenericResponse<Vec<Attestation<T>>>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("blocks")
|
|
|
|
.push(&block_id.to_string())
|
|
|
|
.push("attestations");
|
|
|
|
|
|
|
|
self.get_opt(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `POST beacon/pool/attestations`
|
|
|
|
pub async fn post_beacon_pool_attestations<T: EthSpec>(
|
|
|
|
&self,
|
2020-11-18 23:31:39 +00:00
|
|
|
attestations: &[Attestation<T>],
|
2020-09-29 03:46:54 +00:00
|
|
|
) -> Result<(), Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("pool")
|
|
|
|
.push("attestations");
|
|
|
|
|
2021-08-06 00:47:31 +00:00
|
|
|
self.post_with_timeout(path, &attestations, self.timeouts.attestation)
|
|
|
|
.await?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-11-18 23:31:39 +00:00
|
|
|
/// `GET beacon/pool/attestations?slot,committee_index`
|
2020-09-29 03:46:54 +00:00
|
|
|
pub async fn get_beacon_pool_attestations<T: EthSpec>(
|
|
|
|
&self,
|
2020-11-18 23:31:39 +00:00
|
|
|
slot: Option<Slot>,
|
|
|
|
committee_index: Option<u64>,
|
2020-09-29 03:46:54 +00:00
|
|
|
) -> Result<GenericResponse<Vec<Attestation<T>>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("pool")
|
|
|
|
.push("attestations");
|
|
|
|
|
2020-11-18 23:31:39 +00:00
|
|
|
if let Some(slot) = slot {
|
|
|
|
path.query_pairs_mut()
|
|
|
|
.append_pair("slot", &slot.to_string());
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(index) = committee_index {
|
|
|
|
path.query_pairs_mut()
|
|
|
|
.append_pair("committee_index", &index.to_string());
|
|
|
|
}
|
|
|
|
|
2020-09-29 03:46:54 +00:00
|
|
|
self.get(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `POST beacon/pool/attester_slashings`
|
|
|
|
pub async fn post_beacon_pool_attester_slashings<T: EthSpec>(
|
|
|
|
&self,
|
|
|
|
slashing: &AttesterSlashing<T>,
|
|
|
|
) -> Result<(), Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("pool")
|
|
|
|
.push("attester_slashings");
|
|
|
|
|
|
|
|
self.post(path, slashing).await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET beacon/pool/attester_slashings`
|
|
|
|
pub async fn get_beacon_pool_attester_slashings<T: EthSpec>(
|
|
|
|
&self,
|
|
|
|
) -> Result<GenericResponse<Vec<AttesterSlashing<T>>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("pool")
|
|
|
|
.push("attester_slashings");
|
|
|
|
|
|
|
|
self.get(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `POST beacon/pool/proposer_slashings`
|
|
|
|
pub async fn post_beacon_pool_proposer_slashings(
|
|
|
|
&self,
|
|
|
|
slashing: &ProposerSlashing,
|
|
|
|
) -> Result<(), Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("pool")
|
|
|
|
.push("proposer_slashings");
|
|
|
|
|
|
|
|
self.post(path, slashing).await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET beacon/pool/proposer_slashings`
|
|
|
|
pub async fn get_beacon_pool_proposer_slashings(
|
|
|
|
&self,
|
|
|
|
) -> Result<GenericResponse<Vec<ProposerSlashing>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("pool")
|
|
|
|
.push("proposer_slashings");
|
|
|
|
|
|
|
|
self.get(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `POST beacon/pool/voluntary_exits`
|
|
|
|
pub async fn post_beacon_pool_voluntary_exits(
|
|
|
|
&self,
|
|
|
|
exit: &SignedVoluntaryExit,
|
|
|
|
) -> Result<(), Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("pool")
|
|
|
|
.push("voluntary_exits");
|
|
|
|
|
|
|
|
self.post(path, exit).await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET beacon/pool/voluntary_exits`
|
|
|
|
pub async fn get_beacon_pool_voluntary_exits(
|
|
|
|
&self,
|
|
|
|
) -> Result<GenericResponse<Vec<SignedVoluntaryExit>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("pool")
|
|
|
|
.push("voluntary_exits");
|
|
|
|
|
|
|
|
self.get(path).await
|
|
|
|
}
|
|
|
|
|
2021-08-06 00:47:31 +00:00
|
|
|
/// `POST beacon/pool/sync_committees`
|
|
|
|
pub async fn post_beacon_pool_sync_committee_signatures(
|
|
|
|
&self,
|
|
|
|
signatures: &[SyncCommitteeMessage],
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
let mut path = self.eth_path(V1)?;
|
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("beacon")
|
|
|
|
.push("pool")
|
|
|
|
.push("sync_committees");
|
|
|
|
|
|
|
|
self.post(path, &signatures).await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `POST validator/contribution_and_proofs`
|
|
|
|
pub async fn post_validator_contribution_and_proofs<T: EthSpec>(
|
|
|
|
&self,
|
|
|
|
signed_contributions: &[SignedContributionAndProof<T>],
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
let mut path = self.eth_path(V1)?;
|
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("validator")
|
|
|
|
.push("contribution_and_proofs");
|
|
|
|
|
|
|
|
self.post(path, &signed_contributions).await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-09-29 03:46:54 +00:00
|
|
|
/// `GET config/fork_schedule`
|
|
|
|
pub async fn get_config_fork_schedule(&self) -> Result<GenericResponse<Vec<Fork>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("config")
|
|
|
|
.push("fork_schedule");
|
|
|
|
|
|
|
|
self.get(path).await
|
|
|
|
}
|
|
|
|
|
2020-10-02 09:42:19 +00:00
|
|
|
/// `GET config/spec`
|
2021-07-09 06:15:32 +00:00
|
|
|
pub async fn get_config_spec(&self) -> Result<GenericResponse<ConfigAndPreset>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("config")
|
|
|
|
.push("spec");
|
|
|
|
|
|
|
|
self.get(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET config/deposit_contract`
|
|
|
|
pub async fn get_config_deposit_contract(
|
|
|
|
&self,
|
|
|
|
) -> Result<GenericResponse<DepositContractData>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("config")
|
|
|
|
.push("deposit_contract");
|
|
|
|
|
|
|
|
self.get(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET node/version`
|
|
|
|
pub async fn get_node_version(&self) -> Result<GenericResponse<VersionData>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("node")
|
|
|
|
.push("version");
|
|
|
|
|
|
|
|
self.get(path).await
|
|
|
|
}
|
|
|
|
|
2020-10-22 02:59:42 +00:00
|
|
|
/// `GET node/identity`
|
|
|
|
pub async fn get_node_identity(&self) -> Result<GenericResponse<IdentityData>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-10-22 02:59:42 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("node")
|
|
|
|
.push("identity");
|
|
|
|
|
|
|
|
self.get(path).await
|
|
|
|
}
|
|
|
|
|
2020-09-29 03:46:54 +00:00
|
|
|
/// `GET node/syncing`
|
|
|
|
pub async fn get_node_syncing(&self) -> Result<GenericResponse<SyncingData>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("node")
|
|
|
|
.push("syncing");
|
|
|
|
|
|
|
|
self.get(path).await
|
2020-10-22 02:59:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET node/health`
|
|
|
|
pub async fn get_node_health(&self) -> Result<StatusCode, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-10-22 02:59:42 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("node")
|
|
|
|
.push("health");
|
|
|
|
|
|
|
|
let status = self
|
|
|
|
.client
|
|
|
|
.get(path)
|
|
|
|
.send()
|
|
|
|
.await
|
|
|
|
.map_err(Error::Reqwest)?
|
|
|
|
.status();
|
|
|
|
if status == StatusCode::OK || status == StatusCode::PARTIAL_CONTENT {
|
|
|
|
Ok(status)
|
|
|
|
} else {
|
|
|
|
Err(Error::StatusCode(status))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET node/peers/{peer_id}`
|
|
|
|
pub async fn get_node_peers_by_id(
|
|
|
|
&self,
|
|
|
|
peer_id: PeerId,
|
|
|
|
) -> Result<GenericResponse<PeerData>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-10-22 02:59:42 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("node")
|
|
|
|
.push("peers")
|
|
|
|
.push(&peer_id.to_string());
|
|
|
|
|
|
|
|
self.get(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET node/peers`
|
2020-11-13 02:02:41 +00:00
|
|
|
pub async fn get_node_peers(
|
|
|
|
&self,
|
|
|
|
states: Option<&[PeerState]>,
|
|
|
|
directions: Option<&[PeerDirection]>,
|
|
|
|
) -> Result<PeersData, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-10-22 02:59:42 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("node")
|
|
|
|
.push("peers");
|
|
|
|
|
2020-11-13 02:02:41 +00:00
|
|
|
if let Some(states) = states {
|
|
|
|
let state_string = states
|
|
|
|
.iter()
|
|
|
|
.map(|i| i.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(",");
|
|
|
|
path.query_pairs_mut().append_pair("state", &state_string);
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(directions) = directions {
|
|
|
|
let dir_string = directions
|
|
|
|
.iter()
|
|
|
|
.map(|i| i.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(",");
|
|
|
|
path.query_pairs_mut().append_pair("direction", &dir_string);
|
|
|
|
}
|
|
|
|
|
|
|
|
self.get(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET node/peer_count`
|
|
|
|
pub async fn get_node_peer_count(&self) -> Result<GenericResponse<PeerCount>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-11-13 02:02:41 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("node")
|
|
|
|
.push("peer_count");
|
|
|
|
|
2020-10-22 02:59:42 +00:00
|
|
|
self.get(path).await
|
2020-09-29 03:46:54 +00:00
|
|
|
}
|
|
|
|
|
2021-08-06 00:47:31 +00:00
|
|
|
/// `GET v2/debug/beacon/states/{state_id}`
|
2020-09-29 03:46:54 +00:00
|
|
|
pub async fn get_debug_beacon_states<T: EthSpec>(
|
|
|
|
&self,
|
|
|
|
state_id: StateId,
|
2021-08-06 00:47:31 +00:00
|
|
|
) -> Result<Option<ForkVersionedResponse<BeaconState<T>>>, Error> {
|
|
|
|
let mut path = self.eth_path(V2)?;
|
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("debug")
|
|
|
|
.push("beacon")
|
|
|
|
.push("states")
|
|
|
|
.push(&state_id.to_string());
|
|
|
|
|
|
|
|
self.get_opt(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET v1/debug/beacon/states/{state_id}` (LEGACY)
|
|
|
|
pub async fn get_debug_beacon_states_v1<T: EthSpec>(
|
|
|
|
&self,
|
|
|
|
state_id: StateId,
|
|
|
|
) -> Result<Option<ForkVersionedResponse<BeaconState<T>>>, Error> {
|
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("debug")
|
|
|
|
.push("beacon")
|
|
|
|
.push("states")
|
|
|
|
.push(&state_id.to_string());
|
|
|
|
|
|
|
|
self.get_opt(path).await
|
|
|
|
}
|
|
|
|
|
2021-01-06 03:01:46 +00:00
|
|
|
/// `GET debug/beacon/states/{state_id}`
|
|
|
|
/// `-H "accept: application/octet-stream"`
|
|
|
|
pub async fn get_debug_beacon_states_ssz<T: EthSpec>(
|
|
|
|
&self,
|
|
|
|
state_id: StateId,
|
2021-07-09 06:15:32 +00:00
|
|
|
spec: &ChainSpec,
|
2021-01-06 03:01:46 +00:00
|
|
|
) -> Result<Option<BeaconState<T>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2021-01-06 03:01:46 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("debug")
|
|
|
|
.push("beacon")
|
|
|
|
.push("states")
|
|
|
|
.push(&state_id.to_string());
|
|
|
|
|
|
|
|
self.get_bytes_opt_accept_header(path, Accept::Ssz)
|
|
|
|
.await?
|
2021-07-09 06:15:32 +00:00
|
|
|
.map(|bytes| BeaconState::from_ssz_bytes(&bytes, spec).map_err(Error::InvalidSsz))
|
2021-01-06 03:01:46 +00:00
|
|
|
.transpose()
|
|
|
|
}
|
|
|
|
|
2020-09-29 03:46:54 +00:00
|
|
|
/// `GET debug/beacon/heads`
|
|
|
|
pub async fn get_debug_beacon_heads(
|
|
|
|
&self,
|
|
|
|
) -> Result<GenericResponse<Vec<ChainHeadData>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("debug")
|
|
|
|
.push("beacon")
|
|
|
|
.push("heads");
|
|
|
|
|
|
|
|
self.get(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET validator/duties/proposer/{epoch}`
|
|
|
|
pub async fn get_validator_duties_proposer(
|
|
|
|
&self,
|
|
|
|
epoch: Epoch,
|
2020-12-04 00:18:58 +00:00
|
|
|
) -> Result<DutiesResponse<Vec<ProposerData>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("validator")
|
|
|
|
.push("duties")
|
|
|
|
.push("proposer")
|
|
|
|
.push(&epoch.to_string());
|
|
|
|
|
2021-07-12 01:47:48 +00:00
|
|
|
self.get_with_timeout(path, self.timeouts.proposer_duties)
|
|
|
|
.await
|
2020-09-29 03:46:54 +00:00
|
|
|
}
|
|
|
|
|
2021-08-06 00:47:31 +00:00
|
|
|
/// `GET v2/validator/blocks/{slot}`
|
2020-09-29 03:46:54 +00:00
|
|
|
pub async fn get_validator_blocks<T: EthSpec>(
|
|
|
|
&self,
|
|
|
|
slot: Slot,
|
2020-12-18 09:17:03 +00:00
|
|
|
randao_reveal: &SignatureBytes,
|
2020-09-29 03:46:54 +00:00
|
|
|
graffiti: Option<&Graffiti>,
|
2021-08-06 00:47:31 +00:00
|
|
|
) -> Result<ForkVersionedResponse<BeaconBlock<T>>, Error> {
|
|
|
|
let mut path = self.eth_path(V2)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("validator")
|
|
|
|
.push("blocks")
|
|
|
|
.push(&slot.to_string());
|
|
|
|
|
|
|
|
path.query_pairs_mut()
|
|
|
|
.append_pair("randao_reveal", &randao_reveal.to_string());
|
|
|
|
|
|
|
|
if let Some(graffiti) = graffiti {
|
|
|
|
path.query_pairs_mut()
|
|
|
|
.append_pair("graffiti", &graffiti.to_string());
|
|
|
|
}
|
|
|
|
|
|
|
|
self.get(path).await
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `GET validator/attestation_data?slot,committee_index`
|
|
|
|
pub async fn get_validator_attestation_data(
|
|
|
|
&self,
|
|
|
|
slot: Slot,
|
|
|
|
committee_index: CommitteeIndex,
|
|
|
|
) -> Result<GenericResponse<AttestationData>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("validator")
|
|
|
|
.push("attestation_data");
|
|
|
|
|
|
|
|
path.query_pairs_mut()
|
|
|
|
.append_pair("slot", &slot.to_string())
|
|
|
|
.append_pair("committee_index", &committee_index.to_string());
|
|
|
|
|
2021-07-12 01:47:48 +00:00
|
|
|
self.get_with_timeout(path, self.timeouts.attestation).await
|
2020-09-29 03:46:54 +00:00
|
|
|
}
|
|
|
|
|
2021-07-12 01:47:48 +00:00
|
|
|
/// `GET validator/aggregate_attestation?slot,attestation_data_root`
|
2020-09-29 03:46:54 +00:00
|
|
|
pub async fn get_validator_aggregate_attestation<T: EthSpec>(
|
|
|
|
&self,
|
|
|
|
slot: Slot,
|
|
|
|
attestation_data_root: Hash256,
|
|
|
|
) -> Result<Option<GenericResponse<Attestation<T>>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("validator")
|
|
|
|
.push("aggregate_attestation");
|
|
|
|
|
|
|
|
path.query_pairs_mut()
|
|
|
|
.append_pair("slot", &slot.to_string())
|
|
|
|
.append_pair(
|
|
|
|
"attestation_data_root",
|
|
|
|
&format!("{:?}", attestation_data_root),
|
|
|
|
);
|
|
|
|
|
2021-07-12 01:47:48 +00:00
|
|
|
self.get_opt_with_timeout(path, self.timeouts.attestation)
|
|
|
|
.await
|
2020-09-29 03:46:54 +00:00
|
|
|
}
|
|
|
|
|
2021-08-06 00:47:31 +00:00
|
|
|
/// `GET validator/sync_committee_contribution`
|
|
|
|
pub async fn get_validator_sync_committee_contribution<T: EthSpec>(
|
|
|
|
&self,
|
|
|
|
sync_committee_data: &SyncContributionData,
|
|
|
|
) -> Result<Option<GenericResponse<SyncCommitteeContribution<T>>>, Error> {
|
|
|
|
let mut path = self.eth_path(V1)?;
|
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("validator")
|
|
|
|
.push("sync_committee_contribution");
|
|
|
|
|
|
|
|
path.query_pairs_mut()
|
|
|
|
.append_pair("slot", &sync_committee_data.slot.to_string())
|
|
|
|
.append_pair(
|
|
|
|
"beacon_block_root",
|
|
|
|
&format!("{:?}", sync_committee_data.beacon_block_root),
|
|
|
|
)
|
|
|
|
.append_pair(
|
|
|
|
"subcommittee_index",
|
|
|
|
&sync_committee_data.subcommittee_index.to_string(),
|
|
|
|
);
|
|
|
|
|
|
|
|
self.get_opt(path).await
|
|
|
|
}
|
|
|
|
|
2021-07-31 03:50:52 +00:00
|
|
|
/// `POST lighthouse/liveness`
|
|
|
|
pub async fn post_lighthouse_liveness(
|
|
|
|
&self,
|
|
|
|
ids: &[u64],
|
|
|
|
epoch: Epoch,
|
|
|
|
) -> Result<GenericResponse<Vec<LivenessResponseData>>, Error> {
|
|
|
|
let mut path = self.server.full.clone();
|
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("lighthouse")
|
|
|
|
.push("liveness");
|
|
|
|
|
|
|
|
self.post_with_timeout_and_response(
|
|
|
|
path,
|
|
|
|
&LivenessRequestData {
|
|
|
|
indices: ids.to_vec(),
|
|
|
|
epoch,
|
|
|
|
},
|
|
|
|
self.timeouts.liveness,
|
|
|
|
)
|
|
|
|
.await
|
|
|
|
}
|
|
|
|
|
2020-11-09 23:13:56 +00:00
|
|
|
/// `POST validator/duties/attester/{epoch}`
|
|
|
|
pub async fn post_validator_duties_attester(
|
|
|
|
&self,
|
|
|
|
epoch: Epoch,
|
|
|
|
indices: &[u64],
|
2020-12-04 00:18:58 +00:00
|
|
|
) -> Result<DutiesResponse<Vec<AttesterData>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-11-09 23:13:56 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("validator")
|
|
|
|
.push("duties")
|
|
|
|
.push("attester")
|
|
|
|
.push(&epoch.to_string());
|
|
|
|
|
2021-07-12 01:47:48 +00:00
|
|
|
self.post_with_timeout_and_response(path, &indices, self.timeouts.attester_duties)
|
|
|
|
.await
|
2020-11-09 23:13:56 +00:00
|
|
|
}
|
|
|
|
|
2020-09-29 03:46:54 +00:00
|
|
|
/// `POST validator/aggregate_and_proofs`
|
|
|
|
pub async fn post_validator_aggregate_and_proof<T: EthSpec>(
|
|
|
|
&self,
|
2020-11-09 23:13:56 +00:00
|
|
|
aggregates: &[SignedAggregateAndProof<T>],
|
2020-09-29 03:46:54 +00:00
|
|
|
) -> Result<(), Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("validator")
|
|
|
|
.push("aggregate_and_proofs");
|
|
|
|
|
2021-08-06 00:47:31 +00:00
|
|
|
self.post_with_timeout(path, &aggregates, self.timeouts.attestation)
|
|
|
|
.await?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `POST validator/beacon_committee_subscriptions`
|
|
|
|
pub async fn post_validator_beacon_committee_subscriptions(
|
|
|
|
&self,
|
|
|
|
subscriptions: &[BeaconCommitteeSubscription],
|
|
|
|
) -> Result<(), Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("validator")
|
|
|
|
.push("beacon_committee_subscriptions");
|
|
|
|
|
|
|
|
self.post(path, &subscriptions).await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-12-04 00:18:58 +00:00
|
|
|
|
2021-08-06 00:47:31 +00:00
|
|
|
/// `POST validator/sync_committee_subscriptions`
|
|
|
|
pub async fn post_validator_sync_committee_subscriptions(
|
|
|
|
&self,
|
|
|
|
subscriptions: &[SyncCommitteeSubscription],
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
let mut path = self.eth_path(V1)?;
|
|
|
|
|
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("validator")
|
|
|
|
.push("sync_committee_subscriptions");
|
|
|
|
|
|
|
|
self.post(path, &subscriptions).await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-12-04 00:18:58 +00:00
|
|
|
/// `GET events?topics`
|
|
|
|
pub async fn get_events<T: EthSpec>(
|
|
|
|
&self,
|
|
|
|
topic: &[EventTopic],
|
|
|
|
) -> Result<impl Stream<Item = Result<EventKind<T>, Error>>, Error> {
|
2021-08-06 00:47:31 +00:00
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-12-04 00:18:58 +00:00
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("events");
|
|
|
|
|
|
|
|
let topic_string = topic
|
|
|
|
.iter()
|
|
|
|
.map(|i| i.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(",");
|
|
|
|
path.query_pairs_mut().append_pair("topics", &topic_string);
|
|
|
|
|
|
|
|
Ok(self
|
|
|
|
.client
|
|
|
|
.get(path)
|
|
|
|
.send()
|
|
|
|
.await
|
|
|
|
.map_err(Error::Reqwest)?
|
|
|
|
.bytes_stream()
|
|
|
|
.map(|next| match next {
|
|
|
|
Ok(bytes) => EventKind::from_sse_bytes(bytes.as_ref()),
|
|
|
|
Err(e) => Err(Error::Reqwest(e)),
|
|
|
|
}))
|
|
|
|
}
|
2020-09-29 03:46:54 +00:00
|
|
|
|
2021-08-06 00:47:31 +00:00
|
|
|
/// `POST validator/duties/sync/{epoch}`
|
|
|
|
pub async fn post_validator_duties_sync(
|
|
|
|
&self,
|
|
|
|
epoch: Epoch,
|
|
|
|
indices: &[u64],
|
|
|
|
) -> Result<GenericResponse<Vec<SyncDuty>>, Error> {
|
|
|
|
let mut path = self.eth_path(V1)?;
|
2020-09-29 03:46:54 +00:00
|
|
|
|
2021-08-06 00:47:31 +00:00
|
|
|
path.path_segments_mut()
|
|
|
|
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
|
|
|
.push("validator")
|
|
|
|
.push("duties")
|
|
|
|
.push("sync")
|
|
|
|
.push(&epoch.to_string());
|
|
|
|
|
|
|
|
self.post_with_timeout_and_response(path, &indices, self.timeouts.sync_duties)
|
|
|
|
.await
|
2020-09-29 03:46:54 +00:00
|
|
|
}
|
|
|
|
}
|
2020-11-09 23:13:56 +00:00
|
|
|
|
|
|
|
/// Returns `Ok(response)` if the response is a `200 OK` response. Otherwise, creates an
|
2021-08-06 00:47:31 +00:00
|
|
|
/// appropriate error message.
|
|
|
|
async fn ok_or_error(response: Response) -> Result<Response, Error> {
|
2020-11-09 23:13:56 +00:00
|
|
|
let status = response.status();
|
|
|
|
|
|
|
|
if status == StatusCode::OK {
|
|
|
|
Ok(response)
|
|
|
|
} else if let Ok(message) = response.json().await {
|
2021-08-06 00:47:31 +00:00
|
|
|
match message {
|
|
|
|
ResponseError::Message(message) => Err(Error::ServerMessage(message)),
|
|
|
|
ResponseError::Indexed(indexed) => Err(Error::ServerIndexedMessage(indexed)),
|
|
|
|
}
|
2020-11-09 23:13:56 +00:00
|
|
|
} else {
|
|
|
|
Err(Error::StatusCode(status))
|
|
|
|
}
|
|
|
|
}
|