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.
///
/// Spec v0.5.1
/// Spec v0.6.1
pub fn verify_attester_slashing<T: EthSpec>(
state: &BeaconState<T>,
attester_slashing: &AttesterSlashing,
should_verify_indexed_attestations: bool,
spec: &ChainSpec,
) -> Result<(), Error> {
let indexed_attestation_1 = &attester_slashing.indexed_attestation_1;
let indexed_attestation_2 = &attester_slashing.indexed_attestation_2;
let attestation_1 = &attester_slashing.attestation_1;
let attestation_2 = &attester_slashing.attestation_2;
// Spec: is_slashable_attestation_data
verify!(
indexed_attestation_1.data != indexed_attestation_2.data,
Invalid::AttestationDataIdentical
);
verify!(
indexed_attestation_1.is_double_vote(indexed_attestation_2, spec)
| indexed_attestation_1.is_surround_vote(indexed_attestation_2, spec),
attestation_1.is_double_vote(attestation_2, spec)
|| attestation_1.is_surround_vote(attestation_2, spec),
Invalid::NotSlashable
);
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())))?;
verify_indexed_attestation(state, &indexed_attestation_2, spec)
verify_indexed_attestation(state, &attestation_2, spec)
.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`.
///
/// Spec v0.5.1
pub fn gather_attester_slashing_indices<T: EthSpec>(
/// Spec v0.6.1
pub fn get_slashable_indices<T: EthSpec>(
state: &BeaconState<T>,
attester_slashing: &AttesterSlashing,
spec: &ChainSpec,
@ -50,47 +47,47 @@ pub fn gather_attester_slashing_indices<T: EthSpec>(
gather_attester_slashing_indices_modular(
state,
attester_slashing,
|_, validator| validator.slashed,
|_, validator| validator.is_slashable_at(state.current_epoch()),
spec,
)
}
/// Same as `gather_attester_slashing_indices` but allows the caller to specify the criteria
/// for determining whether a given validator should be considered slashed.
pub fn gather_attester_slashing_indices_modular<F, T: EthSpec>(
/// for determining whether a given validator should be considered slashable.
pub fn get_slashable_indices_modular<F, T: EthSpec>(
state: &BeaconState<T>,
attester_slashing: &AttesterSlashing,
is_slashed: F,
is_slashable: F,
spec: &ChainSpec,
) -> Result<Vec<u64>, Error>
where
F: Fn(u64, &Validator) -> bool,
{
let indexed_attestation_1 = &attester_slashing.indexed_attestation_1;
let indexed_attestation_2 = &attester_slashing.indexed_attestation_2;
let attestation_1 = &attester_slashing.attestation_1;
let attestation_2 = &attester_slashing.attestation_2;
let mut indexed_indices = Vec::with_capacity(spec.max_indices_per_indexed_vote);
for i in &indexed_attestation_1.validator_indices {
let mut attesting_indices_1 = HashSet::new();
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
.validator_registry
.get(*i as usize)
.ok_or_else(|| Error::Invalid(Invalid::UnknownValidator(*i)))?;
.get(index as usize)
.ok_or_else(|| Error::Invalid(Invalid::UnknownValidator(index)))?;
if indexed_attestation_2.validator_indices.contains(&i) & !is_slashed(*i, validator) {
// TODO: verify that we should reject any indexed attestation which includes a
// 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);
if is_slashable(index, validator) {
slashable_indices.push(index);
}
}
verify!(!indexed_indices.is_empty(), Invalid::NoSlashableIndices);
verify!(!slashable_indices.is_empty(), Invalid::NoSlashableIndices);
indexed_indices.shrink_to_fit();
Ok(indexed_indices)
Ok(slashable_indices)
}