Compare commits

...

9 Commits
master ... lume

Author SHA1 Message Date
Derrick Hammer 7adc38ae1a
*WIP 2023-03-26 14:20:07 -04:00
Derrick Hammer 15fd1b8f88
*WIP 2023-03-25 12:47:57 -04:00
Derrick Hammer 6747fe777c
*WIP 2023-03-25 11:33:40 -04:00
Derrick Hammer 086884b617
*WIP 2023-03-24 12:51:57 -04:00
Derrick Hammer 2e116d3e2f
*WIP 2023-03-24 11:14:48 -04:00
Derrick Hammer 18742dcd1c
*WIP 2023-03-24 10:59:16 -04:00
Derrick Hammer 64eddcaa33
*WIP 2023-03-24 10:51:21 -04:00
Derrick Hammer 602b6dfee5
*WIP 2023-03-23 19:05:44 -04:00
Derrick Hammer 93b4d502ba
*WIP 2023-03-23 10:07:05 -04:00
23 changed files with 253 additions and 5418 deletions

5119
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -29,12 +29,12 @@ common = { path = "./common" }
consensus = { path = "./consensus" }
execution = { path = "./execution" }
serde = { version = "1.0.154", features = ["derive"] }
ethers = "1.0.2"
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
tokio = { version = "1", features = ["full"] }
eyre = "0.6.8"
dirs = "4.0.0"
ethers = { version = "1.0.2", features = [ "abigen" ] }
env_logger = "0.9.0"
log = "0.4.17"
tracing-test = "0.2.4"
@ -93,3 +93,6 @@ harness = false
[[bench]]
name = "sync"
harness = false
[replace]
"ethers:1.0.2" = { git = "https://git.lumeweb.com/LumeWeb/ethers-rs.git", branch= "lume" }

View File

@ -23,3 +23,4 @@ futures = "0.3.23"
client = { path = "../client" }
config = { path = "../config" }
common = { path = "../common" }
wasm-bindgen = "0.2.84"

View File

@ -8,7 +8,7 @@ eyre = "0.6.8"
serde = { version = "1.0.143", features = ["derive"] }
hex = "0.4.3"
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" }
ethers = "1.0.0"
ethers = { version = "1.0.2", path = "../../helios-workspace/ethers-rs"}
futures = "0.3.23"
log = "0.4.17"
thiserror = "1.0.37"
@ -17,6 +17,7 @@ common = { path = "../common" }
consensus = { path = "../consensus" }
execution = { path = "../execution" }
config = { path = "../config" }
wasm-bindgen = "0.2.84"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
jsonrpsee = { version = "0.15.1", features = ["full"] }

View File

@ -37,8 +37,6 @@ use crate::rpc::Rpc;
#[derive(Default)]
pub struct ClientBuilder {
network: Option<Network>,
consensus_rpc: Option<String>,
execution_rpc: Option<String>,
checkpoint: Option<Vec<u8>>,
#[cfg(not(target_arch = "wasm32"))]
rpc_port: Option<u16>,
@ -60,16 +58,6 @@ impl ClientBuilder {
self
}
pub fn consensus_rpc(mut self, consensus_rpc: &str) -> Self {
self.consensus_rpc = Some(consensus_rpc.to_string());
self
}
pub fn execution_rpc(mut self, execution_rpc: &str) -> Self {
self.execution_rpc = Some(execution_rpc.to_string());
self
}
pub fn checkpoint(mut self, checkpoint: &str) -> Self {
let checkpoint = hex::decode(checkpoint.strip_prefix("0x").unwrap_or(checkpoint))
.expect("cannot parse checkpoint");
@ -120,22 +108,6 @@ impl ClientBuilder {
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 {
Some(checkpoint)
} else if let Some(config) = &self.config {
@ -189,8 +161,6 @@ impl ClientBuilder {
};
let config = Config {
consensus_rpc,
execution_rpc,
checkpoint,
default_checkpoint,
#[cfg(not(target_arch = "wasm32"))]
@ -344,8 +314,7 @@ impl<DB: Database> Client<DB> {
// 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
let config = self.node.read().await.config.clone();
let consensus =
ConsensusClient::new(&config.consensus_rpc, checkpoint.as_bytes(), config.clone())?;
let consensus = ConsensusClient::new(checkpoint.as_bytes(), config.clone())?;
self.node.write().await.consensus = consensus;
self.node.write().await.sync().await?;
@ -385,8 +354,7 @@ impl<DB: Database> Client<DB> {
// 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
let config = self.node.read().await.config.clone();
let consensus =
ConsensusClient::new(&config.consensus_rpc, checkpoint.as_bytes(), config.clone())?;
let consensus = ConsensusClient::new(checkpoint.as_bytes(), config.clone())?;
self.node.write().await.consensus = consensus;
self.node.write().await.sync().await?;
Ok(())

View File

@ -34,15 +34,12 @@ pub struct Node {
impl Node {
pub fn new(config: Arc<Config>) -> Result<Self, NodeError> {
let consensus_rpc = &config.consensus_rpc;
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)?;
let execution = Arc::new(
ExecutionClient::new(execution_rpc).map_err(NodeError::ExecutionClientCreationError)?,
);
let execution =
Arc::new(ExecutionClient::new("").map_err(NodeError::ExecutionClientCreationError)?);
let payloads = BTreeMap::new();
let finalized_payloads = BTreeMap::new();

View File

@ -1,3 +1,6 @@
use ethers::providers::HttpClientError;
use ethers::providers::JsonRpcError;
use ethers::providers::Provider;
use ethers::types::H256;
use thiserror::Error;

View File

@ -9,7 +9,7 @@ eyre = "0.6.8"
serde = { version = "1.0.143", features = ["derive"] }
hex = "0.4.3"
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" }
ethers = "1.0.0"
ethers = { version = "1.0.2", path = "../../helios-workspace/ethers-rs"}
figment = { version = "0.10.7", features = ["toml", "env"] }
thiserror = "1.0.37"
log = "0.4.17"
@ -19,6 +19,9 @@ strum = "0.24.1"
futures = "0.3.25"
common = { path = "../common" }
wasm-bindgen = "0.2.84"
serde_json = "1.0.94"
js-sys = "0.3.61"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tokio = { version = "1", features = ["full"] }

View File

@ -7,7 +7,6 @@ use crate::utils::bytes_serialize;
#[derive(Serialize, Default)]
pub struct BaseConfig {
pub rpc_port: u16,
pub consensus_rpc: Option<String>,
#[serde(
deserialize_with = "bytes_deserialize",
serialize_with = "bytes_serialize"

View File

@ -2,7 +2,7 @@ use figment::{
providers::{Format, Serialized, Toml},
Figment,
};
use serde::Deserialize;
use serde::{Deserialize, Deserializer};
use std::{path::PathBuf, process::exit};
use crate::base::BaseConfig;
@ -13,8 +13,7 @@ use crate::utils::{bytes_deserialize, bytes_opt_deserialize};
#[derive(Deserialize, Debug, Default)]
pub struct Config {
pub consensus_rpc: String,
pub execution_rpc: String,
#[serde(skip_serializing, skip_deserializing)]
pub rpc_port: Option<u16>,
#[serde(deserialize_with = "bytes_deserialize")]
pub default_checkpoint: Vec<u8>,
@ -30,6 +29,18 @@ pub struct Config {
pub strict_checkpoint_age: bool,
}
struct JsonString(String);
impl<'de> Deserialize<'de> for JsonString {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json_string = String::deserialize(deserializer)?;
Ok(JsonString(json_string))
}
}
impl Config {
pub fn from_file(config_path: &PathBuf, network: &str, cli_config: &CliConfig) -> Self {
let base_config = match network {
@ -87,7 +98,6 @@ impl Config {
pub fn to_base_config(&self) -> BaseConfig {
BaseConfig {
rpc_port: self.rpc_port.unwrap_or(8545),
consensus_rpc: Some(self.consensus_rpc.clone()),
default_checkpoint: self.default_checkpoint.clone(),
chain: self.chain.clone(),
forks: self.forks.clone(),

View File

@ -40,7 +40,6 @@ pub fn mainnet() -> BaseConfig {
)
.unwrap(),
rpc_port: 8545,
consensus_rpc: Some("https://www.lightclientdata.org".to_string()),
chain: ChainConfig {
chain_id: 1,
genesis_time: 1606824023,
@ -78,7 +77,6 @@ pub fn goerli() -> BaseConfig {
)
.unwrap(),
rpc_port: 8545,
consensus_rpc: None,
chain: ChainConfig {
chain_id: 5,
genesis_time: 1616508000,

View File

@ -11,7 +11,7 @@ serde_json = "1.0.85"
hex = "0.4.3"
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" }
milagro_bls = { git = "https://github.com/Snowfork/milagro_bls" }
ethers = "1.0.0"
ethers = { version = "1.0.2", path = "../../helios-workspace/ethers-rs"}
bytes = "1.2.1"
toml = "0.5.9"
async-trait = "0.1.57"
@ -23,6 +23,11 @@ superstruct = "0.7.0"
common = { path = "../common" }
config = { path = "../config" }
wasm-bindgen = "0.2.84"
js-sys = "0.3.61"
serde-wasm-bindgen = "0.5.0"
wasm-bindgen-futures = "0.4.34"
web-sys = { version = "0.3.61" }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
openssl = { version = "0.10", features = ["vendored"] }
@ -30,4 +35,3 @@ tokio = { version = "1", features = ["full"] }
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-timer = "0.2.5"

View File

@ -54,12 +54,8 @@ struct LightClientStore {
}
impl<R: ConsensusRpc> ConsensusClient<R> {
pub fn new(
rpc: &str,
checkpoint_block_root: &[u8],
config: Arc<Config>,
) -> Result<ConsensusClient<R>> {
let rpc = R::new(rpc);
pub fn new(checkpoint_block_root: &[u8], config: Arc<Config>) -> Result<ConsensusClient<R>> {
let rpc = R::new();
Ok(ConsensusClient {
rpc,
@ -660,8 +656,8 @@ mod tests {
async fn get_client(strict_checkpoint_age: bool) -> ConsensusClient<MockRpc> {
let base_config = networks::goerli();
let config = Config {
consensus_rpc: String::new(),
execution_rpc: String::new(),
consensus_rpc: Arc::from(wasm_bindgen::JsValue::null()),
execution_rpc: Arc::from(wasm_bindgen::JsValue::null()),
chain: base_config.chain,
forks: base_config.forks,
strict_checkpoint_age,
@ -672,7 +668,12 @@ mod tests {
hex::decode("1e591af1e90f2db918b2a132991c7c2ee9a4ab26da496bd6e71e4f0bd65ea870")
.unwrap();
let mut client = ConsensusClient::new("testdata/", &checkpoint, Arc::new(config)).unwrap();
let mut client = ConsensusClient::new(
Arc::from(wasm_bindgen::JsValue::null()),
&checkpoint,
Arc::new(config),
)
.unwrap();
client.bootstrap().await.unwrap();
client
}

View File

@ -1,48 +0,0 @@
use std::{fs::read_to_string, path::PathBuf};
use super::ConsensusRpc;
use crate::types::{BeaconBlock, Bootstrap, FinalityUpdate, OptimisticUpdate, Update};
use async_trait::async_trait;
use eyre::Result;
pub struct MockRpc {
testdata: PathBuf,
}
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl ConsensusRpc for MockRpc {
fn new(path: &str) -> Self {
MockRpc {
testdata: PathBuf::from(path),
}
}
async fn get_bootstrap(&self, _block_root: &'_ [u8]) -> Result<Bootstrap> {
let bootstrap = read_to_string(self.testdata.join("bootstrap.json"))?;
Ok(serde_json::from_str(&bootstrap)?)
}
async fn get_updates(&self, _period: u64, _count: u8) -> Result<Vec<Update>> {
let updates = read_to_string(self.testdata.join("updates.json"))?;
Ok(serde_json::from_str(&updates)?)
}
async fn get_finality_update(&self) -> Result<FinalityUpdate> {
let finality = read_to_string(self.testdata.join("finality.json"))?;
Ok(serde_json::from_str(&finality)?)
}
async fn get_optimistic_update(&self) -> Result<OptimisticUpdate> {
let optimistic = read_to_string(self.testdata.join("optimistic.json"))?;
Ok(serde_json::from_str(&optimistic)?)
}
async fn get_block(&self, _slot: u64) -> Result<BeaconBlock> {
let block = read_to_string(self.testdata.join("blocks.json"))?;
Ok(serde_json::from_str(&block)?)
}
async fn chain_id(&self) -> Result<u64> {
eyre::bail!("not implemented")
}
}

View File

@ -1,4 +1,3 @@
pub mod mock_rpc;
pub mod nimbus_rpc;
use async_trait::async_trait;
@ -10,7 +9,7 @@ use crate::types::{BeaconBlock, Bootstrap, FinalityUpdate, OptimisticUpdate, Upd
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
pub trait ConsensusRpc {
fn new(path: &str) -> Self;
fn new() -> Self;
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_finality_update(&self) -> Result<FinalityUpdate>;

View File

@ -1,110 +1,123 @@
use std::cmp;
use std::fmt::{Display, Formatter, Result as FmtResult};
use async_trait::async_trait;
use eyre::Result;
use std::cmp;
use js_sys::Promise;
use serde::Deserialize;
use wasm_bindgen::JsValue;
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen_futures::JsFuture;
use super::ConsensusRpc;
use crate::constants::MAX_REQUEST_LIGHT_CLIENT_UPDATES;
use crate::types::*;
use common::errors::RpcError;
use super::ConsensusRpc;
#[derive(Debug)]
pub struct NimbusRpc {
rpc: String,
pub struct RpcError {
message: String,
_type: String,
}
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl RpcError {
pub fn new(message: String, _type: String) -> Self {
Self { message, _type }
}
}
impl Display for RpcError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "{} error {}", self._type, self.message)
}
}
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, String::from(""))
}
}
impl std::error::Error for RpcError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
#[derive(Debug)]
pub struct NimbusRpc {}
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = self)]
fn consensus_rpc_handler(data: JsValue) -> Promise;
}
#[async_trait(?Send)]
impl ConsensusRpc for NimbusRpc {
fn new(rpc: &str) -> Self {
NimbusRpc {
rpc: rpc.to_string(),
}
fn new() -> Self {
NimbusRpc {}
}
async fn get_bootstrap(&self, block_root: &'_ [u8]) -> Result<Bootstrap> {
let root_hex = hex::encode(block_root);
let req = format!(
"{}/eth/v1/beacon/light_client/bootstrap/0x{}",
self.rpc, root_hex
);
let path = format!("/eth/v1/beacon/light_client/bootstrap/0x{}", root_hex);
let client = reqwest::Client::new();
let res = client
.get(req)
.send()
.await
.map_err(|e| RpcError::new("bootstrap", e))?
.json::<BootstrapResponse>()
.await
.map_err(|e| RpcError::new("bootstrap", e))?;
let res = self
.request::<BootstrapResponse>(&path, "bootstrap")
.await?;
Ok(res.data)
}
async fn get_updates(&self, period: u64, count: u8) -> Result<Vec<Update>> {
let count = cmp::min(count, MAX_REQUEST_LIGHT_CLIENT_UPDATES);
let req = format!(
"{}/eth/v1/beacon/light_client/updates?start_period={}&count={}",
self.rpc, period, count
let path = format!(
"/eth/v1/beacon/light_client/updates?start_period={}&count={}",
period, count
);
let client = reqwest::Client::new();
let res = client
.get(req)
.send()
.await
.map_err(|e| RpcError::new("updates", e))?
.json::<UpdateResponse>()
.await
.map_err(|e| RpcError::new("updates", e))?;
let res = self.request::<UpdateResponse>(&path, "updates").await?;
Ok(res.iter().map(|d| d.data.clone()).collect())
}
async fn get_finality_update(&self) -> Result<FinalityUpdate> {
let req = format!("{}/eth/v1/beacon/light_client/finality_update", self.rpc);
let res = reqwest::get(req)
.await
.map_err(|e| RpcError::new("finality_update", e))?
.json::<FinalityUpdateResponse>()
.await
.map_err(|e| RpcError::new("finality_update", e))?;
let path = format!("/eth/v1/beacon/light_client/finality_update");
let res = self
.request::<FinalityUpdateResponse>(&path, "finality_update")
.await?;
Ok(res.data)
}
async fn get_optimistic_update(&self) -> Result<OptimisticUpdate> {
let req = format!("{}/eth/v1/beacon/light_client/optimistic_update", self.rpc);
let res = reqwest::get(req)
.await
.map_err(|e| RpcError::new("optimistic_update", e))?
.json::<OptimisticUpdateResponse>()
.await
.map_err(|e| RpcError::new("optimistic_update", e))?;
let path = format!("/eth/v1/beacon/light_client/optimistic_update");
let res = self
.request::<OptimisticUpdateResponse>(&path, "optimistic_update")
.await?;
Ok(res.data)
}
async fn get_block(&self, slot: u64) -> Result<BeaconBlock> {
let req = format!("{}/eth/v2/beacon/blocks/{}", self.rpc, slot);
let res = reqwest::get(req)
.await
.map_err(|e| RpcError::new("blocks", e))?
.json::<BeaconBlockResponse>()
.await
.map_err(|e| RpcError::new("blocks", e))?;
let path = format!("/eth/v2/beacon/blocks/{}", slot);
let res = self.request::<BeaconBlockResponse>(&path, "blocks").await?;
Ok(res.data.message)
}
async fn chain_id(&self) -> Result<u64> {
let req = format!("{}/eth/v1/config/spec", self.rpc);
let res = reqwest::get(req)
.await
.map_err(|e| RpcError::new("spec", e))?
.json::<SpecResponse>()
.await
.map_err(|e| RpcError::new("spec", e))?;
let path = format!("/eth/v1/config/spec");
let res = self.request::<SpecResponse>(&path, "blocks").await?;
Ok(res.data.chain_id)
}
@ -152,3 +165,23 @@ struct Spec {
#[serde(rename = "DEPOSIT_NETWORK_ID", deserialize_with = "u64_deserialize")]
chain_id: u64,
}
impl NimbusRpc {
async fn request<T>(&self, path: &str, error_type: &str) -> Result<T, RpcError>
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));
let js_future = JsFuture::from(consensus_rpc_handler(JsValue::from(js_params)));
let result = js_future.await?;
let json = result.as_string().unwrap();
let response: T = serde_json::from_str(&json)
.map_err(|e| RpcError::new(e.to_string(), String::from(error_type)))?;
Ok(response)
}
}

View File

@ -11,7 +11,7 @@ serde_json = "1.0.85"
hex = "0.4.3"
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" }
revm = { version = "2.3", default-features = false, features = ["std", "k256", "with-serde"] }
ethers = "1.0.0"
ethers = { version = "1.0.2", path = "../../helios-workspace/ethers-rs"}
bytes = "1.2.1"
futures = "0.3.23"
toml = "0.5.9"
@ -22,6 +22,10 @@ thiserror = "1.0.37"
common = { path = "../common" }
consensus = { path = "../consensus" }
wasm-bindgen = "0.2.84"
js-sys = "0.3.61"
wasm-bindgen-futures = "0.4.34"
web-sys = {version="0.3.61", features=["console"]}
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
openssl = { version = "0.10", features = ["vendored"] }

View File

@ -31,8 +31,8 @@ pub struct ExecutionClient<R: ExecutionRpc> {
}
impl<R: ExecutionRpc> ExecutionClient<R> {
pub fn new(rpc: &str) -> Result<Self> {
let rpc: R = ExecutionRpc::new(rpc)?;
pub fn new(_rpc: &str) -> Result<Self> {
let rpc: R = ExecutionRpc::new()?;
Ok(ExecutionClient { rpc })
}

View File

@ -1,8 +1,11 @@
use std::str::FromStr;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use async_trait::async_trait;
use ethers::prelude::{Address, Http};
use ethers::providers::{HttpRateLimitRetryPolicy, Middleware, Provider, RetryClient};
use ethers::prelude::Address;
use ethers::providers::{
HttpClientError, JsonRpcClient, Middleware, Provider, ProviderError, Response,
};
use ethers::types::transaction::eip2718::TypedTransaction;
use ethers::types::transaction::eip2930::AccessList;
use ethers::types::{
@ -10,37 +13,105 @@ use ethers::types::{
Filter, Log, Transaction, TransactionReceipt, H256, U256,
};
use eyre::Result;
use serde::de::DeserializeOwned;
use serde::Serialize;
use serde_json::to_value;
use wasm_bindgen::JsValue;
use crate::types::CallOpts;
use common::errors::RpcError;
use super::ExecutionRpc;
use js_sys::Promise;
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen_futures::JsFuture;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = self)]
fn execution_rpc_handler(data: JsValue) -> Promise;
}
pub struct HttpRpc {
url: String,
provider: Provider<RetryClient<Http>>,
provider: Provider<LumeProvider>,
}
impl Clone for HttpRpc {
fn clone(&self) -> Self {
Self::new(&self.url).unwrap()
Self::new().unwrap()
}
}
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl ExecutionRpc for HttpRpc {
fn new(rpc: &str) -> Result<Self> {
let http = Http::from_str(rpc)?;
let mut client = RetryClient::new(http, Box::new(HttpRateLimitRetryPolicy), 100, 50);
client.set_compute_units(300);
#[derive(Clone, Debug)]
pub struct LumeProvider {}
impl LumeProvider {
pub fn new() -> Self {
LumeProvider {}
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl JsonRpcClient for LumeProvider {
type Error = HttpClientError;
async fn request<T, R>(&self, method: &str, params: T) -> Result<R, Self::Error>
where
T: Debug + Serialize + Send + Sync,
R: DeserializeOwned,
{
let request = js_sys::Map::new();
request.set(&JsValue::from_str("method"), &JsValue::from_str(method));
if let Some(params) = Option::from(params) {
let js_params = to_value(&params).unwrap();
let json_str = serde_json::to_string(&js_params).unwrap();
request.set(&JsValue::from_str("params"), &JsValue::from_str(&json_str));
} else {
request.set(&JsValue::from_str("params"), &JsValue::null());
}
let js_future = JsFuture::from(execution_rpc_handler(JsValue::from(request)));
let result = js_future.await?;
let json = result.as_string().expect("response is not a string");
let body = json.as_bytes();
let raw = match serde_json::from_slice(&body) {
Ok(Response::Success { result, .. }) => result.to_owned(),
Ok(Response::Error { error, .. }) => return Err(error.into()),
Ok(_) => {
panic!(
"{} {}",
"unexpected notification over HTTP transport",
String::from_utf8_lossy(&body).to_string()
);
}
Err(err) => {
panic!(
"{} {}",
err.to_string(),
String::from_utf8_lossy(&body).to_string()
);
}
};
let res = serde_json::from_str(raw.get()).map_err(|err| HttpClientError::SerdeJson {
err,
text: raw.to_string(),
})?;
Ok(res)
}
}
#[async_trait(?Send)]
impl ExecutionRpc for HttpRpc {
fn new() -> Result<Self> {
let client = LumeProvider::new();
let provider = Provider::new(client);
Ok(HttpRpc {
url: rpc.to_string(),
provider,
})
Ok(HttpRpc { provider })
}
async fn get_proof(

View File

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

View File

@ -8,12 +8,10 @@ use eyre::Result;
use crate::types::CallOpts;
pub mod http_rpc;
pub mod mock_rpc;
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
pub trait ExecutionRpc: Send + Clone + Sync + 'static {
fn new(rpc: &str) -> Result<Self>
fn new() -> Result<Self>
where
Self: Sized;

View File

@ -13,20 +13,19 @@ wasm-bindgen = "0.2.84"
wasm-bindgen-futures = "0.4.33"
serde-wasm-bindgen = "0.4.5"
console_error_panic_hook = "0.1.7"
futures = "0.3"
serde = { version = "1.0.85", features = ["derive"] }
ethers = "1.0.0"
ethers = { version = "1.0.2", features = [ "abigen" ], path = "../../helios-workspace/ethers-rs" }
hex = "0.4.3"
serde = { version = "1.0.143", features = ["derive"] }
serde_json = "1.0.85"
client = { path = "../client" }
common = { path = "../common" }
consensus = { path = "../consensus" }
execution = { path = "../execution" }
config = { path = "../config" }
tracing-wasm = "0.2.1"
[dependencies.web-sys]
version = "0.3"
features = [
"console",
]
version = "0.3.61"

View File

@ -10,6 +10,7 @@ use wasm_bindgen::prelude::*;
use client::database::ConfigDB;
use config::{networks, Config};
use tracing_wasm;
#[allow(unused_macros)]
macro_rules! log {
@ -27,19 +28,11 @@ pub struct Client {
#[wasm_bindgen]
impl Client {
#[wasm_bindgen(constructor)]
pub fn new(
execution_rpc: String,
consensus_rpc: Option<String>,
network: String,
checkpoint: Option<String>,
) -> Self {
pub fn new(checkpoint: Option<String>) -> Self {
console_error_panic_hook::set_once();
tracing_wasm::set_as_global_default();
let base = match network.as_str() {
"mainnet" => networks::mainnet(),
"goerli" => networks::goerli(),
_ => panic!("invalid network"),
};
let base = networks::mainnet();
let chain_id = base.chain.chain_id;
@ -51,11 +44,7 @@ impl Client {
.unwrap_or(base.default_checkpoint),
);
let consensus_rpc = consensus_rpc.unwrap_or(base.consensus_rpc.unwrap());
let config = Config {
execution_rpc,
consensus_rpc,
checkpoint,
chain: base.chain,