mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-14 10:22:38 +00:00
API for LightClientBootstrap, LightClientFinalityUpdate, LightClientOptimisticUpdate and light client events (#3954)
* rebase and add comment * conditional test * test * optimistic chould be working now * finality should be working now * try again * try again * clippy fix * add lc bootstrap beacon api * add lc optimistic/finality update to events * fmt * That error isn't occuring on my computer but I think this should fix it * Add missing test file * Update light client types to comply with Altair light client spec. * Fix test compilation * Support deserializing light client structures for the Bellatrix fork * Move `get_light_client_bootstrap` logic to `BeaconChain`. `LightClientBootstrap` API to return `ForkVersionedResponse`. * Misc fixes. - log cleanup - move http_api config mutation to `config::get_config` for consistency - fix light client API responses * Add light client bootstrap API test and fix existing ones. * Fix test for `light-client-server` http api config. * Appease clippy * Efficiency improvement when retrieving beacon state. --------- Co-authored-by: Jimmy Chen <jchen.tc@gmail.com>
This commit is contained in:
@@ -99,6 +99,7 @@ pub mod slot_data;
|
||||
pub mod sqlite;
|
||||
|
||||
pub mod blob_sidecar;
|
||||
pub mod light_client_header;
|
||||
pub mod sidecar;
|
||||
pub mod signed_blob;
|
||||
|
||||
@@ -154,8 +155,11 @@ pub use crate::fork_versioned_response::{ForkVersionDeserialize, ForkVersionedRe
|
||||
pub use crate::graffiti::{Graffiti, GRAFFITI_BYTES_LEN};
|
||||
pub use crate::historical_batch::HistoricalBatch;
|
||||
pub use crate::indexed_attestation::IndexedAttestation;
|
||||
pub use crate::light_client_bootstrap::LightClientBootstrap;
|
||||
pub use crate::light_client_finality_update::LightClientFinalityUpdate;
|
||||
pub use crate::light_client_header::LightClientHeader;
|
||||
pub use crate::light_client_optimistic_update::LightClientOptimisticUpdate;
|
||||
pub use crate::light_client_update::{Error as LightClientError, LightClientUpdate};
|
||||
pub use crate::participation_flags::ParticipationFlags;
|
||||
pub use crate::participation_list::ParticipationList;
|
||||
pub use crate::payload::{
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
use super::{BeaconBlockHeader, BeaconState, EthSpec, FixedVector, Hash256, SyncCommittee};
|
||||
use crate::{light_client_update::*, test_utils::TestRandom};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use super::{BeaconState, EthSpec, FixedVector, Hash256, SyncCommittee};
|
||||
use crate::{
|
||||
light_client_update::*, test_utils::TestRandom, ForkName, ForkVersionDeserialize,
|
||||
LightClientHeader,
|
||||
};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use serde_json::Value;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::sync::Arc;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::TreeHash;
|
||||
|
||||
/// A LightClientBootstrap is the initializer we send over to lightclient nodes
|
||||
/// that are trying to generate their basic storage when booting up.
|
||||
@@ -22,8 +25,8 @@ use tree_hash::TreeHash;
|
||||
#[serde(bound = "T: EthSpec")]
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct LightClientBootstrap<T: EthSpec> {
|
||||
/// Requested beacon block header.
|
||||
pub header: BeaconBlockHeader,
|
||||
/// The requested beacon block header.
|
||||
pub header: LightClientHeader,
|
||||
/// The `SyncCommittee` used in the requested period.
|
||||
pub current_sync_committee: Arc<SyncCommittee<T>>,
|
||||
/// Merkle proof for sync committee
|
||||
@@ -33,17 +36,37 @@ pub struct LightClientBootstrap<T: EthSpec> {
|
||||
impl<T: EthSpec> LightClientBootstrap<T> {
|
||||
pub fn from_beacon_state(beacon_state: &mut BeaconState<T>) -> Result<Self, Error> {
|
||||
let mut header = beacon_state.latest_block_header().clone();
|
||||
header.state_root = beacon_state.tree_hash_root();
|
||||
header.state_root = beacon_state.update_tree_hash_cache()?;
|
||||
let current_sync_committee_branch =
|
||||
beacon_state.compute_merkle_proof(CURRENT_SYNC_COMMITTEE_INDEX)?;
|
||||
Ok(LightClientBootstrap {
|
||||
header,
|
||||
header: header.into(),
|
||||
current_sync_committee: beacon_state.current_sync_committee()?.clone(),
|
||||
current_sync_committee_branch: FixedVector::new(current_sync_committee_branch)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ForkVersionDeserialize for LightClientBootstrap<T> {
|
||||
fn deserialize_by_fork<'de, D: Deserializer<'de>>(
|
||||
value: Value,
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, D::Error> {
|
||||
match fork_name {
|
||||
ForkName::Altair | ForkName::Merge => {
|
||||
Ok(serde_json::from_value::<LightClientBootstrap<T>>(value)
|
||||
.map_err(serde::de::Error::custom))?
|
||||
}
|
||||
ForkName::Base | ForkName::Capella | ForkName::Deneb => {
|
||||
Err(serde::de::Error::custom(format!(
|
||||
"LightClientBootstrap failed to deserialize: unsupported fork '{}'",
|
||||
fork_name
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
use super::{
|
||||
BeaconBlockHeader, EthSpec, FixedVector, Hash256, SignedBeaconBlock, SignedBlindedBeaconBlock,
|
||||
Slot, SyncAggregate,
|
||||
EthSpec, FixedVector, Hash256, SignedBeaconBlock, SignedBlindedBeaconBlock, Slot, SyncAggregate,
|
||||
};
|
||||
use crate::{light_client_update::*, test_utils::TestRandom, BeaconState, ChainSpec};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
light_client_update::*, test_utils::TestRandom, BeaconState, ChainSpec, ForkName,
|
||||
ForkVersionDeserialize, LightClientHeader,
|
||||
};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use serde_json::Value;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::TreeHash;
|
||||
@@ -25,9 +28,9 @@ use tree_hash::TreeHash;
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct LightClientFinalityUpdate<T: EthSpec> {
|
||||
/// The last `BeaconBlockHeader` from the last attested block by the sync committee.
|
||||
pub attested_header: BeaconBlockHeader,
|
||||
pub attested_header: LightClientHeader,
|
||||
/// The last `BeaconBlockHeader` from the last attested finalized block (end of epoch).
|
||||
pub finalized_header: BeaconBlockHeader,
|
||||
pub finalized_header: LightClientHeader,
|
||||
/// Merkle proof attesting finalized header.
|
||||
pub finality_branch: FixedVector<Hash256, FinalizedRootProofLen>,
|
||||
/// current sync aggreggate
|
||||
@@ -68,8 +71,8 @@ impl<T: EthSpec> LightClientFinalityUpdate<T> {
|
||||
|
||||
let finality_branch = attested_state.compute_merkle_proof(FINALIZED_ROOT_INDEX)?;
|
||||
Ok(Self {
|
||||
attested_header,
|
||||
finalized_header,
|
||||
attested_header: attested_header.into(),
|
||||
finalized_header: finalized_header.into(),
|
||||
finality_branch: FixedVector::new(finality_branch)?,
|
||||
sync_aggregate: sync_aggregate.clone(),
|
||||
signature_slot: block.slot(),
|
||||
@@ -77,6 +80,26 @@ impl<T: EthSpec> LightClientFinalityUpdate<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ForkVersionDeserialize for LightClientFinalityUpdate<T> {
|
||||
fn deserialize_by_fork<'de, D: Deserializer<'de>>(
|
||||
value: Value,
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, D::Error> {
|
||||
match fork_name {
|
||||
ForkName::Altair | ForkName::Merge => Ok(serde_json::from_value::<
|
||||
LightClientFinalityUpdate<T>,
|
||||
>(value)
|
||||
.map_err(serde::de::Error::custom))?,
|
||||
ForkName::Base | ForkName::Capella | ForkName::Deneb => {
|
||||
Err(serde::de::Error::custom(format!(
|
||||
"LightClientFinalityUpdate failed to deserialize: unsupported fork '{}'",
|
||||
fork_name
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
26
consensus/types/src/light_client_header.rs
Normal file
26
consensus/types/src/light_client_header.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::BeaconBlockHeader;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TestRandom,
|
||||
arbitrary::Arbitrary,
|
||||
)]
|
||||
pub struct LightClientHeader {
|
||||
pub beacon: BeaconBlockHeader,
|
||||
}
|
||||
|
||||
impl From<BeaconBlockHeader> for LightClientHeader {
|
||||
fn from(beacon: BeaconBlockHeader) -> Self {
|
||||
LightClientHeader { beacon }
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
use super::{BeaconBlockHeader, EthSpec, Slot, SyncAggregate};
|
||||
use super::{EthSpec, ForkName, ForkVersionDeserialize, Slot, SyncAggregate};
|
||||
use crate::light_client_header::LightClientHeader;
|
||||
use crate::{
|
||||
light_client_update::Error, test_utils::TestRandom, BeaconState, ChainSpec, SignedBeaconBlock,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use serde_json::Value;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::TreeHash;
|
||||
@@ -24,7 +26,7 @@ use tree_hash::TreeHash;
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct LightClientOptimisticUpdate<T: EthSpec> {
|
||||
/// The last `BeaconBlockHeader` from the last attested block by the sync committee.
|
||||
pub attested_header: BeaconBlockHeader,
|
||||
pub attested_header: LightClientHeader,
|
||||
/// current sync aggreggate
|
||||
pub sync_aggregate: SyncAggregate<T>,
|
||||
/// Slot of the sync aggregated singature
|
||||
@@ -53,13 +55,33 @@ impl<T: EthSpec> LightClientOptimisticUpdate<T> {
|
||||
let mut attested_header = attested_state.latest_block_header().clone();
|
||||
attested_header.state_root = attested_state.tree_hash_root();
|
||||
Ok(Self {
|
||||
attested_header,
|
||||
attested_header: attested_header.into(),
|
||||
sync_aggregate: sync_aggregate.clone(),
|
||||
signature_slot: block.slot(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ForkVersionDeserialize for LightClientOptimisticUpdate<T> {
|
||||
fn deserialize_by_fork<'de, D: Deserializer<'de>>(
|
||||
value: Value,
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, D::Error> {
|
||||
match fork_name {
|
||||
ForkName::Altair | ForkName::Merge => Ok(serde_json::from_value::<
|
||||
LightClientOptimisticUpdate<T>,
|
||||
>(value)
|
||||
.map_err(serde::de::Error::custom))?,
|
||||
ForkName::Base | ForkName::Capella | ForkName::Deneb => {
|
||||
Err(serde::de::Error::custom(format!(
|
||||
"LightClientOptimisticUpdate failed to deserialize: unsupported fork '{}'",
|
||||
fork_name
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
use super::{BeaconBlockHeader, EthSpec, FixedVector, Hash256, Slot, SyncAggregate, SyncCommittee};
|
||||
use crate::{beacon_state, test_utils::TestRandom, BeaconBlock, BeaconState, ChainSpec};
|
||||
use crate::{
|
||||
beacon_state, test_utils::TestRandom, BeaconBlock, BeaconState, ChainSpec, ForkName,
|
||||
ForkVersionDeserialize, LightClientHeader,
|
||||
};
|
||||
use safe_arith::ArithError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use serde_json::Value;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use ssz_types::typenum::{U5, U6};
|
||||
use std::sync::Arc;
|
||||
@@ -67,13 +71,13 @@ impl From<ArithError> for Error {
|
||||
#[arbitrary(bound = "T: EthSpec")]
|
||||
pub struct LightClientUpdate<T: EthSpec> {
|
||||
/// The last `BeaconBlockHeader` from the last attested block by the sync committee.
|
||||
pub attested_header: BeaconBlockHeader,
|
||||
pub attested_header: LightClientHeader,
|
||||
/// The `SyncCommittee` used in the next period.
|
||||
pub next_sync_committee: Arc<SyncCommittee<T>>,
|
||||
/// Merkle proof for next sync committee
|
||||
pub next_sync_committee_branch: FixedVector<Hash256, NextSyncCommitteeProofLen>,
|
||||
/// The last `BeaconBlockHeader` from the last attested finalized block (end of epoch).
|
||||
pub finalized_header: BeaconBlockHeader,
|
||||
pub finalized_header: LightClientHeader,
|
||||
/// Merkle proof attesting finalized header.
|
||||
pub finality_branch: FixedVector<Hash256, FinalizedRootProofLen>,
|
||||
/// current sync aggreggate
|
||||
@@ -128,10 +132,10 @@ impl<T: EthSpec> LightClientUpdate<T> {
|
||||
attested_state.compute_merkle_proof(NEXT_SYNC_COMMITTEE_INDEX)?;
|
||||
let finality_branch = attested_state.compute_merkle_proof(FINALIZED_ROOT_INDEX)?;
|
||||
Ok(Self {
|
||||
attested_header,
|
||||
attested_header: attested_header.into(),
|
||||
next_sync_committee: attested_state.next_sync_committee()?.clone(),
|
||||
next_sync_committee_branch: FixedVector::new(next_sync_committee_branch)?,
|
||||
finalized_header,
|
||||
finalized_header: finalized_header.into(),
|
||||
finality_branch: FixedVector::new(finality_branch)?,
|
||||
sync_aggregate: sync_aggregate.clone(),
|
||||
signature_slot: block.slot(),
|
||||
@@ -139,6 +143,26 @@ impl<T: EthSpec> LightClientUpdate<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ForkVersionDeserialize for LightClientUpdate<T> {
|
||||
fn deserialize_by_fork<'de, D: Deserializer<'de>>(
|
||||
value: Value,
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, D::Error> {
|
||||
match fork_name {
|
||||
ForkName::Altair | ForkName::Merge => {
|
||||
Ok(serde_json::from_value::<LightClientUpdate<T>>(value)
|
||||
.map_err(serde::de::Error::custom))?
|
||||
}
|
||||
ForkName::Base | ForkName::Capella | ForkName::Deneb => {
|
||||
Err(serde::de::Error::custom(format!(
|
||||
"LightClientUpdate failed to deserialize: unsupported fork '{}'",
|
||||
fork_name
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::typenum::Unsigned;
|
||||
use crate::{EthSpec, FixedVector, SyncSubnetId};
|
||||
use bls::PublicKeyBytes;
|
||||
use safe_arith::{ArithError, SafeArith};
|
||||
@@ -46,14 +45,11 @@ pub struct SyncCommittee<T: EthSpec> {
|
||||
|
||||
impl<T: EthSpec> SyncCommittee<T> {
|
||||
/// Create a temporary sync committee that should *never* be included in a legitimate consensus object.
|
||||
pub fn temporary() -> Result<Self, ssz_types::Error> {
|
||||
Ok(Self {
|
||||
pubkeys: FixedVector::new(vec![
|
||||
PublicKeyBytes::empty();
|
||||
T::SyncCommitteeSize::to_usize()
|
||||
])?,
|
||||
pub fn temporary() -> Self {
|
||||
Self {
|
||||
pubkeys: FixedVector::from_elem(PublicKeyBytes::empty()),
|
||||
aggregate_pubkey: PublicKeyBytes::empty(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the pubkeys in this `SyncCommittee` for the given `subcommittee_index`.
|
||||
|
||||
Reference in New Issue
Block a user