Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion beacon_node/http_api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ mod block_rewards;
mod build_block_contents;
mod builder_states;
mod database;
mod light_client;
mod metrics;
mod proposer_duties;
mod publish_blocks;
Expand Down Expand Up @@ -76,7 +77,7 @@ use tokio_stream::{
use types::{
Attestation, AttestationData, AttestationShufflingId, AttesterSlashing, BeaconStateError,
BlindedPayload, CommitteeCache, ConfigAndPreset, Epoch, EthSpec, ForkName, FullPayload,
ProposerPreparationData, ProposerSlashing, RelativeEpoch, SignedAggregateAndProof,
Hash256, ProposerPreparationData, ProposerSlashing, RelativeEpoch, SignedAggregateAndProof,
SignedBlsToExecutionChange, SignedContributionAndProof, SignedValidatorRegistrationData,
SignedVoluntaryExit, Slot, SyncCommitteeMessage, SyncContributionData,
};
Expand Down Expand Up @@ -2470,6 +2471,37 @@ pub fn serve<T: BeaconChainTypes>(
},
);

/*
* light client
*/

let light_client_path = eth_v1
.and(warp::path("beacon"))
.and(warp::path("light_client"))
.and(task_spawner_filter.clone())
.and(chain_filter.clone());

let get_light_client_bootstrap = light_client_path
.and(warp::path("bootstrap"))
.and(warp::path::param::<Hash256>())
.and(warp::path::end())
.and(warp::header::optional::<api_types::Accept>("accept"))
.then(
|task_spawner: TaskSpawner<T::EthSpec>,
chain: Arc<BeaconChain<T>>,
block_root: Hash256,
accept_header: Option<api_types::Accept>| {
task_spawner.spawn_async_with_rejection(Priority::P1, async move {
light_client::get_light_client_bootstrap::<T, T::EthSpec>(
chain,
block_root,
accept_header,
)
.await
})
},
);

/*
* config
*/
Expand Down Expand Up @@ -4608,6 +4640,7 @@ pub fn serve<T: BeaconChainTypes>(
.uor(get_lighthouse_merge_readiness)
.uor(get_events)
.uor(get_expected_withdrawals)
.uor(get_light_client_bootstrap)
.uor(lighthouse_log_events.boxed())
.recover(warp_utils::reject::handle_rejection),
)
Expand Down
77 changes: 77 additions & 0 deletions beacon_node/http_api/src/light_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use beacon_chain::{BeaconChain, BeaconChainTypes};
use bytes::Bytes;
use eth2::types;
use eth2::types::{self as api_types};
use slot_clock::SlotClock;
use ssz::Encode;
use std::sync::Arc;
use types::{light_client_bootstrap::LightClientBootstrap, EthSpec, Hash256};
use warp::{
hyper::{Body, Response},
Reply,
};

use crate::version::add_consensus_version_header;

pub async fn get_light_client_bootstrap<T: BeaconChainTypes, E: EthSpec>(
chain: Arc<BeaconChain<T>>,
block_root: Hash256,
accept_header: Option<api_types::Accept>,
) -> Result<Response<Body>, warp::Rejection> {
let is_altair_or_greater = chain
.spec
.altair_fork_epoch
.and_then(|fork_epoch| {
let current_epoch = chain.slot_clock.now()?.epoch(E::slots_per_epoch());
Some(current_epoch >= fork_epoch)
})
.unwrap_or(false);

if !is_altair_or_greater {
return Err(warp_utils::reject::custom_bad_request(format!(
"cannot fetch pre altair"
)));
}

let block = chain
.get_block(&block_root)
.await
.map_err(|e| {
warp_utils::reject::custom_bad_request(format!("failed to fetch beacon block: {:?}", e))
})?
.ok_or_else(|| warp_utils::reject::custom_bad_request(format!("no beacon block found")))?;

let mut state = chain
.get_state(&block.state_root(), Some(block.slot()))
.map_err(|e| {
warp_utils::reject::custom_bad_request(format!("failed to fetch beacon state: {:?}", e))
})?
.ok_or_else(|| warp_utils::reject::custom_bad_request(format!("no beacon state found")))?;

let fork_name = state.fork_name(&chain.spec).map_err(|e| {
warp_utils::reject::custom_bad_request(format!("failed to fetch fork name: {:?}", e))
})?;

let light_client_bootstrap =
LightClientBootstrap::create_light_client_bootstrap(&mut state, block).map_err(|e| {
warp_utils::reject::custom_bad_request(format!(
"failed to create light client bootstrap: {:?}",
e
))
})?;

match accept_header {
Some(_) => Response::builder()
.status(200)
.header("Content-Type", "application/octet-stream")
.body(light_client_bootstrap.as_ssz_bytes().into())
.map(|res: Response<Bytes>| add_consensus_version_header(res, fork_name))
.map_err(|e| {
warp_utils::reject::custom_server_error(format!("failed to create response: {}", e))
}),
None => Ok(add_consensus_version_header(
warp::reply::json(&light_client_bootstrap).into_response(),
fork_name,
)),
}
}
30 changes: 29 additions & 1 deletion consensus/types/src/light_client_bootstrap.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use super::{BeaconBlockHeader, BeaconState, EthSpec, FixedVector, Hash256, SyncCommittee};
use crate::{light_client_update::*, test_utils::TestRandom};
use crate::{
light_client_update::*, test_utils::TestRandom, AbstractExecPayload, Epoch, SignedBeaconBlock,
};
use serde::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use std::sync::Arc;
Expand Down Expand Up @@ -42,6 +44,32 @@ impl<T: EthSpec> LightClientBootstrap<T> {
current_sync_committee_branch: FixedVector::new(current_sync_committee_branch)?,
})
}

pub fn create_light_client_bootstrap<Payload: AbstractExecPayload<T>>(
beacon_state: &mut BeaconState<T>,
signed_beacon_block: SignedBeaconBlock<T, Payload>,
) -> Result<Self, Error> {
if beacon_state.slot() != beacon_state.latest_block_header().slot {
return Err(Error::CreateBootstrapError);
}

let mut header = beacon_state.latest_block_header().clone();

header.state_root = beacon_state.tree_hash_root();

if header.tree_hash_root() != signed_beacon_block.message().tree_hash_root() {
return Err(Error::CreateBootstrapError);
}

let current_sync_committee_branch =
beacon_state.compute_merkle_proof(CURRENT_SYNC_COMMITTEE_INDEX)?;

Ok(LightClientBootstrap {
header,
current_sync_committee: beacon_state.current_sync_committee()?.clone(),
current_sync_committee_branch: FixedVector::new(current_sync_committee_branch)?,
})
}
}

#[cfg(test)]
Expand Down
1 change: 1 addition & 0 deletions consensus/types/src/light_client_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub enum Error {
NotEnoughSyncCommitteeParticipants,
MismatchingPeriods,
InvalidFinalizedBlock,
CreateBootstrapError,
}

impl From<ssz_types::Error> for Error {
Expand Down