spec v0.6.1: verify attester slashing

This commit is contained in:
Michael Sproul 2019-05-20 15:06:36 +10:00
parent 58481c7119
commit dab11c1eed
No known key found for this signature in database
GPG Key ID: 77B1309D2E54E914

View File

@ -7,30 +7,27 @@ use types::*;
/// ///
/// Returns `Ok(())` if the `AttesterSlashing` is valid, otherwise indicates the reason for invalidity. /// Returns `Ok(())` if the `AttesterSlashing` is valid, otherwise indicates the reason for invalidity.
/// ///
/// Spec v0.5.1 /// Spec v0.6.1
pub fn verify_attester_slashing<T: EthSpec>( pub fn verify_attester_slashing<T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
attester_slashing: &AttesterSlashing, attester_slashing: &AttesterSlashing,
should_verify_indexed_attestations: bool, should_verify_indexed_attestations: bool,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<(), Error> { ) -> Result<(), Error> {
let indexed_attestation_1 = &attester_slashing.indexed_attestation_1; let attestation_1 = &attester_slashing.attestation_1;
let indexed_attestation_2 = &attester_slashing.indexed_attestation_2; let attestation_2 = &attester_slashing.attestation_2;
// Spec: is_slashable_attestation_data
verify!( verify!(
indexed_attestation_1.data != indexed_attestation_2.data, attestation_1.is_double_vote(attestation_2, spec)
Invalid::AttestationDataIdentical || attestation_1.is_surround_vote(attestation_2, spec),
);
verify!(
indexed_attestation_1.is_double_vote(indexed_attestation_2, spec)
| indexed_attestation_1.is_surround_vote(indexed_attestation_2, spec),
Invalid::NotSlashable Invalid::NotSlashable
); );
if should_verify_indexed_attestations { if should_verify_indexed_attestations {
verify_indexed_attestation(state, &indexed_attestation_1, spec) verify_indexed_attestation(state, &attestation_1, spec)
.map_err(|e| Error::Invalid(Invalid::IndexedAttestation1Invalid(e.into())))?; .map_err(|e| Error::Invalid(Invalid::IndexedAttestation1Invalid(e.into())))?;
verify_indexed_attestation(state, &indexed_attestation_2, spec) verify_indexed_attestation(state, &attestation_2, spec)
.map_err(|e| Error::Invalid(Invalid::IndexedAttestation2Invalid(e.into())))?; .map_err(|e| Error::Invalid(Invalid::IndexedAttestation2Invalid(e.into())))?;
} }
@ -41,8 +38,8 @@ pub fn verify_attester_slashing<T: EthSpec>(
/// ///
/// Returns Ok(indices) if `indices.len() > 0`. /// Returns Ok(indices) if `indices.len() > 0`.
/// ///
/// Spec v0.5.1 /// Spec v0.6.1
pub fn gather_attester_slashing_indices<T: EthSpec>( pub fn get_slashable_indices<T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
attester_slashing: &AttesterSlashing, attester_slashing: &AttesterSlashing,
spec: &ChainSpec, spec: &ChainSpec,
@ -50,47 +47,47 @@ pub fn gather_attester_slashing_indices<T: EthSpec>(
gather_attester_slashing_indices_modular( gather_attester_slashing_indices_modular(
state, state,
attester_slashing, attester_slashing,
|_, validator| validator.slashed, |_, validator| validator.is_slashable_at(state.current_epoch()),
spec, spec,
) )
} }
/// Same as `gather_attester_slashing_indices` but allows the caller to specify the criteria /// Same as `gather_attester_slashing_indices` but allows the caller to specify the criteria
/// for determining whether a given validator should be considered slashed. /// for determining whether a given validator should be considered slashable.
pub fn gather_attester_slashing_indices_modular<F, T: EthSpec>( pub fn get_slashable_indices_modular<F, T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
attester_slashing: &AttesterSlashing, attester_slashing: &AttesterSlashing,
is_slashed: F, is_slashable: F,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<Vec<u64>, Error> ) -> Result<Vec<u64>, Error>
where where
F: Fn(u64, &Validator) -> bool, F: Fn(u64, &Validator) -> bool,
{ {
let indexed_attestation_1 = &attester_slashing.indexed_attestation_1; let attestation_1 = &attester_slashing.attestation_1;
let indexed_attestation_2 = &attester_slashing.indexed_attestation_2; let attestation_2 = &attester_slashing.attestation_2;
let mut indexed_indices = Vec::with_capacity(spec.max_indices_per_indexed_vote); let mut attesting_indices_1 = HashSet::new();
for i in &indexed_attestation_1.validator_indices { attesting_indices_1.extend(attestation_1.custody_bit_0_indices.clone());
attesting_indices_1.extend(attestation_1.custody_bit_1_indices.clone());
let mut attesting_indices_2 = HashSet::new();
attesting_indices_2.extend(attestation_2.custody_bit_0_indices.clone());
attesting_indices_2.extend(attestation_2.custody_bit_1_indices.clone());
let mut slashable_indices = vec![];
for index in &attesting_indices_1 & &attesting_indices_2 {
let validator = state let validator = state
.validator_registry .validator_registry
.get(*i as usize) .get(index as usize)
.ok_or_else(|| Error::Invalid(Invalid::UnknownValidator(*i)))?; .ok_or_else(|| Error::Invalid(Invalid::UnknownValidator(index)))?;
if indexed_attestation_2.validator_indices.contains(&i) & !is_slashed(*i, validator) { if is_slashable(index, validator) {
// TODO: verify that we should reject any indexed attestation which includes a slashable_indices.push(index);
// withdrawn validator. PH has asked the question on gitter, awaiting response.
verify!(
validator.withdrawable_epoch > state.slot.epoch(spec.slots_per_epoch),
Invalid::ValidatorAlreadyWithdrawn(*i)
);
indexed_indices.push(*i);
} }
} }
verify!(!indexed_indices.is_empty(), Invalid::NoSlashableIndices); verify!(!slashable_indices.is_empty(), Invalid::NoSlashableIndices);
indexed_indices.shrink_to_fit(); Ok(slashable_indices)
Ok(indexed_indices)
} }