From 61fddb26606d81b8b06ec6cf1cba439890c5e1b6 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Wed, 19 Sep 2018 16:15:05 +1000 Subject: [PATCH] Implement basics for ssz_block --- lighthouse/state/attestation_record.rs | 10 +++ lighthouse/state/block/ssz_block.rs | 97 +++++++++++++++++++++----- 2 files changed, 88 insertions(+), 19 deletions(-) diff --git a/lighthouse/state/attestation_record.rs b/lighthouse/state/attestation_record.rs index 9fa8fc73a..35d61f583 100644 --- a/lighthouse/state/attestation_record.rs +++ b/lighthouse/state/attestation_record.rs @@ -2,6 +2,16 @@ use super::utils::types::{ Hash256, Bitfield }; use super::utils::bls::{ AggregateSignature }; use super::ssz::{ Encodable, SszStream }; +pub const MIN_SSZ_ATTESTION_RECORD_LENGTH: usize = { + 8 + // slot + 2 + // shard_id + 4 + // oblique_parent_hashes (empty list) + 32 + // shard_block_hash + 5 + // attester_bitfield (assuming 1 byte of bitfield) + 8 + // justified_slot + 32 + // justified_block_hash + 2 * 32 // aggregate sig (two 256 bit points) +}; pub struct AttestationRecord { pub slot: u64, diff --git a/lighthouse/state/block/ssz_block.rs b/lighthouse/state/block/ssz_block.rs index 8ee7580a2..8643a531e 100644 --- a/lighthouse/state/block/ssz_block.rs +++ b/lighthouse/state/block/ssz_block.rs @@ -3,9 +3,13 @@ use super::ssz::decode::{ Decodable, }; use super::utils::hash::canonical_hash; +use super::attestation_record::MIN_SSZ_ATTESTION_RECORD_LENGTH; +#[derive(Debug, PartialEq)] pub enum BlockValidatorError { - SszInvalid, + TooShort, + TooLong, + NoAttestationRecords, BadPowHash, SlotTooLow, SlotTooHigh, @@ -21,36 +25,56 @@ const MIN_SSZ_BLOCK_LENGTH: usize = { 32 + // active_state_root 32 // crystallized_state_root }; -const MAX_SSZ_BLOCK_LENGTH: usize = MIN_SSZ_BLOCK_LENGTH + 2^24; +const MAX_SSZ_BLOCK_LENGTH: usize = MIN_SSZ_BLOCK_LENGTH + (1 << 24); /// Allows for reading of block values directly from serialized /// ssz bytes. +#[derive(Debug, PartialEq)] pub struct SszBlock<'a> { ssz: &'a [u8], attestation_len: usize, + pub len: usize, } impl<'a> SszBlock<'a> { - pub fn from_vec(vec: &'a Vec) + pub fn from_slice(vec: &'a [u8]) -> Result { let ssz = &vec[..]; - if vec.len() < MIN_SSZ_BLOCK_LENGTH { - return Err(BlockValidatorError::SszInvalid); + let len = vec.len(); + /* + * Ensure the SSZ is long enough to be a block. + */ + if len < MIN_SSZ_BLOCK_LENGTH { + return Err(BlockValidatorError::TooShort); } - if vec.len() > MAX_SSZ_BLOCK_LENGTH { - return Err(BlockValidatorError::SszInvalid); + /* + * Ensure the SSZ slice isn't longer than is possible for a block. + */ + if len > MAX_SSZ_BLOCK_LENGTH { + return Err(BlockValidatorError::TooLong); } + /* + * Determine how many bytes are used to store attestation records + * and ensure that length is enough to store at least one attestation + * record. + */ let attestation_len = decode_length(ssz, 72, LENGTH_BYTES) - .map_err(|_| BlockValidatorError::SszInvalid)?; - // Is the length adequate now we know now many attestation - // records exist? - if vec.len() < (76 + attestation_len + 96) { - return Err(BlockValidatorError::SszInvalid); + .map_err(|_| BlockValidatorError::TooShort)?; + if attestation_len < MIN_SSZ_ATTESTION_RECORD_LENGTH { + return Err(BlockValidatorError::NoAttestationRecords) + } + /* + * Ensure that the SSZ is long enough, now we know the + * length of the attestation records field. + */ + if len < (76 + attestation_len + 96) { + return Err(BlockValidatorError::TooShort); } Ok(Self{ ssz, - attestation_len + attestation_len, + len, }) } @@ -76,17 +100,52 @@ impl<'a> SszBlock<'a> { } pub fn pow_chain_ref(&self) -> &[u8] { - let len = self.ssz.len(); - &self.ssz[(len - 96)..(len - 64)] + &self.ssz[(self.len - 96)..(self.len - 64)] } pub fn act_state_root(&self) -> &[u8] { - let len = self.ssz.len(); - &self.ssz[(len - 64)..(len - 32)] + &self.ssz[(self.len - 64)..(self.len - 32)] } pub fn cry_state_root(&self) -> &[u8] { - let len = self.ssz.len(); - &self.ssz[(len - 32)..(len)] + &self.ssz[(self.len - 32)..(self.len)] + } +} + +#[cfg(test)] +mod tests { + use super::*; + use super::super::block::Block; + use super::super::attestation_record::AttestationRecord; + use super::super::ssz::SszStream; + + fn get_block_ssz(b: &Block) -> Vec { + let mut ssz_stream = SszStream::new(); + ssz_stream.append(b); + ssz_stream.drain() + } + + #[test] + fn test_ssz_block_zero_attestation_records() { + let mut b = Block::zero(); + b.attestations = vec![]; + let ssz = get_block_ssz(&b); + + assert_eq!( + SszBlock::from_slice(&ssz[..]), + Err(BlockValidatorError::NoAttestationRecords) + ); + } + + #[test] + fn test_ssz_block_single_attestation_record() { + let mut b = Block::zero(); + b.attestations = vec![AttestationRecord::zero()]; + let ssz = get_block_ssz(&b); + + assert_eq!( + SszBlock::from_slice(&ssz[..]), + Err(BlockValidatorError::NoAttestationRecords) + ); } }