mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-08 17:26:04 +00:00
Heavily restructure repo
Separate most modules into crates
This commit is contained in:
11
beacon_chain/types/Cargo.toml
Normal file
11
beacon_chain/types/Cargo.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "types"
|
||||
version = "0.1.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
|
||||
[dependencies]
|
||||
bls = { path = "../utils/bls" }
|
||||
boolean-bitfield = { path = "../utils/boolean-bitfield" }
|
||||
ethereum-types = "0.4.0"
|
||||
rand = "0.3"
|
||||
ssz = { path = "../utils/ssz" }
|
||||
30
beacon_chain/types/src/active_state.rs
Normal file
30
beacon_chain/types/src/active_state.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
use super::Hash256;
|
||||
use super::attestation_record::AttestationRecord;
|
||||
|
||||
pub struct ActiveState {
|
||||
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 {
|
||||
pending_attestations: vec![],
|
||||
recent_block_hashes: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_act_state_zero() {
|
||||
let a = ActiveState::zero();
|
||||
assert_eq!(a.pending_attestations.len(), 0);
|
||||
assert_eq!(a.recent_block_hashes.len(), 0);
|
||||
}
|
||||
}
|
||||
137
beacon_chain/types/src/attestation_record.rs
Normal file
137
beacon_chain/types/src/attestation_record.rs
Normal file
@@ -0,0 +1,137 @@
|
||||
use super::{ Hash256, Bitfield };
|
||||
use super::bls::{
|
||||
AggregateSignature,
|
||||
BLS_AGG_SIG_BYTE_SIZE,
|
||||
};
|
||||
use super::ssz::{
|
||||
Encodable,
|
||||
Decodable,
|
||||
DecodeError,
|
||||
decode_ssz_list,
|
||||
SszStream,
|
||||
};
|
||||
|
||||
pub const MIN_SSZ_ATTESTION_RECORD_LENGTH: usize = {
|
||||
8 + // slot
|
||||
2 + // shard_id
|
||||
4 + // oblique_parent_hashes (empty list)
|
||||
32 + // shard_block_hash
|
||||
5 + // attester_bitfield (assuming 1 byte of bitfield)
|
||||
8 + // justified_slot
|
||||
32 + // justified_block_hash
|
||||
4 + BLS_AGG_SIG_BYTE_SIZE // aggregate sig (two 256 bit points)
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct AttestationRecord {
|
||||
pub slot: u64,
|
||||
pub shard_id: u16,
|
||||
pub oblique_parent_hashes: Vec<Hash256>,
|
||||
pub shard_block_hash: Hash256,
|
||||
pub attester_bitfield: Bitfield,
|
||||
pub justified_slot: u64,
|
||||
pub justified_block_hash: Hash256,
|
||||
pub aggregate_sig: AggregateSignature,
|
||||
}
|
||||
|
||||
impl Encodable for AttestationRecord {
|
||||
fn ssz_append(&self, s: &mut SszStream) {
|
||||
s.append(&self.slot);
|
||||
s.append(&self.shard_id);
|
||||
s.append_vec(&self.oblique_parent_hashes);
|
||||
s.append(&self.shard_block_hash);
|
||||
s.append_vec(&self.attester_bitfield.to_be_vec());
|
||||
s.append(&self.justified_slot);
|
||||
s.append(&self.justified_block_hash);
|
||||
s.append_vec(&self.aggregate_sig.as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for AttestationRecord {
|
||||
fn ssz_decode(bytes: &[u8], i: usize)
|
||||
-> Result<(Self, usize), DecodeError>
|
||||
{
|
||||
let (slot, i) = u64::ssz_decode(bytes, i)?;
|
||||
let (shard_id, i) = u16::ssz_decode(bytes, i)?;
|
||||
let (oblique_parent_hashes, i) = decode_ssz_list(bytes, i)?;
|
||||
let (shard_block_hash, i) = Hash256::ssz_decode(bytes, i)?;
|
||||
let (attester_bitfield, i) = Bitfield::ssz_decode(bytes, i)?;
|
||||
let (justified_slot, i) = u64::ssz_decode(bytes, i)?;
|
||||
let (justified_block_hash, i) = Hash256::ssz_decode(bytes, i)?;
|
||||
// Do aggregate sig decoding properly.
|
||||
let (agg_sig_bytes, i) = decode_ssz_list(bytes, i)?;
|
||||
let aggregate_sig = AggregateSignature::from_bytes(&agg_sig_bytes)
|
||||
.map_err(|_| DecodeError::TooShort)?; // also could be TooLong
|
||||
|
||||
let attestation_record = Self {
|
||||
slot,
|
||||
shard_id,
|
||||
oblique_parent_hashes,
|
||||
shard_block_hash,
|
||||
attester_bitfield,
|
||||
justified_slot,
|
||||
justified_block_hash,
|
||||
aggregate_sig,
|
||||
};
|
||||
Ok((attestation_record, i))
|
||||
}
|
||||
}
|
||||
|
||||
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(),
|
||||
justified_slot: 0,
|
||||
justified_block_hash: Hash256::zero(),
|
||||
aggregate_sig: AggregateSignature::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::super::ssz::SszStream;
|
||||
|
||||
#[test]
|
||||
pub fn test_attestation_record_min_ssz_length() {
|
||||
let ar = AttestationRecord::zero();
|
||||
let mut ssz_stream = SszStream::new();
|
||||
ssz_stream.append(&ar);
|
||||
let ssz = ssz_stream.drain();
|
||||
|
||||
assert_eq!(ssz.len(), MIN_SSZ_ATTESTION_RECORD_LENGTH);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_attestation_record_min_ssz_encode_decode() {
|
||||
let original = AttestationRecord {
|
||||
slot: 7,
|
||||
shard_id: 9,
|
||||
oblique_parent_hashes: vec![Hash256::from(&vec![14; 32][..])],
|
||||
shard_block_hash: Hash256::from(&vec![15; 32][..]),
|
||||
attester_bitfield: Bitfield::from(&vec![17; 42][..]),
|
||||
justified_slot: 19,
|
||||
justified_block_hash: Hash256::from(&vec![15; 32][..]),
|
||||
aggregate_sig: AggregateSignature::new(),
|
||||
};
|
||||
|
||||
let mut ssz_stream = SszStream::new();
|
||||
ssz_stream.append(&original);
|
||||
|
||||
let (decoded, _) = AttestationRecord::
|
||||
ssz_decode(&ssz_stream.drain(), 0).unwrap();
|
||||
assert_eq!(original.slot, decoded.slot);
|
||||
assert_eq!(original.shard_id, decoded.shard_id);
|
||||
assert_eq!(original.oblique_parent_hashes, decoded.oblique_parent_hashes);
|
||||
assert_eq!(original.shard_block_hash, decoded.shard_block_hash);
|
||||
assert_eq!(original.attester_bitfield, decoded.attester_bitfield);
|
||||
assert_eq!(original.justified_slot, decoded.justified_slot);
|
||||
assert_eq!(original.justified_block_hash, decoded.justified_block_hash);
|
||||
}
|
||||
}
|
||||
80
beacon_chain/types/src/block.rs
Normal file
80
beacon_chain/types/src/block.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
use super::Hash256;
|
||||
use super::attestation_record::AttestationRecord;
|
||||
use super::ssz::{ Encodable, SszStream };
|
||||
|
||||
pub const MIN_SSZ_BLOCK_LENGTH: usize = {
|
||||
32 + // parent_hash
|
||||
8 + // slot_number
|
||||
32 + // randao_reveal
|
||||
4 + // attestations (assuming zero)
|
||||
32 + // pow_chain_ref
|
||||
32 + // active_state_root
|
||||
32 // crystallized_state_root
|
||||
};
|
||||
pub const MAX_SSZ_BLOCK_LENGTH: usize = MIN_SSZ_BLOCK_LENGTH + (1 << 24);
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Block {
|
||||
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 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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Block {
|
||||
fn ssz_append(&self, s: &mut SszStream) {
|
||||
s.append(&self.parent_hash);
|
||||
s.append(&self.slot_number);
|
||||
s.append(&self.randao_reveal);
|
||||
s.append_vec(&self.attestations);
|
||||
s.append(&self.pow_chain_ref);
|
||||
s.append(&self.active_state_root);
|
||||
s.append(&self.crystallized_state_root);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_block_zero() {
|
||||
let b = Block::zero();
|
||||
assert!(b.parent_hash.is_zero());
|
||||
assert_eq!(b.slot_number, 0);
|
||||
assert!(b.randao_reveal.is_zero());
|
||||
assert_eq!(b.attestations.len(), 0);
|
||||
assert!(b.pow_chain_ref.is_zero());
|
||||
assert!(b.active_state_root.is_zero());
|
||||
assert!(b.crystallized_state_root.is_zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_block_min_ssz_length() {
|
||||
let b = Block::zero();
|
||||
|
||||
let mut ssz_stream = SszStream::new();
|
||||
ssz_stream.append(&b);
|
||||
let ssz = ssz_stream.drain();
|
||||
|
||||
assert_eq!(ssz.len(), MIN_SSZ_BLOCK_LENGTH);
|
||||
}
|
||||
}
|
||||
32
beacon_chain/types/src/chain_config.rs
Normal file
32
beacon_chain/types/src/chain_config.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
pub struct ChainConfig {
|
||||
pub cycle_length: u8,
|
||||
pub shard_count: u16,
|
||||
pub min_committee_size: u64,
|
||||
pub genesis_time: u64,
|
||||
}
|
||||
|
||||
/*
|
||||
* Presently this is just some arbitrary time in Sept 2018.
|
||||
*/
|
||||
const GENESIS_TIME: u64 = 1_537_488_655;
|
||||
|
||||
impl ChainConfig {
|
||||
pub fn standard() -> Self {
|
||||
Self {
|
||||
cycle_length: 64,
|
||||
shard_count: 1024,
|
||||
min_committee_size: 128,
|
||||
genesis_time: GENESIS_TIME, // arbitrary
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn super_fast_tests() -> Self {
|
||||
Self {
|
||||
cycle_length: 2,
|
||||
shard_count: 2,
|
||||
min_committee_size: 2,
|
||||
genesis_time: GENESIS_TIME, // arbitrary
|
||||
}
|
||||
}
|
||||
}
|
||||
62
beacon_chain/types/src/common/delegation/block_hash.rs
Normal file
62
beacon_chain/types/src/common/delegation/block_hash.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
use super::utils::errors::ParameterError;
|
||||
use super::utils::types::Hash256;
|
||||
|
||||
/*
|
||||
* Work-in-progress function: not ready for review.
|
||||
*/
|
||||
|
||||
pub fn get_block_hash(
|
||||
active_state_recent_block_hashes: &[Hash256],
|
||||
current_block_slot: u64,
|
||||
slot: u64,
|
||||
cycle_length: u64, // convert from standard u8
|
||||
) -> Result<Hash256, ParameterError> {
|
||||
// active_state must have at 2*cycle_length hashes
|
||||
assert_error!(
|
||||
active_state_recent_block_hashes.len() as u64 == cycle_length * 2,
|
||||
ParameterError::InvalidInput(String::from(
|
||||
"active state has incorrect number of block hashes"
|
||||
))
|
||||
);
|
||||
|
||||
let state_start_slot = (current_block_slot)
|
||||
.checked_sub(cycle_length * 2)
|
||||
.unwrap_or(0);
|
||||
|
||||
assert_error!(
|
||||
(state_start_slot <= slot) && (slot < current_block_slot),
|
||||
ParameterError::InvalidInput(String::from("incorrect slot number"))
|
||||
);
|
||||
|
||||
let index = 2 * cycle_length + slot - current_block_slot; // should always be positive
|
||||
Ok(active_state_recent_block_hashes[index as usize])
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_get_block_hash() {
|
||||
let block_slot: u64 = 10;
|
||||
let slot: u64 = 3;
|
||||
let cycle_length: u64 = 8;
|
||||
|
||||
let mut block_hashes: Vec<Hash256> = Vec::new();
|
||||
for _i in 0..2 * cycle_length {
|
||||
block_hashes.push(Hash256::random());
|
||||
}
|
||||
|
||||
let result = get_block_hash(
|
||||
&block_hashes,
|
||||
block_slot,
|
||||
slot,
|
||||
cycle_length)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
block_hashes[(2 * cycle_length + slot - block_slot) as usize]
|
||||
);
|
||||
}
|
||||
}
|
||||
3
beacon_chain/types/src/common/delegation/mod.rs
Normal file
3
beacon_chain/types/src/common/delegation/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
mod block_hash;
|
||||
|
||||
use super::utils;
|
||||
7
beacon_chain/types/src/common/maps.rs
Normal file
7
beacon_chain/types/src/common/maps.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Maps a (slot, shard_id) to attestation_indices.
|
||||
pub type AttesterMap = HashMap<(u64, u16), Vec<usize>>;
|
||||
|
||||
/// Maps a slot to a block proposer.
|
||||
pub type ProposerMap = HashMap<u64, usize>;
|
||||
9
beacon_chain/types/src/common/mod.rs
Normal file
9
beacon_chain/types/src/common/mod.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
mod delegation;
|
||||
mod shuffling;
|
||||
|
||||
pub mod maps;
|
||||
pub mod attestation_parent_hashes;
|
||||
|
||||
use super::utils;
|
||||
use super::utils::types::Hash256;
|
||||
pub use self::shuffling::shuffle;
|
||||
2
beacon_chain/types/src/common/shuffling/README.md
Normal file
2
beacon_chain/types/src/common/shuffling/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
This module includes the fundamental shuffling function. It does not do the
|
||||
full validator delegation amongst slots.
|
||||
52
beacon_chain/types/src/common/shuffling/mod.rs
Normal file
52
beacon_chain/types/src/common/shuffling/mod.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
extern crate blake2_rfc;
|
||||
|
||||
mod rng;
|
||||
|
||||
use self::rng::ShuffleRng;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ShuffleErr {
|
||||
ExceedsListLength,
|
||||
}
|
||||
|
||||
/// Performs a deterministic, in-place shuffle of a vector of bytes.
|
||||
/// The final order of the shuffle is determined by successive hashes
|
||||
/// of the supplied `seed`.
|
||||
pub fn shuffle(
|
||||
seed: &[u8],
|
||||
mut list: Vec<usize>)
|
||||
-> Result<Vec<usize>, ShuffleErr>
|
||||
{
|
||||
let mut rng = ShuffleRng::new(seed);
|
||||
if list.len() > rng.rand_max as usize {
|
||||
return Err(ShuffleErr::ExceedsListLength);
|
||||
}
|
||||
for i in 0..(list.len() - 1) {
|
||||
let n = list.len() - i;
|
||||
let j = rng.rand_range(n as u32) as usize + i;
|
||||
list.swap(i, j);
|
||||
}
|
||||
Ok(list)
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::blake2_rfc::blake2s::{ blake2s, Blake2sResult };
|
||||
|
||||
fn hash(seed: &[u8]) -> Blake2sResult {
|
||||
blake2s(32, &[], seed)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shuffling() {
|
||||
let seed = hash(b"4kn4driuctg8");
|
||||
let list: Vec<usize> = (0..12).collect();
|
||||
let s = shuffle(seed.as_bytes(), list).unwrap();
|
||||
assert_eq!(
|
||||
s,
|
||||
vec![7, 4, 8, 6, 5, 3, 0, 11, 1, 2, 10, 9],
|
||||
)
|
||||
}
|
||||
}
|
||||
129
beacon_chain/types/src/common/shuffling/rng.rs
Normal file
129
beacon_chain/types/src/common/shuffling/rng.rs
Normal file
@@ -0,0 +1,129 @@
|
||||
use super::blake2_rfc::blake2s::{ Blake2s, Blake2sResult };
|
||||
|
||||
const SEED_SIZE_BYTES: usize = 32;
|
||||
const RAND_BYTES: usize = 3; // 24 / 8
|
||||
const RAND_MAX: u32 = 16_777_216; // 2**24
|
||||
|
||||
/// A pseudo-random number generator which given a seed
|
||||
/// uses successive blake2s hashing to generate "entropy".
|
||||
pub struct ShuffleRng {
|
||||
seed: Blake2sResult,
|
||||
idx: usize,
|
||||
pub rand_max: u32,
|
||||
}
|
||||
|
||||
impl ShuffleRng {
|
||||
/// Create a new instance given some "seed" bytes.
|
||||
pub fn new(initial_seed: &[u8]) -> Self {
|
||||
Self {
|
||||
seed: hash(initial_seed),
|
||||
idx: 0,
|
||||
rand_max: RAND_MAX,
|
||||
}
|
||||
}
|
||||
|
||||
/// "Regenerates" the seed by hashing it.
|
||||
fn rehash_seed(&mut self) {
|
||||
self.seed = hash(self.seed.as_bytes());
|
||||
self.idx = 0;
|
||||
}
|
||||
|
||||
/// Extracts 3 bytes from the `seed`. Rehashes seed if required.
|
||||
fn rand(&mut self) -> u32 {
|
||||
self.idx += RAND_BYTES;
|
||||
if self.idx >= SEED_SIZE_BYTES {
|
||||
self.rehash_seed();
|
||||
self.rand()
|
||||
} else {
|
||||
int_from_byte_slice(
|
||||
self.seed.as_bytes(),
|
||||
self.idx - RAND_BYTES,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a random u32 below the specified maximum `n`.
|
||||
///
|
||||
/// Provides a filtered result from a higher-level rng, by discarding
|
||||
/// results which may bias the output. Because of this, execution time is
|
||||
/// not linear and may potentially be infinite.
|
||||
pub fn rand_range(&mut self, n: u32) -> u32 {
|
||||
assert!(n < RAND_MAX, "RAND_MAX exceed");
|
||||
let mut x = self.rand();
|
||||
while x >= self.rand_max - (self.rand_max % n) {
|
||||
x = self.rand();
|
||||
}
|
||||
x % n
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads the next three bytes of `source`, starting from `offset` and
|
||||
/// interprets those bytes as a 24 bit big-endian integer.
|
||||
/// Returns that integer.
|
||||
fn int_from_byte_slice(source: &[u8], offset: usize) -> u32 {
|
||||
(
|
||||
u32::from(source[offset + 2])) |
|
||||
(u32::from(source[offset + 1]) << 8) |
|
||||
(u32::from(source[offset ]) << 16
|
||||
)
|
||||
}
|
||||
|
||||
/// Peform a blake2s hash on the given bytes.
|
||||
fn hash(bytes: &[u8]) -> Blake2sResult {
|
||||
let mut hasher = Blake2s::new(SEED_SIZE_BYTES);
|
||||
hasher.update(bytes);
|
||||
hasher.finalize()
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_shuffling_int_from_slice() {
|
||||
let mut x = int_from_byte_slice(
|
||||
&[0, 0, 1],
|
||||
0);
|
||||
assert_eq!((x as u32), 1);
|
||||
|
||||
x = int_from_byte_slice(
|
||||
&[0, 1, 1],
|
||||
0);
|
||||
assert_eq!(x, 257);
|
||||
|
||||
x = int_from_byte_slice(
|
||||
&[1, 1, 1],
|
||||
0);
|
||||
assert_eq!(x, 65793);
|
||||
|
||||
x = int_from_byte_slice(
|
||||
&[255, 1, 1],
|
||||
0);
|
||||
assert_eq!(x, 16711937);
|
||||
|
||||
x = int_from_byte_slice(
|
||||
&[255, 255, 255],
|
||||
0);
|
||||
assert_eq!(x, 16777215);
|
||||
|
||||
x = int_from_byte_slice(
|
||||
&[0x8f, 0xbb, 0xc7],
|
||||
0);
|
||||
assert_eq!(x, 9419719);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shuffling_hash_fn() {
|
||||
let digest = hash(hash(b"4kn4driuctg8").as_bytes()); // double-hash is intentional
|
||||
let digest_bytes = digest.as_bytes();
|
||||
let expected = [
|
||||
0xff, 0xff, 0xff, 0x8f, 0xbb, 0xc7, 0xab, 0x64, 0x43, 0x9a,
|
||||
0xe5, 0x12, 0x44, 0xd8, 0x70, 0xcf, 0xe5, 0x79, 0xf6, 0x55,
|
||||
0x6b, 0xbd, 0x81, 0x43, 0xc5, 0xcd, 0x70, 0x2b, 0xbe, 0xe3,
|
||||
0x87, 0xc7,
|
||||
];
|
||||
assert_eq!(digest_bytes.len(), expected.len());
|
||||
assert_eq!(digest_bytes, expected)
|
||||
}
|
||||
}
|
||||
29
beacon_chain/types/src/crosslink_record.rs
Normal file
29
beacon_chain/types/src/crosslink_record.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
use super::Hash256;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CrosslinkRecord {
|
||||
pub dynasty: u64,
|
||||
pub hash: Hash256,
|
||||
}
|
||||
|
||||
impl CrosslinkRecord {
|
||||
/// Generates a new instance where `dynasty` and `hash` are both zero.
|
||||
pub fn zero() -> Self {
|
||||
Self {
|
||||
dynasty: 0,
|
||||
hash: Hash256::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_crosslink_record_zero() {
|
||||
let c = CrosslinkRecord::zero();
|
||||
assert_eq!(c.dynasty, 0);
|
||||
assert!(c.hash.is_zero());
|
||||
}
|
||||
}
|
||||
65
beacon_chain/types/src/crystallized_state.rs
Normal file
65
beacon_chain/types/src/crystallized_state.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
use super::validator_record::ValidatorRecord;
|
||||
use super::crosslink_record::CrosslinkRecord;
|
||||
use super::shard_and_committee::ShardAndCommittee;
|
||||
use super::ethereum_types::U256;
|
||||
use super::Hash256;
|
||||
|
||||
|
||||
pub struct CrystallizedState {
|
||||
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 where all fields are either zero or an
|
||||
/// empty vector.
|
||||
pub fn zero() -> Self {
|
||||
Self {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
49
beacon_chain/types/src/lib.rs
Normal file
49
beacon_chain/types/src/lib.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
extern crate ethereum_types;
|
||||
extern crate bls;
|
||||
extern crate boolean_bitfield;
|
||||
extern crate ssz;
|
||||
|
||||
pub mod active_state;
|
||||
pub mod attestation_record;
|
||||
pub mod crystallized_state;
|
||||
pub mod chain_config;
|
||||
pub mod block;
|
||||
pub mod crosslink_record;
|
||||
pub mod shard_and_committee;
|
||||
pub mod validator_record;
|
||||
|
||||
use self::ethereum_types::{
|
||||
H256,
|
||||
H160,
|
||||
U256
|
||||
};
|
||||
use self::boolean_bitfield::BooleanBitfield;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub use active_state::ActiveState;
|
||||
pub use attestation_record::AttestationRecord;
|
||||
pub use crystallized_state::CrystallizedState;
|
||||
pub use chain_config::ChainConfig;
|
||||
pub use block::Block;
|
||||
pub use crosslink_record::CrosslinkRecord;
|
||||
pub use shard_and_committee::ShardAndCommittee;
|
||||
pub use validator_record::ValidatorRecord;
|
||||
|
||||
pub type Hash256 = H256;
|
||||
pub type Address = H160;
|
||||
pub type EthBalance = U256;
|
||||
pub type Bitfield = BooleanBitfield;
|
||||
|
||||
/// Maps a (slot, shard_id) to attestation_indices.
|
||||
pub type AttesterMap = HashMap<(u64, u16), Vec<usize>>;
|
||||
|
||||
/// Maps a slot to a block proposer.
|
||||
pub type ProposerMap = HashMap<u64, usize>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
}
|
||||
20
beacon_chain/types/src/mod.rs
Normal file
20
beacon_chain/types/src/mod.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
extern crate rlp;
|
||||
extern crate ethereum_types;
|
||||
extern crate blake2_rfc as blake2;
|
||||
extern crate bytes;
|
||||
extern crate ssz;
|
||||
|
||||
mod common;
|
||||
|
||||
pub mod active_state;
|
||||
pub mod attestation_record;
|
||||
pub mod crystallized_state;
|
||||
pub mod chain_config;
|
||||
pub mod block;
|
||||
pub mod crosslink_record;
|
||||
pub mod shard_and_committee;
|
||||
pub mod validator_record;
|
||||
|
||||
use super::bls;
|
||||
use super::db;
|
||||
use super::utils;
|
||||
28
beacon_chain/types/src/shard_and_committee.rs
Normal file
28
beacon_chain/types/src/shard_and_committee.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ShardAndCommittee {
|
||||
pub shard_id: u16,
|
||||
pub committee: Vec<usize>
|
||||
}
|
||||
|
||||
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 = ShardAndCommittee::zero();
|
||||
assert_eq!(s.shard_id, 0);
|
||||
assert_eq!(s.committee.len(), 0);
|
||||
}
|
||||
}
|
||||
67
beacon_chain/types/src/validator_record.rs
Normal file
67
beacon_chain/types/src/validator_record.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
use super::{
|
||||
Hash256,
|
||||
Address,
|
||||
EthBalance,
|
||||
};
|
||||
use super::bls::{
|
||||
PublicKey,
|
||||
Keypair
|
||||
};
|
||||
|
||||
pub struct ValidatorRecord {
|
||||
pub pubkey: PublicKey,
|
||||
pub withdrawal_shard: u16,
|
||||
pub withdrawal_address: Address,
|
||||
pub randao_commitment: Hash256,
|
||||
pub balance: EthBalance,
|
||||
pub start_dynasty: u64,
|
||||
pub end_dynasty: u64,
|
||||
}
|
||||
|
||||
impl ValidatorRecord {
|
||||
/// 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 keypair = Keypair::random();
|
||||
let s = Self {
|
||||
pubkey: keypair.pk.clone(),
|
||||
withdrawal_shard: 0,
|
||||
withdrawal_address: Address::zero(),
|
||||
randao_commitment: Hash256::zero(),
|
||||
balance: EthBalance::zero(),
|
||||
start_dynasty: 0,
|
||||
end_dynasty: 0,
|
||||
};
|
||||
(s, keypair)
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for ValidatorRecord {
|
||||
fn clone(&self) -> ValidatorRecord {
|
||||
ValidatorRecord {
|
||||
pubkey: self.pubkey.clone(),
|
||||
..*self
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user