*WIP
This commit is contained in:
parent
602b6dfee5
commit
64eddcaa33
|
@ -709,6 +709,7 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"wasm-timer",
|
"wasm-timer",
|
||||||
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -37,8 +37,6 @@ use crate::rpc::Rpc;
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ClientBuilder {
|
pub struct ClientBuilder {
|
||||||
network: Option<Network>,
|
network: Option<Network>,
|
||||||
consensus_rpc: Option<Arc<wasm_bindgen::JsValue>>,
|
|
||||||
execution_rpc: Option<Arc<wasm_bindgen::JsValue>>,
|
|
||||||
checkpoint: Option<Vec<u8>>,
|
checkpoint: Option<Vec<u8>>,
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
rpc_port: Option<u16>,
|
rpc_port: Option<u16>,
|
||||||
|
@ -60,16 +58,6 @@ impl ClientBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn consensus_rpc(mut self, consensus_rpc: Arc<wasm_bindgen::JsValue>) -> Self {
|
|
||||||
self.consensus_rpc = Some(consensus_rpc);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn execution_rpc(mut self, execution_rpc: Arc<wasm_bindgen::JsValue>) -> Self {
|
|
||||||
self.execution_rpc = Some(execution_rpc);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn checkpoint(mut self, checkpoint: &str) -> Self {
|
pub fn checkpoint(mut self, checkpoint: &str) -> Self {
|
||||||
let checkpoint = hex::decode(checkpoint.strip_prefix("0x").unwrap_or(checkpoint))
|
let checkpoint = hex::decode(checkpoint.strip_prefix("0x").unwrap_or(checkpoint))
|
||||||
.expect("cannot parse checkpoint");
|
.expect("cannot parse checkpoint");
|
||||||
|
@ -120,22 +108,6 @@ impl ClientBuilder {
|
||||||
config.to_base_config()
|
config.to_base_config()
|
||||||
};
|
};
|
||||||
|
|
||||||
let consensus_rpc = self.consensus_rpc.unwrap_or_else(|| {
|
|
||||||
self.config
|
|
||||||
.as_ref()
|
|
||||||
.expect("missing consensus rpc")
|
|
||||||
.consensus_rpc
|
|
||||||
.clone()
|
|
||||||
});
|
|
||||||
|
|
||||||
let execution_rpc = self.execution_rpc.unwrap_or_else(|| {
|
|
||||||
self.config
|
|
||||||
.as_ref()
|
|
||||||
.expect("missing execution rpc")
|
|
||||||
.execution_rpc
|
|
||||||
.clone()
|
|
||||||
});
|
|
||||||
|
|
||||||
let checkpoint = if let Some(checkpoint) = self.checkpoint {
|
let checkpoint = if let Some(checkpoint) = self.checkpoint {
|
||||||
Some(checkpoint)
|
Some(checkpoint)
|
||||||
} else if let Some(config) = &self.config {
|
} else if let Some(config) = &self.config {
|
||||||
|
@ -189,8 +161,6 @@ impl ClientBuilder {
|
||||||
};
|
};
|
||||||
|
|
||||||
let config = Config {
|
let config = Config {
|
||||||
consensus_rpc,
|
|
||||||
execution_rpc,
|
|
||||||
checkpoint,
|
checkpoint,
|
||||||
default_checkpoint,
|
default_checkpoint,
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
@ -344,11 +314,7 @@ impl<DB: Database> Client<DB> {
|
||||||
// Try to sync again with the new checkpoint by reconstructing the consensus client
|
// Try to sync again with the new checkpoint by reconstructing the consensus client
|
||||||
// We fail fast here since the node is unrecoverable at this point
|
// We fail fast here since the node is unrecoverable at this point
|
||||||
let config = self.node.read().await.config.clone();
|
let config = self.node.read().await.config.clone();
|
||||||
let consensus = ConsensusClient::new(
|
let consensus = ConsensusClient::new(checkpoint.as_bytes(), config.clone())?;
|
||||||
config.consensus_rpc.clone(),
|
|
||||||
checkpoint.as_bytes(),
|
|
||||||
config.clone(),
|
|
||||||
)?;
|
|
||||||
self.node.write().await.consensus = consensus;
|
self.node.write().await.consensus = consensus;
|
||||||
self.node.write().await.sync().await?;
|
self.node.write().await.sync().await?;
|
||||||
|
|
||||||
|
@ -388,11 +354,7 @@ impl<DB: Database> Client<DB> {
|
||||||
// Try to sync again with the new checkpoint by reconstructing the consensus client
|
// Try to sync again with the new checkpoint by reconstructing the consensus client
|
||||||
// We fail fast here since the node is unrecoverable at this point
|
// We fail fast here since the node is unrecoverable at this point
|
||||||
let config = self.node.read().await.config.clone();
|
let config = self.node.read().await.config.clone();
|
||||||
let consensus = ConsensusClient::new(
|
let consensus = ConsensusClient::new(checkpoint.as_bytes(), config.clone())?;
|
||||||
config.consensus_rpc.clone(),
|
|
||||||
checkpoint.as_bytes(),
|
|
||||||
config.clone(),
|
|
||||||
)?;
|
|
||||||
self.node.write().await.consensus = consensus;
|
self.node.write().await.consensus = consensus;
|
||||||
self.node.write().await.sync().await?;
|
self.node.write().await.sync().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -34,15 +34,12 @@ pub struct Node {
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
pub fn new(config: Arc<Config>) -> Result<Self, NodeError> {
|
pub fn new(config: Arc<Config>) -> Result<Self, NodeError> {
|
||||||
let consensus_rpc = &config.consensus_rpc;
|
|
||||||
let checkpoint_hash = &config.checkpoint.as_ref().unwrap();
|
let checkpoint_hash = &config.checkpoint.as_ref().unwrap();
|
||||||
let execution_rpc = &config.execution_rpc;
|
|
||||||
|
|
||||||
let consensus = ConsensusClient::new(consensus_rpc, checkpoint_hash, config.clone())
|
let consensus = ConsensusClient::new(checkpoint_hash, config.clone())
|
||||||
.map_err(NodeError::ConsensusClientCreationError)?;
|
.map_err(NodeError::ConsensusClientCreationError)?;
|
||||||
let execution = Arc::new(
|
let execution =
|
||||||
ExecutionClient::new(execution_rpc).map_err(NodeError::ExecutionClientCreationError)?,
|
Arc::new(ExecutionClient::new("").map_err(NodeError::ExecutionClientCreationError)?);
|
||||||
);
|
|
||||||
|
|
||||||
let payloads = BTreeMap::new();
|
let payloads = BTreeMap::new();
|
||||||
let finalized_payloads = BTreeMap::new();
|
let finalized_payloads = BTreeMap::new();
|
||||||
|
|
|
@ -9,8 +9,6 @@ use crate::utils::bytes_serialize;
|
||||||
#[derive(Serialize, Default)]
|
#[derive(Serialize, Default)]
|
||||||
pub struct BaseConfig {
|
pub struct BaseConfig {
|
||||||
pub rpc_port: u16,
|
pub rpc_port: u16,
|
||||||
#[serde(skip_serializing, skip_deserializing)]
|
|
||||||
pub consensus_rpc: Option<Arc<JsValue>>,
|
|
||||||
#[serde(
|
#[serde(
|
||||||
deserialize_with = "bytes_deserialize",
|
deserialize_with = "bytes_deserialize",
|
||||||
serialize_with = "bytes_serialize"
|
serialize_with = "bytes_serialize"
|
||||||
|
|
|
@ -17,9 +17,6 @@ use crate::utils::{bytes_deserialize, bytes_opt_deserialize};
|
||||||
#[derive(Deserialize, Debug, Default)]
|
#[derive(Deserialize, Debug, Default)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
#[serde(skip_serializing, skip_deserializing)]
|
#[serde(skip_serializing, skip_deserializing)]
|
||||||
pub consensus_rpc: Arc<wasm_bindgen::JsValue>,
|
|
||||||
#[serde(skip_serializing, skip_deserializing)]
|
|
||||||
pub execution_rpc: Arc<wasm_bindgen::JsValue>,
|
|
||||||
pub rpc_port: Option<u16>,
|
pub rpc_port: Option<u16>,
|
||||||
#[serde(deserialize_with = "bytes_deserialize")]
|
#[serde(deserialize_with = "bytes_deserialize")]
|
||||||
pub default_checkpoint: Vec<u8>,
|
pub default_checkpoint: Vec<u8>,
|
||||||
|
@ -106,7 +103,6 @@ impl Config {
|
||||||
pub fn to_base_config(&self) -> BaseConfig {
|
pub fn to_base_config(&self) -> BaseConfig {
|
||||||
BaseConfig {
|
BaseConfig {
|
||||||
rpc_port: self.rpc_port.unwrap_or(8545),
|
rpc_port: self.rpc_port.unwrap_or(8545),
|
||||||
consensus_rpc: Some(self.consensus_rpc.clone()),
|
|
||||||
default_checkpoint: self.default_checkpoint.clone(),
|
default_checkpoint: self.default_checkpoint.clone(),
|
||||||
chain: self.chain.clone(),
|
chain: self.chain.clone(),
|
||||||
forks: self.forks.clone(),
|
forks: self.forks.clone(),
|
||||||
|
|
|
@ -42,7 +42,6 @@ pub fn mainnet() -> BaseConfig {
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
rpc_port: 8545,
|
rpc_port: 8545,
|
||||||
consensus_rpc: Some(Arc::from(JsValue::null())),
|
|
||||||
chain: ChainConfig {
|
chain: ChainConfig {
|
||||||
chain_id: 1,
|
chain_id: 1,
|
||||||
genesis_time: 1606824023,
|
genesis_time: 1606824023,
|
||||||
|
@ -80,7 +79,6 @@ pub fn goerli() -> BaseConfig {
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
rpc_port: 8545,
|
rpc_port: 8545,
|
||||||
consensus_rpc: None,
|
|
||||||
chain: ChainConfig {
|
chain: ChainConfig {
|
||||||
chain_id: 5,
|
chain_id: 5,
|
||||||
genesis_time: 1616508000,
|
genesis_time: 1616508000,
|
||||||
|
|
|
@ -27,6 +27,7 @@ wasm-bindgen = "0.2.84"
|
||||||
js-sys = "0.3.61"
|
js-sys = "0.3.61"
|
||||||
serde-wasm-bindgen = "0.5.0"
|
serde-wasm-bindgen = "0.5.0"
|
||||||
wasm-bindgen-futures = "0.4.34"
|
wasm-bindgen-futures = "0.4.34"
|
||||||
|
web-sys = {version ="0.3.61", features=["Window","WindowClient"]}
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
openssl = { version = "0.10", features = ["vendored"] }
|
openssl = { version = "0.10", features = ["vendored"] }
|
||||||
|
|
|
@ -54,12 +54,8 @@ struct LightClientStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: ConsensusRpc> ConsensusClient<R> {
|
impl<R: ConsensusRpc> ConsensusClient<R> {
|
||||||
pub fn new(
|
pub fn new(checkpoint_block_root: &[u8], config: Arc<Config>) -> Result<ConsensusClient<R>> {
|
||||||
rpc_handler: Arc<wasm_bindgen::JsValue>,
|
let rpc = R::new();
|
||||||
checkpoint_block_root: &[u8],
|
|
||||||
config: Arc<Config>,
|
|
||||||
) -> Result<ConsensusClient<R>> {
|
|
||||||
let rpc = R::new(rpc_handler);
|
|
||||||
|
|
||||||
Ok(ConsensusClient {
|
Ok(ConsensusClient {
|
||||||
rpc,
|
rpc,
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::types::{BeaconBlock, Bootstrap, FinalityUpdate, OptimisticUpdate, Upd
|
||||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||||
pub trait ConsensusRpc {
|
pub trait ConsensusRpc {
|
||||||
fn new(rpc_handler: Arc<wasm_bindgen::JsValue>) -> Self;
|
fn new() -> Self;
|
||||||
async fn get_bootstrap(&self, block_root: &'_ [u8]) -> Result<Bootstrap>;
|
async fn get_bootstrap(&self, block_root: &'_ [u8]) -> Result<Bootstrap>;
|
||||||
async fn get_updates(&self, period: u64, count: u8) -> Result<Vec<Update>>;
|
async fn get_updates(&self, period: u64, count: u8) -> Result<Vec<Update>>;
|
||||||
async fn get_finality_update(&self) -> Result<FinalityUpdate>;
|
async fn get_finality_update(&self) -> Result<FinalityUpdate>;
|
||||||
|
|
|
@ -1,17 +1,24 @@
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use eyre::{Result, WrapErr};
|
use eyre::{Result, WrapErr};
|
||||||
|
use js_sys::{Function, Map, Promise};
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::from_str as from_json_str;
|
use serde_json::from_str as from_json_str;
|
||||||
|
use serde_wasm_bindgen::to_value;
|
||||||
|
use wasm_bindgen::closure::Closure;
|
||||||
use wasm_bindgen::{JsCast, JsValue};
|
use wasm_bindgen::{JsCast, JsValue};
|
||||||
|
|
||||||
|
use wasm_bindgen::prelude::wasm_bindgen;
|
||||||
use wasm_bindgen_futures::JsFuture;
|
use wasm_bindgen_futures::JsFuture;
|
||||||
|
|
||||||
use crate::constants::MAX_REQUEST_LIGHT_CLIENT_UPDATES;
|
use crate::constants::MAX_REQUEST_LIGHT_CLIENT_UPDATES;
|
||||||
use crate::types::*;
|
use crate::types::*;
|
||||||
|
use web_sys;
|
||||||
|
|
||||||
use super::ConsensusRpc;
|
use super::ConsensusRpc;
|
||||||
|
|
||||||
|
@ -20,30 +27,53 @@ pub struct RpcError {
|
||||||
message: String,
|
message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RpcError {
|
||||||
|
pub fn new(message: String) -> Self {
|
||||||
|
Self { message }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for RpcError {
|
impl Display for RpcError {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||||
write!(f, "{}", self.message)
|
write!(f, "{}", self.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for RpcError {}
|
impl From<JsValue> for RpcError {
|
||||||
|
fn from(js_error: JsValue) -> Self {
|
||||||
|
let message = js_error
|
||||||
|
.as_string()
|
||||||
|
.unwrap_or_else(|| "Unknown error".to_string());
|
||||||
|
RpcError::new(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for RpcError {
|
||||||
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct NimbusRpc {
|
pub struct NimbusRpc {}
|
||||||
rpc_handler: Arc<JsValue>,
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
extern "C" {
|
||||||
|
#[wasm_bindgen(js_namespace = window)]
|
||||||
|
fn consensus_rpc_handler(data: JsValue) -> Promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
impl ConsensusRpc for NimbusRpc {
|
impl ConsensusRpc for NimbusRpc {
|
||||||
fn new(rpc_handler: Arc<JsValue>) -> Self {
|
fn new() -> Self {
|
||||||
NimbusRpc { rpc_handler }
|
NimbusRpc {}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_bootstrap(&self, block_root: &'_ [u8]) -> Result<Bootstrap> {
|
async fn get_bootstrap(&self, block_root: &'_ [u8]) -> Result<Bootstrap> {
|
||||||
let root_hex = hex::encode(block_root);
|
let root_hex = hex::encode(block_root);
|
||||||
let path = format!("/eth/v1/beacon/light_client/bootstrap/0x{}", root_hex);
|
let path = format!("/eth/v1/beacon/light_client/bootstrap/0x{}", root_hex);
|
||||||
|
|
||||||
let res = self.request::<Bootstrap>(path, "bootstrap").await?;
|
let res = self.request::<Bootstrap>(&path, "bootstrap").await?;
|
||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
@ -55,7 +85,7 @@ impl ConsensusRpc for NimbusRpc {
|
||||||
period, count
|
period, count
|
||||||
);
|
);
|
||||||
|
|
||||||
let res = self.request::<UpdateResponse>(path, "updates").await?;
|
let res = self.request::<UpdateResponse>(&path, "updates").await?;
|
||||||
|
|
||||||
Ok(res.iter().map(|d| d.data.clone()).collect())
|
Ok(res.iter().map(|d| d.data.clone()).collect())
|
||||||
}
|
}
|
||||||
|
@ -64,7 +94,7 @@ impl ConsensusRpc for NimbusRpc {
|
||||||
let path = format!("/eth/v1/beacon/light_client/finality_update");
|
let path = format!("/eth/v1/beacon/light_client/finality_update");
|
||||||
|
|
||||||
let res = self
|
let res = self
|
||||||
.request::<FinalityUpdateResponse>(path, "finality_update")
|
.request::<FinalityUpdateResponse>(&path, "finality_update")
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(res.data)
|
Ok(res.data)
|
||||||
|
@ -74,7 +104,7 @@ impl ConsensusRpc for NimbusRpc {
|
||||||
let path = format!("/eth/v1/beacon/light_client/optimistic_update");
|
let path = format!("/eth/v1/beacon/light_client/optimistic_update");
|
||||||
|
|
||||||
let res = self
|
let res = self
|
||||||
.request::<OptimisticUpdateResponse>(path, "optimistic_update")
|
.request::<OptimisticUpdateResponse>(&path, "optimistic_update")
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(res.data)
|
Ok(res.data)
|
||||||
|
@ -83,7 +113,7 @@ impl ConsensusRpc for NimbusRpc {
|
||||||
async fn get_block(&self, slot: u64) -> Result<BeaconBlock> {
|
async fn get_block(&self, slot: u64) -> Result<BeaconBlock> {
|
||||||
let path = format!("/eth/v2/beacon/blocks/{}", slot);
|
let path = format!("/eth/v2/beacon/blocks/{}", slot);
|
||||||
|
|
||||||
let res = self.request::<BeaconBlockResponse>(path, "blocks").await?;
|
let res = self.request::<BeaconBlockResponse>(&path, "blocks").await?;
|
||||||
|
|
||||||
Ok(res.data.message)
|
Ok(res.data.message)
|
||||||
}
|
}
|
||||||
|
@ -91,7 +121,7 @@ impl ConsensusRpc for NimbusRpc {
|
||||||
async fn chain_id(&self) -> Result<u64> {
|
async fn chain_id(&self) -> Result<u64> {
|
||||||
let path = format!("/eth/v1/config/spec");
|
let path = format!("/eth/v1/config/spec");
|
||||||
|
|
||||||
let res = self.request::<SpecResponse>(path, "blocks").await?;
|
let res = self.request::<SpecResponse>(&path, "blocks").await?;
|
||||||
|
|
||||||
Ok(res.data.chain_id)
|
Ok(res.data.chain_id)
|
||||||
}
|
}
|
||||||
|
@ -141,7 +171,7 @@ struct Spec {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NimbusRpc {
|
impl NimbusRpc {
|
||||||
async fn request<T>(&self, path: String, error_type: &str) -> Result<T>
|
async fn request<T>(&self, path: &str, error_type: &str) -> Result<T, RpcError>
|
||||||
where
|
where
|
||||||
for<'a> T: Deserialize<'a>,
|
for<'a> T: Deserialize<'a>,
|
||||||
{
|
{
|
||||||
|
@ -149,20 +179,13 @@ impl NimbusRpc {
|
||||||
js_params.set(&JsValue::from_str("method"), &JsValue::from_str("GET"));
|
js_params.set(&JsValue::from_str("method"), &JsValue::from_str("GET"));
|
||||||
js_params.set(&JsValue::from_str("path"), &JsValue::from_str(&path));
|
js_params.set(&JsValue::from_str("path"), &JsValue::from_str(&path));
|
||||||
|
|
||||||
let rpc_handler_clone = self.rpc_handler.clone();
|
let result = unsafe {
|
||||||
let promise = Arc::clone(&rpc_handler_clone)
|
let js_future = JsFuture::from(consensus_rpc_handler(JsValue::from(js_params)));
|
||||||
.dyn_into::<js_sys::Function>()
|
let result = js_future.await?;
|
||||||
.unwrap()
|
result
|
||||||
.call1(&JsValue::null(), &js_params)
|
|
||||||
.expect("Failed to make JSON-RPC request");
|
|
||||||
|
|
||||||
let result = match promise.dyn_into::<js_sys::Promise>() {
|
|
||||||
Ok(promise) => JsFuture::from(promise).await.unwrap(),
|
|
||||||
Err(_) => panic!("Unable to convert JS value to Promise"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let json = result.as_string().unwrap();
|
let json = result.as_string().unwrap();
|
||||||
let response: T = serde_json::from_str(&json)?;
|
let response: T = serde_json::from_str(&json).map_err(|e| RpcError::new(e.to_string()))?;
|
||||||
|
|
||||||
Ok(response)
|
Ok(response)
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ pub struct ExecutionClient<R: ExecutionRpc> {
|
||||||
|
|
||||||
impl<R: ExecutionRpc> ExecutionClient<R> {
|
impl<R: ExecutionRpc> ExecutionClient<R> {
|
||||||
pub fn new(rpc: &str) -> Result<Self> {
|
pub fn new(rpc: &str) -> Result<Self> {
|
||||||
let rpc: R = ExecutionRpc::new(rpc)?;
|
let rpc: R = ExecutionRpc::new()?;
|
||||||
Ok(ExecutionClient { rpc })
|
Ok(ExecutionClient { rpc })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,16 +27,22 @@ use common::errors::RpcError;
|
||||||
use super::ExecutionRpc;
|
use super::ExecutionRpc;
|
||||||
|
|
||||||
use js_sys::{Function, Promise};
|
use js_sys::{Function, Promise};
|
||||||
|
use wasm_bindgen::prelude::wasm_bindgen;
|
||||||
use wasm_bindgen_futures::JsFuture;
|
use wasm_bindgen_futures::JsFuture;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
extern "C" {
|
||||||
|
#[wasm_bindgen(js_namespace = window)]
|
||||||
|
fn consensus_rpc_handler(data: JsValue) -> Promise;
|
||||||
|
}
|
||||||
|
|
||||||
pub struct HttpRpc {
|
pub struct HttpRpc {
|
||||||
provider: Provider<LumeProvider>,
|
provider: Provider<LumeProvider>,
|
||||||
rpc_handler: Arc<JsValue>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for HttpRpc {
|
impl Clone for HttpRpc {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self::new(self.rpc_handler.clone()).unwrap()
|
Self::new().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,18 +70,32 @@ impl From<LumeError> for ProviderError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
impl From<JsValue> for LumeError {
|
||||||
pub struct LumeProvider {
|
fn from(error: JsValue) -> Self {
|
||||||
pub rpc_handler: Arc<JsValue>,
|
LumeError {
|
||||||
|
message: error
|
||||||
|
.as_string()
|
||||||
|
.unwrap_or_else(|| "Unknown error".to_string()),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<RpcError<String>> for LumeError {
|
||||||
|
fn from(error: RpcError<String>) -> Self {
|
||||||
|
LumeError {
|
||||||
|
message: error.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct LumeProvider {}
|
||||||
|
|
||||||
impl LumeProvider {
|
impl LumeProvider {
|
||||||
pub fn new(rpc_handler: Arc<JsValue>) -> Self {
|
pub fn new() -> Self {
|
||||||
LumeProvider { rpc_handler }
|
LumeProvider {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||||
impl JsonRpcClient for LumeProvider {
|
impl JsonRpcClient for LumeProvider {
|
||||||
type Error = LumeError;
|
type Error = LumeError;
|
||||||
|
@ -85,32 +105,31 @@ impl JsonRpcClient for LumeProvider {
|
||||||
T: Debug + Serialize + Send + Sync,
|
T: Debug + Serialize + Send + Sync,
|
||||||
R: DeserializeOwned,
|
R: DeserializeOwned,
|
||||||
{
|
{
|
||||||
let js_method = JsValue::from(method);
|
|
||||||
let js_params = to_value(¶ms).unwrap();
|
let js_params = to_value(¶ms).unwrap();
|
||||||
|
let json_str = serde_json::to_string(&js_params).unwrap();
|
||||||
|
let js_value = JsValue::from_str(&json_str);
|
||||||
|
|
||||||
let promise = self
|
let result = unsafe {
|
||||||
.rpc_handler
|
let js_future = JsFuture::from(consensus_rpc_handler(js_value));
|
||||||
.dyn_into::<Function>()
|
let result = js_future.await?;
|
||||||
.unwrap()
|
result
|
||||||
.call2(&js_method, &js_params)
|
|
||||||
.unwrap();
|
|
||||||
let result = match promise.dyn_into::<js_sys::Promise>() {
|
|
||||||
Ok(promise) => JsFuture::from(promise).await.unwrap(),
|
|
||||||
Err(_) => panic!("Unable to convert JS value to Promise"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let json = result.as_string().unwrap();
|
||||||
|
let response: R =
|
||||||
|
serde_json::from_str(&json).map_err(|e| RpcError::new(method, e.to_string()))?;
|
||||||
|
|
||||||
|
Ok(response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
impl ExecutionRpc for HttpRpc {
|
impl ExecutionRpc for HttpRpc {
|
||||||
fn new(rpc_handler: Arc<JsValue>) -> Result<Self> {
|
fn new() -> Result<Self> {
|
||||||
let mut client = LumeProvider::new(rpc_handler.clone());
|
let mut client = LumeProvider::new();
|
||||||
let provider = Provider::new(client);
|
let provider = Provider::new(client);
|
||||||
|
|
||||||
Ok(HttpRpc {
|
Ok(HttpRpc { provider })
|
||||||
provider,
|
|
||||||
rpc_handler,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_proof(
|
async fn get_proof(
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
use std::{fs::read_to_string, path::PathBuf};
|
|
||||||
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use common::utils::hex_str_to_bytes;
|
|
||||||
use ethers::types::{
|
|
||||||
transaction::eip2930::AccessList, Address, EIP1186ProofResponse, FeeHistory, Filter, Log,
|
|
||||||
Transaction, TransactionReceipt, H256,
|
|
||||||
};
|
|
||||||
use eyre::{eyre, Result};
|
|
||||||
|
|
||||||
use crate::types::CallOpts;
|
|
||||||
|
|
||||||
use super::ExecutionRpc;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct MockRpc {
|
|
||||||
path: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
|
||||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
|
||||||
impl ExecutionRpc for MockRpc {
|
|
||||||
fn new(rpc: &str) -> Result<Self> {
|
|
||||||
let path = PathBuf::from(rpc);
|
|
||||||
Ok(MockRpc { path })
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_proof(
|
|
||||||
&self,
|
|
||||||
_address: &Address,
|
|
||||||
_slots: &[H256],
|
|
||||||
_block: u64,
|
|
||||||
) -> Result<EIP1186ProofResponse> {
|
|
||||||
let proof = read_to_string(self.path.join("proof.json"))?;
|
|
||||||
Ok(serde_json::from_str(&proof)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn create_access_list(&self, _opts: &CallOpts, _block: u64) -> Result<AccessList> {
|
|
||||||
Err(eyre!("not implemented"))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_code(&self, _address: &Address, _block: u64) -> Result<Vec<u8>> {
|
|
||||||
let code = read_to_string(self.path.join("code.json"))?;
|
|
||||||
hex_str_to_bytes(&code[0..code.len() - 1])
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send_raw_transaction(&self, _bytes: &[u8]) -> Result<H256> {
|
|
||||||
Err(eyre!("not implemented"))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_transaction_receipt(&self, _tx_hash: &H256) -> Result<Option<TransactionReceipt>> {
|
|
||||||
let receipt = read_to_string(self.path.join("receipt.json"))?;
|
|
||||||
Ok(serde_json::from_str(&receipt)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_transaction(&self, _tx_hash: &H256) -> Result<Option<Transaction>> {
|
|
||||||
let tx = read_to_string(self.path.join("transaction.json"))?;
|
|
||||||
Ok(serde_json::from_str(&tx)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_logs(&self, _filter: &Filter) -> Result<Vec<Log>> {
|
|
||||||
let logs = read_to_string(self.path.join("logs.json"))?;
|
|
||||||
Ok(serde_json::from_str(&logs)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn chain_id(&self) -> Result<u64> {
|
|
||||||
Err(eyre!("not implemented"))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_fee_history(
|
|
||||||
&self,
|
|
||||||
_block_count: u64,
|
|
||||||
_last_block: u64,
|
|
||||||
_reward_percentiles: &[f64],
|
|
||||||
) -> Result<FeeHistory> {
|
|
||||||
let fee_history = read_to_string(self.path.join("fee_history.json"))?;
|
|
||||||
Ok(serde_json::from_str(&fee_history)?)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,12 +8,10 @@ use eyre::Result;
|
||||||
use crate::types::CallOpts;
|
use crate::types::CallOpts;
|
||||||
|
|
||||||
pub mod http_rpc;
|
pub mod http_rpc;
|
||||||
pub mod mock_rpc;
|
|
||||||
|
|
||||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||||
pub trait ExecutionRpc: Send + Clone + Sync + 'static {
|
pub trait ExecutionRpc: Send + Clone + Sync + 'static {
|
||||||
fn new(rpc: &str) -> Result<Self>
|
fn new() -> Result<Self>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,4 @@ execution = { path = "../execution" }
|
||||||
config = { path = "../config" }
|
config = { path = "../config" }
|
||||||
|
|
||||||
[dependencies.web-sys]
|
[dependencies.web-sys]
|
||||||
version = "0.3"
|
version = "0.3.61"
|
||||||
features = [
|
|
||||||
"console",
|
|
||||||
]
|
|
||||||
|
|
|
@ -28,21 +28,13 @@ pub struct Client {
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
impl Client {
|
impl Client {
|
||||||
#[wasm_bindgen(constructor)]
|
#[wasm_bindgen(constructor)]
|
||||||
pub fn new(
|
pub fn new(network: String, checkpoint: Option<String>) -> Self {
|
||||||
execution_rpc: JsValue,
|
|
||||||
consensus_rpc: JsValue,
|
|
||||||
network: String,
|
|
||||||
checkpoint: Option<String>,
|
|
||||||
) -> Self {
|
|
||||||
console_error_panic_hook::set_once();
|
console_error_panic_hook::set_once();
|
||||||
|
|
||||||
let base = networks::mainnet();
|
let base = networks::mainnet();
|
||||||
|
|
||||||
let chain_id = base.chain.chain_id;
|
let chain_id = base.chain.chain_id;
|
||||||
|
|
||||||
let execution_rpc = Arc::new(execution_rpc);
|
|
||||||
let consensus_rpc = Arc::new(consensus_rpc);
|
|
||||||
|
|
||||||
let checkpoint = Some(
|
let checkpoint = Some(
|
||||||
checkpoint
|
checkpoint
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -52,8 +44,6 @@ impl Client {
|
||||||
);
|
);
|
||||||
|
|
||||||
let config = Config {
|
let config = Config {
|
||||||
execution_rpc,
|
|
||||||
consensus_rpc,
|
|
||||||
checkpoint,
|
checkpoint,
|
||||||
|
|
||||||
chain: base.chain,
|
chain: base.chain,
|
||||||
|
|
Loading…
Reference in New Issue