diff --git a/eth2/types/src/attestation.rs b/eth2/types/src/attestation.rs index a0c8505b8..03ef8ce48 100644 --- a/eth2/types/src/attestation.rs +++ b/eth2/types/src/attestation.rs @@ -1,12 +1,15 @@ -use super::{AggregatePublicKey, AggregateSignature, AttestationData, Bitfield, Hash256}; +use super::{AggregateSignature, AttestationData, Bitfield}; use crate::test_utils::TestRandom; use rand::RngCore; use serde_derive::Serialize; use ssz::TreeHash; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz_derive::{Decode, Encode, SignedRoot, TreeHash}; use test_random_derive::TestRandom; -#[derive(Debug, Clone, PartialEq, Serialize, Encode, Decode, TreeHash, TestRandom)] +/// Details an attestation that can be slashable. +/// +/// Spec v0.4.0 +#[derive(Debug, Clone, PartialEq, Serialize, Encode, Decode, TreeHash, TestRandom, SignedRoot)] pub struct Attestation { pub aggregation_bitfield: Bitfield, pub data: AttestationData, @@ -14,29 +17,6 @@ pub struct Attestation { pub aggregate_signature: AggregateSignature, } -impl Attestation { - pub fn canonical_root(&self) -> Hash256 { - Hash256::from(&self.hash_tree_root()[..]) - } - - pub fn signable_message(&self, custody_bit: bool) -> Vec { - self.data.signable_message(custody_bit) - } - - pub fn verify_signature( - &self, - group_public_key: &AggregatePublicKey, - custody_bit: bool, - domain: u64, - ) -> bool { - self.aggregate_signature.verify( - &self.signable_message(custody_bit), - domain, - group_public_key, - ) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/eth2/types/src/attestation_data.rs b/eth2/types/src/attestation_data.rs index e23cdab46..1dfadfb1d 100644 --- a/eth2/types/src/attestation_data.rs +++ b/eth2/types/src/attestation_data.rs @@ -1,31 +1,33 @@ use crate::test_utils::TestRandom; -use crate::{AttestationDataAndCustodyBit, Crosslink, Epoch, Hash256, Slot}; +use crate::{Crosslink, Epoch, Hash256, Slot}; use rand::RngCore; use serde_derive::Serialize; use ssz::TreeHash; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz_derive::{Decode, Encode, SignedRoot, TreeHash}; use test_random_derive::TestRandom; -pub const SSZ_ATTESTION_DATA_LENGTH: usize = { - 8 + // slot - 8 + // shard - 32 + // beacon_block_hash - 32 + // epoch_boundary_root - 32 + // shard_block_hash - 32 + // latest_crosslink_hash - 8 + // justified_epoch - 32 // justified_block_root -}; - +/// The data upon which an attestation is based. +/// +/// Spec v0.4.0 #[derive( - Debug, Clone, PartialEq, Default, Serialize, Hash, Encode, Decode, TreeHash, TestRandom, + Debug, + Clone, + PartialEq, + Default, + Serialize, + Hash, + Encode, + Decode, + TreeHash, + TestRandom, + SignedRoot, )] pub struct AttestationData { pub slot: Slot, pub shard: u64, pub beacon_block_root: Hash256, pub epoch_boundary_root: Hash256, - pub shard_block_root: Hash256, + pub crosslink_data_root: Hash256, pub latest_crosslink: Crosslink, pub justified_epoch: Epoch, pub justified_block_root: Hash256, @@ -33,20 +35,6 @@ pub struct AttestationData { impl Eq for AttestationData {} -impl AttestationData { - pub fn canonical_root(&self) -> Hash256 { - Hash256::from(&self.hash_tree_root()[..]) - } - - pub fn signable_message(&self, custody_bit: bool) -> Vec { - let attestation_data_and_custody_bit = AttestationDataAndCustodyBit { - data: self.clone(), - custody_bit, - }; - attestation_data_and_custody_bit.hash_tree_root() - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/eth2/types/src/attestation_data_and_custody_bit.rs b/eth2/types/src/attestation_data_and_custody_bit.rs index 9175863ae..2f652609e 100644 --- a/eth2/types/src/attestation_data_and_custody_bit.rs +++ b/eth2/types/src/attestation_data_and_custody_bit.rs @@ -4,6 +4,9 @@ use rand::RngCore; use serde_derive::Serialize; use ssz_derive::{Decode, Encode, TreeHash}; +/// Used for pairing an attestation with a proof-of-custody. +/// +/// Spec v0.4.0 #[derive(Debug, Clone, PartialEq, Default, Serialize, Encode, Decode, TreeHash)] pub struct AttestationDataAndCustodyBit { pub data: AttestationData, diff --git a/eth2/types/src/attester_slashing.rs b/eth2/types/src/attester_slashing.rs index ac75a2562..1cb671960 100644 --- a/eth2/types/src/attester_slashing.rs +++ b/eth2/types/src/attester_slashing.rs @@ -8,6 +8,9 @@ mod builder; pub use builder::AttesterSlashingBuilder; +/// Two conflicting attestations. +/// +/// Spec v0.4.0 #[derive(Debug, PartialEq, Clone, Serialize, Encode, Decode, TreeHash, TestRandom)] pub struct AttesterSlashing { pub slashable_attestation_1: SlashableAttestation, diff --git a/eth2/types/src/beacon_block.rs b/eth2/types/src/beacon_block.rs index cb4e6668b..53b0dac80 100644 --- a/eth2/types/src/beacon_block.rs +++ b/eth2/types/src/beacon_block.rs @@ -4,18 +4,21 @@ use bls::Signature; use rand::RngCore; use serde_derive::Serialize; use ssz::TreeHash; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz_derive::{Decode, Encode, SignedRoot, TreeHash}; use test_random_derive::TestRandom; -#[derive(Debug, PartialEq, Clone, Serialize, Encode, Decode, TreeHash, TestRandom)] +/// A block of the `BeaconChain`. +/// +/// Spec v0.4.0 +#[derive(Debug, PartialEq, Clone, Serialize, Encode, Decode, TreeHash, TestRandom, SignedRoot)] pub struct BeaconBlock { pub slot: Slot, pub parent_root: Hash256, pub state_root: Hash256, pub randao_reveal: Signature, pub eth1_data: Eth1Data, - pub signature: Signature, pub body: BeaconBlockBody, + pub signature: Signature, } impl BeaconBlock { @@ -40,25 +43,6 @@ impl BeaconBlock { }, } } - - pub fn canonical_root(&self) -> Hash256 { - Hash256::from(&self.hash_tree_root()[..]) - } - - pub fn proposal_root(&self, spec: &ChainSpec) -> Hash256 { - let block_without_signature_root = { - let mut block_without_signature = self.clone(); - block_without_signature.signature = spec.empty_signature.clone(); - block_without_signature.canonical_root() - }; - - let proposal = ProposalSignedData { - slot: self.slot, - shard: spec.beacon_chain_shard_number, - block_root: block_without_signature_root, - }; - Hash256::from(&proposal.hash_tree_root()[..]) - } } #[cfg(test)] diff --git a/eth2/types/src/beacon_block_body.rs b/eth2/types/src/beacon_block_body.rs index 2b343b970..13c82e42f 100644 --- a/eth2/types/src/beacon_block_body.rs +++ b/eth2/types/src/beacon_block_body.rs @@ -1,17 +1,21 @@ -use super::{Attestation, AttesterSlashing, Deposit, Exit, ProposerSlashing}; +use super::{Attestation, AttesterSlashing, Deposit, ProposerSlashing, Transfer, VolutaryExit}; use crate::test_utils::TestRandom; use rand::RngCore; use serde_derive::Serialize; use ssz_derive::{Decode, Encode, TreeHash}; use test_random_derive::TestRandom; +/// The body of a `BeaconChain` block, containing operations. +/// +/// Spec v0.4.0 #[derive(Debug, PartialEq, Clone, Default, Serialize, Encode, Decode, TreeHash, TestRandom)] pub struct BeaconBlockBody { pub proposer_slashings: Vec, pub attester_slashings: Vec, pub attestations: Vec, pub deposits: Vec, - pub exits: Vec, + pub voluntary_exits: Vec, + pub transfers: Vec, } #[cfg(test)] diff --git a/eth2/types/src/beacon_state.rs b/eth2/types/src/beacon_state.rs index a9e2f2673..c96beff52 100644 --- a/eth2/types/src/beacon_state.rs +++ b/eth2/types/src/beacon_state.rs @@ -1,6 +1,6 @@ use self::epoch_cache::EpochCache; use crate::test_utils::TestRandom; -use crate::{validator::StatusFlags, validator_registry::get_active_validator_indices, *}; +use crate::{validator_registry::get_active_validator_indices, *}; use bls::verify_proof_of_possession; use honey_badger_split::SplitExt; use log::{debug, error, trace}; @@ -82,12 +82,12 @@ pub struct BeaconState { // Randomness and committees pub latest_randao_mixes: Vec, - pub previous_epoch_start_shard: u64, - pub current_epoch_start_shard: u64, - pub previous_calculation_epoch: Epoch, - pub current_calculation_epoch: Epoch, - pub previous_epoch_seed: Hash256, - pub current_epoch_seed: Hash256, + pub previous_shuffling_start_shard: u64, + pub current_shuffling_start_shard: u64, + pub previous_shuffling_epoch: Epoch, + pub current_shuffling_epoch: Epoch, + pub previous_shuffling_seed: Hash256, + pub current_shuffling_seed: Hash256, // Finality pub previous_justified_epoch: Epoch, @@ -98,8 +98,8 @@ pub struct BeaconState { // Recent state pub latest_crosslinks: Vec, pub latest_block_roots: Vec, - pub latest_index_roots: Vec, - pub latest_penalized_balances: Vec, + pub latest_active_index_roots: Vec, + pub latest_slashed_balances: Vec, pub latest_attestations: Vec, pub batched_block_roots: Vec, @@ -107,7 +107,7 @@ pub struct BeaconState { pub latest_eth1_data: Eth1Data, pub eth1_data_votes: Vec, - // Caching + // Caching (not in the spec) pub cache_index_offset: usize, pub caches: Vec, } @@ -148,12 +148,12 @@ impl BeaconState { * Randomness and committees */ latest_randao_mixes: vec![spec.zero_hash; spec.latest_randao_mixes_length as usize], - previous_epoch_start_shard: spec.genesis_start_shard, - current_epoch_start_shard: spec.genesis_start_shard, - previous_calculation_epoch: spec.genesis_epoch, - current_calculation_epoch: spec.genesis_epoch, - previous_epoch_seed: spec.zero_hash, - current_epoch_seed: spec.zero_hash, + previous_shuffling_start_shard: spec.genesis_start_shard, + current_shuffling_start_shard: spec.genesis_start_shard, + previous_shuffling_epoch: spec.genesis_epoch, + current_shuffling_epoch: spec.genesis_epoch, + previous_shuffling_seed: spec.zero_hash, + current_shuffling_seed: spec.zero_hash, /* * Finality @@ -168,8 +168,11 @@ impl BeaconState { */ latest_crosslinks: vec![initial_crosslink; spec.shard_count as usize], latest_block_roots: vec![spec.zero_hash; spec.latest_block_roots_length as usize], - latest_index_roots: vec![spec.zero_hash; spec.latest_index_roots_length as usize], - latest_penalized_balances: vec![0; spec.latest_penalized_exit_length as usize], + latest_active_index_roots: vec![ + spec.zero_hash; + spec.latest_active_index_roots_length as usize + ], + latest_slashed_balances: vec![0; spec.latest_penalized_exit_length as usize], latest_attestations: vec![], batched_block_roots: vec![], @@ -218,9 +221,10 @@ impl BeaconState { &genesis_state.validator_registry, spec.genesis_epoch, )); - genesis_state.latest_index_roots = - vec![genesis_active_index_root; spec.latest_index_roots_length]; - genesis_state.current_epoch_seed = genesis_state.generate_seed(spec.genesis_epoch, spec)?; + genesis_state.latest_active_index_roots = + vec![genesis_active_index_root; spec.latest_active_index_roots_length]; + genesis_state.current_shuffling_seed = + genesis_state.generate_seed(spec.genesis_epoch, spec)?; Ok(genesis_state) } @@ -440,7 +444,7 @@ impl BeaconState { /// Spec v0.2.0 fn get_previous_epoch_committee_count(&self, spec: &ChainSpec) -> u64 { let previous_active_validators = - get_active_validator_indices(&self.validator_registry, self.previous_calculation_epoch); + get_active_validator_indices(&self.validator_registry, self.previous_shuffling_epoch); self.get_epoch_committee_count(previous_active_validators.len(), spec) } @@ -449,7 +453,7 @@ impl BeaconState { /// Spec v0.2.0 pub fn get_current_epoch_committee_count(&self, spec: &ChainSpec) -> u64 { let current_active_validators = - get_active_validator_indices(&self.validator_registry, self.current_calculation_epoch); + get_active_validator_indices(&self.validator_registry, self.current_shuffling_epoch); self.get_epoch_committee_count(current_active_validators.len(), spec) } @@ -468,13 +472,17 @@ impl BeaconState { pub fn get_active_index_root(&self, epoch: Epoch, spec: &ChainSpec) -> Option { let current_epoch = self.current_epoch(spec); - let earliest_index_root = current_epoch - Epoch::from(spec.latest_index_roots_length) + let earliest_index_root = current_epoch + - Epoch::from(spec.latest_active_index_roots_length) + Epoch::from(spec.entry_exit_delay) + 1; let latest_index_root = current_epoch + spec.entry_exit_delay; if (epoch >= earliest_index_root) & (epoch <= latest_index_root) { - Some(self.latest_index_roots[epoch.as_usize() % spec.latest_index_roots_length]) + Some( + self.latest_active_index_roots + [epoch.as_usize() % spec.latest_active_index_roots_length], + ) } else { None } @@ -566,17 +574,17 @@ impl BeaconState { trace!("get_committee_params_at_slot: current_epoch"); Ok(( self.get_current_epoch_committee_count(spec), - self.current_epoch_seed, - self.current_calculation_epoch, - self.current_epoch_start_shard, + self.current_shuffling_seed, + self.current_shuffling_epoch, + self.current_shuffling_start_shard, )) } else if epoch == previous_epoch { trace!("get_committee_params_at_slot: previous_epoch"); Ok(( self.get_previous_epoch_committee_count(spec), - self.previous_epoch_seed, - self.previous_calculation_epoch, - self.previous_epoch_start_shard, + self.previous_shuffling_seed, + self.previous_shuffling_epoch, + self.previous_shuffling_start_shard, )) } else if epoch == next_epoch { trace!("get_committee_params_at_slot: next_epoch"); @@ -587,16 +595,19 @@ impl BeaconState { let next_seed = self.generate_seed(next_epoch, spec)?; ( next_seed, - (self.current_epoch_start_shard + current_committees_per_epoch) + (self.current_shuffling_start_shard + current_committees_per_epoch) % spec.shard_count, ) } else if (epochs_since_last_registry_update > 1) & epochs_since_last_registry_update.is_power_of_two() { let next_seed = self.generate_seed(next_epoch, spec)?; - (next_seed, self.current_epoch_start_shard) + (next_seed, self.current_shuffling_start_shard) } else { - (self.current_epoch_seed, self.current_epoch_start_shard) + ( + self.current_shuffling_seed, + self.current_shuffling_start_shard, + ) }; Ok(( self.get_next_epoch_committee_count(spec), @@ -715,9 +726,9 @@ impl BeaconState { let epoch_index: usize = current_epoch.as_usize() % spec.latest_penalized_exit_length; - let total_at_start = self.latest_penalized_balances + let total_at_start = self.latest_slashed_balances [(epoch_index + 1) % spec.latest_penalized_exit_length]; - let total_at_end = self.latest_penalized_balances[epoch_index]; + let total_at_end = self.latest_slashed_balances[epoch_index]; let total_penalities = total_at_end.saturating_sub(total_at_start); let penalty = self.get_effective_balance(index, spec) * std::cmp::min(total_penalities * 3, total_balance) @@ -983,7 +994,7 @@ impl BeaconState { self.exit_validator(validator_index, spec); let current_epoch = self.current_epoch(spec); - self.latest_penalized_balances + self.latest_slashed_balances [current_epoch.as_usize() % spec.latest_penalized_exit_length] += self.get_effective_balance(validator_index, spec); @@ -1329,20 +1340,20 @@ impl Encodable for BeaconState { s.append(&self.validator_balances); s.append(&self.validator_registry_update_epoch); s.append(&self.latest_randao_mixes); - s.append(&self.previous_epoch_start_shard); - s.append(&self.current_epoch_start_shard); - s.append(&self.previous_calculation_epoch); - s.append(&self.current_calculation_epoch); - s.append(&self.previous_epoch_seed); - s.append(&self.current_epoch_seed); + s.append(&self.previous_shuffling_start_shard); + s.append(&self.current_shuffling_start_shard); + s.append(&self.previous_shuffling_epoch); + s.append(&self.current_shuffling_epoch); + s.append(&self.previous_shuffling_seed); + s.append(&self.current_shuffling_seed); s.append(&self.previous_justified_epoch); s.append(&self.justified_epoch); s.append(&self.justification_bitfield); s.append(&self.finalized_epoch); s.append(&self.latest_crosslinks); s.append(&self.latest_block_roots); - s.append(&self.latest_index_roots); - s.append(&self.latest_penalized_balances); + s.append(&self.latest_active_index_roots); + s.append(&self.latest_slashed_balances); s.append(&self.latest_attestations); s.append(&self.batched_block_roots); s.append(&self.latest_eth1_data); @@ -1359,20 +1370,20 @@ impl Decodable for BeaconState { let (validator_balances, i) = <_>::ssz_decode(bytes, i)?; let (validator_registry_update_epoch, i) = <_>::ssz_decode(bytes, i)?; let (latest_randao_mixes, i) = <_>::ssz_decode(bytes, i)?; - let (previous_epoch_start_shard, i) = <_>::ssz_decode(bytes, i)?; - let (current_epoch_start_shard, i) = <_>::ssz_decode(bytes, i)?; - let (previous_calculation_epoch, i) = <_>::ssz_decode(bytes, i)?; - let (current_calculation_epoch, i) = <_>::ssz_decode(bytes, i)?; - let (previous_epoch_seed, i) = <_>::ssz_decode(bytes, i)?; - let (current_epoch_seed, i) = <_>::ssz_decode(bytes, i)?; + let (previous_shuffling_start_shard, i) = <_>::ssz_decode(bytes, i)?; + let (current_shuffling_start_shard, i) = <_>::ssz_decode(bytes, i)?; + let (previous_shuffling_epoch, i) = <_>::ssz_decode(bytes, i)?; + let (current_shuffling_epoch, i) = <_>::ssz_decode(bytes, i)?; + let (previous_shuffling_seed, i) = <_>::ssz_decode(bytes, i)?; + let (current_shuffling_seed, i) = <_>::ssz_decode(bytes, i)?; let (previous_justified_epoch, i) = <_>::ssz_decode(bytes, i)?; let (justified_epoch, i) = <_>::ssz_decode(bytes, i)?; let (justification_bitfield, i) = <_>::ssz_decode(bytes, i)?; let (finalized_epoch, i) = <_>::ssz_decode(bytes, i)?; let (latest_crosslinks, i) = <_>::ssz_decode(bytes, i)?; let (latest_block_roots, i) = <_>::ssz_decode(bytes, i)?; - let (latest_index_roots, i) = <_>::ssz_decode(bytes, i)?; - let (latest_penalized_balances, i) = <_>::ssz_decode(bytes, i)?; + let (latest_active_index_roots, i) = <_>::ssz_decode(bytes, i)?; + let (latest_slashed_balances, i) = <_>::ssz_decode(bytes, i)?; let (latest_attestations, i) = <_>::ssz_decode(bytes, i)?; let (batched_block_roots, i) = <_>::ssz_decode(bytes, i)?; let (latest_eth1_data, i) = <_>::ssz_decode(bytes, i)?; @@ -1387,20 +1398,20 @@ impl Decodable for BeaconState { validator_balances, validator_registry_update_epoch, latest_randao_mixes, - previous_epoch_start_shard, - current_epoch_start_shard, - previous_calculation_epoch, - current_calculation_epoch, - previous_epoch_seed, - current_epoch_seed, + previous_shuffling_start_shard, + current_shuffling_start_shard, + previous_shuffling_epoch, + current_shuffling_epoch, + previous_shuffling_seed, + current_shuffling_seed, previous_justified_epoch, justified_epoch, justification_bitfield, finalized_epoch, latest_crosslinks, latest_block_roots, - latest_index_roots, - latest_penalized_balances, + latest_active_index_roots, + latest_slashed_balances, latest_attestations, batched_block_roots, latest_eth1_data, @@ -1427,20 +1438,24 @@ impl TreeHash for BeaconState { .hash_tree_root_internal(), ); result.append(&mut self.latest_randao_mixes.hash_tree_root_internal()); - result.append(&mut self.previous_epoch_start_shard.hash_tree_root_internal()); - result.append(&mut self.current_epoch_start_shard.hash_tree_root_internal()); - result.append(&mut self.previous_calculation_epoch.hash_tree_root_internal()); - result.append(&mut self.current_calculation_epoch.hash_tree_root_internal()); - result.append(&mut self.previous_epoch_seed.hash_tree_root_internal()); - result.append(&mut self.current_epoch_seed.hash_tree_root_internal()); + result.append( + &mut self + .previous_shuffling_start_shard + .hash_tree_root_internal(), + ); + result.append(&mut self.current_shuffling_start_shard.hash_tree_root_internal()); + result.append(&mut self.previous_shuffling_epoch.hash_tree_root_internal()); + result.append(&mut self.current_shuffling_epoch.hash_tree_root_internal()); + result.append(&mut self.previous_shuffling_seed.hash_tree_root_internal()); + result.append(&mut self.current_shuffling_seed.hash_tree_root_internal()); result.append(&mut self.previous_justified_epoch.hash_tree_root_internal()); result.append(&mut self.justified_epoch.hash_tree_root_internal()); result.append(&mut self.justification_bitfield.hash_tree_root_internal()); result.append(&mut self.finalized_epoch.hash_tree_root_internal()); result.append(&mut self.latest_crosslinks.hash_tree_root_internal()); result.append(&mut self.latest_block_roots.hash_tree_root_internal()); - result.append(&mut self.latest_index_roots.hash_tree_root_internal()); - result.append(&mut self.latest_penalized_balances.hash_tree_root_internal()); + result.append(&mut self.latest_active_index_roots.hash_tree_root_internal()); + result.append(&mut self.latest_slashed_balances.hash_tree_root_internal()); result.append(&mut self.latest_attestations.hash_tree_root_internal()); result.append(&mut self.batched_block_roots.hash_tree_root_internal()); result.append(&mut self.latest_eth1_data.hash_tree_root_internal()); @@ -1459,20 +1474,20 @@ impl TestRandom for BeaconState { validator_balances: <_>::random_for_test(rng), validator_registry_update_epoch: <_>::random_for_test(rng), latest_randao_mixes: <_>::random_for_test(rng), - previous_epoch_start_shard: <_>::random_for_test(rng), - current_epoch_start_shard: <_>::random_for_test(rng), - previous_calculation_epoch: <_>::random_for_test(rng), - current_calculation_epoch: <_>::random_for_test(rng), - previous_epoch_seed: <_>::random_for_test(rng), - current_epoch_seed: <_>::random_for_test(rng), + previous_shuffling_start_shard: <_>::random_for_test(rng), + current_shuffling_start_shard: <_>::random_for_test(rng), + previous_shuffling_epoch: <_>::random_for_test(rng), + current_shuffling_epoch: <_>::random_for_test(rng), + previous_shuffling_seed: <_>::random_for_test(rng), + current_shuffling_seed: <_>::random_for_test(rng), previous_justified_epoch: <_>::random_for_test(rng), justified_epoch: <_>::random_for_test(rng), justification_bitfield: <_>::random_for_test(rng), finalized_epoch: <_>::random_for_test(rng), latest_crosslinks: <_>::random_for_test(rng), latest_block_roots: <_>::random_for_test(rng), - latest_index_roots: <_>::random_for_test(rng), - latest_penalized_balances: <_>::random_for_test(rng), + latest_active_index_roots: <_>::random_for_test(rng), + latest_slashed_balances: <_>::random_for_test(rng), latest_attestations: <_>::random_for_test(rng), batched_block_roots: <_>::random_for_test(rng), latest_eth1_data: <_>::random_for_test(rng), diff --git a/eth2/types/src/crosslink.rs b/eth2/types/src/crosslink.rs index 11fb3386d..142d0f894 100644 --- a/eth2/types/src/crosslink.rs +++ b/eth2/types/src/crosslink.rs @@ -5,6 +5,9 @@ use serde_derive::Serialize; use ssz_derive::{Decode, Encode, TreeHash}; use test_random_derive::TestRandom; +/// Specifies the block hash for a shard at an epoch. +/// +/// Spec v0.4.0 #[derive( Debug, Clone, PartialEq, Default, Serialize, Hash, Encode, Decode, TreeHash, TestRandom, )] @@ -13,16 +16,6 @@ pub struct Crosslink { pub shard_block_root: Hash256, } -impl Crosslink { - /// Generates a new instance where `dynasty` and `hash` are both zero. - pub fn zero() -> Self { - Self { - epoch: Epoch::new(0), - shard_block_root: Hash256::zero(), - } - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/eth2/types/src/deposit.rs b/eth2/types/src/deposit.rs index 02da32cfe..2e69ea599 100644 --- a/eth2/types/src/deposit.rs +++ b/eth2/types/src/deposit.rs @@ -5,6 +5,9 @@ use serde_derive::Serialize; use ssz_derive::{Decode, Encode, TreeHash}; use test_random_derive::TestRandom; +/// A deposit to potentially become a beacon chain validator. +/// +/// Spec v0.4.0 #[derive(Debug, PartialEq, Clone, Serialize, Encode, Decode, TreeHash, TestRandom)] pub struct Deposit { pub branch: Vec, diff --git a/eth2/types/src/deposit_data.rs b/eth2/types/src/deposit_data.rs index 349207791..1eb2722a9 100644 --- a/eth2/types/src/deposit_data.rs +++ b/eth2/types/src/deposit_data.rs @@ -5,6 +5,9 @@ use serde_derive::Serialize; use ssz_derive::{Decode, Encode, TreeHash}; use test_random_derive::TestRandom; +/// Data generated by the deposit contract. +/// +/// Spec v0.4.0 #[derive(Debug, PartialEq, Clone, Serialize, Encode, Decode, TreeHash, TestRandom)] pub struct DepositData { pub amount: u64, diff --git a/eth2/types/src/deposit_input.rs b/eth2/types/src/deposit_input.rs index 1f3b22779..c4c79c3d1 100644 --- a/eth2/types/src/deposit_input.rs +++ b/eth2/types/src/deposit_input.rs @@ -6,6 +6,9 @@ use serde_derive::Serialize; use ssz_derive::{Decode, Encode, TreeHash}; use test_random_derive::TestRandom; +/// The data supplied by the user to the deposit contract. +/// +/// Spec v0.4.0 #[derive(Debug, PartialEq, Clone, Serialize, Encode, Decode, TreeHash, TestRandom)] pub struct DepositInput { pub pubkey: PublicKey, diff --git a/eth2/types/src/eth1_data.rs b/eth2/types/src/eth1_data.rs index 8eabbabc7..2c817ca38 100644 --- a/eth2/types/src/eth1_data.rs +++ b/eth2/types/src/eth1_data.rs @@ -5,7 +5,9 @@ use serde_derive::Serialize; use ssz_derive::{Decode, Encode, TreeHash}; use test_random_derive::TestRandom; -// Note: this is refer to as DepositRootVote in specs +/// Contains data obtained from the Eth1 chain. +/// +/// Spec v0.4.0 #[derive(Debug, PartialEq, Clone, Default, Serialize, Encode, Decode, TreeHash, TestRandom)] pub struct Eth1Data { pub deposit_root: Hash256, diff --git a/eth2/types/src/eth1_data_vote.rs b/eth2/types/src/eth1_data_vote.rs index fa30b9052..898145575 100644 --- a/eth2/types/src/eth1_data_vote.rs +++ b/eth2/types/src/eth1_data_vote.rs @@ -5,7 +5,9 @@ use serde_derive::Serialize; use ssz_derive::{Decode, Encode, TreeHash}; use test_random_derive::TestRandom; -// Note: this is refer to as DepositRootVote in specs +/// A summation of votes for some `Eth1Data`. +/// +/// Spec v0.4.0 #[derive(Debug, PartialEq, Clone, Default, Serialize, Encode, Decode, TreeHash, TestRandom)] pub struct Eth1DataVote { pub eth1_data: Eth1Data, diff --git a/eth2/types/src/fork.rs b/eth2/types/src/fork.rs index 5b13a2388..783a65302 100644 --- a/eth2/types/src/fork.rs +++ b/eth2/types/src/fork.rs @@ -4,6 +4,9 @@ use serde_derive::Serialize; use ssz_derive::{Decode, Encode, TreeHash}; use test_random_derive::TestRandom; +/// Specifies a fork of the `BeaconChain`, to prevent replay attacks. +/// +/// Spec v0.4.0 #[derive(Debug, Clone, PartialEq, Default, Serialize, Encode, Decode, TreeHash, TestRandom)] pub struct Fork { pub previous_version: u64, diff --git a/eth2/types/src/lib.rs b/eth2/types/src/lib.rs index ff73a6ea6..b4b124294 100644 --- a/eth2/types/src/lib.rs +++ b/eth2/types/src/lib.rs @@ -15,7 +15,6 @@ pub mod deposit_data; pub mod deposit_input; pub mod eth1_data; pub mod eth1_data_vote; -pub mod exit; pub mod fork; pub mod free_attestation; pub mod pending_attestation; @@ -26,6 +25,8 @@ pub mod readers; pub mod shard_reassignment_record; pub mod slashable_attestation; pub mod slashable_vote_data; +pub mod transfer; +pub mod voluntary_exit; #[macro_use] pub mod slot_epoch_macros; pub mod slot_epoch; @@ -54,7 +55,6 @@ pub use crate::deposit_data::DepositData; pub use crate::deposit_input::DepositInput; pub use crate::eth1_data::Eth1Data; pub use crate::eth1_data_vote::Eth1DataVote; -pub use crate::exit::Exit; pub use crate::fork::Fork; pub use crate::free_attestation::FreeAttestation; pub use crate::pending_attestation::PendingAttestation; @@ -65,8 +65,10 @@ pub use crate::slashable_attestation::SlashableAttestation; pub use crate::slashable_vote_data::SlashableVoteData; pub use crate::slot_epoch::{Epoch, Slot}; pub use crate::slot_height::SlotHeight; -pub use crate::validator::{StatusFlags as ValidatorStatusFlags, Validator}; +pub use crate::transfer::Transfer; +pub use crate::validator::Validator; pub use crate::validator_registry_delta_block::ValidatorRegistryDeltaBlock; +pub use crate::voluntary_exit::VolutaryExit; pub type Hash256 = H256; pub type Address = H160; diff --git a/eth2/types/src/pending_attestation.rs b/eth2/types/src/pending_attestation.rs index 84eb59207..0430d18ba 100644 --- a/eth2/types/src/pending_attestation.rs +++ b/eth2/types/src/pending_attestation.rs @@ -5,6 +5,9 @@ use serde_derive::Serialize; use ssz_derive::{Decode, Encode, TreeHash}; use test_random_derive::TestRandom; +/// An attestation that has been included in the state but not yet fully processed. +/// +/// Spec v0.4.0 #[derive(Debug, Clone, PartialEq, Serialize, Encode, Decode, TreeHash, TestRandom)] pub struct PendingAttestation { pub aggregation_bitfield: Bitfield, diff --git a/eth2/types/src/proposal.rs b/eth2/types/src/proposal.rs index af69731cb..b1fd737a0 100644 --- a/eth2/types/src/proposal.rs +++ b/eth2/types/src/proposal.rs @@ -7,6 +7,9 @@ use ssz::TreeHash; use ssz_derive::{Decode, Encode, SignedRoot, TreeHash}; use test_random_derive::TestRandom; +/// A proposal for some shard or beacon block. +/// +/// Spec v0.4.0 #[derive(Debug, PartialEq, Clone, Serialize, Encode, Decode, TreeHash, TestRandom, SignedRoot)] pub struct Proposal { pub slot: Slot, diff --git a/eth2/types/src/proposer_slashing.rs b/eth2/types/src/proposer_slashing.rs index 3b6f57c40..f86e7f3a8 100644 --- a/eth2/types/src/proposer_slashing.rs +++ b/eth2/types/src/proposer_slashing.rs @@ -15,8 +15,8 @@ pub use builder::ProposerSlashingBuilder; #[derive(Debug, PartialEq, Clone, Serialize, Encode, Decode, TreeHash, TestRandom)] pub struct ProposerSlashing { pub proposer_index: u64, - pub proposer_1: Proposal, - pub proposer_2: Proposal, + pub proposal_1: Proposal, + pub proposal_2: Proposal, } #[cfg(test)] diff --git a/eth2/types/src/proposer_slashing/builder.rs b/eth2/types/src/proposer_slashing/builder.rs index 7923ff74d..66f74a2e2 100644 --- a/eth2/types/src/proposer_slashing/builder.rs +++ b/eth2/types/src/proposer_slashing/builder.rs @@ -1,5 +1,5 @@ use crate::*; -use ssz::TreeHash; +use ssz::SignedRoot; /// Builds a `ProposerSlashing`. pub struct ProposerSlashingBuilder(); @@ -22,27 +22,29 @@ impl ProposerSlashingBuilder { let slot = Slot::new(0); let shard = 0; - let proposal_data_1 = ProposalSignedData { + let mut proposal_1 = Proposal { slot, shard, block_root: Hash256::from(&[1][..]), + signature: Signature::empty_signature(), }; - let proposal_data_2 = ProposalSignedData { + let mut proposal_2 = Proposal { slot, shard, block_root: Hash256::from(&[2][..]), + signature: Signature::empty_signature(), }; - let proposal_signature_1 = { - let message = proposal_data_1.hash_tree_root(); + proposal_1.signature = { + let message = proposal_1.signed_root(); let epoch = slot.epoch(spec.epoch_length); let domain = spec.domain_proposal; signer(proposer_index, &message[..], epoch, domain) }; - let proposal_signature_2 = { - let message = proposal_data_2.hash_tree_root(); + proposal_2.signature = { + let message = proposal_2.signed_root(); let epoch = slot.epoch(spec.epoch_length); let domain = spec.domain_proposal; signer(proposer_index, &message[..], epoch, domain) @@ -50,10 +52,8 @@ impl ProposerSlashingBuilder { ProposerSlashing { proposer_index, - proposal_data_1, - proposal_signature_1, - proposal_data_2, - proposal_signature_2, + proposal_1, + proposal_2, } } } diff --git a/eth2/types/src/slashable_attestation.rs b/eth2/types/src/slashable_attestation.rs index 8ad582ce6..9f2ccab60 100644 --- a/eth2/types/src/slashable_attestation.rs +++ b/eth2/types/src/slashable_attestation.rs @@ -1,11 +1,18 @@ use crate::{test_utils::TestRandom, AggregateSignature, AttestationData, Bitfield, ChainSpec}; use rand::RngCore; use serde_derive::Serialize; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz::TreeHash; +use ssz_derive::{Decode, Encode, SignedRoot, TreeHash}; use test_random_derive::TestRandom; -#[derive(Debug, PartialEq, Clone, Serialize, Encode, Decode, TreeHash, TestRandom)] +/// Details an attestation that can be slashable. +/// +/// To be included in an `AttesterSlashing`. +/// +/// Spec v0.4.0 +#[derive(Debug, PartialEq, Clone, Serialize, Encode, Decode, TreeHash, TestRandom, SignedRoot)] pub struct SlashableAttestation { + /// Lists validator registry indices, not committee indices. pub validator_indices: Vec, pub data: AttestationData, pub custody_bitfield: Bitfield, @@ -15,21 +22,21 @@ pub struct SlashableAttestation { impl SlashableAttestation { /// Check if ``attestation_data_1`` and ``attestation_data_2`` have the same target. /// - /// Spec v0.3.0 + /// Spec v0.4.0 pub fn is_double_vote(&self, other: &SlashableAttestation, spec: &ChainSpec) -> bool { self.data.slot.epoch(spec.epoch_length) == other.data.slot.epoch(spec.epoch_length) } /// Check if ``attestation_data_1`` surrounds ``attestation_data_2``. /// - /// Spec v0.3.0 + /// Spec v0.4.0 pub fn is_surround_vote(&self, other: &SlashableAttestation, spec: &ChainSpec) -> bool { let source_epoch_1 = self.data.justified_epoch; let source_epoch_2 = other.data.justified_epoch; let target_epoch_1 = self.data.slot.epoch(spec.epoch_length); let target_epoch_2 = other.data.slot.epoch(spec.epoch_length); - (source_epoch_1 < source_epoch_2) && (target_epoch_2 < target_epoch_1) + (source_epoch_1 < source_epoch_2) & (target_epoch_2 < target_epoch_1) } } diff --git a/eth2/types/src/transfer.rs b/eth2/types/src/transfer.rs new file mode 100644 index 000000000..f23d3845e --- /dev/null +++ b/eth2/types/src/transfer.rs @@ -0,0 +1,51 @@ +use super::Slot; +use crate::test_utils::TestRandom; +use bls::{PublicKey, Signature}; +use rand::RngCore; +use serde_derive::Serialize; +use ssz_derive::{Decode, Encode, TreeHash}; +use test_random_derive::TestRandom; + +/// The data submitted to the deposit contract. +/// +/// Spec v0.4.0 +#[derive(Debug, PartialEq, Clone, Serialize, Encode, Decode, TreeHash, TestRandom)] +pub struct Transfer { + pub from: u64, + pub to: u64, + pub amount: u64, + pub fee: u64, + pub slot: Slot, + pub pubkey: PublicKey, + pub signature: Signature, +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng}; + use ssz::{ssz_encode, Decodable, TreeHash}; + + #[test] + pub fn test_ssz_round_trip() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = Transfer::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_internal() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = Transfer::random_for_test(&mut rng); + + let result = original.hash_tree_root_internal(); + + assert_eq!(result.len(), 32); + // TODO: Add further tests + // https://github.com/sigp/lighthouse/issues/170 + } +} diff --git a/eth2/types/src/validator.rs b/eth2/types/src/validator.rs index 587a48a1f..5b5dab6bf 100644 --- a/eth2/types/src/validator.rs +++ b/eth2/types/src/validator.rs @@ -2,55 +2,21 @@ use crate::{test_utils::TestRandom, Epoch, Hash256, PublicKey}; use rand::RngCore; use serde_derive::Serialize; use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; +use ssz_derive::{Decode, Encode, TreeHash}; +use test_random_derive::TestRandom; -const STATUS_FLAG_INITIATED_EXIT: u8 = 1; -const STATUS_FLAG_WITHDRAWABLE: u8 = 2; - -#[derive(Debug, PartialEq, Clone, Copy, Serialize)] -pub enum StatusFlags { - InitiatedExit, - Withdrawable, -} - -struct StatusFlagsDecodeError; - -impl From for DecodeError { - fn from(_: StatusFlagsDecodeError) -> DecodeError { - DecodeError::Invalid - } -} - -/// Handles the serialization logic for the `status_flags` field of the `Validator`. -fn status_flag_to_byte(flag: Option) -> u8 { - if let Some(flag) = flag { - match flag { - StatusFlags::InitiatedExit => STATUS_FLAG_INITIATED_EXIT, - StatusFlags::Withdrawable => STATUS_FLAG_WITHDRAWABLE, - } - } else { - 0 - } -} - -/// Handles the deserialization logic for the `status_flags` field of the `Validator`. -fn status_flag_from_byte(flag: u8) -> Result, StatusFlagsDecodeError> { - match flag { - 0 => Ok(None), - 1 => Ok(Some(StatusFlags::InitiatedExit)), - 2 => Ok(Some(StatusFlags::Withdrawable)), - _ => Err(StatusFlagsDecodeError), - } -} - -#[derive(Debug, Clone, PartialEq, Serialize)] +/// Information about a `BeaconChain` validator. +/// +/// Spec v0.4.0 +#[derive(Debug, Clone, PartialEq, Serialize, Encode, Decode, TestRandom)] pub struct Validator { pub pubkey: PublicKey, pub withdrawal_credentials: Hash256, pub activation_epoch: Epoch, pub exit_epoch: Epoch, pub withdrawal_epoch: Epoch, - pub penalized_epoch: Epoch, - pub status_flags: Option, + pub initiated_exit: bool, + pub slashed: bool, } impl Validator { @@ -64,9 +30,9 @@ impl Validator { self.exit_epoch <= epoch } - /// Returns `true` if the validator is considered penalized at some epoch. - pub fn is_penalized_at(&self, epoch: Epoch) -> bool { - self.penalized_epoch <= epoch + /// Returns `true` if the validator is able to withdraw at some epoch. + pub fn is_withdrawable_at(&self, epoch: Epoch) -> bool { + self.withdrawal_epoch <= epoch } } @@ -85,82 +51,6 @@ impl Default for Validator { } } -impl TestRandom for StatusFlags { - fn random_for_test(rng: &mut T) -> Self { - let options = vec![StatusFlags::InitiatedExit, StatusFlags::Withdrawable]; - options[(rng.next_u32() as usize) % options.len()] - } -} - -impl Encodable for Validator { - fn ssz_append(&self, s: &mut SszStream) { - s.append(&self.pubkey); - s.append(&self.withdrawal_credentials); - 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)); - } -} - -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 (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 status_flags = status_flag_from_byte(status_flags_byte)?; - - Ok(( - Self { - pubkey, - withdrawal_credentials, - activation_epoch, - exit_epoch, - withdrawal_epoch, - penalized_epoch, - status_flags, - }, - i, - )) - } -} - -impl TreeHash for Validator { - fn hash_tree_root_internal(&self) -> Vec { - let mut result: Vec = vec![]; - result.append(&mut self.pubkey.hash_tree_root_internal()); - result.append(&mut self.withdrawal_credentials.hash_tree_root_internal()); - result.append(&mut self.activation_epoch.hash_tree_root_internal()); - result.append(&mut self.exit_epoch.hash_tree_root_internal()); - result.append(&mut self.withdrawal_epoch.hash_tree_root_internal()); - result.append(&mut self.penalized_epoch.hash_tree_root_internal()); - result.append( - &mut u64::from(status_flag_to_byte(self.status_flags)).hash_tree_root_internal(), - ); - hash(&result) - } -} - -impl TestRandom for Validator { - fn random_for_test(rng: &mut T) -> Self { - Self { - pubkey: <_>::random_for_test(rng), - withdrawal_credentials: <_>::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)), - } - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/eth2/types/src/exit.rs b/eth2/types/src/voluntary_exit.rs similarity index 74% rename from eth2/types/src/exit.rs rename to eth2/types/src/voluntary_exit.rs index 5b41fcc7a..3cb0a85b7 100644 --- a/eth2/types/src/exit.rs +++ b/eth2/types/src/voluntary_exit.rs @@ -2,11 +2,15 @@ use crate::{test_utils::TestRandom, Epoch}; use bls::Signature; use rand::RngCore; use serde_derive::Serialize; -use ssz_derive::{Decode, Encode, TreeHash}; +use ssz::TreeHash; +use ssz_derive::{Decode, Encode, SignedRoot, TreeHash}; use test_random_derive::TestRandom; -#[derive(Debug, PartialEq, Clone, Serialize, Encode, Decode, TreeHash, TestRandom)] -pub struct Exit { +/// An exit voluntarily submitted a validator who wishes to withdraw. +/// +/// Spec v0.4.0 +#[derive(Debug, PartialEq, Clone, Serialize, Encode, Decode, TreeHash, TestRandom, SignedRoot)] +pub struct VolutaryExit { pub epoch: Epoch, pub validator_index: u64, pub signature: Signature, @@ -21,7 +25,7 @@ mod tests { #[test] pub fn test_ssz_round_trip() { let mut rng = XorShiftRng::from_seed([42; 16]); - let original = Exit::random_for_test(&mut rng); + let original = VolutaryExit::random_for_test(&mut rng); let bytes = ssz_encode(&original); let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap(); @@ -32,7 +36,7 @@ mod tests { #[test] pub fn test_hash_tree_root_internal() { let mut rng = XorShiftRng::from_seed([42; 16]); - let original = Exit::random_for_test(&mut rng); + let original = VolutaryExit::random_for_test(&mut rng); let result = original.hash_tree_root_internal();