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:
Michael Sproul
2020-11-23 03:43:22 +00:00
parent 59b2247ab8
commit 5828ff1204
44 changed files with 3662 additions and 87 deletions

View File

@@ -16,6 +16,7 @@ use eth2_libp2p::NetworkGlobals;
use genesis::{interop_genesis_state, Eth1GenesisService};
use network::{NetworkConfig, NetworkMessage, NetworkService};
use parking_lot::Mutex;
use slasher::{Slasher, SlasherServer};
use slog::{debug, info, warn};
use ssz::Decode;
use std::net::SocketAddr;
@@ -64,6 +65,7 @@ pub struct ClientBuilder<T: BeaconChainTypes> {
http_api_config: http_api::Config,
http_metrics_config: http_metrics::Config,
websocket_listen_addr: Option<SocketAddr>,
slasher: Option<Arc<Slasher<T::EthSpec>>>,
eth_spec_instance: T::EthSpec,
}
@@ -97,6 +99,7 @@ where
http_api_config: <_>::default(),
http_metrics_config: <_>::default(),
websocket_listen_addr: None,
slasher: None,
eth_spec_instance,
}
}
@@ -113,6 +116,11 @@ where
self
}
pub fn slasher(mut self, slasher: Arc<Slasher<TEthSpec>>) -> Self {
self.slasher = Some(slasher);
self
}
/// Initializes the `BeaconChainBuilder`. The `build_beacon_chain` method will need to be
/// called later in order to actually instantiate the `BeaconChain`.
pub async fn beacon_chain_builder(
@@ -146,6 +154,12 @@ where
.disabled_forks(disabled_forks)
.graffiti(graffiti);
let builder = if let Some(slasher) = self.slasher.clone() {
builder.slasher(slasher)
} else {
builder
};
let chain_exists = builder
.store_contains_beacon_chain()
.unwrap_or_else(|_| false);
@@ -343,6 +357,27 @@ where
self
}
/// Immediately start the slasher service.
///
/// Error if no slasher is configured.
pub fn start_slasher_server(&self) -> Result<(), String> {
let context = self
.runtime_context
.as_ref()
.ok_or_else(|| "slasher requires a runtime_context")?
.service_context("slasher_server_ctxt".into());
let slasher = self
.slasher
.clone()
.ok_or_else(|| "slasher server requires a slasher")?;
let slot_clock = self
.slot_clock
.clone()
.ok_or_else(|| "slasher server requires a slot clock")?;
SlasherServer::run(slasher, slot_clock, &context.executor);
Ok(())
}
/// Immediately starts the service that periodically logs information each slot.
pub fn notifier(self) -> Result<Self, String> {
let context = self
@@ -442,6 +477,10 @@ where
None
};
if self.slasher.is_some() {
self.start_slasher_server()?;
}
Ok(Client {
beacon_chain: self.beacon_chain,
network_globals: self.network_globals,