helios/consensus/src/rpc/nimbus_rpc.rs

188 lines
4.6 KiB
Rust
Raw Normal View History

use std::cmp;
2023-03-23 14:07:05 +00:00
use std::fmt::{Display, Formatter, Result as FmtResult};
use async_trait::async_trait;
2023-03-24 14:59:16 +00:00
use eyre::Result;
use js_sys::Promise;
2023-03-23 14:07:05 +00:00
use serde::Deserialize;
2023-03-24 14:59:16 +00:00
use wasm_bindgen::JsValue;
2023-03-23 14:07:05 +00:00
2023-03-24 14:51:21 +00:00
use wasm_bindgen::prelude::wasm_bindgen;
2023-03-23 14:07:05 +00:00
use wasm_bindgen_futures::JsFuture;
2022-08-21 15:21:50 +00:00
use crate::constants::MAX_REQUEST_LIGHT_CLIENT_UPDATES;
use crate::types::*;
2023-03-23 14:07:05 +00:00
use super::ConsensusRpc;
#[derive(Debug)]
pub struct RpcError {
message: String,
2023-03-24 15:14:48 +00:00
_type: String,
2023-03-23 14:07:05 +00:00
}
2023-03-24 14:51:21 +00:00
impl RpcError {
2023-03-24 15:14:48 +00:00
pub fn new(message: String, _type: String) -> Self {
Self { message, _type }
2023-03-24 14:51:21 +00:00
}
}
2023-03-23 14:07:05 +00:00
impl Display for RpcError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
2023-03-24 15:14:48 +00:00
write!(f, "{} error {}", self._type, self.message)
2023-03-23 14:07:05 +00:00
}
}
2023-03-24 14:51:21 +00:00
impl From<JsValue> for RpcError {
fn from(js_error: JsValue) -> Self {
let message = js_error
.as_string()
.unwrap_or_else(|| "Unknown error".to_string());
2023-03-24 15:14:48 +00:00
RpcError::new(message, String::from(""))
2023-03-24 14:51:21 +00:00
}
}
impl std::error::Error for RpcError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
2022-08-21 15:21:50 +00:00
#[derive(Debug)]
2023-03-24 14:51:21 +00:00
pub struct NimbusRpc {}
#[wasm_bindgen]
extern "C" {
2023-03-25 15:33:40 +00:00
#[wasm_bindgen(js_namespace = self)]
2023-03-24 14:51:21 +00:00
fn consensus_rpc_handler(data: JsValue) -> Promise;
2022-08-21 15:21:50 +00:00
}
2023-03-23 23:05:44 +00:00
#[async_trait(?Send)]
impl ConsensusRpc for NimbusRpc {
2023-03-24 14:51:21 +00:00
fn new() -> Self {
NimbusRpc {}
2022-08-21 15:21:50 +00:00
}
async fn get_bootstrap(&self, block_root: &'_ [u8]) -> Result<Bootstrap> {
2022-08-27 00:05:12 +00:00
let root_hex = hex::encode(block_root);
2023-03-23 14:07:05 +00:00
let path = format!("/eth/v1/beacon/light_client/bootstrap/0x{}", root_hex);
2023-03-24 15:14:48 +00:00
let res = self
.request::<BootstrapResponse>(&path, "bootstrap")
.await?;
2023-03-24 15:14:48 +00:00
Ok(res.data)
2022-08-21 15:21:50 +00:00
}
async fn get_updates(&self, period: u64, count: u8) -> Result<Vec<Update>> {
let count = cmp::min(count, MAX_REQUEST_LIGHT_CLIENT_UPDATES);
2023-03-23 14:07:05 +00:00
let path = format!(
"/eth/v1/beacon/light_client/updates?start_period={}&count={}",
period, count
2022-08-21 15:21:50 +00:00
);
2023-03-24 14:51:21 +00:00
let res = self.request::<UpdateResponse>(&path, "updates").await?;
Ok(res.iter().map(|d| d.data.clone()).collect())
2022-08-21 15:21:50 +00:00
}
async fn get_finality_update(&self) -> Result<FinalityUpdate> {
2023-03-23 14:07:05 +00:00
let path = format!("/eth/v1/beacon/light_client/finality_update");
let res = self
2023-03-24 14:51:21 +00:00
.request::<FinalityUpdateResponse>(&path, "finality_update")
2023-03-23 14:07:05 +00:00
.await?;
2022-08-21 15:21:50 +00:00
Ok(res.data)
}
async fn get_optimistic_update(&self) -> Result<OptimisticUpdate> {
2023-03-23 14:07:05 +00:00
let path = format!("/eth/v1/beacon/light_client/optimistic_update");
let res = self
2023-03-24 14:51:21 +00:00
.request::<OptimisticUpdateResponse>(&path, "optimistic_update")
2023-03-23 14:07:05 +00:00
.await?;
2022-08-31 00:31:58 +00:00
Ok(res.data)
}
async fn get_block(&self, slot: u64) -> Result<BeaconBlock> {
2023-03-23 14:07:05 +00:00
let path = format!("/eth/v2/beacon/blocks/{}", slot);
2023-03-24 14:51:21 +00:00
let res = self.request::<BeaconBlockResponse>(&path, "blocks").await?;
2022-08-21 15:21:50 +00:00
Ok(res.data.message)
}
async fn chain_id(&self) -> Result<u64> {
2023-03-23 14:07:05 +00:00
let path = format!("/eth/v1/config/spec");
2023-03-24 14:51:21 +00:00
let res = self.request::<SpecResponse>(&path, "blocks").await?;
Ok(res.data.chain_id)
}
2022-08-21 15:21:50 +00:00
}
#[derive(serde::Deserialize, Debug)]
struct BeaconBlockResponse {
data: BeaconBlockData,
}
#[derive(serde::Deserialize, Debug)]
struct BeaconBlockData {
message: BeaconBlock,
}
type UpdateResponse = Vec<UpdateData>;
2022-08-21 15:21:50 +00:00
#[derive(serde::Deserialize, Debug)]
struct UpdateData {
data: Update,
2022-08-21 15:21:50 +00:00
}
#[derive(serde::Deserialize, Debug)]
struct FinalityUpdateResponse {
data: FinalityUpdate,
}
2022-08-31 00:31:58 +00:00
#[derive(serde::Deserialize, Debug)]
struct OptimisticUpdateResponse {
data: OptimisticUpdate,
}
2022-08-21 15:21:50 +00:00
#[derive(serde::Deserialize, Debug)]
struct BootstrapResponse {
data: Bootstrap,
2022-08-21 15:21:50 +00:00
}
#[derive(serde::Deserialize, Debug)]
struct SpecResponse {
data: Spec,
}
#[derive(serde::Deserialize, Debug)]
struct Spec {
#[serde(rename = "DEPOSIT_NETWORK_ID", deserialize_with = "u64_deserialize")]
chain_id: u64,
}
2023-03-23 14:07:05 +00:00
impl NimbusRpc {
2023-03-24 14:51:21 +00:00
async fn request<T>(&self, path: &str, error_type: &str) -> Result<T, RpcError>
2023-03-23 14:07:05 +00:00
where
for<'a> T: Deserialize<'a>,
{
let js_params = js_sys::Map::new();
js_params.set(&JsValue::from_str("method"), &JsValue::from_str("GET"));
js_params.set(&JsValue::from_str("path"), &JsValue::from_str(&path));
2023-03-24 14:59:16 +00:00
let js_future = JsFuture::from(consensus_rpc_handler(JsValue::from(js_params)));
let result = js_future.await?;
2023-03-23 23:05:44 +00:00
let json = result.as_string().unwrap();
2023-03-24 15:14:48 +00:00
let response: T = serde_json::from_str(&json)
.map_err(|e| RpcError::new(e.to_string(), String::from(error_type)))?;
2023-03-23 23:05:44 +00:00
Ok(response)
2023-03-23 14:07:05 +00:00
}
}