lighthouse/beacon_chain/validation/tests/attestation_validation/helpers.rs
Paul Hauner 117a207d49
Add pre-written validation code
This adds block and attestation validation code that was written
previously. There were many non-validation specific changes made whilst
building these functions (e.g., db, hashing, etc) -- these changes have
already been merged into master and this branch has been created just to
make it easy to review this code.
2018-10-02 17:35:03 +10:00

193 lines
5.4 KiB
Rust

use std::sync::Arc;
use super::db::{
MemoryDB,
};
use super::db::stores::{
BlockStore,
ValidatorStore,
};
use super::types::{
AttestationRecord,
AttesterMap,
Bitfield,
Hash256,
};
use super::validation::attestation_validation::{
AttestationValidationContext,
};
use super::bls::{
AggregateSignature,
Keypair,
SecretKey,
Signature,
};
use super::ssz::SszStream;
use super::hashing::{
canonical_hash,
};
pub struct TestStore {
pub db: Arc<MemoryDB>,
pub block: Arc<BlockStore<MemoryDB>>,
pub validator: Arc<ValidatorStore<MemoryDB>>,
}
impl TestStore {
pub fn new() -> Self {
let db = Arc::new(MemoryDB::open());
let block = Arc::new(BlockStore::new(db.clone()));
let validator = Arc::new(ValidatorStore::new(db.clone()));
Self {
db,
block,
validator,
}
}
}
pub struct TestRig {
pub attestation: AttestationRecord,
pub context: AttestationValidationContext<MemoryDB>,
pub stores: TestStore,
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>
{
let mut stream = SszStream::new();
stream.append(&slot);
stream.append_vec(&parent_hashes.to_vec());
stream.append(&shard_id);
stream.append(shard_block_hash);
stream.append(&justified_slot);
let bytes = stream.drain();
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>])
-> AttestationRecord
{
let mut attester_bitfield = Bitfield::new();
let mut aggregate_sig = AggregateSignature::new();
let parent_hashes_slice = {
let distance: usize = (block_slot - attestation_slot) as usize;
let last: usize = parent_hashes.len() - distance;
let first: usize = last - usize::from(cycle_length);
&parent_hashes[first..last]
};
/*
* Generate the message that will be signed across for this attr record.
*/
let attestation_message = generate_message_hash(
attestation_slot,
parent_hashes_slice,
shard_id,
shard_block_hash,
justified_slot);
for (i, secret_key) in signing_keys.iter().enumerate() {
/*
* If the signing key is Some, set the bitfield bit to true
* and sign the aggregate sig.
*/
if let Some(sk) = secret_key {
attester_bitfield.set_bit(i, true);
let sig = Signature::new(&attestation_message, sk);
aggregate_sig.add(&sig);
}
}
AttestationRecord {
slot: attestation_slot,
shard_id,
oblique_parent_hashes: vec![],
shard_block_hash: shard_block_hash.clone(),
attester_bitfield,
justified_slot,
justified_block_hash: justified_block_hash.clone(),
aggregate_sig,
}
}
pub fn setup_attestation_validation_test(shard_id: u16, attester_count: usize)
-> TestRig
{
let stores = TestStore::new();
let block_slot = 10000;
let cycle_length: u8 = 64;
let last_justified_slot = block_slot - u64::from(cycle_length);
let parent_hashes: Vec<Hash256> = (0..(cycle_length * 2))
.map(|i| Hash256::from(i as u64))
.collect();
let parent_hashes = Arc::new(parent_hashes);
let justified_block_hash = Hash256::from("justified_block".as_bytes());
let shard_block_hash = Hash256::from("shard_block".as_bytes());
stores.block.put_serialized_block(&justified_block_hash.as_ref(), &[42]).unwrap();
let attestation_slot = block_slot - 1;
let mut keypairs = vec![];
let mut signing_keys = vec![];
let mut attester_map = AttesterMap::new();
let mut attesters = vec![];
/*
* Generate a random keypair for each validator and clone it into the
* 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);
}
attester_map.insert((attestation_slot, shard_id), attesters);
let context: AttestationValidationContext<MemoryDB> = AttestationValidationContext {
block_slot,
cycle_length,
last_justified_slot,
parent_hashes: parent_hashes.clone(),
block_store: stores.block.clone(),
validator_store: stores.validator.clone(),
attester_map: Arc::new(attester_map),
};
let attestation = generate_attestation(
shard_id,
&shard_block_hash,
block_slot,
attestation_slot,
last_justified_slot,
&justified_block_hash,
cycle_length,
&parent_hashes.clone(),
&signing_keys);
TestRig {
attestation,
context,
stores,
attester_count,
}
}