mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 20:57:10 +00:00
add initial IL gossip verification
This commit is contained in:
104
beacon_node/beacon_chain/src/inclusion_list_verification.rs
Normal file
104
beacon_node/beacon_chain/src/inclusion_list_verification.rs
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
use crate::{BeaconChain, BeaconChainError, BeaconChainTypes};
|
||||||
|
|
||||||
|
use slot_clock::SlotClock;
|
||||||
|
use strum::AsRefStr;
|
||||||
|
use types::{Domain, EthSpec, SignedInclusionList, SignedRoot, Slot};
|
||||||
|
|
||||||
|
#[derive(Debug, AsRefStr)]
|
||||||
|
pub enum GossipInclusionListError {
|
||||||
|
FutureSlot {
|
||||||
|
message_slot: Slot,
|
||||||
|
latest_permissible_slot: Slot,
|
||||||
|
},
|
||||||
|
PastSlot {
|
||||||
|
message_slot: Slot,
|
||||||
|
earliest_permissible_slot: Slot,
|
||||||
|
},
|
||||||
|
InvalidCommitteeRoot,
|
||||||
|
ValidatorNotInCommittee,
|
||||||
|
TooManyTransactions,
|
||||||
|
InvalidSignature,
|
||||||
|
BeaconChainError(BeaconChainError),
|
||||||
|
// TODO: equivocation e.g. PriorInclusionListKnown
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BeaconChainError> for GossipInclusionListError {
|
||||||
|
fn from(value: BeaconChainError) -> Self {
|
||||||
|
Self::BeaconChainError(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GossipVerifiedInclusionList<T: BeaconChainTypes> {
|
||||||
|
signed_il: SignedInclusionList<T::EthSpec>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BeaconChainTypes> GossipVerifiedInclusionList<T> {
|
||||||
|
pub fn verify(
|
||||||
|
signed_il: &SignedInclusionList<T::EthSpec>,
|
||||||
|
chain: &BeaconChain<T>,
|
||||||
|
) -> Result<Self, GossipInclusionListError> {
|
||||||
|
// the slot is equal to the previous slot or the current slot
|
||||||
|
let message_slot = signed_il.message.slot;
|
||||||
|
let earliest_permissible_slot = chain
|
||||||
|
.slot_clock
|
||||||
|
.now_with_past_tolerance(chain.spec.maximum_gossip_clock_disparity())
|
||||||
|
.ok_or(BeaconChainError::UnableToReadSlot)?;
|
||||||
|
if message_slot < earliest_permissible_slot {
|
||||||
|
return Err(GossipInclusionListError::PastSlot {
|
||||||
|
message_slot,
|
||||||
|
earliest_permissible_slot,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let latest_permissible_slot = chain
|
||||||
|
.slot_clock
|
||||||
|
.now_with_future_tolerance(chain.spec.maximum_gossip_clock_disparity())
|
||||||
|
.ok_or(BeaconChainError::UnableToReadSlot)?;
|
||||||
|
if message_slot > latest_permissible_slot {
|
||||||
|
return Err(GossipInclusionListError::FutureSlot {
|
||||||
|
message_slot,
|
||||||
|
latest_permissible_slot,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: the slot is equal to the current slot or the previous slot and the current time is
|
||||||
|
// not past the attestation deadline
|
||||||
|
|
||||||
|
// TODO: the IL committee root is equal to the hash tree root of the expected committee
|
||||||
|
|
||||||
|
// TODO: the validator index is contained in the committee corresponding to the committee
|
||||||
|
// root
|
||||||
|
|
||||||
|
// the transaction length is less than or equal to the specified maximum
|
||||||
|
if signed_il.message.transactions.len() > T::EthSpec::max_transactions_per_inclusion_list()
|
||||||
|
{
|
||||||
|
return Err(GossipInclusionListError::TooManyTransactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: the message is the first or second valid message received from the validator
|
||||||
|
// corresponding to the validator index
|
||||||
|
|
||||||
|
// the signature is valid w.r.t. the validator index
|
||||||
|
let epoch = chain.epoch()?;
|
||||||
|
let fork = chain.spec.fork_at_epoch(epoch);
|
||||||
|
let genesis_validators_root = chain.genesis_validators_root;
|
||||||
|
let domain = chain.spec.get_domain(
|
||||||
|
epoch,
|
||||||
|
Domain::InclusionListCommittee,
|
||||||
|
&fork,
|
||||||
|
genesis_validators_root,
|
||||||
|
);
|
||||||
|
let message = signed_il.message.signing_root(domain);
|
||||||
|
let validator_index = signed_il.message.validator_index as usize;
|
||||||
|
let pubkey = chain.validator_pubkey(validator_index)?;
|
||||||
|
let Some(pubkey) = pubkey else {
|
||||||
|
return Err(GossipInclusionListError::BeaconChainError(
|
||||||
|
BeaconChainError::ValidatorIndexUnknown(validator_index),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
signed_il.signature.verify(&pubkey, message);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
signed_il: signed_il.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ pub mod fork_revert;
|
|||||||
pub mod graffiti_calculator;
|
pub mod graffiti_calculator;
|
||||||
mod head_tracker;
|
mod head_tracker;
|
||||||
pub mod historical_blocks;
|
pub mod historical_blocks;
|
||||||
|
pub mod inclusion_list_verification;
|
||||||
pub mod kzg_utils;
|
pub mod kzg_utils;
|
||||||
pub mod light_client_finality_update_verification;
|
pub mod light_client_finality_update_verification;
|
||||||
pub mod light_client_optimistic_update_verification;
|
pub mod light_client_optimistic_update_verification;
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ use crate::{
|
|||||||
use beacon_chain::blob_verification::{GossipBlobError, GossipVerifiedBlob};
|
use beacon_chain::blob_verification::{GossipBlobError, GossipVerifiedBlob};
|
||||||
use beacon_chain::block_verification_types::AsBlock;
|
use beacon_chain::block_verification_types::AsBlock;
|
||||||
use beacon_chain::data_column_verification::{GossipDataColumnError, GossipVerifiedDataColumn};
|
use beacon_chain::data_column_verification::{GossipDataColumnError, GossipVerifiedDataColumn};
|
||||||
|
use beacon_chain::inclusion_list_verification::{
|
||||||
|
GossipInclusionListError, GossipVerifiedInclusionList,
|
||||||
|
};
|
||||||
use beacon_chain::store::Error;
|
use beacon_chain::store::Error;
|
||||||
use beacon_chain::{
|
use beacon_chain::{
|
||||||
attestation_verification::{self, Error as AttnError, VerifiedAttestation},
|
attestation_verification::{self, Error as AttnError, VerifiedAttestation},
|
||||||
@@ -36,8 +39,8 @@ use types::{
|
|||||||
DataColumnSidecar, DataColumnSubnetId, EthSpec, Hash256, IndexedAttestation,
|
DataColumnSidecar, DataColumnSubnetId, EthSpec, Hash256, IndexedAttestation,
|
||||||
LightClientFinalityUpdate, LightClientOptimisticUpdate, ProposerSlashing,
|
LightClientFinalityUpdate, LightClientOptimisticUpdate, ProposerSlashing,
|
||||||
SignedAggregateAndProof, SignedBeaconBlock, SignedBlsToExecutionChange,
|
SignedAggregateAndProof, SignedBeaconBlock, SignedBlsToExecutionChange,
|
||||||
SignedContributionAndProof, SignedVoluntaryExit, Slot, SubnetId, SyncCommitteeMessage,
|
SignedContributionAndProof, SignedInclusionList, SignedVoluntaryExit, Slot, SubnetId,
|
||||||
SyncSubnetId,
|
SyncCommitteeMessage, SyncSubnetId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use beacon_processor::{
|
use beacon_processor::{
|
||||||
@@ -2139,6 +2142,35 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn process_gossip_inclusion_list(
|
||||||
|
self: &Arc<Self>,
|
||||||
|
message_id: MessageId,
|
||||||
|
peer_id: PeerId,
|
||||||
|
il: SignedInclusionList<T::EthSpec>,
|
||||||
|
seen_timestamp: Duration,
|
||||||
|
) {
|
||||||
|
match GossipVerifiedInclusionList::verify(&il, &self.chain) {
|
||||||
|
Ok(gossip_verified_il) => {
|
||||||
|
debug!(self.log, "Successfully verified gossip inclusion list");
|
||||||
|
}
|
||||||
|
Err(err) => match err {
|
||||||
|
GossipInclusionListError::FutureSlot { .. }
|
||||||
|
| GossipInclusionListError::PastSlot { .. }
|
||||||
|
| GossipInclusionListError::ValidatorNotInCommittee
|
||||||
|
| GossipInclusionListError::TooManyTransactions
|
||||||
|
| GossipInclusionListError::InvalidSignature => {
|
||||||
|
debug!(self.log, "Could not verify inclusion list for gossip. Rejecting the inclusion list"; "error" => ?err);
|
||||||
|
}
|
||||||
|
GossipInclusionListError::InvalidCommitteeRoot => {
|
||||||
|
debug!(self.log, "Could not verify inclusion list for gossip. Ignoring the inclusion list"; "error" => ?err);
|
||||||
|
}
|
||||||
|
GossipInclusionListError::BeaconChainError(_) => {
|
||||||
|
crit!(self.log, "Internal error when verifying inclusion list"; "error" => ?err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle an error whilst verifying an `Attestation` or `SignedAggregateAndProof` from the
|
/// Handle an error whilst verifying an `Attestation` or `SignedAggregateAndProof` from the
|
||||||
/// network.
|
/// network.
|
||||||
fn handle_attestation_verification_failure(
|
fn handle_attestation_verification_failure(
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ pub enum Domain {
|
|||||||
ContributionAndProof,
|
ContributionAndProof,
|
||||||
SyncCommitteeSelectionProof,
|
SyncCommitteeSelectionProof,
|
||||||
ApplicationMask(ApplicationDomain),
|
ApplicationMask(ApplicationDomain),
|
||||||
|
InclusionListCommittee,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lighthouse's internal configuration struct.
|
/// Lighthouse's internal configuration struct.
|
||||||
@@ -187,6 +188,11 @@ pub struct ChainSpec {
|
|||||||
pub min_per_epoch_churn_limit_electra: u64,
|
pub min_per_epoch_churn_limit_electra: u64,
|
||||||
pub max_per_epoch_activation_exit_churn_limit: u64,
|
pub max_per_epoch_activation_exit_churn_limit: u64,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FOCIL params
|
||||||
|
*/
|
||||||
|
pub domain_inclusion_list_committee: u32,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DAS params
|
* DAS params
|
||||||
*/
|
*/
|
||||||
@@ -475,6 +481,7 @@ impl ChainSpec {
|
|||||||
Domain::SyncCommitteeSelectionProof => self.domain_sync_committee_selection_proof,
|
Domain::SyncCommitteeSelectionProof => self.domain_sync_committee_selection_proof,
|
||||||
Domain::ApplicationMask(application_domain) => application_domain.get_domain_constant(),
|
Domain::ApplicationMask(application_domain) => application_domain.get_domain_constant(),
|
||||||
Domain::BlsToExecutionChange => self.domain_bls_to_execution_change,
|
Domain::BlsToExecutionChange => self.domain_bls_to_execution_change,
|
||||||
|
Domain::InclusionListCommittee => self.domain_inclusion_list_committee,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -797,6 +804,11 @@ impl ChainSpec {
|
|||||||
})
|
})
|
||||||
.expect("calculation does not overflow"),
|
.expect("calculation does not overflow"),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FOCIL params
|
||||||
|
*/
|
||||||
|
domain_inclusion_list_committee: 13,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DAS params
|
* DAS params
|
||||||
*/
|
*/
|
||||||
@@ -1115,6 +1127,11 @@ impl ChainSpec {
|
|||||||
})
|
})
|
||||||
.expect("calculation does not overflow"),
|
.expect("calculation does not overflow"),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FOCIL params
|
||||||
|
*/
|
||||||
|
domain_inclusion_list_committee: 13,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DAS params
|
* DAS params
|
||||||
*/
|
*/
|
||||||
@@ -1951,6 +1968,12 @@ mod tests {
|
|||||||
spec.domain_bls_to_execution_change,
|
spec.domain_bls_to_execution_change,
|
||||||
&spec,
|
&spec,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test_domain(
|
||||||
|
Domain::InclusionListCommittee,
|
||||||
|
spec.domain_inclusion_list_committee,
|
||||||
|
&spec,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_bit_mask(domain_bytes: [u8; 4], spec: &ChainSpec) -> u32 {
|
fn apply_bit_mask(domain_bytes: [u8; 4], spec: &ChainSpec) -> u32 {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::test_utils::TestRandom;
|
use crate::test_utils::TestRandom;
|
||||||
use crate::{EthSpec, Hash256, Signature, Slot, Transaction};
|
use crate::{EthSpec, Hash256, Signature, SignedRoot, Slot, Transaction};
|
||||||
|
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -33,6 +33,8 @@ pub struct InclusionList<E: EthSpec> {
|
|||||||
VariableList<Transaction<E::MaxBytesPerTransaction>, E::MaxTransactionsPerInclusionList>,
|
VariableList<Transaction<E::MaxBytesPerTransaction>, E::MaxTransactionsPerInclusionList>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E: EthSpec> SignedRoot for InclusionList<E> {}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Debug, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, Derivative, arbitrary::Arbitrary,
|
Debug, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, Derivative, arbitrary::Arbitrary,
|
||||||
)]
|
)]
|
||||||
|
|||||||
Reference in New Issue
Block a user