Add more gossip verification conditions

This commit is contained in:
Pawan Dhananjay 2022-10-06 21:16:57 -05:00
parent 44515b8cbe
commit 1430b561c3
No known key found for this signature in database
GPG Key ID: 647E56278D7E9B4C
2 changed files with 100 additions and 34 deletions

View File

@ -1,13 +1,13 @@
use derivative::Derivative; use derivative::Derivative;
use slot_clock::SlotClock; use slot_clock::SlotClock;
use crate::beacon_chain::{BeaconChain, BeaconChainTypes, MAXIMUM_GOSSIP_CLOCK_DISPARITY}; use crate::beacon_chain::{
use crate::{BeaconChainError}; BeaconChain, BeaconChainTypes, MAXIMUM_GOSSIP_CLOCK_DISPARITY,
use bls::PublicKey; VALIDATOR_PUBKEY_CACHE_LOCK_TIMEOUT,
use types::{
consts::eip4844::BLS_MODULUS, BeaconStateError, Hash256,
SignedBlobsSidecar, Slot,
}; };
use crate::BeaconChainError;
use bls::PublicKey;
use types::{consts::eip4844::BLS_MODULUS, BeaconStateError, Hash256, SignedBlobsSidecar, Slot};
pub enum BlobError { pub enum BlobError {
/// The blob sidecar is from a slot that is later than the current slot (with respect to the /// The blob sidecar is from a slot that is later than the current slot (with respect to the
@ -69,6 +69,13 @@ pub enum BlobError {
/// is valid or not. /// is valid or not.
UnknownHeadBlock { beacon_block_root: Hash256 }, UnknownHeadBlock { beacon_block_root: Hash256 },
/// The proposal_index corresponding to blob.beacon_block_root is not known.
///
/// ## Peer scoring
///
/// The block is invalid and the peer is faulty.
UnknownValidator(u64),
/// There was an error whilst processing the sync contribution. It is not known if it is valid or invalid. /// There was an error whilst processing the sync contribution. It is not known if it is valid or invalid.
/// ///
/// ## Peer scoring /// ## Peer scoring
@ -103,17 +110,17 @@ impl<'a, T: BeaconChainTypes> VerifiedBlobsSidecar<'a, T> {
blob_sidecar: &'a SignedBlobsSidecar<T::EthSpec>, blob_sidecar: &'a SignedBlobsSidecar<T::EthSpec>,
chain: &BeaconChain<T>, chain: &BeaconChain<T>,
) -> Result<Self, BlobError> { ) -> Result<Self, BlobError> {
let blob_slot = blob_sidecar.message.beacon_block_slot; let block_slot = blob_sidecar.message.beacon_block_slot;
let _blob_root = blob_sidecar.message.beacon_block_root; let block_root = blob_sidecar.message.beacon_block_root;
// Do not gossip or process blobs from future or past slots. // Do not gossip or process blobs from future or past slots.
let latest_permissible_slot = chain let latest_permissible_slot = chain
.slot_clock .slot_clock
.now_with_future_tolerance(MAXIMUM_GOSSIP_CLOCK_DISPARITY) .now_with_future_tolerance(MAXIMUM_GOSSIP_CLOCK_DISPARITY)
.ok_or(BeaconChainError::UnableToReadSlot)?; .ok_or(BeaconChainError::UnableToReadSlot)?;
if blob_slot > latest_permissible_slot { if block_slot > latest_permissible_slot {
return Err(BlobError::FutureSlot { return Err(BlobError::FutureSlot {
message_slot: latest_permissible_slot, message_slot: latest_permissible_slot,
latest_permissible_slot: blob_slot, latest_permissible_slot: block_slot,
}); });
} }
@ -124,10 +131,10 @@ impl<'a, T: BeaconChainTypes> VerifiedBlobsSidecar<'a, T> {
.slot_clock .slot_clock
.now_with_past_tolerance(MAXIMUM_GOSSIP_CLOCK_DISPARITY) .now_with_past_tolerance(MAXIMUM_GOSSIP_CLOCK_DISPARITY)
.ok_or(BeaconChainError::UnableToReadSlot)?; .ok_or(BeaconChainError::UnableToReadSlot)?;
if blob_slot > earliest_permissible_slot { if block_slot > earliest_permissible_slot {
return Err(BlobError::PastSlot { return Err(BlobError::PastSlot {
message_slot: earliest_permissible_slot, message_slot: earliest_permissible_slot,
earliest_permissible_slot: blob_slot, earliest_permissible_slot: block_slot,
}); });
} }
@ -140,34 +147,59 @@ impl<'a, T: BeaconChainTypes> VerifiedBlobsSidecar<'a, T> {
} }
// Verify that the KZG proof is a valid G1 point // Verify that the KZG proof is a valid G1 point
// TODO(pawan): KZG commitment can also be point at infinity, use a different check
// (bls.KeyValidate)
if PublicKey::deserialize(&blob_sidecar.message.kzg_aggregate_proof.0).is_err() { if PublicKey::deserialize(&blob_sidecar.message.kzg_aggregate_proof.0).is_err() {
return Err(BlobError::InvalidKZGCommitment); return Err(BlobError::InvalidKZGCommitment);
} }
// TODO: Verify proposer signature let proposer_shuffling_root = chain
.canonical_head
.cached_head()
.snapshot
.beacon_state
.proposer_shuffling_decision_root(block_root)?;
// // let state = /* Get a valid state */ let (proposer_index, fork) = match chain
// let proposer_index = state.get_beacon_proposer_index(blob_slot, &chain.spec)? as u64; .beacon_proposer_cache
// let signature_is_valid = { .lock()
// let pubkey_cache = get_validator_pubkey_cache(chain)?; .get_slot::<T::EthSpec>(proposer_shuffling_root, block_slot)
// let pubkey = pubkey_cache {
// .get(proposer_index as usize) Some(proposer) => (proposer.index, proposer.fork),
// .ok_or_else(|| BlobError::UnknownValidator(proposer_index)?; None => {
// blob.verify_signature( let state = &chain.canonical_head.cached_head().snapshot.beacon_state;
// Some(block_root), (
// pubkey, state.get_beacon_proposer_index(block_slot, &chain.spec)?,
// &fork, state.fork(),
// chain.genesis_validators_root, )
// &chain.spec, }
// ) };
// }; let signature_is_valid = {
let pubkey_cache = chain
.validator_pubkey_cache
.try_read_for(VALIDATOR_PUBKEY_CACHE_LOCK_TIMEOUT)
.ok_or(BeaconChainError::ValidatorPubkeyCacheLockTimeout)
.map_err(BlobError::BeaconChainError)?;
// if !signature_is_valid { let pubkey = pubkey_cache
// return Err(BlobError::ProposalSignatureInvalid); .get(proposer_index as usize)
// } .ok_or_else(|| BlobError::UnknownValidator(proposer_index as u64))?;
// TODO: Check that we have not already received a sidecar with a valid signature for this slot. blob_sidecar.verify_signature(
None,
pubkey,
&fork,
chain.genesis_validators_root,
&chain.spec,
)
};
if !signature_is_valid {
return Err(BlobError::ProposalSignatureInvalid);
}
// TODO(pawan): Check that we have not already received a sidecar with a valid signature for this slot.
// TODO(pawan): check if block hash is already known
Ok(Self { blob_sidecar }) Ok(Self { blob_sidecar })
} }
} }

View File

@ -1,7 +1,9 @@
use crate::{BlobsSidecar, EthSpec}; use crate::{
signing_data::SignedRoot, BlobsSidecar, ChainSpec, Domain, EthSpec, Fork, Hash256, PublicKey,
SigningData,
};
use bls::Signature; use bls::Signature;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use ssz::Encode;
use ssz_derive::{Decode, Encode}; use ssz_derive::{Decode, Encode};
use tree_hash::TreeHash; use tree_hash::TreeHash;
use tree_hash_derive::TreeHash; use tree_hash_derive::TreeHash;
@ -21,4 +23,36 @@ impl<T: EthSpec> SignedBlobsSidecar<T> {
signature, signature,
} }
} }
/// Verify `self.signature`.
///
/// If the root of `blob_sidecar.message` is already known it can be passed in via `object_root_opt`.
/// Otherwise, it will be computed locally.
pub fn verify_signature(
&self,
object_root_opt: Option<Hash256>,
pubkey: &PublicKey,
fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec,
) -> bool {
let domain = spec.get_domain(
self.message.beacon_block_slot.epoch(T::slots_per_epoch()),
Domain::BlobsSideCar,
fork,
genesis_validators_root,
);
let message = if let Some(object_root) = object_root_opt {
SigningData {
object_root,
domain,
}
.tree_hash_root()
} else {
self.message.signing_root(domain)
};
self.signature.verify(pubkey, message)
}
} }