-
Notifications
You must be signed in to change notification settings - Fork 784
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement slashing protection interchange format (#1544)
## Issue Addressed Implements support for importing and exporting the slashing protection DB interchange format described here: https://hackmd.io/@sproul/Bk0Y0qdGD Also closes #1584 ## Proposed Changes * [x] Support for serializing and deserializing the format * [x] Support for importing and exporting Lighthouse's database * [x] CLI commands to invoke import and export * [x] Export to minimal format (required when a minimal format has been previously imported) * [x] Tests for export to minimal (utilising mixed importing and attestation signing?) * [x] Tests for import/export of complete format, and import of minimal format * [x] ~~Prevent attestations with sources less than our max source (Danny's suggestion). Required for the fake attestation that we put in for the minimal format to block attestations from source 0.~~ * [x] Add the concept of a "low watermark" for compatibility with the minimal format Bonus! * [x] A fix to a potentially nasty bug involving validators getting re-registered each time the validator client ran! Thankfully, the ordering of keys meant that the validator IDs used for attestations and blocks remained stable -- otherwise we could have had some slashings on our hands! 😱 * [x] Tests to confirm that this bug is indeed vanquished
- Loading branch information
1 parent
22aedda
commit 1d278aa
Showing
25 changed files
with
1,164 additions
and
88 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,4 +6,4 @@ target/ | |
flamegraph.svg | ||
perf.data* | ||
*.tar.gz | ||
bin/ | ||
/bin |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
use clap::{App, Arg, ArgMatches}; | ||
use environment::Environment; | ||
use slashing_protection::{ | ||
interchange::Interchange, SlashingDatabase, SLASHING_PROTECTION_FILENAME, | ||
}; | ||
use std::fs::File; | ||
use std::path::PathBuf; | ||
use types::EthSpec; | ||
|
||
pub const CMD: &str = "slashing-protection"; | ||
pub const IMPORT_CMD: &str = "import"; | ||
pub const EXPORT_CMD: &str = "export"; | ||
|
||
pub const IMPORT_FILE_ARG: &str = "IMPORT-FILE"; | ||
pub const EXPORT_FILE_ARG: &str = "EXPORT-FILE"; | ||
|
||
pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||
App::new(CMD) | ||
.about("Import or export slashing protection data to or from another client") | ||
.subcommand( | ||
App::new(IMPORT_CMD) | ||
.about("Import an interchange file") | ||
.arg( | ||
Arg::with_name(IMPORT_FILE_ARG) | ||
.takes_value(true) | ||
.value_name("FILE") | ||
.help("The slashing protection interchange file to import (.json)"), | ||
), | ||
) | ||
.subcommand( | ||
App::new(EXPORT_CMD) | ||
.about("Export an interchange file") | ||
.arg( | ||
Arg::with_name(EXPORT_FILE_ARG) | ||
.takes_value(true) | ||
.value_name("FILE") | ||
.help("The filename to export the interchange file to"), | ||
), | ||
) | ||
} | ||
|
||
pub fn cli_run<T: EthSpec>( | ||
matches: &ArgMatches<'_>, | ||
env: Environment<T>, | ||
validator_base_dir: PathBuf, | ||
) -> Result<(), String> { | ||
let slashing_protection_db_path = validator_base_dir.join(SLASHING_PROTECTION_FILENAME); | ||
|
||
let genesis_validators_root = env | ||
.testnet | ||
.and_then(|testnet_config| { | ||
Some( | ||
testnet_config | ||
.genesis_state | ||
.as_ref()? | ||
.genesis_validators_root, | ||
) | ||
}) | ||
.ok_or_else(|| { | ||
"Unable to get genesis validators root from testnet config, has genesis occurred?" | ||
})?; | ||
|
||
match matches.subcommand() { | ||
(IMPORT_CMD, Some(matches)) => { | ||
let import_filename: PathBuf = clap_utils::parse_required(&matches, IMPORT_FILE_ARG)?; | ||
let import_file = File::open(&import_filename).map_err(|e| { | ||
format!( | ||
"Unable to open import file at {}: {:?}", | ||
import_filename.display(), | ||
e | ||
) | ||
})?; | ||
|
||
let interchange = Interchange::from_json_reader(&import_file) | ||
.map_err(|e| format!("Error parsing file for import: {:?}", e))?; | ||
|
||
let slashing_protection_database = | ||
SlashingDatabase::open_or_create(&slashing_protection_db_path).map_err(|e| { | ||
format!( | ||
"Unable to open database at {}: {:?}", | ||
slashing_protection_db_path.display(), | ||
e | ||
) | ||
})?; | ||
|
||
slashing_protection_database | ||
.import_interchange_info(&interchange, genesis_validators_root) | ||
.map_err(|e| { | ||
format!( | ||
"Error during import, no data imported: {:?}\n\ | ||
IT IS NOT SAFE TO START VALIDATING", | ||
e | ||
) | ||
})?; | ||
|
||
eprintln!("Import completed successfully"); | ||
|
||
Ok(()) | ||
} | ||
(EXPORT_CMD, Some(matches)) => { | ||
let export_filename: PathBuf = clap_utils::parse_required(&matches, EXPORT_FILE_ARG)?; | ||
|
||
if !slashing_protection_db_path.exists() { | ||
return Err(format!( | ||
"No slashing protection database exists at: {}", | ||
slashing_protection_db_path.display() | ||
)); | ||
} | ||
|
||
let slashing_protection_database = SlashingDatabase::open(&slashing_protection_db_path) | ||
.map_err(|e| { | ||
format!( | ||
"Unable to open database at {}: {:?}", | ||
slashing_protection_db_path.display(), | ||
e | ||
) | ||
})?; | ||
|
||
let interchange = slashing_protection_database | ||
.export_interchange_info(genesis_validators_root) | ||
.map_err(|e| format!("Error during export: {:?}", e))?; | ||
|
||
let output_file = File::create(export_filename) | ||
.map_err(|e| format!("Error creating output file: {:?}", e))?; | ||
|
||
interchange | ||
.write_to(&output_file) | ||
.map_err(|e| format!("Error writing output file: {:?}", e))?; | ||
|
||
eprintln!("Export completed successfully"); | ||
|
||
Ok(()) | ||
} | ||
("", _) => Err("No subcommand provided, see --help for options".to_string()), | ||
(command, _) => Err(format!("No such subcommand `{}`", command)), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.