helios/src/main.rs

232 lines
7.2 KiB
Rust
Raw Normal View History

use eyre::Result;
2022-08-12 16:38:40 +00:00
use serde::Deserializer;
use ssz_rs::prelude::*;
#[tokio::main]
async fn main() -> Result<()> {
2022-08-12 21:19:51 +00:00
let mut client = LightClient::new(
2022-08-12 15:32:16 +00:00
"http://testing.prater.beacon-api.nimbus.team",
"0x29d7ba1ef23b01a8b9024ee0cd73d0b7181edc0eb16e4645300092838c07783f"
).await?;
2022-08-12 15:32:16 +00:00
client.sync().await?;
Ok(())
}
struct LightClient {
nimbus_rpc: String,
2022-08-12 15:32:16 +00:00
store: Store,
}
#[derive(Debug)]
struct Store {
header: Header,
current_sync_committee: SyncCommittee,
next_sync_committee: Option<SyncCommittee>,
}
impl LightClient {
2022-08-12 15:32:16 +00:00
async fn new(nimbus_rpc: &str, checkpoint_block_root: &str) -> Result<LightClient> {
2022-08-12 16:38:40 +00:00
let mut bootstrap = Self::get_bootstrap(nimbus_rpc, checkpoint_block_root).await?;
let committee_hash = bootstrap.current_sync_committee.hash_tree_root()?;
2022-08-12 21:19:51 +00:00
let root = Node::from_bytes(bootstrap.header.state_root);
let committee_branch = branch_to_nodes(bootstrap.current_sync_committee_branch);
2022-08-12 16:38:40 +00:00
2022-08-12 21:19:51 +00:00
let committee_valid = is_valid_merkle_branch(&committee_hash, committee_branch.iter(), 5, 22, &root);
println!("bootstrap committee valid: {}", committee_valid);
let header_hash = bootstrap.header.hash_tree_root()?;
let header_valid = header_hash.to_string() == checkpoint_block_root.to_string();
println!("bootstrap header valid: {}", header_valid);
2022-08-12 16:38:40 +00:00
2022-08-12 21:19:51 +00:00
if !(header_valid && committee_valid) {
return Err(eyre::eyre!("Invalid Bootstrap"));
}
2022-08-12 16:38:40 +00:00
2022-08-12 21:19:51 +00:00
let store = Store {
header: bootstrap.header,
current_sync_committee: bootstrap.current_sync_committee,
next_sync_committee: None,
};
2022-08-12 16:38:40 +00:00
2022-08-12 21:19:51 +00:00
Ok(LightClient { nimbus_rpc: nimbus_rpc.to_string(), store })
}
2022-08-12 21:19:51 +00:00
async fn sync(&mut self) -> Result<()> {
2022-08-12 15:32:16 +00:00
2022-08-12 21:19:51 +00:00
let current_period = calc_sync_period(self.store.header.slot);
let next_period = current_period + 1;
let updates = self.get_updates(next_period).await?;
2022-08-12 15:32:16 +00:00
for update in updates {
2022-08-12 21:19:51 +00:00
self.proccess_update(update)?
2022-08-12 15:32:16 +00:00
}
Ok(())
}
2022-08-12 21:19:51 +00:00
fn proccess_update(&mut self, update: Update) -> Result<()> {
let current_slot = self.store.header.slot;
let update_slot = update.attested_header.slot;
let current_period = calc_sync_period(current_slot);
let update_period = calc_sync_period(update_slot);
println!("current period: {}", current_period);
println!("update period: {}", update_period);
assert!(update_period == current_period + 1);
// TODO: all validations
self.store.header = update.attested_header.clone();
Ok(())
}
2022-08-12 15:32:16 +00:00
async fn get_bootstrap(rpc: &str, block_root: &str) -> Result<Bootstrap> {
let req = format!("{}/eth/v0/beacon/light_client/bootstrap/{}", rpc, block_root);
let res = reqwest::get(req).await?.json::<BootstrapResponse>().await?;
Ok(res.data.v)
}
async fn get_updates(&self, period: u64) -> Result<Vec<Update>> {
let req = format!("{}/eth/v0/beacon/light_client/updates?start_period={}&count=1000", self.nimbus_rpc, period);
let res = reqwest::get(req).await?.json::<UpdateResponse>().await?;
Ok(res.data)
}
async fn get_finality_update(&self) -> Result<FinalityUpdate> {
let req = format!("{}/eth/v0/beacon/light_client/finality_update", self.nimbus_rpc);
let res = reqwest::get(req).await?.json::<FinalityUpdateResponse>().await?;
Ok(res.data)
}
2022-08-12 21:19:51 +00:00
}
2022-08-12 21:19:51 +00:00
fn calc_sync_period(slot: u64) -> u64 {
let epoch = slot / 32;
epoch / 256
}
fn branch_to_nodes(branch: Vec<Bytes32>) -> Vec<Node> {
branch.iter().map(|elem| Node::from_bytes(*elem)).collect()
}
2022-08-12 16:38:40 +00:00
#[derive(serde::Deserialize, Debug)]
struct BootstrapResponse {
data: BootstrapData,
}
2022-08-12 16:38:40 +00:00
#[derive(serde::Deserialize, Debug)]
struct BootstrapData {
v: Bootstrap,
}
2022-08-12 16:38:40 +00:00
#[derive(serde::Deserialize, Debug)]
struct Bootstrap {
header: Header,
current_sync_committee: SyncCommittee,
2022-08-12 21:19:51 +00:00
#[serde(deserialize_with = "branch_deserialize")]
current_sync_committee_branch: Vec<Bytes32>,
}
2022-08-12 16:38:40 +00:00
#[derive(Debug, Clone, Default, SimpleSerialize, serde::Deserialize)]
struct SyncCommittee {
2022-08-12 15:32:16 +00:00
#[serde(deserialize_with = "pubkeys_deserialize")]
2022-08-12 16:38:40 +00:00
pubkeys: Vector<BLSPubKey, 512>,
2022-08-12 15:32:16 +00:00
#[serde(deserialize_with = "pubkey_deserialize")]
2022-08-12 16:38:40 +00:00
aggregate_pubkey: BLSPubKey,
2022-08-12 15:32:16 +00:00
}
2022-08-12 16:38:40 +00:00
type BLSPubKey = Vector<u8, 48>;
2022-08-12 21:19:51 +00:00
type Bytes32 = [u8; 32];
2022-08-12 16:38:40 +00:00
fn pubkey_deserialize<'de, D>(deserializer: D) -> Result<BLSPubKey, D::Error> where D: serde::Deserializer<'de> {
let key: String = serde::Deserialize::deserialize(deserializer)?;
2022-08-12 15:32:16 +00:00
let key_bytes = hex::decode(key.strip_prefix("0x").unwrap()).unwrap();
2022-08-12 16:38:40 +00:00
Ok(Vector::from_iter(key_bytes))
2022-08-12 15:32:16 +00:00
}
2022-08-12 16:38:40 +00:00
fn pubkeys_deserialize<'de, D>(deserializer: D) -> Result<Vector<BLSPubKey, 512>, D::Error> where D: serde::Deserializer<'de> {
let keys: Vec<String> = serde::Deserialize::deserialize(deserializer)?;
Ok(keys.iter().map(|key| {
2022-08-12 15:32:16 +00:00
let key_bytes = hex::decode(key.strip_prefix("0x").unwrap()).unwrap();
2022-08-12 16:38:40 +00:00
Vector::from_iter(key_bytes)
}).collect::<Vector<BLSPubKey, 512>>())
}
2022-08-12 21:19:51 +00:00
fn branch_deserialize<'de, D>(deserializer: D) -> Result<Vec<Bytes32>, D::Error> where D: serde::Deserializer<'de> {
let branch: Vec<String> = serde::Deserialize::deserialize(deserializer)?;
Ok(branch.iter().map(|elem| {
let bytes = hex::decode(elem.strip_prefix("0x").unwrap()).unwrap();
bytes.to_vec().try_into().unwrap()
}).collect())
}
#[derive(serde::Deserialize, Debug, Clone, Default, SimpleSerialize)]
struct Header {
2022-08-12 21:19:51 +00:00
#[serde(deserialize_with = "u64_deserialize")]
slot: u64,
#[serde(deserialize_with = "u64_deserialize")]
proposer_index: u64,
#[serde(deserialize_with = "bytes32_deserialize")]
parent_root: Bytes32,
#[serde(deserialize_with = "bytes32_deserialize")]
state_root: Bytes32,
#[serde(deserialize_with = "bytes32_deserialize")]
body_root: Bytes32,
}
fn u64_deserialize<'de, D>(deserializer: D) -> Result<u64, D::Error> where D: serde::Deserializer<'de> {
let val: String = serde::Deserialize::deserialize(deserializer)?;
Ok(val.parse().unwrap())
}
fn bytes32_deserialize<'de, D>(deserializer: D) -> Result<Bytes32, D::Error> where D: serde::Deserializer<'de> {
let bytes: String = serde::Deserialize::deserialize(deserializer)?;
let bytes = hex::decode(bytes.strip_prefix("0x").unwrap()).unwrap();
Ok(bytes.to_vec().try_into().unwrap())
}
2022-08-12 16:38:40 +00:00
#[derive(serde::Deserialize, Debug)]
struct UpdateResponse {
data: Vec<Update>,
}
2022-08-12 16:38:40 +00:00
#[derive(serde::Deserialize, Debug, Clone)]
struct Update {
attested_header: Header,
next_sync_committee: SyncCommittee,
next_sync_committee_branch: Vec<String>,
finalized_header: Header,
finality_branch: Vec<String>,
sync_aggregate: SyncAggregate,
}
2022-08-12 16:38:40 +00:00
#[derive(serde::Deserialize, Debug, Clone)]
struct SyncAggregate {
sync_committee_bits: String,
sync_committee_signature: String,
}
2022-08-12 16:38:40 +00:00
#[derive(serde::Deserialize, Debug)]
struct FinalityUpdateResponse {
data: FinalityUpdate,
}
2022-08-12 16:38:40 +00:00
#[derive(serde::Deserialize, Debug)]
struct FinalityUpdate {
attested_header: Header,
finalized_header: Header,
finality_branch: Vec<String>,
sync_aggregate: SyncAggregate,
signature_slot: String,
}
2022-08-12 21:19:51 +00:00