Progress further on attestation validation

This commit is contained in:
Paul Hauner 2018-09-24 18:08:48 +10:00
parent f9f5a9e49c
commit 26537c1184
No known key found for this signature in database
GPG Key ID: 303E4494BB28068C

View File

@ -1,3 +1,4 @@
use std::collections::HashSet;
use super::AttestationRecord; use super::AttestationRecord;
use super::attestation_parent_hashes::{ use super::attestation_parent_hashes::{
attestation_parent_hashes, attestation_parent_hashes,
@ -12,33 +13,35 @@ use super::db::stores::{
ValidatorStore, ValidatorStore,
}; };
use super::ssz::SszStream; use super::ssz::SszStream;
use super::bls::{
AggregateSignature,
AggregatePublicKey,
PublicKey,
};
use super::utils::hash::canonical_hash; use super::utils::hash::canonical_hash;
use super::utils::types::{ use super::utils::types::{
Hash256, Hash256,
Bitfield,
}; };
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use super::signatures::{
verify_aggregate_signature_for_indices,
SignatureVerificationError,
};
#[derive(Debug,PartialEq)] #[derive(Debug,PartialEq)]
pub enum AttestationValidationError { pub enum AttestationValidationError {
SlotTooHigh, SlotTooHigh,
SlotTooLow, SlotTooLow,
JustifiedSlotTooHigh, JustifiedSlotTooHigh,
UnknownJustifiedBlock,
TooManyObliqueHashes, TooManyObliqueHashes,
BadCurrentHashes, BadCurrentHashes,
BadObliqueHashes, BadObliqueHashes,
BadAttesterMap, BadAttesterMap,
IntWrapping, IntWrapping,
PublicKeyCorrupt,
NoPublicKeyForValidator,
IncorrectBitField, IncorrectBitField,
NoSignatures, NoSignatures,
NonZeroTrailingBits, NonZeroTrailingBits,
AggregateSignatureFail AggregateSignatureFail,
DBError(String),
} }
type Slot = u64; type Slot = u64;
@ -55,8 +58,9 @@ pub fn validate_attestation<T>(a: &AttestationRecord,
known_last_justified_slot: u64, known_last_justified_slot: u64,
known_parent_hashes: Arc<Vec<Hash256>>, known_parent_hashes: Arc<Vec<Hash256>>,
block_store: BlockStore<T>, block_store: BlockStore<T>,
validator_store: ValidatorStore<T>,
attester_map: Arc<AttesterMap>) attester_map: Arc<AttesterMap>)
-> Result<bool, AttestationValidationError> -> Result<(bool, Option<HashSet<usize>>), AttestationValidationError>
where T: ClientDB + Sized where T: ClientDB + Sized
{ {
/* /*
@ -92,15 +96,46 @@ pub fn validate_attestation<T>(a: &AttestationRecord,
return Err(AttestationValidationError::TooManyObliqueHashes); return Err(AttestationValidationError::TooManyObliqueHashes);
} }
/*
* Retrieve the set of attestation indices for this slot and shard id.
*
* This is an array mapping the order that validators will appear in the bitfield to the
* canonincal index of a validator.
*/
let attestation_indices = attester_map.get(&(a.slot, a.shard_id.into())) let attestation_indices = attester_map.get(&(a.slot, a.shard_id.into()))
.ok_or(AttestationValidationError::BadAttesterMap)?; .ok_or(AttestationValidationError::BadAttesterMap)?;
/*
* The bitfield must be no longer than the minimum required to represent each validator in the
* attestation indicies for this slot and shard id.
*/
if a.attester_bitfield.num_bytes() != if a.attester_bitfield.num_bytes() !=
bytes_for_bits(attestation_indices.len()) bytes_for_bits(attestation_indices.len())
{ {
return Err(AttestationValidationError::IncorrectBitField); return Err(AttestationValidationError::IncorrectBitField);
} }
/*
* If there are excess bits in the bitfield because the number of a validators in not a
* multiple of 8, reject this attestation record.
*
* Allow extra set bits would permit mutliple different byte layouts (and therefore hashes) to
* refer to the same AttesationRecord.
*/
let last_byte =
a.attester_bitfield.get_byte(a.attester_bitfield.num_bytes())
.ok_or(AttestationValidationError::IncorrectBitField)?;
if any_of_last_n_bits_are_set(last_byte, a.attester_bitfield.len() % 8) {
return Err(AttestationValidationError::IncorrectBitField)
}
/*
* The specified justified block hash must be known to us
*/
if !block_store.block_exists(&a.justified_block_hash)? {
return Err(AttestationValidationError::UnknownJustifiedBlock)
}
let signed_message = { let signed_message = {
let parent_hashes = attestation_parent_hashes( let parent_hashes = attestation_parent_hashes(
cycle_length, cycle_length,
@ -116,15 +151,20 @@ pub fn validate_attestation<T>(a: &AttestationRecord,
a.justified_slot) a.justified_slot)
}; };
Ok(false) let (signature_valid, voted_hashmap) =
verify_aggregate_signature_for_indices(
&signed_message,
&a.aggregate_sig,
&attestation_indices,
&a.attester_bitfield,
&validator_store)?;
Ok((signature_valid, voted_hashmap))
} }
fn collect_pub_keys(attestation_indices: &Vec<usize>, fn any_of_last_n_bits_are_set(byte: &u8, n: usize) -> bool {
bitfield: &Bitfield) let shift = 8_u8.saturating_sub(n as u8);
-> Option<Vec<PublicKey>> ((!0 >> shift) & byte) > 0
{
// cats
None
} }
/// Generates the message used to validate the signature provided with an AttestationRecord. /// Generates the message used to validate the signature provided with an AttestationRecord.
@ -161,16 +201,37 @@ fn generate_signed_message(slot: u64,
impl From<ParentHashesError> for AttestationValidationError { impl From<ParentHashesError> for AttestationValidationError {
fn from(e: ParentHashesError) -> Self { fn from(e: ParentHashesError) -> Self {
match e { match e {
ParentHashesError::BadCurrentHashes => ParentHashesError::BadCurrentHashes
AttestationValidationError::BadCurrentHashes, => AttestationValidationError::BadCurrentHashes,
ParentHashesError::BadObliqueHashes => ParentHashesError::BadObliqueHashes
AttestationValidationError::BadObliqueHashes, => AttestationValidationError::BadObliqueHashes,
ParentHashesError::SlotTooLow => ParentHashesError::SlotTooLow
AttestationValidationError::SlotTooLow, => AttestationValidationError::SlotTooLow,
ParentHashesError::SlotTooHigh => ParentHashesError::SlotTooHigh
AttestationValidationError::SlotTooHigh, => AttestationValidationError::SlotTooHigh,
ParentHashesError::IntWrapping => ParentHashesError::IntWrapping
AttestationValidationError::IntWrapping => AttestationValidationError::IntWrapping
}
}
}
impl From<DBError> for AttestationValidationError {
fn from(e: DBError) -> Self {
AttestationValidationError::DBError(e.message)
}
}
impl From<SignatureVerificationError> for AttestationValidationError {
fn from(e: SignatureVerificationError) -> Self {
match e {
SignatureVerificationError::BadValidatorIndex
=> AttestationValidationError::BadAttesterMap,
SignatureVerificationError::PublicKeyCorrupt
=> AttestationValidationError::PublicKeyCorrupt,
SignatureVerificationError::NoPublicKeyForValidator
=> AttestationValidationError::NoPublicKeyForValidator,
SignatureVerificationError::DBError(s)
=> AttestationValidationError::DBError(s),
} }
} }
} }