Update types
defs, move processing out.
- Update `types` to v0.2.0 spec (not all functions upgraded too). - Move slot/block/epoch processing out to a separate crate (not included yet, it doesn't compile)
This commit is contained in:
parent
a0eb359738
commit
a13dd0d871
@ -7,8 +7,8 @@ use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize)]
|
||||
pub struct Attestation {
|
||||
pub data: AttestationData,
|
||||
pub aggregation_bitfield: Bitfield,
|
||||
pub data: AttestationData,
|
||||
pub custody_bitfield: Bitfield,
|
||||
pub aggregate_signature: AggregateSignature,
|
||||
}
|
||||
@ -25,8 +25,8 @@ impl Attestation {
|
||||
|
||||
impl Encodable for Attestation {
|
||||
fn ssz_append(&self, s: &mut SszStream) {
|
||||
s.append(&self.data);
|
||||
s.append(&self.aggregation_bitfield);
|
||||
s.append(&self.data);
|
||||
s.append(&self.custody_bitfield);
|
||||
s.append(&self.aggregate_signature);
|
||||
}
|
||||
@ -34,14 +34,14 @@ impl Encodable for Attestation {
|
||||
|
||||
impl Decodable for Attestation {
|
||||
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
||||
let (data, i) = AttestationData::ssz_decode(bytes, i)?;
|
||||
let (aggregation_bitfield, i) = Bitfield::ssz_decode(bytes, i)?;
|
||||
let (data, i) = AttestationData::ssz_decode(bytes, i)?;
|
||||
let (custody_bitfield, i) = Bitfield::ssz_decode(bytes, i)?;
|
||||
let (aggregate_signature, i) = AggregateSignature::ssz_decode(bytes, i)?;
|
||||
|
||||
let attestation_record = Self {
|
||||
data,
|
||||
aggregation_bitfield,
|
||||
data,
|
||||
custody_bitfield,
|
||||
aggregate_signature,
|
||||
};
|
||||
@ -49,22 +49,11 @@ impl Decodable for Attestation {
|
||||
}
|
||||
}
|
||||
|
||||
impl Attestation {
|
||||
pub fn zero() -> Self {
|
||||
Self {
|
||||
data: AttestationData::zero(),
|
||||
aggregation_bitfield: Bitfield::new(),
|
||||
custody_bitfield: Bitfield::new(),
|
||||
aggregate_signature: AggregateSignature::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TreeHash for Attestation {
|
||||
fn hash_tree_root(&self) -> Vec<u8> {
|
||||
let mut result: Vec<u8> = vec![];
|
||||
result.append(&mut self.data.hash_tree_root());
|
||||
result.append(&mut self.aggregation_bitfield.hash_tree_root());
|
||||
result.append(&mut self.data.hash_tree_root());
|
||||
result.append(&mut self.custody_bitfield.hash_tree_root());
|
||||
result.append(&mut self.aggregate_signature.hash_tree_root());
|
||||
hash(&result)
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{AttestationDataAndCustodyBit, Hash256, Slot};
|
||||
use crate::{AttestationDataAndCustodyBit, Crosslink, Epoch, Hash256, Slot};
|
||||
use rand::RngCore;
|
||||
use serde_derive::Serialize;
|
||||
use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};
|
||||
@ -11,7 +11,7 @@ pub const SSZ_ATTESTION_DATA_LENGTH: usize = {
|
||||
32 + // epoch_boundary_root
|
||||
32 + // shard_block_hash
|
||||
32 + // latest_crosslink_hash
|
||||
8 + // justified_slot
|
||||
8 + // justified_epoch
|
||||
32 // justified_block_root
|
||||
};
|
||||
|
||||
@ -22,27 +22,14 @@ pub struct AttestationData {
|
||||
pub beacon_block_root: Hash256,
|
||||
pub epoch_boundary_root: Hash256,
|
||||
pub shard_block_root: Hash256,
|
||||
pub latest_crosslink_root: Hash256,
|
||||
pub justified_slot: Slot,
|
||||
pub latest_crosslink: Crosslink,
|
||||
pub justified_epoch: Epoch,
|
||||
pub justified_block_root: Hash256,
|
||||
}
|
||||
|
||||
impl Eq for AttestationData {}
|
||||
|
||||
impl AttestationData {
|
||||
pub fn zero() -> Self {
|
||||
Self {
|
||||
slot: Slot::from(0_u64),
|
||||
shard: 0,
|
||||
beacon_block_root: Hash256::zero(),
|
||||
epoch_boundary_root: Hash256::zero(),
|
||||
shard_block_root: Hash256::zero(),
|
||||
latest_crosslink_root: Hash256::zero(),
|
||||
justified_slot: Slot::from(0_u64),
|
||||
justified_block_root: Hash256::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn canonical_root(&self) -> Hash256 {
|
||||
Hash256::from(&self.hash_tree_root()[..])
|
||||
}
|
||||
@ -63,8 +50,8 @@ impl Encodable for AttestationData {
|
||||
s.append(&self.beacon_block_root);
|
||||
s.append(&self.epoch_boundary_root);
|
||||
s.append(&self.shard_block_root);
|
||||
s.append(&self.latest_crosslink_root);
|
||||
s.append(&self.justified_slot);
|
||||
s.append(&self.latest_crosslink);
|
||||
s.append(&self.justified_epoch);
|
||||
s.append(&self.justified_block_root);
|
||||
}
|
||||
}
|
||||
@ -76,8 +63,8 @@ impl Decodable for AttestationData {
|
||||
let (beacon_block_root, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (epoch_boundary_root, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (shard_block_root, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (latest_crosslink_root, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (justified_slot, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (latest_crosslink, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (justified_epoch, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (justified_block_root, i) = <_>::ssz_decode(bytes, i)?;
|
||||
|
||||
let attestation_data = AttestationData {
|
||||
@ -86,8 +73,8 @@ impl Decodable for AttestationData {
|
||||
beacon_block_root,
|
||||
epoch_boundary_root,
|
||||
shard_block_root,
|
||||
latest_crosslink_root,
|
||||
justified_slot,
|
||||
latest_crosslink,
|
||||
justified_epoch,
|
||||
justified_block_root,
|
||||
};
|
||||
Ok((attestation_data, i))
|
||||
@ -102,8 +89,8 @@ impl TreeHash for AttestationData {
|
||||
result.append(&mut self.beacon_block_root.hash_tree_root());
|
||||
result.append(&mut self.epoch_boundary_root.hash_tree_root());
|
||||
result.append(&mut self.shard_block_root.hash_tree_root());
|
||||
result.append(&mut self.latest_crosslink_root.hash_tree_root());
|
||||
result.append(&mut self.justified_slot.hash_tree_root());
|
||||
result.append(&mut self.latest_crosslink.hash_tree_root());
|
||||
result.append(&mut self.justified_epoch.hash_tree_root());
|
||||
result.append(&mut self.justified_block_root.hash_tree_root());
|
||||
hash(&result)
|
||||
}
|
||||
@ -117,8 +104,8 @@ impl<T: RngCore> TestRandom<T> for AttestationData {
|
||||
beacon_block_root: <_>::random_for_test(rng),
|
||||
epoch_boundary_root: <_>::random_for_test(rng),
|
||||
shard_block_root: <_>::random_for_test(rng),
|
||||
latest_crosslink_root: <_>::random_for_test(rng),
|
||||
justified_slot: <_>::random_for_test(rng),
|
||||
latest_crosslink: <_>::random_for_test(rng),
|
||||
justified_epoch: <_>::random_for_test(rng),
|
||||
justified_block_root: <_>::random_for_test(rng),
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use super::AttestationData;
|
||||
use crate::test_utils::TestRandom;
|
||||
use rand::RngCore;
|
||||
use serde_derive::Serialize;
|
||||
use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};
|
||||
use ssz::{Decodable, DecodeError, Encodable, SszStream, TreeHash};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Default, Serialize)]
|
||||
pub struct AttestationDataAndCustodyBit {
|
||||
|
80
eth2/types/src/attester_slashing.rs
Normal file
80
eth2/types/src/attester_slashing.rs
Normal file
@ -0,0 +1,80 @@
|
||||
use crate::{test_utils::TestRandom, SlashableAttestation};
|
||||
use rand::RngCore;
|
||||
use serde_derive::Serialize;
|
||||
use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize)]
|
||||
pub struct AttesterSlashing {
|
||||
pub slashable_attestation_1: SlashableAttestation,
|
||||
pub slashable_attestation_2: SlashableAttestation,
|
||||
}
|
||||
|
||||
impl Encodable for AttesterSlashing {
|
||||
fn ssz_append(&self, s: &mut SszStream) {
|
||||
s.append(&self.slashable_attestation_1);
|
||||
s.append(&self.slashable_attestation_2);
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for AttesterSlashing {
|
||||
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
||||
let (slashable_attestation_1, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (slashable_attestation_2, i) = <_>::ssz_decode(bytes, i)?;
|
||||
|
||||
Ok((
|
||||
AttesterSlashing {
|
||||
slashable_attestation_1,
|
||||
slashable_attestation_2,
|
||||
},
|
||||
i,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl TreeHash for AttesterSlashing {
|
||||
fn hash_tree_root(&self) -> Vec<u8> {
|
||||
let mut result: Vec<u8> = vec![];
|
||||
result.append(&mut self.slashable_attestation_1.hash_tree_root());
|
||||
result.append(&mut self.slashable_attestation_2.hash_tree_root());
|
||||
hash(&result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RngCore> TestRandom<T> for AttesterSlashing {
|
||||
fn random_for_test(rng: &mut T) -> Self {
|
||||
Self {
|
||||
slashable_attestation_1: <_>::random_for_test(rng),
|
||||
slashable_attestation_2: <_>::random_for_test(rng),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
|
||||
use ssz::ssz_encode;
|
||||
|
||||
#[test]
|
||||
pub fn test_ssz_round_trip() {
|
||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
||||
let original = AttesterSlashing::random_for_test(&mut rng);
|
||||
|
||||
let bytes = ssz_encode(&original);
|
||||
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
|
||||
|
||||
assert_eq!(original, decoded);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_hash_tree_root() {
|
||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
||||
let original = AttesterSlashing::random_for_test(&mut rng);
|
||||
|
||||
let result = original.hash_tree_root();
|
||||
|
||||
assert_eq!(result.len(), 32);
|
||||
// TODO: Add further tests
|
||||
// https://github.com/sigp/lighthouse/issues/170
|
||||
}
|
||||
}
|
@ -1,23 +1,14 @@
|
||||
use super::{Attestation, CasperSlashing, Deposit, Exit, ProposerSlashing};
|
||||
use super::{Attestation, AttesterSlashing, Deposit, Exit, ProposerSlashing};
|
||||
use crate::test_utils::TestRandom;
|
||||
use rand::RngCore;
|
||||
use serde_derive::Serialize;
|
||||
use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};
|
||||
|
||||
// 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, Serialize)]
|
||||
pub struct BeaconBlockBody {
|
||||
pub proposer_slashings: Vec<ProposerSlashing>,
|
||||
pub casper_slashings: Vec<CasperSlashing>,
|
||||
pub attester_slashings: Vec<AttesterSlashing>,
|
||||
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>,
|
||||
}
|
||||
@ -25,11 +16,8 @@ pub struct BeaconBlockBody {
|
||||
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.attester_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);
|
||||
}
|
||||
@ -38,22 +26,16 @@ impl Encodable for BeaconBlockBody {
|
||||
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 (attester_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,
|
||||
attester_slashings,
|
||||
attestations,
|
||||
custody_reseeds,
|
||||
custody_challenges,
|
||||
custody_responses,
|
||||
deposits,
|
||||
exits,
|
||||
},
|
||||
@ -66,11 +48,8 @@ impl TreeHash for BeaconBlockBody {
|
||||
fn hash_tree_root(&self) -> Vec<u8> {
|
||||
let mut result: Vec<u8> = vec![];
|
||||
result.append(&mut self.proposer_slashings.hash_tree_root());
|
||||
result.append(&mut self.casper_slashings.hash_tree_root());
|
||||
result.append(&mut self.attester_slashings.hash_tree_root());
|
||||
result.append(&mut self.attestations.hash_tree_root());
|
||||
result.append(&mut self.custody_reseeds.hash_tree_root());
|
||||
result.append(&mut self.custody_challenges.hash_tree_root());
|
||||
result.append(&mut self.custody_responses.hash_tree_root());
|
||||
result.append(&mut self.deposits.hash_tree_root());
|
||||
result.append(&mut self.exits.hash_tree_root());
|
||||
hash(&result)
|
||||
@ -81,11 +60,8 @@ 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),
|
||||
attester_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),
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,12 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{Hash256, Slot};
|
||||
use crate::{Epoch, Hash256};
|
||||
use rand::RngCore;
|
||||
use serde_derive::Serialize;
|
||||
use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Default, Serialize, Hash)]
|
||||
pub struct Crosslink {
|
||||
pub slot: Slot,
|
||||
pub epoch: Epoch,
|
||||
pub shard_block_root: Hash256,
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ impl Crosslink {
|
||||
/// Generates a new instance where `dynasty` and `hash` are both zero.
|
||||
pub fn zero() -> Self {
|
||||
Self {
|
||||
slot: Slot::from(0_u64),
|
||||
epoch: Epoch::new(0),
|
||||
shard_block_root: Hash256::zero(),
|
||||
}
|
||||
}
|
||||
@ -22,19 +22,19 @@ impl Crosslink {
|
||||
|
||||
impl Encodable for Crosslink {
|
||||
fn ssz_append(&self, s: &mut SszStream) {
|
||||
s.append(&self.slot);
|
||||
s.append(&self.epoch);
|
||||
s.append(&self.shard_block_root);
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for Crosslink {
|
||||
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
||||
let (slot, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (epoch, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (shard_block_root, i) = <_>::ssz_decode(bytes, i)?;
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
slot,
|
||||
epoch,
|
||||
shard_block_root,
|
||||
},
|
||||
i,
|
||||
@ -45,7 +45,7 @@ impl Decodable for Crosslink {
|
||||
impl TreeHash for Crosslink {
|
||||
fn hash_tree_root(&self) -> Vec<u8> {
|
||||
let mut result: Vec<u8> = vec![];
|
||||
result.append(&mut self.slot.hash_tree_root());
|
||||
result.append(&mut self.epoch.hash_tree_root());
|
||||
result.append(&mut self.shard_block_root.hash_tree_root());
|
||||
hash(&result)
|
||||
}
|
||||
@ -54,7 +54,7 @@ impl TreeHash for Crosslink {
|
||||
impl<T: RngCore> TestRandom<T> for Crosslink {
|
||||
fn random_for_test(rng: &mut T) -> Self {
|
||||
Self {
|
||||
slot: <_>::random_for_test(rng),
|
||||
epoch: <_>::random_for_test(rng),
|
||||
shard_block_root: <_>::random_for_test(rng),
|
||||
}
|
||||
}
|
||||
|
@ -6,29 +6,29 @@ use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize)]
|
||||
pub struct Deposit {
|
||||
pub merkle_branch: Vec<Hash256>,
|
||||
pub merkle_tree_index: u64,
|
||||
pub branch: Vec<Hash256>,
|
||||
pub 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_vec(&self.branch);
|
||||
s.append(&self.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 (branch, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (index, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (deposit_data, i) = <_>::ssz_decode(bytes, i)?;
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
merkle_branch,
|
||||
merkle_tree_index,
|
||||
branch,
|
||||
index,
|
||||
deposit_data,
|
||||
},
|
||||
i,
|
||||
@ -39,8 +39,8 @@ impl Decodable for Deposit {
|
||||
impl TreeHash for Deposit {
|
||||
fn hash_tree_root(&self) -> Vec<u8> {
|
||||
let mut result: Vec<u8> = vec![];
|
||||
result.append(&mut self.merkle_branch.hash_tree_root());
|
||||
result.append(&mut self.merkle_tree_index.hash_tree_root());
|
||||
result.append(&mut self.branch.hash_tree_root());
|
||||
result.append(&mut self.index.hash_tree_root());
|
||||
result.append(&mut self.deposit_data.hash_tree_root());
|
||||
hash(&result)
|
||||
}
|
||||
@ -49,8 +49,8 @@ impl TreeHash for Deposit {
|
||||
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),
|
||||
branch: <_>::random_for_test(rng),
|
||||
index: <_>::random_for_test(rng),
|
||||
deposit_data: <_>::random_for_test(rng),
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{test_utils::TestRandom, Slot};
|
||||
use crate::{test_utils::TestRandom, Epoch};
|
||||
use bls::Signature;
|
||||
use rand::RngCore;
|
||||
use serde_derive::Serialize;
|
||||
@ -6,14 +6,14 @@ use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize)]
|
||||
pub struct Exit {
|
||||
pub slot: Slot,
|
||||
pub validator_index: u32,
|
||||
pub epoch: Epoch,
|
||||
pub validator_index: u64,
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
impl Encodable for Exit {
|
||||
fn ssz_append(&self, s: &mut SszStream) {
|
||||
s.append(&self.slot);
|
||||
s.append(&self.epoch);
|
||||
s.append(&self.validator_index);
|
||||
s.append(&self.signature);
|
||||
}
|
||||
@ -21,13 +21,13 @@ impl Encodable for Exit {
|
||||
|
||||
impl Decodable for Exit {
|
||||
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
||||
let (slot, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (epoch, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (validator_index, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (signature, i) = <_>::ssz_decode(bytes, i)?;
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
slot,
|
||||
epoch,
|
||||
validator_index,
|
||||
signature,
|
||||
},
|
||||
@ -39,7 +39,7 @@ impl Decodable for Exit {
|
||||
impl TreeHash for Exit {
|
||||
fn hash_tree_root(&self) -> Vec<u8> {
|
||||
let mut result: Vec<u8> = vec![];
|
||||
result.append(&mut self.slot.hash_tree_root());
|
||||
result.append(&mut self.epoch.hash_tree_root());
|
||||
result.append(&mut self.validator_index.hash_tree_root());
|
||||
result.append(&mut self.signature.hash_tree_root());
|
||||
hash(&result)
|
||||
@ -49,7 +49,7 @@ impl TreeHash for Exit {
|
||||
impl<T: RngCore> TestRandom<T> for Exit {
|
||||
fn random_for_test(rng: &mut T) -> Self {
|
||||
Self {
|
||||
slot: <_>::random_for_test(rng),
|
||||
epoch: <_>::random_for_test(rng),
|
||||
validator_index: <_>::random_for_test(rng),
|
||||
signature: <_>::random_for_test(rng),
|
||||
}
|
||||
|
@ -1,34 +1,34 @@
|
||||
use crate::{test_utils::TestRandom, Slot};
|
||||
use crate::{test_utils::TestRandom, Epoch};
|
||||
use rand::RngCore;
|
||||
use serde_derive::Serialize;
|
||||
use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Default, Serialize)]
|
||||
pub struct Fork {
|
||||
pub pre_fork_version: u64,
|
||||
pub post_fork_version: u64,
|
||||
pub fork_slot: Slot,
|
||||
pub previous_version: u64,
|
||||
pub current_version: u64,
|
||||
pub epoch: Epoch,
|
||||
}
|
||||
|
||||
impl Encodable for Fork {
|
||||
fn ssz_append(&self, s: &mut SszStream) {
|
||||
s.append(&self.pre_fork_version);
|
||||
s.append(&self.post_fork_version);
|
||||
s.append(&self.fork_slot);
|
||||
s.append(&self.previous_version);
|
||||
s.append(&self.current_version);
|
||||
s.append(&self.epoch);
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for Fork {
|
||||
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)?;
|
||||
let (previous_version, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (current_version, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (epoch, i) = <_>::ssz_decode(bytes, i)?;
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
pre_fork_version,
|
||||
post_fork_version,
|
||||
fork_slot,
|
||||
previous_version,
|
||||
current_version,
|
||||
epoch,
|
||||
},
|
||||
i,
|
||||
))
|
||||
@ -38,9 +38,9 @@ impl Decodable for Fork {
|
||||
impl TreeHash for Fork {
|
||||
fn hash_tree_root(&self) -> Vec<u8> {
|
||||
let mut result: Vec<u8> = vec![];
|
||||
result.append(&mut self.pre_fork_version.hash_tree_root());
|
||||
result.append(&mut self.post_fork_version.hash_tree_root());
|
||||
result.append(&mut self.fork_slot.hash_tree_root());
|
||||
result.append(&mut self.previous_version.hash_tree_root());
|
||||
result.append(&mut self.current_version.hash_tree_root());
|
||||
result.append(&mut self.epoch.hash_tree_root());
|
||||
hash(&result)
|
||||
}
|
||||
}
|
||||
@ -48,9 +48,9 @@ impl TreeHash for Fork {
|
||||
impl<T: RngCore> TestRandom<T> for Fork {
|
||||
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),
|
||||
previous_version: <_>::random_for_test(rng),
|
||||
current_version: <_>::random_for_test(rng),
|
||||
epoch: <_>::random_for_test(rng),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ pub mod test_utils;
|
||||
pub mod attestation;
|
||||
pub mod attestation_data;
|
||||
pub mod attestation_data_and_custody_bit;
|
||||
pub mod attester_slashing;
|
||||
pub mod beacon_block;
|
||||
pub mod beacon_block_body;
|
||||
pub mod beacon_state;
|
||||
@ -20,12 +21,11 @@ pub mod pending_attestation;
|
||||
pub mod proposal_signed_data;
|
||||
pub mod proposer_slashing;
|
||||
pub mod readers;
|
||||
pub mod shard_committee;
|
||||
pub mod shard_reassignment_record;
|
||||
pub mod slashable_attestation;
|
||||
pub mod slashable_vote_data;
|
||||
pub mod slot_epoch;
|
||||
pub mod spec;
|
||||
pub mod special_record;
|
||||
pub mod validator;
|
||||
pub mod validator_registry;
|
||||
pub mod validator_registry_delta_block;
|
||||
@ -36,6 +36,7 @@ use std::collections::HashMap;
|
||||
pub use crate::attestation::Attestation;
|
||||
pub use crate::attestation_data::AttestationData;
|
||||
pub use crate::attestation_data_and_custody_bit::AttestationDataAndCustodyBit;
|
||||
pub use crate::attester_slashing::AttesterSlashing;
|
||||
pub use crate::beacon_block::BeaconBlock;
|
||||
pub use crate::beacon_block_body::BeaconBlockBody;
|
||||
pub use crate::beacon_state::BeaconState;
|
||||
@ -52,11 +53,10 @@ pub use crate::free_attestation::FreeAttestation;
|
||||
pub use crate::pending_attestation::PendingAttestation;
|
||||
pub use crate::proposal_signed_data::ProposalSignedData;
|
||||
pub use crate::proposer_slashing::ProposerSlashing;
|
||||
pub use crate::shard_committee::ShardCommittee;
|
||||
pub use crate::slashable_attestation::SlashableAttestation;
|
||||
pub use crate::slashable_vote_data::SlashableVoteData;
|
||||
pub use crate::slot_epoch::{Epoch, Slot};
|
||||
pub use crate::spec::ChainSpec;
|
||||
pub use crate::special_record::{SpecialRecord, SpecialRecordKind};
|
||||
pub use crate::validator::{StatusFlags as ValidatorStatusFlags, Validator};
|
||||
pub use crate::validator_registry_delta_block::ValidatorRegistryDeltaBlock;
|
||||
|
||||
|
@ -6,34 +6,34 @@ use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize)]
|
||||
pub struct PendingAttestation {
|
||||
pub data: AttestationData,
|
||||
pub aggregation_bitfield: Bitfield,
|
||||
pub data: AttestationData,
|
||||
pub custody_bitfield: Bitfield,
|
||||
pub slot_included: Slot,
|
||||
pub inclusion_slot: Slot,
|
||||
}
|
||||
|
||||
impl Encodable for PendingAttestation {
|
||||
fn ssz_append(&self, s: &mut SszStream) {
|
||||
s.append(&self.data);
|
||||
s.append(&self.aggregation_bitfield);
|
||||
s.append(&self.data);
|
||||
s.append(&self.custody_bitfield);
|
||||
s.append(&self.slot_included);
|
||||
s.append(&self.inclusion_slot);
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for PendingAttestation {
|
||||
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
||||
let (data, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (aggregation_bitfield, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (data, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (custody_bitfield, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (slot_included, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (inclusion_slot, i) = <_>::ssz_decode(bytes, i)?;
|
||||
|
||||
Ok((
|
||||
Self {
|
||||
data,
|
||||
aggregation_bitfield,
|
||||
custody_bitfield,
|
||||
slot_included,
|
||||
inclusion_slot,
|
||||
},
|
||||
i,
|
||||
))
|
||||
@ -43,10 +43,10 @@ impl Decodable for PendingAttestation {
|
||||
impl TreeHash for PendingAttestation {
|
||||
fn hash_tree_root(&self) -> Vec<u8> {
|
||||
let mut result: Vec<u8> = vec![];
|
||||
result.append(&mut self.data.hash_tree_root());
|
||||
result.append(&mut self.aggregation_bitfield.hash_tree_root());
|
||||
result.append(&mut self.data.hash_tree_root());
|
||||
result.append(&mut self.custody_bitfield.hash_tree_root());
|
||||
result.append(&mut self.custody_bitfield.hash_tree_root());
|
||||
result.append(&mut self.inclusion_slot.hash_tree_root());
|
||||
hash(&result)
|
||||
}
|
||||
}
|
||||
@ -57,7 +57,7 @@ impl<T: RngCore> TestRandom<T> for PendingAttestation {
|
||||
data: <_>::random_for_test(rng),
|
||||
aggregation_bitfield: <_>::random_for_test(rng),
|
||||
custody_bitfield: <_>::random_for_test(rng),
|
||||
slot_included: <_>::random_for_test(rng),
|
||||
inclusion_slot: <_>::random_for_test(rng),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize)]
|
||||
pub struct ProposerSlashing {
|
||||
pub proposer_index: u32,
|
||||
pub proposer_index: u64,
|
||||
pub proposal_data_1: ProposalSignedData,
|
||||
pub proposal_signature_1: Signature,
|
||||
pub proposal_data_2: ProposalSignedData,
|
||||
|
@ -1,74 +0,0 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use rand::RngCore;
|
||||
use serde_derive::Serialize;
|
||||
use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize)]
|
||||
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 TreeHash for ShardCommittee {
|
||||
fn hash_tree_root(&self) -> Vec<u8> {
|
||||
let mut result: Vec<u8> = vec![];
|
||||
result.append(&mut self.shard.hash_tree_root());
|
||||
result.append(&mut self.committee.hash_tree_root());
|
||||
hash(&result)
|
||||
}
|
||||
}
|
||||
|
||||
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::*;
|
||||
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
|
||||
use ssz::ssz_encode;
|
||||
|
||||
#[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);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_hash_tree_root() {
|
||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
||||
let original = ShardCommittee::random_for_test(&mut rng);
|
||||
|
||||
let result = original.hash_tree_root();
|
||||
|
||||
assert_eq!(result.len(), 32);
|
||||
// TODO: Add further tests
|
||||
// https://github.com/sigp/lighthouse/issues/170
|
||||
}
|
||||
}
|
92
eth2/types/src/slashable_attestation.rs
Normal file
92
eth2/types/src/slashable_attestation.rs
Normal file
@ -0,0 +1,92 @@
|
||||
use crate::{test_utils::TestRandom, AggregateSignature, AttestationData, Bitfield};
|
||||
use rand::RngCore;
|
||||
use serde_derive::Serialize;
|
||||
use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize)]
|
||||
pub struct SlashableAttestation {
|
||||
pub validator_indices: Vec<u64>,
|
||||
pub data: AttestationData,
|
||||
pub custody_bitfield: Bitfield,
|
||||
pub aggregate_signature: AggregateSignature,
|
||||
}
|
||||
|
||||
impl Encodable for SlashableAttestation {
|
||||
fn ssz_append(&self, s: &mut SszStream) {
|
||||
s.append_vec(&self.validator_indices);
|
||||
s.append(&self.data);
|
||||
s.append(&self.custody_bitfield);
|
||||
s.append(&self.aggregate_signature);
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for SlashableAttestation {
|
||||
fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
|
||||
let (validator_indices, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (data, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (custody_bitfield, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (aggregate_signature, i) = <_>::ssz_decode(bytes, i)?;
|
||||
|
||||
Ok((
|
||||
SlashableAttestation {
|
||||
validator_indices,
|
||||
data,
|
||||
custody_bitfield,
|
||||
aggregate_signature,
|
||||
},
|
||||
i,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl TreeHash for SlashableAttestation {
|
||||
fn hash_tree_root(&self) -> Vec<u8> {
|
||||
let mut result: Vec<u8> = vec![];
|
||||
result.append(&mut self.validator_indices.hash_tree_root());
|
||||
result.append(&mut self.data.hash_tree_root());
|
||||
result.append(&mut self.custody_bitfield.hash_tree_root());
|
||||
result.append(&mut self.aggregate_signature.hash_tree_root());
|
||||
hash(&result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RngCore> TestRandom<T> for SlashableAttestation {
|
||||
fn random_for_test(rng: &mut T) -> Self {
|
||||
Self {
|
||||
validator_indices: <_>::random_for_test(rng),
|
||||
data: <_>::random_for_test(rng),
|
||||
custody_bitfield: <_>::random_for_test(rng),
|
||||
aggregate_signature: <_>::random_for_test(rng),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
|
||||
use ssz::ssz_encode;
|
||||
|
||||
#[test]
|
||||
pub fn test_ssz_round_trip() {
|
||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
||||
let original = SlashableAttestation::random_for_test(&mut rng);
|
||||
|
||||
let bytes = ssz_encode(&original);
|
||||
let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();
|
||||
|
||||
assert_eq!(original, decoded);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_hash_tree_root() {
|
||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
||||
let original = SlashableAttestation::random_for_test(&mut rng);
|
||||
|
||||
let result = original.hash_tree_root();
|
||||
|
||||
assert_eq!(result.len(), 32);
|
||||
// TODO: Add further tests
|
||||
// https://github.com/sigp/lighthouse/issues/170
|
||||
}
|
||||
}
|
@ -163,6 +163,10 @@ macro_rules! impl_math {
|
||||
*self - other.into()
|
||||
}
|
||||
|
||||
pub fn saturating_add<T: Into<$type>>(&self, other: T) -> $type {
|
||||
*self + other.into()
|
||||
}
|
||||
|
||||
pub fn checked_div<T: Into<$type>>(&self, rhs: T) -> Option<$type> {
|
||||
let rhs: $type = rhs.into();
|
||||
if rhs == 0 {
|
||||
@ -279,6 +283,10 @@ impl Epoch {
|
||||
Epoch(slot)
|
||||
}
|
||||
|
||||
pub fn max_value() -> Epoch {
|
||||
Epoch(u64::max_value())
|
||||
}
|
||||
|
||||
pub fn start_slot(&self, epoch_length: u64) -> Slot {
|
||||
Slot::from(self.0.saturating_mul(epoch_length))
|
||||
}
|
||||
@ -527,6 +535,22 @@ mod tests {
|
||||
assert_saturating_sub(1, 2, 0);
|
||||
}
|
||||
|
||||
fn saturating_add() {
|
||||
let assert_saturating_add = |a: u64, b: u64, result: u64| {
|
||||
assert_eq!($type(a).saturating_add($type(b)), $type(result));
|
||||
};
|
||||
|
||||
assert_saturating_add(0, 1, 1);
|
||||
assert_saturating_add(1, 0, 1);
|
||||
assert_saturating_add(1, 2, 3);
|
||||
assert_saturating_add(2, 1, 3);
|
||||
assert_saturating_add(7, 7, 14);
|
||||
|
||||
// Addition should be saturating.
|
||||
assert_saturating_add(u64::max_value(), 1, u64::max_value());
|
||||
assert_saturating_add(u64::max_value(), u64::max_value(), u64::max_value());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checked_div() {
|
||||
let assert_checked_div = |a: u64, b: u64, result: Option<u64>| {
|
||||
|
@ -1,10 +1,6 @@
|
||||
use super::ChainSpec;
|
||||
use bls::{Keypair, PublicKey, SecretKey, Signature};
|
||||
use crate::{Address, ChainSpec, Epoch, Hash256, Signature, Slot};
|
||||
|
||||
use crate::{Address, Eth1Data, Hash256, Slot, Validator};
|
||||
|
||||
/// The size of a validators deposit in GWei.
|
||||
pub const DEPOSIT_GWEI: u64 = 32_000_000_000;
|
||||
const GWEI: u64 = 1_000_000_000;
|
||||
|
||||
impl ChainSpec {
|
||||
/// Returns a `ChainSpec` compatible with the specification from Ethereum Foundation.
|
||||
@ -12,123 +8,96 @@ impl ChainSpec {
|
||||
/// Of course, the actual foundation specs are unknown at this point so these are just a rough
|
||||
/// estimate.
|
||||
pub fn foundation() -> Self {
|
||||
let genesis_slot = Slot::new(2_u64.pow(19));
|
||||
let epoch_length = 64;
|
||||
let genesis_epoch = genesis_slot.epoch(epoch_length);
|
||||
|
||||
Self {
|
||||
/*
|
||||
* Misc
|
||||
*/
|
||||
shard_count: 1_024,
|
||||
target_committee_size: 128,
|
||||
ejection_balance: 16 * u64::pow(10, 9),
|
||||
max_balance_churn_quotient: 32,
|
||||
beacon_chain_shard_number: u64::max_value(),
|
||||
max_casper_votes: 1_024,
|
||||
latest_block_roots_length: 8_192,
|
||||
latest_randao_mixes_length: 8_192,
|
||||
latest_penalized_exit_length: 8_192,
|
||||
max_indices_per_slashable_vote: 4_096,
|
||||
max_withdrawals_per_epoch: 4,
|
||||
shuffle_round_count: 90,
|
||||
|
||||
/*
|
||||
* Deposit contract
|
||||
*/
|
||||
deposit_contract_address: Address::from("TBD".as_bytes()),
|
||||
deposit_contract_address: Address::zero(),
|
||||
deposit_contract_tree_depth: 32,
|
||||
min_deposit: 1 * u64::pow(10, 9),
|
||||
max_deposit: 32 * u64::pow(10, 9),
|
||||
|
||||
/*
|
||||
* Gwei values
|
||||
*/
|
||||
min_deposit_amount: u64::pow(2, 0) * GWEI,
|
||||
max_deposit_amount: u64::pow(2, 5) * GWEI,
|
||||
fork_choice_balance_increment: u64::pow(2, 0) * GWEI,
|
||||
ejection_balance: u64::pow(2, 4) * GWEI,
|
||||
|
||||
/*
|
||||
* Initial Values
|
||||
*/
|
||||
genesis_fork_version: 0,
|
||||
genesis_slot: Slot::from(0_u64),
|
||||
genesis_slot: Slot::new(2_u64.pow(19)),
|
||||
genesis_epoch,
|
||||
genesis_start_shard: 0,
|
||||
far_future_slot: Slot::from(u64::max_value()),
|
||||
far_future_epoch: Epoch::new(u64::max_value()),
|
||||
zero_hash: Hash256::zero(),
|
||||
empty_signature: Signature::empty_signature(),
|
||||
bls_withdrawal_prefix_byte: 0x00,
|
||||
bls_withdrawal_prefix_byte: 0,
|
||||
|
||||
/*
|
||||
* Time parameters
|
||||
*/
|
||||
slot_duration: 6,
|
||||
min_attestation_inclusion_delay: 4,
|
||||
epoch_length: 64,
|
||||
seed_lookahead: 64,
|
||||
entry_exit_delay: 256,
|
||||
eth1_data_voting_period: 1_024,
|
||||
min_validator_withdrawal_time: u64::pow(2, 14),
|
||||
min_attestation_inclusion_delay: Slot::new(4),
|
||||
epoch_length,
|
||||
seed_lookahead: Epoch::new(1),
|
||||
entry_exit_delay: Epoch::new(4),
|
||||
eth1_data_voting_period: 16,
|
||||
min_validator_withdrawal_epochs: Epoch::new(256),
|
||||
|
||||
/*
|
||||
* State list lengths
|
||||
*/
|
||||
latest_block_roots_length: 8_192,
|
||||
latest_randao_mixes_length: 8_192,
|
||||
latest_index_roots_length: 8_192,
|
||||
latest_penalized_exit_length: 8_192,
|
||||
|
||||
/*
|
||||
* Reward and penalty quotients
|
||||
*/
|
||||
base_reward_quotient: 32,
|
||||
whistleblower_reward_quotient: 512,
|
||||
includer_reward_quotient: 8,
|
||||
inactivity_penalty_quotient: u64::pow(2, 24),
|
||||
inactivity_penalty_quotient: 16_777_216,
|
||||
|
||||
/*
|
||||
* Max operations per block
|
||||
*/
|
||||
max_proposer_slashings: 16,
|
||||
max_casper_slashings: 16,
|
||||
max_attester_slashings: 1,
|
||||
max_attestations: 128,
|
||||
max_deposits: 16,
|
||||
max_exits: 16,
|
||||
|
||||
/*
|
||||
* Intialization parameters
|
||||
* Signature domains
|
||||
*/
|
||||
initial_validators: initial_validators_for_testing(),
|
||||
initial_balances: initial_balances_for_testing(),
|
||||
genesis_time: 1_544_672_897,
|
||||
intial_eth1_data: Eth1Data {
|
||||
deposit_root: Hash256::from("deposit_root".as_bytes()),
|
||||
block_hash: Hash256::from("block_hash".as_bytes()),
|
||||
},
|
||||
domain_deposit: 0,
|
||||
domain_attestation: 1,
|
||||
domain_proposal: 2,
|
||||
domain_exit: 3,
|
||||
domain_randao: 4,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a set of validator records to use with testing until the real chain starts.
|
||||
fn initial_validators_for_testing() -> Vec<Validator> {
|
||||
// Some dummy private keys to start with.
|
||||
let key_strings = vec![
|
||||
"jzjxxgjajfjrmgodszzsgqccmhnyvetcuxobhtynojtpdtbj",
|
||||
"gpeehcjudxdijzhjgirfuhahmnjutlchjmoffxmimbdejakd",
|
||||
"ntrrdwwebodokuwaclhoqreqyodngoyhurvesghjfxeswoaj",
|
||||
"cibmzkqrzdgdlrvqaxinwpvyhcgjkeysrsjkqtkcxvznsvth",
|
||||
"erqrfuahdwprsstkawggounxmihzhrvbhchcyiwtaypqcedr",
|
||||
];
|
||||
|
||||
let mut initial_validators = Vec::with_capacity(key_strings.len());
|
||||
for key_string in key_strings {
|
||||
let keypair = {
|
||||
let secret_key = match SecretKey::from_bytes(&key_string.as_bytes()) {
|
||||
Ok(key) => key,
|
||||
Err(_) => unreachable!(), // Keys are static and should not fail.
|
||||
};
|
||||
let public_key = PublicKey::from_secret_key(&secret_key);
|
||||
Keypair {
|
||||
sk: secret_key,
|
||||
pk: public_key,
|
||||
}
|
||||
};
|
||||
let validator = Validator {
|
||||
pubkey: keypair.pk.clone(),
|
||||
withdrawal_credentials: Hash256::zero(),
|
||||
proposer_slots: 0,
|
||||
activation_slot: Slot::max_value(),
|
||||
exit_slot: Slot::max_value(),
|
||||
withdrawal_slot: Slot::max_value(),
|
||||
penalized_slot: Slot::max_value(),
|
||||
exit_count: 0,
|
||||
status_flags: None,
|
||||
latest_custody_reseed_slot: Slot::from(0_u64),
|
||||
penultimate_custody_reseed_slot: Slot::from(0_u64),
|
||||
};
|
||||
initial_validators.push(validator);
|
||||
}
|
||||
|
||||
initial_validators
|
||||
}
|
||||
|
||||
fn initial_balances_for_testing() -> Vec<u64> {
|
||||
vec![DEPOSIT_GWEI; 4]
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -1,6 +1,6 @@
|
||||
mod foundation;
|
||||
|
||||
use crate::{Address, Eth1Data, Hash256, Slot, Validator};
|
||||
use crate::{Address, Epoch, Hash256, Slot};
|
||||
use bls::Signature;
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
@ -10,41 +10,57 @@ pub struct ChainSpec {
|
||||
*/
|
||||
pub shard_count: u64,
|
||||
pub target_committee_size: u64,
|
||||
pub ejection_balance: u64,
|
||||
pub max_balance_churn_quotient: u64,
|
||||
pub beacon_chain_shard_number: u64,
|
||||
pub max_casper_votes: u64,
|
||||
pub latest_block_roots_length: u64,
|
||||
pub latest_randao_mixes_length: u64,
|
||||
pub latest_penalized_exit_length: u64,
|
||||
pub max_indices_per_slashable_vote: u64,
|
||||
pub max_withdrawals_per_epoch: u64,
|
||||
pub shuffle_round_count: u64,
|
||||
|
||||
/*
|
||||
* Deposit contract
|
||||
*/
|
||||
pub deposit_contract_address: Address,
|
||||
pub deposit_contract_tree_depth: u64,
|
||||
pub min_deposit: u64,
|
||||
pub max_deposit: u64,
|
||||
|
||||
/*
|
||||
* Gwei values
|
||||
*/
|
||||
pub min_deposit_amount: u64,
|
||||
pub max_deposit_amount: u64,
|
||||
pub fork_choice_balance_increment: u64,
|
||||
pub ejection_balance: u64,
|
||||
|
||||
/*
|
||||
* Initial Values
|
||||
*/
|
||||
pub genesis_fork_version: u64,
|
||||
pub genesis_slot: Slot,
|
||||
pub genesis_epoch: Epoch,
|
||||
pub genesis_start_shard: u64,
|
||||
pub far_future_slot: Slot,
|
||||
pub far_future_epoch: Epoch,
|
||||
pub zero_hash: Hash256,
|
||||
pub empty_signature: Signature,
|
||||
pub bls_withdrawal_prefix_byte: u8,
|
||||
|
||||
/*
|
||||
* Time parameters
|
||||
*/
|
||||
pub slot_duration: u64,
|
||||
pub min_attestation_inclusion_delay: u64,
|
||||
pub min_attestation_inclusion_delay: Slot,
|
||||
pub epoch_length: u64,
|
||||
pub seed_lookahead: u64,
|
||||
pub entry_exit_delay: u64,
|
||||
pub seed_lookahead: Epoch,
|
||||
pub entry_exit_delay: Epoch,
|
||||
pub eth1_data_voting_period: u64,
|
||||
pub min_validator_withdrawal_time: u64,
|
||||
pub min_validator_withdrawal_epochs: Epoch,
|
||||
|
||||
/*
|
||||
* State list lengths
|
||||
*/
|
||||
pub latest_block_roots_length: usize,
|
||||
pub latest_randao_mixes_length: usize,
|
||||
pub latest_index_roots_length: usize,
|
||||
pub latest_penalized_exit_length: usize,
|
||||
|
||||
/*
|
||||
* Reward and penalty quotients
|
||||
*/
|
||||
@ -52,19 +68,22 @@ pub struct ChainSpec {
|
||||
pub whistleblower_reward_quotient: u64,
|
||||
pub includer_reward_quotient: u64,
|
||||
pub inactivity_penalty_quotient: u64,
|
||||
|
||||
/*
|
||||
* Max operations per block
|
||||
*/
|
||||
pub max_proposer_slashings: u64,
|
||||
pub max_casper_slashings: u64,
|
||||
pub max_attester_slashings: u64,
|
||||
pub max_attestations: u64,
|
||||
pub max_deposits: u64,
|
||||
pub max_exits: u64,
|
||||
|
||||
/*
|
||||
* Intialization parameters
|
||||
* Signature domains
|
||||
*/
|
||||
pub initial_validators: Vec<Validator>,
|
||||
pub initial_balances: Vec<u64>,
|
||||
pub genesis_time: u64,
|
||||
pub intial_eth1_data: Eth1Data,
|
||||
pub domain_deposit: u64,
|
||||
pub domain_attestation: u64,
|
||||
pub domain_proposal: u64,
|
||||
pub domain_exit: u64,
|
||||
pub domain_randao: u64,
|
||||
}
|
||||
|
@ -1,142 +0,0 @@
|
||||
use serde_derive::Serialize;
|
||||
use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};
|
||||
|
||||
/// 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, Serialize)]
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
impl TreeHash for SpecialRecord {
|
||||
fn hash_tree_root(&self) -> Vec<u8> {
|
||||
let mut result: Vec<u8> = vec![];
|
||||
result.append(&mut self.kind.hash_tree_root());
|
||||
result.append(&mut self.data.as_slice().hash_tree_root());
|
||||
hash(&result)
|
||||
}
|
||||
}
|
||||
|
||||
#[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);
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
use crate::{test_utils::TestRandom, Hash256, PublicKey, Slot};
|
||||
use crate::{test_utils::TestRandom, Epoch, Hash256, PublicKey};
|
||||
use rand::RngCore;
|
||||
use serde_derive::Serialize;
|
||||
use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};
|
||||
@ -46,21 +46,17 @@ fn status_flag_from_byte(flag: u8) -> Result<Option<StatusFlags>, StatusFlagsDec
|
||||
pub struct Validator {
|
||||
pub pubkey: PublicKey,
|
||||
pub withdrawal_credentials: Hash256,
|
||||
pub proposer_slots: u64,
|
||||
pub activation_slot: Slot,
|
||||
pub exit_slot: Slot,
|
||||
pub withdrawal_slot: Slot,
|
||||
pub penalized_slot: Slot,
|
||||
pub exit_count: u64,
|
||||
pub activation_epoch: Epoch,
|
||||
pub exit_epoch: Epoch,
|
||||
pub withdrawal_epoch: Epoch,
|
||||
pub penalized_epoch: Epoch,
|
||||
pub status_flags: Option<StatusFlags>,
|
||||
pub latest_custody_reseed_slot: Slot,
|
||||
pub penultimate_custody_reseed_slot: Slot,
|
||||
}
|
||||
|
||||
impl Validator {
|
||||
/// This predicate indicates if the validator represented by this record is considered "active" at `slot`.
|
||||
pub fn is_active_at(&self, slot: Slot) -> bool {
|
||||
self.activation_slot <= slot && slot < self.exit_slot
|
||||
pub fn is_active_at(&self, slot: Epoch) -> bool {
|
||||
self.activation_epoch <= slot && slot < self.exit_epoch
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,15 +66,11 @@ impl Default for Validator {
|
||||
Self {
|
||||
pubkey: PublicKey::default(),
|
||||
withdrawal_credentials: Hash256::default(),
|
||||
proposer_slots: 0,
|
||||
activation_slot: Slot::from(std::u64::MAX),
|
||||
exit_slot: Slot::from(std::u64::MAX),
|
||||
withdrawal_slot: Slot::from(std::u64::MAX),
|
||||
penalized_slot: Slot::from(std::u64::MAX),
|
||||
exit_count: 0,
|
||||
activation_epoch: Epoch::from(std::u64::MAX),
|
||||
exit_epoch: Epoch::from(std::u64::MAX),
|
||||
withdrawal_epoch: Epoch::from(std::u64::MAX),
|
||||
penalized_epoch: Epoch::from(std::u64::MAX),
|
||||
status_flags: None,
|
||||
latest_custody_reseed_slot: Slot::from(0_u64), // NOTE: is `GENESIS_SLOT`
|
||||
penultimate_custody_reseed_slot: Slot::from(0_u64), // NOTE: is `GENESIS_SLOT`
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,15 +86,11 @@ impl Encodable for Validator {
|
||||
fn ssz_append(&self, s: &mut SszStream) {
|
||||
s.append(&self.pubkey);
|
||||
s.append(&self.withdrawal_credentials);
|
||||
s.append(&self.proposer_slots);
|
||||
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(&self.activation_epoch);
|
||||
s.append(&self.exit_epoch);
|
||||
s.append(&self.withdrawal_epoch);
|
||||
s.append(&self.penalized_epoch);
|
||||
s.append(&status_flag_to_byte(self.status_flags));
|
||||
s.append(&self.latest_custody_reseed_slot);
|
||||
s.append(&self.penultimate_custody_reseed_slot);
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,15 +98,11 @@ impl Decodable for Validator {
|
||||
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 (proposer_slots, 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 (activation_epoch, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (exit_epoch, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (withdrawal_epoch, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (penalized_epoch, i) = <_>::ssz_decode(bytes, i)?;
|
||||
let (status_flags_byte, i): (u8, usize) = <_>::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)?;
|
||||
|
||||
@ -126,15 +110,11 @@ impl Decodable for Validator {
|
||||
Self {
|
||||
pubkey,
|
||||
withdrawal_credentials,
|
||||
proposer_slots,
|
||||
activation_slot,
|
||||
exit_slot,
|
||||
withdrawal_slot,
|
||||
penalized_slot,
|
||||
exit_count,
|
||||
activation_epoch,
|
||||
exit_epoch,
|
||||
withdrawal_epoch,
|
||||
penalized_epoch,
|
||||
status_flags,
|
||||
latest_custody_reseed_slot,
|
||||
penultimate_custody_reseed_slot,
|
||||
},
|
||||
i,
|
||||
))
|
||||
@ -146,15 +126,11 @@ impl TreeHash for Validator {
|
||||
let mut result: Vec<u8> = vec![];
|
||||
result.append(&mut self.pubkey.hash_tree_root());
|
||||
result.append(&mut self.withdrawal_credentials.hash_tree_root());
|
||||
result.append(&mut self.proposer_slots.hash_tree_root());
|
||||
result.append(&mut self.activation_slot.hash_tree_root());
|
||||
result.append(&mut self.exit_slot.hash_tree_root());
|
||||
result.append(&mut self.withdrawal_slot.hash_tree_root());
|
||||
result.append(&mut self.penalized_slot.hash_tree_root());
|
||||
result.append(&mut self.exit_count.hash_tree_root());
|
||||
result.append(&mut self.activation_epoch.hash_tree_root());
|
||||
result.append(&mut self.exit_epoch.hash_tree_root());
|
||||
result.append(&mut self.withdrawal_epoch.hash_tree_root());
|
||||
result.append(&mut self.penalized_epoch.hash_tree_root());
|
||||
result.append(&mut (status_flag_to_byte(self.status_flags) as u64).hash_tree_root());
|
||||
result.append(&mut self.latest_custody_reseed_slot.hash_tree_root());
|
||||
result.append(&mut self.penultimate_custody_reseed_slot.hash_tree_root());
|
||||
hash(&result)
|
||||
}
|
||||
}
|
||||
@ -164,15 +140,11 @@ impl<T: RngCore> TestRandom<T> for Validator {
|
||||
Self {
|
||||
pubkey: <_>::random_for_test(rng),
|
||||
withdrawal_credentials: <_>::random_for_test(rng),
|
||||
proposer_slots: <_>::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),
|
||||
activation_epoch: <_>::random_for_test(rng),
|
||||
exit_epoch: <_>::random_for_test(rng),
|
||||
withdrawal_epoch: <_>::random_for_test(rng),
|
||||
penalized_epoch: <_>::random_for_test(rng),
|
||||
status_flags: Some(<_>::random_for_test(rng)),
|
||||
latest_custody_reseed_slot: <_>::random_for_test(rng),
|
||||
penultimate_custody_reseed_slot: <_>::random_for_test(rng),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -199,17 +171,17 @@ mod tests {
|
||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
||||
let mut validator = Validator::random_for_test(&mut rng);
|
||||
|
||||
let activation_slot = u64::random_for_test(&mut rng);
|
||||
let exit_slot = activation_slot + 234;
|
||||
let activation_epoch = u64::random_for_test(&mut rng);
|
||||
let exit_epoch = activation_epoch + 234;
|
||||
|
||||
validator.activation_slot = Slot::from(activation_slot);
|
||||
validator.exit_slot = Slot::from(exit_slot);
|
||||
validator.activation_epoch = Epoch::from(activation_epoch);
|
||||
validator.exit_epoch = Epoch::from(exit_epoch);
|
||||
|
||||
for slot in (activation_slot - 100)..(exit_slot + 100) {
|
||||
let slot = Slot::from(slot);
|
||||
if slot < activation_slot {
|
||||
for slot in (activation_epoch - 100)..(exit_epoch + 100) {
|
||||
let slot = Epoch::from(slot);
|
||||
if slot < activation_epoch {
|
||||
assert!(!validator.is_active_at(slot));
|
||||
} else if slot >= exit_slot {
|
||||
} else if slot >= exit_epoch {
|
||||
assert!(!validator.is_active_at(slot));
|
||||
} else {
|
||||
assert!(validator.is_active_at(slot));
|
||||
|
@ -1,15 +1,15 @@
|
||||
/// Contains logic to manipulate a `&[Validator]`.
|
||||
/// For now, we avoid defining a newtype and just have flat functions here.
|
||||
use super::validator::*;
|
||||
use crate::Slot;
|
||||
use crate::Epoch;
|
||||
|
||||
/// Given an indexed sequence of `validators`, return the indices corresponding to validators that are active at `slot`.
|
||||
pub fn get_active_validator_indices(validators: &[Validator], slot: Slot) -> Vec<usize> {
|
||||
/// Given an indexed sequence of `validators`, return the indices corresponding to validators that are active at `epoch`.
|
||||
pub fn get_active_validator_indices(validators: &[Validator], epoch: Epoch) -> Vec<usize> {
|
||||
validators
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(index, validator)| {
|
||||
if validator.is_active_at(slot) {
|
||||
if validator.is_active_at(epoch) {
|
||||
Some(index)
|
||||
} else {
|
||||
None
|
||||
@ -28,8 +28,8 @@ mod tests {
|
||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
||||
|
||||
let validators = vec![];
|
||||
let some_slot = Slot::random_for_test(&mut rng);
|
||||
let indices = get_active_validator_indices(&validators, some_slot);
|
||||
let some_epoch = Epoch::random_for_test(&mut rng);
|
||||
let indices = get_active_validator_indices(&validators, some_epoch);
|
||||
assert_eq!(indices, vec![]);
|
||||
}
|
||||
|
||||
@ -42,8 +42,8 @@ mod tests {
|
||||
validators.push(Validator::default())
|
||||
}
|
||||
|
||||
let some_slot = Slot::random_for_test(&mut rng);
|
||||
let indices = get_active_validator_indices(&validators, some_slot);
|
||||
let some_epoch = Epoch::random_for_test(&mut rng);
|
||||
let indices = get_active_validator_indices(&validators, some_epoch);
|
||||
assert_eq!(indices, vec![]);
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ mod tests {
|
||||
fn can_get_all_active_validator_indices() {
|
||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
||||
let count_validators = 10;
|
||||
let some_slot = Slot::random_for_test(&mut rng);
|
||||
let some_epoch = Epoch::random_for_test(&mut rng);
|
||||
|
||||
let mut validators = (0..count_validators)
|
||||
.into_iter()
|
||||
@ -61,8 +61,8 @@ mod tests {
|
||||
let activation_offset = u64::random_for_test(&mut rng);
|
||||
let exit_offset = u64::random_for_test(&mut rng);
|
||||
|
||||
validator.activation_slot = some_slot - activation_offset;
|
||||
validator.exit_slot = some_slot + exit_offset;
|
||||
validator.activation_epoch = some_epoch - activation_offset;
|
||||
validator.exit_epoch = some_epoch + exit_offset;
|
||||
|
||||
validator
|
||||
})
|
||||
@ -70,10 +70,10 @@ mod tests {
|
||||
|
||||
// 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;
|
||||
validator.activation_epoch = some_epoch;
|
||||
}
|
||||
|
||||
let indices = get_active_validator_indices(&validators, some_slot);
|
||||
let indices = get_active_validator_indices(&validators, some_epoch);
|
||||
assert_eq!(
|
||||
indices,
|
||||
(0..count_validators).into_iter().collect::<Vec<_>>()
|
||||
@ -82,31 +82,35 @@ mod tests {
|
||||
|
||||
fn set_validators_to_default_entry_exit(validators: &mut [Validator]) {
|
||||
for validator in validators.iter_mut() {
|
||||
validator.activation_slot = Slot::max_value();
|
||||
validator.exit_slot = Slot::max_value();
|
||||
validator.activation_epoch = Epoch::max_value();
|
||||
validator.exit_epoch = Epoch::max_value();
|
||||
}
|
||||
}
|
||||
|
||||
// sets all `validators` to be active as of some slot prior to `slot`. returns the activation slot.
|
||||
fn set_validators_to_activated(validators: &mut [Validator], slot: Slot) -> Slot {
|
||||
let activation_slot = slot - 10;
|
||||
// sets all `validators` to be active as of some epoch prior to `epoch`. returns the activation epoch.
|
||||
fn set_validators_to_activated(validators: &mut [Validator], epoch: Epoch) -> Epoch {
|
||||
let activation_epoch = epoch - 10;
|
||||
for validator in validators.iter_mut() {
|
||||
validator.activation_slot = activation_slot;
|
||||
validator.activation_epoch = activation_epoch;
|
||||
}
|
||||
activation_slot
|
||||
activation_epoch
|
||||
}
|
||||
|
||||
// sets all `validators` to be exited as of some slot before `slot`.
|
||||
fn set_validators_to_exited(validators: &mut [Validator], slot: Slot, activation_slot: Slot) {
|
||||
assert!(activation_slot < slot);
|
||||
let mut exit_slot = activation_slot + 10;
|
||||
while exit_slot >= slot {
|
||||
exit_slot -= 1;
|
||||
// sets all `validators` to be exited as of some epoch before `epoch`.
|
||||
fn set_validators_to_exited(
|
||||
validators: &mut [Validator],
|
||||
epoch: Epoch,
|
||||
activation_epoch: Epoch,
|
||||
) {
|
||||
assert!(activation_epoch < epoch);
|
||||
let mut exit_epoch = activation_epoch + 10;
|
||||
while exit_epoch >= epoch {
|
||||
exit_epoch -= 1;
|
||||
}
|
||||
assert!(activation_slot < exit_slot && exit_slot < slot);
|
||||
assert!(activation_epoch < exit_epoch && exit_epoch < epoch);
|
||||
|
||||
for validator in validators.iter_mut() {
|
||||
validator.exit_slot = exit_slot;
|
||||
validator.exit_epoch = exit_epoch;
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,18 +119,18 @@ mod tests {
|
||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
||||
const COUNT_PARTITIONS: usize = 3;
|
||||
const COUNT_VALIDATORS: usize = 3 * COUNT_PARTITIONS;
|
||||
let some_slot: Slot = Slot::random_for_test(&mut rng);
|
||||
let some_epoch: Epoch = Epoch::random_for_test(&mut rng);
|
||||
|
||||
let mut validators = (0..COUNT_VALIDATORS)
|
||||
.into_iter()
|
||||
.map(|_| {
|
||||
let mut validator = Validator::default();
|
||||
|
||||
let activation_offset = Slot::random_for_test(&mut rng);
|
||||
let exit_offset = Slot::random_for_test(&mut rng);
|
||||
let activation_offset = Epoch::random_for_test(&mut rng);
|
||||
let exit_offset = Epoch::random_for_test(&mut rng);
|
||||
|
||||
validator.activation_slot = some_slot - activation_offset;
|
||||
validator.exit_slot = some_slot + exit_offset;
|
||||
validator.activation_epoch = some_epoch - activation_offset;
|
||||
validator.exit_epoch = some_epoch + exit_offset;
|
||||
|
||||
validator
|
||||
})
|
||||
@ -141,19 +145,19 @@ mod tests {
|
||||
}
|
||||
1 => {
|
||||
// 2. activated, but not exited
|
||||
set_validators_to_activated(chunk, some_slot);
|
||||
set_validators_to_activated(chunk, some_epoch);
|
||||
// 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;
|
||||
validator.activation_epoch = some_epoch;
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
// 3. exited
|
||||
let activation_slot = set_validators_to_activated(chunk, some_slot);
|
||||
set_validators_to_exited(chunk, some_slot, activation_slot);
|
||||
let activation_epoch = set_validators_to_activated(chunk, some_epoch);
|
||||
set_validators_to_exited(chunk, some_epoch, activation_epoch);
|
||||
// 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;
|
||||
validator.exit_epoch = some_epoch;
|
||||
}
|
||||
}
|
||||
_ => unreachable!(
|
||||
@ -162,7 +166,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
let indices = get_active_validator_indices(&validators, some_slot);
|
||||
let indices = get_active_validator_indices(&validators, some_epoch);
|
||||
assert_eq!(indices, vec![3, 4, 5]);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user