Strict slashing protection by default (#1750)

## Proposed Changes

Replace `--strict-slashing-protection` by `--init-slashing-protection` and remove mentions of `--auto-register`
This commit is contained in:
Michael Sproul 2020-10-09 02:05:32 +00:00
parent 72cc5e35af
commit b0833033b7
10 changed files with 94 additions and 87 deletions

View File

@ -15,4 +15,4 @@ exec lighthouse \
--datadir $VALIDATORS_DIR \
--secrets-dir $SECRETS_DIR \
--testnet-dir $TESTNET_DIR \
--auto-register
--init-slashing-protection

View File

@ -106,6 +106,14 @@ pub fn testing_client_config() -> ClientConfig {
client_config
}
pub fn testing_validator_config() -> ValidatorConfig {
ValidatorConfig {
init_slashing_protection: true,
disable_auto_discover: false,
..ValidatorConfig::default()
}
}
/// Contains the directories for a `LocalValidatorClient`.
///
/// This struct is separate to `LocalValidatorClient` to allow for pre-computation of validator

View File

@ -4,8 +4,8 @@ use eth1::http::Eth1NetworkId;
use eth1_test_rig::GanacheEth1Instance;
use futures::prelude::*;
use node_test_rig::{
environment::EnvironmentBuilder, testing_client_config, ClientGenesis, ValidatorConfig,
ValidatorFiles,
environment::EnvironmentBuilder, testing_client_config, testing_validator_config,
ClientGenesis, ValidatorFiles,
};
use rayon::prelude::*;
use std::net::{IpAddr, Ipv4Addr};
@ -128,14 +128,7 @@ pub fn run_eth1_sim(matches: &ArgMatches) -> Result<(), String> {
*/
for (i, files) in validator_files.into_iter().enumerate() {
network
.add_validator_client(
ValidatorConfig {
disable_auto_discover: false,
..ValidatorConfig::default()
},
i,
files,
)
.add_validator_client(testing_validator_config(), i, files)
.await?;
}

View File

@ -2,8 +2,8 @@ use crate::{checks, LocalNetwork};
use clap::ArgMatches;
use futures::prelude::*;
use node_test_rig::{
environment::EnvironmentBuilder, testing_client_config, ClientGenesis, ValidatorConfig,
ValidatorFiles,
environment::EnvironmentBuilder, testing_client_config, testing_validator_config,
ClientGenesis, ValidatorFiles,
};
use rayon::prelude::*;
use std::net::{IpAddr, Ipv4Addr};
@ -99,14 +99,7 @@ pub fn run_no_eth1_sim(matches: &ArgMatches) -> Result<(), String> {
let add_validators_fut = async {
for (i, files) in validator_files.into_iter().enumerate() {
network
.add_validator_client(
ValidatorConfig {
disable_auto_discover: false,
..ValidatorConfig::default()
},
i,
files,
)
.add_validator_client(testing_validator_config(), i, files)
.await?;
}

View File

@ -173,6 +173,17 @@ impl SlashingDatabase {
Ok(())
}
/// Check that all of the given validators are registered.
pub fn check_validator_registrations<'a>(
&self,
mut public_keys: impl Iterator<Item = &'a PublicKey>,
) -> Result<(), NotSafe> {
let mut conn = self.conn_pool.get()?;
let txn = conn.transaction()?;
public_keys
.try_for_each(|public_key| self.get_validator_id_in_txn(&txn, public_key).map(|_| ()))
}
/// Get the database-internal ID for a validator.
///
/// This is NOT the same as a validator index, and depends on the ordering that validators

View File

@ -52,14 +52,6 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
.conflicts_with("datadir")
.requires("validators-dir"),
)
.arg(Arg::with_name("auto-register").long("auto-register").help(
"If present, the validator client will register any new signing keys with \
the slashing protection database so that they may be used. WARNING: \
enabling the same signing key on multiple validator clients WILL lead to \
that validator getting slashed. Only use this flag the first time you run \
the validator client, or if you're certain there are no other \
nodes using the same key. Automatically enabled unless `--strict` is specified",
))
.arg(
Arg::with_name("delete-lockfiles")
.long("delete-lockfiles")
@ -73,14 +65,15 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
)
)
.arg(
Arg::with_name("strict-slashing-protection")
.long("strict-slashing-protection")
.help(
"If present, do not create a new slashing database. This is to ensure that users \
do not accidentally get slashed in case their slashing protection db ends up in the \
wrong directory during directory restructure and vc creates a new empty db and \
re-registers all validators."
)
Arg::with_name("init-slashing-protection")
.long("init-slashing-protection")
.help(
"If present, do not require the slashing protection database to exist before \
running. You SHOULD NOT use this flag unless you're certain that a new \
slashing protection database is required. Usually, your database \
will have been initialized when you imported your validator keys. If you \
misplace your database and then run with this flag you risk being slashed."
)
)
.arg(
Arg::with_name("disable-auto-discover")

View File

@ -32,8 +32,8 @@ pub struct Config {
pub delete_lockfiles: bool,
/// If true, don't scan the validators dir for new keystores.
pub disable_auto_discover: bool,
/// If true, don't re-register existing validators in definitions.yml for slashing protection.
pub strict_slashing_protection: bool,
/// If true, re-register existing validators in definitions.yml for slashing protection.
pub init_slashing_protection: bool,
/// Graffiti to be inserted everytime we create a block.
pub graffiti: Option<Graffiti>,
/// Configuration for the HTTP REST API.
@ -58,7 +58,7 @@ impl Default for Config {
allow_unsynced_beacon_node: false,
delete_lockfiles: false,
disable_auto_discover: false,
strict_slashing_protection: false,
init_slashing_protection: false,
graffiti: None,
http_api: <_>::default(),
}
@ -122,7 +122,7 @@ impl Config {
config.allow_unsynced_beacon_node = cli_args.is_present("allow-unsynced");
config.delete_lockfiles = cli_args.is_present("delete-lockfiles");
config.disable_auto_discover = cli_args.is_present("disable-auto-discover");
config.strict_slashing_protection = cli_args.is_present("strict-slashing-protection");
config.init_slashing_protection = cli_args.is_present("init-slashing-protection");
if let Some(input_graffiti) = cli_args.value_of("graffiti") {
let graffiti_bytes = input_graffiti.as_bytes();

View File

@ -17,6 +17,7 @@ use eth2::{
};
use eth2_keystore::KeystoreBuilder;
use parking_lot::RwLock;
use slashing_protection::{SlashingDatabase, SLASHING_PROTECTION_FILENAME};
use slot_clock::TestingSlotClock;
use std::marker::PhantomData;
use std::net::Ipv4Addr;
@ -65,15 +66,17 @@ impl ApiTester {
.build()
.unwrap();
let slashing_db_path = config.validator_dir.join(SLASHING_PROTECTION_FILENAME);
let slashing_protection = SlashingDatabase::open_or_create(&slashing_db_path).unwrap();
let validator_store: ValidatorStore<TestingSlotClock, E> = ValidatorStore::new(
initialized_validators,
&config,
slashing_protection,
Hash256::repeat_byte(42),
E::default_spec(),
fork_service.clone(),
log.clone(),
)
.unwrap();
);
let initialized_validators = validator_store.initialized_validators();

View File

@ -28,6 +28,7 @@ use futures::channel::mpsc;
use http_api::ApiSecret;
use initialized_validators::InitializedValidators;
use notifier::spawn_notifier;
use slashing_protection::{SlashingDatabase, SLASHING_PROTECTION_FILENAME};
use slog::{error, info, Logger};
use slot_clock::SlotClock;
use slot_clock::SystemTimeSlotClock;
@ -106,6 +107,44 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
.await
.map_err(|e| format!("Unable to initialize validators: {:?}", e))?;
// Initialize slashing protection.
let slashing_db_path = config.validator_dir.join(SLASHING_PROTECTION_FILENAME);
let slashing_protection = if config.init_slashing_protection {
SlashingDatabase::open_or_create(&slashing_db_path).map_err(|e| {
format!(
"Failed to open or create slashing protection database: {:?}",
e
)
})
} else {
SlashingDatabase::open(&slashing_db_path).map_err(|e| {
format!(
"Failed to open slashing protection database: {:?}.\n\
Ensure that `slashing_protection.sqlite` is in {:?} folder",
e, config.validator_dir
)
})
}?;
// Check validator registration with slashing protection, or auto-register all validators.
if config.init_slashing_protection {
slashing_protection
.register_validators(validators.iter_voting_pubkeys())
.map_err(|e| format!("Error while registering slashing protection: {:?}", e))?;
} else {
slashing_protection
.check_validator_registrations(validators.iter_voting_pubkeys())
.map_err(|e| {
format!(
"One or more validators not found in slashing protection database.\n\
Ensure you haven't misplaced your slashing protection database, or \
carefully consider running with --init-slashing-protection (see --help). \
Error: {:?}",
e
)
})?;
}
info!(
log,
"Initialized validators";
@ -157,12 +196,12 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
let validator_store: ValidatorStore<SystemTimeSlotClock, T> = ValidatorStore::new(
validators,
&config,
slashing_protection,
genesis_validators_root,
context.eth2_config.spec.clone(),
fork_service.clone(),
log.clone(),
)?;
);
info!(
log,
@ -170,8 +209,6 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
"voting_validators" => validator_store.num_voting_validators()
);
validator_store.register_all_validators_for_slashing_protection()?;
let duties_service = DutiesServiceBuilder::new()
.slot_clock(slot_clock.clone())
.validator_store(validator_store.clone())

View File

@ -1,9 +1,7 @@
use crate::{
config::Config, fork_service::ForkService, initialized_validators::InitializedValidators,
};
use crate::{fork_service::ForkService, initialized_validators::InitializedValidators};
use account_utils::{validator_definitions::ValidatorDefinition, ZeroizeString};
use parking_lot::RwLock;
use slashing_protection::{NotSafe, Safe, SlashingDatabase, SLASHING_PROTECTION_FILENAME};
use slashing_protection::{NotSafe, Safe, SlashingDatabase};
use slog::{crit, error, warn, Logger};
use slot_clock::SlotClock;
use std::marker::PhantomData;
@ -56,32 +54,13 @@ pub struct ValidatorStore<T, E: EthSpec> {
impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
pub fn new(
validators: InitializedValidators,
config: &Config,
slashing_protection: SlashingDatabase,
genesis_validators_root: Hash256,
spec: ChainSpec,
fork_service: ForkService<T>,
log: Logger,
) -> Result<Self, String> {
let slashing_db_path = config.validator_dir.join(SLASHING_PROTECTION_FILENAME);
let slashing_protection = if config.strict_slashing_protection {
// Don't create a new slashing database if `strict_slashing_protection` is turned on.
SlashingDatabase::open(&slashing_db_path).map_err(|e| {
format!(
"Failed to open slashing protection database: {:?}.
Ensure that `slashing_protection.sqlite` is in {:?} folder",
e, config.validator_dir
)
})?
} else {
SlashingDatabase::open_or_create(&slashing_db_path).map_err(|e| {
format!(
"Failed to open or create slashing protection database: {:?}",
e
)
})?
};
Ok(Self {
) -> Self {
Self {
validators: Arc::new(RwLock::new(validators)),
slashing_protection,
genesis_validators_root,
@ -90,7 +69,7 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
temp_dir: None,
fork_service,
_phantom: PhantomData,
})
}
}
pub fn initialized_validators(&self) -> Arc<RwLock<InitializedValidators>> {
@ -130,16 +109,6 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
Ok(validator_def)
}
/// Register all known validators with the slashing protection database.
///
/// Registration is required to protect against a lost or missing slashing database,
/// such as when relocating validator keys to a new machine.
pub fn register_all_validators_for_slashing_protection(&self) -> Result<(), String> {
self.slashing_protection
.register_validators(self.validators.read().iter_voting_pubkeys())
.map_err(|e| format!("Error while registering validators: {:?}", e))
}
pub fn voting_pubkeys(&self) -> Vec<PublicKey> {
self.validators
.read()
@ -235,7 +204,7 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
warn!(
self.log,
"Not signing block for unregistered validator";
"msg" => "Carefully consider running with --auto-register (see --help)",
"msg" => "Carefully consider running with --init-slashing-protection (see --help)",
"public_key" => format!("{:?}", pk)
);
None
@ -314,7 +283,7 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
warn!(
self.log,
"Not signing attestation for unregistered validator";
"msg" => "Carefully consider running with --auto-register (see --help)",
"msg" => "Carefully consider running with --init-slashing-protection (see --help)",
"public_key" => format!("{:?}", pk)
);
None