-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Beacon block #50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Beacon block #50
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
064e87a
Add SpecialRecord struct
paulhauner 561167f
Fix panic in ssz decode
paulhauner a862c82
Rename Block -> BeaconBlock
paulhauner e289d8b
Fix comment in attestation_validation
paulhauner cd05616
Merge branch 'validation' into beacon_block
paulhauner e91317c
Change SpecialRecord to use u8 instead of enum
paulhauner 1621901
Update SSZ
paulhauner 1207421
Fix broken block_store test
paulhauner f31d41e
Implement SSZ decode for BeaconBlock, fix encode
paulhauner c45e05c
Update SszBeaconBlock as per new spec
paulhauner c3d88a7
Update validation as per new spec
paulhauner fa70522
Fix clippy lints
paulhauner 1acfb87
Merge branch 'master' into beacon_block
paulhauner 6ee3ad1
Change integer literals to constants
paulhauner 694db90
Simplify parent_hashes code
paulhauner File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,150 @@ | ||
| use super::Hash256; | ||
| use super::attestation_record::AttestationRecord; | ||
| use super::special_record::SpecialRecord; | ||
| use super::ssz::{ | ||
| Encodable, | ||
| Decodable, | ||
| DecodeError, | ||
| SszStream, | ||
| }; | ||
|
|
||
| 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); | ||
|
|
||
| #[derive(Debug, PartialEq, Clone)] | ||
| pub struct BeaconBlock { | ||
| pub slot: u64, | ||
| pub randao_reveal: Hash256, | ||
| pub pow_chain_reference: Hash256, | ||
| pub ancestor_hashes: Vec<Hash256>, | ||
| pub active_state_root: Hash256, | ||
| pub crystallized_state_root: Hash256, | ||
| pub attestations: Vec<AttestationRecord>, | ||
| pub specials: Vec<SpecialRecord>, | ||
| } | ||
|
|
||
| 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) | ||
| } | ||
| } | ||
|
|
||
| impl Encodable for BeaconBlock { | ||
| fn ssz_append(&self, s: &mut SszStream) { | ||
| s.append(&self.slot); | ||
| 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())); | ||
| } | ||
| } | ||
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| use super::ssz::{ | ||
| Encodable, | ||
| Decodable, | ||
| DecodeError, | ||
| SszStream, | ||
| }; | ||
|
|
||
|
|
||
| /// The value of the "type" field of SpecialRecord. | ||
| /// | ||
| /// Note: this value must serialize to a u8 and therefore must not be greater than 255. | ||
| #[derive(Debug, PartialEq, Clone, Copy)] | ||
| pub enum SpecialRecordKind { | ||
| Logout = 0, | ||
| CasperSlashing = 1, | ||
| RandaoChange = 2, | ||
| } | ||
|
|
||
|
|
||
| /// The structure used in the `BeaconBlock.specials` field. | ||
| #[derive(Debug, PartialEq, Clone)] | ||
| pub struct SpecialRecord { | ||
| pub kind: u8, | ||
| pub data: Vec<u8>, | ||
| } | ||
|
|
||
| impl SpecialRecord { | ||
| pub fn logout(data: &[u8]) -> Self { | ||
| Self { | ||
| kind: SpecialRecordKind::Logout as u8, | ||
| data: data.to_vec(), | ||
| } | ||
| } | ||
|
|
||
| pub fn casper_slashing(data: &[u8]) -> Self { | ||
| Self { | ||
| kind: SpecialRecordKind::CasperSlashing as u8, | ||
| data: data.to_vec(), | ||
| } | ||
| } | ||
|
|
||
| pub fn randao_change(data: &[u8]) -> Self { | ||
| Self { | ||
| kind: SpecialRecordKind::RandaoChange as u8, | ||
| data: data.to_vec(), | ||
| } | ||
| } | ||
|
|
||
| /// Match `self.kind` to a `SpecialRecordKind`. | ||
| /// | ||
| /// Returns `None` if `self.kind` is an unknown value. | ||
| fn resolve_kind(&self) -> Option<SpecialRecordKind> { | ||
| match self.kind { | ||
| x if x == SpecialRecordKind::Logout as u8 | ||
| => Some(SpecialRecordKind::Logout), | ||
| x if x == SpecialRecordKind::CasperSlashing as u8 | ||
| => Some(SpecialRecordKind::CasperSlashing), | ||
| x if x == SpecialRecordKind::RandaoChange as u8 | ||
| => Some(SpecialRecordKind::RandaoChange), | ||
| _ => None | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl Encodable for SpecialRecord { | ||
| fn ssz_append(&self, s: &mut SszStream) { | ||
| s.append(&self.kind); | ||
| s.append_vec(&self.data); | ||
| } | ||
| } | ||
|
|
||
| impl Decodable for SpecialRecord { | ||
| fn ssz_decode(bytes: &[u8], i: usize) | ||
| -> Result<(Self, usize), DecodeError> | ||
| { | ||
| let (kind, i) = u8::ssz_decode(bytes, i)?; | ||
| let (data, i) = Decodable::ssz_decode(bytes, i)?; | ||
| Ok((SpecialRecord{kind, data}, i)) | ||
| } | ||
| } | ||
|
|
||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| pub fn test_special_record_ssz_encode() { | ||
| let s = SpecialRecord::logout(&vec![]); | ||
| let mut ssz_stream = SszStream::new(); | ||
| ssz_stream.append(&s); | ||
| let ssz = ssz_stream.drain(); | ||
| assert_eq!(ssz, vec![0, 0, 0, 0, 0]); | ||
|
|
||
| let s = SpecialRecord::casper_slashing(&vec![]); | ||
| let mut ssz_stream = SszStream::new(); | ||
| ssz_stream.append(&s); | ||
| let ssz = ssz_stream.drain(); | ||
| assert_eq!(ssz, vec![1, 0, 0, 0, 0]); | ||
|
|
||
| let s = SpecialRecord::randao_change(&vec![]); | ||
| let mut ssz_stream = SszStream::new(); | ||
| ssz_stream.append(&s); | ||
| let ssz = ssz_stream.drain(); | ||
| assert_eq!(ssz, vec![2, 0, 0, 0, 0]); | ||
|
|
||
| let s = SpecialRecord::randao_change(&vec![42, 43, 44]); | ||
| let mut ssz_stream = SszStream::new(); | ||
| ssz_stream.append(&s); | ||
| let ssz = ssz_stream.drain(); | ||
| assert_eq!(ssz, vec![2, 0, 0, 0, 3, 42, 43, 44]); | ||
| } | ||
|
|
||
| #[test] | ||
| pub fn test_special_record_ssz_encode_decode() { | ||
| let s = SpecialRecord::randao_change(&vec![13, 16, 14]); | ||
| let mut ssz_stream = SszStream::new(); | ||
| ssz_stream.append(&s); | ||
| let ssz = ssz_stream.drain(); | ||
| let (s_decoded, _) = SpecialRecord::ssz_decode(&ssz, 0).unwrap(); | ||
| assert_eq!(s, s_decoded); | ||
| } | ||
|
|
||
| #[test] | ||
| pub fn test_special_record_resolve_kind() { | ||
| let s = SpecialRecord::logout(&vec![]); | ||
| assert_eq!(s.resolve_kind(), Some(SpecialRecordKind::Logout)); | ||
|
|
||
| let s = SpecialRecord::casper_slashing(&vec![]); | ||
| assert_eq!(s.resolve_kind(), Some(SpecialRecordKind::CasperSlashing)); | ||
|
|
||
| let s = SpecialRecord::randao_change(&vec![]); | ||
| assert_eq!(s.resolve_kind(), Some(SpecialRecordKind::RandaoChange)); | ||
|
|
||
| let s = SpecialRecord { kind: 88, data: vec![] }; | ||
| assert_eq!(s.resolve_kind(), None); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not do something like
const SLOT: usize = 8;for all the fields?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented. Great point @HCastano