feat: wasm support (#182)

* basic consensus setup

* basic execution setup

* patch for wasm

* basic wasm client

* proxy cors for testing

* migrate to webpack

* use typescript

* track chain head

* rename to helios-ts

* better build instructions

* add getCode

* builds everywhere

* add wasm-pack to dependencies

* compile for both wasm and non-wasm

* fix deps

* fix deps

* remove ds store

* add blocktags

* add getNonce

* use BTreeMap to store payloads

* add getTransaction

* switch to proper ethers provider

* post merge fixes

* compile client to wasm

* fix tests

* fmt

* use milagro for bls

* handle node advance in rust

* faster bls deserialization

* clippy

* add ConfigDB

* remove ts bindings

* fix gitignore

* remove ts workspace member

* remove unused mut

* uncomment old deletions

* bump to 0.2.0
This commit is contained in:
Noah Citron 2023-01-30 21:38:46 -05:00 committed by GitHub
parent 604b325983
commit 72267b4563
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 499 additions and 566 deletions

4
.gitignore vendored
View File

@ -1,3 +1,3 @@
/target
.DS_Store
target
*.env

683
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
[package]
name = "helios"
version = "0.1.3"
version = "0.2.0"
edition = "2021"
autobenches = false
@ -21,11 +21,11 @@ common = { path = "./common" }
consensus = { path = "./consensus" }
execution = { path = "./execution" }
[dev-dependencies]
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
tokio = { version = "1", features = ["full"] }
eyre = "0.6.8"
home = "0.5.4"
ethers = "1.0.2"
ethers = "1.0.0"
env_logger = "0.9.0"
log = "0.4.17"
tracing-test = "0.2.3"
@ -34,6 +34,9 @@ plotters = "0.3.3"
tempfile = "3.3.0"
hex = "0.4.3"
[patch.crates-io]
ethers = { git = "https://github.com/gakonst/ethers-rs", rev = "c17c0c3c956f12d205a5ede3176599d8a30ca739" }
[profile.release]
strip = true
opt-level = "z"

View File

@ -2,7 +2,7 @@ cargo-features = ["different-binary-name"]
[package]
name = "cli"
version = "0.1.3"
version = "0.2.0"
edition = "2021"
[[bin]]

View File

@ -1,5 +1,4 @@
use std::{
fs,
path::PathBuf,
process::exit,
str::FromStr,
@ -104,10 +103,10 @@ struct Cli {
impl Cli {
fn as_cli_config(&self) -> CliConfig {
let checkpoint = match &self.checkpoint {
Some(checkpoint) => Some(hex_str_to_bytes(checkpoint).expect("invalid checkpoint")),
None => self.get_cached_checkpoint(),
};
let checkpoint = self
.checkpoint
.as_ref()
.map(|c| hex_str_to_bytes(c).expect("invalid checkpoint"));
CliConfig {
checkpoint,
@ -121,21 +120,6 @@ impl Cli {
}
}
fn get_cached_checkpoint(&self) -> Option<Vec<u8>> {
let data_dir = self.get_data_dir();
let checkpoint_file = data_dir.join("checkpoint");
if checkpoint_file.exists() {
let checkpoint_res = fs::read(checkpoint_file);
match checkpoint_res {
Ok(checkpoint) => Some(checkpoint),
Err(_) => None,
}
} else {
None
}
}
fn get_data_dir(&self) -> PathBuf {
if let Some(dir) = &self.data_dir {
PathBuf::from_str(dir).expect("cannot find data dir")

View File

@ -1,16 +1,14 @@
[package]
name = "client"
version = "0.1.3"
version = "0.2.0"
edition = "2021"
[dependencies]
tokio = { version = "1", features = ["full"] }
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 = "cb08f18ca919cc1b685b861d0fa9e2daabe89737" }
ethers = "1.0.2"
jsonrpsee = { version = "0.15.1", features = ["full"] }
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" }
ethers = "1.0.0"
futures = "0.3.23"
log = "0.4.17"
thiserror = "1.0.37"
@ -19,3 +17,13 @@ common = { path = "../common" }
consensus = { path = "../consensus" }
execution = { path = "../execution" }
config = { path = "../config" }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
jsonrpsee = { version = "0.15.1", features = ["full"] }
tokio = { version = "1", features = ["full"] }
[target.'cfg(target_arch = "wasm32")'.dependencies]
gloo-timers = "0.2.6"
wasm-bindgen-futures = "0.4.33"
tokio = { version = "1", features = ["sync"] }

View File

@ -1,4 +1,3 @@
use std::path::PathBuf;
use std::sync::Arc;
use config::networks::Network;
@ -12,13 +11,25 @@ use config::{CheckpointFallback, Config};
use consensus::{types::Header, ConsensusClient};
use execution::types::{CallOpts, ExecutionBlock};
use log::{error, info, warn};
use tokio::spawn;
use tokio::sync::RwLock;
#[cfg(not(target_arch = "wasm32"))]
use std::path::PathBuf;
#[cfg(not(target_arch = "wasm32"))]
use tokio::spawn;
#[cfg(not(target_arch = "wasm32"))]
use tokio::time::sleep;
use crate::database::{Database, FileDB};
#[cfg(target_arch = "wasm32")]
use gloo_timers::callback::Interval;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_futures::spawn_local;
use crate::database::Database;
use crate::errors::NodeError;
use crate::node::Node;
#[cfg(not(target_arch = "wasm32"))]
use crate::rpc::Rpc;
#[derive(Default)]
@ -27,7 +38,9 @@ pub struct ClientBuilder {
consensus_rpc: Option<String>,
execution_rpc: Option<String>,
checkpoint: Option<Vec<u8>>,
#[cfg(not(target_arch = "wasm32"))]
rpc_port: Option<u16>,
#[cfg(not(target_arch = "wasm32"))]
data_dir: Option<PathBuf>,
config: Option<Config>,
fallback: Option<String>,
@ -62,11 +75,13 @@ impl ClientBuilder {
self
}
#[cfg(not(target_arch = "wasm32"))]
pub fn rpc_port(mut self, port: u16) -> Self {
self.rpc_port = Some(port);
self
}
#[cfg(not(target_arch = "wasm32"))]
pub fn data_dir(mut self, data_dir: PathBuf) -> Self {
self.data_dir = Some(data_dir);
self
@ -92,7 +107,7 @@ impl ClientBuilder {
self
}
pub fn build(self) -> Result<Client<FileDB>> {
pub fn build<DB: Database>(self) -> Result<Client<DB>> {
let base_config = if let Some(network) = self.network {
network.to_base_config()
} else {
@ -127,6 +142,7 @@ impl ClientBuilder {
base_config.checkpoint
};
#[cfg(not(target_arch = "wasm32"))]
let rpc_port = if self.rpc_port.is_some() {
self.rpc_port
} else if let Some(config) = &self.config {
@ -135,6 +151,7 @@ impl ClientBuilder {
None
};
#[cfg(not(target_arch = "wasm32"))]
let data_dir = if self.data_dir.is_some() {
self.data_dir
} else if let Some(config) = &self.config {
@ -167,8 +184,14 @@ impl ClientBuilder {
consensus_rpc,
execution_rpc,
checkpoint,
#[cfg(not(target_arch = "wasm32"))]
rpc_port,
#[cfg(target_arch = "wasm32")]
rpc_port: None,
#[cfg(not(target_arch = "wasm32"))]
data_dir,
#[cfg(target_arch = "wasm32")]
data_dir: None,
chain: base_config.chain,
forks: base_config.forks,
max_checkpoint_age: base_config.max_checkpoint_age,
@ -183,35 +206,38 @@ impl ClientBuilder {
pub struct Client<DB: Database> {
node: Arc<RwLock<Node>>,
#[cfg(not(target_arch = "wasm32"))]
rpc: Option<Rpc>,
db: Option<DB>,
db: DB,
fallback: Option<String>,
load_external_fallback: bool,
}
impl Client<FileDB> {
fn new(config: Config) -> Result<Self> {
impl<DB: Database> Client<DB> {
fn new(mut config: Config) -> Result<Self> {
let db = DB::new(&config)?;
let checkpoint = db.load_checkpoint()?;
config.checkpoint = checkpoint;
let config = Arc::new(config);
let node = Node::new(config.clone())?;
let node = Arc::new(RwLock::new(node));
#[cfg(not(target_arch = "wasm32"))]
let rpc = config.rpc_port.map(|port| Rpc::new(node.clone(), port));
let data_dir = config.data_dir.clone();
let db = data_dir.map(FileDB::new);
Ok(Client {
node,
#[cfg(not(target_arch = "wasm32"))]
rpc,
db,
fallback: config.fallback.clone(),
load_external_fallback: config.load_external_fallback,
})
}
}
impl<DB: Database> Client<DB> {
pub async fn start(&mut self) -> Result<()> {
#[cfg(not(target_arch = "wasm32"))]
if let Some(rpc) = &mut self.rpc {
rpc.start().await?;
}
@ -241,6 +267,13 @@ impl<DB: Database> Client<DB> {
}
}
self.start_advance_thread();
Ok(())
}
#[cfg(not(target_arch = "wasm32"))]
fn start_advance_thread(&self) {
let node = self.node.clone();
spawn(async move {
loop {
@ -250,11 +283,25 @@ impl<DB: Database> Client<DB> {
}
let next_update = node.read().await.duration_until_next_update();
sleep(next_update).await;
}
});
}
Ok(())
#[cfg(target_arch = "wasm32")]
fn start_advance_thread(&self) {
let node = self.node.clone();
Interval::new(12000, move || {
let node = node.clone();
spawn_local(async move {
let res = node.write().await.advance().await;
if let Err(err) = res {
warn!("consensus error: {}", err);
}
});
})
.forget();
}
async fn boot_from_fallback(&self) -> eyre::Result<()> {
@ -335,8 +382,8 @@ impl<DB: Database> Client<DB> {
};
info!("saving last checkpoint hash");
let res = self.db.as_ref().map(|db| db.save_checkpoint(checkpoint));
if res.is_some() && res.unwrap().is_err() {
let res = self.db.save_checkpoint(checkpoint);
if res.is_err() {
warn!("checkpoint save failed");
}
}

View File

@ -1,27 +1,40 @@
#[cfg(not(target_arch = "wasm32"))]
use std::{
fs,
io::{Read, Write},
path::PathBuf,
};
use config::Config;
use eyre::Result;
pub trait Database {
fn new(config: &Config) -> Result<Self>
where
Self: Sized;
fn save_checkpoint(&self, checkpoint: Vec<u8>) -> Result<()>;
fn load_checkpoint(&self) -> Result<Vec<u8>>;
}
#[cfg(not(target_arch = "wasm32"))]
pub struct FileDB {
data_dir: PathBuf,
default_checkpoint: Vec<u8>,
}
impl FileDB {
pub fn new(data_dir: PathBuf) -> Self {
FileDB { data_dir }
}
}
#[cfg(not(target_arch = "wasm32"))]
impl Database for FileDB {
fn new(config: &Config) -> Result<Self> {
if let Some(data_dir) = &config.data_dir {
return Ok(FileDB {
data_dir: data_dir.to_path_buf(),
default_checkpoint: config.checkpoint.clone(),
});
}
eyre::bail!("data dir not in config")
}
fn save_checkpoint(&self, checkpoint: Vec<u8>) -> Result<()> {
fs::create_dir_all(&self.data_dir)?;
@ -44,6 +57,30 @@ impl Database for FileDB {
let mut buf = Vec::new();
f.read_to_end(&mut buf)?;
Ok(buf)
if buf.len() == 32 {
Ok(buf)
} else {
Ok(self.default_checkpoint.clone())
}
}
}
pub struct ConfigDB {
checkpoint: Vec<u8>,
}
impl Database for ConfigDB {
fn new(config: &Config) -> Result<Self> {
Ok(Self {
checkpoint: config.checkpoint.clone(),
})
}
fn load_checkpoint(&self) -> Result<Vec<u8>> {
Ok(self.checkpoint.clone())
}
fn save_checkpoint(&self, _checkpoint: Vec<u8>) -> Result<()> {
Ok(())
}
}

View File

@ -37,6 +37,7 @@ pub enum NodeError {
BlockNotFoundError(#[from] BlockNotFoundError),
}
#[cfg(not(target_arch = "wasm32"))]
impl NodeError {
pub fn to_json_rpsee_error(self) -> jsonrpsee::core::Error {
match self {

View File

@ -3,6 +3,8 @@ pub use crate::client::*;
pub mod database;
pub mod errors;
#[cfg(not(target_arch = "wasm32"))]
pub mod rpc;
mod node;
pub mod node;

View File

@ -1,12 +1,12 @@
[package]
name = "common"
version = "0.1.3"
version = "0.2.0"
edition = "2021"
[dependencies]
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 = "cb08f18ca919cc1b685b861d0fa9e2daabe89737" }
ethers = "1.0.2"
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" }
ethers = "1.0.0"
thiserror = "1.0.37"

View File

@ -1,24 +1,24 @@
[package]
name = "config"
version = "0.1.3"
version = "0.2.0"
edition = "2021"
[dependencies]
tokio = { version = "1", features = ["full"] }
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 = "cb08f18ca919cc1b685b861d0fa9e2daabe89737" }
ethers = "1.0.2"
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" }
ethers = "1.0.0"
figment = { version = "0.10.7", features = ["toml", "env"] }
thiserror = "1.0.37"
log = "0.4.17"
common = { path = "../common" }
reqwest = "0.11.13"
serde_yaml = "0.9.14"
strum = "0.24.1"
futures = "0.3.25"
common = { path = "../common" }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tokio = { version = "1", features = ["full"] }

View File

@ -136,26 +136,25 @@ impl CheckpointFallback {
// Iterate over all mainnet checkpoint sync services and get the latest checkpoint slot for each.
let tasks: Vec<_> = services
.iter()
.map(|service| {
.map(|service| async move {
let service = service.clone();
tokio::spawn(async move {
match Self::query_service(&service.endpoint).await {
Some(raw) => {
if raw.data.slots.is_empty() {
return Err(eyre::eyre!("no slots"));
}
Ok(raw.data.slots[0].clone())
match Self::query_service(&service.endpoint).await {
Some(raw) => {
if raw.data.slots.is_empty() {
return Err(eyre::eyre!("no slots"));
}
None => Err(eyre::eyre!("failed to query service")),
Ok(raw.data.slots[0].clone())
}
})
None => Err(eyre::eyre!("failed to query service")),
}
})
.collect();
let slots = futures::future::join_all(tasks)
.await
.iter()
.filter_map(|slot| match &slot {
Ok(Ok(s)) => Some(s.clone()),
Ok(s) => Some(s.clone()),
_ => None,
})
.collect::<Vec<_>>();

View File

@ -36,7 +36,7 @@ impl Network {
pub fn mainnet() -> BaseConfig {
BaseConfig {
checkpoint: hex_str_to_bytes(
"0x428ce0b5f5bbed1fc2b3feb5d4152ae0fe98a80b1bfa8de36681868e81e9222a",
"0x766647f3c4e1fc91c0db9a9374032ae038778411fbff222974e11f2e3ce7dadf",
)
.unwrap(),
rpc_port: 8545,

View File

@ -1,27 +1,31 @@
[package]
name = "consensus"
version = "0.1.3"
version = "0.2.0"
edition = "2021"
[dependencies]
tokio = { version = "1", features = ["full"] }
eyre = "0.6.8"
serde = { version = "1.0.143", features = ["derive"] }
serde_json = "1.0.85"
hex = "0.4.3"
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "cb08f18ca919cc1b685b861d0fa9e2daabe89737" }
blst = "0.3.10"
ethers = "1.0.2"
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "d09f55b4f8554491e3431e01af1c32347a8781cd" }
milagro_bls = { git = "https://github.com/Snowfork/milagro_bls" }
ethers = "1.0.0"
bytes = "1.2.1"
toml = "0.5.9"
async-trait = "0.1.57"
log = "0.4.17"
chrono = "0.4.22"
thiserror = "1.0.37"
openssl = { version = "0.10", features = ["vendored"] }
reqwest = { version = "0.11.12", features = ["json"] }
reqwest-middleware = "0.1.6"
reqwest-retry = "0.1.5"
reqwest = { version = "0.11.13", features = ["json"] }
common = { path = "../common" }
config = { path = "../config" }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
openssl = { version = "0.10", features = ["vendored"] }
tokio = { version = "1", features = ["full"] }
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-timer = "0.2.5"

View File

@ -1,13 +1,12 @@
use std::cmp;
use std::sync::Arc;
use std::time::UNIX_EPOCH;
use blst::min_pk::PublicKey;
use chrono::Duration;
use eyre::eyre;
use eyre::Result;
use log::warn;
use log::{debug, info};
use milagro_bls::PublicKey;
use ssz_rs::prelude::*;
use common::types::*;
@ -21,9 +20,20 @@ use super::rpc::ConsensusRpc;
use super::types::*;
use super::utils::*;
#[cfg(not(target_arch = "wasm32"))]
use std::time::SystemTime;
#[cfg(not(target_arch = "wasm32"))]
use std::time::UNIX_EPOCH;
#[cfg(target_arch = "wasm32")]
use wasm_timer::SystemTime;
#[cfg(target_arch = "wasm32")]
use wasm_timer::UNIX_EPOCH;
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/sync-protocol.md
// does not implement force updates
#[derive(Debug)]
pub struct ConsensusClient<R: ConsensusRpc> {
rpc: R,
store: LightClientStore,
@ -480,18 +490,13 @@ impl<R: ConsensusRpc> ConsensusClient<R> {
fn age(&self, slot: u64) -> Duration {
let expected_time = self.slot_timestamp(slot);
let now = std::time::SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap();
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
let delay = now - std::time::Duration::from_secs(expected_time);
chrono::Duration::from_std(delay).unwrap()
}
pub fn expected_current_slot(&self) -> u64 {
let now = std::time::SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap();
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
let genesis_time = self.config.chain.genesis_time;
let since_genesis = now - std::time::Duration::from_secs(genesis_time);
@ -509,7 +514,7 @@ impl<R: ConsensusRpc> ConsensusClient<R> {
let next_slot = current_slot + 1;
let next_slot_timestamp = self.slot_timestamp(next_slot);
let now = std::time::SystemTime::now()
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
@ -540,7 +545,7 @@ fn get_participating_keys(
bitfield.iter().enumerate().for_each(|(i, bit)| {
if bit == true {
let pk = &committee.pubkeys[i];
let pk = PublicKey::from_bytes(pk).unwrap();
let pk = PublicKey::from_bytes_unchecked(pk).unwrap();
pks.push(pk);
}
});

View File

@ -8,7 +8,8 @@ pub struct MockRpc {
testdata: PathBuf,
}
#[async_trait]
#[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 {

View File

@ -7,7 +7,8 @@ use eyre::Result;
use crate::types::{BeaconBlock, Bootstrap, FinalityUpdate, OptimisticUpdate, Update};
// implements https://github.com/ethereum/beacon-APIs/tree/master/apis/beacon/light_client
#[async_trait]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
pub trait ConsensusRpc {
fn new(path: &str) -> Self;
async fn get_bootstrap(&self, block_root: &'_ [u8]) -> Result<Bootstrap>;

View File

@ -1,7 +1,5 @@
use async_trait::async_trait;
use eyre::Result;
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware};
use std::cmp;
use super::ConsensusRpc;
@ -9,25 +7,17 @@ use crate::constants::MAX_REQUEST_LIGHT_CLIENT_UPDATES;
use crate::types::*;
use common::errors::RpcError;
#[derive(Debug)]
pub struct NimbusRpc {
rpc: String,
client: ClientWithMiddleware,
}
#[async_trait]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl ConsensusRpc for NimbusRpc {
fn new(rpc: &str) -> Self {
let retry_policy = ExponentialBackoff::builder()
.backoff_exponent(1)
.build_with_max_retries(3);
let client = ClientBuilder::new(reqwest::Client::new())
.with(RetryTransientMiddleware::new_with_policy(retry_policy))
.build();
NimbusRpc {
rpc: rpc.to_string(),
client,
}
}
@ -38,8 +28,8 @@ impl ConsensusRpc for NimbusRpc {
self.rpc, root_hex
);
let res = self
.client
let client = reqwest::Client::new();
let res = client
.get(req)
.send()
.await
@ -58,8 +48,8 @@ impl ConsensusRpc for NimbusRpc {
self.rpc, period, count
);
let res = self
.client
let client = reqwest::Client::new();
let res = client
.get(req)
.send()
.await
@ -73,10 +63,7 @@ impl ConsensusRpc for NimbusRpc {
async fn get_finality_update(&self) -> Result<FinalityUpdate> {
let req = format!("{}/eth/v1/beacon/light_client/finality_update", self.rpc);
let res = self
.client
.get(req)
.send()
let res = reqwest::get(req)
.await
.map_err(|e| RpcError::new("finality_update", e))?
.json::<FinalityUpdateResponse>()
@ -88,10 +75,7 @@ impl ConsensusRpc for NimbusRpc {
async fn get_optimistic_update(&self) -> Result<OptimisticUpdate> {
let req = format!("{}/eth/v1/beacon/light_client/optimistic_update", self.rpc);
let res = self
.client
.get(req)
.send()
let res = reqwest::get(req)
.await
.map_err(|e| RpcError::new("optimistic_update", e))?
.json::<OptimisticUpdateResponse>()
@ -103,10 +87,7 @@ impl ConsensusRpc for NimbusRpc {
async fn get_block(&self, slot: u64) -> Result<BeaconBlock> {
let req = format!("{}/eth/v2/beacon/blocks/{}", self.rpc, slot);
let res = self
.client
.get(req)
.send()
let res = reqwest::get(req)
.await
.map_err(|e| RpcError::new("blocks", e))?
.json::<BeaconBlockResponse>()
@ -118,10 +99,7 @@ impl ConsensusRpc for NimbusRpc {
async fn chain_id(&self) -> Result<u64> {
let req = format!("{}/eth/v1/config/spec", self.rpc);
let res = self
.client
.get(req)
.send()
let res = reqwest::get(req)
.await
.map_err(|e| RpcError::new("spec", e))?
.json::<SpecResponse>()

View File

@ -1,9 +1,6 @@
use blst::{
min_pk::{PublicKey, Signature},
BLST_ERROR,
};
use common::{types::Bytes32, utils::bytes32_to_node};
use eyre::Result;
use milagro_bls::{AggregateSignature, PublicKey};
use ssz_rs::prelude::*;
use crate::types::{Header, SignatureBytes};
@ -14,10 +11,9 @@ pub fn calc_sync_period(slot: u64) -> u64 {
}
pub fn is_aggregate_valid(sig_bytes: &SignatureBytes, msg: &[u8], pks: &[&PublicKey]) -> bool {
let dst: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_";
let sig_res = Signature::from_bytes(sig_bytes);
let sig_res = AggregateSignature::from_bytes(sig_bytes);
match sig_res {
Ok(sig) => sig.fast_aggregate_verify(true, msg, dst, pks) == BLST_ERROR::BLST_SUCCESS,
Ok(sig) => sig.fast_aggregate_verify(msg, pks),
Err(_) => false,
}
}

View File

@ -3,7 +3,7 @@ use std::str::FromStr;
use env_logger::Env;
use ethers::{types::Address, utils};
use eyre::Result;
use helios::{client::ClientBuilder, config::networks::Network, types::BlockTag};
use helios::{config::networks::Network, prelude::*};
#[tokio::main]
async fn main() -> Result<()> {
@ -15,12 +15,13 @@ async fn main() -> Result<()> {
let consensus_rpc = "https://www.lightclientdata.org";
log::info!("Using consensus RPC URL: {}", consensus_rpc);
let mut client = ClientBuilder::new()
let mut client: Client<FileDB> = ClientBuilder::new()
.network(Network::MAINNET)
.consensus_rpc(consensus_rpc)
.execution_rpc(untrusted_rpc_url)
.load_external_fallback()
.build()?;
log::info!(
"Built client on network \"{}\" with external checkpoint fallbacks",
Network::MAINNET

View File

@ -35,7 +35,7 @@ async fn main() -> Result<()> {
builder = builder.load_external_fallback();
// Build the client
let _client = builder.build().unwrap();
let _client: Client<FileDB> = builder.build().unwrap();
println!("Constructed client!");
Ok(())

View File

@ -1,18 +1,17 @@
[package]
name = "execution"
version = "0.1.3"
version = "0.2.0"
edition = "2021"
[dependencies]
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }
eyre = "0.6.8"
serde = { version = "1.0.143", features = ["derive"] }
serde_json = "1.0.85"
hex = "0.4.3"
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs", rev = "cb08f18ca919cc1b685b861d0fa9e2daabe89737" }
ethers = "1.0.2"
revm = "2.1.0"
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"
bytes = "1.2.1"
futures = "0.3.23"
toml = "0.5.9"
@ -20,7 +19,10 @@ triehash-ethereum = { git = "https://github.com/openethereum/parity-ethereum", r
async-trait = "0.1.57"
log = "0.4.17"
thiserror = "1.0.37"
openssl = { version = "0.10", features = ["vendored"] }
common = { path = "../common" }
consensus = { path = "../consensus" }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
openssl = { version = "0.10", features = ["vendored"] }
tokio = { version = "1", features = ["full"] }

View File

@ -9,14 +9,13 @@ use bytes::Bytes;
use common::{errors::BlockNotFoundError, types::BlockTag};
use ethers::{
abi::ethereum_types::BigEndianHash,
prelude::{Address, H160, H256, U256},
types::transaction::eip2930::AccessListItem,
types::{Address, H160, H256, U256},
};
use eyre::{Report, Result};
use futures::future::join_all;
use futures::{executor::block_on, future::join_all};
use log::trace;
use revm::{AccountInfo, Bytecode, Database, Env, TransactOut, TransactTo, EVM};
use tokio::runtime::Runtime;
use consensus::types::ExecutionPayload;
@ -225,8 +224,9 @@ impl<'a, R: ExecutionRpc> ProofDB<'a, R> {
let handle = thread::spawn(move || {
let account_fut = execution.get_account(&address, Some(&slots), &payload);
let runtime = Runtime::new()?;
runtime.block_on(account_fut)
// let runtime = Runtime::new()?;
// runtime.block_on(account_fut)
block_on(account_fut)
});
handle.join().unwrap()

View File

@ -27,13 +27,16 @@ impl Clone for HttpRpc {
}
}
#[async_trait]
#[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);
let provider = Provider::new(client);
Ok(HttpRpc {
url: rpc.to_string(),
provider,

View File

@ -17,7 +17,8 @@ pub struct MockRpc {
path: PathBuf,
}
#[async_trait]
#[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);

View File

@ -10,7 +10,8 @@ use crate::types::CallOpts;
pub mod http_rpc;
pub mod mock_rpc;
#[async_trait]
#[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>
where