Update to Spec v0.10 (#817)

* Start updating types

* WIP

* Signature hacking

* Existing EF tests passing with fake_crypto

* Updates

* Delete outdated API spec

* The refactor continues

* It compiles

* WIP test fixes

* All release tests passing bar genesis state parsing

* Update and test YamlConfig

* Update to spec v0.10 compatible BLS

* Updates to BLS EF tests

* Add EF test for AggregateVerify

And delete unused hash2curve tests for uncompressed points

* Update EF tests to v0.10.1

* Use optional block root correctly in block proc

* Use genesis fork in deposit domain. All tests pass

* Cargo fmt

* Fast aggregate verify test

* Update REST API docs

* Cargo fmt

* Fix unused import

* Bump spec tags to v0.10.1

* Add `seconds_per_eth1_block` to chainspec

* Update to timestamp based eth1 voting scheme

* Return None from `get_votes_to_consider` if block cache is empty

* Handle overflows in `is_candidate_block`

* Revert to failing tests

* Fix eth1 data sets test

* Choose default vote according to spec

* Fix collect_valid_votes tests

* Fix `get_votes_to_consider` to choose all eligible blocks

* Uncomment winning_vote tests

* Add comments; remove unused code

* Reduce seconds_per_eth1_block for simulation

* Addressed review comments

* Add test for default vote case

* Fix logs

* Remove unused functions

* Meter default eth1 votes

* Fix comments

* Address review comments; remove unused dependency

* Disable/delete two outdated tests

* Bump eth1 default vote warn to error

* Delete outdated eth1 test

Co-authored-by: Pawan Dhananjay <pawandhananjay@gmail.com>
This commit is contained in:
Michael Sproul
2020-02-11 10:19:36 +11:00
committed by GitHub
parent 03e77390a3
commit 371e5adcf8
145 changed files with 1666 additions and 4437 deletions

View File

@@ -1,14 +1,13 @@
use super::{
AggregateSignature, AttestationData, BitList, ChainSpec, Domain, EthSpec, Fork, SecretKey,
Signature,
Signature, SignedRoot,
};
use crate::test_utils::TestRandom;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash_derive::TreeHash;
#[derive(Debug, PartialEq)]
pub enum Error {
@@ -18,24 +17,12 @@ pub enum Error {
/// Details an attestation that can be slashable.
///
/// Spec v0.9.1
#[derive(
Debug,
Clone,
PartialEq,
Serialize,
Deserialize,
Encode,
Decode,
TreeHash,
TestRandom,
SignedRoot,
)]
/// Spec v0.10.1
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[serde(bound = "T: EthSpec")]
pub struct Attestation<T: EthSpec> {
pub aggregation_bits: BitList<T::MaxValidatorsPerCommittee>,
pub data: AttestationData,
#[signed_root(skip_hashing)]
pub signature: AggregateSignature,
}
@@ -79,11 +66,11 @@ impl<T: EthSpec> Attestation<T> {
.set(committee_position, true)
.map_err(Error::SszTypesError)?;
let message = self.data.tree_hash_root();
let domain = spec.get_domain(self.data.target.epoch, Domain::BeaconAttester, fork);
let message = self.data.signing_root(domain);
self.signature
.add(&Signature::new(&message, domain, secret_key));
.add(&Signature::new(message.as_bytes(), secret_key));
Ok(())
}
@@ -95,5 +82,5 @@ mod tests {
use super::*;
use crate::*;
ssz_tests!(Attestation<MainnetEthSpec>);
ssz_and_tree_hash_tests!(Attestation<MainnetEthSpec>);
}

View File

@@ -1,5 +1,5 @@
use crate::test_utils::TestRandom;
use crate::{Checkpoint, Hash256, Slot};
use crate::{Checkpoint, Hash256, SignedRoot, Slot};
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
@@ -8,7 +8,7 @@ use tree_hash_derive::TreeHash;
/// The data upon which an attestation is based.
///
/// Spec v0.9.1
/// Spec v0.10.1
#[derive(
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Encode, Decode, TreeHash, TestRandom,
)]
@@ -24,9 +24,11 @@ pub struct AttestationData {
pub target: Checkpoint,
}
impl SignedRoot for AttestationData {}
#[cfg(test)]
mod tests {
use super::*;
ssz_tests!(AttestationData);
ssz_and_tree_hash_tests!(AttestationData);
}

View File

@@ -7,7 +7,7 @@ use tree_hash_derive::TreeHash;
/// Two conflicting attestations.
///
/// Spec v0.9.1
/// Spec v0.10.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[serde(bound = "T: EthSpec")]
pub struct AttesterSlashing<T: EthSpec> {
@@ -20,5 +20,5 @@ mod tests {
use super::*;
use crate::*;
ssz_tests!(AttesterSlashing<MainnetEthSpec>);
ssz_and_tree_hash_tests!(AttesterSlashing<MainnetEthSpec>);
}

View File

@@ -5,38 +5,27 @@ use bls::Signature;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::{SignedRoot, TreeHash};
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash::TreeHash;
use tree_hash_derive::TreeHash;
/// A block of the `BeaconChain`.
///
/// Spec v0.9.1
#[derive(
Debug,
PartialEq,
Clone,
Serialize,
Deserialize,
Encode,
Decode,
TreeHash,
TestRandom,
SignedRoot,
)]
/// Spec v0.10.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[serde(bound = "T: EthSpec")]
pub struct BeaconBlock<T: EthSpec> {
pub slot: Slot,
pub parent_root: Hash256,
pub state_root: Hash256,
pub body: BeaconBlockBody<T>,
#[signed_root(skip_hashing)]
pub signature: Signature,
}
impl<T: EthSpec> SignedRoot for BeaconBlock<T> {}
impl<T: EthSpec> BeaconBlock<T> {
/// Returns an empty block to be used during genesis.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn empty(spec: &ChainSpec) -> Self {
BeaconBlock {
slot: spec.genesis_slot,
@@ -56,7 +45,6 @@ impl<T: EthSpec> BeaconBlock<T> {
deposits: VariableList::empty(),
voluntary_exits: VariableList::empty(),
},
signature: Signature::empty_signature(),
}
}
@@ -65,11 +53,11 @@ impl<T: EthSpec> BeaconBlock<T> {
self.slot.epoch(T::slots_per_epoch())
}
/// Returns the `signed_root` of the block.
/// Returns the `tree_hash_root` of the block.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn canonical_root(&self) -> Hash256 {
Hash256::from_slice(&self.signed_root()[..])
Hash256::from_slice(&self.tree_hash_root()[..])
}
/// Returns a full `BeaconBlockHeader` of this block.
@@ -79,33 +67,40 @@ impl<T: EthSpec> BeaconBlock<T> {
///
/// Note: performs a full tree-hash of `self.body`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn block_header(&self) -> BeaconBlockHeader {
BeaconBlockHeader {
slot: self.slot,
parent_root: self.parent_root,
state_root: self.state_root,
body_root: Hash256::from_slice(&self.body.tree_hash_root()[..]),
signature: self.signature.clone(),
}
}
/// Returns a "temporary" header, where the `state_root` is `Hash256::zero()`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn temporary_block_header(&self) -> BeaconBlockHeader {
BeaconBlockHeader {
state_root: Hash256::zero(),
signature: Signature::empty_signature(),
..self.block_header()
}
}
/// Signs `self`.
pub fn sign(&mut self, secret_key: &SecretKey, fork: &Fork, spec: &ChainSpec) {
let message = self.signed_root();
let domain = spec.get_domain(self.epoch(), Domain::BeaconProposer, &fork);
self.signature = Signature::new(&message, domain, &secret_key);
/// Signs `self`, producing a `SignedBeaconBlock`.
pub fn sign(
self,
secret_key: &SecretKey,
fork: &Fork,
spec: &ChainSpec,
) -> SignedBeaconBlock<T> {
let domain = spec.get_domain(self.epoch(), Domain::BeaconProposer, fork);
let message = self.signing_root(domain);
let signature = Signature::new(message.as_bytes(), secret_key);
SignedBeaconBlock {
message: self,
signature,
}
}
}
@@ -113,5 +108,5 @@ impl<T: EthSpec> BeaconBlock<T> {
mod tests {
use super::*;
ssz_tests!(BeaconBlock<MainnetEthSpec>);
ssz_and_tree_hash_tests!(BeaconBlock<MainnetEthSpec>);
}

View File

@@ -10,7 +10,7 @@ use tree_hash_derive::TreeHash;
/// The body of a `BeaconChain` block, containing operations.
///
/// Spec v0.9.1
/// Spec v0.10.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[serde(bound = "T: EthSpec")]
pub struct BeaconBlockBody<T: EthSpec> {
@@ -25,12 +25,12 @@ pub struct BeaconBlockBody<T: EthSpec> {
pub attester_slashings: VariableList<AttesterSlashing<T>, T::MaxAttesterSlashings>,
pub attestations: VariableList<Attestation<T>, T::MaxAttestations>,
pub deposits: VariableList<Deposit, T::MaxDeposits>,
pub voluntary_exits: VariableList<VoluntaryExit, T::MaxVoluntaryExits>,
pub voluntary_exits: VariableList<SignedVoluntaryExit, T::MaxVoluntaryExits>,
}
#[cfg(test)]
mod tests {
use super::*;
ssz_tests!(BeaconBlockBody<MainnetEthSpec>);
ssz_and_tree_hash_tests!(BeaconBlockBody<MainnetEthSpec>);
}

View File

@@ -1,55 +1,59 @@
use crate::test_utils::TestRandom;
use crate::*;
use bls::Signature;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::{SignedRoot, TreeHash};
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash::TreeHash;
use tree_hash_derive::TreeHash;
/// A header of a `BeaconBlock`.
///
/// Spec v0.9.1
#[derive(
Debug,
PartialEq,
Clone,
Serialize,
Deserialize,
Encode,
Decode,
TreeHash,
TestRandom,
SignedRoot,
)]
/// Spec v0.10.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct BeaconBlockHeader {
pub slot: Slot,
pub parent_root: Hash256,
pub state_root: Hash256,
pub body_root: Hash256,
#[signed_root(skip_hashing)]
pub signature: Signature,
}
impl SignedRoot for BeaconBlockHeader {}
impl BeaconBlockHeader {
/// Returns the `tree_hash_root` of the header.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn canonical_root(&self) -> Hash256 {
Hash256::from_slice(&self.signed_root()[..])
Hash256::from_slice(&self.tree_hash_root()[..])
}
/// Given a `body`, consumes `self` and returns a complete `BeaconBlock`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn into_block<T: EthSpec>(self, body: BeaconBlockBody<T>) -> BeaconBlock<T> {
BeaconBlock {
slot: self.slot,
parent_root: self.parent_root,
state_root: self.state_root,
body,
signature: self.signature,
}
}
/// Signs `self`, producing a `SignedBeaconBlockHeader`.
pub fn sign<E: EthSpec>(
self,
secret_key: &SecretKey,
fork: &Fork,
spec: &ChainSpec,
) -> SignedBeaconBlockHeader {
let epoch = self.slot.epoch(E::slots_per_epoch());
let domain = spec.get_domain(epoch, Domain::BeaconProposer, fork);
let message = self.signing_root(domain);
let signature = Signature::new(message.as_bytes(), secret_key);
SignedBeaconBlockHeader {
message: self,
signature,
}
}
}
@@ -58,5 +62,5 @@ impl BeaconBlockHeader {
mod tests {
use super::*;
ssz_tests!(BeaconBlockHeader);
ssz_and_tree_hash_tests!(BeaconBlockHeader);
}

View File

@@ -90,7 +90,7 @@ impl AllowNextEpoch {
/// The state of the `BeaconChain` at some slot.
///
/// Spec v0.9.1
/// Spec v0.10.1
#[derive(
Debug,
PartialEq,
@@ -181,13 +181,17 @@ impl<T: EthSpec> BeaconState<T> {
///
/// Not a complete genesis state, see `initialize_beacon_state_from_eth1`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn new(genesis_time: u64, eth1_data: Eth1Data, spec: &ChainSpec) -> Self {
BeaconState {
// Versioning
genesis_time,
slot: spec.genesis_slot,
fork: spec.genesis_fork.clone(),
fork: Fork {
previous_version: spec.genesis_fork_version,
current_version: spec.genesis_fork_version,
epoch: T::genesis_epoch(),
},
// History
latest_block_header: BeaconBlock::<T>::empty(spec).temporary_block_header(),
@@ -234,7 +238,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Returns the `tree_hash_root` of the state.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn canonical_root(&self) -> Hash256 {
Hash256::from_slice(&self.tree_hash_root()[..])
}
@@ -263,7 +267,7 @@ impl<T: EthSpec> BeaconState<T> {
/// The epoch corresponding to `self.slot`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn current_epoch(&self) -> Epoch {
self.slot.epoch(T::slots_per_epoch())
}
@@ -272,7 +276,7 @@ impl<T: EthSpec> BeaconState<T> {
///
/// If the current epoch is the genesis epoch, the genesis_epoch is returned.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn previous_epoch(&self) -> Epoch {
let current_epoch = self.current_epoch();
if current_epoch > T::genesis_epoch() {
@@ -284,7 +288,7 @@ impl<T: EthSpec> BeaconState<T> {
/// The epoch following `self.current_epoch()`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn next_epoch(&self) -> Epoch {
self.current_epoch() + 1
}
@@ -293,7 +297,7 @@ impl<T: EthSpec> BeaconState<T> {
///
/// Makes use of the committee cache and will fail if no cache exists for the slot's epoch.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_committee_count_at_slot(&self, slot: Slot) -> Result<u64, Error> {
let cache = self.committee_cache_at_slot(slot)?;
Ok(cache.committees_per_slot() as u64)
@@ -301,7 +305,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Compute the number of committees in an entire epoch.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_epoch_committee_count(&self, relative_epoch: RelativeEpoch) -> Result<u64, Error> {
let cache = self.committee_cache(relative_epoch)?;
Ok(cache.epoch_committee_count() as u64)
@@ -325,7 +329,7 @@ impl<T: EthSpec> BeaconState<T> {
///
/// Does not utilize the cache, performs a full iteration over the validator registry.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_active_validator_indices(&self, epoch: Epoch) -> Vec<usize> {
get_active_validator_indices(&self.validators, epoch)
}
@@ -345,7 +349,7 @@ impl<T: EthSpec> BeaconState<T> {
///
/// Utilises the committee cache.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_beacon_committee(
&self,
slot: Slot,
@@ -364,7 +368,7 @@ impl<T: EthSpec> BeaconState<T> {
///
/// Utilises the committee cache.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_beacon_committees_at_slot(&self, slot: Slot) -> Result<Vec<BeaconCommittee>, Error> {
let cache = self.committee_cache_at_slot(slot)?;
cache.get_beacon_committees_at_slot(slot)
@@ -374,7 +378,7 @@ impl<T: EthSpec> BeaconState<T> {
///
/// Utilises the committee cache.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_beacon_committees_at_epoch(
&self,
relative_epoch: RelativeEpoch,
@@ -385,7 +389,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Compute the proposer (not necessarily for the Beacon chain) from a list of indices.
///
/// Spec v0.9.1
/// Spec v0.10.1
// NOTE: be sure to test this bad boy.
pub fn compute_proposer_index(
&self,
@@ -424,7 +428,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Returns the beacon proposer index for the `slot` in the given `relative_epoch`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_beacon_proposer_index(&self, slot: Slot, spec: &ChainSpec) -> Result<usize, Error> {
let epoch = slot.epoch(T::slots_per_epoch());
let seed = self.get_beacon_proposer_seed(slot, spec)?;
@@ -435,7 +439,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Compute the seed to use for the beacon proposer selection at the given `slot`.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn get_beacon_proposer_seed(&self, slot: Slot, spec: &ChainSpec) -> Result<Vec<u8>, Error> {
let epoch = slot.epoch(T::slots_per_epoch());
let mut preimage = self
@@ -450,7 +454,7 @@ impl<T: EthSpec> BeaconState<T> {
///
/// It needs filling in on all slots where there isn't a skip.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_latest_block_root(&self, current_state_root: Hash256) -> Hash256 {
if self.latest_block_header.state_root.is_zero() {
let mut latest_block_header = self.latest_block_header.clone();
@@ -463,7 +467,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Safely obtains the index for latest block roots, given some `slot`.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn get_latest_block_roots_index(&self, slot: Slot) -> Result<usize, Error> {
if (slot < self.slot) && (self.slot <= slot + self.block_roots.len() as u64) {
Ok(slot.as_usize() % self.block_roots.len())
@@ -474,7 +478,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Return the block root at a recent `slot`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_block_root(&self, slot: Slot) -> Result<&Hash256, BeaconStateError> {
let i = self.get_latest_block_roots_index(slot)?;
Ok(&self.block_roots[i])
@@ -482,7 +486,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Return the block root at a recent `epoch`.
///
/// Spec v0.9.1
/// Spec v0.10.1
// NOTE: the spec calls this get_block_root
pub fn get_block_root_at_epoch(&self, epoch: Epoch) -> Result<&Hash256, BeaconStateError> {
self.get_block_root(epoch.start_slot(T::slots_per_epoch()))
@@ -490,7 +494,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Sets the block root for some given slot.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn set_block_root(
&mut self,
slot: Slot,
@@ -508,7 +512,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Safely obtains the index for `randao_mixes`
///
/// Spec v0.9.1
/// Spec v0.10.1
fn get_randao_mix_index(
&self,
epoch: Epoch,
@@ -530,7 +534,7 @@ impl<T: EthSpec> BeaconState<T> {
///
/// See `Self::get_randao_mix`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn update_randao_mix(&mut self, epoch: Epoch, signature: &Signature) -> Result<(), Error> {
let i = epoch.as_usize() % T::EpochsPerHistoricalVector::to_usize();
@@ -543,7 +547,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Return the randao mix at a recent ``epoch``.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_randao_mix(&self, epoch: Epoch) -> Result<&Hash256, Error> {
let i = self.get_randao_mix_index(epoch, AllowNextEpoch::False)?;
Ok(&self.randao_mixes[i])
@@ -551,7 +555,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Set the randao mix at a recent ``epoch``.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn set_randao_mix(&mut self, epoch: Epoch, mix: Hash256) -> Result<(), Error> {
let i = self.get_randao_mix_index(epoch, AllowNextEpoch::True)?;
self.randao_mixes[i] = mix;
@@ -560,7 +564,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Safely obtains the index for latest state roots, given some `slot`.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn get_latest_state_roots_index(&self, slot: Slot) -> Result<usize, Error> {
if (slot < self.slot) && (self.slot <= slot + Slot::from(self.state_roots.len())) {
Ok(slot.as_usize() % self.state_roots.len())
@@ -571,7 +575,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Gets the state root for some slot.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_state_root(&self, slot: Slot) -> Result<&Hash256, Error> {
let i = self.get_latest_state_roots_index(slot)?;
Ok(&self.state_roots[i])
@@ -579,7 +583,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Gets the oldest (earliest slot) state root.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_oldest_state_root(&self) -> Result<&Hash256, Error> {
let i =
self.get_latest_state_roots_index(self.slot - Slot::from(self.state_roots.len()))?;
@@ -588,7 +592,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Gets the oldest (earliest slot) block root.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_oldest_block_root(&self) -> Result<&Hash256, Error> {
let i = self.get_latest_block_roots_index(self.slot - self.block_roots.len() as u64)?;
Ok(&self.block_roots[i])
@@ -596,7 +600,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Sets the latest state root for slot.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn set_state_root(&mut self, slot: Slot, state_root: Hash256) -> Result<(), Error> {
let i = self.get_latest_state_roots_index(slot)?;
self.state_roots[i] = state_root;
@@ -605,7 +609,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Safely obtain the index for `slashings`, given some `epoch`.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn get_slashings_index(
&self,
epoch: Epoch,
@@ -625,14 +629,14 @@ impl<T: EthSpec> BeaconState<T> {
/// Get a reference to the entire `slashings` vector.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_all_slashings(&self) -> &[u64] {
&self.slashings
}
/// Get the total slashed balances for some epoch.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_slashings(&self, epoch: Epoch) -> Result<u64, Error> {
let i = self.get_slashings_index(epoch, AllowNextEpoch::False)?;
Ok(self.slashings[i])
@@ -640,7 +644,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Set the total slashed balances for some epoch.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn set_slashings(&mut self, epoch: Epoch, value: u64) -> Result<(), Error> {
let i = self.get_slashings_index(epoch, AllowNextEpoch::True)?;
self.slashings[i] = value;
@@ -649,7 +653,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Get the attestations from the current or previous epoch.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_matching_source_attestations(
&self,
epoch: Epoch,
@@ -665,7 +669,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Generate a seed for the given `epoch`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_seed(
&self,
epoch: Epoch,
@@ -696,7 +700,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Return the effective balance (also known as "balance at stake") for a validator with the given ``index``.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_effective_balance(
&self,
validator_index: usize,
@@ -710,7 +714,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Return the epoch at which an activation or exit triggered in ``epoch`` takes effect.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn compute_activation_exit_epoch(&self, epoch: Epoch, spec: &ChainSpec) -> Epoch {
epoch + 1 + spec.max_seed_lookahead
}
@@ -719,7 +723,7 @@ impl<T: EthSpec> BeaconState<T> {
///
/// Uses the epoch cache, and will error if it isn't initialized.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_churn_limit(&self, spec: &ChainSpec) -> Result<u64, Error> {
Ok(std::cmp::max(
spec.min_per_epoch_churn_limit,
@@ -734,7 +738,7 @@ impl<T: EthSpec> BeaconState<T> {
///
/// Note: Utilizes the cache and will fail if the appropriate cache is not initialized.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_attestation_duties(
&self,
validator_index: usize,
@@ -747,7 +751,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Return the combined effective balance of an array of validators.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_total_balance(
&self,
validator_indices: &[usize],

View File

@@ -22,7 +22,7 @@ pub struct CommitteeCache {
impl CommitteeCache {
/// Return a new, fully initialized cache.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn initialized<T: EthSpec>(
state: &BeaconState<T>,
epoch: Epoch,
@@ -87,7 +87,7 @@ impl CommitteeCache {
///
/// Always returns `&[]` for a non-initialized epoch.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn active_validator_indices(&self) -> &[usize] {
&self.shuffling
}
@@ -96,7 +96,7 @@ impl CommitteeCache {
///
/// Always returns `&[]` for a non-initialized epoch.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn shuffling(&self) -> &[usize] {
&self.shuffling
}
@@ -202,7 +202,7 @@ impl CommitteeCache {
///
/// Always returns `usize::default()` for a non-initialized epoch.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn active_validator_count(&self) -> usize {
self.shuffling.len()
}
@@ -211,7 +211,7 @@ impl CommitteeCache {
///
/// Always returns `usize::default()` for a non-initialized epoch.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn epoch_committee_count(&self) -> usize {
self.committees_per_slot as usize * self.slots_per_epoch as usize
}
@@ -223,7 +223,7 @@ impl CommitteeCache {
/// Returns a slice of `self.shuffling` that represents the `index`'th committee in the epoch.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn compute_committee(&self, index: usize) -> Option<&[usize]> {
Some(&self.shuffling[self.compute_committee_range(index)?])
}
@@ -234,7 +234,7 @@ impl CommitteeCache {
///
/// Will also return `None` if the index is out of bounds.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn compute_committee_range(&self, index: usize) -> Option<Range<usize>> {
let count = self.epoch_committee_count();
if count == 0 || index >= count {
@@ -261,7 +261,7 @@ impl CommitteeCache {
/// Returns a list of all `validators` indices where the validator is active at the given
/// `epoch`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_active_validator_indices(validators: &[Validator], epoch: Epoch) -> Vec<usize> {
let mut active = Vec::with_capacity(validators.len());

View File

@@ -2,7 +2,7 @@
use super::*;
use crate::test_utils::*;
ssz_tests!(FoundationBeaconState);
ssz_and_tree_hash_tests!(FoundationBeaconState);
fn test_beacon_proposer_index<T: EthSpec>() {
let spec = T::default_spec();

View File

@@ -1,11 +1,16 @@
use crate::*;
use int_to_bytes::int_to_bytes4;
use serde_derive::{Deserialize, Serialize};
use utils::{u32_from_hex_str, u32_to_hex_str, u8_from_hex_str, u8_to_hex_str};
use std::fs::File;
use std::path::Path;
use utils::{
fork_from_hex_str, fork_to_hex_str, u32_from_hex_str, u32_to_hex_str, u8_from_hex_str,
u8_to_hex_str,
};
/// Each of the BLS signature domains.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub enum Domain {
BeaconProposer,
BeaconAttester,
@@ -16,18 +21,18 @@ pub enum Domain {
/// Holds all the "constants" for a BeaconChain.
///
/// Spec v0.9.1
/// Spec v0.10.1
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct ChainSpec {
/*
* Constants
*/
pub genesis_slot: Slot,
#[serde(skip_serializing)] // skipped because Serde TOML has trouble with u64::max
pub far_future_epoch: Epoch,
pub base_rewards_per_epoch: u64,
pub deposit_contract_tree_depth: u64,
pub seconds_per_day: u64,
/*
* Misc
@@ -51,20 +56,25 @@ pub struct ChainSpec {
/*
* Initial Values
*/
pub genesis_slot: Slot,
#[serde(
serialize_with = "fork_to_hex_str",
deserialize_with = "fork_from_hex_str"
)]
pub genesis_fork_version: [u8; 4],
#[serde(deserialize_with = "u8_from_hex_str", serialize_with = "u8_to_hex_str")]
pub bls_withdrawal_prefix_byte: u8,
/*
* Time parameters
*/
pub min_genesis_delay: u64,
pub milliseconds_per_slot: u64,
pub min_attestation_inclusion_delay: u64,
pub min_seed_lookahead: Epoch,
pub max_seed_lookahead: Epoch,
pub min_epochs_to_inactivity_penalty: u64,
pub min_validator_withdrawability_delay: Epoch,
pub persistent_committee_period: u64,
pub min_epochs_to_inactivity_penalty: u64,
/*
* Reward and penalty quotients
@@ -93,17 +103,16 @@ pub struct ChainSpec {
* Eth1
*/
pub eth1_follow_distance: u64,
pub seconds_per_eth1_block: u64,
pub boot_nodes: Vec<String>,
pub network_id: u8,
pub genesis_fork: Fork,
}
impl ChainSpec {
/// Get the domain number, unmodified by the fork.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_domain_constant(&self, domain: Domain) -> u32 {
match domain {
Domain::BeaconProposer => self.domain_beacon_proposer,
@@ -116,28 +125,30 @@ impl ChainSpec {
/// Get the domain number that represents the fork meta and signature domain.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_domain(&self, epoch: Epoch, domain: Domain, fork: &Fork) -> u64 {
let domain_constant = self.get_domain_constant(domain);
let mut bytes: Vec<u8> = int_to_bytes4(domain_constant);
bytes.append(&mut fork.get_fork_version(epoch).to_vec());
let mut fork_and_domain = [0; 8];
fork_and_domain.copy_from_slice(&bytes);
u64::from_le_bytes(fork_and_domain)
let fork_version = fork.get_fork_version(epoch);
self.compute_domain(domain, fork_version)
}
/// Get the domain for a deposit signature.
///
/// Deposits are valid across forks, thus the deposit domain is computed
/// with the fork zeroed.
/// with the genesis fork version.
///
/// Spec v0.8.1
/// Spec v0.10.1
pub fn get_deposit_domain(&self) -> u64 {
let mut bytes: Vec<u8> = int_to_bytes4(self.domain_deposit);
bytes.append(&mut vec![0; 4]);
self.compute_domain(Domain::Deposit, self.genesis_fork_version)
}
/// Compute a domain by applying the given `fork_version`.
///
/// Spec v0.10.1
pub fn compute_domain(&self, domain: Domain, fork_version: [u8; 4]) -> u64 {
let domain_constant = self.get_domain_constant(domain);
let mut bytes: Vec<u8> = int_to_bytes4(domain_constant);
bytes.append(&mut fork_version.to_vec());
let mut fork_and_domain = [0; 8];
fork_and_domain.copy_from_slice(&bytes);
@@ -147,16 +158,16 @@ impl ChainSpec {
/// Returns a `ChainSpec` compatible with the Ethereum Foundation specification.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn mainnet() -> Self {
Self {
/*
* Constants
*/
genesis_slot: Slot::new(0),
far_future_epoch: Epoch::new(u64::max_value()),
base_rewards_per_epoch: 4,
deposit_contract_tree_depth: 32,
seconds_per_day: 86400,
/*
* Misc
@@ -166,7 +177,7 @@ impl ChainSpec {
min_per_epoch_churn_limit: 4,
churn_limit_quotient: 65_536,
shuffle_round_count: 90,
min_genesis_active_validator_count: 65_536,
min_genesis_active_validator_count: 16_384,
min_genesis_time: 1_578_009_600, // Jan 3, 2020
/*
@@ -180,19 +191,20 @@ impl ChainSpec {
/*
* Initial Values
*/
genesis_slot: Slot::new(0),
genesis_fork_version: [0; 4],
bls_withdrawal_prefix_byte: 0,
/*
* Time parameters
*/
min_genesis_delay: 86400, // 1 day
milliseconds_per_slot: 12_000,
min_attestation_inclusion_delay: 1,
min_seed_lookahead: Epoch::new(1),
max_seed_lookahead: Epoch::new(4),
min_epochs_to_inactivity_penalty: 4,
min_validator_withdrawability_delay: Epoch::new(256),
persistent_committee_period: 2_048,
min_epochs_to_inactivity_penalty: 4,
/*
* Reward and penalty quotients
@@ -221,15 +233,7 @@ impl ChainSpec {
* Eth1
*/
eth1_follow_distance: 1_024,
/*
* Fork
*/
genesis_fork: Fork {
previous_version: [0; 4],
current_version: [0; 4],
epoch: Epoch::new(0),
},
seconds_per_eth1_block: 14,
/*
* Network specific
@@ -239,11 +243,9 @@ impl ChainSpec {
}
}
/// Ethereum Foundation minimal spec, as defined here:
/// Ethereum Foundation minimal spec, as defined in the eth2.0-specs repo.
///
/// https://github.com/ethereum/eth2.0-specs/blob/v0.9.1/configs/minimal.yaml
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn minimal() -> Self {
// Note: bootnodes to be updated when static nodes exist.
let boot_nodes = vec![];
@@ -253,10 +255,12 @@ impl ChainSpec {
target_committee_size: 4,
shuffle_round_count: 10,
min_genesis_active_validator_count: 64,
eth1_follow_distance: 16,
genesis_fork_version: [0x00, 0x00, 0x00, 0x01],
min_genesis_delay: 300,
milliseconds_per_slot: 6_000,
network_id: 2, // lighthouse testnet network id
boot_nodes,
eth1_follow_distance: 16,
milliseconds_per_slot: 6_000,
..ChainSpec::mainnet()
}
}
@@ -295,7 +299,11 @@ mod tests {
}
fn test_domain(domain_type: Domain, raw_domain: u32, spec: &ChainSpec) {
let fork = &spec.genesis_fork;
let fork = Fork {
previous_version: spec.genesis_fork_version,
current_version: spec.genesis_fork_version,
epoch: MinimalEthSpec::genesis_epoch(),
};
let epoch = Epoch::new(0);
let domain = spec.get_domain(epoch, domain_type, &fork);
@@ -318,19 +326,20 @@ mod tests {
}
}
// Yaml Config is declared here in order to access domain fields of ChainSpec which are private fields.
/// Union of a ChainSpec struct and an EthSpec struct that holds constants used for the configs
/// from the Ethereum 2 specs repo (https://github.com/ethereum/eth2.0-specs/tree/dev/configs)
///
/// Spec v0.10.1
// Yaml Config is declared here in order to access domain fields of ChainSpec which are private.
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
#[serde(rename_all = "UPPERCASE")]
#[serde(default)]
#[serde(deny_unknown_fields)]
/// Union of a ChainSpec struct and an EthSpec struct that holds constants used for the configs folder of the Ethereum 2 spec (https://github.com/ethereum/eth2.0-specs/tree/dev/configs)
/// Spec v0.9.1
pub struct YamlConfig {
// ChainSpec
far_future_epoch: u64,
base_rewards_per_epoch: u64,
deposit_contract_tree_depth: u64,
seconds_per_day: u64,
max_committees_per_slot: usize,
target_committee_size: usize,
min_per_epoch_churn_limit: u64,
@@ -338,20 +347,26 @@ pub struct YamlConfig {
shuffle_round_count: u8,
min_genesis_active_validator_count: u64,
min_genesis_time: u64,
min_genesis_delay: u64,
min_deposit_amount: u64,
max_effective_balance: u64,
ejection_balance: u64,
effective_balance_increment: u64,
genesis_slot: u64,
#[serde(
serialize_with = "fork_to_hex_str",
deserialize_with = "fork_from_hex_str"
)]
genesis_fork_version: [u8; 4],
#[serde(deserialize_with = "u8_from_hex_str", serialize_with = "u8_to_hex_str")]
bls_withdrawal_prefix: u8,
seconds_per_slot: u64,
min_attestation_inclusion_delay: u64,
min_seed_lookahead: u64,
max_seed_lookahead: u64,
min_epochs_to_inactivity_penalty: u64,
min_validator_withdrawability_delay: u64,
persistent_committee_period: u64,
min_epochs_to_inactivity_penalty: u64,
base_reward_factor: u64,
whistleblower_reward_quotient: u64,
proposer_reward_quotient: u64,
@@ -359,9 +374,6 @@ pub struct YamlConfig {
min_slashing_penalty_quotient: u64,
safe_slots_to_update_justified: u64,
#[serde(skip_serializing)]
genesis_fork: Fork,
#[serde(
deserialize_with = "u32_from_hex_str",
serialize_with = "u32_to_hex_str"
@@ -408,12 +420,14 @@ pub struct YamlConfig {
max_deposits: u32,
max_voluntary_exits: u32,
// Eth1
// Validator
eth1_follow_distance: u64,
target_aggregators_per_committee: u64,
random_subnets_per_validator: u64,
epochs_per_random_subnet_subscription: u64,
seconds_per_eth1_block: u64,
// Unused
#[serde(skip_serializing)]
early_derived_secret_penalty_max_future_epochs: u32,
// Deposit Contract (unused)
#[serde(skip_serializing)]
deposit_contract_address: String,
@@ -438,6 +452,8 @@ pub struct YamlConfig {
domain_shard_attester: u32,
#[serde(skip_serializing)]
max_epochs_per_crosslink: u64,
#[serde(skip_serializing)]
early_derived_secret_penalty_max_future_epochs: u32,
}
impl Default for YamlConfig {
@@ -447,7 +463,7 @@ impl Default for YamlConfig {
}
}
/// Spec v0.8.1
/// Spec v0.10.1
impl YamlConfig {
pub fn from_spec<T: EthSpec>(spec: &ChainSpec) -> Self {
Self {
@@ -455,7 +471,6 @@ impl YamlConfig {
far_future_epoch: spec.far_future_epoch.into(),
base_rewards_per_epoch: spec.base_rewards_per_epoch,
deposit_contract_tree_depth: spec.deposit_contract_tree_depth,
seconds_per_day: spec.seconds_per_day,
max_committees_per_slot: spec.max_committees_per_slot,
target_committee_size: spec.target_committee_size,
min_per_epoch_churn_limit: spec.min_per_epoch_churn_limit,
@@ -463,6 +478,7 @@ impl YamlConfig {
shuffle_round_count: spec.shuffle_round_count,
min_genesis_active_validator_count: spec.min_genesis_active_validator_count,
min_genesis_time: spec.min_genesis_time,
min_genesis_delay: spec.min_genesis_delay,
min_deposit_amount: spec.min_deposit_amount,
max_effective_balance: spec.max_effective_balance,
ejection_balance: spec.ejection_balance,
@@ -481,7 +497,7 @@ impl YamlConfig {
proposer_reward_quotient: spec.proposer_reward_quotient,
inactivity_penalty_quotient: spec.inactivity_penalty_quotient,
min_slashing_penalty_quotient: spec.min_slashing_penalty_quotient,
genesis_fork: spec.genesis_fork.clone(),
genesis_fork_version: spec.genesis_fork_version.clone(),
safe_slots_to_update_justified: spec.safe_slots_to_update_justified,
domain_beacon_proposer: spec.domain_beacon_proposer,
domain_beacon_attester: spec.domain_beacon_attester,
@@ -506,11 +522,14 @@ impl YamlConfig {
max_deposits: T::MaxDeposits::to_u32(),
max_voluntary_exits: T::MaxVoluntaryExits::to_u32(),
// Eth1
// Validator
eth1_follow_distance: spec.eth1_follow_distance,
target_aggregators_per_committee: 0,
random_subnets_per_validator: 0,
epochs_per_random_subnet_subscription: 0,
seconds_per_eth1_block: spec.seconds_per_eth1_block,
// Unused
early_derived_secret_penalty_max_future_epochs: 0,
// Deposit Contract (unused)
deposit_contract_address: String::new(),
// Phase 1
@@ -524,9 +543,17 @@ impl YamlConfig {
domain_shard_proposer: 0,
domain_shard_attester: 0,
max_epochs_per_crosslink: 0,
early_derived_secret_penalty_max_future_epochs: 0,
}
}
pub fn from_file(filename: &Path) -> Result<Self, String> {
let f = File::open(filename)
.map_err(|e| format!("Error opening spec at {}: {:?}", filename.display(), e))?;
serde_yaml::from_reader(f)
.map_err(|e| format!("Error parsing spec at {}: {:?}", filename.display(), e))
}
pub fn apply_to_chain_spec<T: EthSpec>(&self, chain_spec: &ChainSpec) -> Option<ChainSpec> {
// Checking for EthSpec constants
if self.justification_bits_length != T::JustificationBitsLength::to_u32()
@@ -553,7 +580,6 @@ impl YamlConfig {
far_future_epoch: Epoch::from(self.far_future_epoch),
base_rewards_per_epoch: self.base_rewards_per_epoch,
deposit_contract_tree_depth: self.deposit_contract_tree_depth,
seconds_per_day: self.seconds_per_day,
target_committee_size: self.target_committee_size,
min_per_epoch_churn_limit: self.min_per_epoch_churn_limit,
churn_limit_quotient: self.churn_limit_quotient,
@@ -561,6 +587,7 @@ impl YamlConfig {
min_genesis_active_validator_count: self.min_genesis_active_validator_count,
min_genesis_time: self.min_genesis_time,
min_deposit_amount: self.min_deposit_amount,
min_genesis_delay: self.min_genesis_delay,
max_effective_balance: self.max_effective_balance,
ejection_balance: self.ejection_balance,
effective_balance_increment: self.effective_balance_increment,
@@ -585,7 +612,7 @@ impl YamlConfig {
domain_deposit: self.domain_deposit,
domain_voluntary_exit: self.domain_voluntary_exit,
boot_nodes: chain_spec.boot_nodes.clone(),
genesis_fork: chain_spec.genesis_fork.clone(),
genesis_fork_version: chain_spec.genesis_fork_version.clone(),
eth1_follow_distance: self.eth1_follow_distance,
..*chain_spec
})

View File

@@ -7,7 +7,7 @@ use tree_hash_derive::TreeHash;
/// Casper FFG checkpoint, used in attestations.
///
/// Spec v0.9.1
/// Spec v0.10.1
#[derive(
Debug,
Clone,
@@ -31,5 +31,5 @@ pub struct Checkpoint {
mod tests {
use super::*;
ssz_tests!(Checkpoint);
ssz_and_tree_hash_tests!(Checkpoint);
}

View File

@@ -11,7 +11,7 @@ pub const DEPOSIT_TREE_DEPTH: usize = 32;
/// A deposit to potentially become a beacon chain validator.
///
/// Spec v0.9.1
/// Spec v0.10.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct Deposit {
pub proof: FixedVector<Hash256, U33>,
@@ -22,5 +22,5 @@ pub struct Deposit {
mod tests {
use super::*;
ssz_tests!(Deposit);
ssz_and_tree_hash_tests!(Deposit);
}

View File

@@ -1,46 +1,43 @@
use crate::test_utils::TestRandom;
use crate::*;
use bls::{PublicKeyBytes, SignatureBytes};
use std::convert::From;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::{SignedRoot, TreeHash};
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash_derive::TreeHash;
/// The data supplied by the user to the deposit contract.
///
/// Spec v0.9.1
#[derive(
Debug,
PartialEq,
Clone,
Serialize,
Deserialize,
Encode,
Decode,
SignedRoot,
TreeHash,
TestRandom,
)]
/// Spec v0.10.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct DepositData {
pub pubkey: PublicKeyBytes,
pub withdrawal_credentials: Hash256,
pub amount: u64,
#[signed_root(skip_hashing)]
pub signature: SignatureBytes,
}
impl DepositData {
/// Create a `DepositMessage` corresponding to this `DepositData`, for signature verification.
///
/// Spec v0.10.1
pub fn as_deposit_message(&self) -> DepositMessage {
DepositMessage {
pubkey: self.pubkey.clone(),
withdrawal_credentials: self.withdrawal_credentials,
amount: self.amount,
}
}
/// Generate the signature for a given DepositData details.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn create_signature(&self, secret_key: &SecretKey, spec: &ChainSpec) -> SignatureBytes {
let msg = self.signed_root();
let domain = spec.get_deposit_domain();
let msg = self.as_deposit_message().signing_root(domain);
SignatureBytes::from(Signature::new(msg.as_slice(), domain, secret_key))
SignatureBytes::from(Signature::new(msg.as_bytes(), secret_key))
}
}
@@ -48,5 +45,5 @@ impl DepositData {
mod tests {
use super::*;
ssz_tests!(DepositData);
ssz_and_tree_hash_tests!(DepositData);
}

View File

@@ -0,0 +1,27 @@
use crate::test_utils::TestRandom;
use crate::*;
use bls::PublicKeyBytes;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
/// The data supplied by the user to the deposit contract.
///
/// Spec v0.10.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct DepositMessage {
pub pubkey: PublicKeyBytes,
pub withdrawal_credentials: Hash256,
pub amount: u64,
}
impl SignedRoot for DepositMessage {}
#[cfg(test)]
mod tests {
use super::*;
ssz_and_tree_hash_tests!(DepositMessage);
}

View File

@@ -8,7 +8,7 @@ use tree_hash_derive::TreeHash;
/// Contains data obtained from the Eth1 chain.
///
/// Spec v0.9.1
/// Spec v0.10.1
#[derive(
Debug,
PartialEq,
@@ -33,5 +33,5 @@ pub struct Eth1Data {
mod tests {
use super::*;
ssz_tests!(Eth1Data);
ssz_and_tree_hash_tests!(Eth1Data);
}

View File

@@ -10,15 +10,12 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq {
/*
* Constants
*/
type GenesisEpoch: Unsigned + Clone + Sync + Send + Debug + PartialEq;
type JustificationBitsLength: Unsigned + Clone + Sync + Send + Debug + PartialEq + Default;
/*
* Misc
*/
type MaxValidatorsPerCommittee: Unsigned + Clone + Sync + Send + Debug + PartialEq;
/*
* Initial values
*/
type GenesisEpoch: Unsigned + Clone + Sync + Send + Debug + PartialEq;
/*
* Time parameters
*/
@@ -61,7 +58,7 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq {
/// Note: the number of committees per slot is constant in each epoch, and depends only on
/// the `active_validator_count` during the slot's epoch.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn get_committee_count_per_slot(active_validator_count: usize, spec: &ChainSpec) -> usize {
let slots_per_epoch = Self::SlotsPerEpoch::to_usize();
@@ -85,28 +82,28 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq {
/// Returns the `SLOTS_PER_EPOCH` constant for this specification.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn slots_per_epoch() -> u64 {
Self::SlotsPerEpoch::to_u64()
}
/// Returns the `SLOTS_PER_HISTORICAL_ROOT` constant for this specification.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn slots_per_historical_root() -> usize {
Self::SlotsPerHistoricalRoot::to_usize()
}
/// Returns the `EPOCHS_PER_HISTORICAL_VECTOR` constant for this specification.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn epochs_per_historical_vector() -> usize {
Self::EpochsPerHistoricalVector::to_usize()
}
/// Returns the `SLOTS_PER_ETH1_VOTING_PERIOD` constant for this specification.
///
/// Spec v0.9.1
/// Spec v0.10.1
fn slots_per_eth1_voting_period() -> usize {
Self::SlotsPerEth1VotingPeriod::to_usize()
}
@@ -122,7 +119,7 @@ macro_rules! params_from_eth_spec {
/// Ethereum Foundation specifications.
///
/// Spec v0.9.1
/// Spec v0.10.1
#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
pub struct MainnetEthSpec;
@@ -151,11 +148,9 @@ impl EthSpec for MainnetEthSpec {
pub type FoundationBeaconState = BeaconState<MainnetEthSpec>;
/// Ethereum Foundation minimal spec, as defined here:
/// Ethereum Foundation minimal spec, as defined in the eth2.0-specs repo.
///
/// https://github.com/ethereum/eth2.0-specs/blob/v0.8.0/configs/constant_presets/minimal.yaml
///
/// Spec v0.9.1
/// Spec v0.10.1
#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
pub struct MinimalEthSpec;

View File

@@ -9,7 +9,7 @@ use tree_hash_derive::TreeHash;
/// Specifies a fork of the `BeaconChain`, to prevent replay attacks.
///
/// Spec v0.9.1
/// Spec v0.10.1
#[derive(
Debug, Clone, PartialEq, Default, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
)]
@@ -30,7 +30,7 @@ pub struct Fork {
impl Fork {
/// Return the fork version of the given ``epoch``.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn get_fork_version(&self, epoch: Epoch) -> [u8; 4] {
if epoch < self.epoch {
return self.previous_version;
@@ -43,7 +43,7 @@ impl Fork {
mod tests {
use super::*;
ssz_tests!(Fork);
ssz_and_tree_hash_tests!(Fork);
#[test]
fn get_fork_version() {

View File

@@ -9,7 +9,7 @@ use tree_hash_derive::TreeHash;
/// Historical block and state roots.
///
/// Spec v0.9.1
/// Spec v0.10.1
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct HistoricalBatch<T: EthSpec> {
pub block_roots: FixedVector<Hash256, T::SlotsPerHistoricalRoot>,
@@ -22,5 +22,5 @@ mod tests {
pub type FoundationHistoricalBatch = HistoricalBatch<MainnetEthSpec>;
ssz_tests!(FoundationHistoricalBatch);
ssz_and_tree_hash_tests!(FoundationHistoricalBatch);
}

View File

@@ -2,46 +2,33 @@ use crate::{test_utils::TestRandom, AggregateSignature, AttestationData, EthSpec
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash_derive::TreeHash;
/// Details an attestation that can be slashable.
///
/// To be included in an `AttesterSlashing`.
///
/// Spec v0.9.1
#[derive(
Debug,
PartialEq,
Clone,
Serialize,
Deserialize,
Encode,
Decode,
TreeHash,
TestRandom,
SignedRoot,
)]
/// Spec v0.10.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[serde(bound = "T: EthSpec")]
pub struct IndexedAttestation<T: EthSpec> {
/// Lists validator registry indices, not committee indices.
pub attesting_indices: VariableList<u64, T::MaxValidatorsPerCommittee>,
pub data: AttestationData,
#[signed_root(skip_hashing)]
pub signature: AggregateSignature,
}
impl<T: EthSpec> IndexedAttestation<T> {
/// Check if ``attestation_data_1`` and ``attestation_data_2`` have the same target.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn is_double_vote(&self, other: &Self) -> bool {
self.data.target.epoch == other.data.target.epoch && self.data != other.data
}
/// Check if ``attestation_data_1`` surrounds ``attestation_data_2``.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn is_surround_vote(&self, other: &Self) -> bool {
self.data.source.epoch < other.data.source.epoch
&& other.data.target.epoch < self.data.target.epoch
@@ -121,7 +108,7 @@ mod tests {
);
}
ssz_tests!(IndexedAttestation<MainnetEthSpec>);
ssz_and_tree_hash_tests!(IndexedAttestation<MainnetEthSpec>);
fn create_indexed_attestation(
target_epoch: u64,

View File

@@ -19,6 +19,7 @@ pub mod chain_spec;
pub mod checkpoint;
pub mod deposit;
pub mod deposit_data;
pub mod deposit_message;
pub mod eth1_data;
pub mod eth_spec;
pub mod fork;
@@ -27,15 +28,18 @@ pub mod historical_batch;
pub mod indexed_attestation;
pub mod pending_attestation;
pub mod proposer_slashing;
pub mod relative_epoch;
pub mod signed_beacon_block;
pub mod signed_beacon_block_header;
pub mod signed_voluntary_exit;
pub mod signing_root;
pub mod utils;
pub mod validator;
pub mod voluntary_exit;
#[macro_use]
pub mod slot_epoch_macros;
pub mod relative_epoch;
pub mod slot_epoch;
pub mod slot_height;
mod tree_hash_impls;
pub mod validator;
use ethereum_types::{H160, H256};
@@ -52,6 +56,7 @@ pub use crate::chain_spec::{ChainSpec, Domain, YamlConfig};
pub use crate::checkpoint::Checkpoint;
pub use crate::deposit::{Deposit, DEPOSIT_TREE_DEPTH};
pub use crate::deposit_data::DepositData;
pub use crate::deposit_message::DepositMessage;
pub use crate::eth1_data::Eth1Data;
pub use crate::fork::Fork;
pub use crate::free_attestation::FreeAttestation;
@@ -60,8 +65,11 @@ pub use crate::indexed_attestation::IndexedAttestation;
pub use crate::pending_attestation::PendingAttestation;
pub use crate::proposer_slashing::ProposerSlashing;
pub use crate::relative_epoch::{Error as RelativeEpochError, RelativeEpoch};
pub use crate::signed_beacon_block::SignedBeaconBlock;
pub use crate::signed_beacon_block_header::SignedBeaconBlockHeader;
pub use crate::signed_voluntary_exit::SignedVoluntaryExit;
pub use crate::signing_root::{SignedRoot, SigningRoot};
pub use crate::slot_epoch::{Epoch, Slot};
pub use crate::slot_height::SlotHeight;
pub use crate::validator::Validator;
pub use crate::voluntary_exit::VoluntaryExit;

View File

@@ -8,7 +8,7 @@ use tree_hash_derive::TreeHash;
/// An attestation that has been included in the state but not yet fully processed.
///
/// Spec v0.9.1
/// Spec v0.10.1
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct PendingAttestation<T: EthSpec> {
pub aggregation_bits: BitList<T::MaxValidatorsPerCommittee>,
@@ -22,5 +22,5 @@ mod tests {
use super::*;
use crate::*;
ssz_tests!(PendingAttestation<MainnetEthSpec>);
ssz_and_tree_hash_tests!(PendingAttestation<MainnetEthSpec>);
}

View File

@@ -1,5 +1,5 @@
use super::BeaconBlockHeader;
use crate::test_utils::TestRandom;
use crate::SignedBeaconBlockHeader;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
@@ -8,17 +8,17 @@ use tree_hash_derive::TreeHash;
/// Two conflicting proposals from the same proposer (validator).
///
/// Spec v0.9.1
/// Spec v0.10.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct ProposerSlashing {
pub proposer_index: u64,
pub header_1: BeaconBlockHeader,
pub header_2: BeaconBlockHeader,
pub signed_header_1: SignedBeaconBlockHeader,
pub signed_header_2: SignedBeaconBlockHeader,
}
#[cfg(test)]
mod tests {
use super::*;
ssz_tests!(ProposerSlashing);
ssz_and_tree_hash_tests!(ProposerSlashing);
}

View File

@@ -9,7 +9,7 @@ pub enum Error {
/// Defines the epochs relative to some epoch. Most useful when referring to the committees prior
/// to and following some epoch.
///
/// Spec v0.9.1
/// Spec v0.10.1
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum RelativeEpoch {
/// The prior epoch.
@@ -23,7 +23,7 @@ pub enum RelativeEpoch {
impl RelativeEpoch {
/// Returns the `epoch` that `self` refers to, with respect to the `base` epoch.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn into_epoch(self, base: Epoch) -> Epoch {
match self {
// Due to saturating nature of epoch, check for current first.
@@ -40,7 +40,7 @@ impl RelativeEpoch {
/// - `EpochTooLow` when `other` is more than 1 prior to `base`.
/// - `EpochTooHigh` when `other` is more than 1 after `base`.
///
/// Spec v0.9.1
/// Spec v0.10.1
pub fn from_epoch(base: Epoch, other: Epoch) -> Result<Self, Error> {
// Due to saturating nature of epoch, check for current first.
if other == base {

View File

@@ -0,0 +1,49 @@
use crate::{test_utils::TestRandom, BeaconBlock, EthSpec, Hash256, Slot};
use bls::Signature;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
/// A `BeaconBlock` and a signature from its proposer.
///
/// Spec v0.10.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TestRandom)]
#[serde(bound = "E: EthSpec")]
pub struct SignedBeaconBlock<E: EthSpec> {
pub message: BeaconBlock<E>,
pub signature: Signature,
}
impl<E: EthSpec> SignedBeaconBlock<E> {
/// Convenience accessor for the block's slot.
pub fn slot(&self) -> Slot {
self.message.slot
}
/// Convenience accessor for the block's parent root.
pub fn parent_root(&self) -> Hash256 {
self.message.parent_root
}
/// Convenience accessor for the block's state root.
pub fn state_root(&self) -> Hash256 {
self.message.state_root
}
/// Returns the `tree_hash_root` of the block.
///
/// Spec v0.10.1
pub fn canonical_root(&self) -> Hash256 {
Hash256::from_slice(&self.message.tree_hash_root()[..])
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::MainnetEthSpec;
ssz_tests!(SignedBeaconBlock<MainnetEthSpec>);
}

View File

@@ -0,0 +1,23 @@
use crate::{test_utils::TestRandom, BeaconBlockHeader};
use bls::Signature;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
/// An exit voluntarily submitted a validator who wishes to withdraw.
///
/// Spec v0.10.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct SignedBeaconBlockHeader {
pub message: BeaconBlockHeader,
pub signature: Signature,
}
#[cfg(test)]
mod tests {
use super::*;
ssz_and_tree_hash_tests!(SignedBeaconBlockHeader);
}

View File

@@ -0,0 +1,23 @@
use crate::{test_utils::TestRandom, VoluntaryExit};
use bls::Signature;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
/// An exit voluntarily submitted a validator who wishes to withdraw.
///
/// Spec v0.10.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct SignedVoluntaryExit {
pub message: VoluntaryExit,
pub signature: Signature,
}
#[cfg(test)]
mod tests {
use super::*;
ssz_and_tree_hash_tests!(SignedVoluntaryExit);
}

View File

@@ -0,0 +1,25 @@
use crate::test_utils::TestRandom;
use crate::Hash256;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
use tree_hash_derive::TreeHash;
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct SigningRoot {
pub object_root: Hash256,
pub domain: u64,
}
pub trait SignedRoot: TreeHash {
fn signing_root(&self, domain: u64) -> Hash256 {
Hash256::from_slice(
&SigningRoot {
object_root: Hash256::from_slice(&self.tree_hash_root()),
domain,
}
.tree_hash_root(),
)
}
}

View File

@@ -10,8 +10,8 @@
//! implement `Into<u64>`, however this would allow operations between `Slots` and `Epochs` which
//! may lead to programming errors which are not detected by the compiler.
use crate::slot_height::SlotHeight;
use crate::test_utils::TestRandom;
use crate::SignedRoot;
use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
use slog;
@@ -41,10 +41,6 @@ impl Slot {
Epoch::from(self.0 / slots_per_epoch)
}
pub fn height(self, genesis_slot: Slot) -> SlotHeight {
SlotHeight::from(self.0.saturating_sub(genesis_slot.as_u64()))
}
pub fn max_value() -> Slot {
Slot(u64::max_value())
}
@@ -97,6 +93,8 @@ impl Epoch {
}
}
impl SignedRoot for Epoch {}
pub struct SlotIter<'a> {
current_iteration: u64,
epoch: &'a Epoch,

View File

@@ -562,7 +562,7 @@ macro_rules! all_tests {
new_tests!($type);
math_between_tests!($type, $type);
math_tests!($type);
ssz_tests!($type);
ssz_and_tree_hash_tests!($type);
mod u64_tests {
use super::*;

View File

@@ -1,41 +0,0 @@
use crate::slot_epoch::{Epoch, Slot};
use crate::test_utils::TestRandom;
use rand::RngCore;
use serde_derive::Serialize;
use ssz::{ssz_encode, Decode, DecodeError, Encode};
use std::cmp::{Ord, Ordering};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, Sub, SubAssign};
/// Beacon block height, effectively `Slot/GENESIS_START_BLOCK`.
#[derive(Eq, Debug, Clone, Copy, Default, Serialize)]
pub struct SlotHeight(u64);
impl_common!(SlotHeight);
impl SlotHeight {
pub fn new(slot: u64) -> SlotHeight {
SlotHeight(slot)
}
pub fn slot(self, genesis_slot: Slot) -> Slot {
Slot::from(self.0.saturating_add(genesis_slot.as_u64()))
}
pub fn epoch(self, genesis_slot: u64, slots_per_epoch: u64) -> Epoch {
Epoch::from(self.0.saturating_add(genesis_slot) / slots_per_epoch)
}
pub fn max_value() -> SlotHeight {
SlotHeight(u64::max_value())
}
}
#[cfg(test)]
mod slot_height_tests {
use super::*;
all_tests!(SlotHeight);
}

View File

@@ -1,6 +1,5 @@
use crate::test_utils::{AttestationTestTask, TestingAttestationDataBuilder};
use crate::*;
use tree_hash::TreeHash;
/// Builds an attestation to be used for testing purposes.
///
@@ -71,31 +70,22 @@ impl<T: EthSpec> TestingAttestationBuilder<T> {
.position(|v| *v == *validator_index)
.expect("Signing validator not in attestation committee");
match test_task {
AttestationTestTask::BadIndexedAttestationBadSignature => (),
_ => {
self.attestation
.aggregation_bits
.set(committee_index, true)
.unwrap();
}
}
let message = self.attestation.data.tree_hash_root();
let domain = spec.get_domain(
self.attestation.data.target.epoch,
Domain::BeaconAttester,
fork,
);
let index = if test_task == AttestationTestTask::BadSignature {
0
} else {
key_index
};
let signature = Signature::new(&message, domain, secret_keys[index]);
self.attestation.signature.add(&signature)
self.attestation
.sign(secret_keys[index], committee_index, fork, spec)
.expect("can sign attestation");
if let AttestationTestTask::BadIndexedAttestationBadSignature = test_task {
self.attestation
.aggregation_bits
.set(committee_index, false)
.unwrap();
}
}
self

View File

@@ -55,11 +55,12 @@ impl TestingAttestationDataBuilder {
slot = state.slot - spec.min_attestation_inclusion_delay + 1
}
AttestationTestTask::IncludedTooLate => slot -= T::SlotsPerEpoch::to_u64(),
AttestationTestTask::BadTargetEpoch => {
AttestationTestTask::TargetEpochSlotMismatch => {
target = Checkpoint {
epoch: Epoch::from(5 as u64),
epoch: current_epoch + 1,
root: Hash256::zero(),
}
};
assert_ne!(target.epoch, slot.epoch(T::slots_per_epoch()));
}
AttestationTestTask::WrongJustifiedCheckpoint => {
source = Checkpoint {
@@ -67,18 +68,6 @@ impl TestingAttestationDataBuilder {
root: Hash256::zero(),
}
}
AttestationTestTask::BadTargetTooLow => {
target = Checkpoint {
epoch: Epoch::from(0 as u64),
root: Hash256::zero(),
}
}
AttestationTestTask::BadTargetTooHigh => {
target = Checkpoint {
epoch: Epoch::from(10 as u64),
root: Hash256::zero(),
}
}
_ => (),
}

View File

@@ -1,6 +1,5 @@
use crate::test_utils::AttesterSlashingTestTask;
use crate::*;
use tree_hash::TreeHash;
/// Builds an `AttesterSlashing`.
///
@@ -22,14 +21,15 @@ impl TestingAttesterSlashingBuilder {
test_task: AttesterSlashingTestTask,
validator_indices: &[u64],
signer: F,
fork: &Fork,
spec: &ChainSpec,
) -> AttesterSlashing<T>
where
F: Fn(u64, &[u8], Epoch, Domain) -> Signature,
F: Fn(u64, &[u8]) -> Signature,
{
let slot = Slot::new(1);
let index = 0;
let epoch_1 = Epoch::new(1);
let epoch_2 = Epoch::new(2);
let hash_1 = Hash256::from_low_u64_le(1);
let hash_2 = Hash256::from_low_u64_le(2);
let checkpoint_1 = Checkpoint {
@@ -83,15 +83,12 @@ impl TestingAttesterSlashingBuilder {
};
let add_signatures = |attestation: &mut IndexedAttestation<T>| {
let message = attestation.data.tree_hash_root();
let domain =
spec.get_domain(attestation.data.target.epoch, Domain::BeaconAttester, fork);
let message = attestation.data.signing_root(domain);
for validator_index in validator_indices {
let signature = signer(
*validator_index,
&message[..],
epoch_2,
Domain::BeaconAttester,
);
let signature = signer(*validator_index, message.as_bytes());
attestation.signature.add(&signature);
}
};

View File

@@ -9,7 +9,7 @@ use crate::{
use int_to_bytes::int_to_bytes32;
use merkle_proof::MerkleTree;
use rayon::prelude::*;
use tree_hash::{SignedRoot, TreeHash};
use tree_hash::TreeHash;
/// Builds a beacon block to be used for testing purposes.
///
@@ -46,8 +46,6 @@ pub enum AttestationTestTask {
Valid,
NoCommiteeForShard,
WrongJustifiedCheckpoint,
BadTargetTooLow,
BadTargetTooHigh,
BadShard,
BadIndexedAttestationBadSignature,
BadAggregationBitfieldLen,
@@ -55,7 +53,9 @@ pub enum AttestationTestTask {
ValidatorUnknown,
IncludedTooEarly,
IncludedTooLate,
BadTargetEpoch,
TargetEpochSlotMismatch,
// Note: BadTargetEpoch is unreachable in block processing due to valid inclusion window and
// slot check
}
/// Enum used for passing test options to builder
@@ -97,24 +97,14 @@ impl<T: EthSpec> TestingBeaconBlockBuilder<T> {
self.block.slot = slot;
}
/// Signs the block.
///
/// Modifying the block after signing may invalidate the signature.
pub fn sign(&mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) {
let message = self.block.signed_root();
let epoch = self.block.slot.epoch(T::slots_per_epoch());
let domain = spec.get_domain(epoch, Domain::BeaconProposer, fork);
self.block.signature = Signature::new(&message, domain, sk);
}
/// Sets the randao to be a signature across the blocks epoch.
///
/// Modifying the block's slot after signing may invalidate the signature.
pub fn set_randao_reveal(&mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) {
let epoch = self.block.slot.epoch(T::slots_per_epoch());
let message = epoch.tree_hash_root();
let domain = spec.get_domain(epoch, Domain::Randao, fork);
self.block.body.randao_reveal = Signature::new(&message, domain, sk);
let message = epoch.signing_root(domain);
self.block.body.randao_reveal = Signature::new(message.as_bytes(), sk);
}
/// Has the randao reveal been set?
@@ -364,26 +354,23 @@ impl<T: EthSpec> TestingBeaconBlockBuilder<T> {
_ => (),
}
let mut builder = TestingVoluntaryExitBuilder::new(exit_epoch, validator_index);
let builder = TestingVoluntaryExitBuilder::new(exit_epoch, validator_index);
let exit = builder.build(sk, &state.fork, spec);
builder.sign(sk, &state.fork, spec);
self.block
.body
.voluntary_exits
.push(builder.build())
.unwrap();
self.block.body.voluntary_exits.push(exit).unwrap();
}
/// Signs and returns the block, consuming the builder.
pub fn build(mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) -> BeaconBlock<T> {
self.sign(sk, fork, spec);
self.block
pub fn build(self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) -> SignedBeaconBlock<T> {
self.block.sign(sk, fork, spec)
}
/// Returns the block, consuming the builder.
pub fn build_without_signing(self) -> BeaconBlock<T> {
self.block
pub fn build_without_signing(self) -> SignedBeaconBlock<T> {
SignedBeaconBlock {
message: self.block,
signature: Signature::empty_signature(),
}
}
}
@@ -397,12 +384,13 @@ fn build_proposer_slashing<T: EthSpec>(
fork: &Fork,
spec: &ChainSpec,
) -> ProposerSlashing {
let signer = |_validator_index: u64, message: &[u8], epoch: Epoch, domain: Domain| {
let domain = spec.get_domain(epoch, domain, fork);
Signature::new(message, domain, secret_key)
};
TestingProposerSlashingBuilder::double_vote::<T, _>(test_task, validator_index, signer)
TestingProposerSlashingBuilder::double_vote::<T>(
test_task,
validator_index,
secret_key,
fork,
spec,
)
}
/// Builds an `AttesterSlashing` for some `validator_indices`.
@@ -415,14 +403,13 @@ fn build_double_vote_attester_slashing<T: EthSpec>(
fork: &Fork,
spec: &ChainSpec,
) -> AttesterSlashing<T> {
let signer = |validator_index: u64, message: &[u8], epoch: Epoch, domain: Domain| {
let signer = |validator_index: u64, message: &[u8]| {
let key_index = validator_indices
.iter()
.position(|&i| i == validator_index)
.expect("Unable to find attester slashing key");
let domain = spec.get_domain(epoch, domain, fork);
Signature::new(message, domain, secret_keys[key_index])
Signature::new(message, secret_keys[key_index])
};
TestingAttesterSlashingBuilder::double_vote(test_task, validator_indices, signer)
TestingAttesterSlashingBuilder::double_vote(test_task, validator_indices, signer, fork, spec)
}

View File

@@ -1,31 +1,24 @@
use crate::test_utils::ProposerSlashingTestTask;
use crate::*;
use tree_hash::SignedRoot;
/// Builds a `ProposerSlashing`.
///
/// This struct should **never be used for production purposes.**
pub struct TestingProposerSlashingBuilder();
pub struct TestingProposerSlashingBuilder;
impl TestingProposerSlashingBuilder {
/// Builds a `ProposerSlashing` that is a double vote.
///
/// The `signer` function is used to sign the double-vote and accepts:
///
/// - `validator_index: u64`
/// - `message: &[u8]`
/// - `epoch: Epoch`
/// - `domain: Domain`
///
/// Where domain is a domain "constant" (e.g., `spec.domain_attestation`).
pub fn double_vote<T, F>(
pub fn double_vote<T>(
test_task: ProposerSlashingTestTask,
mut proposer_index: u64,
signer: F,
secret_key: &SecretKey,
fork: &Fork,
spec: &ChainSpec,
) -> ProposerSlashing
where
T: EthSpec,
F: Fn(u64, &[u8], Epoch, Domain) -> Signature,
{
let slot = Slot::new(0);
let hash_1 = Hash256::from([1; 32]);
@@ -35,11 +28,13 @@ impl TestingProposerSlashingBuilder {
Hash256::from([2; 32])
};
let mut header_1 = BeaconBlockHeader {
slot,
parent_root: hash_1,
state_root: hash_1,
body_root: hash_1,
let mut signed_header_1 = SignedBeaconBlockHeader {
message: BeaconBlockHeader {
slot,
parent_root: hash_1,
state_root: hash_1,
body_root: hash_1,
},
signature: Signature::empty_signature(),
};
@@ -49,26 +44,21 @@ impl TestingProposerSlashingBuilder {
Slot::new(0)
};
let mut header_2 = BeaconBlockHeader {
parent_root: hash_2,
slot: slot_2,
..header_1.clone()
let mut signed_header_2 = SignedBeaconBlockHeader {
message: BeaconBlockHeader {
parent_root: hash_2,
slot: slot_2,
..signed_header_1.message.clone()
},
signature: Signature::empty_signature(),
};
let epoch = slot.epoch(T::slots_per_epoch());
if test_task != ProposerSlashingTestTask::BadProposal1Signature {
header_1.signature = {
let message = header_1.signed_root();
signer(proposer_index, &message[..], epoch, Domain::BeaconProposer)
};
signed_header_1 = signed_header_1.message.sign::<T>(secret_key, fork, spec);
}
if test_task != ProposerSlashingTestTask::BadProposal2Signature {
header_2.signature = {
let message = header_2.signed_root();
signer(proposer_index, &message[..], epoch, Domain::BeaconProposer)
};
signed_header_2 = signed_header_2.message.sign::<T>(secret_key, fork, spec);
}
if test_task == ProposerSlashingTestTask::ProposerUnknown {
@@ -77,8 +67,8 @@ impl TestingProposerSlashingBuilder {
ProposerSlashing {
proposer_index,
header_1,
header_2,
signed_header_1,
signed_header_2,
}
}
}

View File

@@ -1,5 +1,4 @@
use crate::*;
use tree_hash::SignedRoot;
/// Builds an exit to be used for testing purposes.
///
@@ -14,24 +13,20 @@ impl TestingVoluntaryExitBuilder {
let exit = VoluntaryExit {
epoch,
validator_index,
signature: Signature::empty_signature(),
};
Self { exit }
}
/// Signs the exit.
/// Build and sign the exit.
///
/// The signing secret key must match that of the exiting validator.
pub fn sign(&mut self, secret_key: &SecretKey, fork: &Fork, spec: &ChainSpec) {
let message = self.exit.signed_root();
let domain = spec.get_domain(self.exit.epoch, Domain::VoluntaryExit, fork);
self.exit.signature = Signature::new(&message, domain, secret_key);
}
/// Builds the exit, consuming the builder.
pub fn build(self) -> VoluntaryExit {
self.exit
pub fn build(
self,
secret_key: &SecretKey,
fork: &Fork,
spec: &ChainSpec,
) -> SignedVoluntaryExit {
self.exit.sign(secret_key, fork, spec)
}
}

View File

@@ -1,4 +1,13 @@
#[cfg(test)]
#![cfg(test)]
#[macro_export]
macro_rules! ssz_and_tree_hash_tests {
($type: ty) => {
ssz_tests!($type);
tree_hash_tests!($type);
};
}
#[macro_export]
macro_rules! ssz_tests {
($type: ty) => {
@@ -16,7 +25,12 @@ macro_rules! ssz_tests {
assert_eq!(original, decoded);
}
};
}
#[macro_export]
macro_rules! tree_hash_tests {
($type: ty) => {
#[test]
pub fn test_tree_hash_root() {
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
@@ -28,8 +42,6 @@ macro_rules! ssz_tests {
let result = original.tree_hash_root();
assert_eq!(result.len(), 32);
// TODO: Add further tests
// https://github.com/sigp/lighthouse/issues/170
}
};
}

View File

@@ -7,6 +7,6 @@ impl TestRandom for Signature {
let mut message = vec![0; 32];
rng.fill_bytes(&mut message);
Signature::new(&message, 0, &secret_key)
Signature::new(&message, &secret_key)
}
}

View File

@@ -1,4 +1,6 @@
use crate::{test_utils::TestRandom, Epoch, Hash256, PublicKeyBytes};
use crate::{
test_utils::TestRandom, BeaconState, ChainSpec, Epoch, EthSpec, Hash256, PublicKeyBytes,
};
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
@@ -6,7 +8,7 @@ use tree_hash_derive::TreeHash;
/// Information about a `BeaconChain` validator.
///
/// Spec v0.9.1
/// Spec v0.10.1
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom, TreeHash)]
pub struct Validator {
pub pubkey: PublicKeyBytes,
@@ -39,6 +41,28 @@ impl Validator {
pub fn is_withdrawable_at(&self, epoch: Epoch) -> bool {
epoch >= self.withdrawable_epoch
}
/// Returns `true` if the validator is eligible to join the activation queue.
///
/// Spec v0.10.1
pub fn is_eligible_for_activation_queue(&self, spec: &ChainSpec) -> bool {
self.activation_eligibility_epoch == spec.far_future_epoch
&& self.effective_balance == spec.max_effective_balance
}
/// Returns `true` if the validator is eligible to be activated.
///
/// Spec v0.10.1
pub fn is_eligible_for_activation<E: EthSpec>(
&self,
state: &BeaconState<E>,
spec: &ChainSpec,
) -> bool {
// Placement in queue is finalized
self.activation_eligibility_epoch <= state.finalized_checkpoint.epoch
// Has not yet been activated
&& self.activation_epoch == spec.far_future_epoch
}
}
impl Default for Validator {
@@ -115,5 +139,5 @@ mod tests {
assert_eq!(v.is_withdrawable_at(epoch + 1), true);
}
ssz_tests!(Validator);
ssz_and_tree_hash_tests!(Validator);
}

View File

@@ -1,38 +1,45 @@
use crate::{test_utils::TestRandom, Epoch};
use bls::Signature;
use crate::{
test_utils::TestRandom, ChainSpec, Domain, Epoch, Fork, SecretKey, Signature, SignedRoot,
SignedVoluntaryExit,
};
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash_derive::TreeHash;
/// An exit voluntarily submitted a validator who wishes to withdraw.
///
/// Spec v0.9.1
#[derive(
Debug,
PartialEq,
Clone,
Serialize,
Deserialize,
Encode,
Decode,
TreeHash,
TestRandom,
SignedRoot,
)]
/// Spec v0.10.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct VoluntaryExit {
/// Earliest epoch when voluntary exit can be processed.
pub epoch: Epoch,
pub validator_index: u64,
#[signed_root(skip_hashing)]
pub signature: Signature,
}
impl SignedRoot for VoluntaryExit {}
impl VoluntaryExit {
pub fn sign(
self,
secret_key: &SecretKey,
fork: &Fork,
spec: &ChainSpec,
) -> SignedVoluntaryExit {
let domain = spec.get_domain(self.epoch, Domain::VoluntaryExit, fork);
let message = self.signing_root(domain);
let signature = Signature::new(message.as_bytes(), &secret_key);
SignedVoluntaryExit {
message: self,
signature,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
ssz_tests!(VoluntaryExit);
ssz_and_tree_hash_tests!(VoluntaryExit);
}