Skip to content

Commit

Permalink
feat: properly fetch bootstrap if slot is missing
Browse files Browse the repository at this point in the history
  • Loading branch information
benluelo committed Sep 28, 2023
1 parent 4b5facf commit 4accd1f
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 81 deletions.
3 changes: 2 additions & 1 deletion lib/beacon-api/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use unionlabs::{
};

use crate::{
errors::{Error, InternalServerError},
errors::{Error, InternalServerError, NotFoundError},
types::{BeaconHeaderData, LightClientUpdatesResponse, Spec},
};

Expand Down Expand Up @@ -130,6 +130,7 @@ impl<C: ChainSpec> BeaconApiClient<C> {

Ok(serde_json::from_slice(&bytes).map_err(Error::Json)?)
}
StatusCode::NOT_FOUND => Err(Error::NotFound(res.json::<NotFoundError>().await?)),
StatusCode::INTERNAL_SERVER_ERROR => {
Err(Error::Internal(res.json::<InternalServerError>().await?))
}
Expand Down
22 changes: 16 additions & 6 deletions lib/beacon-api/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,34 @@ use reqwest::StatusCode;
pub enum Error {
Http(reqwest::Error),
Internal(InternalServerError),
NotFound(NotFoundError),
Json(serde_json::Error),
Other { code: StatusCode, text: String },
}

#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct NotFoundError {
#[serde(rename = "statusCode")]
pub status_code: u64,
pub error: String,
pub message: String,
}

#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct InternalServerError {
#[serde(rename = "statusCode")]
status_code: u64,
error: String,
message: String,
pub status_code: u64,
pub error: String,
pub message: String,
}

impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Http(err) => write!(f, "`{err}`"),
Self::Internal(err) => write!(f, "{err:#?}"),
Self::Json(err) => write!(f, "{err}"),
Self::Http(err) => write!(f, "Http error: {err}"),
Self::Internal(err) => write!(f, "Internal server error: {err:#?}"),
Error::NotFound(err) => write!(f, "Not found: {err:#?}"),
Self::Json(err) => write!(f, "Deserialization error: {err}"),
Self::Other { code, text } => write!(f, "Unknown error (code {code}): {text}"),
}
}
Expand Down
52 changes: 1 addition & 51 deletions lib/chain-utils/src/evm.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{fmt::Display, ops::Div, str::FromStr, sync::Arc, time::Duration};
use std::{fmt::Display, ops::Div, str::FromStr, sync::Arc};

use beacon_api::client::BeaconApiClient;
use contracts::{
Expand Down Expand Up @@ -323,56 +323,6 @@ impl<C: ChainSpec> Evm<C> {
}
}

pub async fn wait_for_beacon_block(&self, requested_height: Height) {
const WAIT_TIME_SECONDS: Duration = Duration::from_secs(3);

loop {
let current_height = self.query_latest_height().await;

tracing::debug!(
"waiting for beacon block {requested_height}, current height is {current_height}",
);

if current_height.revision_height >= requested_height.revision_height {
break;
}

tracing::debug!(
"requested height {requested_height} not yet reached, trying again in {} seconds",
WAIT_TIME_SECONDS.as_secs()
);

tokio::time::sleep(WAIT_TIME_SECONDS).await;
}
}

pub async fn wait_for_execution_block(&self, block_number: ethers::types::U64) {
loop {
let latest_finalized_block_number: u64 = self
.beacon_api_client
.finality_update()
.await
.unwrap()
.data
.attested_header
.execution
.block_number;

tracing::debug!(
%latest_finalized_block_number,
waiting_for = %block_number,
"waiting for block"
);

if latest_finalized_block_number >= block_number.as_u64() {
break;
}

tracing::debug!("requested height not yet reached");
tokio::time::sleep(Duration::from_secs(3)).await;
}
}

pub async fn read_ibc_state<Call>(
&self,
call: Call,
Expand Down
68 changes: 48 additions & 20 deletions voyager/src/chain/evm.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::{collections::VecDeque, fmt::Debug, marker::PhantomData, ops::Div, sync::Arc};

use beacon_api::errors::{InternalServerError, NotFoundError};
use chain_utils::{
evm::{EthCallExt, Evm, TupleToOption},
Chain, ClientState,
Expand Down Expand Up @@ -29,11 +30,9 @@ use ethers::{
use frame_support_procedural::{CloneNoBound, DebugNoBound, PartialEqNoBound};
use frunk::{hlist_pat, HList};
use futures::Future;
use hubble::hasura::{insert_demo_tx, Datastore, InsertDemoTx};
use prost::Message;
use protos::union::ibc::lightclients::ethereum::v1 as ethereum_v1;
use serde::{Deserialize, Serialize};
use serde_json::json;
use typenum::Unsigned;
use unionlabs::{
ethereum::{
Expand Down Expand Up @@ -1113,26 +1112,55 @@ where
// either. It would be nice if the beacon chain exposed "fetch bootstrap by slot"
// functionality; I'm surprised it doesn't.

let currently_trusted_block = evm
.beacon_api_client
.header(beacon_api::client::BlockId::Slot(
slot / (C::SLOTS_PER_EPOCH::U64 * C::SECONDS_PER_SLOT::U64)
* (C::SLOTS_PER_EPOCH::U64 * C::SECONDS_PER_SLOT::U64),
))
.await
.unwrap()
.data;
let mut amount_of_slots_back: u64 = 0;

// bootstrap contains the current sync committee for the given height
CometblsDataMsg::Bootstrap(BootstrapData {
slot,
bootstrap: evm
let floored_slot = slot / (C::SLOTS_PER_EPOCH::U64 * C::SECONDS_PER_SLOT::U64)
* (C::SLOTS_PER_EPOCH::U64 * C::SECONDS_PER_SLOT::U64);

let bootstrap = loop {
let header_response = evm
.beacon_api_client
.bootstrap(currently_trusted_block.root.clone())
.await
.unwrap()
.data,
})
.header(beacon_api::client::BlockId::Slot(
floored_slot - amount_of_slots_back,
))
.await;

let header = match dbg!(header_response) {
Ok(header) => header,
Err(beacon_api::errors::Error::NotFound(NotFoundError {
status_code: _,
error: _,
message,
})) if message.starts_with("No block found for id") => {
amount_of_slots_back += 1;
continue;
}

Err(err) => panic!("{err}"),
};

let bootstrap_response = evm
.beacon_api_client
.bootstrap(header.data.root.clone())
.await;

match bootstrap_response {
Ok(ok) => break ok.data,
Err(err) => match err {
beacon_api::errors::Error::Internal(InternalServerError {
status_code: _,
error: _,
message,
}) if message.starts_with("syncCommitteeWitness not available") => {
amount_of_slots_back += 1;
}
_ => panic!("{err}"),
},
};
};

// bootstrap contains the current sync committee for the given height
CometblsDataMsg::Bootstrap(BootstrapData { slot, bootstrap })
}
CometblsFetchMsg::FetchAccountUpdate(FetchAccountUpdate { slot, __marker: _ }) => {
let execution_height = evm
Expand Down
21 changes: 18 additions & 3 deletions voyager/src/queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,19 +115,34 @@ impl Voyager {
let chain_id = c.chain_id.clone();
assert!(union.insert(c.chain_id.clone(), c).is_none());

tracing::info!("registered chain {chain_name} (chain id {chain_id})");
tracing::info!(
chain_name,
chain_id,
chain_type = "Union",
"registered chain"
);
}
AnyChain::EvmMainnet(c) => {
let chain_id = c.chain_id;
assert!(evm_mainnet.insert(c.chain_id, c).is_none());

tracing::info!("registered chain {chain_name} (chain id {chain_id})");
tracing::info!(
chain_name,
%chain_id,
chain_type = "EvmMainnet",
"registered chain"
);
}
AnyChain::EvmMinimal(c) => {
let chain_id = c.chain_id;
assert!(evm_minimal.insert(c.chain_id, c).is_none());

tracing::info!("registered chain {chain_name} (chain id {chain_id})");
tracing::info!(
chain_name,
%chain_id,
chain_type = "EvmMinimal",
"registered chain"
);
}
}
}
Expand Down

0 comments on commit 4accd1f

Please sign in to comment.