mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-31 13:17:09 +00:00
Sidecar inclusion proof (#4900)
* Refactor BlobSidecar to new type * Fix some compile errors * Gossip verification compiles * Fix http api types take 1 * Fix another round of compile errors * Beacon node crate compiles * EF tests compile * Remove all blob signing from VC * fmt * Tests compile * Fix some tests * Fix more http tests * get compiling * Fix gossip conditions and tests * Add basic proof generation and verification * remove unnecessary ssz decode * add back build_sidecar * remove default at fork for blobs * fix beacon chain tests * get relase tests compiling * fix lints * fix existing spec tests * add new ef tests * fix gossip duplicate rule * lints * add back sidecar signature check in gossip * add finalized descendant check to blob sidecar gossip * fix error conversion * fix release tests * sidecar inclusion self review cleanup * Add proof verification and computation metrics * Remove accidentally committed file * Unify some block and blob errors; add slashing conditions for sidecars * Address review comment * Clean up re-org tests (#4957) * Address more review comments * Add Comments & Eliminate Unnecessary Clones * update names * Update beacon_node/beacon_chain/src/metrics.rs Co-authored-by: Jimmy Chen <jchen.tc@gmail.com> * Update beacon_node/network/src/network_beacon_processor/tests.rs Co-authored-by: Jimmy Chen <jchen.tc@gmail.com> * pr feedback * fix test compile * Sidecar Inclusion proof small refactor and updates (#4967) * Update some comments, variables and small cosmetic fixes. * Couple blobs and proofs into a tuple in `PayloadAndBlobs` for simplicity and safety. * Update function comment. * Update testing/ef_tests/src/cases/merkle_proof_validity.rs Co-authored-by: Jimmy Chen <jchen.tc@gmail.com> * Rename the block and blob wrapper types used in the beacon API interfaces. * make sure gossip invalid blobs are passed to the slasher (#4970) * Add blob headers to slasher before adding to DA checker * Replace Vec with HashSet in BlockQueue * fmt * Rename gindex -> index * Simplify gossip condition --------- Co-authored-by: realbigsean <seananderson33@gmail.com> Co-authored-by: realbigsean <sean@sigmaprime.io> Co-authored-by: Michael Sproul <michael@sigmaprime.io> Co-authored-by: Mark Mackey <mark@sigmaprime.io> Co-authored-by: Jimmy Chen <jchen.tc@gmail.com>
This commit is contained in:
@@ -1,6 +1,11 @@
|
||||
use super::*;
|
||||
use crate::decode::{ssz_decode_file, ssz_decode_file_with, ssz_decode_state, yaml_decode_file};
|
||||
use ::fork_choice::PayloadVerificationStatus;
|
||||
use ::fork_choice::{PayloadVerificationStatus, ProposerHeadError};
|
||||
use beacon_chain::beacon_proposer_cache::compute_proposer_duties_from_head;
|
||||
use beacon_chain::blob_verification::GossipBlobError;
|
||||
use beacon_chain::chain_config::{
|
||||
DisallowedReOrgOffsets, DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, DEFAULT_RE_ORG_THRESHOLD,
|
||||
};
|
||||
use beacon_chain::slot_clock::SlotClock;
|
||||
use beacon_chain::{
|
||||
attestation_verification::{
|
||||
@@ -20,7 +25,7 @@ use std::time::Duration;
|
||||
use types::{
|
||||
Attestation, AttesterSlashing, BeaconBlock, BeaconState, BlobSidecar, BlobsList, Checkpoint,
|
||||
EthSpec, ExecutionBlockHash, ForkName, Hash256, IndexedAttestation, KzgProof,
|
||||
ProgressiveBalancesMode, Signature, SignedBeaconBlock, SignedBlobSidecar, Slot, Uint256,
|
||||
ProgressiveBalancesMode, ProposerPreparationData, SignedBeaconBlock, Slot, Uint256,
|
||||
};
|
||||
|
||||
#[derive(Default, Debug, PartialEq, Clone, Deserialize, Decode)]
|
||||
@@ -38,6 +43,13 @@ pub struct Head {
|
||||
root: Hash256,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ShouldOverrideFcu {
|
||||
validator_is_connected: bool,
|
||||
result: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Checks {
|
||||
@@ -50,6 +62,8 @@ pub struct Checks {
|
||||
u_justified_checkpoint: Option<Checkpoint>,
|
||||
u_finalized_checkpoint: Option<Checkpoint>,
|
||||
proposer_boost_root: Option<Hash256>,
|
||||
get_proposer_head: Option<Hash256>,
|
||||
should_override_forkchoice_update: Option<ShouldOverrideFcu>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
@@ -256,6 +270,8 @@ impl<E: EthSpec> Case for ForkChoiceTest<E> {
|
||||
u_justified_checkpoint,
|
||||
u_finalized_checkpoint,
|
||||
proposer_boost_root,
|
||||
get_proposer_head,
|
||||
should_override_forkchoice_update: should_override_fcu,
|
||||
} = checks.as_ref();
|
||||
|
||||
if let Some(expected_head) = head {
|
||||
@@ -294,6 +310,14 @@ impl<E: EthSpec> Case for ForkChoiceTest<E> {
|
||||
if let Some(expected_proposer_boost_root) = proposer_boost_root {
|
||||
tester.check_expected_proposer_boost_root(*expected_proposer_boost_root)?;
|
||||
}
|
||||
|
||||
if let Some(should_override_fcu) = should_override_fcu {
|
||||
tester.check_should_override_fcu(*should_override_fcu)?;
|
||||
}
|
||||
|
||||
if let Some(expected_proposer_head) = get_proposer_head {
|
||||
tester.check_expected_proposer_head(*expected_proposer_head)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -325,6 +349,7 @@ impl<E: EthSpec> Tester<E> {
|
||||
}
|
||||
|
||||
let harness = BeaconChainHarness::<EphemeralHarnessType<E>>::builder(E::default())
|
||||
.logger(logging::test_logger())
|
||||
.spec(spec.clone())
|
||||
.keypairs(vec![])
|
||||
.chain_config(ChainConfig {
|
||||
@@ -413,6 +438,8 @@ impl<E: EthSpec> Tester<E> {
|
||||
) -> Result<(), Error> {
|
||||
let block_root = block.canonical_root();
|
||||
|
||||
let mut blob_success = true;
|
||||
|
||||
// Convert blobs and kzg_proofs into sidecars, then plumb them into the availability tracker
|
||||
if let Some(blobs) = blobs.clone() {
|
||||
let proofs = kzg_proofs.unwrap();
|
||||
@@ -432,25 +459,32 @@ impl<E: EthSpec> Tester<E> {
|
||||
.zip(commitments.into_iter())
|
||||
.enumerate()
|
||||
{
|
||||
let signed_sidecar = SignedBlobSidecar {
|
||||
message: Arc::new(BlobSidecar {
|
||||
block_root,
|
||||
index: i as u64,
|
||||
slot: block.slot(),
|
||||
block_parent_root: block.parent_root(),
|
||||
proposer_index: block.message().proposer_index(),
|
||||
blob,
|
||||
kzg_commitment,
|
||||
kzg_proof,
|
||||
}),
|
||||
signature: Signature::empty(),
|
||||
_phantom: Default::default(),
|
||||
};
|
||||
let result = self.block_on_dangerous(
|
||||
self.harness
|
||||
.chain
|
||||
.process_gossip_blob(GossipVerifiedBlob::__assumed_valid(signed_sidecar)),
|
||||
)?;
|
||||
let blob_sidecar = Arc::new(BlobSidecar {
|
||||
index: i as u64,
|
||||
blob,
|
||||
kzg_commitment,
|
||||
kzg_proof,
|
||||
signed_block_header: block.signed_block_header(),
|
||||
kzg_commitment_inclusion_proof: block
|
||||
.message()
|
||||
.body()
|
||||
.kzg_commitment_merkle_proof(i)
|
||||
.unwrap(),
|
||||
});
|
||||
|
||||
let chain = self.harness.chain.clone();
|
||||
let blob =
|
||||
match GossipVerifiedBlob::new(blob_sidecar.clone(), blob_sidecar.index, &chain)
|
||||
{
|
||||
Ok(gossip_verified_blob) => gossip_verified_blob,
|
||||
Err(GossipBlobError::KzgError(_)) => {
|
||||
blob_success = false;
|
||||
GossipVerifiedBlob::__assumed_valid(blob_sidecar)
|
||||
}
|
||||
Err(_) => GossipVerifiedBlob::__assumed_valid(blob_sidecar),
|
||||
};
|
||||
let result =
|
||||
self.block_on_dangerous(self.harness.chain.process_gossip_blob(blob))?;
|
||||
if valid {
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
@@ -466,7 +500,7 @@ impl<E: EthSpec> Tester<E> {
|
||||
|| Ok(()),
|
||||
))?
|
||||
.map(|avail: AvailabilityProcessingStatus| avail.try_into());
|
||||
let success = result.as_ref().map_or(false, |inner| inner.is_ok());
|
||||
let success = blob_success && result.as_ref().map_or(false, |inner| inner.is_ok());
|
||||
if success != valid {
|
||||
return Err(Error::DidntFail(format!(
|
||||
"block with root {} was valid={} whilst test expects valid={}. result: {:?}",
|
||||
@@ -703,6 +737,82 @@ impl<E: EthSpec> Tester<E> {
|
||||
expected_proposer_boost_root,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn check_expected_proposer_head(
|
||||
&self,
|
||||
expected_proposer_head: Hash256,
|
||||
) -> Result<(), Error> {
|
||||
let mut fc = self.harness.chain.canonical_head.fork_choice_write_lock();
|
||||
let slot = self.harness.chain.slot().unwrap();
|
||||
let canonical_head = fc.get_head(slot, &self.harness.spec).unwrap();
|
||||
let proposer_head_result = fc.get_proposer_head(
|
||||
slot,
|
||||
canonical_head,
|
||||
DEFAULT_RE_ORG_THRESHOLD,
|
||||
&DisallowedReOrgOffsets::default(),
|
||||
DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION,
|
||||
);
|
||||
let proposer_head = match proposer_head_result {
|
||||
Ok(head) => head.parent_node.root,
|
||||
Err(ProposerHeadError::DoNotReOrg(_)) => canonical_head,
|
||||
_ => panic!("Unexpected error in get proposer head"),
|
||||
};
|
||||
|
||||
check_equal("proposer_head", proposer_head, expected_proposer_head)
|
||||
}
|
||||
|
||||
pub fn check_should_override_fcu(
|
||||
&self,
|
||||
expected_should_override_fcu: ShouldOverrideFcu,
|
||||
) -> Result<(), Error> {
|
||||
// Determine proposer.
|
||||
let cached_head = self.harness.chain.canonical_head.cached_head();
|
||||
let next_slot = cached_head.snapshot.beacon_block.slot() + 1;
|
||||
let next_slot_epoch = next_slot.epoch(E::slots_per_epoch());
|
||||
let (proposer_indices, decision_root, _, fork) =
|
||||
compute_proposer_duties_from_head(next_slot_epoch, &self.harness.chain).unwrap();
|
||||
let proposer_index = proposer_indices[next_slot.as_usize() % E::slots_per_epoch() as usize];
|
||||
|
||||
// Ensure the proposer index cache is primed.
|
||||
self.harness
|
||||
.chain
|
||||
.beacon_proposer_cache
|
||||
.lock()
|
||||
.insert(next_slot_epoch, decision_root, proposer_indices, fork)
|
||||
.unwrap();
|
||||
|
||||
// Update the execution layer proposer preparation to match the test config.
|
||||
let el = self.harness.chain.execution_layer.clone().unwrap();
|
||||
self.block_on_dangerous(async {
|
||||
if expected_should_override_fcu.validator_is_connected {
|
||||
el.update_proposer_preparation(
|
||||
next_slot_epoch,
|
||||
&[ProposerPreparationData {
|
||||
validator_index: dbg!(proposer_index) as u64,
|
||||
fee_recipient: Default::default(),
|
||||
}],
|
||||
)
|
||||
.await;
|
||||
} else {
|
||||
el.clear_proposer_preparation(proposer_index as u64).await;
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
// Check forkchoice override.
|
||||
let canonical_fcu_params = cached_head.forkchoice_update_parameters();
|
||||
let fcu_params = self
|
||||
.harness
|
||||
.chain
|
||||
.overridden_forkchoice_update_params(canonical_fcu_params)
|
||||
.unwrap();
|
||||
|
||||
check_equal(
|
||||
"should_override_forkchoice_update",
|
||||
fcu_params != canonical_fcu_params,
|
||||
expected_should_override_fcu.result,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that the `head` checkpoint from the beacon chain head matches the `fc` checkpoint gleaned
|
||||
|
||||
Reference in New Issue
Block a user