mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-15 02:42:38 +00:00
Update to v0.9.1
This commit is contained in:
@@ -3,7 +3,7 @@ use types::*;
|
||||
|
||||
/// Returns validator indices which participated in the attestation, sorted by increasing index.
|
||||
///
|
||||
/// Spec v0.9.0
|
||||
/// Spec v0.9.1
|
||||
pub fn get_attesting_indices<T: EthSpec>(
|
||||
state: &BeaconState<T>,
|
||||
attestation_data: &AttestationData,
|
||||
|
||||
@@ -6,117 +6,19 @@ type Result<T> = std::result::Result<T, BlockOperationError<Invalid>>;
|
||||
|
||||
/// Convert `attestation` to (almost) indexed-verifiable form.
|
||||
///
|
||||
/// Spec v0.9.0
|
||||
/// Spec v0.9.1
|
||||
pub fn get_indexed_attestation<T: EthSpec>(
|
||||
state: &BeaconState<T>,
|
||||
attestation: &Attestation<T>,
|
||||
) -> Result<IndexedAttestation<T>> {
|
||||
// Note: we rely on both calls to `get_attesting_indices` to check the bitfield lengths
|
||||
// against the committee length
|
||||
let attesting_indices =
|
||||
get_attesting_indices(state, &attestation.data, &attestation.aggregation_bits)?;
|
||||
|
||||
let custody_bit_1_indices =
|
||||
get_attesting_indices(state, &attestation.data, &attestation.custody_bits)?;
|
||||
|
||||
verify!(
|
||||
custody_bit_1_indices.is_subset(&attesting_indices),
|
||||
Invalid::CustodyBitfieldNotSubset
|
||||
);
|
||||
|
||||
let custody_bit_0_indices = &attesting_indices - &custody_bit_1_indices;
|
||||
|
||||
Ok(IndexedAttestation {
|
||||
custody_bit_0_indices: VariableList::new(
|
||||
custody_bit_0_indices
|
||||
.into_iter()
|
||||
.map(|x| x as u64)
|
||||
.collect(),
|
||||
)?,
|
||||
custody_bit_1_indices: VariableList::new(
|
||||
custody_bit_1_indices
|
||||
.into_iter()
|
||||
.map(|x| x as u64)
|
||||
.collect(),
|
||||
attesting_indices: VariableList::new(
|
||||
attesting_indices.into_iter().map(|x| x as u64).collect(),
|
||||
)?,
|
||||
data: attestation.data.clone(),
|
||||
signature: attestation.signature.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use itertools::{Either, Itertools};
|
||||
use types::test_utils::*;
|
||||
|
||||
#[test]
|
||||
fn custody_bitfield_indexing() {
|
||||
let validator_count = 128;
|
||||
let spec = MinimalEthSpec::default_spec();
|
||||
let state_builder =
|
||||
TestingBeaconStateBuilder::<MinimalEthSpec>::from_default_keypairs_file_if_exists(
|
||||
validator_count,
|
||||
&spec,
|
||||
);
|
||||
let (mut state, keypairs) = state_builder.build();
|
||||
state.build_all_caches(&spec).unwrap();
|
||||
state.slot += 1;
|
||||
|
||||
let index = 0;
|
||||
let bc = state.get_beacon_committee(Slot::new(0), index).unwrap();
|
||||
|
||||
// Make a third of the validators sign with custody bit 0, a third with custody bit 1
|
||||
// and a third not sign at all.
|
||||
assert!(
|
||||
bc.committee.len() >= 4,
|
||||
"need at least 4 validators per committee for this test to work"
|
||||
);
|
||||
let (mut bit_0_indices, mut bit_1_indices): (Vec<_>, Vec<_>) = bc
|
||||
.committee
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(i, _)| i % 3 != 0)
|
||||
.partition_map(|(i, index)| {
|
||||
if i % 3 == 1 {
|
||||
Either::Left(*index)
|
||||
} else {
|
||||
Either::Right(*index)
|
||||
}
|
||||
});
|
||||
assert!(!bit_0_indices.is_empty());
|
||||
assert!(!bit_1_indices.is_empty());
|
||||
|
||||
let bit_0_keys = bit_0_indices
|
||||
.iter()
|
||||
.map(|validator_index| &keypairs[*validator_index].sk)
|
||||
.collect::<Vec<_>>();
|
||||
let bit_1_keys = bit_1_indices
|
||||
.iter()
|
||||
.map(|validator_index| &keypairs[*validator_index].sk)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut attestation_builder =
|
||||
TestingAttestationBuilder::new(&state, &bc.committee, bc.slot, index);
|
||||
attestation_builder
|
||||
.sign(&bit_0_indices, &bit_0_keys, &state.fork, &spec, false)
|
||||
.sign(&bit_1_indices, &bit_1_keys, &state.fork, &spec, true);
|
||||
let attestation = attestation_builder.build();
|
||||
|
||||
let indexed_attestation = get_indexed_attestation(&state, &attestation).unwrap();
|
||||
|
||||
bit_0_indices.sort();
|
||||
bit_1_indices.sort();
|
||||
|
||||
assert!(indexed_attestation
|
||||
.custody_bit_0_indices
|
||||
.iter()
|
||||
.copied()
|
||||
.eq(bit_0_indices.iter().map(|idx| *idx as u64)));
|
||||
assert!(indexed_attestation
|
||||
.custody_bit_1_indices
|
||||
.iter()
|
||||
.copied()
|
||||
.eq(bit_1_indices.iter().map(|idx| *idx as u64)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
use super::errors::{BlockOperationError, IndexedAttestationInvalid as Invalid};
|
||||
use super::signature_sets::indexed_attestation_signature_set;
|
||||
use crate::VerifySignatures;
|
||||
use std::collections::HashSet;
|
||||
use std::iter::FromIterator;
|
||||
use types::*;
|
||||
|
||||
type Result<T> = std::result::Result<T, BlockOperationError<Invalid>>;
|
||||
@@ -20,28 +18,15 @@ pub fn is_valid_indexed_attestation<T: EthSpec>(
|
||||
verify_signatures: VerifySignatures,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<()> {
|
||||
let bit_0_indices = &indexed_attestation.custody_bit_0_indices;
|
||||
let bit_1_indices = &indexed_attestation.custody_bit_1_indices;
|
||||
|
||||
// Verify no index has custody bit equal to 1 [to be removed in phase 1]
|
||||
verify!(bit_1_indices.is_empty(), Invalid::CustodyBitfieldHasSetBits);
|
||||
let indices = &indexed_attestation.attesting_indices;
|
||||
|
||||
// Verify max number of indices
|
||||
let total_indices = bit_0_indices.len() + bit_1_indices.len();
|
||||
verify!(
|
||||
total_indices <= T::MaxValidatorsPerCommittee::to_usize(),
|
||||
Invalid::MaxIndicesExceed(T::MaxValidatorsPerCommittee::to_usize(), total_indices)
|
||||
indices.len() <= T::MaxValidatorsPerCommittee::to_usize(),
|
||||
Invalid::MaxIndicesExceed(T::MaxValidatorsPerCommittee::to_usize(), indices.len())
|
||||
);
|
||||
|
||||
// Verify index sets are disjoint
|
||||
let custody_bit_intersection: HashSet<&u64> =
|
||||
&HashSet::from_iter(bit_0_indices.iter()) & &HashSet::from_iter(bit_1_indices.iter());
|
||||
verify!(
|
||||
custody_bit_intersection.is_empty(),
|
||||
Invalid::CustodyBitValidatorsIntersect
|
||||
);
|
||||
|
||||
// Check that both vectors of indices are sorted
|
||||
// Check that indices are sorted
|
||||
let check_sorted = |list: &[u64]| -> Result<()> {
|
||||
list.windows(2).enumerate().try_for_each(|(i, pair)| {
|
||||
if pair[0] >= pair[1] {
|
||||
@@ -52,8 +37,7 @@ pub fn is_valid_indexed_attestation<T: EthSpec>(
|
||||
})?;
|
||||
Ok(())
|
||||
};
|
||||
check_sorted(&bit_0_indices)?;
|
||||
check_sorted(&bit_1_indices)?;
|
||||
check_sorted(indices)?;
|
||||
|
||||
if verify_signatures.is_true() {
|
||||
verify!(
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
//! validated individually, or alongside in others in a potentially cheaper bulk operation.
|
||||
//!
|
||||
//! This module exposes one function to extract each type of `SignatureSet` from a `BeaconBlock`.
|
||||
use bls::SignatureSet;
|
||||
use bls::{SignatureSet, SignedMessage};
|
||||
use std::convert::TryInto;
|
||||
use tree_hash::{SignedRoot, TreeHash};
|
||||
use types::{
|
||||
AggregateSignature, AttestationDataAndCustodyBit, AttesterSlashing, BeaconBlock,
|
||||
BeaconBlockHeader, BeaconState, BeaconStateError, ChainSpec, Deposit, Domain, EthSpec, Fork,
|
||||
Hash256, IndexedAttestation, ProposerSlashing, PublicKey, Signature, VoluntaryExit,
|
||||
AggregateSignature, AttesterSlashing, BeaconBlock, BeaconBlockHeader, BeaconState,
|
||||
BeaconStateError, ChainSpec, Deposit, Domain, EthSpec, Fork, Hash256, IndexedAttestation,
|
||||
ProposerSlashing, PublicKey, Signature, VoluntaryExit,
|
||||
};
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
@@ -138,16 +138,12 @@ pub fn indexed_attestation_signature_set<'a, 'b, T: EthSpec>(
|
||||
indexed_attestation: &'b IndexedAttestation<T>,
|
||||
spec: &'a ChainSpec,
|
||||
) -> Result<SignatureSet<'a>> {
|
||||
let message_0 = AttestationDataAndCustodyBit {
|
||||
data: indexed_attestation.data.clone(),
|
||||
custody_bit: false,
|
||||
}
|
||||
.tree_hash_root();
|
||||
let message_1 = AttestationDataAndCustodyBit {
|
||||
data: indexed_attestation.data.clone(),
|
||||
custody_bit: true,
|
||||
}
|
||||
.tree_hash_root();
|
||||
let message = indexed_attestation.data.tree_hash_root();
|
||||
|
||||
let signed_message = SignedMessage::new(
|
||||
get_pubkeys(state, &indexed_attestation.attesting_indices)?,
|
||||
message,
|
||||
);
|
||||
|
||||
let domain = spec.get_domain(
|
||||
indexed_attestation.data.target.epoch,
|
||||
@@ -155,14 +151,7 @@ pub fn indexed_attestation_signature_set<'a, 'b, T: EthSpec>(
|
||||
&state.fork,
|
||||
);
|
||||
|
||||
Ok(SignatureSet::dual(
|
||||
signature,
|
||||
message_0,
|
||||
get_pubkeys(state, &indexed_attestation.custody_bit_0_indices)?,
|
||||
message_1,
|
||||
get_pubkeys(state, &indexed_attestation.custody_bit_1_indices)?,
|
||||
domain,
|
||||
))
|
||||
Ok(SignatureSet::new(signature, vec![signed_message], domain))
|
||||
}
|
||||
|
||||
/// Returns the signature set for the given `attester_slashing` and corresponding `pubkeys`.
|
||||
|
||||
@@ -71,15 +71,13 @@ where
|
||||
let attestation_2 = &attester_slashing.attestation_2;
|
||||
|
||||
let attesting_indices_1 = attestation_1
|
||||
.custody_bit_0_indices
|
||||
.attesting_indices
|
||||
.iter()
|
||||
.chain(&attestation_1.custody_bit_1_indices)
|
||||
.cloned()
|
||||
.collect::<BTreeSet<_>>();
|
||||
let attesting_indices_2 = attestation_2
|
||||
.custody_bit_0_indices
|
||||
.attesting_indices
|
||||
.iter()
|
||||
.chain(&attestation_2.custody_bit_1_indices)
|
||||
.cloned()
|
||||
.collect::<BTreeSet<_>>();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user