From 39f217105357ceb8d4e2733e5b071e1a23bbe389 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Fri, 28 Dec 2018 19:46:33 +1100 Subject: [PATCH] Implement ssz Enc/Decode for BeaconState + more --- beacon_chain/types/src/beacon_state.rs | 114 ++++++++++++++ .../src/candidate_pow_receipt_root_record.rs | 53 +++++++ beacon_chain/types/src/crosslink_record.rs | 53 +++++++ beacon_chain/types/src/deposit_input.rs | 7 +- beacon_chain/types/src/fork_data.rs | 58 +++++++ .../types/src/pending_attestation_record.rs | 61 ++++++++ beacon_chain/types/src/shard_committee.rs | 47 ++++-- .../types/src/shard_reassignment_record.rs | 58 +++++++ beacon_chain/types/src/test_utils/address.rs | 11 ++ beacon_chain/types/src/test_utils/mod.rs | 7 + beacon_chain/types/src/validator_record.rs | 148 ++++++++++++++---- .../types/src/validator_registration.rs | 16 +- 12 files changed, 574 insertions(+), 59 deletions(-) create mode 100644 beacon_chain/types/src/test_utils/address.rs diff --git a/beacon_chain/types/src/beacon_state.rs b/beacon_chain/types/src/beacon_state.rs index a3e83a5233..7c61d1d207 100644 --- a/beacon_chain/types/src/beacon_state.rs +++ b/beacon_chain/types/src/beacon_state.rs @@ -6,6 +6,9 @@ use super::shard_committee::ShardCommittee; use super::shard_reassignment_record::ShardReassignmentRecord; use super::validator_record::ValidatorRecord; use super::Hash256; +use crate::test_utils::TestRandom; +use rand::RngCore; +use ssz::{Decodable, DecodeError, Encodable, SszStream}; #[derive(Debug, PartialEq, Clone)] pub struct BeaconState { @@ -51,3 +54,114 @@ impl BeaconState { Hash256::zero() } } + +impl Encodable for BeaconState { + fn ssz_append(&self, s: &mut SszStream) { + s.append(&self.slot); + s.append(&self.genesis_time); + s.append(&self.fork_data); + s.append(&self.validator_registry); + s.append(&self.validator_registry_latest_change_slot); + s.append(&self.validator_registry_exit_count); + s.append(&self.validator_registry_delta_chain_tip); + s.append(&self.randao_mix); + s.append(&self.next_seed); + s.append(&self.shard_committees_at_slots); + s.append(&self.persistent_committees); + s.append(&self.persistent_committee_reassignments); + s.append(&self.previous_justified_slot); + s.append(&self.justified_slot); + s.append(&self.justification_bitfield); + s.append(&self.finalized_slot); + s.append(&self.latest_crosslinks); + s.append(&self.latest_block_roots); + s.append(&self.latest_penalized_exit_balances); + s.append(&self.latest_attestations); + s.append(&self.processed_pow_receipt_root); + s.append(&self.candidate_pow_receipt_roots); + } +} + +impl Decodable for BeaconState { + fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { + let (slot, i) = <_>::ssz_decode(bytes, i)?; + let (genesis_time, i) = <_>::ssz_decode(bytes, i)?; + let (fork_data, i) = <_>::ssz_decode(bytes, i)?; + let (validator_registry, i) = <_>::ssz_decode(bytes, i)?; + let (validator_registry_latest_change_slot, i) = <_>::ssz_decode(bytes, i)?; + let (validator_registry_exit_count, i) = <_>::ssz_decode(bytes, i)?; + let (validator_registry_delta_chain_tip, i) = <_>::ssz_decode(bytes, i)?; + let (randao_mix, i) = <_>::ssz_decode(bytes, i)?; + let (next_seed, i) = <_>::ssz_decode(bytes, i)?; + let (shard_committees_at_slots, i) = <_>::ssz_decode(bytes, i)?; + let (persistent_committees, i) = <_>::ssz_decode(bytes, i)?; + let (persistent_committee_reassignments, i) = <_>::ssz_decode(bytes, i)?; + let (previous_justified_slot, i) = <_>::ssz_decode(bytes, i)?; + let (justified_slot, i) = <_>::ssz_decode(bytes, i)?; + let (justification_bitfield, i) = <_>::ssz_decode(bytes, i)?; + let (finalized_slot, i) = <_>::ssz_decode(bytes, i)?; + let (latest_crosslinks, i) = <_>::ssz_decode(bytes, i)?; + let (latest_block_roots, i) = <_>::ssz_decode(bytes, i)?; + let (latest_penalized_exit_balances, i) = <_>::ssz_decode(bytes, i)?; + let (latest_attestations, i) = <_>::ssz_decode(bytes, i)?; + let (processed_pow_receipt_root, i) = <_>::ssz_decode(bytes, i)?; + let (candidate_pow_receipt_roots, i) = <_>::ssz_decode(bytes, i)?; + + Ok(( + Self { + slot, + genesis_time, + fork_data, + validator_registry, + validator_registry_latest_change_slot, + validator_registry_exit_count, + validator_registry_delta_chain_tip, + randao_mix, + next_seed, + shard_committees_at_slots, + persistent_committees, + persistent_committee_reassignments, + previous_justified_slot, + justified_slot, + justification_bitfield, + finalized_slot, + latest_crosslinks, + latest_block_roots, + latest_penalized_exit_balances, + latest_attestations, + processed_pow_receipt_root, + candidate_pow_receipt_roots, + }, + i, + )) + } +} + +impl TestRandom for BeaconState { + fn random_for_test(rng: &mut T) -> Self { + Self { + slot: <_>::random_for_test(rng), + genesis_time: <_>::random_for_test(rng), + fork_data: <_>::random_for_test(rng), + validator_registry: <_>::random_for_test(rng), + validator_registry_latest_change_slot: <_>::random_for_test(rng), + validator_registry_exit_count: <_>::random_for_test(rng), + validator_registry_delta_chain_tip: <_>::random_for_test(rng), + randao_mix: <_>::random_for_test(rng), + next_seed: <_>::random_for_test(rng), + shard_committees_at_slots: <_>::random_for_test(rng), + persistent_committees: <_>::random_for_test(rng), + persistent_committee_reassignments: <_>::random_for_test(rng), + previous_justified_slot: <_>::random_for_test(rng), + justified_slot: <_>::random_for_test(rng), + justification_bitfield: <_>::random_for_test(rng), + finalized_slot: <_>::random_for_test(rng), + latest_crosslinks: <_>::random_for_test(rng), + latest_block_roots: <_>::random_for_test(rng), + latest_penalized_exit_balances: <_>::random_for_test(rng), + latest_attestations: <_>::random_for_test(rng), + processed_pow_receipt_root: <_>::random_for_test(rng), + candidate_pow_receipt_roots: <_>::random_for_test(rng), + } + } +} diff --git a/beacon_chain/types/src/candidate_pow_receipt_root_record.rs b/beacon_chain/types/src/candidate_pow_receipt_root_record.rs index a06e5e7943..663c3e1dbf 100644 --- a/beacon_chain/types/src/candidate_pow_receipt_root_record.rs +++ b/beacon_chain/types/src/candidate_pow_receipt_root_record.rs @@ -1,7 +1,60 @@ +use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; use super::Hash256; +use crate::test_utils::TestRandom; +use rand::RngCore; #[derive(Debug, PartialEq, Clone)] pub struct CandidatePoWReceiptRootRecord { pub candidate_pow_receipt_root: Hash256, pub votes: u64, } + +impl Encodable for CandidatePoWReceiptRootRecord { + fn ssz_append(&self, s: &mut SszStream) { + s.append(&self.candidate_pow_receipt_root); + s.append(&self.votes); + } +} + +impl Decodable for CandidatePoWReceiptRootRecord { + fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { + let (candidate_pow_receipt_root, i) = <_>::ssz_decode(bytes, i)?; + let (votes, i) = <_>::ssz_decode(bytes, i)?; + + Ok(( + Self { + candidate_pow_receipt_root, + votes, + }, + i, + )) + } +} + +impl TestRandom for CandidatePoWReceiptRootRecord { + fn random_for_test(rng: &mut T) -> Self { + Self { + candidate_pow_receipt_root: <_>::random_for_test(rng), + votes: <_>::random_for_test(rng), + } + } +} + +#[cfg(test)] +mod tests { + use super::super::ssz::ssz_encode; + use super::*; + use crate::test_utils::TestRandom; + use rand::{prng::XorShiftRng, SeedableRng}; + + #[test] + pub fn test_ssz_round_trip() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = CandidatePoWReceiptRootRecord::random_for_test(&mut rng); + + let bytes = ssz_encode(&original); + let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap(); + + assert_eq!(original, decoded); + } +} diff --git a/beacon_chain/types/src/crosslink_record.rs b/beacon_chain/types/src/crosslink_record.rs index 6a70daade4..9e525664a0 100644 --- a/beacon_chain/types/src/crosslink_record.rs +++ b/beacon_chain/types/src/crosslink_record.rs @@ -1,4 +1,7 @@ +use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; use super::Hash256; +use crate::test_utils::TestRandom; +use rand::RngCore; #[derive(Clone, Debug, PartialEq)] pub struct CrosslinkRecord { @@ -15,3 +18,53 @@ impl CrosslinkRecord { } } } + +impl Encodable for CrosslinkRecord { + fn ssz_append(&self, s: &mut SszStream) { + s.append(&self.slot); + s.append(&self.shard_block_root); + } +} + +impl Decodable for CrosslinkRecord { + fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { + let (slot, i) = <_>::ssz_decode(bytes, i)?; + let (shard_block_root, i) = <_>::ssz_decode(bytes, i)?; + + Ok(( + Self { + slot, + shard_block_root, + }, + i, + )) + } +} + +impl TestRandom for CrosslinkRecord { + fn random_for_test(rng: &mut T) -> Self { + Self { + slot: <_>::random_for_test(rng), + shard_block_root: <_>::random_for_test(rng), + } + } +} + +#[cfg(test)] +mod tests { + use super::super::ssz::ssz_encode; + use super::*; + use crate::test_utils::TestRandom; + use rand::{prng::XorShiftRng, SeedableRng}; + + #[test] + pub fn test_ssz_round_trip() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = CrosslinkRecord::random_for_test(&mut rng); + + let bytes = ssz_encode(&original); + let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap(); + + assert_eq!(original, decoded); + } +} diff --git a/beacon_chain/types/src/deposit_input.rs b/beacon_chain/types/src/deposit_input.rs index 41b579cdab..3a9a08412c 100644 --- a/beacon_chain/types/src/deposit_input.rs +++ b/beacon_chain/types/src/deposit_input.rs @@ -1,4 +1,4 @@ -use super::ssz::{decode_ssz_list, Decodable, DecodeError, Encodable, SszStream}; +use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; use super::Hash256; use crate::test_utils::TestRandom; use bls::{PublicKey, Signature}; @@ -14,7 +14,7 @@ pub struct DepositInput { impl Encodable for DepositInput { fn ssz_append(&self, s: &mut SszStream) { - s.append_vec(&self.pubkey.as_bytes()); + s.append(&self.pubkey); s.append(&self.withdrawal_credentials); s.append(&self.randao_commitment); s.append(&self.proof_of_possession); @@ -23,8 +23,7 @@ impl Encodable for DepositInput { impl Decodable for DepositInput { fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - let (pubkey_bytes, i) = decode_ssz_list(bytes, i)?; - let pubkey = PublicKey::from_bytes(&pubkey_bytes).map_err(|_| DecodeError::TooShort)?; + let (pubkey, i) = <_>::ssz_decode(bytes, i)?; let (withdrawal_credentials, i) = <_>::ssz_decode(bytes, i)?; let (randao_commitment, i) = <_>::ssz_decode(bytes, i)?; let (proof_of_possession, i) = <_>::ssz_decode(bytes, i)?; diff --git a/beacon_chain/types/src/fork_data.rs b/beacon_chain/types/src/fork_data.rs index 4c3541c3f8..e779c797e7 100644 --- a/beacon_chain/types/src/fork_data.rs +++ b/beacon_chain/types/src/fork_data.rs @@ -1,6 +1,64 @@ +use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use crate::test_utils::TestRandom; +use rand::RngCore; + #[derive(Debug, Clone, PartialEq)] pub struct ForkData { pub pre_fork_version: u64, pub post_fork_version: u64, pub fork_slot: u64, } + +impl Encodable for ForkData { + fn ssz_append(&self, s: &mut SszStream) { + s.append(&self.pre_fork_version); + s.append(&self.post_fork_version); + s.append(&self.fork_slot); + } +} + +impl Decodable for ForkData { + fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { + let (pre_fork_version, i) = <_>::ssz_decode(bytes, i)?; + let (post_fork_version, i) = <_>::ssz_decode(bytes, i)?; + let (fork_slot, i) = <_>::ssz_decode(bytes, i)?; + + Ok(( + Self { + pre_fork_version, + post_fork_version, + fork_slot, + }, + i, + )) + } +} + +impl TestRandom for ForkData { + fn random_for_test(rng: &mut T) -> Self { + Self { + pre_fork_version: <_>::random_for_test(rng), + post_fork_version: <_>::random_for_test(rng), + fork_slot: <_>::random_for_test(rng), + } + } +} + +#[cfg(test)] +mod tests { + use super::super::ssz::ssz_encode; + use super::*; + use crate::test_utils::TestRandom; + use rand::{prng::XorShiftRng, SeedableRng}; + + #[test] + pub fn test_ssz_round_trip() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = ForkData::random_for_test(&mut rng); + + let bytes = ssz_encode(&original); + let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap(); + + assert_eq!(original, decoded); + } +} diff --git a/beacon_chain/types/src/pending_attestation_record.rs b/beacon_chain/types/src/pending_attestation_record.rs index 16f77c90c7..aa289e9048 100644 --- a/beacon_chain/types/src/pending_attestation_record.rs +++ b/beacon_chain/types/src/pending_attestation_record.rs @@ -1,4 +1,7 @@ +use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; use super::{AttestationData, Bitfield}; +use crate::test_utils::TestRandom; +use rand::RngCore; #[derive(Debug, Clone, PartialEq)] pub struct PendingAttestationRecord { @@ -7,3 +10,61 @@ pub struct PendingAttestationRecord { pub custody_bitfield: Bitfield, pub slot_included: u64, } + +impl Encodable for PendingAttestationRecord { + fn ssz_append(&self, s: &mut SszStream) { + s.append(&self.data); + s.append(&self.participation_bitfield); + s.append(&self.custody_bitfield); + s.append(&self.slot_included); + } +} + +impl Decodable for PendingAttestationRecord { + fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { + let (data, i) = <_>::ssz_decode(bytes, i)?; + let (participation_bitfield, i) = <_>::ssz_decode(bytes, i)?; + let (custody_bitfield, i) = <_>::ssz_decode(bytes, i)?; + let (slot_included, i) = <_>::ssz_decode(bytes, i)?; + + Ok(( + Self { + data, + participation_bitfield, + custody_bitfield, + slot_included, + }, + i, + )) + } +} + +impl TestRandom for PendingAttestationRecord { + fn random_for_test(rng: &mut T) -> Self { + Self { + data: <_>::random_for_test(rng), + participation_bitfield: <_>::random_for_test(rng), + custody_bitfield: <_>::random_for_test(rng), + slot_included: <_>::random_for_test(rng), + } + } +} + +#[cfg(test)] +mod tests { + use super::super::ssz::ssz_encode; + use super::*; + use crate::test_utils::TestRandom; + use rand::{prng::XorShiftRng, SeedableRng}; + + #[test] + pub fn test_ssz_round_trip() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = PendingAttestationRecord::random_for_test(&mut rng); + + let bytes = ssz_encode(&original); + let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap(); + + assert_eq!(original, decoded); + } +} diff --git a/beacon_chain/types/src/shard_committee.rs b/beacon_chain/types/src/shard_committee.rs index 75208670f7..073dd01769 100644 --- a/beacon_chain/types/src/shard_committee.rs +++ b/beacon_chain/types/src/shard_committee.rs @@ -1,28 +1,53 @@ +use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use crate::test_utils::TestRandom; +use rand::RngCore; + #[derive(Clone, Debug, PartialEq)] pub struct ShardCommittee { - pub shard: u16, + pub shard: u64, pub committee: Vec, } -impl ShardCommittee { - /// Returns a new instance where the `shard_id` is zero and the - /// committee is an empty vector. - pub fn zero() -> Self { +impl Encodable for ShardCommittee { + fn ssz_append(&self, s: &mut SszStream) { + s.append(&self.shard); + s.append(&self.committee); + } +} + +impl Decodable for ShardCommittee { + fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { + let (shard, i) = <_>::ssz_decode(bytes, i)?; + let (committee, i) = <_>::ssz_decode(bytes, i)?; + + Ok((Self { shard, committee }, i)) + } +} + +impl TestRandom for ShardCommittee { + fn random_for_test(rng: &mut T) -> Self { Self { - shard: 0, - committee: vec![], + shard: <_>::random_for_test(rng), + committee: <_>::random_for_test(rng), } } } #[cfg(test)] mod tests { + use super::super::ssz::ssz_encode; use super::*; + use crate::test_utils::TestRandom; + use rand::{prng::XorShiftRng, SeedableRng}; #[test] - fn test_shard_and_committee_zero() { - let s = ShardCommittee::zero(); - assert_eq!(s.shard, 0); - assert_eq!(s.committee.len(), 0); + pub fn test_ssz_round_trip() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = ShardCommittee::random_for_test(&mut rng); + + let bytes = ssz_encode(&original); + let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap(); + + assert_eq!(original, decoded); } } diff --git a/beacon_chain/types/src/shard_reassignment_record.rs b/beacon_chain/types/src/shard_reassignment_record.rs index c9a17741c7..e990afeac8 100644 --- a/beacon_chain/types/src/shard_reassignment_record.rs +++ b/beacon_chain/types/src/shard_reassignment_record.rs @@ -1,6 +1,64 @@ +use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use crate::test_utils::TestRandom; +use rand::RngCore; + #[derive(Debug, PartialEq, Clone)] pub struct ShardReassignmentRecord { pub validator_index: u64, pub shard: u64, pub slot: u64, } + +impl Encodable for ShardReassignmentRecord { + fn ssz_append(&self, s: &mut SszStream) { + s.append(&self.validator_index); + s.append(&self.shard); + s.append(&self.slot); + } +} + +impl Decodable for ShardReassignmentRecord { + fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { + let (validator_index, i) = <_>::ssz_decode(bytes, i)?; + let (shard, i) = <_>::ssz_decode(bytes, i)?; + let (slot, i) = <_>::ssz_decode(bytes, i)?; + + Ok(( + Self { + validator_index, + shard, + slot, + }, + i, + )) + } +} + +impl TestRandom for ShardReassignmentRecord { + fn random_for_test(rng: &mut T) -> Self { + Self { + validator_index: <_>::random_for_test(rng), + shard: <_>::random_for_test(rng), + slot: <_>::random_for_test(rng), + } + } +} + +#[cfg(test)] +mod tests { + use super::super::ssz::ssz_encode; + use super::*; + use crate::test_utils::TestRandom; + use rand::{prng::XorShiftRng, SeedableRng}; + + #[test] + pub fn test_ssz_round_trip() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = ShardReassignmentRecord::random_for_test(&mut rng); + + let bytes = ssz_encode(&original); + let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap(); + + assert_eq!(original, decoded); + } +} diff --git a/beacon_chain/types/src/test_utils/address.rs b/beacon_chain/types/src/test_utils/address.rs new file mode 100644 index 0000000000..2d60b72da7 --- /dev/null +++ b/beacon_chain/types/src/test_utils/address.rs @@ -0,0 +1,11 @@ +use super::TestRandom; +use crate::Address; +use rand::RngCore; + +impl TestRandom for Address { + fn random_for_test(rng: &mut T) -> Self { + let mut key_bytes = vec![0; 20]; + rng.fill_bytes(&mut key_bytes); + Address::from(&key_bytes[..]) + } +} diff --git a/beacon_chain/types/src/test_utils/mod.rs b/beacon_chain/types/src/test_utils/mod.rs index 131ff9aacf..f3e382e6ef 100644 --- a/beacon_chain/types/src/test_utils/mod.rs +++ b/beacon_chain/types/src/test_utils/mod.rs @@ -2,6 +2,7 @@ use rand::RngCore; pub use rand::{prng::XorShiftRng, SeedableRng}; +pub mod address; pub mod aggregate_signature; pub mod bitfield; pub mod hash256; @@ -27,6 +28,12 @@ impl TestRandom for u32 { } } +impl TestRandom for usize { + fn random_for_test(rng: &mut T) -> Self { + rng.next_u32() as usize + } +} + impl TestRandom for Vec where U: TestRandom { diff --git a/beacon_chain/types/src/validator_record.rs b/beacon_chain/types/src/validator_record.rs index 00c4637bf5..7da858676a 100644 --- a/beacon_chain/types/src/validator_record.rs +++ b/beacon_chain/types/src/validator_record.rs @@ -1,5 +1,8 @@ -use super::bls::{Keypair, PublicKey}; +use super::bls::PublicKey; use super::{Address, Hash256}; +use crate::test_utils::TestRandom; +use rand::RngCore; +use ssz::{Decodable, DecodeError, Encodable, SszStream}; use std::convert; #[derive(Debug, PartialEq, Clone)] @@ -38,44 +41,131 @@ pub struct ValidatorRecord { pub exit_slot: u64, } -impl ValidatorRecord { - /// Generates a new instance where the keypair is generated using - /// `rand::thread_rng` entropy and all other fields are set to zero. - /// - /// Returns the new instance and new keypair. - pub fn zero_with_thread_rand_keypair() -> (Self, Keypair) { - let keypair = Keypair::random(); - let s = Self { - pubkey: keypair.pk.clone(), - withdrawal_shard: 0, - withdrawal_address: Address::zero(), - randao_commitment: Hash256::zero(), - randao_last_change: 0, - balance: 0, - status: From::from(0), - exit_slot: 0, +impl Encodable for ValidatorStatus { + fn ssz_append(&self, s: &mut SszStream) { + let byte: u8 = match self { + ValidatorStatus::PendingActivation => 0, + ValidatorStatus::Active => 1, + ValidatorStatus::PendingExit => 2, + ValidatorStatus::PendingWithdraw => 3, + ValidatorStatus::Withdrawn => 5, + ValidatorStatus::Penalized => 127, }; - (s, keypair) + s.append(&byte); } +} - pub fn status_is(&self, status: ValidatorStatus) -> bool { - self.status == status +impl Decodable for ValidatorStatus { + fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { + let (byte, i) = u8::ssz_decode(bytes, i)?; + let status = match byte { + 0 => ValidatorStatus::PendingActivation, + 1 => ValidatorStatus::Active, + 2 => ValidatorStatus::PendingExit, + 3 => ValidatorStatus::PendingWithdraw, + 5 => ValidatorStatus::Withdrawn, + 127 => ValidatorStatus::Penalized, + _ => return Err(DecodeError::Invalid), + }; + Ok((status, i)) + } +} + +impl TestRandom for ValidatorStatus { + fn random_for_test(rng: &mut T) -> Self { + let options = vec![ + ValidatorStatus::PendingActivation, + ValidatorStatus::Active, + ValidatorStatus::PendingExit, + ValidatorStatus::PendingWithdraw, + ValidatorStatus::Withdrawn, + ValidatorStatus::Penalized, + ]; + options[(rng.next_u32() as usize) % options.len()].clone() + } +} + +impl Encodable for ValidatorRecord { + fn ssz_append(&self, s: &mut SszStream) { + s.append(&self.pubkey); + s.append(&self.withdrawal_shard); + s.append(&self.withdrawal_address); + s.append(&self.randao_commitment); + s.append(&self.randao_last_change); + s.append(&self.balance); + s.append(&self.status); + s.append(&self.exit_slot); + } +} + +impl Decodable for ValidatorRecord { + fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { + let (pubkey, i) = <_>::ssz_decode(bytes, i)?; + let (withdrawal_shard, i) = <_>::ssz_decode(bytes, i)?; + let (withdrawal_address, i) = <_>::ssz_decode(bytes, i)?; + let (randao_commitment, i) = <_>::ssz_decode(bytes, i)?; + let (randao_last_change, i) = <_>::ssz_decode(bytes, i)?; + let (balance, i) = <_>::ssz_decode(bytes, i)?; + let (status, i) = <_>::ssz_decode(bytes, i)?; + let (exit_slot, i) = <_>::ssz_decode(bytes, i)?; + + Ok(( + Self { + pubkey, + withdrawal_shard, + withdrawal_address, + randao_commitment, + randao_last_change, + balance, + status, + exit_slot, + }, + i, + )) + } +} + +impl TestRandom for ValidatorRecord { + fn random_for_test(rng: &mut T) -> Self { + Self { + pubkey: <_>::random_for_test(rng), + withdrawal_shard: <_>::random_for_test(rng), + withdrawal_address: <_>::random_for_test(rng), + randao_commitment: <_>::random_for_test(rng), + randao_last_change: <_>::random_for_test(rng), + balance: <_>::random_for_test(rng), + status: <_>::random_for_test(rng), + exit_slot: <_>::random_for_test(rng), + } } } #[cfg(test)] mod tests { + use super::super::ssz::ssz_encode; use super::*; + use crate::test_utils::TestRandom; + use rand::{prng::XorShiftRng, SeedableRng}; #[test] - fn test_validator_record_zero_rand_keypair() { - let (v, _kp) = ValidatorRecord::zero_with_thread_rand_keypair(); - assert_eq!(v.withdrawal_shard, 0); - assert!(v.withdrawal_address.is_zero()); - assert!(v.randao_commitment.is_zero()); - assert_eq!(v.randao_last_change, 0); - assert_eq!(v.balance, 0); - assert_eq!(v.status, From::from(0)); - assert_eq!(v.exit_slot, 0); + pub fn test_ssz_round_trip() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = ValidatorRecord::random_for_test(&mut rng); + + let bytes = ssz_encode(&original); + let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap(); + + assert_eq!(original, decoded); + } + + #[test] + pub fn test_validator_status_ssz_round_trip() { + let mut rng = XorShiftRng::from_seed([42; 16]); + let original = ValidatorStatus::random_for_test(&mut rng); + + let bytes = ssz_encode(&original); + let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap(); + + assert_eq!(original, decoded); } } diff --git a/beacon_chain/types/src/validator_registration.rs b/beacon_chain/types/src/validator_registration.rs index 11f6d11c50..964b80b8af 100644 --- a/beacon_chain/types/src/validator_registration.rs +++ b/beacon_chain/types/src/validator_registration.rs @@ -1,5 +1,5 @@ use super::{Address, Hash256}; -use bls::{create_proof_of_possession, Keypair, PublicKey, Signature}; +use bls::{PublicKey, Signature}; /// The information gathered from the PoW chain validator registration function. #[derive(Debug, Clone, PartialEq)] @@ -10,17 +10,3 @@ pub struct ValidatorRegistration { pub randao_commitment: Hash256, pub proof_of_possession: Signature, } - -impl ValidatorRegistration { - pub fn random() -> Self { - let keypair = Keypair::random(); - - Self { - pubkey: keypair.pk.clone(), - withdrawal_shard: 0, - withdrawal_address: Address::random(), - randao_commitment: Hash256::random(), - proof_of_possession: create_proof_of_possession(&keypair), - } - } -}