Finish Modifications to get_attesting_indices()

This commit is contained in:
Mark Mackey
2024-09-11 16:18:35 -05:00
parent 330863d970
commit 4c9e12cfb6
14 changed files with 143 additions and 72 deletions

View File

@@ -629,6 +629,7 @@ impl<'a, T: BeaconChainTypes> IndexedAggregatedAttestation<'a, T> {
attesting_indices_electra::get_indexed_attestation(
&committees,
&signed_aggregate.message.aggregate,
&chain.spec,
)
.map_err(|e| BeaconChainError::from(e).into())
}
@@ -1364,7 +1365,7 @@ pub fn obtain_indexed_attestation_and_committees_per_slot<T: BeaconChainTypes>(
}
}
AttestationRef::Electra(att) => {
attesting_indices_electra::get_indexed_attestation(&committees, att)
attesting_indices_electra::get_indexed_attestation(&committees, att, &chain.spec)
.map(|attestation| (attestation, committees_per_slot))
.map_err(|e| {
if let BlockOperationError::BeaconStateError(NoCommitteeFound(index)) = e {

View File

@@ -226,7 +226,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let inclusion_delay = state.slot().safe_sub(attestation.data().slot)?.as_u64();
let sqrt_total_active_balance =
SqrtTotalActiveBalance::new(processing_epoch_end.get_total_active_balance()?);
for attester in get_attesting_indices_from_state(state, attestation)? {
for attester in get_attesting_indices_from_state(state, attestation, &self.spec)? {
let validator = processing_epoch_end.get_validator(attester as usize)?;
if !validator.slashed
&& !rewarded_attesters.contains(&attester)
@@ -281,7 +281,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
&self.spec,
)?;
let attesting_indices = get_attesting_indices_from_state(state, attestation)?;
let attesting_indices =
get_attesting_indices_from_state(state, attestation, &self.spec)?;
let mut proposer_reward_numerator = 0;
for index in attesting_indices {
let index = index as usize;

View File

@@ -4202,19 +4202,20 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
// Attestations.
for attestation in block.body().attestations() {
let indexed_attestation = match ctxt.get_indexed_attestation(state, attestation) {
Ok(indexed) => indexed,
Err(e) => {
debug!(
self.log,
"Failed to get indexed attestation";
"purpose" => "validator monitor",
"attestation_slot" => attestation.data().slot,
"error" => ?e,
);
continue;
}
};
let indexed_attestation =
match ctxt.get_indexed_attestation(state, attestation, &self.spec) {
Ok(indexed) => indexed,
Err(e) => {
debug!(
self.log,
"Failed to get indexed attestation";
"purpose" => "validator monitor",
"attestation_slot" => attestation.data().slot,
"error" => ?e,
);
continue;
}
};
validator_monitor.register_attestation_in_block(
indexed_attestation,
parent_block_slot,
@@ -4270,7 +4271,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
}
}
let indexed_attestation = match ctxt.get_indexed_attestation(state, a) {
let indexed_attestation = match ctxt.get_indexed_attestation(state, a, &self.spec) {
Ok(indexed) => indexed,
Err(e) => {
debug!(
@@ -4311,19 +4312,20 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
) {
if let Some(slasher) = self.slasher.as_ref() {
for attestation in block.body().attestations() {
let indexed_attestation = match ctxt.get_indexed_attestation(state, attestation) {
Ok(indexed) => indexed,
Err(e) => {
debug!(
self.log,
"Failed to get indexed attestation";
"purpose" => "slasher",
"attestation_slot" => attestation.data().slot,
"error" => ?e,
);
continue;
}
};
let indexed_attestation =
match ctxt.get_indexed_attestation(state, attestation, &self.spec) {
Ok(indexed) => indexed,
Err(e) => {
debug!(
self.log,
"Failed to get indexed attestation";
"purpose" => "slasher",
"attestation_slot" => attestation.data().slot,
"error" => ?e,
);
continue;
}
};
slasher.accept_attestation(indexed_attestation.clone_as_indexed_attestation());
}
}
@@ -5355,7 +5357,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
for attestation in self.naive_aggregation_pool.read().iter() {
let import = |attestation: &Attestation<T::EthSpec>| {
let attesting_indices =
get_attesting_indices_from_state(&state, attestation.to_ref())?;
get_attesting_indices_from_state(&state, attestation.to_ref(), &self.spec)?;
self.op_pool
.insert_attestation(attestation.clone(), attesting_indices)
};

View File

@@ -28,7 +28,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.body()
.attestations()
.map(|att| {
let attesting_indices = get_attesting_indices_from_state(state, att)?;
let attesting_indices = get_attesting_indices_from_state(state, att, &self.spec)?;
Ok(SplitAttestation::new(
att.clone_as_attestation(),
attesting_indices,

View File

@@ -1650,7 +1650,7 @@ impl<T: BeaconChainTypes> ExecutionPendingBlock<T> {
// Register each attestation in the block with fork choice.
for (i, attestation) in block.message().body().attestations().enumerate() {
let indexed_attestation = consensus_context
.get_indexed_attestation(&state, attestation)
.get_indexed_attestation(&state, attestation, &chain.spec)
.map_err(|e| BlockError::PerBlockProcessingError(e.into_with_index(i)))?;
match fork_choice.on_attestation(

View File

@@ -56,11 +56,13 @@ pub mod attesting_indices_electra {
pub fn get_indexed_attestation<E: EthSpec>(
committees: &[BeaconCommittee],
attestation: &AttestationElectra<E>,
spec: &ChainSpec,
) -> Result<IndexedAttestation<E>, BlockOperationError<Invalid>> {
let attesting_indices = get_attesting_indices::<E>(
committees,
&attestation.aggregation_bits,
&attestation.committee_bits,
spec,
)?;
Ok(IndexedAttestation::Electra(IndexedAttestationElectra {
@@ -73,18 +75,45 @@ pub mod attesting_indices_electra {
pub fn get_indexed_attestation_from_state<E: EthSpec>(
beacon_state: &BeaconState<E>,
attestation: &AttestationElectra<E>,
spec: &ChainSpec,
) -> Result<IndexedAttestation<E>, BlockOperationError<Invalid>> {
let committees = beacon_state.get_beacon_committees_at_slot(attestation.data.slot)?;
get_indexed_attestation(&committees, attestation)
get_indexed_attestation(&committees, attestation, spec)
}
/// Shortcut for getting the attesting indices while fetching the committee from the state's cache.
pub fn get_attesting_indices_from_state<E: EthSpec>(
state: &BeaconState<E>,
att: &AttestationElectra<E>,
spec: &ChainSpec,
) -> Result<Vec<u64>, BeaconStateError> {
let committees = state.get_beacon_committees_at_slot(att.data.slot)?;
get_attesting_indices::<E>(&committees, &att.aggregation_bits, &att.committee_bits)
get_attesting_indices::<E>(
&committees,
&att.aggregation_bits,
&att.committee_bits,
spec,
)
}
/// Returns a set of the PTC if the attestation slot is post EIP-7732, otherwise returns an empty set.
pub fn get_ptc_set<E: EthSpec>(
committees: &[BeaconCommittee],
spec: &ChainSpec,
) -> Result<HashSet<u64>, BeaconStateError> {
let attestation_slot = committees
.get(0)
.map(|committee| committee.slot)
.ok_or(Error::NoCommitteeFound(0))?;
if spec
.fork_name_at_slot::<E>(attestation_slot)
.eip7732_enabled()
{
PTC::<E>::from_committees(committees)
.map(|ptc| ptc.into_iter().map(|i| i as u64).collect())
} else {
Ok(HashSet::new())
}
}
/// Returns validator indices which participated in the attestation, sorted by increasing index.
@@ -94,9 +123,11 @@ pub mod attesting_indices_electra {
committees: &[BeaconCommittee],
aggregation_bits: &BitList<E::MaxValidatorsPerSlot>,
committee_bits: &BitVector<E::MaxCommitteesPerSlot>,
spec: &ChainSpec,
) -> Result<Vec<u64>, BeaconStateError> {
let mut attesting_indices = vec![];
let ptc_set = get_ptc_set::<E>(committees, spec)?;
let committee_indices = get_committee_indices::<E>(committee_bits);
let mut committee_offset = 0;
@@ -125,6 +156,8 @@ pub mod attesting_indices_electra {
}
None
})
// EIP-7732: filter out the PTC
.filter(|index| !ptc_set.contains(index))
.collect::<HashSet<u64>>();
attesting_indices.extend(committee_attesters);
@@ -156,6 +189,7 @@ pub mod attesting_indices_electra {
pub fn get_attesting_indices_from_state<E: EthSpec>(
state: &BeaconState<E>,
att: AttestationRef<E>,
spec: &ChainSpec,
) -> Result<Vec<u64>, BeaconStateError> {
match att {
AttestationRef::Base(att) => {
@@ -166,7 +200,7 @@ pub fn get_attesting_indices_from_state<E: EthSpec>(
)
}
AttestationRef::Electra(att) => {
attesting_indices_electra::get_attesting_indices_from_state::<E>(state, att)
attesting_indices_electra::get_attesting_indices_from_state::<E>(state, att, spec)
}
}
}

View File

@@ -24,14 +24,14 @@ pub fn get_payload_attesting_indices<E: EthSpec>(
) -> Result<Vec<u64>, BeaconStateError> {
let ptc = state.get_ptc(slot)?;
let bitlist = &payload_attestation.aggregation_bits;
if bitlist.len() != ptc.len() {
if bitlist.len() != E::PTCSize::to_usize() {
return Err(BeaconStateError::InvalidBitfield);
}
let mut attesting_indices = Vec::<u64>::new();
for (i, index) in ptc.into_iter().enumerate() {
if let Ok(true) = bitlist.get(i) {
attesting_indices.push(*index as u64);
attesting_indices.push(index as u64);
}
}
attesting_indices.sort_unstable();

View File

@@ -161,6 +161,7 @@ impl<E: EthSpec> ConsensusContext<E> {
&'a mut self,
state: &BeaconState<E>,
attestation: AttestationRef<'a, E>,
spec: &ChainSpec,
) -> Result<IndexedAttestationRef<E>, BlockOperationError<AttestationInvalid>> {
let key = attestation.tree_hash_root();
match attestation {
@@ -177,7 +178,9 @@ impl<E: EthSpec> ConsensusContext<E> {
Entry::Occupied(occupied) => Ok(occupied.into_mut()),
Entry::Vacant(vacant) => {
let indexed_attestation =
attesting_indices_electra::get_indexed_attestation_from_state(state, attn)?;
attesting_indices_electra::get_indexed_attestation_from_state(
state, attn, spec,
)?;
Ok(vacant.insert(indexed_attestation))
}
},

View File

@@ -282,7 +282,8 @@ where
.body()
.attestations()
.try_for_each(|attestation| {
let indexed_attestation = ctxt.get_indexed_attestation(self.state, attestation)?;
let indexed_attestation =
ctxt.get_indexed_attestation(self.state, attestation, self.spec)?;
self.sets.push(indexed_attestation_signature_set(
self.state,

View File

@@ -87,7 +87,7 @@ pub fn verify_attestation_for_state<'ctxt, E: EthSpec>(
verify_casper_ffg_vote(attestation, state)?;
// Check signature and bitfields
let indexed_attestation = ctxt.get_indexed_attestation(state, attestation)?;
let indexed_attestation = ctxt.get_indexed_attestation(state, attestation, spec)?;
is_valid_indexed_attestation(state, indexed_attestation, verify_signatures, spec)?;
Ok(indexed_attestation)

View File

@@ -1843,40 +1843,12 @@ impl<E: EthSpec> BeaconState<E> {
/// Get the PTC
/// Requires the committee cache to be initialized.
/// TODO(EIP-7732): is it easier to return u64 or usize?
/// TODO(EIP-7732): definitely gonna have to cache this..
pub fn get_ptc(&self, slot: Slot) -> Result<FixedVector<usize, E::PTCSize>, Error> {
// this function is only used here and
// I have no idea where else to put it
fn bit_floor(n: u64) -> u64 {
if n == 0 {
0
} else {
1 << (n.leading_zeros() as u64 ^ 63)
}
}
pub fn get_ptc(&self, slot: Slot) -> Result<PTC<E>, Error> {
let committee_cache = self.committee_cache_at_slot(slot)?;
let committee_count_per_slot = committee_cache.committees_per_slot();
let committees_per_slot = bit_floor(std::cmp::min(
committee_count_per_slot as u64,
E::PTCSize::to_u64(),
));
let members_per_committee =
committee_count_per_slot.safe_div(committees_per_slot)? as usize;
let committees = committee_cache.get_beacon_committees_at_slot(slot)?;
let mut validator_indices = Vec::with_capacity(committees_per_slot as usize);
for idx in 0..committees_per_slot {
let beacon_committee = committees
.get(idx as usize)
.ok_or_else(|| Error::InvalidCommitteeIndex(idx))?;
validator_indices
.extend_from_slice(&beacon_committee.committee[..members_per_committee]);
}
Ok(FixedVector::new(validator_indices)?)
PTC::from_committees(&committees)
}
/// Build all caches (except the tree hash cache), if they need to be built.

View File

@@ -67,6 +67,7 @@ pub mod pending_consolidation;
pub mod pending_partial_withdrawal;
pub mod proposer_preparation_data;
pub mod proposer_slashing;
pub mod ptc;
pub mod relative_epoch;
pub mod selection_proof;
pub mod shuffling_id;
@@ -236,6 +237,7 @@ pub use crate::preset::{
};
pub use crate::proposer_preparation_data::ProposerPreparationData;
pub use crate::proposer_slashing::ProposerSlashing;
pub use crate::ptc::PTC;
pub use crate::relative_epoch::{Error as RelativeEpochError, RelativeEpoch};
pub use crate::runtime_var_list::RuntimeVariableList;
pub use crate::selection_proof::SelectionProof;

View File

@@ -0,0 +1,55 @@
use crate::*;
use safe_arith::SafeArith;
/// TODO(EIP-7732): is it easier to return u64 or usize?
#[derive(Clone, Debug, PartialEq)]
pub struct PTC<E: EthSpec>(FixedVector<usize, E::PTCSize>);
impl<E: EthSpec> PTC<E> {
pub fn from_committees(committees: &[BeaconCommittee]) -> Result<Self, BeaconStateError> {
// this function is only used here and
// I have no idea where else to put it
fn bit_floor(n: u64) -> u64 {
if n == 0 {
0
} else {
1 << (n.leading_zeros() as u64 ^ 63)
}
}
let committee_count_per_slot = committees.len() as u64;
let committees_per_slot = bit_floor(std::cmp::min(
committee_count_per_slot,
E::PTCSize::to_u64(),
)) as usize;
let members_per_committee = E::PTCSize::to_usize().safe_div(committees_per_slot)?;
let mut ptc = Vec::with_capacity(E::PTCSize::to_usize());
for idx in 0..committees_per_slot {
let beacon_committee = committees
.get(idx as usize)
.ok_or_else(|| Error::InvalidCommitteeIndex(idx as u64))?;
ptc.extend_from_slice(&beacon_committee.committee[..members_per_committee]);
}
Ok(Self(FixedVector::from(ptc)))
}
}
impl<'a, E: EthSpec> IntoIterator for &'a PTC<E> {
type Item = &'a usize;
type IntoIter = std::slice::Iter<'a, usize>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<E: EthSpec> IntoIterator for PTC<E> {
type Item = usize;
type IntoIter = std::vec::IntoIter<usize>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}

View File

@@ -39,7 +39,7 @@ pub fn run<E: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
attesting_indices_base::get_indexed_attestation(committee.committee, &att)
}
Attestation::Electra(att) => {
attesting_indices_electra::get_indexed_attestation_from_state(&state, &att)
attesting_indices_electra::get_indexed_attestation_from_state(&state, &att, spec)
}
})
.collect::<Result<Vec<_>, _>>()