From fd47f6c4330388153d686ba7a5c0010009a58a7a Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Sun, 27 Jan 2019 17:54:26 +1100 Subject: [PATCH] Move attestation validator to `BeaconState` fn --- .../beacon_chain/src/state_transition.rs | 99 +++---------------- .../beacon_state/attestation_validation.rs | 96 ++++++++++++++++++ eth2/types/src/beacon_state/mod.rs | 2 + eth2/utils/bls/src/lib.rs | 10 ++ 4 files changed, 121 insertions(+), 86 deletions(-) create mode 100644 eth2/types/src/beacon_state/attestation_validation.rs diff --git a/beacon_node/beacon_chain/src/state_transition.rs b/beacon_node/beacon_chain/src/state_transition.rs index 0537ad1959..199bf8210f 100644 --- a/beacon_node/beacon_chain/src/state_transition.rs +++ b/beacon_node/beacon_chain/src/state_transition.rs @@ -1,17 +1,16 @@ use super::{BeaconChain, ClientDB, DBError, SlotClock}; -use bls::{AggregatePublicKey, AggregateSignature, PublicKey, Signature}; +use bls::{PublicKey, Signature}; use boolean_bitfield::BooleanBitfield; use hashing::hash; use slot_clock::{SystemTimeSlotClockError, TestingSlotClockError}; use ssz::{ssz_encode, TreeHash}; use types::{ - beacon_state::SlotProcessingError, readers::BeaconBlockReader, AttestationData, - AttestationDataAndCustodyBit, BeaconBlock, BeaconState, Exit, Fork, Hash256, - PendingAttestation, + beacon_state::{AttestationValidationError, SlotProcessingError}, + readers::BeaconBlockReader, + AttestationData, BeaconBlock, BeaconState, Exit, Fork, Hash256, PendingAttestation, }; // TODO: define elsehwere. -const DOMAIN_ATTESTATION: u64 = 1; const DOMAIN_PROPOSAL: u64 = 2; const DOMAIN_EXIT: u64 = 3; const DOMAIN_RANDAO: u64 = 4; @@ -43,7 +42,7 @@ pub enum Error { MaxProposerSlashingsExceeded, BadProposerSlashing, MaxAttestationsExceeded, - BadAttestation, + InvalidAttestation(AttestationValidationError), NoBlockRoot, MaxDepositsExceeded, MaxExitsExceeded, @@ -218,67 +217,8 @@ where ); for attestation in &block.body.attestations { - ensure!( - attestation.data.slot + self.spec.min_attestation_inclusion_delay <= state.slot, - Error::BadAttestation - ); - ensure!( - attestation.data.slot + self.spec.epoch_length >= state.slot, - Error::BadAttestation - ); - if state.justified_slot >= state.slot - (state.slot % self.spec.epoch_length) { - ensure!( - attestation.data.justified_slot == state.justified_slot, - Error::BadAttestation - ); - } else { - ensure!( - attestation.data.justified_slot == state.previous_justified_slot, - Error::BadAttestation - ); - } - ensure!( - attestation.data.justified_block_root - == *state - .get_block_root(attestation.data.justified_slot, &self.spec) - .ok_or(Error::NoBlockRoot)?, - Error::BadAttestation - ); - ensure!( - (attestation.data.latest_crosslink_root - == state.latest_crosslinks[attestation.data.shard as usize].shard_block_root) - || (attestation.data.shard_block_root - == state.latest_crosslinks[attestation.data.shard as usize] - .shard_block_root), - Error::BadAttestation - ); - let participants = get_attestation_participants( - &state, - &attestation.data, - &attestation.aggregation_bitfield, - ); - let mut group_public_key = AggregatePublicKey::new(); - for participant in participants { - group_public_key.add( - state.validator_registry[participant as usize] - .pubkey - .as_raw(), - ) - } - // Signature verification. - ensure!( - bls_verify_aggregate( - &group_public_key, - &attestation.signable_message(), - &attestation.aggregate_signature, - get_domain(&state.fork_data, attestation.data.slot, DOMAIN_ATTESTATION) - ), - Error::BadProposerSlashing - ); - ensure!( - attestation.data.shard_block_root == self.spec.zero_hash, - Error::BadAttestation - ); + state.validate_attestation(attestation, &self.spec)?; + let pending_attestation = PendingAttestation { data: attestation.data.clone(), aggregation_bitfield: attestation.aggregation_bitfield.clone(), @@ -365,15 +305,6 @@ fn initiate_validator_exit(_state: &BeaconState, _index: u32) { // TODO: stubbed out. } -fn get_attestation_participants( - _state: &BeaconState, - _attestation_data: &AttestationData, - _aggregation_bitfield: &BooleanBitfield, -) -> Vec { - // TODO: stubbed out. - vec![0, 1] -} - fn penalize_validator(_state: &BeaconState, _proposer_index: usize) { // TODO: stubbed out. } @@ -388,16 +319,6 @@ fn bls_verify(pubkey: &PublicKey, message: &[u8], signature: &Signature, _domain signature.verify(message, pubkey) } -fn bls_verify_aggregate( - pubkey: &AggregatePublicKey, - message: &[u8], - signature: &AggregateSignature, - _domain: u64, -) -> bool { - // TODO: add domain - signature.verify(message, pubkey) -} - impl From for Error { fn from(e: DBError) -> Error { Error::DBError(e.message) @@ -423,3 +344,9 @@ impl From for Error { } } } + +impl From for Error { + fn from(e: AttestationValidationError) -> Error { + Error::InvalidAttestation(e) + } +} diff --git a/eth2/types/src/beacon_state/attestation_validation.rs b/eth2/types/src/beacon_state/attestation_validation.rs new file mode 100644 index 0000000000..160ff81282 --- /dev/null +++ b/eth2/types/src/beacon_state/attestation_validation.rs @@ -0,0 +1,96 @@ +use crate::{AggregatePublicKey, Attestation, BeaconState, ChainSpec, Fork}; +use bls::bls_verify_aggregate; + +#[derive(Debug, PartialEq)] +pub enum Error { + IncludedTooEarly, + IncludedTooLate, + WrongJustifiedSlot, + WrongJustifiedRoot, + BadLatestCrosslinkRoot, + BadSignature, + ShardBlockRootNotZero, + NoBlockRoot, +} + +macro_rules! ensure { + ($condition: expr, $result: expr) => { + if !$condition { + return Err($result); + } + }; +} + +// TODO: define elsehwere. +const DOMAIN_ATTESTATION: u64 = 1; + +impl BeaconState { + pub fn validate_attestation( + &self, + attestation: &Attestation, + spec: &ChainSpec, + ) -> Result<(), Error> { + ensure!( + attestation.data.slot + spec.min_attestation_inclusion_delay <= self.slot, + Error::IncludedTooEarly + ); + ensure!( + attestation.data.slot + spec.epoch_length >= self.slot, + Error::IncludedTooLate + ); + if self.justified_slot >= self.slot - (self.slot % spec.epoch_length) { + ensure!( + attestation.data.justified_slot == self.justified_slot, + Error::WrongJustifiedSlot + ); + } else { + ensure!( + attestation.data.justified_slot == self.previous_justified_slot, + Error::WrongJustifiedSlot + ); + } + ensure!( + attestation.data.justified_block_root + == *self + .get_block_root(attestation.data.justified_slot, &spec) + .ok_or(Error::NoBlockRoot)?, + Error::WrongJustifiedRoot + ); + ensure!( + (attestation.data.latest_crosslink_root + == self.latest_crosslinks[attestation.data.shard as usize].shard_block_root) + || (attestation.data.shard_block_root + == self.latest_crosslinks[attestation.data.shard as usize].shard_block_root), + Error::BadLatestCrosslinkRoot + ); + let participants = + self.get_attestation_participants(&attestation.data, &attestation.aggregation_bitfield); + let mut group_public_key = AggregatePublicKey::new(); + for participant in participants { + group_public_key.add( + self.validator_registry[participant as usize] + .pubkey + .as_raw(), + ) + } + ensure!( + bls_verify_aggregate( + &group_public_key, + &attestation.signable_message(), + &attestation.aggregate_signature, + get_domain(&self.fork_data, attestation.data.slot, DOMAIN_ATTESTATION) + ), + Error::BadSignature + ); + ensure!( + attestation.data.shard_block_root == spec.zero_hash, + Error::ShardBlockRootNotZero + ); + Ok(()) + } +} + +pub fn get_domain(_fork: &Fork, _slot: u64, _domain_type: u64) -> u64 { + // TODO: stubbed out. + 0 +} diff --git a/eth2/types/src/beacon_state/mod.rs b/eth2/types/src/beacon_state/mod.rs index 46f1396912..b287c0c7f1 100644 --- a/eth2/types/src/beacon_state/mod.rs +++ b/eth2/types/src/beacon_state/mod.rs @@ -10,10 +10,12 @@ use rand::RngCore; use serde_derive::Serialize; use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; +mod attestation_validation; mod epoch_processing; mod slot_processing; mod winning_root; +pub use self::attestation_validation::Error as AttestationValidationError; pub use self::epoch_processing::Error as EpochProcessingError; pub use self::slot_processing::Error as SlotProcessingError; diff --git a/eth2/utils/bls/src/lib.rs b/eth2/utils/bls/src/lib.rs index fe2f3a17ea..646047d183 100644 --- a/eth2/utils/bls/src/lib.rs +++ b/eth2/utils/bls/src/lib.rs @@ -40,3 +40,13 @@ pub fn create_proof_of_possession(keypair: &Keypair) -> Signature { extend_if_needed(&mut hash); Signature::new_hashed(&hash, &keypair.sk) } + +pub fn bls_verify_aggregate( + pubkey: &AggregatePublicKey, + message: &[u8], + signature: &AggregateSignature, + _domain: u64, +) -> bool { + // TODO: add domain + signature.verify(message, pubkey) +}