Make slashing protection import more resilient (#2598)

## Issue Addressed

Closes #2419

## Proposed Changes

Address a long-standing issue with the import of slashing protection data where the import would fail due to the data appearing slashable w.r.t the existing database. Importing is now idempotent, and will have no issues importing data that has been handed back and forth between different validator clients, or different implementations.

The implementation works by updating the high and low watermarks if they need updating, and not attempting to check if the input is slashable w.r.t itself or the database. This is a strengthening of the minification that we started to do by default since #2380, and what Teku has been doing since the beginning.

## Additional Info

The only feature we lose by doing this is the ability to do non-minified imports of clock drifted messages (cf. Prysm on Medalla). In theory, with the previous implementation we could import all the messages in case of clock drift and be aware of the "gap" between the real present time and the messages signed in the far future. _However_ for attestations this is close to useless, as the source epoch will advance as soon as justification occurs, which will require us to make slashable attestations with respect to our bogus attestation(s). E.g. if I sign an attestation 100=>200 when the current epoch is 101, then I won't be able to vote in any epochs prior to 101 becoming justified because 101=>102, 101=>103, etc are all surrounded by 100=>200. Seeing as signing attestations gets blocked almost immediately in this case regardless of our import behaviour, there's no point trying to handle it. For blocks the situation is more hopeful due to the lack of surrounds, but losing block proposals from validators who by definition can't attest doesn't seem like an issue (the other block proposers can pick up the slack).
This commit is contained in:
Michael Sproul
2021-10-13 01:49:51 +00:00
parent 34d22b5920
commit 0a77d783a4
11 changed files with 343 additions and 171 deletions

View File

@@ -33,11 +33,10 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
Arg::with_name(MINIFY_FLAG)
.long(MINIFY_FLAG)
.takes_value(true)
.default_value("true")
.possible_values(&["false", "true"])
.help(
"Minify the input file before processing. This is *much* faster, \
but will not detect slashable data in the input.",
"Deprecated: Lighthouse no longer requires minification on import \
because it always minifies",
),
),
)
@@ -88,7 +87,7 @@ pub fn cli_run<T: EthSpec>(
match matches.subcommand() {
(IMPORT_CMD, Some(matches)) => {
let import_filename: PathBuf = clap_utils::parse_required(matches, IMPORT_FILE_ARG)?;
let minify: bool = clap_utils::parse_required(matches, MINIFY_FLAG)?;
let minify: Option<bool> = clap_utils::parse_optional(matches, MINIFY_FLAG)?;
let import_file = File::open(&import_filename).map_err(|e| {
format!(
"Unable to open import file at {}: {:?}",
@@ -102,12 +101,17 @@ pub fn cli_run<T: EthSpec>(
.map_err(|e| format!("Error parsing file for import: {:?}", e))?;
eprintln!(" [done].");
if minify {
eprint!("Minifying input file for faster loading");
interchange = interchange
.minify()
.map_err(|e| format!("Minification failed: {:?}", e))?;
eprintln!(" [done].");
if let Some(minify) = minify {
eprintln!(
"WARNING: --minify flag is deprecated and will be removed in a future release"
);
if minify {
eprint!("Minifying input file for faster loading");
interchange = interchange
.minify()
.map_err(|e| format!("Minification failed: {:?}", e))?;
eprintln!(" [done].");
}
}
let slashing_protection_database =
@@ -120,14 +124,16 @@ pub fn cli_run<T: EthSpec>(
})?;
let display_slot = |slot: Option<Slot>| {
slot.map_or("none".to_string(), |slot| format!("{}", slot.as_u64()))
slot.map_or("none".to_string(), |slot| format!("slot {}", slot.as_u64()))
};
let display_epoch = |epoch: Option<Epoch>| {
epoch.map_or("?".to_string(), |epoch| format!("{}", epoch.as_u64()))
epoch.map_or("?".to_string(), |epoch| format!("epoch {}", epoch.as_u64()))
};
let display_attestation = |source, target| match (source, target) {
(None, None) => "none".to_string(),
(source, target) => format!("{}=>{}", display_epoch(source), display_epoch(target)),
(source, target) => {
format!("{} => {}", display_epoch(source), display_epoch(target))
}
};
match slashing_protection_database
@@ -140,18 +146,11 @@ pub fn cli_run<T: EthSpec>(
InterchangeImportOutcome::Success { pubkey, summary } => {
eprintln!("- {:?}", pubkey);
eprintln!(
" - min block: {}",
display_slot(summary.min_block_slot)
" - latest block: {}",
display_slot(summary.max_block_slot)
);
eprintln!(
" - min attestation: {}",
display_attestation(
summary.min_attestation_source,
summary.min_attestation_target
)
);
eprintln!(
" - max attestation: {}",
" - latest attestation: {}",
display_attestation(
summary.max_attestation_source,
summary.max_attestation_target
@@ -168,18 +167,20 @@ pub fn cli_run<T: EthSpec>(
}
}
Err(InterchangeError::AtomicBatchAborted(outcomes)) => {
eprintln!("ERROR, slashable data in input:");
eprintln!("ERROR: import aborted due to one or more errors");
for outcome in &outcomes {
if let InterchangeImportOutcome::Failure { pubkey, error } = outcome {
eprintln!("- {:?}", pubkey);
eprintln!(" - error: {:?}", error);
}
}
return Err(
"ERROR: import aborted due to slashable data, see above.\n\
Please see https://lighthouse-book.sigmaprime.io/slashing-protection.html#slashable-data-in-import\n\
IT IS NOT SAFE TO START VALIDATING".to_string()
);
return Err("ERROR: import aborted due to errors, see above.\n\
No data has been imported and the slashing protection \
database is in the same state it was in before the import.\n\
Due to the failed import it is NOT SAFE to start validating\n\
with any newly imported validator keys, as your database lacks\n\
slashing protection data for them."
.to_string());
}
Err(e) => {
return Err(format!(
@@ -192,7 +193,7 @@ pub fn cli_run<T: EthSpec>(
eprintln!("Import completed successfully.");
eprintln!(
"Please double-check that the minimum and maximum blocks and attestations above \
"Please double-check that the latest blocks and attestations above \
match your expectations."
);