Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion beacon_node/beacon_chain/src/beacon_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1584,7 +1584,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
pub fn validator_pubkey(&self, validator_index: usize) -> Result<Option<PublicKey>, Error> {
let pubkey_cache = self.validator_pubkey_cache.read();

Ok(pubkey_cache.get(validator_index).cloned())
Ok(pubkey_cache.get(validator_index).ok().cloned())
}

/// As per `Self::validator_pubkey`, but returns `PublicKeyBytes`.
Expand Down
4 changes: 2 additions & 2 deletions beacon_node/beacon_chain/src/blob_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub enum GossipBlobError {
/// ## Peer scoring
///
/// The blob is invalid and the peer is faulty.
UnknownValidator(u64),
UnknownValidator(u64, /* reason */ String),

/// The provided blob is not from a later slot than its parent.
///
Expand Down Expand Up @@ -547,7 +547,7 @@ pub fn validate_blob_sidecar_for_gossip<T: BeaconChainTypes, O: ObservationStrat

let pubkey = pubkey_cache
.get(proposer_index)
.ok_or_else(|| GossipBlobError::UnknownValidator(proposer_index as u64))?;
.map_err(|e| GossipBlobError::UnknownValidator(proposer_index as u64, e))?;
signed_block_header.verify_signature::<T::EthSpec>(
pubkey,
&fork,
Expand Down
35 changes: 21 additions & 14 deletions beacon_node/beacon_chain/src/block_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ use safe_arith::ArithError;
use slot_clock::SlotClock;
use ssz::Encode;
use ssz_derive::{Decode, Encode};
use state_processing::block_signature_verifier::GetPubkeyFnReturn;
use state_processing::per_block_processing::{errors::IntoWithIndex, is_merge_transition_block};
use state_processing::{
block_signature_verifier::{BlockSignatureVerifier, Error as BlockSignatureVerifierError},
Expand Down Expand Up @@ -213,7 +214,7 @@ pub enum BlockError {
/// ## Peer scoring
///
/// The block is invalid and the peer is faulty.
UnknownValidator(u64),
UnknownValidator(u64, /* reason */ String),
/// A signature in the block is invalid
///
/// ## Peer scoring
Expand Down Expand Up @@ -959,7 +960,7 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
let pubkey_cache = get_validator_pubkey_cache(chain)?;
let pubkey = pubkey_cache
.get(block.message().proposer_index() as usize)
.ok_or_else(|| BlockError::UnknownValidator(block.message().proposer_index()))?;
.map_err(|e| BlockError::UnknownValidator(block.message().proposer_index(), e))?;
block.verify_signature(
Some(block_root),
pubkey,
Expand Down Expand Up @@ -1109,7 +1110,10 @@ impl<T: BeaconChainTypes> SignatureVerifiedBlock<T> {
// Re-verify the proposer signature in isolation to attribute fault
let pubkey = pubkey_cache
.get(block.message().proposer_index() as usize)
.ok_or_else(|| BlockError::UnknownValidator(block.message().proposer_index()))?;
.map_err(|e| {
// TODO: bound by state
BlockError::UnknownValidator(block.message().proposer_index(), e)
})?;
if block.as_block().verify_signature(
Some(block_root),
pubkey,
Expand Down Expand Up @@ -1980,7 +1984,7 @@ fn load_parent<T: BeaconChainTypes, B: AsBlock<T::EthSpec>>(
/// This trait is used to unify `BlockError` and `GossipBlobError`.
pub trait BlockBlobError: From<BeaconStateError> + From<BeaconChainError> + Debug {
fn not_later_than_parent_error(block_slot: Slot, state_slot: Slot) -> Self;
fn unknown_validator_error(validator_index: u64) -> Self;
fn unknown_validator_error(validator_index: u64, e: String) -> Self;
fn proposer_signature_invalid() -> Self;
}

Expand All @@ -1992,8 +1996,8 @@ impl BlockBlobError for BlockError {
}
}

fn unknown_validator_error(validator_index: u64) -> Self {
BlockError::UnknownValidator(validator_index)
fn unknown_validator_error(validator_index: u64, e: String) -> Self {
BlockError::UnknownValidator(validator_index, e)
}

fn proposer_signature_invalid() -> Self {
Expand All @@ -2009,8 +2013,8 @@ impl BlockBlobError for GossipBlobError {
}
}

fn unknown_validator_error(validator_index: u64) -> Self {
GossipBlobError::UnknownValidator(validator_index)
fn unknown_validator_error(validator_index: u64, e: String) -> Self {
GossipBlobError::UnknownValidator(validator_index, e)
}

fn proposer_signature_invalid() -> Self {
Expand All @@ -2026,8 +2030,8 @@ impl BlockBlobError for GossipDataColumnError {
}
}

fn unknown_validator_error(validator_index: u64) -> Self {
GossipDataColumnError::UnknownValidator(validator_index)
fn unknown_validator_error(validator_index: u64, e: String) -> Self {
GossipDataColumnError::UnknownValidator(validator_index, e)
}

fn proposer_signature_invalid() -> Self {
Expand Down Expand Up @@ -2098,7 +2102,7 @@ fn get_signature_verifier<'a, T: BeaconChainTypes>(
) -> BlockSignatureVerifier<
'a,
T::EthSpec,
impl Fn(usize) -> Option<Cow<'a, PublicKey>> + Clone,
impl Fn(usize) -> GetPubkeyFnReturn<'a> + Clone,
impl Fn(&'a PublicKeyBytes) -> Option<Cow<'a, PublicKey>>,
> {
let get_pubkey = move |validator_index| {
Expand All @@ -2108,15 +2112,18 @@ fn get_signature_verifier<'a, T: BeaconChainTypes>(
.get(validator_index)
.map(Cow::Borrowed)
} else {
None
Err(format!(
"AboveStateRegistryLimit({})",
state.validators().len()
))
}
};

let decompressor = move |pk_bytes| {
// Map compressed pubkey to validator index.
let validator_index = validator_pubkey_cache.get_index(pk_bytes)?;
// Map validator index to pubkey (respecting guard on unknown validators).
get_pubkey(validator_index)
get_pubkey(validator_index).ok()
};

BlockSignatureVerifier::new(state, get_pubkey, decompressor, spec)
Expand All @@ -2132,7 +2139,7 @@ pub fn verify_header_signature<T: BeaconChainTypes, Err: BlockBlobError>(
let proposer_pubkey = get_validator_pubkey_cache(chain)?
.get(header.message.proposer_index as usize)
.cloned()
.ok_or(Err::unknown_validator_error(header.message.proposer_index))?;
.map_err(|e| Err::unknown_validator_error(header.message.proposer_index, e))?;
let head_fork = chain.canonical_head.cached_head().head_fork();

if header.verify_signature::<T::EthSpec>(
Expand Down
4 changes: 2 additions & 2 deletions beacon_node/beacon_chain/src/data_column_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub enum GossipDataColumnError {
/// ## Peer scoring
///
/// The data column is invalid and the peer is faulty.
UnknownValidator(u64),
UnknownValidator(u64, /* reason */ String),
/// The provided data column is not from a later slot than its parent.
///
/// ## Peer scoring
Expand Down Expand Up @@ -623,7 +623,7 @@ fn verify_proposer_and_signature<T: BeaconChainTypes>(

let pubkey = pubkey_cache
.get(proposer_index)
.ok_or_else(|| GossipDataColumnError::UnknownValidator(proposer_index as u64))?;
.map_err(|e| GossipDataColumnError::UnknownValidator(proposer_index as u64, e))?;
let signed_block_header = &data_column.signed_block_header;
signed_block_header.verify_signature::<T::EthSpec>(
pubkey,
Expand Down
12 changes: 8 additions & 4 deletions beacon_node/beacon_chain/src/validator_pubkey_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,17 @@ impl<T: BeaconChainTypes> ValidatorPubkeyCache<T> {
}

/// Get the public key for a validator with index `i`.
pub fn get(&self, i: usize) -> Option<&PublicKey> {
self.pubkeys.get(i)
/// Returns an Err with the length of the cache at query time.
pub fn get(&self, i: usize) -> Result<&PublicKey, String> {
self.pubkeys
.get(i)
.ok_or(format!("UnknownIndexInCache({})", self.pubkeys.len()))
}

/// Get the `PublicKey` for a validator with `PublicKeyBytes`.
pub fn get_pubkey_from_pubkey_bytes(&self, pubkey: &PublicKeyBytes) -> Option<&PublicKey> {
self.get_index(pubkey).and_then(|index| self.get(index))
self.get_index(pubkey)
.and_then(|index| self.get(index).ok())
}

/// Get the public key (in bytes form) for a validator with index `i`.
Expand Down Expand Up @@ -255,7 +259,7 @@ mod test {
);
} else {
assert_eq!(
cache.get(i),
cache.get(i).ok(),
None,
"should not get pubkey for out of bounds index",
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -817,7 +817,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
)
}
GossipDataColumnError::ProposalSignatureInvalid
| GossipDataColumnError::UnknownValidator(_)
| GossipDataColumnError::UnknownValidator { .. }
| GossipDataColumnError::ProposerIndexMismatch { .. }
| GossipDataColumnError::IsNotLaterThanParent { .. }
| GossipDataColumnError::InvalidSubnetId { .. }
Expand Down Expand Up @@ -965,7 +965,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
)
}
GossipBlobError::ProposalSignatureInvalid
| GossipBlobError::UnknownValidator(_)
| GossipBlobError::UnknownValidator { .. }
| GossipBlobError::ProposerIndexMismatch { .. }
| GossipBlobError::BlobIsNotLaterThanParent { .. }
| GossipBlobError::InvalidSubnet { .. }
Expand Down Expand Up @@ -1394,7 +1394,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
| Err(e @ BlockError::IncorrectBlockProposer { .. })
| Err(e @ BlockError::BlockSlotLimitReached)
| Err(e @ BlockError::NonLinearSlots)
| Err(e @ BlockError::UnknownValidator(_))
| Err(e @ BlockError::UnknownValidator { .. })
| Err(e @ BlockError::PerBlockProcessingError(_))
| Err(e @ BlockError::NonLinearParentRoots)
| Err(e @ BlockError::BlockIsNotLaterThanParent { .. })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,16 @@ impl From<BlockOperationError<AttestationInvalid>> for Error {
}
}

pub type GetPubkeyFnReturn<'a> = std::result::Result<Cow<'a, PublicKey>, String>;

/// Reads the BLS signatures and keys from a `SignedBeaconBlock`, storing them as a `Vec<SignatureSet>`.
///
/// This allows for optimizations related to batch BLS operations (see the
/// `Self::verify_entire_block(..)` function).
pub struct BlockSignatureVerifier<'a, E, F, D>
where
E: EthSpec,
F: Fn(usize) -> Option<Cow<'a, PublicKey>> + Clone,
F: Fn(usize) -> GetPubkeyFnReturn<'a> + Clone,
D: Fn(&'a PublicKeyBytes) -> Option<Cow<'a, PublicKey>>,
{
get_pubkey: F,
Expand All @@ -97,7 +99,7 @@ impl<'a> From<Vec<SignatureSet<'a>>> for ParallelSignatureSets<'a> {
impl<'a, E, F, D> BlockSignatureVerifier<'a, E, F, D>
where
E: EthSpec,
F: Fn(usize) -> Option<Cow<'a, PublicKey>> + Clone,
F: Fn(usize) -> GetPubkeyFnReturn<'a> + Clone,
D: Fn(&'a PublicKeyBytes) -> Option<Cow<'a, PublicKey>>,
{
/// Create a new verifier without any included signatures. See the `include...` functions to
Expand Down
Loading
Loading