mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-17 21:08:32 +00:00
some tests and fixed attestqtion calc
This commit is contained in:
@@ -16,6 +16,7 @@ use crate::{
|
||||
BeaconChain, BeaconChainTypes, BlockError, ChainConfig, ServerSentEventHandler,
|
||||
StateSkipConfig,
|
||||
};
|
||||
use attestation::SingleAttestation;
|
||||
use bls::get_withdrawal_credentials;
|
||||
use eth2::types::SignedBlockContentsTuple;
|
||||
use execution_layer::test_utils::generate_genesis_header;
|
||||
@@ -662,10 +663,14 @@ pub struct BeaconChainHarness<T: BeaconChainTypes> {
|
||||
pub rng: Mutex<StdRng>,
|
||||
}
|
||||
|
||||
pub type CommitteeSingleAttestations = Vec<(SingleAttestation, SubnetId)>;
|
||||
pub type CommitteeAttestations<E> = Vec<(Attestation<E>, SubnetId)>;
|
||||
pub type HarnessAttestations<E> =
|
||||
Vec<(CommitteeAttestations<E>, Option<SignedAggregateAndProof<E>>)>;
|
||||
|
||||
pub type HarnessSingleAttestations<E> =
|
||||
Vec<(CommitteeSingleAttestations, Option<SignedAggregateAndProof<E>>)>;
|
||||
|
||||
pub type HarnessSyncContributions<E> = Vec<(
|
||||
Vec<(SyncCommitteeMessage, usize)>,
|
||||
Option<SignedContributionAndProof<E>>,
|
||||
@@ -1023,6 +1028,79 @@ where
|
||||
)
|
||||
}
|
||||
|
||||
pub fn produce_single_attestation_for_block(
|
||||
&self,
|
||||
slot: Slot,
|
||||
index: CommitteeIndex,
|
||||
beacon_block_root: Hash256,
|
||||
mut state: Cow<BeaconState<E>>,
|
||||
state_root: Hash256,
|
||||
aggregation_bit_index: usize,
|
||||
validator_index: usize,
|
||||
) -> Result<SingleAttestation, BeaconChainError> {
|
||||
|
||||
let epoch = slot.epoch(E::slots_per_epoch());
|
||||
|
||||
if state.slot() > slot {
|
||||
return Err(BeaconChainError::CannotAttestToFutureState);
|
||||
} else if state.current_epoch() < epoch {
|
||||
let mut_state = state.to_mut();
|
||||
complete_state_advance(
|
||||
mut_state,
|
||||
Some(state_root),
|
||||
epoch.start_slot(E::slots_per_epoch()),
|
||||
&self.spec,
|
||||
)?;
|
||||
mut_state.build_committee_cache(RelativeEpoch::Current, &self.spec)?;
|
||||
}
|
||||
|
||||
let committee_len = state.get_beacon_committee(slot, index)?.committee.len();
|
||||
|
||||
let target_slot = epoch.start_slot(E::slots_per_epoch());
|
||||
let target_root = if state.slot() <= target_slot {
|
||||
beacon_block_root
|
||||
} else {
|
||||
*state.get_block_root(target_slot)?
|
||||
};
|
||||
|
||||
let mut attestation: Attestation<E> = Attestation::empty_for_signing(
|
||||
index,
|
||||
committee_len,
|
||||
slot,
|
||||
beacon_block_root,
|
||||
state.current_justified_checkpoint(),
|
||||
Checkpoint {
|
||||
epoch,
|
||||
root: target_root,
|
||||
},
|
||||
&self.spec,
|
||||
)?;
|
||||
|
||||
let attestation = match attestation {
|
||||
Attestation::Electra(mut attn) => {
|
||||
attn.aggregation_bits.set(aggregation_bit_index, true).unwrap();
|
||||
attn
|
||||
},
|
||||
Attestation::Base(_) => panic!("MUST BE AN ELECTRA ATTESTATION"),
|
||||
};
|
||||
|
||||
let committee = state.get_beacon_committee(slot, index)?;
|
||||
|
||||
// let committees = state.get_beacon_committees_at_epoch(RelativeEpoch::Current)?;
|
||||
|
||||
let single_attestation = attestation.to_single_attestation(
|
||||
&vec![committee.clone()]
|
||||
)?;
|
||||
|
||||
let attestation: Attestation<E> = single_attestation.to_attestation(&vec![committee])?;
|
||||
|
||||
assert_eq!(single_attestation.committee_index, attestation.committee_index().unwrap() as usize);
|
||||
assert_eq!(single_attestation.attester_index, validator_index);
|
||||
// assert_eq!(single_attestation.attester_index, attestation.attester_index());
|
||||
Ok(single_attestation)
|
||||
}
|
||||
|
||||
|
||||
/// Produces an "unaggregated" attestation for the given `slot` and `index` that attests to
|
||||
/// `beacon_block_root`. The provided `state` should match the `block.state_root` for the
|
||||
/// `block` identified by `beacon_block_root`.
|
||||
@@ -1080,6 +1158,33 @@ where
|
||||
)?)
|
||||
}
|
||||
|
||||
/// A list of attestations for each committee for the given slot.
|
||||
///
|
||||
/// The first layer of the Vec is organised per committee. For example, if the return value is
|
||||
/// called `all_attestations`, then all attestations in `all_attestations[0]` will be for
|
||||
/// committee 0, whilst all in `all_attestations[1]` will be for committee 1.
|
||||
pub fn make_single_attestations(
|
||||
&self,
|
||||
attesting_validators: &[usize],
|
||||
state: &BeaconState<E>,
|
||||
state_root: Hash256,
|
||||
head_block_root: SignedBeaconBlockHash,
|
||||
attestation_slot: Slot,
|
||||
) -> Vec<CommitteeSingleAttestations> {
|
||||
let fork = self
|
||||
.spec
|
||||
.fork_at_epoch(attestation_slot.epoch(E::slots_per_epoch()));
|
||||
self.make_single_attestations_with_opts(
|
||||
attesting_validators,
|
||||
state,
|
||||
state_root,
|
||||
head_block_root,
|
||||
attestation_slot,
|
||||
MakeAttestationOptions { limit: None, fork },
|
||||
)
|
||||
.0
|
||||
}
|
||||
|
||||
/// A list of attestations for each committee for the given slot.
|
||||
///
|
||||
/// The first layer of the Vec is organised per committee. For example, if the return value is
|
||||
@@ -1107,6 +1212,99 @@ where
|
||||
.0
|
||||
}
|
||||
|
||||
pub fn make_single_attestations_with_opts(
|
||||
&self,
|
||||
attesting_validators: &[usize],
|
||||
state: &BeaconState<E>,
|
||||
state_root: Hash256,
|
||||
head_block_root: SignedBeaconBlockHash,
|
||||
attestation_slot: Slot,
|
||||
opts: MakeAttestationOptions,
|
||||
) -> (Vec<CommitteeSingleAttestations>, Vec<usize>) {
|
||||
let MakeAttestationOptions { limit, fork } = opts;
|
||||
let committee_count = state.get_committee_count_at_slot(state.slot()).unwrap();
|
||||
let num_attesters = AtomicUsize::new(0);
|
||||
|
||||
let (attestations, split_attesters) = state
|
||||
.get_beacon_committees_at_slot(attestation_slot)
|
||||
.expect("should get committees")
|
||||
.iter()
|
||||
.map(|bc| {
|
||||
bc.committee
|
||||
.par_iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, validator_index)| {
|
||||
if !attesting_validators.contains(validator_index) {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(limit) = limit {
|
||||
// This atomics stuff is necessary because we're under a par_iter,
|
||||
// and Rayon will deadlock if we use a mutex.
|
||||
if num_attesters.fetch_add(1, Ordering::Relaxed) >= limit {
|
||||
num_attesters.fetch_sub(1, Ordering::Relaxed);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
let mut attestation = self
|
||||
.produce_single_attestation_for_block(
|
||||
attestation_slot,
|
||||
bc.index,
|
||||
head_block_root.into(),
|
||||
Cow::Borrowed(state),
|
||||
state_root,
|
||||
i,
|
||||
*validator_index
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
attestation.signature = {
|
||||
let domain = self.spec.get_domain(
|
||||
attestation.data.target.epoch,
|
||||
Domain::BeaconAttester,
|
||||
&fork,
|
||||
state.genesis_validators_root(),
|
||||
);
|
||||
|
||||
let message = attestation.data.signing_root(domain);
|
||||
|
||||
let mut agg_sig = AggregateSignature::infinity();
|
||||
|
||||
agg_sig.add_assign(
|
||||
&self.validator_keypairs[*validator_index].sk.sign(message),
|
||||
);
|
||||
|
||||
agg_sig
|
||||
};
|
||||
|
||||
let subnet_id = SubnetId::compute_subnet_for_single_attestation::<E>(
|
||||
attestation.clone(),
|
||||
committee_count,
|
||||
&self.chain.spec,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Some(((attestation, subnet_id), validator_index))
|
||||
})
|
||||
.unzip::<_, _, Vec<_>, Vec<_>>()
|
||||
})
|
||||
.unzip::<_, _, Vec<_>, Vec<_>>();
|
||||
|
||||
// Flatten attesters.
|
||||
let attesters = split_attesters.into_iter().flatten().collect::<Vec<_>>();
|
||||
|
||||
if let Some(limit) = limit {
|
||||
assert_eq!(limit, num_attesters.load(Ordering::Relaxed));
|
||||
assert_eq!(
|
||||
limit,
|
||||
attesters.len(),
|
||||
"failed to generate `limit` attestations"
|
||||
);
|
||||
}
|
||||
(attestations, attesters)
|
||||
}
|
||||
|
||||
pub fn make_unaggregated_attestations_with_opts(
|
||||
&self,
|
||||
attesting_validators: &[usize],
|
||||
@@ -1287,6 +1485,32 @@ where
|
||||
)
|
||||
}
|
||||
|
||||
/// A list of attestations for each committee for the given slot.
|
||||
///
|
||||
/// The first layer of the Vec is organised per committee. For example, if the return value is
|
||||
/// called `all_attestations`, then all attestations in `all_attestations[0]` will be for
|
||||
/// committee 0, whilst all in `all_attestations[1]` will be for committee 1.
|
||||
pub fn get_single_attestations(
|
||||
&self,
|
||||
attestation_strategy: &AttestationStrategy,
|
||||
state: &BeaconState<E>,
|
||||
state_root: Hash256,
|
||||
head_block_root: Hash256,
|
||||
attestation_slot: Slot,
|
||||
) -> Vec<Vec<(SingleAttestation, SubnetId)>> {
|
||||
let validators: Vec<usize> = match attestation_strategy {
|
||||
AttestationStrategy::AllValidators => self.get_all_validators(),
|
||||
AttestationStrategy::SomeValidators(vals) => vals.clone(),
|
||||
};
|
||||
self.make_single_attestations(
|
||||
&validators,
|
||||
state,
|
||||
state_root,
|
||||
head_block_root.into(),
|
||||
attestation_slot,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn make_attestations(
|
||||
&self,
|
||||
attesting_validators: &[usize],
|
||||
|
||||
Reference in New Issue
Block a user