diff --git a/eth2/types/src/beacon_block.rs b/eth2/types/src/beacon_block.rs index 9e1b3f7ae..b67c866a4 100644 --- a/eth2/types/src/beacon_block.rs +++ b/eth2/types/src/beacon_block.rs @@ -23,6 +23,8 @@ pub struct BeaconBlock { impl BeaconBlock { /// Produce the first block of the Beacon Chain. + /// + /// Spec v0.4.0 pub fn genesis(state_root: Hash256, spec: &ChainSpec) -> BeaconBlock { BeaconBlock { slot: spec.genesis_slot, @@ -46,11 +48,15 @@ impl BeaconBlock { } /// Returns the `hash_tree_root` of the block. + /// + /// Spec v0.4.0 pub fn canonical_root(&self) -> Hash256 { Hash256::from_slice(&self.hash_tree_root()[..]) } /// Returns an unsigned proposal for block. + /// + /// Spec v0.4.0 pub fn proposal(&self, spec: &ChainSpec) -> Proposal { Proposal { slot: self.slot, diff --git a/eth2/types/src/beacon_state.rs b/eth2/types/src/beacon_state.rs index f69746dae..b4faa6a49 100644 --- a/eth2/types/src/beacon_state.rs +++ b/eth2/types/src/beacon_state.rs @@ -6,7 +6,6 @@ use honey_badger_split::SplitExt; use int_to_bytes::int_to_bytes32; use log::{debug, error, trace}; use rand::RngCore; -use rayon::prelude::*; use serde_derive::Serialize; use ssz::{hash, Decodable, DecodeError, Encodable, SignedRoot, SszStream, TreeHash}; use std::collections::HashMap; @@ -113,6 +112,11 @@ pub struct BeaconState { impl BeaconState { /// Produce the first state of the Beacon Chain. + /// + /// This does not fully build a genesis beacon state, it omits processing of initial validator + /// deposits. To obtain a full genesis beacon state, use the `BeaconStateBuilder`. + /// + /// Spec v0.4.0 pub fn genesis(genesis_time: u64, latest_eth1_data: Eth1Data, spec: &ChainSpec) -> BeaconState { let initial_crosslink = Crosslink { epoch: spec.genesis_epoch, @@ -185,44 +189,9 @@ impl BeaconState { } } - /// Produce the first state of the Beacon Chain. - pub fn process_initial_deposits( - &mut self, - initial_validator_deposits: Vec, - spec: &ChainSpec, - ) -> Result<(), Error> { - debug!("Processing genesis deposits..."); - - let deposit_data = initial_validator_deposits - .par_iter() - .map(|deposit| &deposit.deposit_data) - .collect(); - - self.process_deposits(deposit_data, spec); - - trace!("Processed genesis deposits."); - - for validator_index in 0..self.validator_registry.len() { - if self.get_effective_balance(validator_index, spec) >= spec.max_deposit_amount { - self.activate_validator(validator_index, true, spec); - } - } - - self.deposit_index = initial_validator_deposits.len() as u64; - - let genesis_active_index_root = hash_tree_root(get_active_validator_indices( - &self.validator_registry, - spec.genesis_epoch, - )); - self.latest_active_index_roots = - vec![genesis_active_index_root; spec.latest_active_index_roots_length]; - - self.current_shuffling_seed = self.generate_seed(spec.genesis_epoch, spec)?; - - Ok(()) - } - /// Returns the `hash_tree_root` of the state. + /// + /// Spec v0.4.0 pub fn canonical_root(&self) -> Hash256 { Hash256::from_slice(&self.hash_tree_root()[..]) } @@ -1129,10 +1098,6 @@ impl BeaconState { } } -fn hash_tree_root(input: Vec) -> Hash256 { - Hash256::from_slice(&input.hash_tree_root()[..]) -} - impl Encodable for BeaconState { fn ssz_append(&self, s: &mut SszStream) { s.append(&self.slot); diff --git a/eth2/types/src/test_utils/keypairs_file.rs b/eth2/types/src/test_utils/keypairs_file.rs index ebc50f528..a1ea4d928 100644 --- a/eth2/types/src/test_utils/keypairs_file.rs +++ b/eth2/types/src/test_utils/keypairs_file.rs @@ -12,12 +12,17 @@ pub const BATCH_SIZE: usize = 1_000; // ~15MB pub const KEYPAIR_BYTES_LEN: usize = PUBLIC_KEY_BYTES_LEN + SECRET_KEY_BYTES_LEN; pub const BATCH_BYTE_LEN: usize = KEYPAIR_BYTES_LEN * BATCH_SIZE; +/// Defines a trait that allows reading/writing a vec of `Keypair` from/to a file. pub trait KeypairsFile { + /// Write to file, without guaranteeing interoperability with other clients. fn to_raw_file(&self, path: &Path, keypairs: &[Keypair]) -> Result<(), Error>; + /// Read from file, without guaranteeing interoperability with other clients. fn from_raw_file(path: &Path, count: usize) -> Result, Error>; } impl KeypairsFile for Vec { + /// Write the keypairs to file, using the fastest possible method without guaranteeing + /// interoperability with other clients. fn to_raw_file(&self, path: &Path, keypairs: &[Keypair]) -> Result<(), Error> { let mut keypairs_file = File::create(path)?; @@ -35,6 +40,8 @@ impl KeypairsFile for Vec { Ok(()) } + /// Read the keypairs from file, using the fastest possible method without guaranteeing + /// interoperability with other clients. fn from_raw_file(path: &Path, count: usize) -> Result, Error> { let mut keypairs_file = File::open(path)?; diff --git a/eth2/types/src/test_utils/testing_attestation_builder.rs b/eth2/types/src/test_utils/testing_attestation_builder.rs index f52edadfe..8c86d756d 100644 --- a/eth2/types/src/test_utils/testing_attestation_builder.rs +++ b/eth2/types/src/test_utils/testing_attestation_builder.rs @@ -1,12 +1,16 @@ use crate::*; use ssz::TreeHash; +/// Builds an attestation to be used for testing purposes. +/// +/// This struct should **never be used for production purposes.** pub struct TestingAttestationBuilder { committee: Vec, attestation: Attestation, } impl TestingAttestationBuilder { + /// Create a new attestation builder. pub fn new( state: &BeaconState, committee: &[usize], @@ -70,6 +74,10 @@ impl TestingAttestationBuilder { } } + /// Signs the attestation with a subset (or all) committee members. + /// + /// `secret_keys` must be supplied in the same order as `signing_validators`. I.e., the first + /// keypair must be that of the first signing validator. pub fn sign( &mut self, signing_validators: &[usize], @@ -111,6 +119,7 @@ impl TestingAttestationBuilder { } } + /// Consume the builder and return the attestation. pub fn build(self) -> Attestation { self.attestation } diff --git a/eth2/types/src/test_utils/testing_attester_slashing_builder.rs b/eth2/types/src/test_utils/testing_attester_slashing_builder.rs index d9da3db2d..232de87ec 100644 --- a/eth2/types/src/test_utils/testing_attester_slashing_builder.rs +++ b/eth2/types/src/test_utils/testing_attester_slashing_builder.rs @@ -2,6 +2,8 @@ use crate::*; use ssz::TreeHash; /// Builds an `AttesterSlashing`. +/// +/// This struct should **never be used for production purposes.** pub struct TestingAttesterSlashingBuilder(); impl TestingAttesterSlashingBuilder { diff --git a/eth2/types/src/test_utils/testing_beacon_block_builder.rs b/eth2/types/src/test_utils/testing_beacon_block_builder.rs index 3ebd24b0a..97e395e1f 100644 --- a/eth2/types/src/test_utils/testing_beacon_block_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_block_builder.rs @@ -8,22 +8,29 @@ use crate::{ use rayon::prelude::*; use ssz::{SignedRoot, TreeHash}; +/// Builds a beacon block to be used for testing purposes. +/// +/// This struct should **never be used for production purposes.** pub struct TestingBeaconBlockBuilder { block: BeaconBlock, } impl TestingBeaconBlockBuilder { + /// Create a new builder from genesis. pub fn new(spec: &ChainSpec) -> Self { Self { block: BeaconBlock::genesis(spec.zero_hash, spec), } } + /// Set the slot of the block. pub fn set_slot(&mut self, slot: Slot) { 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 proposal = self.block.proposal(spec); let message = proposal.signed_root(); @@ -33,6 +40,8 @@ impl TestingBeaconBlockBuilder { } /// 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(spec.slots_per_epoch); let message = epoch.hash_tree_root(); @@ -65,9 +74,15 @@ impl TestingBeaconBlockBuilder { self.block.body.attester_slashings.push(attester_slashing); } - /// Fills the block with as many attestations as possible. + /// Fills the block with `MAX_ATTESTATIONS` attestations. /// - /// Note: this will not perform well when `jepoch_committees_count % slots_per_epoch != 0` + /// It will first go and get each committee that is able to include an attestation in this + /// block. If there are enough committees, it will produce an attestation for each. If there + /// are _not_ enough committees, it will start splitting the committees in half until it + /// achieves the target. It will then produce separate attestations for each split committee. + /// + /// Note: the signed messages of the split committees will be identical -- it would be possible + /// to aggregate these split attestations. pub fn fill_with_attestations( &mut self, state: &BeaconState, diff --git a/eth2/types/src/test_utils/testing_beacon_state_builder.rs b/eth2/types/src/test_utils/testing_beacon_state_builder.rs index afefa4063..b2cf28c8a 100644 --- a/eth2/types/src/test_utils/testing_beacon_state_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_state_builder.rs @@ -20,6 +20,9 @@ pub fn keypairs_path() -> PathBuf { dir.join(KEYPAIRS_FILE) } +/// Builds a beacon state to be used for testing purposes. +/// +/// This struct should **never be used for production purposes.** pub struct TestingBeaconStateBuilder { state: BeaconState, keypairs: Vec, diff --git a/eth2/types/src/test_utils/testing_deposit_builder.rs b/eth2/types/src/test_utils/testing_deposit_builder.rs index 56e81cad0..729311468 100644 --- a/eth2/types/src/test_utils/testing_deposit_builder.rs +++ b/eth2/types/src/test_utils/testing_deposit_builder.rs @@ -1,11 +1,15 @@ use crate::*; use bls::get_withdrawal_credentials; +/// Builds an deposit to be used for testing purposes. +/// +/// This struct should **never be used for production purposes.** pub struct TestingDepositBuilder { deposit: Deposit, } impl TestingDepositBuilder { + /// Instantiates a new builder. pub fn new(amount: u64) -> Self { let keypair = Keypair::random(); @@ -26,10 +30,16 @@ impl TestingDepositBuilder { Self { deposit } } + /// Set the `deposit.index` value. pub fn set_index(&mut self, index: u64) { self.deposit.index = index; } + /// Signs the deposit, also setting the following values: + /// + /// - `pubkey` to the signing pubkey. + /// - `withdrawal_credentials` to the signing pubkey. + /// - `proof_of_possesssion` pub fn sign(&mut self, keypair: &Keypair, state: &BeaconState, spec: &ChainSpec) { let withdrawal_credentials = Hash256::from_slice( &get_withdrawal_credentials(&keypair.pk, spec.bls_withdrawal_prefix_byte)[..], @@ -47,6 +57,7 @@ impl TestingDepositBuilder { DepositInput::create_proof_of_possession(&keypair, &withdrawal_credentials, domain); } + /// Builds the deposit, consuming the builder. pub fn build(self) -> Deposit { self.deposit } diff --git a/eth2/types/src/test_utils/testing_proposer_slashing_builder.rs b/eth2/types/src/test_utils/testing_proposer_slashing_builder.rs index 43ff3d0b7..7f16b679f 100644 --- a/eth2/types/src/test_utils/testing_proposer_slashing_builder.rs +++ b/eth2/types/src/test_utils/testing_proposer_slashing_builder.rs @@ -2,6 +2,8 @@ use crate::*; use ssz::SignedRoot; /// Builds a `ProposerSlashing`. +/// +/// This struct should **never be used for production purposes.** pub struct TestingProposerSlashingBuilder(); impl TestingProposerSlashingBuilder { diff --git a/eth2/types/src/test_utils/testing_transfer_builder.rs b/eth2/types/src/test_utils/testing_transfer_builder.rs index c343e8fd2..c4256ebea 100644 --- a/eth2/types/src/test_utils/testing_transfer_builder.rs +++ b/eth2/types/src/test_utils/testing_transfer_builder.rs @@ -1,11 +1,15 @@ use crate::*; use ssz::SignedRoot; +/// Builds a transfer to be used for testing purposes. +/// +/// This struct should **never be used for production purposes.** pub struct TestingTransferBuilder { transfer: Transfer, } impl TestingTransferBuilder { + /// Instantiates a new builder. pub fn new(from: u64, to: u64, amount: u64, slot: Slot) -> Self { let keypair = Keypair::random(); @@ -22,6 +26,9 @@ impl TestingTransferBuilder { Self { transfer } } + /// Signs the transfer. + /// + /// The keypair must match that of the `from` validator index. pub fn sign(&mut self, keypair: Keypair, fork: &Fork, spec: &ChainSpec) { self.transfer.pubkey = keypair.pk; let message = self.transfer.signed_root(); @@ -31,6 +38,7 @@ impl TestingTransferBuilder { self.transfer.signature = Signature::new(&message, domain, &keypair.sk); } + /// Builds the transfer, consuming the builder. pub fn build(self) -> Transfer { self.transfer } diff --git a/eth2/types/src/test_utils/testing_voluntary_exit_builder.rs b/eth2/types/src/test_utils/testing_voluntary_exit_builder.rs index 92ef4484e..fe5c8325a 100644 --- a/eth2/types/src/test_utils/testing_voluntary_exit_builder.rs +++ b/eth2/types/src/test_utils/testing_voluntary_exit_builder.rs @@ -1,11 +1,15 @@ use crate::*; use ssz::SignedRoot; +/// Builds an exit to be used for testing purposes. +/// +/// This struct should **never be used for production purposes.** pub struct TestingVoluntaryExitBuilder { exit: VoluntaryExit, } impl TestingVoluntaryExitBuilder { + /// Instantiates a new builder. pub fn new(epoch: Epoch, validator_index: u64) -> Self { let exit = VoluntaryExit { epoch, @@ -16,6 +20,9 @@ impl TestingVoluntaryExitBuilder { Self { exit } } + /// Signs 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::Exit, fork); @@ -23,6 +30,7 @@ impl TestingVoluntaryExitBuilder { self.exit.signature = Signature::new(&message, domain, secret_key); } + /// Builds the exit, consuming the builder. pub fn build(self) -> VoluntaryExit { self.exit }