add initial IL gossip verification

This commit is contained in:
jacobkaufmann
2024-11-26 20:15:00 -07:00
parent 024dbf6efc
commit 4919a3b4d7
5 changed files with 165 additions and 3 deletions

View 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(),
})
}
}

View File

@@ -34,6 +34,7 @@ pub mod fork_revert;
pub mod graffiti_calculator;
mod head_tracker;
pub mod historical_blocks;
pub mod inclusion_list_verification;
pub mod kzg_utils;
pub mod light_client_finality_update_verification;
pub mod light_client_optimistic_update_verification;

View File

@@ -7,6 +7,9 @@ use crate::{
use beacon_chain::blob_verification::{GossipBlobError, GossipVerifiedBlob};
use beacon_chain::block_verification_types::AsBlock;
use beacon_chain::data_column_verification::{GossipDataColumnError, GossipVerifiedDataColumn};
use beacon_chain::inclusion_list_verification::{
GossipInclusionListError, GossipVerifiedInclusionList,
};
use beacon_chain::store::Error;
use beacon_chain::{
attestation_verification::{self, Error as AttnError, VerifiedAttestation},
@@ -36,8 +39,8 @@ use types::{
DataColumnSidecar, DataColumnSubnetId, EthSpec, Hash256, IndexedAttestation,
LightClientFinalityUpdate, LightClientOptimisticUpdate, ProposerSlashing,
SignedAggregateAndProof, SignedBeaconBlock, SignedBlsToExecutionChange,
SignedContributionAndProof, SignedVoluntaryExit, Slot, SubnetId, SyncCommitteeMessage,
SyncSubnetId,
SignedContributionAndProof, SignedInclusionList, SignedVoluntaryExit, Slot, SubnetId,
SyncCommitteeMessage, SyncSubnetId,
};
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
/// network.
fn handle_attestation_verification_failure(