6ef4268d6d
Previously there was not a check that the hash was in the chain, just that it was known (in the database in any chain)
233 lines
6.8 KiB
Rust
233 lines
6.8 KiB
Rust
use std::sync::Arc;
|
|
|
|
use super::db::{
|
|
MemoryDB,
|
|
};
|
|
use super::db::stores::{
|
|
ValidatorStore,
|
|
BlockStore,
|
|
};
|
|
use super::types::{
|
|
AttestationRecord,
|
|
AttesterMap,
|
|
Bitfield,
|
|
Block,
|
|
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 validator: Arc<ValidatorStore<MemoryDB>>,
|
|
pub block: Arc<BlockStore<MemoryDB>>,
|
|
}
|
|
|
|
impl TestStore {
|
|
pub fn new() -> Self {
|
|
let db = Arc::new(MemoryDB::open());
|
|
let validator = Arc::new(ValidatorStore::new(db.clone()));
|
|
let block = Arc::new(BlockStore::new(db.clone()));
|
|
Self {
|
|
db,
|
|
validator,
|
|
block,
|
|
}
|
|
}
|
|
}
|
|
|
|
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>],
|
|
block_store: &BlockStore<MemoryDB>)
|
|
-> 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]
|
|
};
|
|
|
|
/*
|
|
* Create a justified block at the correct slot and store it in the db.
|
|
*/
|
|
create_block_at_slot(&block_store, &justified_block_hash, justified_slot);
|
|
|
|
/*
|
|
* 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,
|
|
}
|
|
}
|
|
|
|
/// Create a minimum viable block at some slot.
|
|
///
|
|
/// Allows the validation function to read the block and verify its slot.
|
|
pub fn create_block_at_slot(block_store: &BlockStore<MemoryDB>, hash: &Hash256, slot: u64) {
|
|
let mut justified_block = Block::zero();
|
|
justified_block.attestations.push(AttestationRecord::zero());
|
|
justified_block.slot_number = slot;
|
|
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();
|
|
}
|
|
|
|
/// Inserts a justified_block_hash in a position that will be referenced by an attestation record.
|
|
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);
|
|
parent_hashes[attestation_parent_hash_index] = justified_block_hash.clone();
|
|
}
|
|
|
|
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 mut parent_hashes: Vec<Hash256> = (0..(cycle_length * 2))
|
|
.map(|i| Hash256::from(i as u64))
|
|
.collect();
|
|
let attestation_slot = block_slot - 1;
|
|
let last_justified_slot = attestation_slot - 1;
|
|
let justified_block_hash = Hash256::from("justified_block".as_bytes());
|
|
let shard_block_hash = Hash256::from("shard_block".as_bytes());
|
|
|
|
/*
|
|
* Insert the required justified_block_hash into parent_hashes
|
|
*/
|
|
insert_justified_block_hash(
|
|
&mut parent_hashes,
|
|
&justified_block_hash,
|
|
block_slot,
|
|
attestation_slot);
|
|
|
|
let parent_hashes = Arc::new(parent_hashes);
|
|
|
|
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,
|
|
&stores.block);
|
|
|
|
TestRig {
|
|
attestation,
|
|
context,
|
|
stores,
|
|
attester_count,
|
|
}
|
|
}
|