mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-07 08:52:54 +00:00
@@ -25,9 +25,8 @@ pub fn attestation_parent_hashes(
|
||||
block_slot: u64,
|
||||
attestation_slot: u64,
|
||||
current_hashes: &[Hash256],
|
||||
oblique_hashes: &[Hash256])
|
||||
-> Result<Vec<Hash256>, ParentHashesError>
|
||||
{
|
||||
oblique_hashes: &[Hash256],
|
||||
) -> Result<Vec<Hash256>, ParentHashesError> {
|
||||
// This cast places a limit on cycle_length. If you change it, check math
|
||||
// for overflow.
|
||||
let cycle_length: u64 = u64::from(cycle_length);
|
||||
@@ -65,20 +64,18 @@ pub fn attestation_parent_hashes(
|
||||
* Arithmetic is:
|
||||
* start + cycle_length - oblique_hashes.len()
|
||||
*/
|
||||
let end = start.checked_add(cycle_length)
|
||||
let end = start
|
||||
.checked_add(cycle_length)
|
||||
.and_then(|x| x.checked_sub(oblique_hashes.len() as u64))
|
||||
.ok_or(ParentHashesError::IntWrapping)?;
|
||||
|
||||
|
||||
let mut hashes = Vec::new();
|
||||
hashes.extend_from_slice(
|
||||
¤t_hashes[(start as usize)..(end as usize)]);
|
||||
hashes.extend_from_slice(¤t_hashes[(start as usize)..(end as usize)]);
|
||||
hashes.extend_from_slice(oblique_hashes);
|
||||
|
||||
Ok(hashes)
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -106,7 +103,8 @@ mod tests {
|
||||
block_slot,
|
||||
attestation_slot,
|
||||
¤t_hashes,
|
||||
&oblique_hashes);
|
||||
&oblique_hashes,
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
let result = result.unwrap();
|
||||
assert_eq!(result.len(), cycle_length as usize);
|
||||
@@ -131,7 +129,8 @@ mod tests {
|
||||
block_slot,
|
||||
attestation_slot,
|
||||
¤t_hashes,
|
||||
&oblique_hashes);
|
||||
&oblique_hashes,
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
let result = result.unwrap();
|
||||
assert_eq!(result.len(), cycle_length as usize);
|
||||
@@ -156,7 +155,8 @@ mod tests {
|
||||
block_slot,
|
||||
attestation_slot,
|
||||
¤t_hashes,
|
||||
&oblique_hashes);
|
||||
&oblique_hashes,
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
let result = result.unwrap();
|
||||
assert_eq!(result.len(), cycle_length as usize);
|
||||
@@ -179,7 +179,8 @@ mod tests {
|
||||
block_slot,
|
||||
attestation_slot,
|
||||
¤t_hashes,
|
||||
&oblique_hashes);
|
||||
&oblique_hashes,
|
||||
);
|
||||
let result = result.unwrap();
|
||||
assert_eq!(result.len(), cycle_length as usize);
|
||||
let expected_result = get_range_of_hashes(7, 15);
|
||||
@@ -201,7 +202,8 @@ mod tests {
|
||||
block_slot,
|
||||
attestation_slot,
|
||||
¤t_hashes,
|
||||
&oblique_hashes);
|
||||
&oblique_hashes,
|
||||
);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
@@ -220,7 +222,8 @@ mod tests {
|
||||
block_slot,
|
||||
attestation_slot,
|
||||
¤t_hashes,
|
||||
&oblique_hashes);
|
||||
&oblique_hashes,
|
||||
);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,16 @@
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
use super::types::{
|
||||
AttestationRecord,
|
||||
AttesterMap,
|
||||
};
|
||||
use super::attestation_parent_hashes::{
|
||||
attestation_parent_hashes,
|
||||
ParentHashesError,
|
||||
};
|
||||
use super::db::{
|
||||
ClientDB,
|
||||
DBError
|
||||
};
|
||||
use super::db::stores::{
|
||||
BeaconBlockStore,
|
||||
BeaconBlockAtSlotError,
|
||||
ValidatorStore,
|
||||
};
|
||||
use super::types::{
|
||||
Hash256,
|
||||
};
|
||||
use super::attestation_parent_hashes::{attestation_parent_hashes, ParentHashesError};
|
||||
use super::db::stores::{BeaconBlockAtSlotError, BeaconBlockStore, ValidatorStore};
|
||||
use super::db::{ClientDB, DBError};
|
||||
use super::message_generation::generate_signed_message;
|
||||
use super::signature_verification::{
|
||||
verify_aggregate_signature_for_indices,
|
||||
SignatureVerificationError,
|
||||
verify_aggregate_signature_for_indices, SignatureVerificationError,
|
||||
};
|
||||
use super::types::Hash256;
|
||||
use super::types::{AttestationRecord, AttesterMap};
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug,PartialEq)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum AttestationValidationError {
|
||||
ParentSlotTooHigh,
|
||||
ParentSlotTooLow,
|
||||
@@ -52,7 +36,8 @@ pub enum AttestationValidationError {
|
||||
|
||||
/// The context against which some attestation should be validated.
|
||||
pub struct AttestationValidationContext<T>
|
||||
where T: ClientDB + Sized
|
||||
where
|
||||
T: ClientDB + Sized,
|
||||
{
|
||||
/// The slot as determined by the system time.
|
||||
pub block_slot: u64,
|
||||
@@ -73,7 +58,8 @@ pub struct AttestationValidationContext<T>
|
||||
}
|
||||
|
||||
impl<T> AttestationValidationContext<T>
|
||||
where T: ClientDB
|
||||
where
|
||||
T: ClientDB,
|
||||
{
|
||||
/// Validate a (fully deserialized) AttestationRecord against this context.
|
||||
///
|
||||
@@ -82,9 +68,10 @@ impl<T> AttestationValidationContext<T>
|
||||
///
|
||||
/// The attestation's aggregate signature will be verified, therefore the function must able to
|
||||
/// access all required validation public keys via the `validator_store`.
|
||||
pub fn validate_attestation(&self, a: &AttestationRecord)
|
||||
-> Result<HashSet<usize>, AttestationValidationError>
|
||||
{
|
||||
pub fn validate_attestation(
|
||||
&self,
|
||||
a: &AttestationRecord,
|
||||
) -> Result<HashSet<usize>, AttestationValidationError> {
|
||||
/*
|
||||
* The attesation slot must be less than or equal to the parent of the slot of the block
|
||||
* that contained the attestation.
|
||||
@@ -97,8 +84,10 @@ impl<T> AttestationValidationContext<T>
|
||||
* The slot of this attestation must not be more than cycle_length + 1 distance
|
||||
* from the parent_slot of block that contained it.
|
||||
*/
|
||||
if a.slot < self.parent_block_slot
|
||||
.saturating_sub(u64::from(self.cycle_length).saturating_add(1)) {
|
||||
if a.slot < self
|
||||
.parent_block_slot
|
||||
.saturating_sub(u64::from(self.cycle_length).saturating_add(1))
|
||||
{
|
||||
return Err(AttestationValidationError::ParentSlotTooLow);
|
||||
}
|
||||
|
||||
@@ -124,18 +113,18 @@ impl<T> AttestationValidationContext<T>
|
||||
* This is an array mapping the order that validators will appear in the bitfield to the
|
||||
* canonincal index of a validator.
|
||||
*/
|
||||
let attestation_indices = self.attester_map.get(&(a.slot, a.shard_id))
|
||||
let attestation_indices = self
|
||||
.attester_map
|
||||
.get(&(a.slot, a.shard_id))
|
||||
.ok_or(AttestationValidationError::BadAttesterMap)?;
|
||||
|
||||
/*
|
||||
* The bitfield must be no longer than the minimum required to represent each validator in the
|
||||
* attestation indices for this slot and shard id.
|
||||
*/
|
||||
if a.attester_bitfield.num_bytes() !=
|
||||
bytes_for_bits(attestation_indices.len())
|
||||
{
|
||||
if a.attester_bitfield.num_bytes() != bytes_for_bits(attestation_indices.len()) {
|
||||
return Err(AttestationValidationError::BadBitfieldLength);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are excess bits in the bitfield because the number of a validators in not a
|
||||
@@ -145,7 +134,7 @@ impl<T> AttestationValidationContext<T>
|
||||
* refer to the same AttesationRecord.
|
||||
*/
|
||||
if a.attester_bitfield.len() > attestation_indices.len() {
|
||||
return Err(AttestationValidationError::InvalidBitfieldEndBits)
|
||||
return Err(AttestationValidationError::InvalidBitfieldEndBits);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -156,7 +145,8 @@ impl<T> AttestationValidationContext<T>
|
||||
self.block_slot,
|
||||
a.slot,
|
||||
&self.recent_block_hashes,
|
||||
&a.oblique_parent_hashes)?;
|
||||
&a.oblique_parent_hashes,
|
||||
)?;
|
||||
|
||||
/*
|
||||
* The specified justified block hash supplied in the attestation must be in the chain at
|
||||
@@ -166,11 +156,15 @@ impl<T> AttestationValidationContext<T>
|
||||
* block store (database) we iterate back through the blocks until we find (or fail to
|
||||
* find) the justified block hash referenced in the attestation record.
|
||||
*/
|
||||
let latest_parent_hash = parent_hashes.last()
|
||||
let latest_parent_hash = parent_hashes
|
||||
.last()
|
||||
.ok_or(AttestationValidationError::BadCurrentHashes)?;
|
||||
match self.block_store.block_at_slot(&latest_parent_hash, a.justified_slot)? {
|
||||
match self
|
||||
.block_store
|
||||
.block_at_slot(&latest_parent_hash, a.justified_slot)?
|
||||
{
|
||||
Some((ref hash, _)) if *hash == a.justified_block_hash.to_vec() => (),
|
||||
_ => return Err(AttestationValidationError::InvalidJustifiedBlockHash)
|
||||
_ => return Err(AttestationValidationError::InvalidJustifiedBlockHash),
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -182,16 +176,17 @@ impl<T> AttestationValidationContext<T>
|
||||
&parent_hashes,
|
||||
a.shard_id,
|
||||
&a.shard_block_hash,
|
||||
a.justified_slot)
|
||||
a.justified_slot,
|
||||
)
|
||||
};
|
||||
|
||||
let voted_hashset =
|
||||
verify_aggregate_signature_for_indices(
|
||||
&signed_message,
|
||||
&a.aggregate_sig,
|
||||
&attestation_indices,
|
||||
&a.attester_bitfield,
|
||||
&self.validator_store)?;
|
||||
let voted_hashset = verify_aggregate_signature_for_indices(
|
||||
&signed_message,
|
||||
&a.aggregate_sig,
|
||||
&attestation_indices,
|
||||
&a.attester_bitfield,
|
||||
&self.validator_store,
|
||||
)?;
|
||||
|
||||
/*
|
||||
* If the hashset of voters is None, the signature verification failed.
|
||||
@@ -210,16 +205,11 @@ fn bytes_for_bits(bits: usize) -> usize {
|
||||
impl From<ParentHashesError> for AttestationValidationError {
|
||||
fn from(e: ParentHashesError) -> Self {
|
||||
match e {
|
||||
ParentHashesError::BadCurrentHashes
|
||||
=> AttestationValidationError::BadCurrentHashes,
|
||||
ParentHashesError::BadObliqueHashes
|
||||
=> AttestationValidationError::BadObliqueHashes,
|
||||
ParentHashesError::SlotTooLow
|
||||
=> AttestationValidationError::BlockSlotTooLow,
|
||||
ParentHashesError::SlotTooHigh
|
||||
=> AttestationValidationError::BlockSlotTooHigh,
|
||||
ParentHashesError::IntWrapping
|
||||
=> AttestationValidationError::IntWrapping
|
||||
ParentHashesError::BadCurrentHashes => AttestationValidationError::BadCurrentHashes,
|
||||
ParentHashesError::BadObliqueHashes => AttestationValidationError::BadObliqueHashes,
|
||||
ParentHashesError::SlotTooLow => AttestationValidationError::BlockSlotTooLow,
|
||||
ParentHashesError::SlotTooHigh => AttestationValidationError::BlockSlotTooHigh,
|
||||
ParentHashesError::IntWrapping => AttestationValidationError::IntWrapping,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -228,8 +218,7 @@ impl From<BeaconBlockAtSlotError> for AttestationValidationError {
|
||||
fn from(e: BeaconBlockAtSlotError) -> Self {
|
||||
match e {
|
||||
BeaconBlockAtSlotError::DBError(s) => AttestationValidationError::DBError(s),
|
||||
_ => AttestationValidationError::InvalidJustifiedBlockHash
|
||||
|
||||
_ => AttestationValidationError::InvalidJustifiedBlockHash,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,14 +232,16 @@ impl From<DBError> for AttestationValidationError {
|
||||
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),
|
||||
SignatureVerificationError::BadValidatorIndex => {
|
||||
AttestationValidationError::BadAttesterMap
|
||||
}
|
||||
SignatureVerificationError::PublicKeyCorrupt => {
|
||||
AttestationValidationError::PublicKeyCorrupt
|
||||
}
|
||||
SignatureVerificationError::NoPublicKeyForValidator => {
|
||||
AttestationValidationError::NoPublicKeyForValidator
|
||||
}
|
||||
SignatureVerificationError::DBError(s) => AttestationValidationError::DBError(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
extern crate db;
|
||||
extern crate bls;
|
||||
extern crate db;
|
||||
extern crate hashing;
|
||||
extern crate ssz;
|
||||
extern crate ssz_helpers;
|
||||
extern crate types;
|
||||
|
||||
pub mod attestation_validation;
|
||||
mod attestation_parent_hashes;
|
||||
pub mod attestation_validation;
|
||||
pub mod block_validation;
|
||||
mod message_generation;
|
||||
mod signature_verification;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::ssz::SszStream;
|
||||
use super::hashing::canonical_hash;
|
||||
use super::ssz::SszStream;
|
||||
use super::types::Hash256;
|
||||
|
||||
/// Generates the message used to validate the signature provided with an AttestationRecord.
|
||||
@@ -10,9 +10,8 @@ pub fn generate_signed_message(
|
||||
parent_hashes: &[Hash256],
|
||||
shard_id: u16,
|
||||
shard_block_hash: &Hash256,
|
||||
justified_slot: u64)
|
||||
-> Vec<u8>
|
||||
{
|
||||
justified_slot: u64,
|
||||
) -> Vec<u8> {
|
||||
/*
|
||||
* Note: it's a little risky here to use SSZ, because the encoding is not necessarily SSZ
|
||||
* (for example, SSZ might change whilst this doesn't).
|
||||
@@ -39,9 +38,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_generate_signed_message() {
|
||||
let slot = 93;
|
||||
let parent_hashes: Vec<Hash256> = (0..12)
|
||||
.map(|i| Hash256::from(i as u64))
|
||||
.collect();
|
||||
let parent_hashes: Vec<Hash256> = (0..12).map(|i| Hash256::from(i as u64)).collect();
|
||||
let shard_id = 15;
|
||||
let shard_block_hash = Hash256::from("shard_block_hash".as_bytes());
|
||||
let justified_slot = 18;
|
||||
@@ -51,7 +48,8 @@ mod tests {
|
||||
&parent_hashes,
|
||||
shard_id,
|
||||
&shard_block_hash,
|
||||
justified_slot);
|
||||
justified_slot,
|
||||
);
|
||||
|
||||
/*
|
||||
* Note: this is not some well-known test vector, it's simply the result of running
|
||||
@@ -60,9 +58,8 @@ mod tests {
|
||||
* Once well-known test vectors are established, they should be placed here.
|
||||
*/
|
||||
let expected = vec![
|
||||
149, 99, 94, 229, 72, 144, 233, 14, 164, 16, 143, 53, 94, 48,
|
||||
118, 179, 33, 181, 172, 215, 2, 191, 176, 18, 188, 172, 137,
|
||||
178, 236, 66, 74, 120
|
||||
149, 99, 94, 229, 72, 144, 233, 14, 164, 16, 143, 53, 94, 48, 118, 179, 33, 181, 172,
|
||||
215, 2, 191, 176, 18, 188, 172, 137, 178, 236, 66, 74, 120,
|
||||
];
|
||||
|
||||
assert_eq!(output, expected);
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
use std::collections::HashSet;
|
||||
use super::bls::{
|
||||
AggregateSignature,
|
||||
AggregatePublicKey,
|
||||
};
|
||||
use super::bls::{AggregatePublicKey, AggregateSignature};
|
||||
use super::db::stores::{ValidatorStore, ValidatorStoreError};
|
||||
use super::db::ClientDB;
|
||||
use super::db::stores::{
|
||||
ValidatorStore,
|
||||
ValidatorStoreError,
|
||||
};
|
||||
use super::types::Bitfield;
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum SignatureVerificationError {
|
||||
@@ -30,9 +24,10 @@ pub fn verify_aggregate_signature_for_indices<T>(
|
||||
agg_sig: &AggregateSignature,
|
||||
attestation_indices: &[usize],
|
||||
bitfield: &Bitfield,
|
||||
validator_store: &ValidatorStore<T>)
|
||||
-> Result<Option<HashSet<usize>>, SignatureVerificationError>
|
||||
where T: ClientDB + Sized
|
||||
validator_store: &ValidatorStore<T>,
|
||||
) -> Result<Option<HashSet<usize>>, SignatureVerificationError>
|
||||
where
|
||||
T: ClientDB + Sized,
|
||||
{
|
||||
let mut voters = HashSet::new();
|
||||
let mut agg_pub_key = AggregatePublicKey::new();
|
||||
@@ -43,7 +38,8 @@ pub fn verify_aggregate_signature_for_indices<T>(
|
||||
/*
|
||||
* De-reference the attestation index into a canonical ValidatorRecord index.
|
||||
*/
|
||||
let validator = *attestation_indices.get(i)
|
||||
let validator = *attestation_indices
|
||||
.get(i)
|
||||
.ok_or(SignatureVerificationError::BadValidatorIndex)?;
|
||||
/*
|
||||
* Load the validators public key from our store.
|
||||
@@ -77,23 +73,17 @@ pub fn verify_aggregate_signature_for_indices<T>(
|
||||
impl From<ValidatorStoreError> for SignatureVerificationError {
|
||||
fn from(error: ValidatorStoreError) -> Self {
|
||||
match error {
|
||||
ValidatorStoreError::DBError(s) =>
|
||||
SignatureVerificationError::DBError(s),
|
||||
ValidatorStoreError::DecodeError =>
|
||||
SignatureVerificationError::PublicKeyCorrupt,
|
||||
ValidatorStoreError::DBError(s) => SignatureVerificationError::DBError(s),
|
||||
ValidatorStoreError::DecodeError => SignatureVerificationError::PublicKeyCorrupt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::super::bls::{
|
||||
Keypair,
|
||||
Signature,
|
||||
};
|
||||
use super::super::bls::{Keypair, Signature};
|
||||
use super::super::db::MemoryDB;
|
||||
use super::*;
|
||||
use std::sync::Arc;
|
||||
|
||||
/*
|
||||
@@ -130,8 +120,7 @@ mod tests {
|
||||
let mut all_keypairs = signing_keypairs.clone();
|
||||
all_keypairs.append(&mut non_signing_keypairs.clone());
|
||||
|
||||
let attestation_indices: Vec<usize> = (0..all_keypairs.len())
|
||||
.collect();
|
||||
let attestation_indices: Vec<usize> = (0..all_keypairs.len()).collect();
|
||||
let mut bitfield = Bitfield::new();
|
||||
for i in 0..signing_keypairs.len() {
|
||||
bitfield.set_bit(i, true);
|
||||
@@ -158,11 +147,11 @@ mod tests {
|
||||
&agg_sig,
|
||||
&attestation_indices,
|
||||
&bitfield,
|
||||
&store).unwrap();
|
||||
&store,
|
||||
).unwrap();
|
||||
|
||||
let voters = voters.unwrap();
|
||||
(0..signing_keypairs.len())
|
||||
.for_each(|i| assert!(voters.contains(&i)));
|
||||
(0..signing_keypairs.len()).for_each(|i| assert!(voters.contains(&i)));
|
||||
(signing_keypairs.len()..non_signing_keypairs.len())
|
||||
.for_each(|i| assert!(!voters.contains(&i)));
|
||||
|
||||
@@ -176,7 +165,8 @@ mod tests {
|
||||
&agg_sig,
|
||||
&attestation_indices,
|
||||
&bitfield,
|
||||
&store).unwrap();
|
||||
&store,
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(voters, None);
|
||||
}
|
||||
|
||||
@@ -1,33 +1,12 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::db::{
|
||||
MemoryDB,
|
||||
};
|
||||
use super::db::stores::{
|
||||
ValidatorStore,
|
||||
BeaconBlockStore,
|
||||
};
|
||||
use super::types::{
|
||||
AttestationRecord,
|
||||
AttesterMap,
|
||||
Bitfield,
|
||||
BeaconBlock,
|
||||
Hash256,
|
||||
};
|
||||
use super::validation::attestation_validation::{
|
||||
AttestationValidationContext,
|
||||
};
|
||||
use super::bls::{
|
||||
AggregateSignature,
|
||||
Keypair,
|
||||
SecretKey,
|
||||
Signature,
|
||||
};
|
||||
use super::bls::{AggregateSignature, Keypair, SecretKey, Signature};
|
||||
use super::db::stores::{BeaconBlockStore, ValidatorStore};
|
||||
use super::db::MemoryDB;
|
||||
use super::hashing::canonical_hash;
|
||||
use super::ssz::SszStream;
|
||||
use super::hashing::{
|
||||
canonical_hash,
|
||||
};
|
||||
|
||||
use super::types::{AttestationRecord, AttesterMap, BeaconBlock, Bitfield, Hash256};
|
||||
use super::validation::attestation_validation::AttestationValidationContext;
|
||||
|
||||
pub struct TestStore {
|
||||
pub db: Arc<MemoryDB>,
|
||||
@@ -55,13 +34,13 @@ pub struct TestRig {
|
||||
pub attester_count: usize,
|
||||
}
|
||||
|
||||
fn generate_message_hash(slot: u64,
|
||||
parent_hashes: &[Hash256],
|
||||
shard_id: u16,
|
||||
shard_block_hash: &Hash256,
|
||||
justified_slot: u64)
|
||||
-> Vec<u8>
|
||||
{
|
||||
fn generate_message_hash(
|
||||
slot: u64,
|
||||
parent_hashes: &[Hash256],
|
||||
shard_id: u16,
|
||||
shard_block_hash: &Hash256,
|
||||
justified_slot: u64,
|
||||
) -> Vec<u8> {
|
||||
let mut stream = SszStream::new();
|
||||
stream.append(&slot);
|
||||
stream.append_vec(&parent_hashes.to_vec());
|
||||
@@ -72,18 +51,18 @@ fn generate_message_hash(slot: u64,
|
||||
canonical_hash(&bytes)
|
||||
}
|
||||
|
||||
pub fn generate_attestation(shard_id: u16,
|
||||
shard_block_hash: &Hash256,
|
||||
block_slot: u64,
|
||||
attestation_slot: u64,
|
||||
justified_slot: u64,
|
||||
justified_block_hash: &Hash256,
|
||||
cycle_length: u8,
|
||||
parent_hashes: &[Hash256],
|
||||
signing_keys: &[Option<SecretKey>],
|
||||
block_store: &BeaconBlockStore<MemoryDB>)
|
||||
-> AttestationRecord
|
||||
{
|
||||
pub fn generate_attestation(
|
||||
shard_id: u16,
|
||||
shard_block_hash: &Hash256,
|
||||
block_slot: u64,
|
||||
attestation_slot: u64,
|
||||
justified_slot: u64,
|
||||
justified_block_hash: &Hash256,
|
||||
cycle_length: u8,
|
||||
parent_hashes: &[Hash256],
|
||||
signing_keys: &[Option<SecretKey>],
|
||||
block_store: &BeaconBlockStore<MemoryDB>,
|
||||
) -> AttestationRecord {
|
||||
let mut attester_bitfield = Bitfield::new();
|
||||
let mut aggregate_sig = AggregateSignature::new();
|
||||
|
||||
@@ -107,7 +86,8 @@ pub fn generate_attestation(shard_id: u16,
|
||||
parent_hashes_slice,
|
||||
shard_id,
|
||||
shard_block_hash,
|
||||
justified_slot);
|
||||
justified_slot,
|
||||
);
|
||||
|
||||
for (i, secret_key) in signing_keys.iter().enumerate() {
|
||||
/*
|
||||
@@ -143,7 +123,9 @@ pub fn create_block_at_slot(block_store: &BeaconBlockStore<MemoryDB>, hash: &Has
|
||||
let mut s = SszStream::new();
|
||||
s.append(&justified_block);
|
||||
let justified_block_ssz = s.drain();
|
||||
block_store.put_serialized_block(&hash.to_vec(), &justified_block_ssz).unwrap();
|
||||
block_store
|
||||
.put_serialized_block(&hash.to_vec(), &justified_block_ssz)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// Inserts a justified_block_hash in a position that will be referenced by an attestation record.
|
||||
@@ -151,16 +133,14 @@ pub fn insert_justified_block_hash(
|
||||
parent_hashes: &mut Vec<Hash256>,
|
||||
justified_block_hash: &Hash256,
|
||||
block_slot: u64,
|
||||
attestation_slot: u64)
|
||||
{
|
||||
let attestation_parent_hash_index = parent_hashes.len() - 1 -
|
||||
(block_slot as usize - attestation_slot as usize);
|
||||
attestation_slot: u64,
|
||||
) {
|
||||
let attestation_parent_hash_index =
|
||||
parent_hashes.len() - 1 - (block_slot as usize - attestation_slot as usize);
|
||||
parent_hashes[attestation_parent_hash_index] = justified_block_hash.clone();
|
||||
}
|
||||
|
||||
pub fn setup_attestation_validation_test(shard_id: u16, attester_count: usize)
|
||||
-> TestRig
|
||||
{
|
||||
pub fn setup_attestation_validation_test(shard_id: u16, attester_count: usize) -> TestRig {
|
||||
let stores = TestStore::new();
|
||||
|
||||
let block_slot = 10000;
|
||||
@@ -181,7 +161,8 @@ pub fn setup_attestation_validation_test(shard_id: u16, attester_count: usize)
|
||||
&mut parent_hashes,
|
||||
&justified_block_hash,
|
||||
block_slot,
|
||||
attestation_slot);
|
||||
attestation_slot,
|
||||
);
|
||||
|
||||
let parent_hashes = Arc::new(parent_hashes);
|
||||
|
||||
@@ -195,11 +176,14 @@ pub fn setup_attestation_validation_test(shard_id: u16, attester_count: usize)
|
||||
* list of keypairs. Store it in the database.
|
||||
*/
|
||||
for i in 0..attester_count {
|
||||
let keypair = Keypair::random();
|
||||
keypairs.push(keypair.clone());
|
||||
stores.validator.put_public_key_by_index(i, &keypair.pk).unwrap();
|
||||
signing_keys.push(Some(keypair.sk.clone()));
|
||||
attesters.push(i);
|
||||
let keypair = Keypair::random();
|
||||
keypairs.push(keypair.clone());
|
||||
stores
|
||||
.validator
|
||||
.put_public_key_by_index(i, &keypair.pk)
|
||||
.unwrap();
|
||||
signing_keys.push(Some(keypair.sk.clone()));
|
||||
attesters.push(i);
|
||||
}
|
||||
attester_map.insert((attestation_slot, shard_id), attesters);
|
||||
|
||||
@@ -223,7 +207,8 @@ pub fn setup_attestation_validation_test(shard_id: u16, attester_count: usize)
|
||||
cycle_length,
|
||||
&parent_hashes.clone(),
|
||||
&signing_keys,
|
||||
&stores.block);
|
||||
&stores.block,
|
||||
);
|
||||
|
||||
TestRig {
|
||||
attestation,
|
||||
|
||||
@@ -3,7 +3,7 @@ mod tests;
|
||||
|
||||
use super::bls;
|
||||
use super::db;
|
||||
use super::hashing;
|
||||
use super::ssz;
|
||||
use super::types;
|
||||
use super::hashing;
|
||||
use super::validation;
|
||||
|
||||
@@ -1,20 +1,10 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::helpers::{
|
||||
TestRig,
|
||||
setup_attestation_validation_test,
|
||||
create_block_at_slot,
|
||||
};
|
||||
use super::validation::attestation_validation::{
|
||||
AttestationValidationError,
|
||||
};
|
||||
use super::bls::AggregateSignature;
|
||||
use super::helpers::{create_block_at_slot, setup_attestation_validation_test, TestRig};
|
||||
use super::types::AttesterMap;
|
||||
use super::bls::{
|
||||
AggregateSignature,
|
||||
};
|
||||
use super::types::{
|
||||
Hash256,
|
||||
};
|
||||
use super::types::Hash256;
|
||||
use super::validation::attestation_validation::AttestationValidationError;
|
||||
|
||||
fn generic_rig() -> TestRig {
|
||||
let shard_id = 10;
|
||||
@@ -80,21 +70,29 @@ fn test_attestation_validation_invalid_justified_slot_incorrect() {
|
||||
create_block_at_slot(
|
||||
&rig.stores.block,
|
||||
&rig.attestation.justified_block_hash,
|
||||
rig.attestation.justified_slot);
|
||||
rig.attestation.justified_slot,
|
||||
);
|
||||
let result = rig.context.validate_attestation(&rig.attestation);
|
||||
assert_eq!(result, Err(AttestationValidationError::BadAggregateSignature));
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(AttestationValidationError::BadAggregateSignature)
|
||||
);
|
||||
|
||||
rig.attestation.justified_slot = original + 1;
|
||||
// Ensures we don't get a bad justified block error instead.
|
||||
create_block_at_slot(
|
||||
&rig.stores.block,
|
||||
&rig.attestation.justified_block_hash,
|
||||
rig.attestation.justified_slot);
|
||||
rig.attestation.justified_slot,
|
||||
);
|
||||
// Ensures we don't get an error that the last justified slot is ahead of the context justified
|
||||
// slot.
|
||||
rig.context.last_justified_slot = rig.attestation.justified_slot;
|
||||
let result = rig.context.validate_attestation(&rig.attestation);
|
||||
assert_eq!(result, Err(AttestationValidationError::BadAggregateSignature));
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(AttestationValidationError::BadAggregateSignature)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -108,7 +106,10 @@ fn test_attestation_validation_invalid_too_many_oblique() {
|
||||
rig.attestation.oblique_parent_hashes = obliques;
|
||||
|
||||
let result = rig.context.validate_attestation(&rig.attestation);
|
||||
assert_eq!(result, Err(AttestationValidationError::TooManyObliqueHashes));
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(AttestationValidationError::TooManyObliqueHashes)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -132,8 +133,12 @@ fn test_attestation_validation_invalid_bad_bitfield_length() {
|
||||
* of the bitfield.
|
||||
*/
|
||||
let one_byte_higher = rig.attester_count + 8;
|
||||
rig.attestation.attester_bitfield.set_bit(one_byte_higher, true);
|
||||
rig.attestation.attester_bitfield.set_bit(one_byte_higher, false);
|
||||
rig.attestation
|
||||
.attester_bitfield
|
||||
.set_bit(one_byte_higher, true);
|
||||
rig.attestation
|
||||
.attester_bitfield
|
||||
.set_bit(one_byte_higher, false);
|
||||
|
||||
let result = rig.context.validate_attestation(&rig.attestation);
|
||||
assert_eq!(result, Err(AttestationValidationError::BadBitfieldLength));
|
||||
@@ -144,10 +149,15 @@ fn test_attestation_validation_invalid_invalid_bitfield_end_bit() {
|
||||
let mut rig = generic_rig();
|
||||
|
||||
let one_bit_high = rig.attester_count + 1;
|
||||
rig.attestation.attester_bitfield.set_bit(one_bit_high, true);
|
||||
rig.attestation
|
||||
.attester_bitfield
|
||||
.set_bit(one_bit_high, true);
|
||||
|
||||
let result = rig.context.validate_attestation(&rig.attestation);
|
||||
assert_eq!(result, Err(AttestationValidationError::InvalidBitfieldEndBits));
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(AttestationValidationError::InvalidBitfieldEndBits)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -164,11 +174,19 @@ fn test_attestation_validation_invalid_invalid_bitfield_end_bit_with_irreguar_bi
|
||||
* bit in a bitfield and the byte length of that bitfield
|
||||
*/
|
||||
let one_bit_high = rig.attester_count + 1;
|
||||
assert!(one_bit_high % 8 != 0, "the test is ineffective in this case.");
|
||||
rig.attestation.attester_bitfield.set_bit(one_bit_high, true);
|
||||
assert!(
|
||||
one_bit_high % 8 != 0,
|
||||
"the test is ineffective in this case."
|
||||
);
|
||||
rig.attestation
|
||||
.attester_bitfield
|
||||
.set_bit(one_bit_high, true);
|
||||
|
||||
let result = rig.context.validate_attestation(&rig.attestation);
|
||||
assert_eq!(result, Err(AttestationValidationError::InvalidBitfieldEndBits));
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(AttestationValidationError::InvalidBitfieldEndBits)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -178,7 +196,10 @@ fn test_attestation_validation_invalid_unknown_justified_block_hash() {
|
||||
rig.attestation.justified_block_hash = Hash256::from("unknown block hash".as_bytes());
|
||||
|
||||
let result = rig.context.validate_attestation(&rig.attestation);
|
||||
assert_eq!(result, Err(AttestationValidationError::InvalidJustifiedBlockHash));
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(AttestationValidationError::InvalidJustifiedBlockHash)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -191,9 +212,13 @@ fn test_attestation_validation_invalid_unknown_justified_block_hash_wrong_slot()
|
||||
create_block_at_slot(
|
||||
&rig.stores.block,
|
||||
&rig.attestation.justified_block_hash,
|
||||
rig.attestation.justified_slot + 1);
|
||||
rig.attestation.justified_slot + 1,
|
||||
);
|
||||
let result = rig.context.validate_attestation(&rig.attestation);
|
||||
assert_eq!(result, Err(AttestationValidationError::InvalidJustifiedBlockHash));
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(AttestationValidationError::InvalidJustifiedBlockHash)
|
||||
);
|
||||
|
||||
/*
|
||||
* justified_block_hash points to a block with a slot that is too low.
|
||||
@@ -201,9 +226,13 @@ fn test_attestation_validation_invalid_unknown_justified_block_hash_wrong_slot()
|
||||
create_block_at_slot(
|
||||
&rig.stores.block,
|
||||
&rig.attestation.justified_block_hash,
|
||||
rig.attestation.justified_slot - 1);
|
||||
rig.attestation.justified_slot - 1,
|
||||
);
|
||||
let result = rig.context.validate_attestation(&rig.attestation);
|
||||
assert_eq!(result, Err(AttestationValidationError::InvalidJustifiedBlockHash));
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(AttestationValidationError::InvalidJustifiedBlockHash)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -213,5 +242,8 @@ fn test_attestation_validation_invalid_empty_signature() {
|
||||
rig.attestation.aggregate_sig = AggregateSignature::new();
|
||||
|
||||
let result = rig.context.validate_attestation(&rig.attestation);
|
||||
assert_eq!(result, Err(AttestationValidationError::BadAggregateSignature));
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(AttestationValidationError::BadAggregateSignature)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user