setup api bindings for reaching out to light servers

This commit is contained in:
Noah Citron 2022-08-11 14:09:58 -04:00
commit 2dd11e6a1c
4 changed files with 1184 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

1046
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

12
Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "lightclient"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }
eyre = "0.6.8"
serde = { version = "1.0.143", features = ["derive"] }

125
src/main.rs Normal file
View File

@ -0,0 +1,125 @@
use eyre::Result;
use serde::Deserialize;
#[tokio::main]
async fn main() -> Result<()> {
let client = LightClient::new("http://testing.prater.beacon-api.nimbus.team");
let bootstrap = client.get_bootstrap("0x29d7ba1ef23b01a8b9024ee0cd73d0b7181edc0eb16e4645300092838c07783f").await?;
let current_slot = bootstrap.header.slot;
let current_sync_period = LightClient::calc_sync_period(current_slot.parse()?);
let next_sync_period = current_sync_period + 1;
println!("{}", next_sync_period);
let updates = client.get_updates(next_sync_period).await?;
let attested_headers = updates.iter().map(|update| &update.attested_header).collect::<Vec<&Header>>();
let finalized_headers = updates.iter().map(|update| &update.finalized_header).collect::<Vec<&Header>>();
println!("{:?}", attested_headers);
println!("{:?}", finalized_headers);
let finality_update = client.get_finality_update().await?;
println!("{:?}", finality_update.attested_header);
println!("{:?}", finality_update.finalized_header);
Ok(())
}
struct LightClient {
nimbus_rpc: String,
}
impl LightClient {
fn new(nimbus_rpc: &str) -> LightClient {
LightClient { nimbus_rpc: nimbus_rpc.to_string() }
}
async fn get_bootstrap(&self, block_root: &str) -> Result<Bootstrap> {
let req = format!("{}/eth/v0/beacon/light_client/bootstrap/{}", self.nimbus_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)
}
fn calc_sync_period(slot: u64) -> u64 {
let epoch = slot / 32;
epoch / 256
}
}
#[derive(Deserialize, Debug)]
struct BootstrapResponse {
data: BootstrapData,
}
#[derive(Deserialize, Debug)]
struct BootstrapData {
v: Bootstrap,
}
#[derive(Deserialize, Debug)]
struct Bootstrap {
header: Header,
current_sync_committee: SyncCommittee,
current_sync_committee_branch: Vec<String>,
}
#[derive(Deserialize, Debug, Clone)]
struct SyncCommittee {
pubkeys: Vec<String>,
aggregate_pubkey: String,
}
#[derive(Deserialize, Debug, Clone)]
struct Header {
slot: String,
}
#[derive(Deserialize, Debug)]
struct UpdateResponse {
data: Vec<Update>,
}
#[derive(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,
}
#[derive(Deserialize, Debug, Clone)]
struct SyncAggregate {
sync_committee_bits: String,
sync_committee_signature: String,
}
#[derive(Deserialize, Debug)]
struct FinalityUpdateResponse {
data: FinalityUpdate,
}
#[derive(Deserialize, Debug)]
struct FinalityUpdate {
attested_header: Header,
finalized_header: Header,
finality_branch: Vec<String>,
sync_aggregate: SyncAggregate,
signature_slot: String,
}