Complete attestation_validation, bar tests

This commit is contained in:
Paul Hauner 2018-12-10 09:09:21 +11:00
parent a8bfa4d733
commit 0f9482f9d1
No known key found for this signature in database
GPG Key ID: 303E4494BB28068C
9 changed files with 119 additions and 56 deletions

View File

@ -37,6 +37,7 @@ pub fn validate_attestation_for_block(
#[cfg(test)]
mod tests {
use super::*;
/*
* Invalid::AttestationTooOld tests.
*/

View File

@ -1,42 +1,25 @@
use super::db::stores::{BeaconBlockAtSlotError, BeaconBlockStore};
use super::db::ClientDB;
use super::types::AttestationData;
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<T>(
/// Verify that a attestation's `data.justified_block_hash` matches the local hash of the block at the
/// attestation's `data.justified_slot`.
///
/// `chain_tip_block_hash` is the tip of the chain in which the justified block hash should exist
/// locally. As Lightouse stores multiple chains locally, it is possible to have multiple blocks at
/// the same slot. `chain_tip_block_hash` serves to restrict the lookup to a single chain, where
/// each slot may have exactly zero or one blocks.
pub fn validate_attestation_justified_block_hash<T>(
data: &AttestationData,
chain_tip_block_hash: &Hash256,
state: &BeaconState,
block_store: &Arc<BeaconBlockStore<T>>,
) -> Result<Outcome, Error>
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.
@ -53,28 +36,6 @@ where
);
}
};
/*
* 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!()
}
@ -105,3 +66,15 @@ impl From<BeaconBlockAtSlotError> for Error {
}
}
}
#[cfg(test)]
mod tests {
/*
* TODO: Implement tests.
*
* These tests will require the `BeaconBlock` and `BeaconBlockBody` updates, which are not
* yet included in the code base. Adding tests now will result in duplicated work.
*
* https://github.com/sigp/lighthouse/issues/97
*/
}

View File

@ -0,0 +1,38 @@
use super::types::{AttestationData, BeaconState};
use super::{Error, Invalid, Outcome};
/// Verify that an attestation's `data.justified_slot` matches the justified slot known to the
/// `state`.
///
/// In the case that an attestation references a slot _before_ the latest state transition, 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.
pub fn validate_attestation_justified_slot(
data: &AttestationData,
state: &BeaconState,
) -> Result<Outcome, Error> {
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)
);
accept!()
}
#[cfg(test)]
mod tests {
/*
* TODO: Implement tests.
*
* These tests will require the `BeaconBlock` and `BeaconBlockBody` updates, which are not
* yet included in the code base. Adding tests now will result in duplicated work.
*
* https://github.com/sigp/lighthouse/issues/97
*/
}

View File

@ -7,12 +7,17 @@ extern crate types;
#[macro_use]
mod macros;
mod block_inclusion;
mod enums;
mod validate_for_block;
mod validate_for_state;
mod validate_signature;
mod justified_block;
mod justified_slot;
mod shard_block;
mod 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;
pub use block_inclusion::validate_attestation_for_block;
pub use justified_slot::validate_attestation_justified_slot;
pub use justified_block::validate_attestation_justified_block_hash;
pub use signature::validate_attestation_signature;
pub use shard_block::validate_attestation_data_shard_block_hash;

View File

@ -0,0 +1,46 @@
use super::db::ClientDB;
use super::types::{AttestationData, BeaconState};
use super::{Error, Invalid, Outcome};
/// Check that an attestation is valid with reference to some state.
pub fn validate_attestation_data_shard_block_hash<T>(
data: &AttestationData,
state: &BeaconState,
) -> Result<Outcome, Error>
where
T: ClientDB + Sized,
{
/*
* 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!()
}
#[cfg(test)]
mod tests {
/*
* TODO: Implement tests.
*
* These tests will require the `BeaconBlock` and `BeaconBlockBody` updates, which are not
* yet included in the code base. Adding tests now will result in duplicated work.
*
* https://github.com/sigp/lighthouse/issues/97
*/
}

View File

@ -12,7 +12,7 @@ pub const SSZ_ATTESTION_DATA_LENGTH: usize = {
32 // justified_block_hash
};
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Default)]
pub struct AttestationData {
pub slot: u64,
pub shard: u64,

View File

@ -15,7 +15,7 @@ pub const MIN_SSZ_BLOCK_LENGTH: usize = {
};
pub const MAX_SSZ_BLOCK_LENGTH: usize = MIN_SSZ_BLOCK_LENGTH + (1 << 24);
#[derive(Debug, PartialEq, Clone)]
#[derive(Debug, PartialEq, Clone, Default)]
pub struct BeaconBlock {
pub slot: u64,
pub randao_reveal: Hash256,