Draft in new 2.1 objects

This commit is contained in:
Paul Hauner 2018-08-10 10:48:03 +10:00
parent fd775e3252
commit 123c6d7088
9 changed files with 188 additions and 446 deletions

View File

@ -1,121 +1,31 @@
use super::partial_crosslink_record::PartialCrosslinkRecord;
use super::recent_proposer_record::RecentPropserRecord;
use super::rlp::{ RlpStream, Encodable };
use super::rlp::encode as rlp_encode;
use super::blake2::{ Blake2s, Digest };
use super::utils::types::*;
use super::utils::types::Hash256;
use super::attestation_record::AttestationRecord;
#[derive(Clone)]
pub struct ActiveState {
pub height: u64,
pub randao: Sha256Digest,
pub ffg_voter_bitfield: Bitfield,
pub recent_attesters: Vec<usize>, // TODO: should be u24
pub partial_crosslinks: Vec<PartialCrosslinkRecord>,
pub total_skip_count: u64,
pub recent_proposers: Vec<RecentPropserRecord>
pub pending_attestations: Vec<AttestationRecord>,
pub recent_block_hashes: Vec<Hash256>,
}
impl ActiveState {
/// Returns a new instance where all fields are empty vectors.
pub fn zero() -> Self {
Self {
height: 0,
randao: Sha256Digest::zero(),
ffg_voter_bitfield: Bitfield::new(),
recent_attesters: Vec::new(),
partial_crosslinks: Vec::new(),
total_skip_count: 0,
recent_proposers: Vec::new()
pending_attestations: vec![],
recent_block_hashes: vec![],
}
}
pub fn num_recent_proposers(&self) -> usize {
self.recent_proposers.len()
}
pub fn num_recent_attesters(&self) -> usize {
self.recent_attesters.len()
}
pub fn blake2s_hash(&self) -> Blake2sDigest {
let mut hasher = Blake2s::new();
hasher.input(&rlp_encode(self).into_vec());
let mut digest = Blake2sDigest::new();
digest.clone_from_slice(hasher.result().as_slice());
digest
}
}
/*
* RLP Encoding
*/
impl Encodable for ActiveState {
fn rlp_append(&self, s: &mut RlpStream) {
s.append(&self.height);
s.append(&self.randao);
s.append(&self.ffg_voter_bitfield);
s.append_list(&self.recent_attesters);
s.append_list(&self.partial_crosslinks);
s.append(&self.total_skip_count);
s.append_list(&self.recent_proposers);
}
}
#[cfg(test)]
mod tests {
use super::super::rlp;
use super::*;
#[test]
fn test_zero_fn() {
fn test_act_state_zero() {
let a = ActiveState::zero();
assert_eq!(a.height, 0);
// TODO: test all the things
assert_eq!(a.total_skip_count, 0);
}
#[test]
fn test_num_recent_proposers() {
let mut a = ActiveState::zero();
for _ in 1..5 {
a.recent_proposers.push(RecentPropserRecord::new(
1,
Sha256Digest::random(),
2));
}
assert_eq!(a.num_recent_proposers(), 4)
}
#[test]
fn test_num_recent_attesters() {
let mut a = ActiveState::zero();
for _ in 1..5 {
a.recent_attesters.push(1);
}
assert_eq!(a.num_recent_attesters(), 4)
}
#[test]
fn test_rlp_serialization() {
let a = ActiveState {
height: 100,
randao: Sha256Digest::zero(),
ffg_voter_bitfield: Bitfield::new(),
recent_attesters: Vec::new(),
partial_crosslinks: Vec::new(),
total_skip_count: 99,
recent_proposers: Vec::new()
};
let e = rlp::encode(&a);
assert_eq!(e.len(), 39);
assert_eq!(e[0], 100);
assert_eq!(e[1], 160);
assert_eq!(e[2..34], [0; 32]);
assert_eq!(e[34], 128);
assert_eq!(e[35], 192);
assert_eq!(e[36], 192);
assert_eq!(e[37], 99);
assert_eq!(e[38], 192);
assert_eq!(a.pending_attestations.len(), 0);
assert_eq!(a.recent_block_hashes.len(), 0);
}
}

View File

@ -0,0 +1,26 @@
use super::utils::types::{ Hash256, Bitfield };
use super::utils::bls::{ AggregateSignature };
#[derive(Clone)]
pub struct AttestationRecord {
slot: u64,
shard_id: u16,
oblique_parent_hashes: Vec<Hash256>,
shard_block_hash: Hash256,
attester_bitfield: Bitfield,
aggregate_sig: Option<AggregateSignature>,
}
impl AttestationRecord {
pub fn zero() -> Self {
Self {
slot: 0,
shard_id: 0,
oblique_parent_hashes: vec![],
shard_block_hash: Hash256::zero(),
attester_bitfield: Bitfield::new(),
aggregate_sig: None,
}
}
}

View File

@ -1,114 +1,56 @@
use super::utils::types::{ Sha256Digest, Bitfield, StateHash };
use super::utils::types::Hash256;
use super::utils::bls::{ Signature, AggregateSignature, Keypair, PublicKey };
use super::aggregate_vote::AggregateVote;
use super::rlp::{ RlpStream, Encodable } ;
use super::attestation_record::AttestationRecord;
use super::ssz;
use std::hash::{ Hash, Hasher };
const SSZ_BLOCK_LENGTH: usize = 192;
pub struct Block {
pub parent_hash: Sha256Digest,
pub skip_count: u64,
pub randao_reveal: Sha256Digest,
pub attestation_bitfield: Bitfield,
pub attestation_aggregate_sig: AggregateSignature,
pub shard_aggregate_votes: Vec<AggregateVote>,
pub main_chain_ref: Sha256Digest,
pub state_hash: StateHash,
pub sig: Option<Signature>
pub parent_hash: Hash256,
pub slot_number: u64,
pub randao_reveal: Hash256,
pub attestations: Vec<AttestationRecord>,
pub pow_chain_ref: Hash256,
pub active_state_root: Hash256,
pub crystallized_state_root: Hash256,
}
impl Block {
pub fn new(parent_hash: Sha256Digest,
randao_reveal: Sha256Digest,
main_chain_ref: Sha256Digest,
state_hash: StateHash) -> Block {
Block {
parent_hash: parent_hash,
skip_count: 0,
randao_reveal: randao_reveal,
attestation_bitfield: Bitfield::new(),
attestation_aggregate_sig: AggregateSignature::new(),
shard_aggregate_votes: Vec::new(),
main_chain_ref: main_chain_ref,
state_hash: state_hash,
sig: None
}
}
pub fn zero() -> Block {
Block {
parent_hash: Sha256Digest::zero(),
skip_count: 0,
randao_reveal: Sha256Digest::zero(),
attestation_bitfield: Bitfield::new(),
attestation_aggregate_sig: AggregateSignature::new(),
shard_aggregate_votes: vec![],
main_chain_ref: Sha256Digest::zero(),
state_hash: StateHash::zero(),
sig: None
pub fn zero() -> Self {
Self {
parent_hash: Hash256::zero(),
slot_number: 0,
randao_reveal: Hash256::zero(),
attestations: vec![],
pow_chain_ref: Hash256::zero(),
active_state_root: Hash256::zero(),
crystallized_state_root: Hash256::zero(),
}
}
/*
* Take a Block and covert it into an array of u8 for BLS signing
* or verfication. The `sig` field is purposefully omitted.
*/
pub fn encode_to_signable_message(&self) -> [u8; 9140] {
// Using biggest avg. block size from v2 spec
let mut message: [u8; 9140] = [0; 9140];
// Create the RLP vector
let mut s = RlpStream::new();
/// Returns a Vec<u8>
pub fn ssz_encode_without_attestations(&self)
-> [u8; SSZ_BLOCK_LENGTH]
{
let mut s = ssz::SszStream::new();
s.append(&self.parent_hash);
s.append(&self.skip_count);
s.append(&self.slot_number);
s.append(&self.randao_reveal);
s.append(&self.attestation_bitfield);
// s.append(&self.attestation_aggregate_sig); // TODO: RLP this
s.append_list(&self.shard_aggregate_votes);
s.append(&self.main_chain_ref);
// TODO: state hash serialization is probably incorrect.
s.append(&self.state_hash.crystallized_state);
s.append(&self.state_hash.active_state);
let rlp_vec = s.out();
// Parse the RLP vector into an array compatible with the BLS signer
let len = rlp_vec.len();
message[..len].copy_from_slice(&rlp_vec[..len]);
message
}
/*
* Sign the block with the given keypair.
*/
pub fn sig_sign(&mut self, keypair: &Keypair) {
let message = self.encode_to_signable_message();
self.sig = Some(keypair.sign(&message));
}
/*
* Verify a block signature given some keypair.
*/
pub fn sig_verify(&self, pub_key: &PublicKey) -> bool {
let message = self.encode_to_signable_message();
match &self.sig {
None => false,
Some(sig) => {
pub_key.verify(&message, &sig)
},
}
s.append(&self.pow_chain_ref);
s.append(&self.active_state_root);
s.append(&self.crystallized_state_root);
let vec = s.drain();
let mut encoded = [0; SSZ_BLOCK_LENGTH];
encoded.copy_from_slice(&vec); encoded
}
}
impl Encodable for Block {
fn rlp_append(&self, s: &mut RlpStream) {
s.append(&self.parent_hash);
s.append(&self.skip_count);
s.append(&self.randao_reveal);
s.append(&self.attestation_bitfield);
// s.append(&self.attestation_aggregate_sig); // TODO: RLP this
s.append_list(&self.shard_aggregate_votes);
s.append(&self.main_chain_ref);
// TODO: state hash serialization is probably incorrect.
s.append(&self.state_hash.crystallized_state);
s.append(&self.state_hash.active_state);
// s.append(&self.sig); // TODO: RLP this
impl Hash for Block {
fn hash<H: Hasher>(&self, state: &mut H) {
let bytes = self.ssz_encode_without_attestations();
bytes.hash(state);
}
}
@ -161,7 +103,7 @@ mod tests {
}
#[test]
fn test_rlp_serialization() {
fn test_ssz_serialization() {
let b = Block {
parent_hash: Sha256Digest::zero(),
skip_count: 100,

View File

@ -1,59 +1,30 @@
use super::utils::types::Sha256Digest;
use super::rlp::{ RlpStream, Encodable };
use super::utils::types::Hash256;
#[derive(Copy)]
#[derive(Clone)]
pub struct CrosslinkRecord {
pub epoch: u64,
pub hash: Sha256Digest
pub dynasty: u64,
pub hash: Hash256,
}
impl CrosslinkRecord {
pub fn new(epoch: u64, hash: Sha256Digest) -> CrosslinkRecord {
CrosslinkRecord {
epoch: epoch,
hash: hash
/// Generates a new instance where `dynasty` and `hash` are both zero.
pub fn zero() -> Self {
Self {
dynasty: 0,
hash: Hash256::zero(),
}
}
}
impl Clone for CrosslinkRecord {
fn clone(&self) -> CrosslinkRecord { *self }
}
/*
* RLP Encoding
*/
impl Encodable for CrosslinkRecord {
fn rlp_append(&self, s: &mut RlpStream) {
s.append(&self.epoch);
s.append(&self.hash);
}
}
#[cfg(test)]
mod tests {
use super::super::rlp;
use super::*;
#[test]
fn test_new() {
let epoch = 1;
let hash = Sha256Digest::random();
let c = CrosslinkRecord::new(epoch, hash);
assert_eq!(c.epoch, epoch);
assert_eq!(c.hash, hash);
}
#[test]
fn test_rlp_serialization() {
let c = CrosslinkRecord {
epoch: 100,
hash: Sha256Digest::zero()
};
let e = rlp::encode(&c);
assert_eq!(e.len(), 34);
assert_eq!(e[0], 100);
assert_eq!(e[1], 160);
assert_eq!(e[2..34], [0; 32]);
fn test_crosslink_record_zero() {
let c = CrosslinkRecord::zero();
assert_eq!(c.dynasty, 0);
assert!(c.hash.is_zero());
}
}

View File

@ -1,129 +1,66 @@
use super::utils::types::{ Sha256Digest, Blake2sDigest };
use super::validator_record::ValidatorRecord;
use super::crosslink_record::CrosslinkRecord;
use super::rlp::{ RlpStream, Encodable };
use super::rlp::encode as rlp_encode;
use super::shard_and_committee::ShardAndCommittee;
use super::ethereum_types::U256;
use super::blake2::{ Blake2s, Digest };
use super::utils::types::{ Hash256 };
#[derive(Clone)]
pub struct CrystallizedState {
pub active_validators: Vec<ValidatorRecord>,
pub queued_validators: Vec<ValidatorRecord>,
pub exited_validators: Vec<ValidatorRecord>,
pub current_shuffling: Vec<usize>, // TODO: should be u24
pub current_epoch: u64,
pub last_justified_epoch: u64,
pub last_finalized_epoch: u64,
pub dynasty: u64,
pub next_shard: u16,
pub current_checkpoint: Sha256Digest,
pub validators: Vec<ValidatorRecord>,
pub epoch_number: u64,
pub indicies_for_heights: Vec<ShardAndCommittee>,
pub last_justified_slot: u64,
pub justified_streak: u16,
pub last_finalized_slot: u64,
pub current_dynasty: u64,
pub crosslinking_shard_start: u16,
pub crosslink_records: Vec<CrosslinkRecord>,
pub total_deposits: U256,
pub dynasty_seed: Hash256,
pub dynasty_seed_last_reset: u64,
}
impl CrystallizedState {
// Returns a new instance with all values set to zero.
/// Returns a new instance where all fields are either zero or an
/// empty vector.
pub fn zero() -> Self {
Self {
active_validators: Vec::new(),
queued_validators: Vec::new(),
exited_validators: Vec::new(),
current_shuffling: Vec::new(),
current_epoch: 0,
last_justified_epoch: 0,
last_finalized_epoch: 0,
dynasty: 0,
next_shard: 0,
current_checkpoint: Sha256Digest::zero(),
crosslink_records: Vec::new(),
validators: vec![],
epoch_number: 0,
indicies_for_heights: vec![],
last_justified_slot: 0,
justified_streak: 0,
last_finalized_slot: 0,
current_dynasty: 0,
crosslinking_shard_start: 0,
crosslink_records: vec![],
total_deposits: U256::zero(),
dynasty_seed: Hash256::zero(),
dynasty_seed_last_reset: 0,
}
}
pub fn finality_distance(&self) -> u64 {
assert!(self.current_epoch >= self.last_finalized_epoch);
self.current_epoch - self.last_finalized_epoch
}
pub fn num_active_validators(&self) -> usize {
self.active_validators.len()
}
pub fn num_queued_validators(&self) -> usize {
self.queued_validators.len()
}
pub fn num_exited_validators(&self) -> usize {
self.exited_validators.len()
}
pub fn num_crosslink_records(&self) -> usize {
self.crosslink_records.len()
}
pub fn blake2s_hash(&self) -> Blake2sDigest {
let mut hasher = Blake2s::new();
hasher.input(&rlp_encode(self).into_vec());
let mut digest = Blake2sDigest::new();
digest.clone_from_slice(hasher.result().as_slice());
digest
}
}
/*
* RLP Encoding
*/
impl Encodable for CrystallizedState {
fn rlp_append(&self, s: &mut RlpStream) {
s.append_list(&self.active_validators);
s.append_list(&self.queued_validators);
s.append_list(&self.exited_validators);
s.append_list(&self.current_shuffling);
s.append(&self.current_epoch);
s.append(&self.last_justified_epoch);
s.append(&self.last_finalized_epoch);
s.append(&self.dynasty);
s.append(&self.next_shard);
s.append(&self.current_checkpoint);
s.append_list(&self.crosslink_records);
s.append(&self.total_deposits);
}
}
#[cfg(test)]
mod tests {
use super::super::rlp;
use super::*;
#[test]
fn test_rlp_serialization() {
let a = CrystallizedState {
active_validators: Vec::new(),
queued_validators: Vec::new(),
exited_validators: Vec::new(),
current_shuffling: Vec::new(),
current_epoch: 10,
last_justified_epoch: 8,
last_finalized_epoch: 2,
dynasty: 3,
next_shard: 12,
current_checkpoint: Sha256Digest::zero(),
crosslink_records: Vec::new(),
total_deposits: U256::zero(),
};
let e = rlp::encode(&a);
assert_eq!(e.len(), 44);
assert_eq!(e[0..4], [192; 4]);
assert_eq!(e[4], 10);
assert_eq!(e[5], 8);
assert_eq!(e[6], 2);
assert_eq!(e[7], 3);
assert_eq!(e[8], 12);
assert_eq!(e[9], 160);
assert_eq!(e[10..42], [0; 32]);
assert_eq!(e[42], 192);
assert_eq!(e[43], 128);
fn test_cry_state_zero() {
let c = CrystallizedState::zero();
assert_eq!(c.validators.len(), 0);
assert_eq!(c.epoch_number, 0);
assert_eq!(c.indicies_for_heights.len(), 0);
assert_eq!(c.last_justified_slot, 0);
assert_eq!(c.justified_streak, 0);
assert_eq!(c.last_finalized_slot, 0);
assert_eq!(c.current_dynasty, 0);
assert_eq!(c.crosslinking_shard_start, 0);
assert_eq!(c.crosslink_records.len(), 0);
assert!(c.total_deposits.is_zero());
assert!(c.dynasty_seed.is_zero());
assert_eq!(c.dynasty_seed_last_reset, 0);
}
}

View File

@ -2,17 +2,20 @@ extern crate rlp;
extern crate ethereum_types;
extern crate blake2;
extern crate bytes;
extern crate ssz;
use super::utils;
use super::pubkeystore;
// use super::pubkeystore;
pub mod active_state;
pub mod attestation_record;
pub mod crystallized_state;
pub mod config;
pub mod aggregate_vote;
// pub mod aggregate_vote;
pub mod block;
pub mod crosslink_record;
pub mod partial_crosslink_record;
pub mod recent_proposer_record;
pub mod transition;
// pub mod partial_crosslink_record;
// pub mod recent_proposer_record;
// pub mod transition;
pub mod shard_and_committee;
pub mod validator_record;

View File

@ -0,0 +1,28 @@
#[derive(Clone)]
pub struct ShardAndCommittee {
shard_id: u16,
committee: Vec<u32>
}
impl ShardAndCommittee {
/// Returns a new instance where the `shard_id` is zero and the
/// committee is an empty vector.
pub fn zero() -> Self {
Self {
shard_id: 0,
committee: vec![],
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_shard_and_committee_zero() {
let s = CrystallizedState::zero();
assert_eq!(s.shard_id, 0);
assert_eq!(s.committee.len(), 0);
}
}

View File

@ -1,8 +1,7 @@
extern crate rand;
use super::utils::types::{ Sha256Digest, Address, U256 };
use super::utils::types::{ Hash256, Address, U256 };
use super::utils::bls::{ PublicKey, Keypair };
use super::rlp::{ RlpStream, Encodable };
use self::rand::thread_rng;
@ -10,43 +9,17 @@ pub struct ValidatorRecord {
pub pubkey: PublicKey,
pub withdrawal_shard: u16,
pub withdrawal_address: Address,
pub randao_commitment: Sha256Digest,
pub randao_commitment: Hash256,
pub balance: U256,
pub switch_dynasty: u64
pub start_dynasty: u64,
pub end_dynasty: u64,
}
impl ValidatorRecord {
pub fn new(pubkey: PublicKey,
withdrawal_shard: u16,
withdrawal_address: Address,
randao_commitment: Sha256Digest,
balance: U256,
switch_dynasty: u64)
-> Self
{
Self {
pubkey,
withdrawal_shard,
withdrawal_address,
randao_commitment,
balance,
switch_dynasty
}
}
pub fn zero_with_thread_rand_pub_key() -> Self {
let mut rng = thread_rng();
let keypair = Keypair::generate(&mut rng);
Self {
pubkey: keypair.public,
withdrawal_shard: 0,
withdrawal_address: Address::zero(),
randao_commitment: Sha256Digest::zero(),
balance: U256::zero(),
switch_dynasty: 0
}
}
/// Generates a new instance where the keypair is generated using
/// `rand::thread_rng` entropy and all other fields are set to zero.
///
/// Returns the new instance and new keypair.
pub fn zero_with_thread_rand_keypair() -> (Self, Keypair) {
let mut rng = thread_rng();
let keypair = Keypair::generate(&mut rng);
@ -54,9 +27,10 @@ impl ValidatorRecord {
pubkey: keypair.public.clone(),
withdrawal_shard: 0,
withdrawal_address: Address::zero(),
randao_commitment: Sha256Digest::zero(),
randao_commitment: Hash256::zero(),
balance: U256::zero(),
switch_dynasty: 0
start_dynasty: 0,
end_dynasty: 0,
};
(s, keypair)
}
@ -72,20 +46,6 @@ impl Clone for ValidatorRecord {
}
}
/*
* RLP Encoding
*/
impl Encodable for ValidatorRecord {
fn rlp_append(&self, s: &mut RlpStream) {
// s.append(&self.pubkey); // TODO: serialize this
s.append(&self.withdrawal_shard);
s.append(&self.withdrawal_address);
s.append(&self.randao_commitment);
s.append(&self.balance);
s.append(&self.switch_dynasty);
}
}
#[cfg(test)]
mod tests {
@ -97,50 +57,14 @@ mod tests {
utils::test_helpers::get_dangerous_test_keypair;
#[test]
fn test_new() {
let keypair = get_dangerous_test_keypair();;
let withdrawal_shard = 1;
let withdrawal_address = Address::random();
let randao_commitment = Sha256Digest::random();
let balance = U256::from(100);
let switch_dynasty = 10;
let v = ValidatorRecord::new(
keypair.public,
withdrawal_shard,
withdrawal_address,
randao_commitment,
balance,
switch_dynasty);
// TODO: figure out how to compare keys
// assert_eq!(v.pubkey, keypair.public);
assert_eq!(v.withdrawal_shard, withdrawal_shard);
assert_eq!(v.withdrawal_address, withdrawal_address);
assert_eq!(v.randao_commitment, randao_commitment);
assert_eq!(v.balance, balance);
assert_eq!(v.switch_dynasty, switch_dynasty);
}
#[test]
fn test_rlp_serialization() {
let keypair = get_dangerous_test_keypair();
let v = ValidatorRecord {
pubkey: keypair.public,
withdrawal_shard: 100,
withdrawal_address: Address::zero(),
randao_commitment: Sha256Digest::zero(),
balance: U256::from(120),
switch_dynasty: 30
};
let e = rlp::encode(&v);
assert_eq!(e.len(), 57); // TODO: fix when pubkey is serialized
// TODO: test for serialized pubkey
assert_eq!(e[0], 100);
assert_eq!(e[1], 148);
assert_eq!(e[2..22], [0; 20]);
assert_eq!(e[22], 160);
assert_eq!(e[23..55], [0; 32]);
assert_eq!(e[55], 120);
assert_eq!(e[56], 30);
fn test_validator_record_zero_rand_keypair() {
let (v, kp) = ValidatorRecord::zero_with_thread_rand_keypair();
// TODO: check keys
assert_eq!(v.withdrawal_shard, 0);
assert!(v.withdrawal_address.is_zero());
assert!(v.randao_commitment.is_zero());
assert!(v.balance.is_zero());
assert_eq!(v.start_dynasty, 0);
assert_eq!(v.end_dynasty, 0);
}
}

View File

@ -11,6 +11,7 @@ pub use super::ethereum_types::U256;
// which is bad. Make the compiler think they're incompatible.
pub type Sha256Digest = H256;
pub type Blake2sDigest = H256;
pub type Hash256 = H256;
pub type Address = H160;