Introduce AttestationValidationContext

This reduced code duplication.
This commit is contained in:
Paul Hauner 2018-09-30 16:09:35 +09:30
parent b426c9e724
commit c3ec8a3407
No known key found for this signature in database
GPG Key ID: 303E4494BB28068C
4 changed files with 141 additions and 129 deletions

View File

@ -19,6 +19,6 @@ pub use self::ssz_splitter::{
AttestationSplitError, AttestationSplitError,
}; };
pub use self::validation::{ pub use self::validation::{
validate_attestation, AttestationValidationContext,
AttestationValidationError, AttestationValidationError,
}; };

View File

@ -45,7 +45,23 @@ pub enum AttestationValidationError {
DBError(String), DBError(String),
} }
pub fn validate_attestation<T>(a: &AttestationRecord, pub struct AttestationValidationContext<T>
where T: ClientDB + Sized
{
pub block_slot: u64,
pub cycle_length: u8,
pub last_justified_slot: u64,
pub parent_hashes: Arc<Vec<Hash256>>,
pub block_store: Arc<BlockStore<T>>,
pub validator_store: Arc<ValidatorStore<T>>,
pub attester_map: Arc<AttesterMap>,
}
impl<T> AttestationValidationContext<T>
where T: ClientDB
{
pub fn validate_attestation(&self, a: &AttestationRecord)
/*
block_slot: u64, block_slot: u64,
cycle_length: u8, cycle_length: u8,
known_last_justified_slot: u64, known_last_justified_slot: u64,
@ -53,13 +69,14 @@ pub fn validate_attestation<T>(a: &AttestationRecord,
block_store: &Arc<BlockStore<T>>, block_store: &Arc<BlockStore<T>>,
validator_store: &Arc<ValidatorStore<T>>, validator_store: &Arc<ValidatorStore<T>>,
attester_map: &Arc<AttesterMap>) attester_map: &Arc<AttesterMap>)
*/
-> Result<Option<HashSet<usize>>, AttestationValidationError> -> Result<Option<HashSet<usize>>, AttestationValidationError>
where T: ClientDB + Sized where T: ClientDB + Sized
{ {
/* /*
* The attesation slot must not be higher than the block that contained it. * The attesation slot must not be higher than the block that contained it.
*/ */
if a.slot > block_slot { if a.slot > self.block_slot {
return Err(AttestationValidationError::SlotTooHigh); return Err(AttestationValidationError::SlotTooHigh);
} }
@ -69,7 +86,8 @@ pub fn validate_attestation<T>(a: &AttestationRecord,
* *
* The below code stays overflow-safe as long as cycle length is a < 64 bit integer. * The below code stays overflow-safe as long as cycle length is a < 64 bit integer.
*/ */
if a.slot < block_slot.saturating_sub(u64::from(cycle_length) + 1) { if a.slot < self.block_slot
.saturating_sub(u64::from(self.cycle_length).saturating_add(1)) {
return Err(AttestationValidationError::SlotTooLow); return Err(AttestationValidationError::SlotTooLow);
} }
@ -77,7 +95,7 @@ pub fn validate_attestation<T>(a: &AttestationRecord,
* The attestation must indicate that its last justified slot is the same as the last justified * The attestation must indicate that its last justified slot is the same as the last justified
* slot known to us. * slot known to us.
*/ */
if a.justified_slot > known_last_justified_slot { if a.justified_slot > self.last_justified_slot {
return Err(AttestationValidationError::JustifiedSlotTooHigh); return Err(AttestationValidationError::JustifiedSlotTooHigh);
} }
@ -85,7 +103,7 @@ pub fn validate_attestation<T>(a: &AttestationRecord,
* There is no need to include more oblique parents hashes than there are blocks * There is no need to include more oblique parents hashes than there are blocks
* in a cycle. * in a cycle.
*/ */
if a.oblique_parent_hashes.len() > usize::from(cycle_length) { if a.oblique_parent_hashes.len() > usize::from(self.cycle_length) {
return Err(AttestationValidationError::TooManyObliqueHashes); return Err(AttestationValidationError::TooManyObliqueHashes);
} }
@ -95,7 +113,7 @@ pub fn validate_attestation<T>(a: &AttestationRecord,
* This is an array mapping the order that validators will appear in the bitfield to the * This is an array mapping the order that validators will appear in the bitfield to the
* canonincal index of a validator. * canonincal index of a validator.
*/ */
let attestation_indices = attester_map.get(&(a.slot, a.shard_id)) let attestation_indices = self.attester_map.get(&(a.slot, a.shard_id))
.ok_or(AttestationValidationError::BadAttesterMap)?; .ok_or(AttestationValidationError::BadAttesterMap)?;
/* /*
@ -125,16 +143,16 @@ pub fn validate_attestation<T>(a: &AttestationRecord,
/* /*
* The specified justified block hash must be known to us * The specified justified block hash must be known to us
*/ */
if !block_store.block_exists(&a.justified_block_hash)? { if !self.block_store.block_exists(&a.justified_block_hash)? {
return Err(AttestationValidationError::UnknownJustifiedBlock) return Err(AttestationValidationError::UnknownJustifiedBlock)
} }
let signed_message = { let signed_message = {
let parent_hashes = attestation_parent_hashes( let parent_hashes = attestation_parent_hashes(
cycle_length, self.cycle_length,
block_slot, self.block_slot,
a.slot, a.slot,
&known_parent_hashes, &self.parent_hashes,
&a.oblique_parent_hashes)?; &a.oblique_parent_hashes)?;
generate_signed_message( generate_signed_message(
a.slot, a.slot,
@ -150,10 +168,11 @@ pub fn validate_attestation<T>(a: &AttestationRecord,
&a.aggregate_sig, &a.aggregate_sig,
&attestation_indices, &attestation_indices,
&a.attester_bitfield, &a.attester_bitfield,
&validator_store)?; &self.validator_store)?;
Ok(voted_hashmap) Ok(voted_hashmap)
} }
}
fn bytes_for_bits(bits: usize) -> usize { fn bytes_for_bits(bits: usize) -> usize {
(bits.saturating_sub(1) / 8) + 1 (bits.saturating_sub(1) / 8) + 1

View File

@ -11,6 +11,6 @@ mod signature_verification;
mod message_generation; mod message_generation;
pub use self::attestation_validation::{ pub use self::attestation_validation::{
validate_attestation, AttestationValidationContext,
AttestationValidationError, AttestationValidationError,
}; };

View File

@ -7,7 +7,7 @@ use std::sync::{
RwLock, RwLock,
}; };
use super::attestation_record::{ use super::attestation_record::{
validate_attestation, AttestationValidationContext,
AttestationValidationError, AttestationValidationError,
}; };
use super::attestation_record::{ use super::attestation_record::{
@ -99,10 +99,6 @@ impl<T> BlockValidationContext<T>
/// a suspicion that the block might be invalid. Such a suspicion should be applied to /// a suspicion that the block might be invalid. Such a suspicion should be applied to
/// all blocks coming from the network. /// all blocks coming from the network.
/// ///
/// Of course, this function will only be more efficient if a block is already serialized.
/// Serializing a complete block and then validating with this function will be less
/// efficient than just validating the original block.
///
/// This function will determine if the block is new, already known or invalid (either /// This function will determine if the block is new, already known or invalid (either
/// intrinsically or due to some application error.) /// intrinsically or due to some application error.)
/// ///
@ -183,18 +179,24 @@ impl<T> BlockValidationContext<T>
return Err(SszBlockValidationError::ProposerAttestationHasObliqueHashes); return Err(SszBlockValidationError::ProposerAttestationHasObliqueHashes);
} }
/*
* Generate the context in which attestations will be validated.
*/
let attestation_validation_context = Arc::new(AttestationValidationContext {
block_slot,
cycle_length: self.cycle_length,
last_justified_slot: self.last_justified_slot,
parent_hashes: self.parent_hashes.clone(),
block_store: self.block_store.clone(),
validator_store: self.validator_store.clone(),
attester_map: self.attester_map.clone(),
});
/* /*
* Validate this first attestation. * Validate this first attestation.
*/ */
let attestation_voters = validate_attestation( let attestation_voters = attestation_validation_context
&first_attestation, .validate_attestation(&first_attestation)?;
block_slot,
self.cycle_length,
self.last_justified_slot,
&self.parent_hashes,
&self.block_store,
&self.validator_store,
&self.attester_map)?;
/* /*
* If the set of voters is None, the attestation was invalid. * If the set of voters is None, the attestation was invalid.
@ -274,16 +276,7 @@ impl<T> BlockValidationContext<T>
* Deserialization succeeded and the attestation should be validated. * Deserialization succeeded and the attestation should be validated.
*/ */
Ok((attestation, _)) => { Ok((attestation, _)) => {
let result = validate_attestation( match attestation_validation_context.validate_attestation(&attestation) {
&attestation,
block_slot,
self.cycle_length,
self.last_justified_slot,
&self.parent_hashes,
&self.block_store,
&self.validator_store,
&self.attester_map);
match result {
/* /*
* Attestation validation failed with some error. * Attestation validation failed with some error.
*/ */