Rename beacon_chain/ -> eth2/

This commit is contained in:
Paul Hauner
2019-01-22 16:16:02 +11:00
parent 87c73b1af9
commit e16f9e0aec
92 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
use super::bls::AggregateSignature;
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use super::{AttestationData, Bitfield};
use crate::test_utils::TestRandom;
use rand::RngCore;
#[derive(Debug, Clone, PartialEq)]
pub struct Attestation {
pub data: AttestationData,
pub participation_bitfield: Bitfield,
pub custody_bitfield: Bitfield,
pub aggregate_sig: AggregateSignature,
}
impl Encodable for Attestation {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.data);
s.append(&self.participation_bitfield);
s.append(&self.custody_bitfield);
s.append(&self.aggregate_sig);
}
}
impl Decodable for Attestation {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (data, i) = AttestationData::ssz_decode(bytes, i)?;
let (participation_bitfield, i) = Bitfield::ssz_decode(bytes, i)?;
let (custody_bitfield, i) = Bitfield::ssz_decode(bytes, i)?;
let (aggregate_sig, i) = AggregateSignature::ssz_decode(bytes, i)?;
let attestation_record = Self {
data,
participation_bitfield,
custody_bitfield,
aggregate_sig,
};
Ok((attestation_record, i))
}
}
impl Attestation {
pub fn zero() -> Self {
Self {
data: AttestationData::zero(),
participation_bitfield: Bitfield::new(),
custody_bitfield: Bitfield::new(),
aggregate_sig: AggregateSignature::new(),
}
}
}
impl<T: RngCore> TestRandom<T> for Attestation {
fn random_for_test(rng: &mut T) -> Self {
Self {
data: <_>::random_for_test(rng),
participation_bitfield: <_>::random_for_test(rng),
custody_bitfield: <_>::random_for_test(rng),
aggregate_sig: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = Attestation::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

View File

@@ -0,0 +1,119 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use super::Hash256;
use crate::test_utils::TestRandom;
use rand::RngCore;
pub const SSZ_ATTESTION_DATA_LENGTH: usize = {
8 + // slot
8 + // shard
32 + // beacon_block_hash
32 + // epoch_boundary_hash
32 + // shard_block_hash
32 + // latest_crosslink_hash
8 + // justified_slot
32 // justified_block_hash
};
#[derive(Debug, Clone, PartialEq, Default)]
pub struct AttestationData {
pub slot: u64,
pub shard: u64,
pub beacon_block_hash: Hash256,
pub epoch_boundary_hash: Hash256,
pub shard_block_hash: Hash256,
pub latest_crosslink_hash: Hash256,
pub justified_slot: u64,
pub justified_block_hash: Hash256,
}
impl AttestationData {
pub fn zero() -> Self {
Self {
slot: 0,
shard: 0,
beacon_block_hash: Hash256::zero(),
epoch_boundary_hash: Hash256::zero(),
shard_block_hash: Hash256::zero(),
latest_crosslink_hash: Hash256::zero(),
justified_slot: 0,
justified_block_hash: Hash256::zero(),
}
}
// TODO: Implement this as a merkle root, once tree_ssz is implemented.
// https://github.com/sigp/lighthouse/issues/92
pub fn canonical_root(&self) -> Hash256 {
Hash256::zero()
}
}
impl Encodable for AttestationData {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.slot);
s.append(&self.shard);
s.append(&self.beacon_block_hash);
s.append(&self.epoch_boundary_hash);
s.append(&self.shard_block_hash);
s.append(&self.latest_crosslink_hash);
s.append(&self.justified_slot);
s.append(&self.justified_block_hash);
}
}
impl Decodable for AttestationData {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (slot, i) = u64::ssz_decode(bytes, i)?;
let (shard, i) = u64::ssz_decode(bytes, i)?;
let (beacon_block_hash, i) = Hash256::ssz_decode(bytes, i)?;
let (epoch_boundary_hash, i) = Hash256::ssz_decode(bytes, i)?;
let (shard_block_hash, i) = Hash256::ssz_decode(bytes, i)?;
let (latest_crosslink_hash, i) = Hash256::ssz_decode(bytes, i)?;
let (justified_slot, i) = u64::ssz_decode(bytes, i)?;
let (justified_block_hash, i) = Hash256::ssz_decode(bytes, i)?;
let attestation_data = AttestationData {
slot,
shard,
beacon_block_hash,
epoch_boundary_hash,
shard_block_hash,
latest_crosslink_hash,
justified_slot,
justified_block_hash,
};
Ok((attestation_data, i))
}
}
impl<T: RngCore> TestRandom<T> for AttestationData {
fn random_for_test(rng: &mut T) -> Self {
Self {
slot: <_>::random_for_test(rng),
shard: <_>::random_for_test(rng),
beacon_block_hash: <_>::random_for_test(rng),
epoch_boundary_hash: <_>::random_for_test(rng),
shard_block_hash: <_>::random_for_test(rng),
latest_crosslink_hash: <_>::random_for_test(rng),
justified_slot: <_>::random_for_test(rng),
justified_block_hash: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = AttestationData::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

View File

@@ -0,0 +1,60 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use rand::RngCore;
use crate::test_utils::TestRandom;
use super::AttestationData;
#[derive(Debug, Clone, PartialEq, Default)]
pub struct AttestationDataAndCustodyBit {
pub data: AttestationData,
pub custody_bit: bool,
}
impl Encodable for AttestationDataAndCustodyBit {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.data);
s.append(&self.custody_bit);
}
}
impl Decodable for AttestationDataAndCustodyBit {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (data, i) = <_>::ssz_decode(bytes, i)?;
let (custody_bit, i) = <_>::ssz_decode(bytes, i)?;
let attestation_data_and_custody_bit = AttestationDataAndCustodyBit {
data,
custody_bit,
};
Ok((attestation_data_and_custody_bit, i))
}
}
impl<T: RngCore> TestRandom<T> for AttestationDataAndCustodyBit {
fn random_for_test(rng: &mut T) -> Self {
Self {
data: <_>::random_for_test(rng),
custody_bit: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod test {
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
use super::*;
use super::super::ssz::ssz_encode;
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = AttestationDataAndCustodyBit::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

View File

@@ -0,0 +1,94 @@
use super::ssz::{ssz_encode, Decodable, DecodeError, Encodable, SszStream};
use super::{BeaconBlockBody, Hash256};
use crate::test_utils::TestRandom;
use bls::Signature;
use hashing::canonical_hash;
use rand::RngCore;
#[derive(Debug, PartialEq, Clone)]
pub struct BeaconBlock {
pub slot: u64,
pub parent_root: Hash256,
pub state_root: Hash256,
pub randao_reveal: Hash256,
pub candidate_pow_receipt_root: Hash256,
pub signature: Signature,
pub body: BeaconBlockBody,
}
impl BeaconBlock {
pub fn canonical_root(&self) -> Hash256 {
// TODO: implement tree hashing.
// https://github.com/sigp/lighthouse/issues/70
Hash256::from(&canonical_hash(&ssz_encode(self))[..])
}
}
impl Encodable for BeaconBlock {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.slot);
s.append(&self.parent_root);
s.append(&self.state_root);
s.append(&self.randao_reveal);
s.append(&self.candidate_pow_receipt_root);
s.append(&self.signature);
s.append(&self.body);
}
}
impl Decodable for BeaconBlock {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (slot, i) = <_>::ssz_decode(bytes, i)?;
let (parent_root, i) = <_>::ssz_decode(bytes, i)?;
let (state_root, i) = <_>::ssz_decode(bytes, i)?;
let (randao_reveal, i) = <_>::ssz_decode(bytes, i)?;
let (candidate_pow_receipt_root, i) = <_>::ssz_decode(bytes, i)?;
let (signature, i) = <_>::ssz_decode(bytes, i)?;
let (body, i) = <_>::ssz_decode(bytes, i)?;
Ok((
Self {
slot,
parent_root,
state_root,
randao_reveal,
candidate_pow_receipt_root,
signature,
body,
},
i,
))
}
}
impl<T: RngCore> TestRandom<T> for BeaconBlock {
fn random_for_test(rng: &mut T) -> Self {
Self {
slot: <_>::random_for_test(rng),
parent_root: <_>::random_for_test(rng),
state_root: <_>::random_for_test(rng),
randao_reveal: <_>::random_for_test(rng),
candidate_pow_receipt_root: <_>::random_for_test(rng),
signature: <_>::random_for_test(rng),
body: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = BeaconBlock::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

View File

@@ -0,0 +1,95 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use super::{Attestation, CasperSlashing, Deposit, Exit, ProposerSlashing};
use crate::test_utils::TestRandom;
use rand::RngCore;
// The following types are just dummy classes as they will not be defined until
// Phase 1 (Sharding phase)
type CustodyReseed = usize;
type CustodyChallenge = usize;
type CustodyResponse = usize;
#[derive(Debug, PartialEq, Clone, Default)]
pub struct BeaconBlockBody {
pub proposer_slashings: Vec<ProposerSlashing>,
pub casper_slashings: Vec<CasperSlashing>,
pub attestations: Vec<Attestation>,
pub custody_reseeds: Vec<CustodyReseed>,
pub custody_challenges: Vec<CustodyChallenge>,
pub custody_responses: Vec<CustodyResponse>,
pub deposits: Vec<Deposit>,
pub exits: Vec<Exit>,
}
impl Encodable for BeaconBlockBody {
fn ssz_append(&self, s: &mut SszStream) {
s.append_vec(&self.proposer_slashings);
s.append_vec(&self.casper_slashings);
s.append_vec(&self.attestations);
s.append_vec(&self.custody_reseeds);
s.append_vec(&self.custody_challenges);
s.append_vec(&self.custody_responses);
s.append_vec(&self.deposits);
s.append_vec(&self.exits);
}
}
impl Decodable for BeaconBlockBody {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (proposer_slashings, i) = <_>::ssz_decode(bytes, i)?;
let (casper_slashings, i) = <_>::ssz_decode(bytes, i)?;
let (attestations, i) = <_>::ssz_decode(bytes, i)?;
let (custody_reseeds, i) = <_>::ssz_decode(bytes, i)?;
let (custody_challenges, i) = <_>::ssz_decode(bytes, i)?;
let (custody_responses, i) = <_>::ssz_decode(bytes, i)?;
let (deposits, i) = <_>::ssz_decode(bytes, i)?;
let (exits, i) = <_>::ssz_decode(bytes, i)?;
Ok((
Self {
proposer_slashings,
casper_slashings,
attestations,
custody_reseeds,
custody_challenges,
custody_responses,
deposits,
exits,
},
i,
))
}
}
impl<T: RngCore> TestRandom<T> for BeaconBlockBody {
fn random_for_test(rng: &mut T) -> Self {
Self {
proposer_slashings: <_>::random_for_test(rng),
casper_slashings: <_>::random_for_test(rng),
attestations: <_>::random_for_test(rng),
custody_reseeds: <_>::random_for_test(rng),
custody_challenges: <_>::random_for_test(rng),
custody_responses: <_>::random_for_test(rng),
deposits: <_>::random_for_test(rng),
exits: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = BeaconBlockBody::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

View File

@@ -0,0 +1,219 @@
use super::candidate_pow_receipt_root_record::CandidatePoWReceiptRootRecord;
use super::crosslink_record::CrosslinkRecord;
use super::fork_data::ForkData;
use super::pending_attestation_record::PendingAttestationRecord;
use super::validator_record::ValidatorRecord;
use super::Hash256;
use crate::test_utils::TestRandom;
use hashing::canonical_hash;
use rand::RngCore;
use ssz::{ssz_encode, Decodable, DecodeError, Encodable, SszStream};
// Custody will not be added to the specs until Phase 1 (Sharding Phase) so dummy class used.
type CustodyChallenge = usize;
#[derive(Debug, PartialEq, Clone, Default)]
pub struct BeaconState {
// Misc
pub slot: u64,
pub genesis_time: u64,
pub fork_data: ForkData,
// Validator registry
pub validator_registry: Vec<ValidatorRecord>,
pub validator_balances: Vec<u64>,
pub validator_registry_latest_change_slot: u64,
pub validator_registry_exit_count: u64,
pub validator_registry_delta_chain_tip: Hash256,
// Randomness and committees
pub latest_randao_mixes: Vec<Hash256>,
pub latest_vdf_outputs: Vec<Hash256>,
pub previous_epoch_start_shard: u64,
pub current_epoch_start_shard: u64,
pub previous_epoch_calculation_slot: u64,
pub current_epoch_calculation_slot: u64,
pub previous_epoch_randao_mix: Hash256,
pub current_epoch_randao_mix: Hash256,
// Custody challenges
pub custody_challenges: Vec<CustodyChallenge>,
// Finality
pub previous_justified_slot: u64,
pub justified_slot: u64,
pub justification_bitfield: u64,
pub finalized_slot: u64,
// Recent state
pub latest_crosslinks: Vec<CrosslinkRecord>,
pub latest_block_roots: Vec<Hash256>,
pub latest_penalized_exit_balances: Vec<u64>,
pub latest_attestations: Vec<PendingAttestationRecord>,
pub batched_block_roots: Vec<Hash256>,
// PoW receipt root (a.k.a. deposit root)
pub processed_pow_receipt_root: Hash256,
pub candidate_pow_receipt_roots: Vec<CandidatePoWReceiptRootRecord>,
}
impl BeaconState {
pub fn canonical_root(&self) -> Hash256 {
// TODO: implement tree hashing.
// https://github.com/sigp/lighthouse/issues/70
Hash256::from(&canonical_hash(&ssz_encode(self))[..])
}
}
impl Encodable for BeaconState {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.slot);
s.append(&self.genesis_time);
s.append(&self.fork_data);
s.append(&self.validator_registry);
s.append(&self.validator_balances);
s.append(&self.validator_registry_latest_change_slot);
s.append(&self.validator_registry_exit_count);
s.append(&self.validator_registry_delta_chain_tip);
s.append(&self.latest_randao_mixes);
s.append(&self.latest_vdf_outputs);
s.append(&self.previous_epoch_start_shard);
s.append(&self.current_epoch_start_shard);
s.append(&self.previous_epoch_calculation_slot);
s.append(&self.current_epoch_calculation_slot);
s.append(&self.previous_epoch_randao_mix);
s.append(&self.current_epoch_randao_mix);
s.append(&self.custody_challenges);
s.append(&self.previous_justified_slot);
s.append(&self.justified_slot);
s.append(&self.justification_bitfield);
s.append(&self.finalized_slot);
s.append(&self.latest_crosslinks);
s.append(&self.latest_block_roots);
s.append(&self.latest_penalized_exit_balances);
s.append(&self.latest_attestations);
s.append(&self.batched_block_roots);
s.append(&self.processed_pow_receipt_root);
s.append(&self.candidate_pow_receipt_roots);
}
}
impl Decodable for BeaconState {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (slot, i) = <_>::ssz_decode(bytes, i)?;
let (genesis_time, i) = <_>::ssz_decode(bytes, i)?;
let (fork_data, i) = <_>::ssz_decode(bytes, i)?;
let (validator_registry, i) = <_>::ssz_decode(bytes, i)?;
let (validator_balances, i) = <_>::ssz_decode(bytes, i)?;
let (validator_registry_latest_change_slot, i) = <_>::ssz_decode(bytes, i)?;
let (validator_registry_exit_count, i) = <_>::ssz_decode(bytes, i)?;
let (validator_registry_delta_chain_tip, i) = <_>::ssz_decode(bytes, i)?;
let (latest_randao_mixes, i) = <_>::ssz_decode(bytes, i)?;
let (latest_vdf_outputs, i) = <_>::ssz_decode(bytes, i)?;
let (previous_epoch_start_shard, i) = <_>::ssz_decode(bytes, i)?;
let (current_epoch_start_shard, i) = <_>::ssz_decode(bytes, i)?;
let (previous_epoch_calculation_slot, i) = <_>::ssz_decode(bytes, i)?;
let (current_epoch_calculation_slot, i) = <_>::ssz_decode(bytes, i)?;
let (previous_epoch_randao_mix, i) = <_>::ssz_decode(bytes, i)?;
let (current_epoch_randao_mix, i) = <_>::ssz_decode(bytes, i)?;
let (custody_challenges, i) = <_>::ssz_decode(bytes, i)?;
let (previous_justified_slot, i) = <_>::ssz_decode(bytes, i)?;
let (justified_slot, i) = <_>::ssz_decode(bytes, i)?;
let (justification_bitfield, i) = <_>::ssz_decode(bytes, i)?;
let (finalized_slot, i) = <_>::ssz_decode(bytes, i)?;
let (latest_crosslinks, i) = <_>::ssz_decode(bytes, i)?;
let (latest_block_roots, i) = <_>::ssz_decode(bytes, i)?;
let (latest_penalized_exit_balances, i) = <_>::ssz_decode(bytes, i)?;
let (latest_attestations, i) = <_>::ssz_decode(bytes, i)?;
let (batched_block_roots, i) = <_>::ssz_decode(bytes, i)?;
let (processed_pow_receipt_root, i) = <_>::ssz_decode(bytes, i)?;
let (candidate_pow_receipt_roots, i) = <_>::ssz_decode(bytes, i)?;
Ok((
Self {
slot,
genesis_time,
fork_data,
validator_registry,
validator_balances,
validator_registry_latest_change_slot,
validator_registry_exit_count,
validator_registry_delta_chain_tip,
latest_randao_mixes,
latest_vdf_outputs,
previous_epoch_start_shard,
current_epoch_start_shard,
previous_epoch_calculation_slot,
current_epoch_calculation_slot,
previous_epoch_randao_mix,
current_epoch_randao_mix,
custody_challenges,
previous_justified_slot,
justified_slot,
justification_bitfield,
finalized_slot,
latest_crosslinks,
latest_block_roots,
latest_penalized_exit_balances,
latest_attestations,
batched_block_roots,
processed_pow_receipt_root,
candidate_pow_receipt_roots,
},
i,
))
}
}
impl<T: RngCore> TestRandom<T> for BeaconState {
fn random_for_test(rng: &mut T) -> Self {
Self {
slot: <_>::random_for_test(rng),
genesis_time: <_>::random_for_test(rng),
fork_data: <_>::random_for_test(rng),
validator_registry: <_>::random_for_test(rng),
validator_balances: <_>::random_for_test(rng),
validator_registry_latest_change_slot: <_>::random_for_test(rng),
validator_registry_exit_count: <_>::random_for_test(rng),
validator_registry_delta_chain_tip: <_>::random_for_test(rng),
latest_randao_mixes: <_>::random_for_test(rng),
latest_vdf_outputs: <_>::random_for_test(rng),
previous_epoch_start_shard: <_>::random_for_test(rng),
current_epoch_start_shard: <_>::random_for_test(rng),
previous_epoch_calculation_slot: <_>::random_for_test(rng),
current_epoch_calculation_slot: <_>::random_for_test(rng),
previous_epoch_randao_mix: <_>::random_for_test(rng),
current_epoch_randao_mix: <_>::random_for_test(rng),
custody_challenges: <_>::random_for_test(rng),
previous_justified_slot: <_>::random_for_test(rng),
justified_slot: <_>::random_for_test(rng),
justification_bitfield: <_>::random_for_test(rng),
finalized_slot: <_>::random_for_test(rng),
latest_crosslinks: <_>::random_for_test(rng),
latest_block_roots: <_>::random_for_test(rng),
latest_penalized_exit_balances: <_>::random_for_test(rng),
latest_attestations: <_>::random_for_test(rng),
batched_block_roots: <_>::random_for_test(rng),
processed_pow_receipt_root: <_>::random_for_test(rng),
candidate_pow_receipt_roots: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = BeaconState::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

View File

@@ -0,0 +1,60 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use super::Hash256;
use crate::test_utils::TestRandom;
use rand::RngCore;
// Note: this is refer to as DepositRootVote in specs
#[derive(Debug, PartialEq, Clone)]
pub struct CandidatePoWReceiptRootRecord {
pub candidate_pow_receipt_root: Hash256,
pub votes: u64,
}
impl Encodable for CandidatePoWReceiptRootRecord {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.candidate_pow_receipt_root);
s.append(&self.votes);
}
}
impl Decodable for CandidatePoWReceiptRootRecord {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (candidate_pow_receipt_root, i) = <_>::ssz_decode(bytes, i)?;
let (votes, i) = <_>::ssz_decode(bytes, i)?;
Ok((
Self {
candidate_pow_receipt_root,
votes,
},
i,
))
}
}
impl<T: RngCore> TestRandom<T> for CandidatePoWReceiptRootRecord {
fn random_for_test(rng: &mut T) -> Self {
Self {
candidate_pow_receipt_root: <_>::random_for_test(rng),
votes: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = CandidatePoWReceiptRootRecord::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

View File

@@ -0,0 +1,59 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use super::SlashableVoteData;
use crate::test_utils::TestRandom;
use rand::RngCore;
#[derive(Debug, PartialEq, Clone)]
pub struct CasperSlashing {
pub slashable_vote_data_1: SlashableVoteData,
pub slashable_vote_data_2: SlashableVoteData,
}
impl Encodable for CasperSlashing {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.slashable_vote_data_1);
s.append(&self.slashable_vote_data_2);
}
}
impl Decodable for CasperSlashing {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (slashable_vote_data_1, i) = <_>::ssz_decode(bytes, i)?;
let (slashable_vote_data_2, i) = <_>::ssz_decode(bytes, i)?;
Ok((
CasperSlashing {
slashable_vote_data_1,
slashable_vote_data_2,
},
i,
))
}
}
impl<T: RngCore> TestRandom<T> for CasperSlashing {
fn random_for_test(rng: &mut T) -> Self {
Self {
slashable_vote_data_1: <_>::random_for_test(rng),
slashable_vote_data_2: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = CasperSlashing::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

View File

@@ -0,0 +1,69 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use super::Hash256;
use crate::test_utils::TestRandom;
use rand::RngCore;
#[derive(Clone, Debug, PartialEq)]
pub struct CrosslinkRecord {
pub slot: u64,
pub shard_block_root: Hash256,
}
impl CrosslinkRecord {
/// Generates a new instance where `dynasty` and `hash` are both zero.
pub fn zero() -> Self {
Self {
slot: 0,
shard_block_root: Hash256::zero(),
}
}
}
impl Encodable for CrosslinkRecord {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.slot);
s.append(&self.shard_block_root);
}
}
impl Decodable for CrosslinkRecord {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (slot, i) = <_>::ssz_decode(bytes, i)?;
let (shard_block_root, i) = <_>::ssz_decode(bytes, i)?;
Ok((
Self {
slot,
shard_block_root,
},
i,
))
}
}
impl<T: RngCore> TestRandom<T> for CrosslinkRecord {
fn random_for_test(rng: &mut T) -> Self {
Self {
slot: <_>::random_for_test(rng),
shard_block_root: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = CrosslinkRecord::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

64
eth2/types/src/deposit.rs Normal file
View File

@@ -0,0 +1,64 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use super::{DepositData, Hash256};
use crate::test_utils::TestRandom;
use rand::RngCore;
#[derive(Debug, PartialEq, Clone)]
pub struct Deposit {
pub merkle_branch: Vec<Hash256>,
pub merkle_tree_index: u64,
pub deposit_data: DepositData,
}
impl Encodable for Deposit {
fn ssz_append(&self, s: &mut SszStream) {
s.append_vec(&self.merkle_branch);
s.append(&self.merkle_tree_index);
s.append(&self.deposit_data);
}
}
impl Decodable for Deposit {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (merkle_branch, i) = <_>::ssz_decode(bytes, i)?;
let (merkle_tree_index, i) = <_>::ssz_decode(bytes, i)?;
let (deposit_data, i) = <_>::ssz_decode(bytes, i)?;
Ok((
Self {
merkle_branch,
merkle_tree_index,
deposit_data,
},
i,
))
}
}
impl<T: RngCore> TestRandom<T> for Deposit {
fn random_for_test(rng: &mut T) -> Self {
Self {
merkle_branch: <_>::random_for_test(rng),
merkle_tree_index: <_>::random_for_test(rng),
deposit_data: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = Deposit::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

View File

@@ -0,0 +1,64 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use super::DepositInput;
use crate::test_utils::TestRandom;
use rand::RngCore;
#[derive(Debug, PartialEq, Clone)]
pub struct DepositData {
pub deposit_input: DepositInput,
pub value: u64,
pub timestamp: u64,
}
impl Encodable for DepositData {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.deposit_input);
s.append(&self.value);
s.append(&self.timestamp);
}
}
impl Decodable for DepositData {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (deposit_input, i) = <_>::ssz_decode(bytes, i)?;
let (value, i) = <_>::ssz_decode(bytes, i)?;
let (timestamp, i) = <_>::ssz_decode(bytes, i)?;
Ok((
Self {
deposit_input,
value,
timestamp,
},
i,
))
}
}
impl<T: RngCore> TestRandom<T> for DepositData {
fn random_for_test(rng: &mut T) -> Self {
Self {
deposit_input: <_>::random_for_test(rng),
value: <_>::random_for_test(rng),
timestamp: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = DepositData::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

View File

@@ -0,0 +1,75 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use super::Hash256;
use crate::test_utils::TestRandom;
use bls::{PublicKey, Signature};
use rand::RngCore;
#[derive(Debug, PartialEq, Clone)]
pub struct DepositInput {
pub pubkey: PublicKey,
pub withdrawal_credentials: Hash256,
pub randao_commitment: Hash256,
pub custody_commitment: Hash256,
pub proof_of_possession: Signature,
}
impl Encodable for DepositInput {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.pubkey);
s.append(&self.withdrawal_credentials);
s.append(&self.randao_commitment);
s.append(&self.custody_commitment);
s.append(&self.proof_of_possession);
}
}
impl Decodable for DepositInput {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (pubkey, i) = <_>::ssz_decode(bytes, i)?;
let (withdrawal_credentials, i) = <_>::ssz_decode(bytes, i)?;
let (randao_commitment, i) = <_>::ssz_decode(bytes, i)?;
let (custody_commitment, i) = <_>::ssz_decode(bytes, i)?;
let (proof_of_possession, i) = <_>::ssz_decode(bytes, i)?;
Ok((
Self {
pubkey,
withdrawal_credentials,
randao_commitment,
custody_commitment,
proof_of_possession,
},
i,
))
}
}
impl<T: RngCore> TestRandom<T> for DepositInput {
fn random_for_test(rng: &mut T) -> Self {
Self {
pubkey: <_>::random_for_test(rng),
withdrawal_credentials: <_>::random_for_test(rng),
randao_commitment: <_>::random_for_test(rng),
custody_commitment: <_>::random_for_test(rng),
proof_of_possession: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = DepositInput::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

64
eth2/types/src/exit.rs Normal file
View File

@@ -0,0 +1,64 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use crate::test_utils::TestRandom;
use bls::Signature;
use rand::RngCore;
#[derive(Debug, PartialEq, Clone)]
pub struct Exit {
pub slot: u64,
pub validator_index: u32,
pub signature: Signature,
}
impl Encodable for Exit {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.slot);
s.append(&self.validator_index);
s.append(&self.signature);
}
}
impl Decodable for Exit {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (slot, i) = <_>::ssz_decode(bytes, i)?;
let (validator_index, i) = <_>::ssz_decode(bytes, i)?;
let (signature, i) = <_>::ssz_decode(bytes, i)?;
Ok((
Self {
slot,
validator_index,
signature,
},
i,
))
}
}
impl<T: RngCore> TestRandom<T> for Exit {
fn random_for_test(rng: &mut T) -> Self {
Self {
slot: <_>::random_for_test(rng),
validator_index: <_>::random_for_test(rng),
signature: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = Exit::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

View File

@@ -0,0 +1,63 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use crate::test_utils::TestRandom;
use rand::RngCore;
#[derive(Debug, Clone, PartialEq, Default)]
pub struct ForkData {
pub pre_fork_version: u64,
pub post_fork_version: u64,
pub fork_slot: u64,
}
impl Encodable for ForkData {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.pre_fork_version);
s.append(&self.post_fork_version);
s.append(&self.fork_slot);
}
}
impl Decodable for ForkData {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (pre_fork_version, i) = <_>::ssz_decode(bytes, i)?;
let (post_fork_version, i) = <_>::ssz_decode(bytes, i)?;
let (fork_slot, i) = <_>::ssz_decode(bytes, i)?;
Ok((
Self {
pre_fork_version,
post_fork_version,
fork_slot,
},
i,
))
}
}
impl<T: RngCore> TestRandom<T> for ForkData {
fn random_for_test(rng: &mut T) -> Self {
Self {
pre_fork_version: <_>::random_for_test(rng),
post_fork_version: <_>::random_for_test(rng),
fork_slot: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = ForkData::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

68
eth2/types/src/lib.rs Normal file
View File

@@ -0,0 +1,68 @@
extern crate bls;
extern crate boolean_bitfield;
extern crate ethereum_types;
extern crate ssz;
pub mod test_utils;
pub mod attestation;
pub mod attestation_data;
pub mod beacon_block;
pub mod beacon_block_body;
pub mod beacon_state;
pub mod candidate_pow_receipt_root_record;
pub mod casper_slashing;
pub mod crosslink_record;
pub mod deposit;
pub mod deposit_data;
pub mod deposit_input;
pub mod exit;
pub mod fork_data;
pub mod pending_attestation_record;
pub mod proposal_signed_data;
pub mod proposer_slashing;
pub mod shard_committee;
pub mod shard_reassignment_record;
pub mod slashable_vote_data;
pub mod special_record;
pub mod validator_record;
pub mod validator_registry;
pub mod readers;
use self::ethereum_types::{H160, H256, U256};
use std::collections::HashMap;
pub use crate::attestation::Attestation;
pub use crate::attestation_data::AttestationData;
pub use crate::beacon_block::BeaconBlock;
pub use crate::beacon_block_body::BeaconBlockBody;
pub use crate::beacon_state::BeaconState;
pub use crate::casper_slashing::CasperSlashing;
pub use crate::crosslink_record::CrosslinkRecord;
pub use crate::deposit::Deposit;
pub use crate::deposit_data::DepositData;
pub use crate::deposit_input::DepositInput;
pub use crate::exit::Exit;
pub use crate::fork_data::ForkData;
pub use crate::pending_attestation_record::PendingAttestationRecord;
pub use crate::proposal_signed_data::ProposalSignedData;
pub use crate::proposer_slashing::ProposerSlashing;
pub use crate::shard_committee::ShardCommittee;
pub use crate::slashable_vote_data::SlashableVoteData;
pub use crate::special_record::{SpecialRecord, SpecialRecordKind};
pub use crate::validator_record::{StatusFlags as ValidatorStatusFlags, ValidatorRecord};
pub type Hash256 = H256;
pub type Address = H160;
pub type EthBalance = U256;
pub type Bitfield = boolean_bitfield::BooleanBitfield;
pub type BitfieldError = boolean_bitfield::Error;
/// Maps a (slot, shard_id) to attestation_indices.
pub type AttesterMap = HashMap<(u64, u64), Vec<usize>>;
/// Maps a slot to a block proposer.
pub type ProposerMap = HashMap<u64, usize>;
pub use bls::{AggregatePublicKey, AggregateSignature, PublicKey, Signature};

View File

@@ -0,0 +1,69 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use super::{AttestationData, Bitfield};
use crate::test_utils::TestRandom;
use rand::RngCore;
#[derive(Debug, Clone, PartialEq)]
pub struct PendingAttestationRecord {
pub data: AttestationData,
pub participation_bitfield: Bitfield,
pub custody_bitfield: Bitfield,
pub slot_included: u64,
}
impl Encodable for PendingAttestationRecord {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.data);
s.append(&self.participation_bitfield);
s.append(&self.custody_bitfield);
s.append(&self.slot_included);
}
}
impl Decodable for PendingAttestationRecord {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (data, i) = <_>::ssz_decode(bytes, i)?;
let (participation_bitfield, i) = <_>::ssz_decode(bytes, i)?;
let (custody_bitfield, i) = <_>::ssz_decode(bytes, i)?;
let (slot_included, i) = <_>::ssz_decode(bytes, i)?;
Ok((
Self {
data,
participation_bitfield,
custody_bitfield,
slot_included,
},
i,
))
}
}
impl<T: RngCore> TestRandom<T> for PendingAttestationRecord {
fn random_for_test(rng: &mut T) -> Self {
Self {
data: <_>::random_for_test(rng),
participation_bitfield: <_>::random_for_test(rng),
custody_bitfield: <_>::random_for_test(rng),
slot_included: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = PendingAttestationRecord::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

View File

@@ -0,0 +1,64 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use super::Hash256;
use crate::test_utils::TestRandom;
use rand::RngCore;
#[derive(Debug, PartialEq, Clone, Default)]
pub struct ProposalSignedData {
pub slot: u64,
pub shard: u64,
pub block_root: Hash256,
}
impl Encodable for ProposalSignedData {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.slot);
s.append(&self.shard);
s.append(&self.block_root);
}
}
impl Decodable for ProposalSignedData {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (slot, i) = <_>::ssz_decode(bytes, i)?;
let (shard, i) = <_>::ssz_decode(bytes, i)?;
let (block_root, i) = <_>::ssz_decode(bytes, i)?;
Ok((
ProposalSignedData {
slot,
shard,
block_root,
},
i,
))
}
}
impl<T: RngCore> TestRandom<T> for ProposalSignedData {
fn random_for_test(rng: &mut T) -> Self {
Self {
slot: <_>::random_for_test(rng),
shard: <_>::random_for_test(rng),
block_root: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = ProposalSignedData::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

View File

@@ -0,0 +1,75 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use super::ProposalSignedData;
use crate::test_utils::TestRandom;
use bls::Signature;
use rand::RngCore;
#[derive(Debug, PartialEq, Clone)]
pub struct ProposerSlashing {
pub proposer_index: u32,
pub proposal_data_1: ProposalSignedData,
pub proposal_signature_1: Signature,
pub proposal_data_2: ProposalSignedData,
pub proposal_signature_2: Signature,
}
impl Encodable for ProposerSlashing {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.proposer_index);
s.append(&self.proposal_data_1);
s.append(&self.proposal_signature_1);
s.append(&self.proposal_data_2);
s.append(&self.proposal_signature_2);
}
}
impl Decodable for ProposerSlashing {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (proposer_index, i) = <_>::ssz_decode(bytes, i)?;
let (proposal_data_1, i) = <_>::ssz_decode(bytes, i)?;
let (proposal_signature_1, i) = <_>::ssz_decode(bytes, i)?;
let (proposal_data_2, i) = <_>::ssz_decode(bytes, i)?;
let (proposal_signature_2, i) = <_>::ssz_decode(bytes, i)?;
Ok((
ProposerSlashing {
proposer_index,
proposal_data_1,
proposal_signature_1,
proposal_data_2,
proposal_signature_2,
},
i,
))
}
}
impl<T: RngCore> TestRandom<T> for ProposerSlashing {
fn random_for_test(rng: &mut T) -> Self {
Self {
proposer_index: <_>::random_for_test(rng),
proposal_data_1: <_>::random_for_test(rng),
proposal_signature_1: <_>::random_for_test(rng),
proposal_data_2: <_>::random_for_test(rng),
proposal_signature_2: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = ProposerSlashing::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

View File

@@ -0,0 +1,40 @@
use crate::{BeaconBlock, Hash256};
use std::fmt::Debug;
/// The `BeaconBlockReader` provides interfaces for reading a subset of fields of a `BeaconBlock`.
///
/// The purpose of this trait is to allow reading from either;
/// - a standard `BeaconBlock` struct, or
/// - a SSZ serialized byte array.
///
/// Note: presently, direct SSZ reading has not been implemented so this trait is being used for
/// "future proofing".
pub trait BeaconBlockReader: Debug + PartialEq {
fn slot(&self) -> u64;
fn parent_root(&self) -> Hash256;
fn state_root(&self) -> Hash256;
fn canonical_root(&self) -> Hash256;
fn into_beacon_block(self) -> Option<BeaconBlock>;
}
impl BeaconBlockReader for BeaconBlock {
fn slot(&self) -> u64 {
self.slot
}
fn parent_root(&self) -> Hash256 {
self.parent_root
}
fn state_root(&self) -> Hash256 {
self.state_root
}
fn canonical_root(&self) -> Hash256 {
self.canonical_root()
}
fn into_beacon_block(self) -> Option<BeaconBlock> {
Some(self)
}
}

View File

@@ -0,0 +1,5 @@
mod block_reader;
mod state_reader;
pub use self::block_reader::BeaconBlockReader;
pub use self::state_reader::BeaconStateReader;

View File

@@ -0,0 +1,30 @@
use crate::{BeaconState, Hash256};
use std::fmt::Debug;
/// The `BeaconStateReader` provides interfaces for reading a subset of fields of a `BeaconState`.
///
/// The purpose of this trait is to allow reading from either;
/// - a standard `BeaconState` struct, or
/// - a SSZ serialized byte array.
///
/// Note: presently, direct SSZ reading has not been implemented so this trait is being used for
/// "future proofing".
pub trait BeaconStateReader: Debug + PartialEq {
fn slot(&self) -> u64;
fn canonical_root(&self) -> Hash256;
fn into_beacon_state(self) -> Option<BeaconState>;
}
impl BeaconStateReader for BeaconState {
fn slot(&self) -> u64 {
self.slot
}
fn canonical_root(&self) -> Hash256 {
self.canonical_root()
}
fn into_beacon_state(self) -> Option<BeaconState> {
Some(self)
}
}

View File

@@ -0,0 +1,52 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use crate::test_utils::TestRandom;
use rand::RngCore;
#[derive(Clone, Debug, PartialEq)]
pub struct ShardCommittee {
pub shard: u64,
pub committee: Vec<usize>,
}
impl Encodable for ShardCommittee {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.shard);
s.append(&self.committee);
}
}
impl Decodable for ShardCommittee {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (shard, i) = <_>::ssz_decode(bytes, i)?;
let (committee, i) = <_>::ssz_decode(bytes, i)?;
Ok((Self { shard, committee }, i))
}
}
impl<T: RngCore> TestRandom<T> for ShardCommittee {
fn random_for_test(rng: &mut T) -> Self {
Self {
shard: <_>::random_for_test(rng),
committee: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = ShardCommittee::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

View File

@@ -0,0 +1,63 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use crate::test_utils::TestRandom;
use rand::RngCore;
#[derive(Debug, PartialEq, Clone)]
pub struct ShardReassignmentRecord {
pub validator_index: u64,
pub shard: u64,
pub slot: u64,
}
impl Encodable for ShardReassignmentRecord {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.validator_index);
s.append(&self.shard);
s.append(&self.slot);
}
}
impl Decodable for ShardReassignmentRecord {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (validator_index, i) = <_>::ssz_decode(bytes, i)?;
let (shard, i) = <_>::ssz_decode(bytes, i)?;
let (slot, i) = <_>::ssz_decode(bytes, i)?;
Ok((
Self {
validator_index,
shard,
slot,
},
i,
))
}
}
impl<T: RngCore> TestRandom<T> for ShardReassignmentRecord {
fn random_for_test(rng: &mut T) -> Self {
Self {
validator_index: <_>::random_for_test(rng),
shard: <_>::random_for_test(rng),
slot: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = ShardReassignmentRecord::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

View File

@@ -0,0 +1,70 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use super::AttestationData;
use crate::test_utils::TestRandom;
use bls::AggregateSignature;
use rand::RngCore;
#[derive(Debug, PartialEq, Clone)]
pub struct SlashableVoteData {
pub aggregate_signature_poc_0_indices: Vec<u32>,
pub aggregate_signature_poc_1_indices: Vec<u32>,
pub data: AttestationData,
pub aggregate_signature: AggregateSignature,
}
impl Encodable for SlashableVoteData {
fn ssz_append(&self, s: &mut SszStream) {
s.append_vec(&self.aggregate_signature_poc_0_indices);
s.append_vec(&self.aggregate_signature_poc_1_indices);
s.append(&self.data);
s.append(&self.aggregate_signature);
}
}
impl Decodable for SlashableVoteData {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (aggregate_signature_poc_0_indices, i) = <_>::ssz_decode(bytes, i)?;
let (aggregate_signature_poc_1_indices, i) = <_>::ssz_decode(bytes, i)?;
let (data, i) = <_>::ssz_decode(bytes, i)?;
let (aggregate_signature, i) = <_>::ssz_decode(bytes, i)?;
Ok((
SlashableVoteData {
aggregate_signature_poc_0_indices,
aggregate_signature_poc_1_indices,
data,
aggregate_signature,
},
i,
))
}
}
impl<T: RngCore> TestRandom<T> for SlashableVoteData {
fn random_for_test(rng: &mut T) -> Self {
Self {
aggregate_signature_poc_0_indices: <_>::random_for_test(rng),
aggregate_signature_poc_1_indices: <_>::random_for_test(rng),
data: <_>::random_for_test(rng),
aggregate_signature: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = SlashableVoteData::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
}

View File

@@ -0,0 +1,132 @@
use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
/// The value of the "type" field of SpecialRecord.
///
/// Note: this value must serialize to a u8 and therefore must not be greater than 255.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum SpecialRecordKind {
Logout = 0,
CasperSlashing = 1,
RandaoChange = 2,
}
/// The structure used in the `BeaconBlock.specials` field.
#[derive(Debug, PartialEq, Clone)]
pub struct SpecialRecord {
pub kind: u8,
pub data: Vec<u8>,
}
impl SpecialRecord {
pub fn logout(data: &[u8]) -> Self {
Self {
kind: SpecialRecordKind::Logout as u8,
data: data.to_vec(),
}
}
pub fn casper_slashing(data: &[u8]) -> Self {
Self {
kind: SpecialRecordKind::CasperSlashing as u8,
data: data.to_vec(),
}
}
pub fn randao_change(data: &[u8]) -> Self {
Self {
kind: SpecialRecordKind::RandaoChange as u8,
data: data.to_vec(),
}
}
/// Match `self.kind` to a `SpecialRecordKind`.
///
/// Returns `None` if `self.kind` is an unknown value.
pub fn resolve_kind(&self) -> Option<SpecialRecordKind> {
match self.kind {
x if x == SpecialRecordKind::Logout as u8 => Some(SpecialRecordKind::Logout),
x if x == SpecialRecordKind::CasperSlashing as u8 => {
Some(SpecialRecordKind::CasperSlashing)
}
x if x == SpecialRecordKind::RandaoChange as u8 => {
Some(SpecialRecordKind::RandaoChange)
}
_ => None,
}
}
}
impl Encodable for SpecialRecord {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.kind);
s.append_vec(&self.data);
}
}
impl Decodable for SpecialRecord {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (kind, i) = u8::ssz_decode(bytes, i)?;
let (data, i) = Decodable::ssz_decode(bytes, i)?;
Ok((SpecialRecord { kind, data }, i))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn test_special_record_ssz_encode() {
let s = SpecialRecord::logout(&vec![]);
let mut ssz_stream = SszStream::new();
ssz_stream.append(&s);
let ssz = ssz_stream.drain();
assert_eq!(ssz, vec![0, 0, 0, 0, 0]);
let s = SpecialRecord::casper_slashing(&vec![]);
let mut ssz_stream = SszStream::new();
ssz_stream.append(&s);
let ssz = ssz_stream.drain();
assert_eq!(ssz, vec![1, 0, 0, 0, 0]);
let s = SpecialRecord::randao_change(&vec![]);
let mut ssz_stream = SszStream::new();
ssz_stream.append(&s);
let ssz = ssz_stream.drain();
assert_eq!(ssz, vec![2, 0, 0, 0, 0]);
let s = SpecialRecord::randao_change(&vec![42, 43, 44]);
let mut ssz_stream = SszStream::new();
ssz_stream.append(&s);
let ssz = ssz_stream.drain();
assert_eq!(ssz, vec![2, 0, 0, 0, 3, 42, 43, 44]);
}
#[test]
pub fn test_special_record_ssz_encode_decode() {
let s = SpecialRecord::randao_change(&vec![13, 16, 14]);
let mut ssz_stream = SszStream::new();
ssz_stream.append(&s);
let ssz = ssz_stream.drain();
let (s_decoded, _) = SpecialRecord::ssz_decode(&ssz, 0).unwrap();
assert_eq!(s, s_decoded);
}
#[test]
pub fn test_special_record_resolve_kind() {
let s = SpecialRecord::logout(&vec![]);
assert_eq!(s.resolve_kind(), Some(SpecialRecordKind::Logout));
let s = SpecialRecord::casper_slashing(&vec![]);
assert_eq!(s.resolve_kind(), Some(SpecialRecordKind::CasperSlashing));
let s = SpecialRecord::randao_change(&vec![]);
assert_eq!(s.resolve_kind(), Some(SpecialRecordKind::RandaoChange));
let s = SpecialRecord {
kind: 88,
data: vec![],
};
assert_eq!(s.resolve_kind(), None);
}
}

View File

@@ -0,0 +1,11 @@
use super::TestRandom;
use crate::Address;
use rand::RngCore;
impl<T: RngCore> TestRandom<T> for Address {
fn random_for_test(rng: &mut T) -> Self {
let mut key_bytes = vec![0; 20];
rng.fill_bytes(&mut key_bytes);
Address::from(&key_bytes[..])
}
}

View File

@@ -0,0 +1,12 @@
use super::TestRandom;
use bls::{AggregateSignature, Signature};
use rand::RngCore;
impl<T: RngCore> TestRandom<T> for AggregateSignature {
fn random_for_test(rng: &mut T) -> Self {
let signature = Signature::random_for_test(rng);
let mut aggregate_signature = AggregateSignature::new();
aggregate_signature.add(&signature);
aggregate_signature
}
}

View File

@@ -0,0 +1,11 @@
use super::super::Bitfield;
use super::TestRandom;
use rand::RngCore;
impl<T: RngCore> TestRandom<T> for Bitfield {
fn random_for_test(rng: &mut T) -> Self {
let mut raw_bytes = vec![0; 32];
rng.fill_bytes(&mut raw_bytes);
Bitfield::from_bytes(&raw_bytes)
}
}

View File

@@ -0,0 +1,11 @@
use super::TestRandom;
use crate::Hash256;
use rand::RngCore;
impl<T: RngCore> TestRandom<T> for Hash256 {
fn random_for_test(rng: &mut T) -> Self {
let mut key_bytes = vec![0; 32];
rng.fill_bytes(&mut key_bytes);
Hash256::from(&key_bytes[..])
}
}

View File

@@ -0,0 +1,49 @@
use rand::RngCore;
pub use rand::{prng::XorShiftRng, SeedableRng};
pub mod address;
pub mod aggregate_signature;
pub mod bitfield;
pub mod hash256;
pub mod public_key;
pub mod secret_key;
pub mod signature;
pub trait TestRandom<T>
where
T: RngCore,
{
fn random_for_test(rng: &mut T) -> Self;
}
impl<T: RngCore> TestRandom<T> for u64 {
fn random_for_test(rng: &mut T) -> Self {
rng.next_u64()
}
}
impl<T: RngCore> TestRandom<T> for u32 {
fn random_for_test(rng: &mut T) -> Self {
rng.next_u32()
}
}
impl<T: RngCore> TestRandom<T> for usize {
fn random_for_test(rng: &mut T) -> Self {
rng.next_u32() as usize
}
}
impl<T: RngCore, U> TestRandom<T> for Vec<U>
where
U: TestRandom<T>,
{
fn random_for_test(rng: &mut T) -> Self {
vec![
<U>::random_for_test(rng),
<U>::random_for_test(rng),
<U>::random_for_test(rng),
]
}
}

View File

@@ -0,0 +1,10 @@
use super::TestRandom;
use bls::{PublicKey, SecretKey};
use rand::RngCore;
impl<T: RngCore> TestRandom<T> for PublicKey {
fn random_for_test(rng: &mut T) -> Self {
let secret_key = SecretKey::random_for_test(rng);
PublicKey::from_secret_key(&secret_key)
}
}

View File

@@ -0,0 +1,19 @@
use super::TestRandom;
use bls::SecretKey;
use rand::RngCore;
impl<T: RngCore> TestRandom<T> for SecretKey {
fn random_for_test(rng: &mut T) -> Self {
let mut key_bytes = vec![0; 48];
rng.fill_bytes(&mut key_bytes);
/*
* An `unreachable!` is used here as there's no reason why you cannot constuct a key from a
* fixed-length byte slice. Also, this should only be used during testing so a panic is
* acceptable.
*/
match SecretKey::from_bytes(&key_bytes) {
Ok(key) => key,
Err(_) => unreachable!(),
}
}
}

View File

@@ -0,0 +1,13 @@
use super::TestRandom;
use bls::{SecretKey, Signature};
use rand::RngCore;
impl<T: RngCore> TestRandom<T> for Signature {
fn random_for_test(rng: &mut T) -> Self {
let secret_key = SecretKey::random_for_test(rng);
let mut message = vec![0; 32];
rng.fill_bytes(&mut message);
Signature::new(&message, &secret_key)
}
}

View File

@@ -0,0 +1,213 @@
use super::bls::PublicKey;
use super::Hash256;
use crate::test_utils::TestRandom;
use rand::RngCore;
use ssz::{Decodable, DecodeError, Encodable, SszStream};
const STATUS_FLAG_INITIATED_EXIT: u8 = 1;
const STATUS_FLAG_WITHDRAWABLE: u8 = 2;
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum StatusFlags {
InitiatedExit,
Withdrawable,
}
struct StatusFlagsDecodeError;
impl From<StatusFlagsDecodeError> for DecodeError {
fn from(_: StatusFlagsDecodeError) -> DecodeError {
DecodeError::Invalid
}
}
/// Handles the serialization logic for the `status_flags` field of the `ValidatorRecord`.
fn status_flag_to_byte(flag: Option<StatusFlags>) -> u8 {
if let Some(flag) = flag {
match flag {
StatusFlags::InitiatedExit => STATUS_FLAG_INITIATED_EXIT,
StatusFlags::Withdrawable => STATUS_FLAG_WITHDRAWABLE,
}
} else {
0
}
}
/// Handles the deserialization logic for the `status_flags` field of the `ValidatorRecord`.
fn status_flag_from_byte(flag: u8) -> Result<Option<StatusFlags>, StatusFlagsDecodeError> {
match flag {
0 => Ok(None),
1 => Ok(Some(StatusFlags::InitiatedExit)),
2 => Ok(Some(StatusFlags::Withdrawable)),
_ => Err(StatusFlagsDecodeError),
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct ValidatorRecord {
pub pubkey: PublicKey,
pub withdrawal_credentials: Hash256,
pub randao_commitment: Hash256,
pub randao_layers: u64,
pub activation_slot: u64,
pub exit_slot: u64,
pub withdrawal_slot: u64,
pub penalized_slot: u64,
pub exit_count: u64,
pub status_flags: Option<StatusFlags>,
pub custody_commitment: Hash256,
pub latest_custody_reseed_slot: u64,
pub penultimate_custody_reseed_slot: u64,
}
impl ValidatorRecord {
/// This predicate indicates if the validator represented by this record is considered "active" at `slot`.
pub fn is_active_at(&self, slot: u64) -> bool {
self.activation_slot <= slot && slot < self.exit_slot
}
}
impl Default for ValidatorRecord {
/// Yields a "default" `ValidatorRecord`. Primarily used for testing.
fn default() -> Self {
Self {
pubkey: PublicKey::default(),
withdrawal_credentials: Hash256::default(),
randao_commitment: Hash256::default(),
randao_layers: 0,
activation_slot: std::u64::MAX,
exit_slot: std::u64::MAX,
withdrawal_slot: std::u64::MAX,
penalized_slot: std::u64::MAX,
exit_count: 0,
status_flags: None,
custody_commitment: Hash256::default(),
latest_custody_reseed_slot: 0, // NOTE: is `GENESIS_SLOT`
penultimate_custody_reseed_slot: 0, // NOTE: is `GENESIS_SLOT`
}
}
}
impl<T: RngCore> TestRandom<T> for StatusFlags {
fn random_for_test(rng: &mut T) -> Self {
let options = vec![StatusFlags::InitiatedExit, StatusFlags::Withdrawable];
options[(rng.next_u32() as usize) % options.len()].clone()
}
}
impl Encodable for ValidatorRecord {
fn ssz_append(&self, s: &mut SszStream) {
s.append(&self.pubkey);
s.append(&self.withdrawal_credentials);
s.append(&self.randao_commitment);
s.append(&self.randao_layers);
s.append(&self.activation_slot);
s.append(&self.exit_slot);
s.append(&self.withdrawal_slot);
s.append(&self.penalized_slot);
s.append(&self.exit_count);
s.append(&status_flag_to_byte(self.status_flags));
s.append(&self.custody_commitment);
s.append(&self.latest_custody_reseed_slot);
s.append(&self.penultimate_custody_reseed_slot);
}
}
impl Decodable for ValidatorRecord {
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
let (pubkey, i) = <_>::ssz_decode(bytes, i)?;
let (withdrawal_credentials, i) = <_>::ssz_decode(bytes, i)?;
let (randao_commitment, i) = <_>::ssz_decode(bytes, i)?;
let (randao_layers, i) = <_>::ssz_decode(bytes, i)?;
let (activation_slot, i) = <_>::ssz_decode(bytes, i)?;
let (exit_slot, i) = <_>::ssz_decode(bytes, i)?;
let (withdrawal_slot, i) = <_>::ssz_decode(bytes, i)?;
let (penalized_slot, i) = <_>::ssz_decode(bytes, i)?;
let (exit_count, i) = <_>::ssz_decode(bytes, i)?;
let (status_flags_byte, i): (u8, usize) = <_>::ssz_decode(bytes, i)?;
let (custody_commitment, i) = <_>::ssz_decode(bytes, i)?;
let (latest_custody_reseed_slot, i) = <_>::ssz_decode(bytes, i)?;
let (penultimate_custody_reseed_slot, i) = <_>::ssz_decode(bytes, i)?;
let status_flags = status_flag_from_byte(status_flags_byte)?;
Ok((
Self {
pubkey,
withdrawal_credentials,
randao_commitment,
randao_layers,
activation_slot,
exit_slot,
withdrawal_slot,
penalized_slot,
exit_count,
status_flags,
custody_commitment,
latest_custody_reseed_slot,
penultimate_custody_reseed_slot,
},
i,
))
}
}
impl<T: RngCore> TestRandom<T> for ValidatorRecord {
fn random_for_test(rng: &mut T) -> Self {
Self {
pubkey: <_>::random_for_test(rng),
withdrawal_credentials: <_>::random_for_test(rng),
randao_commitment: <_>::random_for_test(rng),
randao_layers: <_>::random_for_test(rng),
activation_slot: <_>::random_for_test(rng),
exit_slot: <_>::random_for_test(rng),
withdrawal_slot: <_>::random_for_test(rng),
penalized_slot: <_>::random_for_test(rng),
exit_count: <_>::random_for_test(rng),
status_flags: Some(<_>::random_for_test(rng)),
custody_commitment: <_>::random_for_test(rng),
latest_custody_reseed_slot: <_>::random_for_test(rng),
penultimate_custody_reseed_slot: <_>::random_for_test(rng),
}
}
}
#[cfg(test)]
mod tests {
use super::super::ssz::ssz_encode;
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
pub fn test_ssz_round_trip() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = ValidatorRecord::random_for_test(&mut rng);
let bytes = ssz_encode(&original);
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
assert_eq!(original, decoded);
}
#[test]
fn test_validator_can_be_active() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let mut validator = ValidatorRecord::random_for_test(&mut rng);
let activation_slot = u64::random_for_test(&mut rng);
let exit_slot = activation_slot + 234;
validator.activation_slot = activation_slot;
validator.exit_slot = exit_slot;
for slot in (activation_slot - 100)..(exit_slot + 100) {
if slot < activation_slot {
assert!(!validator.is_active_at(slot));
} else if slot >= exit_slot {
assert!(!validator.is_active_at(slot));
} else {
assert!(validator.is_active_at(slot));
}
}
}
}

View File

@@ -0,0 +1,12 @@
use super::{Address, Hash256};
use bls::{PublicKey, Signature};
/// The information gathered from the PoW chain validator registration function.
#[derive(Debug, Clone, PartialEq)]
pub struct ValidatorRegistration {
pub pubkey: PublicKey,
pub withdrawal_shard: u64,
pub withdrawal_address: Address,
pub randao_commitment: Hash256,
pub proof_of_possession: Signature,
}

View File

@@ -0,0 +1,171 @@
/// Contains logic to manipulate a `&[ValidatorRecord]`.
/// For now, we avoid defining a newtype and just have flat functions here.
use super::validator_record::*;
/// Given an indexed sequence of `validators`, return the indices corresponding to validators that are active at `slot`.
pub fn get_active_validator_indices(validators: &[ValidatorRecord], slot: u64) -> Vec<usize> {
validators
.iter()
.enumerate()
.filter_map(|(index, validator)| {
if validator.is_active_at(slot) {
Some(index)
} else {
None
}
})
.collect::<Vec<_>>()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
#[test]
fn can_get_empty_active_validator_indices() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let validators = vec![];
let some_slot = u64::random_for_test(&mut rng);
let indices = get_active_validator_indices(&validators, some_slot);
assert_eq!(indices, vec![]);
}
#[test]
fn can_get_no_active_validator_indices() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let mut validators = vec![];
let count_validators = 10;
for _ in 0..count_validators {
validators.push(ValidatorRecord::default())
}
let some_slot = u64::random_for_test(&mut rng);
let indices = get_active_validator_indices(&validators, some_slot);
assert_eq!(indices, vec![]);
}
#[test]
fn can_get_all_active_validator_indices() {
let mut rng = XorShiftRng::from_seed([42; 16]);
let count_validators = 10;
let some_slot = u64::random_for_test(&mut rng);
let mut validators = (0..count_validators)
.into_iter()
.map(|_| {
let mut validator = ValidatorRecord::default();
let activation_offset = u64::random_for_test(&mut rng);
let exit_offset = u64::random_for_test(&mut rng);
validator.activation_slot = some_slot.checked_sub(activation_offset).unwrap_or(0);
validator.exit_slot = some_slot.checked_add(exit_offset).unwrap_or(std::u64::MAX);
validator
})
.collect::<Vec<_>>();
// test boundary condition by ensuring that at least one validator in the list just activated
if let Some(validator) = validators.get_mut(0) {
validator.activation_slot = some_slot;
}
let indices = get_active_validator_indices(&validators, some_slot);
assert_eq!(
indices,
(0..count_validators).into_iter().collect::<Vec<_>>()
);
}
fn set_validators_to_default_entry_exit(validators: &mut [ValidatorRecord]) {
for validator in validators.iter_mut() {
validator.activation_slot = std::u64::MAX;
validator.exit_slot = std::u64::MAX;
}
}
// sets all `validators` to be active as of some slot prior to `slot`. returns the activation slot.
fn set_validators_to_activated(validators: &mut [ValidatorRecord], slot: u64) -> u64 {
let activation_slot = slot - 10;
for validator in validators.iter_mut() {
validator.activation_slot = activation_slot;
}
activation_slot
}
// sets all `validators` to be exited as of some slot before `slot`.
fn set_validators_to_exited(
validators: &mut [ValidatorRecord],
slot: u64,
activation_slot: u64,
) {
assert!(activation_slot < slot);
let mut exit_slot = activation_slot + 10;
while exit_slot >= slot {
exit_slot -= 1;
}
assert!(activation_slot < exit_slot && exit_slot < slot);
for validator in validators.iter_mut() {
validator.exit_slot = exit_slot;
}
}
#[test]
fn can_get_some_active_validator_indices() {
let mut rng = XorShiftRng::from_seed([42; 16]);
const COUNT_PARTITIONS: usize = 3;
const COUNT_VALIDATORS: usize = 3 * COUNT_PARTITIONS;
let some_slot: u64 = u64::random_for_test(&mut rng);
let mut validators = (0..COUNT_VALIDATORS)
.into_iter()
.map(|_| {
let mut validator = ValidatorRecord::default();
let activation_offset = u64::random_for_test(&mut rng);
let exit_offset = u64::random_for_test(&mut rng);
validator.activation_slot = some_slot.checked_sub(activation_offset).unwrap_or(0);
validator.exit_slot = some_slot.checked_add(exit_offset).unwrap_or(std::u64::MAX);
validator
})
.collect::<Vec<_>>();
// we partition the set into partitions based on lifecycle:
for (i, chunk) in validators.chunks_exact_mut(COUNT_PARTITIONS).enumerate() {
match i {
0 => {
// 1. not activated (Default::default())
set_validators_to_default_entry_exit(chunk);
}
1 => {
// 2. activated, but not exited
set_validators_to_activated(chunk, some_slot);
// test boundary condition by ensuring that at least one validator in the list just activated
if let Some(validator) = chunk.get_mut(0) {
validator.activation_slot = some_slot;
}
}
2 => {
// 3. exited
let activation_slot = set_validators_to_activated(chunk, some_slot);
set_validators_to_exited(chunk, some_slot, activation_slot);
// test boundary condition by ensuring that at least one validator in the list just exited
if let Some(validator) = chunk.get_mut(0) {
validator.exit_slot = some_slot;
}
}
_ => unreachable!(
"constants local to this test not in sync with generation of test case"
),
}
}
let indices = get_active_validator_indices(&validators, some_slot);
assert_eq!(indices, vec![3, 4, 5]);
}
}