mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-07 16:55:46 +00:00
Merge pull request #5816 from realbigsean/electra-attestation-slashing-handling
Electra slashing handling
This commit is contained in:
@@ -115,6 +115,22 @@ impl<E: EthSpec> IndexedAttestation<E> {
|
|||||||
IndexedAttestation::Electra(att) => att.attesting_indices.first(),
|
IndexedAttestation::Electra(att) => att.attesting_indices.first(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_electra(self) -> Result<IndexedAttestationElectra<E>, ssz_types::Error> {
|
||||||
|
Ok(match self {
|
||||||
|
Self::Base(att) => {
|
||||||
|
let extended_attesting_indices: VariableList<u64, E::MaxValidatorsPerSlot> =
|
||||||
|
VariableList::new(att.attesting_indices.to_vec())?;
|
||||||
|
|
||||||
|
IndexedAttestationElectra {
|
||||||
|
attesting_indices: extended_attesting_indices,
|
||||||
|
data: att.data,
|
||||||
|
signature: att.signature,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::Electra(att) => att,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, E: EthSpec> IndexedAttestationRef<'a, E> {
|
impl<'a, E: EthSpec> IndexedAttestationRef<'a, E> {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use flate2::bufread::{ZlibDecoder, ZlibEncoder};
|
use flate2::bufread::{ZlibDecoder, ZlibEncoder};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use slog::Logger;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::collections::{btree_map::Entry, BTreeMap, HashSet};
|
use std::collections::{btree_map::Entry, BTreeMap, HashSet};
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
@@ -485,6 +486,7 @@ pub fn update<E: EthSpec>(
|
|||||||
batch: Vec<Arc<IndexedAttesterRecord<E>>>,
|
batch: Vec<Arc<IndexedAttesterRecord<E>>>,
|
||||||
current_epoch: Epoch,
|
current_epoch: Epoch,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
|
log: &Logger,
|
||||||
) -> Result<HashSet<AttesterSlashing<E>>, Error> {
|
) -> Result<HashSet<AttesterSlashing<E>>, Error> {
|
||||||
// Split the batch up into horizontal segments.
|
// Split the batch up into horizontal segments.
|
||||||
// Map chunk indexes in the range `0..self.config.chunk_size` to attestations
|
// Map chunk indexes in the range `0..self.config.chunk_size` to attestations
|
||||||
@@ -504,6 +506,7 @@ pub fn update<E: EthSpec>(
|
|||||||
&chunk_attestations,
|
&chunk_attestations,
|
||||||
current_epoch,
|
current_epoch,
|
||||||
config,
|
config,
|
||||||
|
log,
|
||||||
)?;
|
)?;
|
||||||
slashings.extend(update_array::<_, MaxTargetChunk>(
|
slashings.extend(update_array::<_, MaxTargetChunk>(
|
||||||
db,
|
db,
|
||||||
@@ -512,6 +515,7 @@ pub fn update<E: EthSpec>(
|
|||||||
&chunk_attestations,
|
&chunk_attestations,
|
||||||
current_epoch,
|
current_epoch,
|
||||||
config,
|
config,
|
||||||
|
log,
|
||||||
)?);
|
)?);
|
||||||
|
|
||||||
// Update all current epochs.
|
// Update all current epochs.
|
||||||
@@ -570,6 +574,7 @@ pub fn update_array<E: EthSpec, T: TargetArrayChunk>(
|
|||||||
chunk_attestations: &BTreeMap<usize, Vec<Arc<IndexedAttesterRecord<E>>>>,
|
chunk_attestations: &BTreeMap<usize, Vec<Arc<IndexedAttesterRecord<E>>>>,
|
||||||
current_epoch: Epoch,
|
current_epoch: Epoch,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
|
log: &Logger,
|
||||||
) -> Result<HashSet<AttesterSlashing<E>>, Error> {
|
) -> Result<HashSet<AttesterSlashing<E>>, Error> {
|
||||||
let mut slashings = HashSet::new();
|
let mut slashings = HashSet::new();
|
||||||
// Map from chunk index to updated chunk at that index.
|
// Map from chunk index to updated chunk at that index.
|
||||||
@@ -603,9 +608,20 @@ pub fn update_array<E: EthSpec, T: TargetArrayChunk>(
|
|||||||
current_epoch,
|
current_epoch,
|
||||||
config,
|
config,
|
||||||
)?;
|
)?;
|
||||||
if let Some(slashing) = slashing_status.into_slashing(&attestation.indexed) {
|
match slashing_status.into_slashing(&attestation.indexed) {
|
||||||
|
Ok(Some(slashing)) => {
|
||||||
slashings.insert(slashing);
|
slashings.insert(slashing);
|
||||||
}
|
}
|
||||||
|
Err(e) => {
|
||||||
|
slog::error!(
|
||||||
|
log,
|
||||||
|
"Invalid slashing conversion";
|
||||||
|
"validator_index" => validator_index,
|
||||||
|
"error" => e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(None) => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,55 +53,56 @@ impl<E: EthSpec> AttesterSlashingStatus<E> {
|
|||||||
pub fn into_slashing(
|
pub fn into_slashing(
|
||||||
self,
|
self,
|
||||||
new_attestation: &IndexedAttestation<E>,
|
new_attestation: &IndexedAttestation<E>,
|
||||||
) -> Option<AttesterSlashing<E>> {
|
) -> Result<Option<AttesterSlashing<E>>, String> {
|
||||||
use AttesterSlashingStatus::*;
|
use AttesterSlashingStatus::*;
|
||||||
|
|
||||||
// The surrounding attestation must be in `attestation_1` to be valid.
|
// The surrounding attestation must be in `attestation_1` to be valid.
|
||||||
match self {
|
Ok(match self {
|
||||||
NotSlashable => None,
|
NotSlashable => None,
|
||||||
AlreadyDoubleVoted => None,
|
AlreadyDoubleVoted => None,
|
||||||
DoubleVote(existing) | SurroundedByExisting(existing) => {
|
DoubleVote(existing) | SurroundedByExisting(existing) => match *existing {
|
||||||
match (*existing, new_attestation) {
|
IndexedAttestation::Base(existing_att) => {
|
||||||
// TODO(electra) - determine when we would convert a Base attestation to Electra / how to handle mismatched attestations here
|
|
||||||
(IndexedAttestation::Base(existing_att), IndexedAttestation::Base(new_att)) => {
|
|
||||||
Some(AttesterSlashing::Base(AttesterSlashingBase {
|
Some(AttesterSlashing::Base(AttesterSlashingBase {
|
||||||
attestation_1: existing_att,
|
attestation_1: existing_att,
|
||||||
attestation_2: new_att.clone(),
|
attestation_2: new_attestation
|
||||||
|
.as_base()
|
||||||
|
.map_err(|e| format!("{e:?}"))?
|
||||||
|
.clone(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
(
|
IndexedAttestation::Electra(existing_att) => {
|
||||||
IndexedAttestation::Electra(existing_att),
|
Some(AttesterSlashing::Electra(AttesterSlashingElectra {
|
||||||
IndexedAttestation::Electra(new_att),
|
|
||||||
) => Some(AttesterSlashing::Electra(AttesterSlashingElectra {
|
|
||||||
attestation_1: existing_att,
|
attestation_1: existing_att,
|
||||||
attestation_2: new_att.clone(),
|
// A double vote should never convert, a surround vote where the surrounding
|
||||||
})),
|
// vote is electra may convert.
|
||||||
_ => panic!("attestations must be of the same type"),
|
attestation_2: new_attestation
|
||||||
}
|
.clone()
|
||||||
}
|
.to_electra()
|
||||||
// TODO(electra): fix this once we superstruct IndexedAttestation (return the correct type)
|
.map_err(|e| format!("{e:?}"))?,
|
||||||
SurroundsExisting(existing) => match (*existing, new_attestation) {
|
|
||||||
(IndexedAttestation::Base(existing_att), IndexedAttestation::Base(new_att)) => {
|
|
||||||
Some(AttesterSlashing::Base(AttesterSlashingBase {
|
|
||||||
attestation_1: new_att.clone(),
|
|
||||||
attestation_2: existing_att,
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
(
|
|
||||||
IndexedAttestation::Electra(existing_att),
|
|
||||||
IndexedAttestation::Electra(new_att),
|
|
||||||
) => Some(AttesterSlashing::Electra(AttesterSlashingElectra {
|
|
||||||
attestation_1: new_att.clone(),
|
|
||||||
attestation_2: existing_att,
|
|
||||||
})),
|
|
||||||
_ => panic!("attestations must be of the same type"),
|
|
||||||
},
|
},
|
||||||
/*
|
SurroundsExisting(existing) => {
|
||||||
|
match new_attestation {
|
||||||
|
IndexedAttestation::Base(new_attestation) => {
|
||||||
Some(AttesterSlashing::Base(AttesterSlashingBase {
|
Some(AttesterSlashing::Base(AttesterSlashingBase {
|
||||||
attestation_1: new_attestation.clone(),
|
attestation_1: existing
|
||||||
attestation_2: *existing,
|
.as_base()
|
||||||
})),
|
.map_err(|e| format!("{e:?}"))?
|
||||||
*/
|
.clone(),
|
||||||
|
attestation_2: new_attestation.clone(),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
IndexedAttestation::Electra(new_attestation) => {
|
||||||
|
Some(AttesterSlashing::Electra(AttesterSlashingElectra {
|
||||||
|
attestation_1: existing.to_electra().map_err(|e| format!("{e:?}"))?,
|
||||||
|
// A double vote should never convert, a surround vote where the surrounding
|
||||||
|
// vote is electra may convert.
|
||||||
|
attestation_2: new_attestation.clone(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -247,6 +247,7 @@ impl<E: EthSpec> Slasher<E> {
|
|||||||
batch,
|
batch,
|
||||||
current_epoch,
|
current_epoch,
|
||||||
&self.config,
|
&self.config,
|
||||||
|
&self.log,
|
||||||
) {
|
) {
|
||||||
Ok(slashings) => {
|
Ok(slashings) => {
|
||||||
if !slashings.is_empty() {
|
if !slashings.is_empty() {
|
||||||
@@ -294,7 +295,8 @@ impl<E: EthSpec> Slasher<E> {
|
|||||||
indexed_attestation_id,
|
indexed_attestation_id,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if let Some(slashing) = slashing_status.into_slashing(attestation) {
|
match slashing_status.into_slashing(attestation) {
|
||||||
|
Ok(Some(slashing)) => {
|
||||||
debug!(
|
debug!(
|
||||||
self.log,
|
self.log,
|
||||||
"Found double-vote slashing";
|
"Found double-vote slashing";
|
||||||
@@ -303,6 +305,16 @@ impl<E: EthSpec> Slasher<E> {
|
|||||||
);
|
);
|
||||||
slashings.insert(slashing);
|
slashings.insert(slashing);
|
||||||
}
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!(
|
||||||
|
self.log,
|
||||||
|
"Invalid slashing conversion";
|
||||||
|
"validator_index" => validator_index,
|
||||||
|
"error" => e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(None) => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(slashings)
|
Ok(slashings)
|
||||||
|
|||||||
Reference in New Issue
Block a user