feat(examples): Introduces working examples (#126)

* ⚙️ examples and more cleanup

* ⚙️ examples
This commit is contained in:
refcell.eth 2022-12-02 15:41:50 -08:00 committed by GitHub
parent e8642fe521
commit 7e3fe40613
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 210 additions and 3 deletions

12
Cargo.lock generated
View File

@ -1652,6 +1652,9 @@ dependencies = [
"config", "config",
"consensus", "consensus",
"execution", "execution",
"eyre",
"home",
"tokio",
] ]
[[package]] [[package]]
@ -1678,6 +1681,15 @@ dependencies = [
"digest 0.10.5", "digest 0.10.5",
] ]
[[package]]
name = "home"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "747309b4b440c06d57b0b25f2aee03ee9b5e5397d288c60e21fc709bb98a7408"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "http" name = "http"
version = "0.2.8" version = "0.2.8"

View File

@ -24,3 +24,20 @@ execution = { path = "./execution" }
[patch.crates-io] [patch.crates-io]
ethers = { git = "https://github.com/ncitron/ethers-rs", branch = "fix-retry" } ethers = { git = "https://github.com/ncitron/ethers-rs", branch = "fix-retry" }
[dev-dependencies]
tokio = { version = "1", features = ["full"] }
eyre = "0.6.8"
home = "0.5.4"
[[example]]
name = "checkpoints"
path = "examples/checkpoints.rs"
[[example]]
name = "client"
path = "examples/client.rs"
[[example]]
name = "config"
path = "examples/config.rs"

View File

@ -8,6 +8,7 @@ Helios converts an untrusted centralized RPC endpoint into a safe unmanipulable
The entire size of Helios's binary is 13Mb and should be easy to compile into WebAssembly. This makes it a perfect target to embed directly inside wallets and dapps. The entire size of Helios's binary is 13Mb and should be easy to compile into WebAssembly. This makes it a perfect target to embed directly inside wallets and dapps.
## Installing ## Installing
First install `heliosup`, Helios's installer: First install `heliosup`, Helios's installer:
@ -18,6 +19,7 @@ curl https://raw.githubusercontent.com/a16z/helios/master/heliosup/install | bas
To install Helios, run `heliosup`. To install Helios, run `heliosup`.
## Usage ## Usage
To run Helios, run the below command, replacing `$ETH_RPC_URL` with an RPC provider URL such as Alchemy or Infura: To run Helios, run the below command, replacing `$ETH_RPC_URL` with an RPC provider URL such as Alchemy or Infura:
@ -30,10 +32,14 @@ helios --execution-rpc $ETH_RPC_URL
Helios will now run a local RPC server at `http://127.0.0.1:8545`. Helios will now run a local RPC server at `http://127.0.0.1:8545`.
Helios also provides examples in the [`examples/`](./examples/) directory. To run an example, you can execute `cargo run --example <example_name>` from inside the helios repository.
### Warning ### Warning
Helios is still experimental software. While we hope you try it out, we do not suggest adding it as your main RPC in wallets yet. Sending high-value transactions from a wallet connected to Helios is discouraged. Helios is still experimental software. While we hope you try it out, we do not suggest adding it as your main RPC in wallets yet. Sending high-value transactions from a wallet connected to Helios is discouraged.
### Additional Options ### Additional Options
`--consensus-rpc` or `-c` can be used to set a custom consensus layer rpc endpoint. This must be a consenus node that supports the light client beaconchain api. We recommend using Nimbus for this. If no consensus rpc is supplied, it defaults to `https://www.lightclientdata.org` which is run by us. `--consensus-rpc` or `-c` can be used to set a custom consensus layer rpc endpoint. This must be a consenus node that supports the light client beaconchain api. We recommend using Nimbus for this. If no consensus rpc is supplied, it defaults to `https://www.lightclientdata.org` which is run by us.
@ -61,6 +67,7 @@ This can be run like so: `helios --load-external-fallback` (or `helios -l` with
`--help` or `-h` prints the help message. `--help` or `-h` prints the help message.
### Configuration Files ### Configuration Files
All configuration options can be set on a per-network level in `~/.helios/helios.toml`. Here is an example config file: All configuration options can be set on a per-network level in `~/.helios/helios.toml`. Here is an example config file:
@ -77,6 +84,7 @@ execution_rpc = "https://eth-goerli.g.alchemy.com/v2/XXXXX"
checkpoint = "0xb5c375696913865d7c0e166d87bc7c772b6210dc9edf149f4c7ddc6da0dd4495" checkpoint = "0xb5c375696913865d7c0e166d87bc7c772b6210dc9edf149f4c7ddc6da0dd4495"
``` ```
### Using Helios as a Library ### Using Helios as a Library
Helios can be imported into any Rust project. Helios requires the Rust nightly toolchain to compile. Helios can be imported into any Rust project. Helios requires the Rust nightly toolchain to compile.
@ -134,6 +142,8 @@ async fn main() -> Result<()> {
// Fetch the latest mainnet checkpoint // Fetch the latest mainnet checkpoint
let mainnet_checkpoint = cf.fetch_latest_checkpoint(&networks::Network::MAINNET).await.unwrap(); let mainnet_checkpoint = cf.fetch_latest_checkpoint(&networks::Network::MAINNET).await.unwrap();
println!("Fetched latest mainnet checkpoint: {}", mainnet_checkpoint); println!("Fetched latest mainnet checkpoint: {}", mainnet_checkpoint);
Ok(())
} }
``` ```
@ -141,10 +151,12 @@ async fn main() -> Result<()> {
All contributions to Helios are welcome. Before opening a PR, please submit an issue detailing the bug or feature. When opening a PR, please ensure that your contribution builds on the nightly rust toolchain, has been linted with `cargo fmt`, and contains tests when applicable. All contributions to Helios are welcome. Before opening a PR, please submit an issue detailing the bug or feature. When opening a PR, please ensure that your contribution builds on the nightly rust toolchain, has been linted with `cargo fmt`, and contains tests when applicable.
## Telegram ## Telegram
If you are having trouble with Helios or are considering contributing, feel free to join our telegram [here](https://t.me/+IntDY_gZJSRkNTJj). If you are having trouble with Helios or are considering contributing, feel free to join our telegram [here](https://t.me/+IntDY_gZJSRkNTJj).
## Disclaimer ## Disclaimer
_This code is being provided as is. No guarantee, representation or warranty is being made, express or implied, as to the safety or correctness of the code. It has not been audited and as such there can be no assurance it will work as intended, and users may experience delays, failures, errors, omissions or loss of transmitted information. Nothing in this repo should be construed as investment advice or legal advice for any particular facts or circumstances and is not meant to replace competent counsel. It is strongly advised for you to contact a reputable attorney in your jurisdiction for any questions or concerns with respect thereto. a16z is not liable for any use of the foregoing, and users should proceed with caution and use at their own risk. See a16z.com/disclosures for more info._ _This code is being provided as is. No guarantee, representation or warranty is being made, express or implied, as to the safety or correctness of the code. It has not been audited and as such there can be no assurance it will work as intended, and users may experience delays, failures, errors, omissions or loss of transmitted information. Nothing in this repo should be construed as investment advice or legal advice for any particular facts or circumstances and is not meant to replace competent counsel. It is strongly advised for you to contact a reputable attorney in your jurisdiction for any questions or concerns with respect thereto. a16z is not liable for any use of the foregoing, and users should proceed with caution and use at their own risk. See a16z.com/disclosures for more info._

View File

@ -53,7 +53,8 @@ impl ClientBuilder {
} }
pub fn checkpoint(mut self, checkpoint: &str) -> Self { pub fn checkpoint(mut self, checkpoint: &str) -> Self {
let checkpoint = hex::decode(checkpoint).expect("cannot parse checkpoint"); let checkpoint = hex::decode(checkpoint.strip_prefix("0x").unwrap_or(checkpoint))
.expect("cannot parse checkpoint");
self.checkpoint = Some(checkpoint); self.checkpoint = Some(checkpoint);
self self
} }

View File

@ -229,4 +229,12 @@ impl CheckpointFallback {
.map(|service| service.endpoint.clone()) .map(|service| service.endpoint.clone())
.collect() .collect()
} }
/// Returns the raw checkpoint fallback service objects for a given network.
pub fn get_fallback_services(
&self,
network: &networks::Network,
) -> &Vec<CheckpointFallbackService> {
self.services[network].as_ref()
}
} }

View File

@ -1,10 +1,10 @@
use std::{collections::HashMap, path::PathBuf}; use std::{collections::HashMap, path::PathBuf};
use figment::{providers::Serialized, value::Value}; use figment::{providers::Serialized, value::Value};
use serde::Serialize; use serde::{Deserialize, Serialize};
/// Cli Config /// Cli Config
#[derive(Serialize)] #[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct CliConfig { pub struct CliConfig {
pub execution_rpc: Option<String>, pub execution_rpc: Option<String>,
pub consensus_rpc: Option<String>, pub consensus_rpc: Option<String>,

42
examples/checkpoints.rs Normal file
View File

@ -0,0 +1,42 @@
use eyre::Result;
// From helios::config
use config::{checkpoints, networks};
#[tokio::main]
async fn main() -> Result<()> {
// Construct the checkpoint fallback services.
// The `build` method will fetch a list of [CheckpointFallbackService]s from a community-mainained list by ethPandaOps.
// This list is NOT guaranteed to be secure, but is provided in good faith.
// The raw list can be found here: https://github.com/ethpandaops/checkpoint-sync-health-checks/blob/master/_data/endpoints.yaml
let cf = checkpoints::CheckpointFallback::new()
.build()
.await
.unwrap();
// Fetch the latest goerli checkpoint
let goerli_checkpoint = cf
.fetch_latest_checkpoint(&networks::Network::GOERLI)
.await
.unwrap();
println!("Fetched latest goerli checkpoint: {}", goerli_checkpoint);
// Fetch the latest mainnet checkpoint
let mainnet_checkpoint = cf
.fetch_latest_checkpoint(&networks::Network::MAINNET)
.await
.unwrap();
println!("Fetched latest mainnet checkpoint: {}", mainnet_checkpoint);
// Let's get a list of all the fallback service endpoints for mainnet
let endpoints = cf.get_all_fallback_endpoints(&networks::Network::MAINNET);
println!("Fetched all mainnet fallback endpoints: {:?}", endpoints);
// Since we built the checkpoint fallback services, we can also just get the raw checkpoint fallback services.
// The `get_fallback_services` method returns a reference to the internal list of CheckpointFallbackService objects
// for the given network.
let services = cf.get_fallback_services(&networks::Network::MAINNET);
println!("Fetched all mainnet fallback services: {:?}", services);
Ok(())
}

42
examples/client.rs Normal file
View File

@ -0,0 +1,42 @@
use std::path::PathBuf;
use eyre::Result;
use helios::prelude::*;
#[tokio::main]
async fn main() -> Result<()> {
// Create a new Helios Client Builder
let mut builder = ClientBuilder::new();
// Set the network to mainnet
builder = builder.network(networks::Network::MAINNET);
// Set the consensus rpc url
builder = builder.consensus_rpc("https://www.lightclientdata.org");
// Set the execution rpc url
builder = builder.execution_rpc("https://eth-mainnet.g.alchemy.com/v2/XXXXX");
// Set the checkpoint to the last known checkpoint
builder =
builder.checkpoint("85e6151a246e8fdba36db27a0c7678a575346272fe978c9281e13a8b26cdfa68");
// Set the rpc port
builder = builder.rpc_port(8545);
// Set the data dir
builder = builder.data_dir(PathBuf::from("/tmp/helios"));
// Set the fallback service
builder = builder.fallback("https://sync-mainnet.beaconcha.in");
// Enable lazy checkpoints
builder = builder.load_external_fallback();
// Build the client
let _client = builder.build().unwrap();
println!("Constructed client!");
Ok(())
}

14
examples/config.rs Normal file
View File

@ -0,0 +1,14 @@
use config::CliConfig;
use eyre::Result;
use helios::prelude::*;
#[tokio::main]
async fn main() -> Result<()> {
// Load the config from the global config file
let config_path = home::home_dir().unwrap().join(".helios/helios.toml");
let config = Config::from_file(&config_path, "mainnet", &CliConfig::default());
println!("Constructed config: {:#?}", config);
Ok(())
}

View File

@ -1,3 +1,55 @@
#![warn(missing_debug_implementations, rust_2018_idioms, unreachable_pub)]
#![deny(rustdoc::broken_intra_doc_links)]
#![doc(test(
no_crate_inject,
attr(deny(warnings, rust_2018_idioms), allow(dead_code, unused_variables))
))]
//! # Ethereum light client written in Rust.
//!
//! > helios is a fully trustless, efficient, and portable Ethereum light client written in Rust.
//!
//! Helios converts an untrusted centralized RPC endpoint into a safe unmanipulable local RPC for its users. It syncs in seconds, requires no storage, and is lightweight enough to run on mobile devices.
//!
//! The entire size of Helios's binary is 13Mb and should be easy to compile into WebAssembly. This makes it a perfect target to embed directly inside wallets and dapps.
//!
//! ## Quickstart: `prelude`
//!
//! The prelude imports all the necessary data types and traits from helios. Use this to quickly bootstrap a new project.
//!
//! ```no_run
//! # #[allow(unused)]
//! use helios::prelude::*;
//! ```
//!
//! Examples on how you can use the types imported by the prelude can be found in
//! the [`examples` directory of the repository](https://github.com/a16z/helios/tree/master/examples)
//! and in the `tests/` directories of each crate.
//!
//! ## Breakdown of exported helios modules
//!
//! ### `client`
//!
//! The `client` module exports three main types: `Client`, `ClientBuilder`, and `FileDB`.
//!
//! `ClientBuilder` is a builder for the `Client` type. It allows you to configure the client using the fluent builder pattern.
//!
//! `Client` serves Ethereum RPC endpoints locally that call a node on the backend.
//!
//! Finally, the `FileDB` type is a simple local database. It is used by the `Client` to store checkpoint data.
//!
//! ### `config`
//!
//! The `config` module provides the configuration types for all of helios. It is used by the `ClientBuilder` to configure the `Client`.
//!
//! ### `types`
//!
//! Generic types used across helios.
//!
//! ### `errors`
//!
//! Errors used across helios.
pub mod client { pub mod client {
pub use client::{database::FileDB, Client, ClientBuilder}; pub use client::{database::FileDB, Client, ClientBuilder};
} }
@ -16,3 +68,10 @@ pub mod errors {
pub use consensus::errors::*; pub use consensus::errors::*;
pub use execution::errors::*; pub use execution::errors::*;
} }
pub mod prelude {
pub use crate::client::*;
pub use crate::config::*;
pub use crate::errors::*;
pub use crate::types::*;
}