diff --git a/beacon_chain/types/src/beacon_block.rs b/beacon_chain/types/src/beacon_block.rs index 35ad18497..ad87ec84a 100644 --- a/beacon_chain/types/src/beacon_block.rs +++ b/beacon_chain/types/src/beacon_block.rs @@ -1,142 +1,28 @@ -use super::attestation::Attestation; -use super::special_record::SpecialRecord; use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; -use super::Hash256; - -pub const MIN_SSZ_BLOCK_LENGTH: usize = { - 8 + // slot - 32 + // randao_reveal - 32 + // pow_chain_reference - 4 + // ancestor hashes (assuming empty) - 32 + // active_state_root - 32 + // crystallized_state_root - 4 + // attestations (assuming empty) - 4 // specials (assuming empty) -}; -pub const MAX_SSZ_BLOCK_LENGTH: usize = MIN_SSZ_BLOCK_LENGTH + (1 << 24); +use super::{BeaconBlockBody, Hash256}; +use bls::AggregateSignature; #[derive(Debug, PartialEq, Clone, Default)] pub struct BeaconBlock { pub slot: u64, + pub parent_root: Hash256, + pub state_root: Hash256, pub randao_reveal: Hash256, - pub pow_chain_reference: Hash256, - pub ancestor_hashes: Vec, - pub active_state_root: Hash256, - pub crystallized_state_root: Hash256, - pub attestations: Vec, - pub specials: Vec, -} - -impl BeaconBlock { - pub fn zero() -> Self { - Self { - slot: 0, - randao_reveal: Hash256::zero(), - pow_chain_reference: Hash256::zero(), - ancestor_hashes: vec![], - active_state_root: Hash256::zero(), - crystallized_state_root: Hash256::zero(), - attestations: vec![], - specials: vec![], - } - } - - /// Return a reference to `ancestor_hashes[0]`. - /// - /// The first hash in `ancestor_hashes` is the parent of the block. - pub fn parent_hash(&self) -> Option<&Hash256> { - self.ancestor_hashes.get(0) - } + pub candidate_pow_receipt_root: Hash256, + pub signature: AggregateSignature, + pub body: BeaconBlockBody, } +/* impl Encodable for BeaconBlock { fn ssz_append(&self, s: &mut SszStream) { s.append(&self.slot); + s.append(&self.parent_root); + s.append(&self.state_root); s.append(&self.randao_reveal); - s.append(&self.pow_chain_reference); - s.append_vec(&self.ancestor_hashes); - s.append(&self.active_state_root); - s.append(&self.crystallized_state_root); - s.append_vec(&self.attestations); - s.append_vec(&self.specials); - } -} - -impl Decodable for BeaconBlock { - fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { - let (slot, i) = u64::ssz_decode(bytes, i)?; - let (randao_reveal, i) = Hash256::ssz_decode(bytes, i)?; - let (pow_chain_reference, i) = Hash256::ssz_decode(bytes, i)?; - let (ancestor_hashes, i) = Decodable::ssz_decode(bytes, i)?; - let (active_state_root, i) = Hash256::ssz_decode(bytes, i)?; - let (crystallized_state_root, i) = Hash256::ssz_decode(bytes, i)?; - let (attestations, i) = Decodable::ssz_decode(bytes, i)?; - let (specials, i) = Decodable::ssz_decode(bytes, i)?; - let block = BeaconBlock { - slot, - randao_reveal, - pow_chain_reference, - ancestor_hashes, - active_state_root, - crystallized_state_root, - attestations, - specials, - }; - Ok((block, i)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_block_zero() { - let b = BeaconBlock::zero(); - assert_eq!(b.slot, 0); - assert!(b.randao_reveal.is_zero()); - assert!(b.pow_chain_reference.is_zero()); - assert_eq!(b.ancestor_hashes, vec![]); - assert!(b.active_state_root.is_zero()); - assert!(b.crystallized_state_root.is_zero()); - assert_eq!(b.attestations.len(), 0); - assert_eq!(b.specials.len(), 0); - } - - #[test] - pub fn test_block_ssz_encode_decode() { - let mut b = BeaconBlock::zero(); - b.ancestor_hashes = vec![Hash256::zero(); 32]; - - let mut ssz_stream = SszStream::new(); - ssz_stream.append(&b); - let ssz = ssz_stream.drain(); - - let (b_decoded, _) = BeaconBlock::ssz_decode(&ssz, 0).unwrap(); - - assert_eq!(b, b_decoded); - } - - #[test] - pub fn test_block_min_ssz_length() { - let b = BeaconBlock::zero(); - - let mut ssz_stream = SszStream::new(); - ssz_stream.append(&b); - let ssz = ssz_stream.drain(); - - assert_eq!(ssz.len(), MIN_SSZ_BLOCK_LENGTH); - } - - #[test] - pub fn test_block_parent_hash() { - let mut b = BeaconBlock::zero(); - b.ancestor_hashes = vec![ - Hash256::from("cats".as_bytes()), - Hash256::from("dogs".as_bytes()), - Hash256::from("birds".as_bytes()), - ]; - - assert_eq!(b.parent_hash().unwrap(), &Hash256::from("cats".as_bytes())); + s.append(&self.candidate_pow_receipt_root); + s.append_vec(&self.signature.as_bytes()); + s.append(&self.body); } } +*/ diff --git a/beacon_chain/types/src/beacon_block_body.rs b/beacon_chain/types/src/beacon_block_body.rs index e69de29bb..66db774b7 100644 --- a/beacon_chain/types/src/beacon_block_body.rs +++ b/beacon_chain/types/src/beacon_block_body.rs @@ -0,0 +1,23 @@ +use super::ssz::{Encodable, SszStream}; +use super::{Attestation, CasperSlashing, Deposit, Exit, ProposerSlashing}; + +#[derive(Debug, PartialEq, Clone, Default)] +pub struct BeaconBlockBody { + pub proposer_slashings: Vec, + pub casper_slashings: Vec, + pub attestations: Vec, + pub deposits: Vec, + pub exits: Vec, +} + +/* +impl Encodable for BeaconBlockBody { + fn ssz_append(&self, s: &mut SszStream) { + s.append(&self.proposer_slashings); + s.append(&self.casper_slashings); + s.append(&self.attestations); + s.append(&self.deposits); + s.append(&self.exits); + } +} +*/ diff --git a/beacon_chain/types/src/casper_slashing.rs b/beacon_chain/types/src/casper_slashing.rs new file mode 100644 index 000000000..a8f722652 --- /dev/null +++ b/beacon_chain/types/src/casper_slashing.rs @@ -0,0 +1,30 @@ +use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::SlashableVoteData; + +#[derive(Debug, PartialEq, Clone, Default)] +pub struct CasperSlashing { + pub slashable_vote_data_1: SlashableVoteData, + pub slashable_vote_data_2: SlashableVoteData, +} + +impl Encodable for CasperSlashing { + fn ssz_append(&self, s: &mut SszStream) { + s.append(&self.slashable_vote_data_1); + s.append(&self.slashable_vote_data_1); + } +} + +impl Decodable for CasperSlashing { + fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { + let (slashable_vote_data_1, i) = SlashableVoteData::ssz_decode(bytes, i)?; + let (slashable_vote_data_2, i) = SlashableVoteData::ssz_decode(bytes, i)?; + + Ok(( + CasperSlashing { + slashable_vote_data_1, + slashable_vote_data_2, + }, + i, + )) + } +} diff --git a/beacon_chain/types/src/deposit.rs b/beacon_chain/types/src/deposit.rs new file mode 100644 index 000000000..7a6e70409 --- /dev/null +++ b/beacon_chain/types/src/deposit.rs @@ -0,0 +1,24 @@ +use super::Hash256; +use bls::{AggregateSignature, PublicKey}; + +#[derive(Debug, PartialEq, Clone)] +pub struct Deposit { + pub merkle_branch: Vec, + pub merkle_tree_index: u64, + pub deposit_data: DepositData, +} + +#[derive(Debug, PartialEq, Clone)] +pub struct DepositData { + pub deposit_input: DepositInput, + pub value: u64, + pub timestamp: u64, +} + +#[derive(Debug, PartialEq, Clone)] +pub struct DepositInput { + pub pubkey: PublicKey, + pub withdrawal_credentials: Hash256, + pub randao_commitment: Hash256, + pub proof_of_possession: AggregateSignature, +} diff --git a/beacon_chain/types/src/exit.rs b/beacon_chain/types/src/exit.rs new file mode 100644 index 000000000..8de66c630 --- /dev/null +++ b/beacon_chain/types/src/exit.rs @@ -0,0 +1,8 @@ +use bls::AggregateSignature; + +#[derive(Debug, PartialEq, Clone)] +pub struct Exit { + pub slot: u64, + pub validator_index: u32, + pub signature: AggregateSignature, +} diff --git a/beacon_chain/types/src/lib.rs b/beacon_chain/types/src/lib.rs index f86d5f024..c71a205b7 100644 --- a/beacon_chain/types/src/lib.rs +++ b/beacon_chain/types/src/lib.rs @@ -7,16 +7,23 @@ pub mod active_state; pub mod attestation_data; pub mod attestation; pub mod beacon_block; +pub mod beacon_block_body; pub mod beacon_state; pub mod candidate_pow_receipt_root_record; +pub mod casper_slashing; pub mod chain_config; pub mod crosslink_record; pub mod crystallized_state; +pub mod deposit; +pub mod exit; pub mod fork_data; pub mod pending_attestation_record; +pub mod proposal_signed_data; +pub mod proposer_slashing; pub mod shard_and_committee; pub mod shard_reassignment_record; pub mod special_record; +pub mod slashable_vote_data; pub mod validator_record; pub mod validator_registration; @@ -27,12 +34,19 @@ pub use active_state::ActiveState; pub use attestation_data::AttestationData; pub use attestation::Attestation; pub use beacon_block::BeaconBlock; +pub use beacon_block_body::BeaconBlockBody; pub use beacon_state::BeaconState; +pub use casper_slashing::CasperSlashing; pub use chain_config::ChainConfig; pub use crosslink_record::CrosslinkRecord; pub use crystallized_state::CrystallizedState; +pub use deposit::{Deposit, DepositData, DepositInput}; +pub use exit::Exit; pub use fork_data::ForkData; pub use pending_attestation_record::PendingAttestationRecord; +pub use proposal_signed_data::ProposalSignedData; +pub use proposer_slashing::ProposerSlashing; +pub use slashable_vote_data::SlashableVoteData; pub use shard_and_committee::ShardAndCommittee; pub use special_record::{SpecialRecord, SpecialRecordKind}; pub use validator_record::{ValidatorRecord, ValidatorStatus}; diff --git a/beacon_chain/types/src/proposal_signed_data.rs b/beacon_chain/types/src/proposal_signed_data.rs new file mode 100644 index 000000000..25a6f0e04 --- /dev/null +++ b/beacon_chain/types/src/proposal_signed_data.rs @@ -0,0 +1,54 @@ +use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::Hash256; + +#[derive(Debug, PartialEq, Clone, Default)] +pub struct ProposalSignedData { + pub slot: u64, + pub shard: u64, + pub block_root: Hash256, +} + +impl Encodable for ProposalSignedData { + fn ssz_append(&self, s: &mut SszStream) { + s.append(&self.slot); + s.append(&self.shard); + s.append(&self.block_root); + } +} + +impl Decodable for ProposalSignedData { + fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { + let (slot, i) = u64::ssz_decode(bytes, i)?; + let (shard, i) = u64::ssz_decode(bytes, i)?; + let (block_root, i) = Hash256::ssz_decode(bytes, i)?; + + Ok(( + ProposalSignedData { + slot, + shard, + block_root, + }, + i, + )) + } +} + +#[cfg(test)] +mod tests { + use super::super::ssz::ssz_encode; + use super::*; + + #[test] + pub fn test_ssz_round_trip() { + let original = ProposalSignedData { + slot: 42, + shard: 120, + block_root: Hash256::from("cats".as_bytes()), + }; + + let bytes = ssz_encode(&original); + let (decoded, _) = ProposalSignedData::ssz_decode(&bytes, 0).unwrap(); + + assert_eq!(original, decoded); + } +} diff --git a/beacon_chain/types/src/proposer_slashing.rs b/beacon_chain/types/src/proposer_slashing.rs new file mode 100644 index 000000000..33d8103b9 --- /dev/null +++ b/beacon_chain/types/src/proposer_slashing.rs @@ -0,0 +1,77 @@ +use super::ssz::{Decodable, DecodeError, Encodable, SszStream}; +use super::ProposalSignedData; +use bls::Signature; + +#[derive(Debug, PartialEq, Clone, Default)] +pub struct ProposerSlashing { + pub proposer_index: u32, + pub proposal_data_1: ProposalSignedData, + pub proposal_signature_1: Signature, + pub proposal_data_2: ProposalSignedData, + pub proposal_signature_2: Signature, +} + +impl Encodable for ProposerSlashing { + fn ssz_append(&self, s: &mut SszStream) { + s.append(&self.proposer_index); + s.append(&self.proposal_data_1); + s.append(&self.proposal_signature_1); + s.append(&self.proposal_data_2); + s.append(&self.proposal_signature_2); + } +} + +impl Decodable for ProposerSlashing { + fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { + let (proposer_index, i) = u32::ssz_decode(bytes, i)?; + let (proposal_data_1, i) = ProposalSignedData::ssz_decode(bytes, i)?; + let (proposal_signature_1, i) = Signature::ssz_decode(bytes, i)?; + let (proposal_data_2, i) = ProposalSignedData::ssz_decode(bytes, i)?; + let (proposal_signature_2, i) = Signature::ssz_decode(bytes, i)?; + + Ok(( + ProposerSlashing { + proposer_index, + proposal_data_1, + proposal_signature_1, + proposal_data_2, + proposal_signature_2, + }, + i, + )) + } +} + +#[cfg(test)] +mod tests { + use super::super::ssz::ssz_encode; + use super::super::Hash256; + use super::*; + use bls::{Keypair, Signature}; + + #[test] + pub fn test_ssz_round_trip() { + let keypair = Keypair::random(); + + let original = ProposerSlashing { + proposer_index: 42, + proposal_data_1: ProposalSignedData { + slot: 45, + shard: 110, + block_root: Hash256::from("cats".as_bytes()), + }, + proposal_signature_1: Signature::new(&[42, 42], &keypair.sk), + proposal_data_2: ProposalSignedData { + slot: 1, + shard: 260, + block_root: Hash256::from("lol".as_bytes()), + }, + proposal_signature_2: Signature::new(&[7, 8], &keypair.sk), + }; + + let bytes = ssz_encode(&original); + let (decoded, _) = ProposerSlashing::ssz_decode(&bytes, 0).unwrap(); + + assert_eq!(original, decoded); + } +} diff --git a/beacon_chain/types/src/slashable_vote_data.rs b/beacon_chain/types/src/slashable_vote_data.rs new file mode 100644 index 000000000..7a8f3d4da --- /dev/null +++ b/beacon_chain/types/src/slashable_vote_data.rs @@ -0,0 +1,70 @@ +use super::ssz::{decode_ssz_list, Decodable, DecodeError, Encodable, SszStream}; +use super::AttestationData; +use bls::AggregateSignature; + +#[derive(Debug, PartialEq, Clone, Default)] +pub struct SlashableVoteData { + pub aggregate_signature_poc_0_indices: Vec, + pub aggregate_signature_poc_1_indices: Vec, + pub data: AttestationData, + pub aggregate_signature: AggregateSignature, +} + +impl Encodable for SlashableVoteData { + fn ssz_append(&self, s: &mut SszStream) { + s.append_vec(&self.aggregate_signature_poc_0_indices); + s.append_vec(&self.aggregate_signature_poc_1_indices); + s.append(&self.data); + s.append(&self.aggregate_signature); + } +} + +impl Decodable for SlashableVoteData { + fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> { + let (aggregate_signature_poc_0_indices, i) = decode_ssz_list(bytes, i)?; + let (aggregate_signature_poc_1_indices, i) = decode_ssz_list(bytes, i)?; + let (data, i) = AttestationData::ssz_decode(bytes, i)?; + let (aggregate_signature, i) = AggregateSignature::ssz_decode(bytes, i)?; + + Ok(( + SlashableVoteData { + aggregate_signature_poc_0_indices, + aggregate_signature_poc_1_indices, + data, + aggregate_signature, + }, + i, + )) + } +} + +#[cfg(test)] +mod tests { + use super::super::ssz::ssz_encode; + use super::super::Hash256; + use super::*; + + #[test] + pub fn test_ssz_round_trip() { + let original = SlashableVoteData { + aggregate_signature_poc_0_indices: vec![0, 1, 2], + aggregate_signature_poc_1_indices: vec![42, 42, 42], + data: AttestationData { + slot: 42, + shard: 16, + beacon_block_hash: Hash256::from("beacon".as_bytes()), + epoch_boundary_hash: Hash256::from("epoch".as_bytes()), + shard_block_hash: Hash256::from("shard".as_bytes()), + latest_crosslink_hash: Hash256::from("xlink".as_bytes()), + justified_slot: 8, + justified_block_hash: Hash256::from("justified".as_bytes()), + }, + aggregate_signature: AggregateSignature::new(), + }; + + let bytes = ssz_encode(&original); + let (decoded, _) = SlashableVoteData::ssz_decode(&bytes, 0).unwrap(); + + assert_eq!(original, decoded); + } +}