mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-29 20:27:14 +00:00
superstruct the AttesterSlashing (#5636)
* `superstruct` Attester Fork Variants * Push a little further * Deal with Encode / Decode of AttesterSlashing * not so sure about this.. * Stop Encode/Decode Bounds from Propagating Out * Tons of Changes.. * More Conversions to AttestationRef * Add AsReference trait (#15) * Add AsReference trait * Fix some snafus * Got it Compiling! :D * Got Tests Building * Get beacon chain tests compiling --------- Co-authored-by: Michael Sproul <micsproul@gmail.com>
This commit is contained in:
@@ -471,7 +471,7 @@ impl<'a, T: BeaconChainTypes> IndexedAggregatedAttestation<'a, T> {
|
||||
if chain
|
||||
.observed_attestations
|
||||
.write()
|
||||
.is_known_subset(attestation, attestation_data_root)
|
||||
.is_known_subset(attestation.to_ref(), attestation_data_root)
|
||||
.map_err(|e| Error::BeaconChainError(e.into()))?
|
||||
{
|
||||
metrics::inc_counter(&metrics::AGGREGATED_ATTESTATION_SUBSETS);
|
||||
@@ -559,7 +559,7 @@ impl<'a, T: BeaconChainTypes> IndexedAggregatedAttestation<'a, T> {
|
||||
return Err(Error::AggregatorNotInCommittee { aggregator_index });
|
||||
}
|
||||
|
||||
get_indexed_attestation(committee.committee, attestation)
|
||||
get_indexed_attestation(committee.committee, attestation.to_ref())
|
||||
.map_err(|e| BeaconChainError::from(e).into())
|
||||
};
|
||||
|
||||
@@ -597,7 +597,7 @@ impl<'a, T: BeaconChainTypes> VerifiedAggregatedAttestation<'a, T> {
|
||||
if let ObserveOutcome::Subset = chain
|
||||
.observed_attestations
|
||||
.write()
|
||||
.observe_item(attestation, Some(attestation_data_root))
|
||||
.observe_item(attestation.to_ref(), Some(attestation_data_root))
|
||||
.map_err(|e| Error::BeaconChainError(e.into()))?
|
||||
{
|
||||
metrics::inc_counter(&metrics::AGGREGATED_ATTESTATION_SUBSETS);
|
||||
@@ -1241,7 +1241,7 @@ pub fn obtain_indexed_attestation_and_committees_per_slot<T: BeaconChainTypes>(
|
||||
attestation: &Attestation<T::EthSpec>,
|
||||
) -> Result<(IndexedAttestation<T::EthSpec>, CommitteesPerSlot), Error> {
|
||||
map_attestation_committee(chain, attestation, |(committee, committees_per_slot)| {
|
||||
get_indexed_attestation(committee.committee, attestation)
|
||||
get_indexed_attestation(committee.committee, attestation.to_ref())
|
||||
.map(|attestation| (attestation, committees_per_slot))
|
||||
.map_err(Error::Invalid)
|
||||
})
|
||||
|
||||
@@ -2113,7 +2113,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.fork_choice_write_lock()
|
||||
.on_attestation(
|
||||
self.slot()?,
|
||||
verified.indexed_attestation(),
|
||||
verified.indexed_attestation().to_ref(),
|
||||
AttestationFromBlock::False,
|
||||
)
|
||||
.map_err(Into::into)
|
||||
@@ -2465,7 +2465,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
// Add to fork choice.
|
||||
self.canonical_head
|
||||
.fork_choice_write_lock()
|
||||
.on_attester_slashing(attester_slashing.as_inner());
|
||||
.on_attester_slashing(attester_slashing.as_inner().to_ref());
|
||||
|
||||
// Add to the op pool (if we have the ability to propose blocks).
|
||||
if self.eth1_chain.is_some() {
|
||||
@@ -3820,7 +3820,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
slasher.accept_attestation(indexed_attestation.clone());
|
||||
slasher.accept_attestation(indexed_attestation.clone_as_indexed_attestation());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3839,7 +3839,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
if block.slot() + 2 * T::EthSpec::slots_per_epoch() >= current_slot {
|
||||
metrics::observe(
|
||||
&metrics::OPERATIONS_PER_BLOCK_ATTESTATION,
|
||||
block.body().attestations().len() as f64,
|
||||
block.body().attestations().count() as f64,
|
||||
);
|
||||
|
||||
if let Ok(sync_aggregate) = block.body().sync_aggregate() {
|
||||
@@ -4859,7 +4859,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
metrics::start_timer(&metrics::BLOCK_PRODUCTION_UNAGGREGATED_TIMES);
|
||||
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)?;
|
||||
let attesting_indices =
|
||||
get_attesting_indices_from_state(&state, attestation.to_ref())?;
|
||||
self.op_pool
|
||||
.insert_attestation(attestation.clone(), attesting_indices)
|
||||
};
|
||||
@@ -4909,7 +4910,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
attestations.retain(|att| {
|
||||
verify_attestation_for_block_inclusion(
|
||||
&state,
|
||||
att,
|
||||
att.to_ref(),
|
||||
&mut tmp_ctxt,
|
||||
VerifySignatures::True,
|
||||
&self.spec,
|
||||
@@ -5040,6 +5041,72 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
bls_to_execution_changes,
|
||||
} = partial_beacon_block;
|
||||
|
||||
let (attester_slashings_base, attester_slashings_electra) =
|
||||
attester_slashings.into_iter().fold(
|
||||
(Vec::new(), Vec::new()),
|
||||
|(mut base, mut electra), slashing| {
|
||||
match slashing {
|
||||
AttesterSlashing::Base(slashing) => base.push(slashing),
|
||||
AttesterSlashing::Electra(slashing) => electra.push(slashing),
|
||||
}
|
||||
(base, electra)
|
||||
},
|
||||
);
|
||||
let (attestations_base, attestations_electra) = attestations.into_iter().fold(
|
||||
(Vec::new(), Vec::new()),
|
||||
|(mut base, mut electra), attestation| {
|
||||
match attestation {
|
||||
Attestation::Base(attestation) => base.push(attestation),
|
||||
Attestation::Electra(attestation) => electra.push(attestation),
|
||||
}
|
||||
(base, electra)
|
||||
},
|
||||
);
|
||||
|
||||
// TODO(electra): figure out what should *actually* be done here when we have attestations / attester_slashings of the wrong type
|
||||
match &state {
|
||||
BeaconState::Base(_)
|
||||
| BeaconState::Altair(_)
|
||||
| BeaconState::Merge(_)
|
||||
| BeaconState::Capella(_)
|
||||
| BeaconState::Deneb(_) => {
|
||||
if !attestations_electra.is_empty() {
|
||||
error!(
|
||||
self.log,
|
||||
"Tried to produce block with attestations of the wrong type";
|
||||
"slot" => slot,
|
||||
"attestations" => attestations_electra.len(),
|
||||
);
|
||||
}
|
||||
if !attester_slashings_electra.is_empty() {
|
||||
error!(
|
||||
self.log,
|
||||
"Tried to produce block with attester slashings of the wrong type";
|
||||
"slot" => slot,
|
||||
"attester_slashings" => attester_slashings_electra.len(),
|
||||
);
|
||||
}
|
||||
}
|
||||
BeaconState::Electra(_) => {
|
||||
if !attestations_base.is_empty() {
|
||||
error!(
|
||||
self.log,
|
||||
"Tried to produce block with attestations of the wrong type";
|
||||
"slot" => slot,
|
||||
"attestations" => attestations_base.len(),
|
||||
);
|
||||
}
|
||||
if !attester_slashings_base.is_empty() {
|
||||
error!(
|
||||
self.log,
|
||||
"Tried to produce block with attester slashings of the wrong type";
|
||||
"slot" => slot,
|
||||
"attester_slashings" => attester_slashings_base.len(),
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let (inner_block, maybe_blobs_and_proofs, execution_payload_value) = match &state {
|
||||
BeaconState::Base(_) => (
|
||||
BeaconBlock::Base(BeaconBlockBase {
|
||||
@@ -5052,8 +5119,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings: proposer_slashings.into(),
|
||||
attester_slashings: attester_slashings.into(),
|
||||
attestations: attestations.into(),
|
||||
attester_slashings: attester_slashings_base.into(),
|
||||
attestations: attestations_base.into(),
|
||||
deposits: deposits.into(),
|
||||
voluntary_exits: voluntary_exits.into(),
|
||||
_phantom: PhantomData,
|
||||
@@ -5073,8 +5140,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings: proposer_slashings.into(),
|
||||
attester_slashings: attester_slashings.into(),
|
||||
attestations: attestations.into(),
|
||||
attester_slashings: attester_slashings_base.into(),
|
||||
attestations: attestations_base.into(),
|
||||
deposits: deposits.into(),
|
||||
voluntary_exits: voluntary_exits.into(),
|
||||
sync_aggregate: sync_aggregate
|
||||
@@ -5100,8 +5167,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings: proposer_slashings.into(),
|
||||
attester_slashings: attester_slashings.into(),
|
||||
attestations: attestations.into(),
|
||||
attester_slashings: attester_slashings_base.into(),
|
||||
attestations: attestations_base.into(),
|
||||
deposits: deposits.into(),
|
||||
voluntary_exits: voluntary_exits.into(),
|
||||
sync_aggregate: sync_aggregate
|
||||
@@ -5132,8 +5199,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings: proposer_slashings.into(),
|
||||
attester_slashings: attester_slashings.into(),
|
||||
attestations: attestations.into(),
|
||||
attester_slashings: attester_slashings_base.into(),
|
||||
attestations: attestations_base.into(),
|
||||
deposits: deposits.into(),
|
||||
voluntary_exits: voluntary_exits.into(),
|
||||
sync_aggregate: sync_aggregate
|
||||
@@ -5166,8 +5233,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings: proposer_slashings.into(),
|
||||
attester_slashings: attester_slashings.into(),
|
||||
attestations: attestations.into(),
|
||||
attester_slashings: attester_slashings_base.into(),
|
||||
attestations: attestations_base.into(),
|
||||
deposits: deposits.into(),
|
||||
voluntary_exits: voluntary_exits.into(),
|
||||
sync_aggregate: sync_aggregate
|
||||
@@ -5204,8 +5271,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings: proposer_slashings.into(),
|
||||
attester_slashings: attester_slashings.into(),
|
||||
attestations: attestations.into(),
|
||||
attester_slashings: attester_slashings_electra.into(),
|
||||
attestations: attestations_electra.into(),
|
||||
deposits: deposits.into(),
|
||||
voluntary_exits: voluntary_exits.into(),
|
||||
sync_aggregate: sync_aggregate
|
||||
@@ -5216,6 +5283,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
bls_to_execution_changes: bls_to_execution_changes.into(),
|
||||
blob_kzg_commitments: kzg_commitments
|
||||
.ok_or(BlockProductionError::InvalidPayloadFork)?,
|
||||
// TODO(electra): finish consolidations when they're more spec'd out
|
||||
consolidations: Vec::new().into(),
|
||||
},
|
||||
}),
|
||||
maybe_blobs_and_proofs,
|
||||
@@ -5321,7 +5390,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
self.log,
|
||||
"Produced beacon block";
|
||||
"parent" => ?block.parent_root(),
|
||||
"attestations" => block.body().attestations().len(),
|
||||
"attestations" => block.body().attestations_len(),
|
||||
"slot" => block.slot()
|
||||
);
|
||||
|
||||
|
||||
@@ -27,10 +27,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let split_attestations = block
|
||||
.body()
|
||||
.attestations()
|
||||
.iter()
|
||||
.map(|att| {
|
||||
let attesting_indices = get_attesting_indices_from_state(state, att)?;
|
||||
Ok(SplitAttestation::new(att.clone(), attesting_indices))
|
||||
Ok(SplitAttestation::new(
|
||||
att.clone_as_attestation(),
|
||||
attesting_indices,
|
||||
))
|
||||
})
|
||||
.collect::<Result<Vec<_>, BeaconChainError>>()?;
|
||||
|
||||
@@ -86,7 +88,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
block
|
||||
.body()
|
||||
.attestations()
|
||||
.iter()
|
||||
.map(|a| a.data().clone())
|
||||
.collect()
|
||||
} else {
|
||||
|
||||
@@ -1623,7 +1623,7 @@ impl<T: BeaconChainTypes> ExecutionPendingBlock<T> {
|
||||
}
|
||||
|
||||
// Register each attestation in the block with fork choice.
|
||||
for (i, attestation) in block.message().body().attestations().iter().enumerate() {
|
||||
for (i, attestation) in block.message().body().attestations().enumerate() {
|
||||
let _fork_choice_attestation_timer =
|
||||
metrics::start_timer(&metrics::FORK_CHOICE_PROCESS_ATTESTATION_TIMES);
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ use types::consts::altair::{
|
||||
SYNC_COMMITTEE_SUBNET_COUNT, TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE,
|
||||
};
|
||||
use types::slot_data::SlotData;
|
||||
use types::{Attestation, EthSpec, Hash256, Slot, SyncCommitteeContribution};
|
||||
use types::{Attestation, AttestationRef, EthSpec, Hash256, Slot, SyncCommitteeContribution};
|
||||
|
||||
pub type ObservedSyncContributions<E> = ObservedAggregates<
|
||||
SyncCommitteeContribution<E>,
|
||||
@@ -102,30 +102,30 @@ pub trait SubsetItem {
|
||||
fn root(&self) -> Hash256;
|
||||
}
|
||||
|
||||
impl<E: EthSpec> SubsetItem for Attestation<E> {
|
||||
impl<'a, E: EthSpec> SubsetItem for AttestationRef<'a, E> {
|
||||
type Item = BitList<E::MaxValidatorsPerCommittee>;
|
||||
fn is_subset(&self, other: &Self::Item) -> bool {
|
||||
match self {
|
||||
Attestation::Base(att) => att.aggregation_bits.is_subset(other),
|
||||
Self::Base(att) => att.aggregation_bits.is_subset(other),
|
||||
// TODO(electra) implement electra variant
|
||||
Attestation::Electra(_) => todo!(),
|
||||
Self::Electra(_) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_superset(&self, other: &Self::Item) -> bool {
|
||||
match self {
|
||||
Attestation::Base(att) => other.is_subset(&att.aggregation_bits),
|
||||
Self::Base(att) => other.is_subset(&att.aggregation_bits),
|
||||
// TODO(electra) implement electra variant
|
||||
Attestation::Electra(_) => todo!(),
|
||||
Self::Electra(_) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the sync contribution aggregation bits.
|
||||
fn get_item(&self) -> Self::Item {
|
||||
match self {
|
||||
Attestation::Base(att) => att.aggregation_bits.clone(),
|
||||
Self::Base(att) => att.aggregation_bits.clone(),
|
||||
// TODO(electra) implement electra variant
|
||||
Attestation::Electra(_) => todo!(),
|
||||
Self::Electra(_) => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ impl<E: EthSpec> SubsetItem for Attestation<E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> SubsetItem for SyncCommitteeContribution<E> {
|
||||
impl<'a, E: EthSpec> SubsetItem for &'a SyncCommitteeContribution<E> {
|
||||
type Item = BitVector<E::SyncSubcommitteeSize>;
|
||||
fn is_subset(&self, other: &Self::Item) -> bool {
|
||||
self.aggregation_bits.is_subset(other)
|
||||
@@ -208,7 +208,7 @@ impl<I> SlotHashSet<I> {
|
||||
/// Store the items in self so future observations recognise its existence.
|
||||
pub fn observe_item<S: SlotData + SubsetItem<Item = I>>(
|
||||
&mut self,
|
||||
item: &S,
|
||||
item: S,
|
||||
root: Hash256,
|
||||
) -> Result<ObserveOutcome, Error> {
|
||||
if item.get_slot() != self.slot {
|
||||
@@ -254,7 +254,7 @@ impl<I> SlotHashSet<I> {
|
||||
/// the given root and slot.
|
||||
pub fn is_known_subset<S: SlotData + SubsetItem<Item = I>>(
|
||||
&self,
|
||||
item: &S,
|
||||
item: S,
|
||||
root: Hash256,
|
||||
) -> Result<bool, Error> {
|
||||
if item.get_slot() != self.slot {
|
||||
@@ -276,16 +276,43 @@ impl<I> SlotHashSet<I> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for observable items that can be observed from their reference type.
|
||||
///
|
||||
/// This is used to make observations for `Attestation`s from `AttestationRef`s.
|
||||
pub trait AsReference {
|
||||
type Reference<'a>
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
fn as_reference(&self) -> Self::Reference<'_>;
|
||||
}
|
||||
|
||||
impl<E: EthSpec> AsReference for Attestation<E> {
|
||||
type Reference<'a> = AttestationRef<'a, E>;
|
||||
|
||||
fn as_reference(&self) -> AttestationRef<'_, E> {
|
||||
self.to_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> AsReference for SyncCommitteeContribution<E> {
|
||||
type Reference<'a> = &'a Self;
|
||||
|
||||
fn as_reference(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores the roots of objects for some number of `Slots`, so we can determine if
|
||||
/// these have previously been seen on the network.
|
||||
pub struct ObservedAggregates<T: SlotData + Consts, E: EthSpec, I> {
|
||||
pub struct ObservedAggregates<T: Consts + AsReference, E: EthSpec, I> {
|
||||
lowest_permissible_slot: Slot,
|
||||
sets: Vec<SlotHashSet<I>>,
|
||||
_phantom_spec: PhantomData<E>,
|
||||
_phantom_tree_hash: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: SlotData + Consts, E: EthSpec, I> Default for ObservedAggregates<T, E, I> {
|
||||
impl<T: Consts + AsReference, E: EthSpec, I> Default for ObservedAggregates<T, E, I> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
lowest_permissible_slot: Slot::new(0),
|
||||
@@ -296,13 +323,18 @@ impl<T: SlotData + Consts, E: EthSpec, I> Default for ObservedAggregates<T, E, I
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SlotData + Consts + SubsetItem<Item = I>, E: EthSpec, I> ObservedAggregates<T, E, I> {
|
||||
impl<T, E, I> ObservedAggregates<T, E, I>
|
||||
where
|
||||
T: Consts + AsReference,
|
||||
E: EthSpec,
|
||||
for<'a> T::Reference<'a>: SubsetItem<Item = I> + SlotData,
|
||||
{
|
||||
/// Store `item` in `self` keyed at `root`.
|
||||
///
|
||||
/// `root` must equal `item.root::<SubsetItem>()`.
|
||||
pub fn observe_item(
|
||||
&mut self,
|
||||
item: &T,
|
||||
item: T::Reference<'_>,
|
||||
root_opt: Option<Hash256>,
|
||||
) -> Result<ObserveOutcome, Error> {
|
||||
let index = self.get_set_index(item.get_slot())?;
|
||||
@@ -319,7 +351,11 @@ impl<T: SlotData + Consts + SubsetItem<Item = I>, E: EthSpec, I> ObservedAggrega
|
||||
///
|
||||
/// `root` must equal `item.root::<SubsetItem>()`.
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub fn is_known_subset(&mut self, item: &T, root: Hash256) -> Result<bool, Error> {
|
||||
pub fn is_known_subset(
|
||||
&mut self,
|
||||
item: T::Reference<'_>,
|
||||
root: Hash256,
|
||||
) -> Result<bool, Error> {
|
||||
let index = self.get_set_index(item.get_slot())?;
|
||||
|
||||
self.sets
|
||||
@@ -417,8 +453,8 @@ mod tests {
|
||||
|
||||
fn get_attestation(slot: Slot, beacon_block_root: u64) -> Attestation<E> {
|
||||
let mut a: Attestation<E> = test_random_instance();
|
||||
a.data.slot = slot;
|
||||
a.data.beacon_block_root = Hash256::from_low_u64_be(beacon_block_root);
|
||||
a.data_mut().slot = slot;
|
||||
a.data_mut().beacon_block_root = Hash256::from_low_u64_be(beacon_block_root);
|
||||
a
|
||||
}
|
||||
|
||||
@@ -444,12 +480,12 @@ mod tests {
|
||||
|
||||
for a in &items {
|
||||
assert_eq!(
|
||||
store.is_known_subset(a, a.root()),
|
||||
store.is_known_subset(a.as_reference(), a.as_reference().root()),
|
||||
Ok(false),
|
||||
"should indicate an unknown attestation is unknown"
|
||||
);
|
||||
assert_eq!(
|
||||
store.observe_item(a, None),
|
||||
store.observe_item(a.as_reference(), None),
|
||||
Ok(ObserveOutcome::New),
|
||||
"should observe new attestation"
|
||||
);
|
||||
@@ -457,12 +493,12 @@ mod tests {
|
||||
|
||||
for a in &items {
|
||||
assert_eq!(
|
||||
store.is_known_subset(a, a.root()),
|
||||
store.is_known_subset(a.as_reference(), a.as_reference().root()),
|
||||
Ok(true),
|
||||
"should indicate a known attestation is known"
|
||||
);
|
||||
assert_eq!(
|
||||
store.observe_item(a, Some(a.root())),
|
||||
store.observe_item(a.as_reference(), Some(a.as_reference().root())),
|
||||
Ok(ObserveOutcome::Subset),
|
||||
"should acknowledge an existing attestation"
|
||||
);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use derivative::Derivative;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use ssz::{Decode, Encode};
|
||||
use state_processing::{SigVerifiedOp, VerifyOperation, VerifyOperationAt};
|
||||
use state_processing::{SigVerifiedOp, TransformPersist, VerifyOperation, VerifyOperationAt};
|
||||
use std::collections::HashSet;
|
||||
use std::marker::PhantomData;
|
||||
use types::{
|
||||
@@ -34,7 +33,7 @@ pub struct ObservedOperations<T: ObservableOperation<E>, E: EthSpec> {
|
||||
|
||||
/// Was the observed operation new and valid for further processing, or a useless duplicate?
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub enum ObservationOutcome<T: Encode + Decode, E: EthSpec> {
|
||||
pub enum ObservationOutcome<T: TransformPersist, E: EthSpec> {
|
||||
New(SigVerifiedOp<T, E>),
|
||||
AlreadyKnown,
|
||||
}
|
||||
@@ -62,12 +61,12 @@ impl<E: EthSpec> ObservableOperation<E> for ProposerSlashing {
|
||||
impl<E: EthSpec> ObservableOperation<E> for AttesterSlashing<E> {
|
||||
fn observed_validators(&self) -> SmallVec<[u64; SMALL_VEC_SIZE]> {
|
||||
let attestation_1_indices = self
|
||||
.attestation_1
|
||||
.attestation_1()
|
||||
.attesting_indices_iter()
|
||||
.copied()
|
||||
.collect::<HashSet<u64>>();
|
||||
let attestation_2_indices = self
|
||||
.attestation_2
|
||||
.attestation_2()
|
||||
.attesting_indices_iter()
|
||||
.copied()
|
||||
.collect::<HashSet<u64>>();
|
||||
|
||||
@@ -1492,7 +1492,8 @@ where
|
||||
) -> AttesterSlashing<E> {
|
||||
let fork = self.chain.canonical_head.cached_head().head_fork();
|
||||
|
||||
let mut attestation_1 = IndexedAttestation::Base(IndexedAttestationBase {
|
||||
// TODO(electra): consider making this test fork-agnostic
|
||||
let mut attestation_1 = IndexedAttestationBase {
|
||||
attesting_indices: VariableList::new(validator_indices).unwrap(),
|
||||
data: AttestationData {
|
||||
slot: Slot::new(0),
|
||||
@@ -1508,36 +1509,37 @@ where
|
||||
},
|
||||
},
|
||||
signature: AggregateSignature::infinity(),
|
||||
});
|
||||
};
|
||||
|
||||
let mut attestation_2 = attestation_1.clone();
|
||||
attestation_2.data_mut().index += 1;
|
||||
attestation_2.data_mut().source.epoch = source2.unwrap_or(Epoch::new(0));
|
||||
attestation_2.data_mut().target.epoch = target2.unwrap_or(fork.epoch);
|
||||
attestation_2.data.index += 1;
|
||||
attestation_2.data.source.epoch = source2.unwrap_or(Epoch::new(0));
|
||||
attestation_2.data.target.epoch = target2.unwrap_or(fork.epoch);
|
||||
|
||||
for attestation in &mut [&mut attestation_1, &mut attestation_2] {
|
||||
// TODO(electra) we could explore iter mut here
|
||||
for i in attestation.attesting_indices_to_vec() {
|
||||
let sk = &self.validator_keypairs[i as usize].sk;
|
||||
for i in attestation.attesting_indices.iter() {
|
||||
let sk = &self.validator_keypairs[*i as usize].sk;
|
||||
|
||||
let genesis_validators_root = self.chain.genesis_validators_root;
|
||||
|
||||
let domain = self.chain.spec.get_domain(
|
||||
attestation.data().target.epoch,
|
||||
attestation.data.target.epoch,
|
||||
Domain::BeaconAttester,
|
||||
&fork,
|
||||
genesis_validators_root,
|
||||
);
|
||||
let message = attestation.data().signing_root(domain);
|
||||
let message = attestation.data.signing_root(domain);
|
||||
|
||||
attestation.signature_mut().add_assign(&sk.sign(message));
|
||||
attestation.signature.add_assign(&sk.sign(message));
|
||||
}
|
||||
}
|
||||
|
||||
AttesterSlashing {
|
||||
// TODO(electra): fix this test
|
||||
AttesterSlashing::Base(AttesterSlashingBase {
|
||||
attestation_1,
|
||||
attestation_2,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn make_attester_slashing_different_indices(
|
||||
@@ -1559,43 +1561,45 @@ where
|
||||
},
|
||||
};
|
||||
|
||||
let mut attestation_1 = IndexedAttestation::Base(IndexedAttestationBase {
|
||||
// TODO(electra): make this test fork-agnostic
|
||||
let mut attestation_1 = IndexedAttestationBase {
|
||||
attesting_indices: VariableList::new(validator_indices_1).unwrap(),
|
||||
data: data.clone(),
|
||||
signature: AggregateSignature::infinity(),
|
||||
});
|
||||
};
|
||||
|
||||
let mut attestation_2 = IndexedAttestation::Base(IndexedAttestationBase {
|
||||
let mut attestation_2 = IndexedAttestationBase {
|
||||
attesting_indices: VariableList::new(validator_indices_2).unwrap(),
|
||||
data,
|
||||
signature: AggregateSignature::infinity(),
|
||||
});
|
||||
};
|
||||
|
||||
attestation_2.data_mut().index += 1;
|
||||
attestation_2.data.index += 1;
|
||||
|
||||
let fork = self.chain.canonical_head.cached_head().head_fork();
|
||||
for attestation in &mut [&mut attestation_1, &mut attestation_2] {
|
||||
for i in attestation.attesting_indices_to_vec() {
|
||||
let sk = &self.validator_keypairs[i as usize].sk;
|
||||
for i in attestation.attesting_indices.iter() {
|
||||
let sk = &self.validator_keypairs[*i as usize].sk;
|
||||
|
||||
let genesis_validators_root = self.chain.genesis_validators_root;
|
||||
|
||||
let domain = self.chain.spec.get_domain(
|
||||
attestation.data().target.epoch,
|
||||
attestation.data.target.epoch,
|
||||
Domain::BeaconAttester,
|
||||
&fork,
|
||||
genesis_validators_root,
|
||||
);
|
||||
let message = attestation.data().signing_root(domain);
|
||||
let message = attestation.data.signing_root(domain);
|
||||
|
||||
attestation.signature_mut().add_assign(&sk.sign(message));
|
||||
attestation.signature.add_assign(&sk.sign(message));
|
||||
}
|
||||
}
|
||||
|
||||
AttesterSlashing {
|
||||
// TODO(electra): fix this test
|
||||
AttesterSlashing::Base(AttesterSlashingBase {
|
||||
attestation_1,
|
||||
attestation_2,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn make_proposer_slashing(&self, validator_index: u64) -> ProposerSlashing {
|
||||
|
||||
@@ -25,9 +25,10 @@ use types::consts::altair::{
|
||||
TIMELY_HEAD_FLAG_INDEX, TIMELY_SOURCE_FLAG_INDEX, TIMELY_TARGET_FLAG_INDEX,
|
||||
};
|
||||
use types::{
|
||||
Attestation, AttestationData, AttesterSlashing, BeaconBlockRef, BeaconState, BeaconStateError,
|
||||
ChainSpec, Epoch, EthSpec, Hash256, IndexedAttestation, ProposerSlashing, PublicKeyBytes,
|
||||
SignedAggregateAndProof, SignedContributionAndProof, Slot, SyncCommitteeMessage, VoluntaryExit,
|
||||
Attestation, AttestationData, AttesterSlashingRef, BeaconBlockRef, BeaconState,
|
||||
BeaconStateError, ChainSpec, Epoch, EthSpec, Hash256, IndexedAttestation,
|
||||
IndexedAttestationRef, ProposerSlashing, PublicKeyBytes, SignedAggregateAndProof,
|
||||
SignedContributionAndProof, Slot, SyncCommitteeMessage, VoluntaryExit,
|
||||
};
|
||||
|
||||
/// Used for Prometheus labels.
|
||||
@@ -1410,7 +1411,7 @@ impl<E: EthSpec> ValidatorMonitor<E> {
|
||||
/// Note: Blocks that get orphaned will skew the inclusion distance calculation.
|
||||
pub fn register_attestation_in_block(
|
||||
&self,
|
||||
indexed_attestation: &IndexedAttestation<E>,
|
||||
indexed_attestation: IndexedAttestationRef<'_, E>,
|
||||
parent_slot: Slot,
|
||||
spec: &ChainSpec,
|
||||
) {
|
||||
@@ -1783,30 +1784,30 @@ impl<E: EthSpec> ValidatorMonitor<E> {
|
||||
}
|
||||
|
||||
/// Register an attester slashing from the gossip network.
|
||||
pub fn register_gossip_attester_slashing(&self, slashing: &AttesterSlashing<E>) {
|
||||
pub fn register_gossip_attester_slashing(&self, slashing: AttesterSlashingRef<'_, E>) {
|
||||
self.register_attester_slashing("gossip", slashing)
|
||||
}
|
||||
|
||||
/// Register an attester slashing from the HTTP API.
|
||||
pub fn register_api_attester_slashing(&self, slashing: &AttesterSlashing<E>) {
|
||||
pub fn register_api_attester_slashing(&self, slashing: AttesterSlashingRef<'_, E>) {
|
||||
self.register_attester_slashing("api", slashing)
|
||||
}
|
||||
|
||||
/// Register an attester slashing included in a *valid* `BeaconBlock`.
|
||||
pub fn register_block_attester_slashing(&self, slashing: &AttesterSlashing<E>) {
|
||||
pub fn register_block_attester_slashing(&self, slashing: AttesterSlashingRef<'_, E>) {
|
||||
self.register_attester_slashing("block", slashing)
|
||||
}
|
||||
|
||||
fn register_attester_slashing(&self, src: &str, slashing: &AttesterSlashing<E>) {
|
||||
let data = slashing.attestation_1.data();
|
||||
fn register_attester_slashing(&self, src: &str, slashing: AttesterSlashingRef<'_, E>) {
|
||||
let data = slashing.attestation_1().data();
|
||||
let attestation_1_indices: HashSet<u64> = slashing
|
||||
.attestation_1
|
||||
.attestation_1()
|
||||
.attesting_indices_iter()
|
||||
.copied()
|
||||
.collect();
|
||||
|
||||
slashing
|
||||
.attestation_2
|
||||
.attestation_2()
|
||||
.attesting_indices_iter()
|
||||
.filter(|index| attestation_1_indices.contains(index))
|
||||
.filter_map(|index| self.get_validator(*index))
|
||||
|
||||
@@ -8,7 +8,9 @@ use beacon_chain::{metrics, StateSkipConfig, WhenSlotSkipped};
|
||||
use lazy_static::lazy_static;
|
||||
use std::sync::Arc;
|
||||
use tree_hash::TreeHash;
|
||||
use types::{AggregateSignature, EthSpec, Keypair, MainnetEthSpec, RelativeEpoch, Slot};
|
||||
use types::{
|
||||
AggregateSignature, Attestation, EthSpec, Keypair, MainnetEthSpec, RelativeEpoch, Slot,
|
||||
};
|
||||
|
||||
pub const VALIDATOR_COUNT: usize = 16;
|
||||
|
||||
@@ -188,20 +190,35 @@ async fn produces_attestations() {
|
||||
.produce_unaggregated_attestation(slot, index)
|
||||
.expect("should produce attestation");
|
||||
|
||||
let data = &attestation.data;
|
||||
match &attestation {
|
||||
Attestation::Base(att) => {
|
||||
assert_eq!(
|
||||
att.aggregation_bits.len(),
|
||||
committee_len,
|
||||
"bad committee len"
|
||||
);
|
||||
assert!(
|
||||
att.aggregation_bits.is_zero(),
|
||||
"some committee bits are set"
|
||||
);
|
||||
}
|
||||
Attestation::Electra(att) => {
|
||||
assert_eq!(
|
||||
att.aggregation_bits.len(),
|
||||
committee_len,
|
||||
"bad committee len"
|
||||
);
|
||||
assert!(
|
||||
att.aggregation_bits.is_zero(),
|
||||
"some committee bits are set"
|
||||
);
|
||||
}
|
||||
}
|
||||
let data = attestation.data();
|
||||
|
||||
assert_eq!(
|
||||
attestation.aggregation_bits.len(),
|
||||
committee_len,
|
||||
"bad committee len"
|
||||
);
|
||||
assert!(
|
||||
attestation.aggregation_bits.is_zero(),
|
||||
"some committee bits are set"
|
||||
);
|
||||
assert_eq!(
|
||||
attestation.signature,
|
||||
AggregateSignature::empty(),
|
||||
attestation.signature(),
|
||||
&AggregateSignature::empty(),
|
||||
"bad signature"
|
||||
);
|
||||
assert_eq!(data.index, index, "bad index");
|
||||
@@ -329,10 +346,10 @@ async fn early_attester_cache_old_request() {
|
||||
.produce_unaggregated_attestation(attest_slot, 0)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(attestation.data.slot, attest_slot);
|
||||
assert_eq!(attestation.data().slot, attest_slot);
|
||||
let attested_block = harness
|
||||
.chain
|
||||
.get_blinded_block(&attestation.data.beacon_block_root)
|
||||
.get_blinded_block(&attestation.data().beacon_block_root)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(attested_block.slot(), attest_slot);
|
||||
|
||||
@@ -125,7 +125,7 @@ fn get_valid_unaggregated_attestation<T: BeaconChainTypes>(
|
||||
let validator_committee_index = 0;
|
||||
let validator_index = *head
|
||||
.beacon_state
|
||||
.get_beacon_committee(current_slot, valid_attestation.data.index)
|
||||
.get_beacon_committee(current_slot, valid_attestation.data().index)
|
||||
.expect("should get committees")
|
||||
.committee
|
||||
.get(validator_committee_index)
|
||||
@@ -144,7 +144,7 @@ fn get_valid_unaggregated_attestation<T: BeaconChainTypes>(
|
||||
.expect("should sign attestation");
|
||||
|
||||
let subnet_id = SubnetId::compute_subnet_for_attestation_data::<E>(
|
||||
&valid_attestation.data,
|
||||
valid_attestation.data(),
|
||||
head.beacon_state
|
||||
.get_committee_count_at_slot(current_slot)
|
||||
.expect("should get committee count"),
|
||||
@@ -170,7 +170,7 @@ fn get_valid_aggregated_attestation<T: BeaconChainTypes>(
|
||||
let current_slot = chain.slot().expect("should get slot");
|
||||
|
||||
let committee = state
|
||||
.get_beacon_committee(current_slot, aggregate.data.index)
|
||||
.get_beacon_committee(current_slot, aggregate.data().index)
|
||||
.expect("should get committees");
|
||||
let committee_len = committee.committee.len();
|
||||
|
||||
@@ -181,7 +181,7 @@ fn get_valid_aggregated_attestation<T: BeaconChainTypes>(
|
||||
let aggregator_sk = generate_deterministic_keypair(val_index).sk;
|
||||
|
||||
let proof = SelectionProof::new::<T::EthSpec>(
|
||||
aggregate.data.slot,
|
||||
aggregate.data().slot,
|
||||
&aggregator_sk,
|
||||
&state.fork(),
|
||||
chain.genesis_validators_root,
|
||||
@@ -220,7 +220,7 @@ fn get_non_aggregator<T: BeaconChainTypes>(
|
||||
let current_slot = chain.slot().expect("should get slot");
|
||||
|
||||
let committee = state
|
||||
.get_beacon_committee(current_slot, aggregate.data.index)
|
||||
.get_beacon_committee(current_slot, aggregate.data().index)
|
||||
.expect("should get committees");
|
||||
let committee_len = committee.committee.len();
|
||||
|
||||
@@ -231,7 +231,7 @@ fn get_non_aggregator<T: BeaconChainTypes>(
|
||||
let aggregator_sk = generate_deterministic_keypair(val_index).sk;
|
||||
|
||||
let proof = SelectionProof::new::<T::EthSpec>(
|
||||
aggregate.data.slot,
|
||||
aggregate.data().slot,
|
||||
&aggregator_sk,
|
||||
&state.fork(),
|
||||
chain.genesis_validators_root,
|
||||
@@ -301,7 +301,7 @@ impl GossipTester {
|
||||
get_valid_aggregated_attestation(&harness.chain, valid_attestation.clone());
|
||||
|
||||
let mut invalid_attestation = valid_attestation.clone();
|
||||
invalid_attestation.data.beacon_block_root = Hash256::repeat_byte(13);
|
||||
invalid_attestation.data_mut().beacon_block_root = Hash256::repeat_byte(13);
|
||||
|
||||
let (mut invalid_aggregate, _, _) =
|
||||
get_valid_aggregated_attestation(&harness.chain, invalid_attestation.clone());
|
||||
@@ -490,7 +490,7 @@ async fn aggregated_gossip_verification() {
|
||||
*/
|
||||
.inspect_aggregate_err(
|
||||
"aggregate from future slot",
|
||||
|tester, a| a.message.aggregate.data.slot = tester.slot() + 1,
|
||||
|tester, a| a.message.aggregate.data_mut().slot = tester.slot() + 1,
|
||||
|tester, err| {
|
||||
assert!(matches!(
|
||||
err,
|
||||
@@ -504,8 +504,9 @@ async fn aggregated_gossip_verification() {
|
||||
"aggregate from past slot",
|
||||
|tester, a| {
|
||||
let too_early_slot = tester.earliest_valid_attestation_slot() - 1;
|
||||
a.message.aggregate.data.slot = too_early_slot;
|
||||
a.message.aggregate.data.target.epoch = too_early_slot.epoch(E::slots_per_epoch());
|
||||
a.message.aggregate.data_mut().slot = too_early_slot;
|
||||
a.message.aggregate.data_mut().target.epoch =
|
||||
too_early_slot.epoch(E::slots_per_epoch());
|
||||
},
|
||||
|tester, err| {
|
||||
let valid_early_slot = tester.earliest_valid_attestation_slot();
|
||||
@@ -529,7 +530,7 @@ async fn aggregated_gossip_verification() {
|
||||
*/
|
||||
.inspect_aggregate_err(
|
||||
"attestation with invalid target epoch",
|
||||
|_, a| a.message.aggregate.data.target.epoch += 1,
|
||||
|_, a| a.message.aggregate.data_mut().target.epoch += 1,
|
||||
|_, err| assert!(matches!(err, AttnError::InvalidTargetEpoch { .. })),
|
||||
)
|
||||
/*
|
||||
@@ -538,7 +539,7 @@ async fn aggregated_gossip_verification() {
|
||||
*/
|
||||
.inspect_aggregate_err(
|
||||
"attestation with invalid target root",
|
||||
|_, a| a.message.aggregate.data.target.root = Hash256::repeat_byte(42),
|
||||
|_, a| a.message.aggregate.data_mut().target.root = Hash256::repeat_byte(42),
|
||||
|_, err| assert!(matches!(err, AttnError::InvalidTargetRoot { .. })),
|
||||
)
|
||||
/*
|
||||
@@ -548,7 +549,7 @@ async fn aggregated_gossip_verification() {
|
||||
*/
|
||||
.inspect_aggregate_err(
|
||||
"aggregate with unknown head block",
|
||||
|_, a| a.message.aggregate.data.beacon_block_root = Hash256::repeat_byte(42),
|
||||
|_, a| a.message.aggregate.data_mut().beacon_block_root = Hash256::repeat_byte(42),
|
||||
|_, err| {
|
||||
assert!(matches!(
|
||||
err,
|
||||
@@ -567,10 +568,19 @@ async fn aggregated_gossip_verification() {
|
||||
.inspect_aggregate_err(
|
||||
"aggregate with no participants",
|
||||
|_, a| {
|
||||
let aggregation_bits = &mut a.message.aggregate.aggregation_bits;
|
||||
aggregation_bits.difference_inplace(&aggregation_bits.clone());
|
||||
assert!(aggregation_bits.is_zero());
|
||||
a.message.aggregate.signature = AggregateSignature::infinity();
|
||||
match &mut a.message.aggregate {
|
||||
Attestation::Base(ref mut att) => {
|
||||
let aggregation_bits = &mut att.aggregation_bits;
|
||||
aggregation_bits.difference_inplace(&aggregation_bits.clone());
|
||||
assert!(aggregation_bits.is_zero());
|
||||
}
|
||||
Attestation::Electra(ref mut att) => {
|
||||
let aggregation_bits = &mut att.aggregation_bits;
|
||||
aggregation_bits.difference_inplace(&aggregation_bits.clone());
|
||||
assert!(aggregation_bits.is_zero());
|
||||
}
|
||||
}
|
||||
*a.message.aggregate.signature_mut() = AggregateSignature::infinity();
|
||||
},
|
||||
|_, err| assert!(matches!(err, AttnError::EmptyAggregationBitfield)),
|
||||
)
|
||||
@@ -598,7 +608,7 @@ async fn aggregated_gossip_verification() {
|
||||
.chain
|
||||
.head_snapshot()
|
||||
.beacon_state
|
||||
.get_beacon_committee(tester.slot(), a.message.aggregate.data.index)
|
||||
.get_beacon_committee(tester.slot(), a.message.aggregate.data().index)
|
||||
.expect("should get committees")
|
||||
.committee
|
||||
.len();
|
||||
@@ -634,7 +644,7 @@ async fn aggregated_gossip_verification() {
|
||||
|tester, a| {
|
||||
let mut agg_sig = AggregateSignature::infinity();
|
||||
agg_sig.add_assign(&tester.aggregator_sk.sign(Hash256::repeat_byte(42)));
|
||||
a.message.aggregate.signature = agg_sig;
|
||||
*a.message.aggregate.signature_mut() = agg_sig;
|
||||
},
|
||||
|_, err| assert!(matches!(err, AttnError::InvalidSignature)),
|
||||
)
|
||||
@@ -729,7 +739,7 @@ async fn aggregated_gossip_verification() {
|
||||
assert!(matches!(
|
||||
err,
|
||||
AttnError::AttestationSupersetKnown(hash)
|
||||
if hash == tester.valid_aggregate.message.aggregate.data.tree_hash_root()
|
||||
if hash == tester.valid_aggregate.message.aggregate.data().tree_hash_root()
|
||||
))
|
||||
},
|
||||
)
|
||||
@@ -741,7 +751,7 @@ async fn aggregated_gossip_verification() {
|
||||
*/
|
||||
.inspect_aggregate_err(
|
||||
"aggregate from aggregator that has already been seen",
|
||||
|_, a| a.message.aggregate.data.beacon_block_root = Hash256::repeat_byte(42),
|
||||
|_, a| a.message.aggregate.data_mut().beacon_block_root = Hash256::repeat_byte(42),
|
||||
|tester, err| {
|
||||
assert!(matches!(
|
||||
err,
|
||||
@@ -766,12 +776,12 @@ async fn unaggregated_gossip_verification() {
|
||||
.inspect_unaggregate_err(
|
||||
"attestation with invalid committee index",
|
||||
|tester, a, _| {
|
||||
a.data.index = tester
|
||||
a.data_mut().index = tester
|
||||
.harness
|
||||
.chain
|
||||
.head_snapshot()
|
||||
.beacon_state
|
||||
.get_committee_count_at_slot(a.data.slot)
|
||||
.get_committee_count_at_slot(a.data().slot)
|
||||
.unwrap()
|
||||
},
|
||||
|_, err| assert!(matches!(err, AttnError::NoCommitteeForSlotAndIndex { .. })),
|
||||
@@ -806,7 +816,7 @@ async fn unaggregated_gossip_verification() {
|
||||
*/
|
||||
.inspect_unaggregate_err(
|
||||
"attestation from future slot",
|
||||
|tester, a, _| a.data.slot = tester.slot() + 1,
|
||||
|tester, a, _| a.data_mut().slot = tester.slot() + 1,
|
||||
|tester, err| {
|
||||
assert!(matches!(
|
||||
err,
|
||||
@@ -822,8 +832,8 @@ async fn unaggregated_gossip_verification() {
|
||||
"attestation from past slot",
|
||||
|tester, a, _| {
|
||||
let too_early_slot = tester.earliest_valid_attestation_slot() - 1;
|
||||
a.data.slot = too_early_slot;
|
||||
a.data.target.epoch = too_early_slot.epoch(E::slots_per_epoch());
|
||||
a.data_mut().slot = too_early_slot;
|
||||
a.data_mut().target.epoch = too_early_slot.epoch(E::slots_per_epoch());
|
||||
},
|
||||
|tester, err| {
|
||||
let valid_early_slot = tester.earliest_valid_attestation_slot();
|
||||
@@ -847,7 +857,7 @@ async fn unaggregated_gossip_verification() {
|
||||
*/
|
||||
.inspect_unaggregate_err(
|
||||
"attestation with invalid target epoch",
|
||||
|_, a, _| a.data.target.epoch += 1,
|
||||
|_, a, _| a.data_mut().target.epoch += 1,
|
||||
|_, err| {
|
||||
assert!(matches!(
|
||||
err,
|
||||
@@ -863,15 +873,29 @@ async fn unaggregated_gossip_verification() {
|
||||
*/
|
||||
.inspect_unaggregate_err(
|
||||
"attestation without any aggregation bits set",
|
||||
|tester, a, _| {
|
||||
a.aggregation_bits
|
||||
.set(tester.attester_committee_index, false)
|
||||
.expect("should unset aggregation bit");
|
||||
assert_eq!(
|
||||
a.aggregation_bits.num_set_bits(),
|
||||
0,
|
||||
"test requires no set bits"
|
||||
);
|
||||
|tester, mut a, _| {
|
||||
match &mut a {
|
||||
Attestation::Base(ref mut att) => {
|
||||
att.aggregation_bits
|
||||
.set(tester.attester_committee_index, false)
|
||||
.expect("should unset aggregation bit");
|
||||
assert_eq!(
|
||||
att.aggregation_bits.num_set_bits(),
|
||||
0,
|
||||
"test requires no set bits"
|
||||
);
|
||||
}
|
||||
Attestation::Electra(ref mut att) => {
|
||||
att.aggregation_bits
|
||||
.set(tester.attester_committee_index, false)
|
||||
.expect("should unset aggregation bit");
|
||||
assert_eq!(
|
||||
att.aggregation_bits.num_set_bits(),
|
||||
0,
|
||||
"test requires no set bits"
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|_, err| {
|
||||
assert!(matches!(
|
||||
@@ -882,10 +906,19 @@ async fn unaggregated_gossip_verification() {
|
||||
)
|
||||
.inspect_unaggregate_err(
|
||||
"attestation with two aggregation bits set",
|
||||
|tester, a, _| {
|
||||
a.aggregation_bits
|
||||
.set(tester.attester_committee_index + 1, true)
|
||||
.expect("should set second aggregation bit");
|
||||
|tester, mut a, _| {
|
||||
match &mut a {
|
||||
Attestation::Base(ref mut att) => {
|
||||
att.aggregation_bits
|
||||
.set(tester.attester_committee_index + 1, true)
|
||||
.expect("should set second aggregation bit");
|
||||
}
|
||||
Attestation::Electra(ref mut att) => {
|
||||
att.aggregation_bits
|
||||
.set(tester.attester_committee_index + 1, true)
|
||||
.expect("should set second aggregation bit");
|
||||
}
|
||||
}
|
||||
},
|
||||
|_, err| {
|
||||
assert!(matches!(
|
||||
@@ -903,11 +936,22 @@ async fn unaggregated_gossip_verification() {
|
||||
*/
|
||||
.inspect_unaggregate_err(
|
||||
"attestation with invalid bitfield",
|
||||
|_, a, _| {
|
||||
let bits = a.aggregation_bits.iter().collect::<Vec<_>>();
|
||||
a.aggregation_bits = BitList::with_capacity(bits.len() + 1).unwrap();
|
||||
for (i, bit) in bits.into_iter().enumerate() {
|
||||
a.aggregation_bits.set(i, bit).unwrap();
|
||||
|_, mut a, _| {
|
||||
match &mut a {
|
||||
Attestation::Base(ref mut att) => {
|
||||
let bits = att.aggregation_bits.iter().collect::<Vec<_>>();
|
||||
att.aggregation_bits = BitList::with_capacity(bits.len() + 1).unwrap();
|
||||
for (i, bit) in bits.into_iter().enumerate() {
|
||||
att.aggregation_bits.set(i, bit).unwrap();
|
||||
}
|
||||
}
|
||||
Attestation::Electra(ref mut att) => {
|
||||
let bits = att.aggregation_bits.iter().collect::<Vec<_>>();
|
||||
att.aggregation_bits = BitList::with_capacity(bits.len() + 1).unwrap();
|
||||
for (i, bit) in bits.into_iter().enumerate() {
|
||||
att.aggregation_bits.set(i, bit).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|_, err| {
|
||||
@@ -927,7 +971,7 @@ async fn unaggregated_gossip_verification() {
|
||||
.inspect_unaggregate_err(
|
||||
"attestation with unknown head block",
|
||||
|_, a, _| {
|
||||
a.data.beacon_block_root = Hash256::repeat_byte(42);
|
||||
a.data_mut().beacon_block_root = Hash256::repeat_byte(42);
|
||||
},
|
||||
|_, err| {
|
||||
assert!(matches!(
|
||||
@@ -949,7 +993,7 @@ async fn unaggregated_gossip_verification() {
|
||||
.inspect_unaggregate_err(
|
||||
"attestation with invalid target root",
|
||||
|_, a, _| {
|
||||
a.data.target.root = Hash256::repeat_byte(42);
|
||||
a.data_mut().target.root = Hash256::repeat_byte(42);
|
||||
},
|
||||
|_, err| {
|
||||
assert!(matches!(
|
||||
@@ -968,7 +1012,7 @@ async fn unaggregated_gossip_verification() {
|
||||
|tester, a, _| {
|
||||
let mut agg_sig = AggregateSignature::infinity();
|
||||
agg_sig.add_assign(&tester.attester_sk.sign(Hash256::repeat_byte(42)));
|
||||
a.signature = agg_sig;
|
||||
*a.signature_mut() = agg_sig;
|
||||
},
|
||||
|_, err| {
|
||||
assert!(matches!(
|
||||
@@ -1055,7 +1099,7 @@ async fn attestation_that_skips_epochs() {
|
||||
.cloned()
|
||||
.expect("should have at least one attestation in committee");
|
||||
|
||||
let block_root = attestation.data.beacon_block_root;
|
||||
let block_root = attestation.data().beacon_block_root;
|
||||
let block_slot = harness
|
||||
.chain
|
||||
.store
|
||||
@@ -1066,7 +1110,7 @@ async fn attestation_that_skips_epochs() {
|
||||
.slot();
|
||||
|
||||
assert!(
|
||||
attestation.data.slot - block_slot > E::slots_per_epoch() * 2,
|
||||
attestation.data().slot - block_slot > E::slots_per_epoch() * 2,
|
||||
"the attestation must skip more than two epochs"
|
||||
);
|
||||
|
||||
@@ -1228,7 +1272,7 @@ async fn attestation_to_finalized_block() {
|
||||
.first()
|
||||
.cloned()
|
||||
.expect("should have at least one attestation in committee");
|
||||
assert_eq!(attestation.data.beacon_block_root, earlier_block_root);
|
||||
assert_eq!(attestation.data().beacon_block_root, earlier_block_root);
|
||||
|
||||
// Attestation should be rejected for attesting to a pre-finalization block.
|
||||
let res = harness
|
||||
@@ -1281,7 +1325,7 @@ async fn verify_aggregate_for_gossip_doppelganger_detection() {
|
||||
.verify_aggregated_attestation_for_gossip(&valid_aggregate)
|
||||
.expect("should verify aggregate attestation");
|
||||
|
||||
let epoch = valid_aggregate.message.aggregate.data.target.epoch;
|
||||
let epoch = valid_aggregate.message.aggregate.data().target.epoch;
|
||||
let index = valid_aggregate.message.aggregator_index as usize;
|
||||
assert!(harness.chain.validator_seen_at_epoch(index, epoch));
|
||||
|
||||
@@ -1338,7 +1382,7 @@ async fn verify_attestation_for_gossip_doppelganger_detection() {
|
||||
.verify_unaggregated_attestation_for_gossip(&valid_attestation, Some(subnet_id))
|
||||
.expect("should verify attestation");
|
||||
|
||||
let epoch = valid_attestation.data.target.epoch;
|
||||
let epoch = valid_attestation.data().target.epoch;
|
||||
assert!(harness.chain.validator_seen_at_epoch(index, epoch));
|
||||
|
||||
// Check the correct beacon cache is populated
|
||||
|
||||
@@ -664,7 +664,7 @@ async fn invalid_signature_attester_slashing() {
|
||||
for &block_index in BLOCK_INDICES {
|
||||
let harness = get_invalid_sigs_harness(&chain_segment).await;
|
||||
let mut snapshots = chain_segment.clone();
|
||||
let indexed_attestation = IndexedAttestation {
|
||||
let indexed_attestation = IndexedAttestationBase {
|
||||
attesting_indices: vec![0].into(),
|
||||
data: AttestationData {
|
||||
slot: Slot::new(0),
|
||||
@@ -681,7 +681,7 @@ async fn invalid_signature_attester_slashing() {
|
||||
},
|
||||
signature: junk_aggregate_signature(),
|
||||
};
|
||||
let attester_slashing = AttesterSlashing {
|
||||
let attester_slashing = AttesterSlashingBase {
|
||||
attestation_1: indexed_attestation.clone(),
|
||||
attestation_2: indexed_attestation,
|
||||
};
|
||||
@@ -690,11 +690,36 @@ async fn invalid_signature_attester_slashing() {
|
||||
.as_ref()
|
||||
.clone()
|
||||
.deconstruct();
|
||||
block
|
||||
.body_mut()
|
||||
.attester_slashings_mut()
|
||||
.push(attester_slashing)
|
||||
.expect("should update attester slashing");
|
||||
match &mut block.body_mut() {
|
||||
BeaconBlockBodyRefMut::Base(ref mut blk) => {
|
||||
blk.attester_slashings
|
||||
.push(attester_slashing)
|
||||
.expect("should update attester slashing");
|
||||
}
|
||||
BeaconBlockBodyRefMut::Altair(ref mut blk) => {
|
||||
blk.attester_slashings
|
||||
.push(attester_slashing)
|
||||
.expect("should update attester slashing");
|
||||
}
|
||||
BeaconBlockBodyRefMut::Merge(ref mut blk) => {
|
||||
blk.attester_slashings
|
||||
.push(attester_slashing)
|
||||
.expect("should update attester slashing");
|
||||
}
|
||||
BeaconBlockBodyRefMut::Capella(ref mut blk) => {
|
||||
blk.attester_slashings
|
||||
.push(attester_slashing)
|
||||
.expect("should update attester slashing");
|
||||
}
|
||||
BeaconBlockBodyRefMut::Deneb(ref mut blk) => {
|
||||
blk.attester_slashings
|
||||
.push(attester_slashing)
|
||||
.expect("should update attester slashing");
|
||||
}
|
||||
BeaconBlockBodyRefMut::Electra(_) => {
|
||||
panic!("electra test not implemented!");
|
||||
}
|
||||
}
|
||||
snapshots[block_index].beacon_block =
|
||||
Arc::new(SignedBeaconBlock::from_block(block, signature));
|
||||
update_parent_roots(&mut snapshots, &mut chain_segment_blobs);
|
||||
@@ -724,8 +749,34 @@ async fn invalid_signature_attestation() {
|
||||
.as_ref()
|
||||
.clone()
|
||||
.deconstruct();
|
||||
if let Some(attestation) = block.body_mut().attestations_mut().get_mut(0) {
|
||||
attestation.signature = junk_aggregate_signature();
|
||||
match &mut block.body_mut() {
|
||||
BeaconBlockBodyRefMut::Base(ref mut blk) => blk
|
||||
.attestations
|
||||
.get_mut(0)
|
||||
.map(|att| att.signature = junk_aggregate_signature()),
|
||||
BeaconBlockBodyRefMut::Altair(ref mut blk) => blk
|
||||
.attestations
|
||||
.get_mut(0)
|
||||
.map(|att| att.signature = junk_aggregate_signature()),
|
||||
BeaconBlockBodyRefMut::Merge(ref mut blk) => blk
|
||||
.attestations
|
||||
.get_mut(0)
|
||||
.map(|att| att.signature = junk_aggregate_signature()),
|
||||
BeaconBlockBodyRefMut::Capella(ref mut blk) => blk
|
||||
.attestations
|
||||
.get_mut(0)
|
||||
.map(|att| att.signature = junk_aggregate_signature()),
|
||||
BeaconBlockBodyRefMut::Deneb(ref mut blk) => blk
|
||||
.attestations
|
||||
.get_mut(0)
|
||||
.map(|att| att.signature = junk_aggregate_signature()),
|
||||
BeaconBlockBodyRefMut::Electra(ref mut blk) => blk
|
||||
.attestations
|
||||
.get_mut(0)
|
||||
.map(|att| att.signature = junk_aggregate_signature()),
|
||||
};
|
||||
|
||||
if block.body().attestations_len() > 0 {
|
||||
snapshots[block_index].beacon_block =
|
||||
Arc::new(SignedBeaconBlock::from_block(block, signature));
|
||||
update_parent_roots(&mut snapshots, &mut chain_segment_blobs);
|
||||
@@ -1187,9 +1238,13 @@ async fn verify_block_for_gossip_doppelganger_detection() {
|
||||
|
||||
let state = harness.get_current_state();
|
||||
let ((block, _), _) = harness.make_block(state.clone(), Slot::new(1)).await;
|
||||
|
||||
let attestations = block
|
||||
.message()
|
||||
.body()
|
||||
.attestations()
|
||||
.map(|att| att.clone_as_attestation())
|
||||
.collect::<Vec<_>>();
|
||||
let verified_block = harness.chain.verify_block_for_gossip(block).await.unwrap();
|
||||
let attestations = verified_block.block.message().body().attestations().clone();
|
||||
harness
|
||||
.chain
|
||||
.process_block(
|
||||
@@ -1202,37 +1257,69 @@ async fn verify_block_for_gossip_doppelganger_detection() {
|
||||
.unwrap();
|
||||
|
||||
for att in attestations.iter() {
|
||||
let epoch = att.data.target.epoch;
|
||||
let epoch = att.data().target.epoch;
|
||||
let committee = state
|
||||
.get_beacon_committee(att.data.slot, att.data.index)
|
||||
.get_beacon_committee(att.data().slot, att.data().index)
|
||||
.unwrap();
|
||||
let indexed_attestation = get_indexed_attestation(committee.committee, att).unwrap();
|
||||
let indexed_attestation =
|
||||
get_indexed_attestation(committee.committee, att.to_ref()).unwrap();
|
||||
|
||||
for &index in &indexed_attestation.attesting_indices {
|
||||
let index = index as usize;
|
||||
match indexed_attestation {
|
||||
IndexedAttestation::Base(indexed_attestation) => {
|
||||
for &index in &indexed_attestation.attesting_indices {
|
||||
let index = index as usize;
|
||||
|
||||
assert!(harness.chain.validator_seen_at_epoch(index, epoch));
|
||||
assert!(harness.chain.validator_seen_at_epoch(index, epoch));
|
||||
|
||||
// Check the correct beacon cache is populated
|
||||
assert!(harness
|
||||
.chain
|
||||
.observed_block_attesters
|
||||
.read()
|
||||
.validator_has_been_observed(epoch, index)
|
||||
.expect("should check if block attester was observed"));
|
||||
assert!(!harness
|
||||
.chain
|
||||
.observed_gossip_attesters
|
||||
.read()
|
||||
.validator_has_been_observed(epoch, index)
|
||||
.expect("should check if gossip attester was observed"));
|
||||
assert!(!harness
|
||||
.chain
|
||||
.observed_aggregators
|
||||
.read()
|
||||
.validator_has_been_observed(epoch, index)
|
||||
.expect("should check if gossip aggregator was observed"));
|
||||
}
|
||||
// Check the correct beacon cache is populated
|
||||
assert!(harness
|
||||
.chain
|
||||
.observed_block_attesters
|
||||
.read()
|
||||
.validator_has_been_observed(epoch, index)
|
||||
.expect("should check if block attester was observed"));
|
||||
assert!(!harness
|
||||
.chain
|
||||
.observed_gossip_attesters
|
||||
.read()
|
||||
.validator_has_been_observed(epoch, index)
|
||||
.expect("should check if gossip attester was observed"));
|
||||
assert!(!harness
|
||||
.chain
|
||||
.observed_aggregators
|
||||
.read()
|
||||
.validator_has_been_observed(epoch, index)
|
||||
.expect("should check if gossip aggregator was observed"));
|
||||
}
|
||||
}
|
||||
IndexedAttestation::Electra(indexed_attestation) => {
|
||||
for &index in &indexed_attestation.attesting_indices {
|
||||
let index = index as usize;
|
||||
|
||||
assert!(harness.chain.validator_seen_at_epoch(index, epoch));
|
||||
|
||||
// Check the correct beacon cache is populated
|
||||
assert!(harness
|
||||
.chain
|
||||
.observed_block_attesters
|
||||
.read()
|
||||
.validator_has_been_observed(epoch, index)
|
||||
.expect("should check if block attester was observed"));
|
||||
assert!(!harness
|
||||
.chain
|
||||
.observed_gossip_attesters
|
||||
.read()
|
||||
.validator_has_been_observed(epoch, index)
|
||||
.expect("should check if gossip attester was observed"));
|
||||
assert!(!harness
|
||||
.chain
|
||||
.observed_aggregators
|
||||
.read()
|
||||
.validator_has_been_observed(epoch, index)
|
||||
.expect("should check if gossip aggregator was observed"));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1191,9 +1191,17 @@ async fn attesting_to_optimistic_head() {
|
||||
.produce_unaggregated_attestation(Slot::new(0), 0)
|
||||
.unwrap();
|
||||
|
||||
attestation.aggregation_bits.set(0, true).unwrap();
|
||||
attestation.data.slot = slot;
|
||||
attestation.data.beacon_block_root = root;
|
||||
match &mut attestation {
|
||||
Attestation::Base(ref mut att) => {
|
||||
att.aggregation_bits.set(0, true).unwrap();
|
||||
}
|
||||
Attestation::Electra(ref mut att) => {
|
||||
att.aggregation_bits.set(0, true).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
attestation.data_mut().slot = slot;
|
||||
attestation.data_mut().beacon_block_root = root;
|
||||
|
||||
rig.harness
|
||||
.chain
|
||||
@@ -1214,15 +1222,15 @@ async fn attesting_to_optimistic_head() {
|
||||
let get_aggregated = || {
|
||||
rig.harness
|
||||
.chain
|
||||
.get_aggregated_attestation(&attestation.data)
|
||||
.get_aggregated_attestation(attestation.data())
|
||||
};
|
||||
|
||||
let get_aggregated_by_slot_and_root = || {
|
||||
rig.harness
|
||||
.chain
|
||||
.get_aggregated_attestation_by_slot_and_root(
|
||||
attestation.data.slot,
|
||||
&attestation.data.tree_hash_root(),
|
||||
attestation.data().slot,
|
||||
&attestation.data().tree_hash_root(),
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
@@ -606,7 +606,7 @@ async fn epoch_boundary_state_attestation_processing() {
|
||||
|
||||
for (attestation, subnet_id) in late_attestations.into_iter().flatten() {
|
||||
// load_epoch_boundary_state is idempotent!
|
||||
let block_root = attestation.data.beacon_block_root;
|
||||
let block_root = attestation.data().beacon_block_root;
|
||||
let block = store
|
||||
.get_blinded_block(&block_root)
|
||||
.unwrap()
|
||||
@@ -629,7 +629,7 @@ async fn epoch_boundary_state_attestation_processing() {
|
||||
.verify_unaggregated_attestation_for_gossip(&attestation, Some(subnet_id));
|
||||
|
||||
let current_slot = harness.chain.slot().expect("should get slot");
|
||||
let expected_attestation_slot = attestation.data.slot;
|
||||
let expected_attestation_slot = attestation.data().slot;
|
||||
// Extra -1 to handle gossip clock disparity.
|
||||
let expected_earliest_permissible_slot = current_slot - E::slots_per_epoch() - 1;
|
||||
|
||||
@@ -1028,8 +1028,7 @@ async fn multiple_attestations_per_block() {
|
||||
.as_ref()
|
||||
.message()
|
||||
.body()
|
||||
.attestations()
|
||||
.len() as u64,
|
||||
.attestations_len() as u64,
|
||||
if slot <= 1 { 0 } else { committees_per_slot }
|
||||
);
|
||||
}
|
||||
|
||||
@@ -573,7 +573,7 @@ async fn attestations_with_increasing_slots() {
|
||||
.verify_unaggregated_attestation_for_gossip(&attestation, Some(subnet_id));
|
||||
|
||||
let current_slot = harness.chain.slot().expect("should get slot");
|
||||
let expected_attestation_slot = attestation.data.slot;
|
||||
let expected_attestation_slot = attestation.data().slot;
|
||||
let expected_earliest_permissible_slot =
|
||||
current_slot - MinimalEthSpec::slots_per_epoch() - 1;
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ use std::collections::{HashMap, HashSet};
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
use types::{
|
||||
Attestation, BeaconCommittee, BeaconState, BeaconStateError, BlindedPayload, ChainSpec, Epoch,
|
||||
EthSpec, Hash256, OwnedBeaconCommittee, RelativeEpoch, SignedBeaconBlock, Slot,
|
||||
AttestationRef, BeaconCommittee, BeaconState, BeaconStateError, BlindedPayload, ChainSpec,
|
||||
Epoch, EthSpec, Hash256, OwnedBeaconCommittee, RelativeEpoch, SignedBeaconBlock, Slot,
|
||||
};
|
||||
use warp_utils::reject::{beacon_chain_error, custom_bad_request, custom_server_error};
|
||||
|
||||
@@ -111,9 +111,9 @@ impl<E: EthSpec> PackingEfficiencyHandler<E> {
|
||||
let attestations = block_body.attestations();
|
||||
|
||||
let mut attestations_in_block = HashMap::new();
|
||||
for attestation in attestations.iter() {
|
||||
for attestation in attestations {
|
||||
match attestation {
|
||||
Attestation::Base(attn) => {
|
||||
AttestationRef::Base(attn) => {
|
||||
for (position, voted) in attn.aggregation_bits.iter().enumerate() {
|
||||
if voted {
|
||||
let unique_attestation = UniqueAttestation {
|
||||
@@ -133,7 +133,7 @@ impl<E: EthSpec> PackingEfficiencyHandler<E> {
|
||||
}
|
||||
}
|
||||
// TODO(electra) implement electra variant
|
||||
Attestation::Electra(_) => {
|
||||
AttestationRef::Electra(_) => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1635,7 +1635,12 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
let (block, execution_optimistic, finalized) =
|
||||
block_id.blinded_block(&chain)?;
|
||||
Ok(api_types::GenericResponse::from(
|
||||
block.message().body().attestations().clone(),
|
||||
block
|
||||
.message()
|
||||
.body()
|
||||
.attestations()
|
||||
.map(|att| att.clone_as_attestation())
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.add_execution_optimistic_finalized(execution_optimistic, finalized))
|
||||
})
|
||||
@@ -1833,7 +1838,7 @@ pub fn serve<T: BeaconChainTypes>(
|
||||
chain
|
||||
.validator_monitor
|
||||
.read()
|
||||
.register_api_attester_slashing(&slashing);
|
||||
.register_api_attester_slashing(slashing.to_ref());
|
||||
|
||||
if let ObservationOutcome::New(slashing) = outcome {
|
||||
publish_pubsub_message(
|
||||
|
||||
@@ -1633,7 +1633,13 @@ impl ApiTester {
|
||||
|
||||
let expected = block_id.full_block(&self.chain).await.ok().map(
|
||||
|(block, _execution_optimistic, _finalized)| {
|
||||
block.message().body().attestations().clone().into()
|
||||
block
|
||||
.message()
|
||||
.body()
|
||||
.attestations()
|
||||
.map(|att| att.clone_as_attestation())
|
||||
.collect::<Vec<_>>()
|
||||
.into()
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1793,7 +1799,14 @@ impl ApiTester {
|
||||
|
||||
pub async fn test_post_beacon_pool_attester_slashings_invalid(mut self) -> Self {
|
||||
let mut slashing = self.attester_slashing.clone();
|
||||
slashing.attestation_1.data_mut().slot += 1;
|
||||
match &mut slashing {
|
||||
AttesterSlashing::Base(ref mut slashing) => {
|
||||
slashing.attestation_1.data.slot += 1;
|
||||
}
|
||||
AttesterSlashing::Electra(ref mut slashing) => {
|
||||
slashing.attestation_1.data.slot += 1;
|
||||
}
|
||||
}
|
||||
|
||||
self.client
|
||||
.post_beacon_pool_attester_slashings(&slashing)
|
||||
@@ -3183,8 +3196,10 @@ impl ApiTester {
|
||||
.head_beacon_block()
|
||||
.message()
|
||||
.body()
|
||||
.attestations()[0]
|
||||
.clone();
|
||||
.attestations()
|
||||
.next()
|
||||
.unwrap()
|
||||
.clone_as_attestation();
|
||||
|
||||
let result = self
|
||||
.client
|
||||
|
||||
@@ -7,12 +7,12 @@ use ssz::{Decode, Encode};
|
||||
use std::io::{Error, ErrorKind};
|
||||
use std::sync::Arc;
|
||||
use types::{
|
||||
Attestation, AttesterSlashing, BlobSidecar, EthSpec, ForkContext, ForkName,
|
||||
LightClientFinalityUpdate, LightClientOptimisticUpdate, ProposerSlashing,
|
||||
SignedAggregateAndProof, SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase,
|
||||
SignedBeaconBlockCapella, SignedBeaconBlockDeneb, SignedBeaconBlockElectra,
|
||||
SignedBeaconBlockMerge, SignedBlsToExecutionChange, SignedContributionAndProof,
|
||||
SignedVoluntaryExit, SubnetId, SyncCommitteeMessage, SyncSubnetId,
|
||||
Attestation, AttesterSlashing, AttesterSlashingBase, AttesterSlashingElectra, BlobSidecar,
|
||||
EthSpec, ForkContext, ForkName, LightClientFinalityUpdate, LightClientOptimisticUpdate,
|
||||
ProposerSlashing, SignedAggregateAndProof, SignedBeaconBlock, SignedBeaconBlockAltair,
|
||||
SignedBeaconBlockBase, SignedBeaconBlockCapella, SignedBeaconBlockDeneb,
|
||||
SignedBeaconBlockElectra, SignedBeaconBlockMerge, SignedBlsToExecutionChange,
|
||||
SignedContributionAndProof, SignedVoluntaryExit, SubnetId, SyncCommitteeMessage, SyncSubnetId,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
@@ -239,8 +239,28 @@ impl<E: EthSpec> PubsubMessage<E> {
|
||||
Ok(PubsubMessage::ProposerSlashing(Box::new(proposer_slashing)))
|
||||
}
|
||||
GossipKind::AttesterSlashing => {
|
||||
let attester_slashing = AttesterSlashing::from_ssz_bytes(data)
|
||||
.map_err(|e| format!("{:?}", e))?;
|
||||
// TODO(electra): could an older attester slashing still be floating around during the fork transition?
|
||||
let attester_slashing =
|
||||
match fork_context.from_context_bytes(gossip_topic.fork_digest) {
|
||||
Some(ForkName::Base)
|
||||
| Some(ForkName::Altair)
|
||||
| Some(ForkName::Merge)
|
||||
| Some(ForkName::Capella)
|
||||
| Some(ForkName::Deneb) => AttesterSlashing::Base(
|
||||
AttesterSlashingBase::from_ssz_bytes(data)
|
||||
.map_err(|e| format!("{:?}", e))?,
|
||||
),
|
||||
Some(ForkName::Electra) => AttesterSlashing::Electra(
|
||||
AttesterSlashingElectra::from_ssz_bytes(data)
|
||||
.map_err(|e| format!("{:?}", e))?,
|
||||
),
|
||||
None => {
|
||||
return Err(format!(
|
||||
"Unknown gossipsub fork digest: {:?}",
|
||||
gossip_topic.fork_digest
|
||||
))
|
||||
}
|
||||
};
|
||||
Ok(PubsubMessage::AttesterSlashing(Box::new(attester_slashing)))
|
||||
}
|
||||
GossipKind::SignedContributionAndProof => {
|
||||
|
||||
@@ -1428,7 +1428,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
|
||||
self.chain
|
||||
.validator_monitor
|
||||
.read()
|
||||
.register_gossip_attester_slashing(slashing.as_inner());
|
||||
.register_gossip_attester_slashing(slashing.as_inner().to_ref());
|
||||
|
||||
self.chain.import_attester_slashing(slashing);
|
||||
debug!(self.log, "Successfully imported attester slashing");
|
||||
|
||||
@@ -2,8 +2,9 @@ use crate::AttestationStats;
|
||||
use itertools::Itertools;
|
||||
use std::collections::HashMap;
|
||||
use types::{
|
||||
attestation::{AttestationBase, AttestationElectra}, superstruct, AggregateSignature, Attestation, AttestationData,
|
||||
BeaconState, BitList, BitVector, Checkpoint, Epoch, EthSpec, Hash256, Slot,
|
||||
attestation::{AttestationBase, AttestationElectra},
|
||||
superstruct, AggregateSignature, Attestation, AttestationData, BeaconState, BitList, BitVector,
|
||||
Checkpoint, Epoch, EthSpec, Hash256, Slot,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
@@ -121,12 +122,14 @@ impl<'a, E: EthSpec> AttestationRef<'a, E> {
|
||||
data: self.attestation_data(),
|
||||
signature: indexed_att.signature.clone(),
|
||||
}),
|
||||
CompactIndexedAttestation::Electra(indexed_att) => Attestation::Electra(AttestationElectra {
|
||||
aggregation_bits: indexed_att.aggregation_bits.clone(),
|
||||
data: self.attestation_data(),
|
||||
signature: indexed_att.signature.clone(),
|
||||
committee_bits: indexed_att.committee_bits.clone(),
|
||||
}),
|
||||
CompactIndexedAttestation::Electra(indexed_att) => {
|
||||
Attestation::Electra(AttestationElectra {
|
||||
aggregation_bits: indexed_att.aggregation_bits.clone(),
|
||||
data: self.attestation_data(),
|
||||
signature: indexed_att.signature.clone(),
|
||||
committee_bits: indexed_att.committee_bits.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
use crate::max_cover::MaxCover;
|
||||
use state_processing::per_block_processing::get_slashable_indices_modular;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use types::{AttesterSlashing, BeaconState, EthSpec};
|
||||
use types::{AttesterSlashing, AttesterSlashingRef, BeaconState, EthSpec};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AttesterSlashingMaxCover<'a, E: EthSpec> {
|
||||
slashing: &'a AttesterSlashing<E>,
|
||||
slashing: AttesterSlashingRef<'a, E>,
|
||||
effective_balances: HashMap<u64, u64>,
|
||||
}
|
||||
|
||||
impl<'a, E: EthSpec> AttesterSlashingMaxCover<'a, E> {
|
||||
pub fn new(
|
||||
slashing: &'a AttesterSlashing<E>,
|
||||
slashing: AttesterSlashingRef<'a, E>,
|
||||
proposer_slashing_indices: &HashSet<u64>,
|
||||
state: &BeaconState<E>,
|
||||
) -> Option<Self> {
|
||||
@@ -39,16 +39,16 @@ impl<'a, E: EthSpec> AttesterSlashingMaxCover<'a, E> {
|
||||
impl<'a, E: EthSpec> MaxCover for AttesterSlashingMaxCover<'a, E> {
|
||||
/// The result type, of which we would eventually like a collection of maximal quality.
|
||||
type Object = AttesterSlashing<E>;
|
||||
type Intermediate = AttesterSlashing<E>;
|
||||
type Intermediate = AttesterSlashingRef<'a, E>;
|
||||
/// The type used to represent sets.
|
||||
type Set = HashMap<u64, u64>;
|
||||
|
||||
fn intermediate(&self) -> &AttesterSlashing<E> {
|
||||
self.slashing
|
||||
fn intermediate(&self) -> &AttesterSlashingRef<'a, E> {
|
||||
&self.slashing
|
||||
}
|
||||
|
||||
fn convert_to_object(slashing: &AttesterSlashing<E>) -> AttesterSlashing<E> {
|
||||
slashing.clone()
|
||||
fn convert_to_object(slashing: &AttesterSlashingRef<'a, E>) -> AttesterSlashing<E> {
|
||||
slashing.clone_as_attester_slashing()
|
||||
}
|
||||
|
||||
/// Get the set of elements covered.
|
||||
@@ -58,7 +58,7 @@ impl<'a, E: EthSpec> MaxCover for AttesterSlashingMaxCover<'a, E> {
|
||||
/// Update the set of items covered, for the inclusion of some object in the solution.
|
||||
fn update_covering_set(
|
||||
&mut self,
|
||||
_best_slashing: &AttesterSlashing<E>,
|
||||
_best_slashing: &AttesterSlashingRef<'a, E>,
|
||||
covered_validator_indices: &HashMap<u64, u64>,
|
||||
) {
|
||||
self.effective_balances
|
||||
|
||||
@@ -428,7 +428,7 @@ impl<E: EthSpec> OperationPool<E> {
|
||||
|
||||
let relevant_attester_slashings = reader.iter().flat_map(|slashing| {
|
||||
if slashing.signature_is_still_valid(&state.fork()) {
|
||||
AttesterSlashingMaxCover::new(slashing.as_inner(), to_be_slashed, state)
|
||||
AttesterSlashingMaxCover::new(slashing.as_inner().to_ref(), to_be_slashed, state)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -442,7 +442,7 @@ impl<E: EthSpec> OperationPool<E> {
|
||||
.into_iter()
|
||||
.map(|cover| {
|
||||
to_be_slashed.extend(cover.covering_set().keys());
|
||||
cover.intermediate().clone()
|
||||
AttesterSlashingMaxCover::convert_to_object(cover.intermediate())
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@@ -463,16 +463,19 @@ impl<E: EthSpec> OperationPool<E> {
|
||||
// Check that the attestation's signature is still valid wrt the fork version.
|
||||
let signature_ok = slashing.signature_is_still_valid(&head_state.fork());
|
||||
// Slashings that don't slash any validators can also be dropped.
|
||||
let slashing_ok =
|
||||
get_slashable_indices_modular(head_state, slashing.as_inner(), |_, validator| {
|
||||
let slashing_ok = get_slashable_indices_modular(
|
||||
head_state,
|
||||
slashing.as_inner().to_ref(),
|
||||
|_, validator| {
|
||||
// Declare that a validator is still slashable if they have not exited prior
|
||||
// to the finalized epoch.
|
||||
//
|
||||
// We cannot check the `slashed` field since the `head` is not finalized and
|
||||
// a fork could un-slash someone.
|
||||
validator.exit_epoch > head_state.finalized_checkpoint().epoch
|
||||
})
|
||||
.map_or(false, |indices| !indices.is_empty());
|
||||
},
|
||||
)
|
||||
.map_or(false, |indices| !indices.is_empty());
|
||||
|
||||
signature_ok && slashing_ok
|
||||
});
|
||||
@@ -907,8 +910,8 @@ mod release_tests {
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let att1_indices = get_attesting_indices_from_state(&state, &att1).unwrap();
|
||||
let att2_indices = get_attesting_indices_from_state(&state, &att2).unwrap();
|
||||
let att1_indices = get_attesting_indices_from_state(&state, att1.to_ref()).unwrap();
|
||||
let att2_indices = get_attesting_indices_from_state(&state, att2.to_ref()).unwrap();
|
||||
let att1_split = SplitAttestation::new(att1.clone(), att1_indices);
|
||||
let att2_split = SplitAttestation::new(att2.clone(), att2_indices);
|
||||
|
||||
@@ -981,7 +984,8 @@ mod release_tests {
|
||||
|
||||
for (atts, _) in attestations {
|
||||
for (att, _) in atts {
|
||||
let attesting_indices = get_attesting_indices_from_state(&state, &att).unwrap();
|
||||
let attesting_indices =
|
||||
get_attesting_indices_from_state(&state, att.to_ref()).unwrap();
|
||||
op_pool.insert_attestation(att, attesting_indices).unwrap();
|
||||
}
|
||||
}
|
||||
@@ -1051,7 +1055,7 @@ mod release_tests {
|
||||
|
||||
for (_, aggregate) in attestations {
|
||||
let att = aggregate.unwrap().message.aggregate;
|
||||
let attesting_indices = get_attesting_indices_from_state(&state, &att).unwrap();
|
||||
let attesting_indices = get_attesting_indices_from_state(&state, att.to_ref()).unwrap();
|
||||
op_pool
|
||||
.insert_attestation(att.clone(), attesting_indices.clone())
|
||||
.unwrap();
|
||||
@@ -1139,7 +1143,8 @@ mod release_tests {
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for att in aggs1.into_iter().chain(aggs2.into_iter()) {
|
||||
let attesting_indices = get_attesting_indices_from_state(&state, &att).unwrap();
|
||||
let attesting_indices =
|
||||
get_attesting_indices_from_state(&state, att.to_ref()).unwrap();
|
||||
op_pool.insert_attestation(att, attesting_indices).unwrap();
|
||||
}
|
||||
}
|
||||
@@ -1211,7 +1216,8 @@ mod release_tests {
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for att in aggs {
|
||||
let attesting_indices = get_attesting_indices_from_state(&state, &att).unwrap();
|
||||
let attesting_indices =
|
||||
get_attesting_indices_from_state(&state, att.to_ref()).unwrap();
|
||||
op_pool.insert_attestation(att, attesting_indices).unwrap();
|
||||
}
|
||||
};
|
||||
@@ -1306,7 +1312,8 @@ mod release_tests {
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for att in aggs {
|
||||
let attesting_indices = get_attesting_indices_from_state(&state, &att).unwrap();
|
||||
let attesting_indices =
|
||||
get_attesting_indices_from_state(&state, att.to_ref()).unwrap();
|
||||
op_pool.insert_attestation(att, attesting_indices).unwrap();
|
||||
}
|
||||
};
|
||||
@@ -1349,7 +1356,7 @@ mod release_tests {
|
||||
reward_cache.update(&state).unwrap();
|
||||
|
||||
for att in best_attestations {
|
||||
let attesting_indices = get_attesting_indices_from_state(&state, &att).unwrap();
|
||||
let attesting_indices = get_attesting_indices_from_state(&state, att.to_ref()).unwrap();
|
||||
let split_attestation = SplitAttestation::new(att, attesting_indices);
|
||||
let mut fresh_validators_rewards = AttMaxCover::new(
|
||||
split_attestation.as_ref(),
|
||||
|
||||
@@ -39,9 +39,7 @@ pub struct PersistedOperationPool<E: EthSpec> {
|
||||
pub attestations: Vec<(Attestation<E>, Vec<u64>)>,
|
||||
/// Mapping from sync contribution ID to sync contributions and aggregate.
|
||||
pub sync_contributions: PersistedSyncContributions<E>,
|
||||
/// [DEPRECATED] Attester slashings.
|
||||
#[superstruct(only(V5))]
|
||||
pub attester_slashings_v5: Vec<(AttesterSlashing<E>, ForkVersion)>,
|
||||
/// TODO(electra): we've made a DB change here!!!
|
||||
/// Attester slashings.
|
||||
#[superstruct(only(V12, V14, V15))]
|
||||
pub attester_slashings: Vec<SigVerifiedOp<AttesterSlashing<E>, E>>,
|
||||
|
||||
Reference in New Issue
Block a user