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

83
slasher/src/error.rs Normal file
View File

@@ -0,0 +1,83 @@
use crate::Config;
use std::io;
use types::{Epoch, Hash256};
#[derive(Debug)]
pub enum Error {
DatabaseError(lmdb::Error),
DatabaseIOError(io::Error),
SszDecodeError(ssz::DecodeError),
BincodeError(bincode::Error),
ArithError(safe_arith::ArithError),
ChunkIndexOutOfBounds(usize),
IncompatibleSchemaVersion {
database_schema_version: u64,
software_schema_version: u64,
},
ConfigInvalidChunkSize {
chunk_size: usize,
history_length: usize,
},
ConfigInvalidZeroParameter {
config: Config,
},
ConfigIncompatible {
on_disk_config: Config,
config: Config,
},
DistanceTooLarge,
DistanceCalculationOverflow,
/// Missing an attester record that we expected to exist.
MissingAttesterRecord {
validator_index: u64,
target_epoch: Epoch,
},
AttesterRecordCorrupt {
length: usize,
},
AttesterKeyCorrupt {
length: usize,
},
ProposerKeyCorrupt {
length: usize,
},
MissingIndexedAttestation {
root: Hash256,
},
MissingAttesterKey,
MissingProposerKey,
AttesterRecordInconsistentRoot,
}
impl From<lmdb::Error> for Error {
fn from(e: lmdb::Error) -> Self {
match e {
lmdb::Error::Other(os_error) => Error::from(io::Error::from_raw_os_error(os_error)),
_ => Error::DatabaseError(e),
}
}
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
Error::DatabaseIOError(e)
}
}
impl From<ssz::DecodeError> for Error {
fn from(e: ssz::DecodeError) -> Self {
Error::SszDecodeError(e)
}
}
impl From<bincode::Error> for Error {
fn from(e: bincode::Error) -> Self {
Error::BincodeError(e)
}
}
impl From<safe_arith::ArithError> for Error {
fn from(e: safe_arith::ArithError) -> Self {
Error::ArithError(e)
}
}