From 643b4a0367fa427006b01388360eaf8a1030ed91 Mon Sep 17 00:00:00 2001 From: Noah Citron Date: Fri, 12 Aug 2022 17:19:51 -0400 Subject: [PATCH] fully validate bootstrap --- src/main.rs | 116 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 86 insertions(+), 30 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7964532..d190311 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ use ssz_rs::prelude::*; #[tokio::main] async fn main() -> Result<()> { - let client = LightClient::new( + let mut client = LightClient::new( "http://testing.prater.beacon-api.nimbus.team", "0x29d7ba1ef23b01a8b9024ee0cd73d0b7181edc0eb16e4645300092838c07783f" ).await?; @@ -33,40 +33,63 @@ impl LightClient { let mut bootstrap = Self::get_bootstrap(nimbus_rpc, checkpoint_block_root).await?; let committee_hash = bootstrap.current_sync_committee.hash_tree_root()?; - let root = Node::from_bytes(hex::decode(bootstrap.header.state_root.strip_prefix("0x").unwrap()).unwrap().try_into().unwrap()); - let committee_branch = bootstrap.current_sync_committee_branch.iter().map(|elem| { - Node::from_bytes(hex::decode(elem.strip_prefix("0x").unwrap()).unwrap().try_into().unwrap()) - }).collect::>(); - - println!("{}", committee_hash); + let root = Node::from_bytes(bootstrap.header.state_root); + let committee_branch = branch_to_nodes(bootstrap.current_sync_committee_branch); - let is_valid = is_valid_merkle_branch(&committee_hash, committee_branch.iter(), 5, 22, &root); - println!("{}", is_valid); + let committee_valid = is_valid_merkle_branch(&committee_hash, committee_branch.iter(), 5, 22, &root); + println!("bootstrap committee valid: {}", committee_valid); - // let store = Store { - // header: bootstrap.header, - // current_sync_committee: bootstrap.current_sync_committee, - // next_sync_committee: None, - // }; + 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); - // Ok(LightClient { nimbus_rpc: nimbus_rpc.to_string(), store }) + if !(header_valid && committee_valid) { + return Err(eyre::eyre!("Invalid Bootstrap")); + } - eyre::bail!("") + let store = Store { + header: bootstrap.header, + current_sync_committee: bootstrap.current_sync_committee, + next_sync_committee: None, + }; + + Ok(LightClient { nimbus_rpc: nimbus_rpc.to_string(), store }) } - async fn sync(&self) -> Result<()> { + async fn sync(&mut self) -> Result<()> { - let period = LightClient::calc_sync_period(self.store.header.slot.parse().unwrap()); - let updates = self.get_updates(period).await?; + let current_period = calc_sync_period(self.store.header.slot); + let next_period = current_period + 1; + + let updates = self.get_updates(next_period).await?; for update in updates { - // TODO: verify update - println!("{:?}", update.finalized_header); + self.proccess_update(update)? } Ok(()) } + 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(()) + } + async fn get_bootstrap(rpc: &str, block_root: &str) -> Result { let req = format!("{}/eth/v0/beacon/light_client/bootstrap/{}", rpc, block_root); let res = reqwest::get(req).await?.json::().await?; @@ -84,11 +107,15 @@ impl LightClient { let res = reqwest::get(req).await?.json::().await?; Ok(res.data) } +} - fn calc_sync_period(slot: u64) -> u64 { - let epoch = slot / 32; - epoch / 256 - } +fn calc_sync_period(slot: u64) -> u64 { + let epoch = slot / 32; + epoch / 256 +} + +fn branch_to_nodes(branch: Vec) -> Vec { + branch.iter().map(|elem| Node::from_bytes(*elem)).collect() } #[derive(serde::Deserialize, Debug)] @@ -105,7 +132,8 @@ struct BootstrapData { struct Bootstrap { header: Header, current_sync_committee: SyncCommittee, - current_sync_committee_branch: Vec, + #[serde(deserialize_with = "branch_deserialize")] + current_sync_committee_branch: Vec, } #[derive(Debug, Clone, Default, SimpleSerialize, serde::Deserialize)] @@ -117,6 +145,7 @@ struct SyncCommittee { } type BLSPubKey = Vector; +type Bytes32 = [u8; 32]; fn pubkey_deserialize<'de, D>(deserializer: D) -> Result where D: serde::Deserializer<'de> { let key: String = serde::Deserialize::deserialize(deserializer)?; @@ -132,11 +161,37 @@ fn pubkeys_deserialize<'de, D>(deserializer: D) -> Result }).collect::>()) } -#[derive(serde::Deserialize, Debug, Clone)] +fn branch_deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de> { + let branch: Vec = 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 { - slot: String, - state_root: String, - body_root: String, + #[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 where D: serde::Deserializer<'de> { + let val: String = serde::Deserialize::deserialize(deserializer)?; + Ok(val.parse().unwrap()) +} + +fn bytes32_deserialize<'de, D>(deserializer: D) -> Result 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()) } #[derive(serde::Deserialize, Debug)] @@ -173,3 +228,4 @@ struct FinalityUpdate { sync_aggregate: SyncAggregate, signature_slot: String, } +