Skip to content

Commit

Permalink
Attestation superstruct changes for EIP 7549 (#5644)
Browse files Browse the repository at this point in the history
* update

* experiment

* superstruct changes

* revert

* superstruct changes

* fix tests

* indexed attestation

* indexed attestation superstruct

* updated TODOs
  • Loading branch information
eserilev authored Apr 30, 2024
1 parent 4a48d7b commit 3b7132b
Show file tree
Hide file tree
Showing 56 changed files with 940 additions and 426 deletions.
2 changes: 1 addition & 1 deletion beacon_node/beacon_chain/src/attestation_simulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub fn produce_unaggregated_attestation<T: BeaconChainTypes>(
// Store the unaggregated attestation in the validator monitor for later processing
match chain.produce_unaggregated_attestation(current_slot, beacon_committee_index) {
Ok(unaggregated_attestation) => {
let data = &unaggregated_attestation.data;
let data = unaggregated_attestation.data();

debug!(
chain.log,
Expand Down
85 changes: 42 additions & 43 deletions beacon_node/beacon_chain/src/attestation_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ pub trait VerifiedAttestation<T: BeaconChainTypes>: Sized {
// Inefficient default implementation. This is overridden for gossip verified attestations.
fn into_attestation_and_indices(self) -> (Attestation<T::EthSpec>, Vec<u64>) {
let attestation = self.attestation().clone();
let attesting_indices = self.indexed_attestation().attesting_indices.clone().into();
let attesting_indices = self.indexed_attestation().attesting_indices_to_vec();
(attestation, attesting_indices)
}
}
Expand Down Expand Up @@ -455,17 +455,17 @@ impl<'a, T: BeaconChainTypes> IndexedAggregatedAttestation<'a, T> {
verify_propagation_slot_range(&chain.slot_clock, attestation, &chain.spec)?;

// Check the attestation's epoch matches its target.
if attestation.data.slot.epoch(T::EthSpec::slots_per_epoch())
!= attestation.data.target.epoch
if attestation.data().slot.epoch(T::EthSpec::slots_per_epoch())
!= attestation.data().target.epoch
{
return Err(Error::InvalidTargetEpoch {
slot: attestation.data.slot,
epoch: attestation.data.target.epoch,
slot: attestation.data().slot,
epoch: attestation.data().target.epoch,
});
}

// Ensure the valid aggregated attestation has not already been seen locally.
let attestation_data = &attestation.data;
let attestation_data = attestation.data();
let attestation_data_root = attestation_data.tree_hash_root();

if chain
Expand All @@ -486,7 +486,7 @@ impl<'a, T: BeaconChainTypes> IndexedAggregatedAttestation<'a, T> {
match chain
.observed_aggregators
.read()
.validator_has_been_observed(attestation.data.target.epoch, aggregator_index as usize)
.validator_has_been_observed(attestation.data().target.epoch, aggregator_index as usize)
{
Ok(true) => Err(Error::AggregatorAlreadyKnown(aggregator_index)),
Ok(false) => Ok(()),
Expand Down Expand Up @@ -518,7 +518,7 @@ impl<'a, T: BeaconChainTypes> IndexedAggregatedAttestation<'a, T> {
verify_attestation_target_root::<T::EthSpec>(&head_block, attestation)?;

// Ensure that the attestation has participants.
if attestation.aggregation_bits.is_zero() {
if attestation.is_aggregation_bits_zero() {
Err(Error::EmptyAggregationBitfield)
} else {
Ok(attestation_data_root)
Expand Down Expand Up @@ -611,12 +611,12 @@ impl<'a, T: BeaconChainTypes> VerifiedAggregatedAttestation<'a, T> {
if chain
.observed_aggregators
.write()
.observe_validator(attestation.data.target.epoch, aggregator_index as usize)
.observe_validator(attestation.data().target.epoch, aggregator_index as usize)
.map_err(BeaconChainError::from)?
{
return Err(Error::PriorAttestationKnown {
validator_index: aggregator_index,
epoch: attestation.data.target.epoch,
epoch: attestation.data().target.epoch,
});
}

Expand Down Expand Up @@ -712,13 +712,13 @@ impl<'a, T: BeaconChainTypes> IndexedUnaggregatedAttestation<'a, T> {
attestation: &Attestation<T::EthSpec>,
chain: &BeaconChain<T>,
) -> Result<(), Error> {
let attestation_epoch = attestation.data.slot.epoch(T::EthSpec::slots_per_epoch());
let attestation_epoch = attestation.data().slot.epoch(T::EthSpec::slots_per_epoch());

// Check the attestation's epoch matches its target.
if attestation_epoch != attestation.data.target.epoch {
if attestation_epoch != attestation.data().target.epoch {
return Err(Error::InvalidTargetEpoch {
slot: attestation.data.slot,
epoch: attestation.data.target.epoch,
slot: attestation.data().slot,
epoch: attestation.data().target.epoch,
});
}

Expand All @@ -730,7 +730,7 @@ impl<'a, T: BeaconChainTypes> IndexedUnaggregatedAttestation<'a, T> {

// Check to ensure that the attestation is "unaggregated". I.e., it has exactly one
// aggregation bit set.
let num_aggregation_bits = attestation.aggregation_bits.num_set_bits();
let num_aggregation_bits = attestation.num_set_aggregation_bits();
if num_aggregation_bits != 1 {
return Err(Error::NotExactlyOneAggregationBitSet(num_aggregation_bits));
}
Expand All @@ -757,7 +757,7 @@ impl<'a, T: BeaconChainTypes> IndexedUnaggregatedAttestation<'a, T> {
chain: &BeaconChain<T>,
) -> Result<(u64, SubnetId), Error> {
let expected_subnet_id = SubnetId::compute_subnet_for_attestation_data::<T::EthSpec>(
&indexed_attestation.data,
indexed_attestation.data(),
committees_per_slot,
&chain.spec,
)
Expand All @@ -774,8 +774,7 @@ impl<'a, T: BeaconChainTypes> IndexedUnaggregatedAttestation<'a, T> {
};

let validator_index = *indexed_attestation
.attesting_indices
.first()
.attesting_indices_first()
.ok_or(Error::NotExactlyOneAggregationBitSet(0))?;

/*
Expand All @@ -785,12 +784,12 @@ impl<'a, T: BeaconChainTypes> IndexedUnaggregatedAttestation<'a, T> {
if chain
.observed_gossip_attesters
.read()
.validator_has_been_observed(attestation.data.target.epoch, validator_index as usize)
.validator_has_been_observed(attestation.data().target.epoch, validator_index as usize)
.map_err(BeaconChainError::from)?
{
return Err(Error::PriorAttestationKnown {
validator_index,
epoch: attestation.data.target.epoch,
epoch: attestation.data().target.epoch,
});
}

Expand Down Expand Up @@ -881,12 +880,12 @@ impl<'a, T: BeaconChainTypes> VerifiedUnaggregatedAttestation<'a, T> {
if chain
.observed_gossip_attesters
.write()
.observe_validator(attestation.data.target.epoch, validator_index as usize)
.observe_validator(attestation.data().target.epoch, validator_index as usize)
.map_err(BeaconChainError::from)?
{
return Err(Error::PriorAttestationKnown {
validator_index,
epoch: attestation.data.target.epoch,
epoch: attestation.data().target.epoch,
});
}
Ok(())
Expand Down Expand Up @@ -998,28 +997,28 @@ fn verify_head_block_is_known<T: BeaconChainTypes>(
let block_opt = chain
.canonical_head
.fork_choice_read_lock()
.get_block(&attestation.data.beacon_block_root)
.get_block(&attestation.data().beacon_block_root)
.or_else(|| {
chain
.early_attester_cache
.get_proto_block(attestation.data.beacon_block_root)
.get_proto_block(attestation.data().beacon_block_root)
});

if let Some(block) = block_opt {
// Reject any block that exceeds our limit on skipped slots.
if let Some(max_skip_slots) = max_skip_slots {
if attestation.data.slot > block.slot + max_skip_slots {
if attestation.data().slot > block.slot + max_skip_slots {
return Err(Error::TooManySkippedSlots {
head_block_slot: block.slot,
attestation_slot: attestation.data.slot,
attestation_slot: attestation.data().slot,
});
}
}

Ok(block)
} else if chain.is_pre_finalization_block(attestation.data.beacon_block_root)? {
} else if chain.is_pre_finalization_block(attestation.data().beacon_block_root)? {
Err(Error::HeadBlockFinalized {
beacon_block_root: attestation.data.beacon_block_root,
beacon_block_root: attestation.data().beacon_block_root,
})
} else {
// The block is either:
Expand All @@ -1029,7 +1028,7 @@ fn verify_head_block_is_known<T: BeaconChainTypes>(
// 2) A post-finalization block that we don't know about yet. We'll queue
// the attestation until the block becomes available (or we time out).
Err(Error::UnknownHeadBlock {
beacon_block_root: attestation.data.beacon_block_root,
beacon_block_root: attestation.data().beacon_block_root,
})
}
}
Expand All @@ -1043,7 +1042,7 @@ pub fn verify_propagation_slot_range<S: SlotClock, E: EthSpec>(
attestation: &Attestation<E>,
spec: &ChainSpec,
) -> Result<(), Error> {
let attestation_slot = attestation.data.slot;
let attestation_slot = attestation.data().slot;
let latest_permissible_slot = slot_clock
.now_with_future_tolerance(spec.maximum_gossip_clock_disparity())
.ok_or(BeaconChainError::UnableToReadSlot)?;
Expand Down Expand Up @@ -1095,11 +1094,11 @@ pub fn verify_attestation_signature<T: BeaconChainTypes>(

let fork = chain
.spec
.fork_at_epoch(indexed_attestation.data.target.epoch);
.fork_at_epoch(indexed_attestation.data().target.epoch);

let signature_set = indexed_attestation_signature_set_from_pubkeys(
|validator_index| pubkey_cache.get(validator_index).map(Cow::Borrowed),
&indexed_attestation.signature,
indexed_attestation.signature(),
indexed_attestation,
&fork,
chain.genesis_validators_root,
Expand Down Expand Up @@ -1127,7 +1126,7 @@ pub fn verify_attestation_target_root<E: EthSpec>(
) -> Result<(), Error> {
// Check the attestation target root.
let head_block_epoch = head_block.slot.epoch(E::slots_per_epoch());
let attestation_epoch = attestation.data.slot.epoch(E::slots_per_epoch());
let attestation_epoch = attestation.data().slot.epoch(E::slots_per_epoch());
if head_block_epoch > attestation_epoch {
// The epoch references an invalid head block from a future epoch.
//
Expand All @@ -1140,7 +1139,7 @@ pub fn verify_attestation_target_root<E: EthSpec>(
// Reference:
// https://github.com/ethereum/eth2.0-specs/pull/2001#issuecomment-699246659
return Err(Error::InvalidTargetRoot {
attestation: attestation.data.target.root,
attestation: attestation.data().target.root,
// It is not clear what root we should expect in this case, since the attestation is
// fundamentally invalid.
expected: None,
Expand All @@ -1159,9 +1158,9 @@ pub fn verify_attestation_target_root<E: EthSpec>(
};

// Reject any attestation with an invalid target root.
if target_root != attestation.data.target.root {
if target_root != attestation.data().target.root {
return Err(Error::InvalidTargetRoot {
attestation: attestation.data.target.root,
attestation: attestation.data().target.root,
expected: Some(target_root),
});
}
Expand Down Expand Up @@ -1199,7 +1198,7 @@ pub fn verify_signed_aggregate_signatures<T: BeaconChainTypes>(

let fork = chain
.spec
.fork_at_epoch(indexed_attestation.data.target.epoch);
.fork_at_epoch(indexed_attestation.data().target.epoch);

let signature_sets = vec![
signed_aggregate_selection_proof_signature_set(
Expand All @@ -1220,7 +1219,7 @@ pub fn verify_signed_aggregate_signatures<T: BeaconChainTypes>(
.map_err(BeaconChainError::SignatureSetError)?,
indexed_attestation_signature_set_from_pubkeys(
|validator_index| pubkey_cache.get(validator_index).map(Cow::Borrowed),
&indexed_attestation.signature,
indexed_attestation.signature(),
indexed_attestation,
&fork,
chain.genesis_validators_root,
Expand Down Expand Up @@ -1266,8 +1265,8 @@ where
T: BeaconChainTypes,
F: Fn((BeaconCommittee, CommitteesPerSlot)) -> Result<R, Error>,
{
let attestation_epoch = attestation.data.slot.epoch(T::EthSpec::slots_per_epoch());
let target = &attestation.data.target;
let attestation_epoch = attestation.data().slot.epoch(T::EthSpec::slots_per_epoch());
let target = &attestation.data().target;

// Attestation target must be for a known block.
//
Expand All @@ -1290,12 +1289,12 @@ where
let committees_per_slot = committee_cache.committees_per_slot();

Ok(committee_cache
.get_beacon_committee(attestation.data.slot, attestation.data.index)
.get_beacon_committee(attestation.data().slot, attestation.data().index)
.map(|committee| map_fn((committee, committees_per_slot)))
.unwrap_or_else(|| {
Err(Error::NoCommitteeForSlotAndIndex {
slot: attestation.data.slot,
index: attestation.data.index,
slot: attestation.data().slot,
index: attestation.data().index,
})
}))
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ where
let indexed_attestation = &indexed.indexed_attestation;
let fork = chain
.spec
.fork_at_epoch(indexed_attestation.data.target.epoch);
.fork_at_epoch(indexed_attestation.data().target.epoch);

signature_sets.push(
signed_aggregate_selection_proof_signature_set(
Expand All @@ -98,7 +98,7 @@ where
signature_sets.push(
indexed_attestation_signature_set_from_pubkeys(
|validator_index| pubkey_cache.get(validator_index).map(Cow::Borrowed),
&indexed_attestation.signature,
indexed_attestation.signature(),
indexed_attestation,
&fork,
chain.genesis_validators_root,
Expand Down Expand Up @@ -182,11 +182,11 @@ where
let indexed_attestation = &partially_verified.indexed_attestation;
let fork = chain
.spec
.fork_at_epoch(indexed_attestation.data.target.epoch);
.fork_at_epoch(indexed_attestation.data().target.epoch);

let signature_set = indexed_attestation_signature_set_from_pubkeys(
|validator_index| pubkey_cache.get(validator_index).map(Cow::Borrowed),
&indexed_attestation.signature,
indexed_attestation.signature(),
indexed_attestation,
&fork,
chain.genesis_validators_root,
Expand Down
2 changes: 1 addition & 1 deletion beacon_node/beacon_chain/src/beacon_block_reward.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let mut previous_epoch_participation = state.previous_epoch_participation()?.clone();

for attestation in block.body().attestations() {
let data = &attestation.data;
let data = attestation.data();
let inclusion_delay = state.slot().safe_sub(data.slot)?.as_u64();
// [Modified in Deneb:EIP7045]
let participation_flag_indices = get_attestation_participation_flag_indices(
Expand Down
Loading

0 comments on commit 3b7132b

Please sign in to comment.