diff --git a/Cargo.toml b/Cargo.toml index f2fe2aa7d9..cc77c734fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,8 @@ name = "lighthouse" [workspace] members = [ + "beacon_chain/attestation_validation", + "beacon_chain/block_validation", "beacon_chain/chain", "beacon_chain/naive_fork_choice", "beacon_chain/state-transition", @@ -45,7 +47,6 @@ members = [ "beacon_chain/utils/ssz", "beacon_chain/utils/ssz_helpers", "beacon_chain/utils/vec_shuffle", - "beacon_chain/validation", "beacon_chain/validator_change", "beacon_chain/validator_induction", "beacon_chain/validator_shuffling", diff --git a/beacon_chain/attestation_validation/Cargo.toml b/beacon_chain/attestation_validation/Cargo.toml new file mode 100644 index 0000000000..4606d03ec2 --- /dev/null +++ b/beacon_chain/attestation_validation/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "attestation_validation" +version = "0.1.0" +authors = ["Paul Hauner "] + +[dependencies] +bls = { path = "../utils/bls" } +db = { path = "../../lighthouse/db" } +hashing = { path = "../utils/hashing" } +ssz = { path = "../utils/ssz" } +ssz_helpers = { path = "../utils/ssz_helpers" } +types = { path = "../types" } diff --git a/beacon_chain/attestation_validation/src/enums.rs b/beacon_chain/attestation_validation/src/enums.rs new file mode 100644 index 0000000000..3174d11548 --- /dev/null +++ b/beacon_chain/attestation_validation/src/enums.rs @@ -0,0 +1,34 @@ +/// Reasons why an `AttestationRecord` can be invalid. +pub enum Invalid { + AttestationTooRecent, + AttestationTooOld, + JustifiedSlotImpermissable, + JustifiedBlockNotInChain, + JustifiedBlockHashMismatch, + UnknownShard, + ShardBlockHashMismatch, + SignatureInvalid, +} + +/// The outcome of validating the `AttestationRecord`. +/// +/// Distinct from the `Error` enum as an `Outcome` indicates that validation executed sucessfully +/// and determined the validity `AttestationRecord`. +pub enum Outcome { + Valid, + Invalid(Invalid), +} + +/// Errors that prevent this function from correctly validating the `AttestationRecord`. +/// +/// Distinct from the `Outcome` enum as `Errors` indicate that validation encountered an unexpected +/// condition and was unable to perform its duty. +pub enum Error { + BlockHasNoParent, + BadValidatorIndex, + UnableToLookupBlockAtSlot, + OutOfBoundsBitfieldIndex, + PublicKeyCorrupt, + NoPublicKeyForValidator, + DBError(String), +} diff --git a/beacon_chain/attestation_validation/src/lib.rs b/beacon_chain/attestation_validation/src/lib.rs new file mode 100644 index 0000000000..8a54a31940 --- /dev/null +++ b/beacon_chain/attestation_validation/src/lib.rs @@ -0,0 +1,18 @@ +extern crate bls; +extern crate db; +extern crate hashing; +extern crate ssz; +extern crate ssz_helpers; +extern crate types; + +#[macro_use] +mod macros; +mod enums; +mod validate_for_block; +mod validate_for_state; +mod validate_signature; + +pub use enums::{Invalid, Outcome, Error}; +pub use validate_for_block::validate_attestation_for_block; +pub use validate_for_state::validate_attestation_data_for_state; +pub use validate_signature::validate_attestation_signature; diff --git a/beacon_chain/attestation_validation/src/macros.rs b/beacon_chain/attestation_validation/src/macros.rs new file mode 100644 index 0000000000..faae00fcfa --- /dev/null +++ b/beacon_chain/attestation_validation/src/macros.rs @@ -0,0 +1,19 @@ +macro_rules! verify_or { + ($condition: expr, $result: expr) => { + if !$condition { + $result + } + }; +} + +macro_rules! reject { + ($result: expr) => { + return Ok(Outcome::Invalid($result)); + }; +} + +macro_rules! accept { + () => { + Ok(Outcome::Valid) + }; +} diff --git a/beacon_chain/attestation_validation/src/validate_for_block.rs b/beacon_chain/attestation_validation/src/validate_for_block.rs new file mode 100644 index 0000000000..0094f5c597 --- /dev/null +++ b/beacon_chain/attestation_validation/src/validate_for_block.rs @@ -0,0 +1,33 @@ +use super::{Error, Invalid, Outcome}; + +/// Check that an attestation is valid to be included in some block. +pub fn validate_attestation_for_block( + attestation_slot: u64, + block_slot: u64, + parent_block_slot: u64, + min_attestation_inclusion_delay: u64, + epoch_length: u64, +) -> Result { + /* + * There is a delay before an attestation may be included in a block, quantified by + * `slots` and defined as `min_attestation_inclusion_delay`. + * + * So, an attestation must be at least `min_attestation_inclusion_delay` slots "older" than the + * block it is contained in. + */ + verify_or!( + attestation_slot <= block_slot.saturating_sub(min_attestation_inclusion_delay), + reject!(Invalid::AttestationTooRecent) + ); + + /* + * A block may not include attestations reference slots more than an epoch length + 1 prior to + * the block slot. + */ + verify_or!( + attestation_slot >= parent_block_slot.saturating_sub(epoch_length + 1), + reject!(Invalid::AttestationTooOld) + ); + + accept!() +} diff --git a/beacon_chain/attestation_validation/src/validate_for_state.rs b/beacon_chain/attestation_validation/src/validate_for_state.rs new file mode 100644 index 0000000000..9312dd1256 --- /dev/null +++ b/beacon_chain/attestation_validation/src/validate_for_state.rs @@ -0,0 +1,107 @@ +use super::db::stores::{BeaconBlockAtSlotError, BeaconBlockStore}; +use super::db::ClientDB; +use super::types::Hash256; +use super::types::{AttestationData, BeaconState}; +use super::{Error, Invalid, Outcome}; +use std::sync::Arc; + +/// Check that an attestation is valid with reference to some state. +pub fn validate_attestation_data_for_state( + data: &AttestationData, + chain_tip_block_hash: &Hash256, + state: &BeaconState, + block_store: &Arc>, +) -> Result +where + T: ClientDB + Sized, +{ + /* + * The attestation's `justified_slot` must be the same as the last justified slot known to this + * client. + * + * In the case that an attestation references a slot _before_ the latest state transition, it + * is acceptable for the attestation to reference the previous known `justified_slot`. If this + * were not the case, all attestations created _prior_ to the last state recalculation would be + * rejected if a block was justified in that state recalculation. It is both ideal and likely + * that blocks will be justified during a state recalcuation. + */ + { + let permissable_justified_slot = if data.slot >= state.latest_state_recalculation_slot { + state.justified_slot + } else { + state.previous_justified_slot + }; + verify_or!( + data.justified_slot == permissable_justified_slot, + reject!(Invalid::JustifiedSlotImpermissable) + ); + } + + /* + * The `justified_block_hash` in the attestation must match exactly the hash of the block at + * that slot in the local chain. + * + * This condition also infers that the `justified_slot` specified in attestation must exist + * locally. + */ + match block_hash_at_slot(chain_tip_block_hash, data.justified_slot, block_store)? { + None => reject!(Invalid::JustifiedBlockNotInChain), + Some(local_justified_block_hash) => { + verify_or!( + data.justified_block_hash == local_justified_block_hash, + reject!(Invalid::JustifiedBlockHashMismatch) + ); + } + }; + + /* + * The `shard_block_hash` in the state's `latest_crosslinks` must match either the + * `latest_crosslink_hash` or the `shard_block_hash` on the attestation. + * + * TODO: figure out the reasoning behind this. + */ + match state.latest_crosslinks.get(data.shard as usize) { + None => reject!(Invalid::UnknownShard), + Some(crosslink) => { + let local_shard_block_hash = crosslink.shard_block_hash; + let shard_block_hash_is_permissable = { + (local_shard_block_hash == data.latest_crosslink_hash) + || (local_shard_block_hash == data.shard_block_hash) + }; + verify_or!( + shard_block_hash_is_permissable, + reject!(Invalid::ShardBlockHashMismatch) + ); + } + }; + + accept!() +} + +/// Returns the hash (or None) of a block at a slot in the chain that is specified by +/// `chain_tip_hash`. +/// +/// Given that the database stores multiple chains, it is possible for there to be multiple blocks +/// at the given slot. `chain_tip_hash` specifies exactly which chain should be used. +fn block_hash_at_slot( + chain_tip_hash: &Hash256, + slot: u64, + block_store: &Arc>, +) -> Result, Error> +where + T: ClientDB + Sized, +{ + match block_store.block_at_slot(&chain_tip_hash, slot)? { + None => Ok(None), + Some((hash_bytes, _)) => Ok(Some(Hash256::from(&hash_bytes[..]))), + } +} + +impl From for Error { + fn from(e: BeaconBlockAtSlotError) -> Self { + match e { + BeaconBlockAtSlotError::DBError(s) => Error::DBError(s), + _ => Error::UnableToLookupBlockAtSlot, + } + } +} diff --git a/beacon_chain/attestation_validation/src/validate_signature.rs b/beacon_chain/attestation_validation/src/validate_signature.rs new file mode 100644 index 0000000000..67ba7d2ecb --- /dev/null +++ b/beacon_chain/attestation_validation/src/validate_signature.rs @@ -0,0 +1,64 @@ +use super::bls::{AggregatePublicKey, AggregateSignature}; +use super::db::stores::{ValidatorStore, ValidatorStoreError}; +use super::db::ClientDB; +use super::types::{AttestationData, Bitfield, BitfieldError}; +use super::{Error, Invalid, Outcome}; + +/// Validate that some signature is correct for some attestation data and known validator set. +pub fn validate_attestation_signature( + attestation_data: &AttestationData, + participation_bitfield: &Bitfield, + aggregate_signature: &AggregateSignature, + attestation_indices: &[usize], + validator_store: &ValidatorStore, +) -> Result +where + T: ClientDB + Sized, +{ + let mut agg_pub_key = AggregatePublicKey::new(); + + for i in 0..attestation_indices.len() { + let voted = participation_bitfield.get(i)?; + if voted { + // De-reference the attestation index into a canonical ValidatorRecord index. + let validator = *attestation_indices.get(i).ok_or(Error::BadValidatorIndex)?; + // Load the public key. + let pub_key = validator_store + .get_public_key_by_index(validator)? + .ok_or(Error::NoPublicKeyForValidator)?; + // Aggregate the public key. + agg_pub_key.add(&pub_key); + } + } + + let signed_message = attestation_data_signing_message(attestation_data); + verify_or!( + // TODO: ensure "domain" for aggregate signatures is included. + // https://github.com/sigp/lighthouse/issues/91 + aggregate_signature.verify(&signed_message, &agg_pub_key), + reject!(Invalid::SignatureInvalid) + ); + + accept!() +} + +fn attestation_data_signing_message(attestation_data: &AttestationData) -> Vec { + let mut signed_message = attestation_data.canonical_root().to_vec(); + signed_message.append(&mut vec![0]); + signed_message +} + +impl From for Error { + fn from(error: ValidatorStoreError) -> Self { + match error { + ValidatorStoreError::DBError(s) => Error::DBError(s), + ValidatorStoreError::DecodeError => Error::PublicKeyCorrupt, + } + } +} + +impl From for Error { + fn from(_error: BitfieldError) -> Self { + Error::OutOfBoundsBitfieldIndex + } +} diff --git a/beacon_chain/block_validation/Cargo.toml b/beacon_chain/block_validation/Cargo.toml new file mode 100644 index 0000000000..5a68759c6c --- /dev/null +++ b/beacon_chain/block_validation/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "block_validation" +version = "0.1.0" +authors = ["Paul Hauner "] + +[dependencies] +attestation_validation = { path = "../attestation_validation" } +bls = { path = "../utils/bls" } +db = { path = "../../lighthouse/db" } +hashing = { path = "../utils/hashing" } +rayon = "1.0.2" +ssz = { path = "../utils/ssz" } +ssz_helpers = { path = "../utils/ssz_helpers" } +types = { path = "../types" } diff --git a/beacon_chain/block_validation/src/block_validation.rs b/beacon_chain/block_validation/src/block_validation.rs new file mode 100644 index 0000000000..7898e17c8e --- /dev/null +++ b/beacon_chain/block_validation/src/block_validation.rs @@ -0,0 +1,371 @@ +extern crate rayon; + +use self::rayon::prelude::*; + +use super::attestation_validation::{AttestationValidationContext, AttestationValidationError}; +use super::db::stores::{BeaconBlockStore, PoWChainStore, ValidatorStore}; +use super::db::{ClientDB, DBError}; +use super::ssz::{Decodable, DecodeError}; +use super::ssz_helpers::attestation_ssz_splitter::{ + split_all_attestations, split_one_attestation, AttestationSplitError, +}; +use super::ssz_helpers::ssz_beacon_block::{SszBeaconBlock, SszBeaconBlockError}; +use super::types::Hash256; +use super::types::{AttestationRecord, AttesterMap, BeaconBlock, ProposerMap}; +use std::sync::{Arc, RwLock}; + +#[derive(Debug, PartialEq)] +pub enum SszBeaconBlockValidationError { + FutureSlot, + SlotAlreadyFinalized, + UnknownPoWChainRef, + UnknownParentHash, + BadAttestationSsz, + BadAncestorHashesSsz, + BadSpecialsSsz, + ParentSlotHigherThanBlockSlot, + AttestationValidationError(AttestationValidationError), + AttestationSignatureFailed, + ProposerAttestationHasObliqueHashes, + NoProposerSignature, + BadProposerMap, + RwLockPoisoned, + DBError(String), +} + +/// The context against which a block should be validated. +pub struct BeaconBlockValidationContext +where + T: ClientDB + Sized, +{ + /// The slot as determined by the system time. + pub present_slot: u64, + /// The cycle_length as determined by the chain configuration. + pub cycle_length: u8, + /// The last justified slot as per the client's view of the canonical chain. + pub last_justified_slot: u64, + /// The last justified block hash as per the client's view of the canonical chain. + pub last_justified_block_hash: Hash256, + /// The last finalized slot as per the client's view of the canonical chain. + pub last_finalized_slot: u64, + /// A vec of the hashes of the blocks preceeding the present slot. + pub recent_block_hashes: Arc>, + /// A map of slots to a block proposer validation index. + pub proposer_map: Arc, + /// A map of (slot, shard_id) to the attestation set of validation indices. + pub attester_map: Arc, + /// The store containing block information. + pub block_store: Arc>, + /// The store containing validator information. + pub validator_store: Arc>, + /// The store containing information about the proof-of-work chain. + pub pow_store: Arc>, +} + +impl BeaconBlockValidationContext +where + T: ClientDB, +{ + /// Validate some SszBeaconBlock against a block validation context. An SszBeaconBlock varies from a BeaconBlock in + /// that is a read-only structure that reads directly from encoded SSZ. + /// + /// The reason to validate an SzzBeaconBlock is to avoid decoding it in its entirety if there is + /// a suspicion that the block might be invalid. Such a suspicion should be applied to + /// all blocks coming from the network. + /// + /// This function will determine if the block is new, already known or invalid (either + /// intrinsically or due to some application error.) + /// + /// Note: this function does not implement randao_reveal checking as it is not in the + /// specification. + #[allow(dead_code)] + pub fn validate_ssz_block( + &self, + b: &SszBeaconBlock, + ) -> Result + where + T: ClientDB + Sized, + { + /* + * If the block slot corresponds to a slot in the future, return immediately with an error. + * + * It is up to the calling fn to determine what should be done with "future" blocks (e.g., + * cache or discard). + */ + let block_slot = b.slot(); + if block_slot > self.present_slot { + return Err(SszBeaconBlockValidationError::FutureSlot); + } + + /* + * If the block is unknown (assumed unknown because we checked the db earlier in this + * function) and it comes from a slot that is already finalized, drop the block. + * + * If a slot is finalized, there's no point in considering any other blocks for that slot. + * + * TODO: We can more strongly throw away blocks based on the `last_finalized_block` related + * to this `last_finalized_slot`. Namely, any block in a future slot must include the + * `last_finalized_block` in it's chain. + */ + if block_slot <= self.last_finalized_slot { + return Err(SszBeaconBlockValidationError::SlotAlreadyFinalized); + } + + /* + * If the PoW chain hash is not known to us, drop it. + * + * We only accept blocks that reference a known PoW hash. + * + * Note: it is not clear what a "known" PoW chain ref is. Likely it means the block hash is + * "sufficienty deep in the canonical PoW chain". This should be clarified as the spec + * crystallizes. + */ + let pow_chain_reference = b.pow_chain_reference(); + if !self.pow_store.block_hash_exists(b.pow_chain_reference())? { + return Err(SszBeaconBlockValidationError::UnknownPoWChainRef); + } + + /* + * Store a slice of the serialized attestations from the block SSZ. + */ + let attestations_ssz = &b.attestations_without_length(); + + /* + * Get a slice of the first serialized attestation (the 0'th) and decode it into + * a full AttestationRecord object. + * + * The first attestation must be validated separately as it must contain a signature of the + * proposer of the previous block (this is checked later in this function). + */ + let (first_attestation_ssz, next_index) = split_one_attestation(&attestations_ssz, 0)?; + let (first_attestation, _) = AttestationRecord::ssz_decode(&first_attestation_ssz, 0)?; + + /* + * The first attestation may not have oblique hashes. + * + * The presence of oblique hashes in the first attestation would indicate that the proposer + * of the previous block is attesting to some other block than the one they produced. + */ + if !first_attestation.oblique_parent_hashes.is_empty() { + return Err(SszBeaconBlockValidationError::ProposerAttestationHasObliqueHashes); + } + + /* + * Read the parent hash from the block we are validating then attempt to load + * that parent block ssz from the database. + * + * If that parent doesn't exist in the database or is invalid, reject the block. + * + * Also, read the slot from the parent block for later use. + */ + let parent_hash = b + .parent_hash() + .ok_or(SszBeaconBlockValidationError::BadAncestorHashesSsz)?; + let parent_block_slot = match self.block_store.get_serialized_block(&parent_hash)? { + None => return Err(SszBeaconBlockValidationError::UnknownParentHash), + Some(ssz) => { + let parent_block = SszBeaconBlock::from_slice(&ssz[..])?; + parent_block.slot() + } + }; + + /* + * The parent block slot must be less than the block slot. + * + * In other words, the parent must come before the child. + */ + if parent_block_slot >= block_slot { + return Err(SszBeaconBlockValidationError::ParentSlotHigherThanBlockSlot); + } + + /* + * Generate the context in which attestations will be validated. + */ + let attestation_validation_context = Arc::new(AttestationValidationContext { + block_slot, + parent_block_slot, + cycle_length: self.cycle_length, + last_justified_slot: self.last_justified_slot, + recent_block_hashes: self.recent_block_hashes.clone(), + block_store: self.block_store.clone(), + validator_store: self.validator_store.clone(), + attester_map: self.attester_map.clone(), + }); + + /* + * Validate this first attestation. + */ + let attestation_voters = + attestation_validation_context.validate_attestation(&first_attestation)?; + + /* + * Attempt to read load the parent block proposer from the proposer map. Return with an + * error if it fails. + * + * If the signature of proposer for the parent slot was not present in the first (0'th) + * attestation of this block, reject the block. + */ + let parent_block_proposer = self + .proposer_map + .get(&parent_block_slot) + .ok_or(SszBeaconBlockValidationError::BadProposerMap)?; + if !attestation_voters.contains(&parent_block_proposer) { + return Err(SszBeaconBlockValidationError::NoProposerSignature); + } + + /* + * Split the remaining attestations into a vector of slices, each containing + * a single serialized attestation record. + */ + let other_attestations = split_all_attestations(attestations_ssz, next_index)?; + + /* + * Verify each other AttestationRecord. + * + * This uses the `rayon` library to do "sometimes" parallelization. Put simply, + * if there are some spare threads, the verification of attestation records will happen + * concurrently. + * + * There is a thread-safe `failure` variable which is set whenever an attestation fails + * validation. This is so all attestation validation is halted if a single bad attestation + * is found. + */ + let failure: RwLock> = RwLock::new(None); + let mut deserialized_attestations: Vec = other_attestations + .par_iter() + .filter_map(|attestation_ssz| { + /* + * If some thread has set the `failure` variable to `Some(error)` the abandon + * attestation serialization and validation. Also, fail early if the lock has been + * poisoned. + */ + match failure.read() { + Ok(ref option) if option.is_none() => (), + _ => return None, + } + /* + * If there has not been a failure yet, attempt to serialize and validate the + * attestation. + */ + match AttestationRecord::ssz_decode(&attestation_ssz, 0) { + /* + * Deserialization failed, therefore the block is invalid. + */ + Err(e) => { + /* + * If the failure lock isn't poisoned, set it to some error. + */ + if let Ok(mut f) = failure.write() { + *f = Some(SszBeaconBlockValidationError::from(e)); + } + None + } + /* + * Deserialization succeeded and the attestation should be validated. + */ + Ok((attestation, _)) => { + match attestation_validation_context.validate_attestation(&attestation) { + /* + * Attestation validation failed with some error. + */ + Err(e) => { + /* + * If the failure lock isn't poisoned, set it to some error. + */ + if let Ok(mut f) = failure.write() { + *f = Some(SszBeaconBlockValidationError::from(e)); + } + None + } + /* + * Attestation validation succeded. + */ + Ok(_) => Some(attestation), + } + } + } + }).collect(); + + match failure.into_inner() { + Err(_) => return Err(SszBeaconBlockValidationError::RwLockPoisoned), + Ok(failure) => match failure { + Some(error) => return Err(error), + _ => (), + }, + } + + /* + * Add the first attestation to the vec of deserialized attestations at + * index 0. + */ + deserialized_attestations.insert(0, first_attestation); + + let (ancestor_hashes, _) = Decodable::ssz_decode(&b.ancestor_hashes(), 0) + .map_err(|_| SszBeaconBlockValidationError::BadAncestorHashesSsz)?; + let (specials, _) = Decodable::ssz_decode(&b.specials(), 0) + .map_err(|_| SszBeaconBlockValidationError::BadSpecialsSsz)?; + + /* + * If we have reached this point, the block is a new valid block that is worthy of + * processing. + */ + let block = BeaconBlock { + slot: block_slot, + randao_reveal: Hash256::from(b.randao_reveal()), + pow_chain_reference: Hash256::from(pow_chain_reference), + ancestor_hashes, + active_state_root: Hash256::from(b.act_state_root()), + crystallized_state_root: Hash256::from(b.cry_state_root()), + attestations: deserialized_attestations, + specials, + }; + Ok(block) + } +} + +impl From for SszBeaconBlockValidationError { + fn from(e: DBError) -> Self { + SszBeaconBlockValidationError::DBError(e.message) + } +} + +impl From for SszBeaconBlockValidationError { + fn from(e: AttestationSplitError) -> Self { + match e { + AttestationSplitError::TooShort => SszBeaconBlockValidationError::BadAttestationSsz, + } + } +} + +impl From for SszBeaconBlockValidationError { + fn from(e: SszBeaconBlockError) -> Self { + match e { + SszBeaconBlockError::TooShort => { + SszBeaconBlockValidationError::DBError("Bad parent block in db.".to_string()) + } + SszBeaconBlockError::TooLong => { + SszBeaconBlockValidationError::DBError("Bad parent block in db.".to_string()) + } + } + } +} + +impl From for SszBeaconBlockValidationError { + fn from(e: DecodeError) -> Self { + match e { + DecodeError::TooShort => SszBeaconBlockValidationError::BadAttestationSsz, + DecodeError::TooLong => SszBeaconBlockValidationError::BadAttestationSsz, + } + } +} + +impl From for SszBeaconBlockValidationError { + fn from(e: AttestationValidationError) -> Self { + SszBeaconBlockValidationError::AttestationValidationError(e) + } +} + +/* + * Tests for block validation are contained in the root directory "tests" directory (AKA + * "integration tests directory"). + */ diff --git a/beacon_chain/block_validation/src/lib.rs b/beacon_chain/block_validation/src/lib.rs new file mode 100644 index 0000000000..c4eae2bd8f --- /dev/null +++ b/beacon_chain/block_validation/src/lib.rs @@ -0,0 +1,9 @@ +extern crate attestation_validation; +extern crate bls; +extern crate db; +extern crate hashing; +extern crate ssz; +extern crate ssz_helpers; +extern crate types; + +pub mod block_validation; diff --git a/beacon_chain/types/src/attestation_data.rs b/beacon_chain/types/src/attestation_data.rs index 0e87ace6a3..43c1b8350a 100644 --- a/beacon_chain/types/src/attestation_data.rs +++ b/beacon_chain/types/src/attestation_data.rs @@ -37,6 +37,12 @@ impl AttestationData { justified_block_hash: Hash256::zero(), } } + + // TODO: Implement this as a merkle root, once tree_ssz is implemented. + // https://github.com/sigp/lighthouse/issues/92 + pub fn canonical_root(&self) -> Hash256 { + Hash256::zero() + } } impl Encodable for AttestationData { diff --git a/beacon_chain/types/src/chain_config.rs b/beacon_chain/types/src/chain_config.rs index bcc565a757..8428945bb4 100644 --- a/beacon_chain/types/src/chain_config.rs +++ b/beacon_chain/types/src/chain_config.rs @@ -2,6 +2,7 @@ use super::ValidatorRegistration; #[derive(Debug, Clone, PartialEq)] pub struct ChainConfig { + // Old, potentially outdated constants pub cycle_length: u8, pub deposit_size_gwei: u64, pub shard_count: u16, @@ -10,6 +11,10 @@ pub struct ChainConfig { pub genesis_time: u64, pub slot_duration_millis: u64, pub initial_validators: Vec, + + // New constants + pub epoch_length: u64, + pub min_attestation_inclusion_delay: u64, } /* @@ -28,6 +33,10 @@ impl ChainConfig { genesis_time: TEST_GENESIS_TIME, slot_duration_millis: 16 * 1000, initial_validators: vec![], + + // New + epoch_length: 64, + min_attestation_inclusion_delay: 4, } } @@ -54,6 +63,10 @@ impl ChainConfig { genesis_time: TEST_GENESIS_TIME, // arbitrary slot_duration_millis: 16 * 1000, initial_validators: vec![], + + // New constants + epoch_length: 64, + min_attestation_inclusion_delay: 4, } } } diff --git a/beacon_chain/types/src/crosslink_record.rs b/beacon_chain/types/src/crosslink_record.rs index d28df43509..3f7ac2f1af 100644 --- a/beacon_chain/types/src/crosslink_record.rs +++ b/beacon_chain/types/src/crosslink_record.rs @@ -2,31 +2,16 @@ use super::Hash256; #[derive(Clone, Debug, PartialEq)] pub struct CrosslinkRecord { - pub recently_changed: bool, pub slot: u64, - pub hash: Hash256, + pub shard_block_hash: Hash256, } impl CrosslinkRecord { /// Generates a new instance where `dynasty` and `hash` are both zero. pub fn zero() -> Self { Self { - recently_changed: false, slot: 0, - hash: Hash256::zero(), + shard_block_hash: Hash256::zero(), } } } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_crosslink_record_zero() { - let c = CrosslinkRecord::zero(); - assert_eq!(c.recently_changed, false); - assert_eq!(c.slot, 0); - assert!(c.hash.is_zero()); - } -}