Persist light client updates (#5545)

* persist light client updates

* update beacon chain to serve light client updates

* resolve todos

* cache best update

* extend cache parts

* is better light client update

* resolve merge conflict

* initial api changes

* add lc update db column

* fmt

* added tests

* add sim

* Merge branch 'unstable' of https://github.com/sigp/lighthouse into persist-light-client-updates

* fix some weird issues with the simulator

* tests

* Merge branch 'unstable' of https://github.com/sigp/lighthouse into persist-light-client-updates

* test changes

* merge conflict

* testing

* started work on ef tests and some code clean up

* update tests

* linting

* noop pre altair, were still failing on electra though

* allow for zeroed light client header

* Merge branch 'unstable' of https://github.com/sigp/lighthouse into persist-light-client-updates

* merge unstable

* remove unwraps

* remove unwraps

* Update light_client_update.rs

* merge unstable

* move functionality to helper methods

* refactor is best update fn

* refactor is best update fn

* improve organization of light client server cache logic

* fork diget calc, and only spawn as many blcoks as we need for the lc update test

* fetch lc update from the cache if it exists

* fmt

* Fix beacon_chain tests

* Add debug code to update ranking_order ef test

* Fix compare code

* merge conflicts

* fix test

* Merge branch 'persist-light-client-updates' of https://github.com/eserilev/lighthouse into persist-light-client-updates

* Use blinded blocks for light client proofs

* fix ef test

* merge conflicts

* fix lc update check

* Lint

* resolve merge conflict

* Merge branch 'persist-light-client-updates' of https://github.com/eserilev/lighthouse into persist-light-client-updates

* revert basic sim

* small fix

* revert sim

* Review PR

* resolve merge conflicts

* Merge branch 'unstable' into persist-light-client-updates
This commit is contained in:
Eitan Seri-Levi
2024-08-09 00:36:20 -07:00
committed by GitHub
parent aad8727f52
commit 3913ea44c6
21 changed files with 1124 additions and 124 deletions

View File

@@ -0,0 +1,110 @@
use super::*;
use decode::ssz_decode_light_client_update;
use serde::Deserialize;
use types::{LightClientUpdate, Slot};
#[derive(Debug, Clone, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct LightClientVerifyIsBetterUpdate<E: EthSpec> {
light_client_updates: Vec<LightClientUpdate<E>>,
}
#[derive(Debug, Clone, Default, Deserialize)]
pub struct Metadata {
updates_count: u64,
}
impl<E: EthSpec> LoadCase for LightClientVerifyIsBetterUpdate<E> {
fn load_from_dir(path: &Path, fork_name: ForkName) -> Result<Self, Error> {
let mut light_client_updates = vec![];
let metadata: Metadata = decode::yaml_decode_file(path.join("meta.yaml").as_path())?;
for index in 0..metadata.updates_count {
let light_client_update = ssz_decode_light_client_update(
&path.join(format!("updates_{}.ssz_snappy", index)),
&fork_name,
)?;
light_client_updates.push(light_client_update);
}
Ok(Self {
light_client_updates,
})
}
}
impl<E: EthSpec> Case for LightClientVerifyIsBetterUpdate<E> {
// Light client updates in `self.light_client_updates` are ordered in descending precedence
// where the update at index = 0 is considered the best update. This test iterates through
// all light client updates in a nested loop to make all possible comparisons. If a light client update
// at index `i`` is considered 'better' than a light client update at index `j`` when `i > j`, this test fails.
fn result(&self, _case_index: usize, fork_name: ForkName) -> Result<(), Error> {
let spec = fork_name.make_genesis_spec(E::default_spec());
for (i, ith_light_client_update) in self.light_client_updates.iter().enumerate() {
for (j, jth_light_client_update) in self.light_client_updates.iter().enumerate() {
eprintln!("{i} {j}");
if i == j {
continue;
}
let is_better_update = ith_light_client_update
.is_better_light_client_update(jth_light_client_update, &spec)
.unwrap();
let ith_summary =
LightClientUpdateSummary::from_update(ith_light_client_update, &spec);
let jth_summary =
LightClientUpdateSummary::from_update(jth_light_client_update, &spec);
let (best_index, other_index, best_update, other_update, failed) = if i < j {
// i is better, so is_better_update must return false
(i, j, ith_summary, jth_summary, is_better_update)
} else {
// j is better, so is_better must return true
(j, i, jth_summary, ith_summary, !is_better_update)
};
if failed {
eprintln!("is_better_update: {is_better_update}");
eprintln!("index {best_index} update {best_update:?}");
eprintln!("index {other_index} update {other_update:?}");
eprintln!(
"update at index {best_index} must be considered better than update at index {other_index}"
);
return Err(Error::FailedComparison(format!(
"update at index {best_index} must be considered better than update at index {other_index}"
)));
}
}
}
Ok(())
}
}
#[derive(Debug)]
#[allow(dead_code)]
struct LightClientUpdateSummary {
participants: usize,
supermajority: bool,
relevant_sync_committee: bool,
has_finality: bool,
has_sync_committee_finality: bool,
header_slot: Slot,
signature_slot: Slot,
}
impl LightClientUpdateSummary {
fn from_update<E: EthSpec>(update: &LightClientUpdate<E>, spec: &ChainSpec) -> Self {
let max_participants = update.sync_aggregate().sync_committee_bits.len();
let participants = update.sync_aggregate().sync_committee_bits.num_set_bits();
Self {
participants,
supermajority: participants * 3 > max_participants * 2,
relevant_sync_committee: update.is_sync_committee_update(spec).unwrap(),
has_finality: !update.is_finality_branch_empty(),
has_sync_committee_finality: update.has_sync_committee_finality(spec).unwrap(),
header_slot: update.attested_header_slot(),
signature_slot: *update.signature_slot(),
}
}
}