mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-17 12:58:31 +00:00
Implement slasher (#1567)
This is an implementation of a slasher that lives inside the BN and can be enabled via `lighthouse bn --slasher`. Features included in this PR: - [x] Detection of attester slashing conditions (double votes, surrounds existing, surrounded by existing) - [x] Integration into Lighthouse's attestation verification flow - [x] Detection of proposer slashing conditions - [x] Extraction of attestations from blocks as they are verified - [x] Compression of chunks - [x] Configurable history length - [x] Pruning of old attestations and blocks - [x] More tests Future work: * Focus on a slice of history separate from the most recent N epochs (e.g. epochs `current - K` to `current - M`) * Run out-of-process * Ingest attestations from the chain without a resync Design notes are here https://hackmd.io/@sproul/HJSEklmPL
This commit is contained in:
115
slasher/src/test_utils.rs
Normal file
115
slasher/src/test_utils.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
use slog::Logger;
|
||||
use sloggers::Build;
|
||||
use std::collections::HashSet;
|
||||
use std::iter::FromIterator;
|
||||
use types::{
|
||||
AggregateSignature, AttestationData, AttesterSlashing, BeaconBlockHeader, Checkpoint, Epoch,
|
||||
Hash256, IndexedAttestation, MainnetEthSpec, Signature, SignedBeaconBlockHeader, Slot,
|
||||
};
|
||||
|
||||
pub type E = MainnetEthSpec;
|
||||
|
||||
pub fn logger() -> Logger {
|
||||
if cfg!(feature = "test_logger") {
|
||||
sloggers::terminal::TerminalLoggerBuilder::new()
|
||||
.level(sloggers::types::Severity::Trace)
|
||||
.build()
|
||||
.unwrap()
|
||||
} else {
|
||||
sloggers::null::NullLoggerBuilder.build().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn indexed_att(
|
||||
attesting_indices: impl AsRef<[u64]>,
|
||||
source_epoch: u64,
|
||||
target_epoch: u64,
|
||||
target_root: u64,
|
||||
) -> IndexedAttestation<E> {
|
||||
IndexedAttestation {
|
||||
attesting_indices: attesting_indices.as_ref().to_vec().into(),
|
||||
data: AttestationData {
|
||||
slot: Slot::new(0),
|
||||
index: 0,
|
||||
beacon_block_root: Hash256::zero(),
|
||||
source: Checkpoint {
|
||||
epoch: Epoch::new(source_epoch),
|
||||
root: Hash256::from_low_u64_be(0),
|
||||
},
|
||||
target: Checkpoint {
|
||||
epoch: Epoch::new(target_epoch),
|
||||
root: Hash256::from_low_u64_be(target_root),
|
||||
},
|
||||
},
|
||||
signature: AggregateSignature::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn att_slashing(
|
||||
attestation_1: &IndexedAttestation<E>,
|
||||
attestation_2: &IndexedAttestation<E>,
|
||||
) -> AttesterSlashing<E> {
|
||||
AttesterSlashing {
|
||||
attestation_1: attestation_1.clone(),
|
||||
attestation_2: attestation_2.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hashset_intersection(
|
||||
attestation_1_indices: &[u64],
|
||||
attestation_2_indices: &[u64],
|
||||
) -> HashSet<u64> {
|
||||
&HashSet::from_iter(attestation_1_indices.iter().copied())
|
||||
& &HashSet::from_iter(attestation_2_indices.iter().copied())
|
||||
}
|
||||
|
||||
pub fn slashed_validators_from_slashings(slashings: &HashSet<AttesterSlashing<E>>) -> HashSet<u64> {
|
||||
slashings
|
||||
.iter()
|
||||
.flat_map(|slashing| {
|
||||
let att1 = &slashing.attestation_1;
|
||||
let att2 = &slashing.attestation_2;
|
||||
assert!(
|
||||
att1.is_double_vote(att2) || att1.is_surround_vote(att2),
|
||||
"invalid slashing: {:#?}",
|
||||
slashing
|
||||
);
|
||||
hashset_intersection(&att1.attesting_indices, &att2.attesting_indices)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn slashed_validators_from_attestations(
|
||||
attestations: &[IndexedAttestation<E>],
|
||||
) -> HashSet<u64> {
|
||||
let mut slashed_validators = HashSet::new();
|
||||
// O(n^2) code, watch out.
|
||||
for att1 in attestations {
|
||||
for att2 in attestations {
|
||||
if att1 == att2 {
|
||||
continue;
|
||||
}
|
||||
|
||||
if att1.is_double_vote(att2) || att1.is_surround_vote(att2) {
|
||||
slashed_validators.extend(hashset_intersection(
|
||||
&att1.attesting_indices,
|
||||
&att2.attesting_indices,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
slashed_validators
|
||||
}
|
||||
|
||||
pub fn block(slot: u64, proposer_index: u64, block_root: u64) -> SignedBeaconBlockHeader {
|
||||
SignedBeaconBlockHeader {
|
||||
message: BeaconBlockHeader {
|
||||
slot: Slot::new(slot),
|
||||
proposer_index,
|
||||
parent_root: Hash256::zero(),
|
||||
state_root: Hash256::zero(),
|
||||
body_root: Hash256::from_low_u64_be(block_root),
|
||||
},
|
||||
signature: Signature::empty(),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user