Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
benluelo committed Aug 10, 2024
1 parent 242eee6 commit 7937c4f
Show file tree
Hide file tree
Showing 50 changed files with 1,406 additions and 1,350 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions lib/beacon-api/examples/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use beacon_api::client::{BeaconApiClient, BlockId};
use unionlabs::ethereum::config::Minimal;

#[tokio::main]
async fn main() {
Expand All @@ -9,7 +8,7 @@ async fn main() {
}

async fn do_main() {
let client = BeaconApiClient::<Minimal>::new("http://localhost:9596".to_string())
let client = BeaconApiClient::new("http://localhost:9596".to_string())
.await
.unwrap();

Expand Down
108 changes: 30 additions & 78 deletions lib/beacon-api/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
//! Beacon API client, implemented as per https://ethereum.github.io/beacon-APIs/releases/v2.4.1/beacon-node-oapi.json
use std::{fmt::Display, marker::PhantomData};
use std::fmt::Display;

use macros::AnyChainSpec;
use reqwest::{Client, StatusCode};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use tracing::{debug, info, trace};
use unionlabs::{
ethereum::{
beacon::{GenesisData, LightClientBootstrap, LightClientFinalityUpdate},
config::{AnyChainSpec, ChainSpec, Mainnet, Minimal},
SignedBeaconBlock,
ethereum::beacon::{
genesis_data::GenesisData, light_client_bootstrap::UnboundedLightClientBootstrap,
light_client_finality_update::UnboundedLightClientFinalityUpdate,
signed_beacon_block::UnboundedSignedBeaconBlock,
},
hash::H256,
typenum::Unsigned,
};

use crate::{
Expand All @@ -23,11 +21,10 @@ use crate::{

pub type Result<T> = core::result::Result<T, Error>;

#[derive(Debug, Clone, AnyChainSpec)]
pub struct BeaconApiClient<C: ChainSpec> {
#[derive(Debug, Clone)]
pub struct BeaconApiClient {
client: Client,
base_url: String,
__marker: PhantomData<C>,
}

#[derive(Debug, thiserror::Error)]
Expand All @@ -38,55 +35,23 @@ pub enum NewError {
Error(#[from] Error),
}

#[derive(Debug, thiserror::Error)]
pub enum AnyBeaconApiClientError {
#[error("error creating minimal beacon client")]
Minimal(#[source] NewError),
#[error("error creating mainnet beacon client")]
Mainnet(#[source] NewError),
#[error("unknown chain spec")]
UnknownChainSpec,
}

pub async fn new_any(
url: String,
) -> core::result::Result<AnyChainSpec<AnyBeaconApiClient>, AnyBeaconApiClientError> {
match BeaconApiClient::<Mainnet>::new(url.clone()).await {
Ok(eth) => return Ok(AnyChainSpec::Mainnet(eth)),
Err(NewError::IncorrectChainSpec) => {}
Err(err) => {
return Err(AnyBeaconApiClientError::Mainnet(err));
}
}

match BeaconApiClient::<Minimal>::new(url).await {
Ok(eth) => return Ok(AnyChainSpec::Minimal(eth)),
Err(NewError::IncorrectChainSpec) => {}
Err(err) => {
return Err(AnyBeaconApiClientError::Minimal(err));
}
}

Err(AnyBeaconApiClientError::UnknownChainSpec)
}

impl<C: ChainSpec> BeaconApiClient<C> {
impl BeaconApiClient {
pub async fn new(base_url: String) -> core::result::Result<Self, NewError> {
let this = Self {
client: reqwest::Client::new(),
base_url,
__marker: PhantomData,
};

let spec = this.spec().await?;
// TODO: Do checks against a spec?
let _spec = this.spec().await?;

if spec.data.seconds_per_slot != C::SECONDS_PER_SLOT::U64 {
return Err(NewError::IncorrectChainSpec);
}
// if spec.data.seconds_per_slot != C::SECONDS_PER_SLOT::U64 {
// return Err(NewError::IncorrectChainSpec);
// }

if spec.data.slots_per_epoch != C::SLOTS_PER_EPOCH::U64 {
return Err(NewError::IncorrectChainSpec);
}
// if spec.data.slots_per_epoch != C::SLOTS_PER_EPOCH::U64 {
// return Err(NewError::IncorrectChainSpec);
// }

Ok(this)
}
Expand All @@ -95,7 +60,9 @@ impl<C: ChainSpec> BeaconApiClient<C> {
self.get_json("/eth/v1/config/spec").await
}

pub async fn finality_update(&self) -> Result<Response<LightClientFinalityUpdate<C>, Version>> {
pub async fn finality_update(
&self,
) -> Result<Response<UnboundedLightClientFinalityUpdate, Version>> {
self.get_json("/eth/v1/beacon/light_client/finality_update")
.await
}
Expand All @@ -111,15 +78,15 @@ impl<C: ChainSpec> BeaconApiClient<C> {
pub async fn block(
&self,
block_id: BlockId,
) -> Result<Response<SignedBeaconBlock<C>, BeaconBlockExtra>> {
) -> Result<Response<UnboundedSignedBeaconBlock, BeaconBlockExtra>> {
self.get_json(format!("/eth/v2/beacon/blocks/{block_id}"))
.await
}

pub async fn bootstrap(
&self,
finalized_root: H256,
) -> Result<Response<LightClientBootstrap<C>>> {
) -> Result<Response<UnboundedLightClientBootstrap>> {
self.get_json(format!(
"/eth/v1/beacon/light_client/bootstrap/{finalized_root}"
))
Expand All @@ -137,7 +104,7 @@ impl<C: ChainSpec> BeaconApiClient<C> {
&self,
start_period: u64,
count: u64,
) -> Result<LightClientUpdatesResponse<C>> {
) -> Result<LightClientUpdatesResponse> {
self.get_json(format!(
"/eth/v1/beacon/light_client/updates?start_period={start_period}&count={count}"
))
Expand All @@ -160,17 +127,21 @@ impl<C: ChainSpec> BeaconApiClient<C> {
Ok(height)
}

pub async fn bootstrap_for_slot(&self, slot: u64) -> Result<Response<LightClientBootstrap<C>>> {
pub async fn bootstrap_for_slot(
&self,
slot: u64,
) -> Result<Response<UnboundedLightClientBootstrap>> {
// NOTE(benluelo): While this is technically two actions, I consider it to be one
// action - if the beacon chain doesn't have the header, it won't have the bootstrap
// either. It would be nice if the beacon chain exposed "fetch bootstrap by slot"
// functionality; I'm surprised it doesn't.

let mut amount_of_slots_back: u64 = 0;

let floored_slot = slot
/ (C::SLOTS_PER_EPOCH::U64 * C::EPOCHS_PER_SYNC_COMMITTEE_PERIOD::U64)
* (C::SLOTS_PER_EPOCH::U64 * C::EPOCHS_PER_SYNC_COMMITTEE_PERIOD::U64);
let spec = self.spec().await?.data;

let floored_slot = slot / (spec.slots_per_epoch * spec.epochs_per_sync_committee_period)
* (spec.slots_per_epoch * spec.epochs_per_sync_committee_period);

info!("fetching bootstrap at {}", floored_slot);

Expand Down Expand Up @@ -211,25 +182,6 @@ impl<C: ChainSpec> BeaconApiClient<C> {
}
}

// pub async fn get_light_client_updates_simple<
// const SYNC_COMMITTEE_SIZE: usize,
// const BYTES_PER_LOGS_BLOOM: usize,
// const MAX_EXTRA_DATA_BYTES: usize,
// >(
// &self,
// start_period: SyncCommitteePeriod,
// count: u64,
// ) -> Result<
// LightClientUpdatesResponse<SYNC_COMMITTEE_SIZE, BYTES_PER_LOGS_BLOOM, MAX_EXTRA_DATA_BYTES>,
// > {
// let count = if count < 1 { 1 } else { count };
// self.get_json(format!(
// "/eth/v1/beacon/light_client/updates?start_period={}&count={}",
// start_period, count
// ))
// .await
// }

// Helper functions

async fn get_json<T: DeserializeOwned>(&self, path: impl Into<String>) -> Result<T> {
Expand Down
24 changes: 13 additions & 11 deletions lib/beacon-api/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,26 +137,23 @@ pub struct BeaconHeaderSignature {
use serde::{Deserialize, Serialize};
use unionlabs::{
bls::BlsSignature,
ethereum::{
config::{ChainSpec, PresetBaseKind},
Version,
},
ethereum::{config::PresetBaseKind, Version},
hash::H256,
ibc::lightclients::ethereum::{
beacon_block_header::BeaconBlockHeader, fork::Fork, fork_parameters::ForkParameters,
light_client_update::LightClientUpdate,
light_client_update::UnboundedLightClientUpdate,
},
};

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(bound(serialize = "", deserialize = ""), deny_unknown_fields)]
pub struct LightClientUpdatesResponse<C: ChainSpec>(pub Vec<LightClientUpdateResponse<C>>);
pub struct LightClientUpdatesResponse(pub Vec<LightClientUpdateResponse>);

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(bound(serialize = "", deserialize = ""), deny_unknown_fields)]
pub struct LightClientUpdateResponse<C: ChainSpec> {
pub struct LightClientUpdateResponse {
pub version: String,
pub data: LightClientUpdate<C>,
pub data: UnboundedLightClientUpdate,
}

// #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
Expand Down Expand Up @@ -204,7 +201,7 @@ pub struct LightClientUpdateResponse<C: ChainSpec> {
// }
// }

#[derive(Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub struct Spec {
pub preset_base: PresetBaseKind,
Expand Down Expand Up @@ -278,7 +275,8 @@ pub struct Spec {
// MAX_DEPOSITS: 16,
// MAX_VOLUNTARY_EXITS: 16,
// SYNC_COMMITTEE_SIZE: 512,
// EPOCHS_PER_SYNC_COMMITTEE_PERIOD: 256,
#[serde(with = "::serde_utils::string")]
pub epochs_per_sync_committee_period: u64,
// INACTIVITY_PENALTY_QUOTIENT_ALTAIR: 50331648,
// MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR: 64,
// PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR: 2,
Expand All @@ -297,7 +295,7 @@ pub struct Spec {
// FIELD_ELEMENTS_PER_BLOB: 4096,
// MAX_BLOBS_PER_BLOCK: 4,
#[serde(with = "::serde_utils::string")]
genesis_slot: u64,
pub genesis_slot: u64,
// GENESIS_EPOCH: 0,
// FAR_FUTURE_EPOCH: 18446744073709551615,
// BASE_REWARDS_PER_EPOCH: 4,
Expand Down Expand Up @@ -360,4 +358,8 @@ impl Spec {
},
}
}

pub fn period(&self) -> u64 {
self.epochs_per_sync_committee_period * self.slots_per_epoch
}
}
2 changes: 1 addition & 1 deletion lib/block-message/src/aggregate.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::collections::VecDeque;

use enumorph::Enumorph;
use frunk::{hlist_pat, HList};
use frunk::{hlist, hlist_pat, HCons, HList};
use macros::apply;
use queue_msg::{
aggregate,
Expand Down
Loading

0 comments on commit 7937c4f

Please sign in to comment.