Require manual confirmation to purge database with purge-db (#6154)

* Require manual confirmation to purge database

* Fix tests

* Rename to `purge-db-force and skip in non-interactive mode

* Do not skip when stdin_inputs is true

* Change prompt to be info logging to ensure consistent output

* Update warning text

* Move delete log after deletion
This commit is contained in:
Mac L
2024-08-20 06:03:40 +04:00
committed by GitHub
parent d957161740
commit 32f2e059c5
22 changed files with 116 additions and 104 deletions

1
Cargo.lock generated
View File

@@ -836,6 +836,7 @@ dependencies = [
name = "beacon_node"
version = "5.3.0"
dependencies = [
"account_utils",
"beacon_chain",
"clap",
"clap_utils",

View File

@@ -1,8 +1,8 @@
use crate::common::read_wallet_name_from_cli;
use crate::wallet::create::STDIN_INPUTS_FLAG;
use crate::{SECRETS_DIR_FLAG, WALLETS_DIR_FLAG};
use account_utils::{
random_password, read_password_from_user, strip_off_newlines, validator_definitions, PlainText,
STDIN_INPUTS_FLAG,
};
use clap::{Arg, ArgAction, ArgMatches, Command};
use clap_utils::FLAG_HEADER;
@@ -114,16 +114,6 @@ pub fn cli_app() -> Command {
.action(ArgAction::Set)
.display_order(0)
)
.arg(
Arg::new(STDIN_INPUTS_FLAG)
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.hide(cfg!(windows))
.long(STDIN_INPUTS_FLAG)
.help("If present, read all user inputs from stdin instead of tty.")
.display_order(0)
.action(ArgAction::SetTrue)
)
}
pub fn cli_run<E: EthSpec>(

View File

@@ -1,4 +1,4 @@
use crate::wallet::create::STDIN_INPUTS_FLAG;
use account_utils::STDIN_INPUTS_FLAG;
use bls::{Keypair, PublicKey};
use clap::{Arg, ArgAction, ArgMatches, Command};
use clap_utils::FLAG_HEADER;
@@ -74,15 +74,6 @@ pub fn cli_app() -> Command {
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
)
.arg(
Arg::new(STDIN_INPUTS_FLAG)
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.hide(cfg!(windows))
.long(STDIN_INPUTS_FLAG)
.help("If present, read all user inputs from stdin instead of tty.")
.display_order(0)
)
}
pub fn cli_run<E: EthSpec>(matches: &ArgMatches, env: Environment<E>) -> Result<(), String> {

View File

@@ -1,4 +1,4 @@
use crate::wallet::create::{PASSWORD_FLAG, STDIN_INPUTS_FLAG};
use crate::wallet::create::PASSWORD_FLAG;
use account_utils::validator_definitions::SigningDefinition;
use account_utils::{
eth2_keystore::Keystore,
@@ -7,7 +7,7 @@ use account_utils::{
recursively_find_voting_keystores, PasswordStorage, ValidatorDefinition,
ValidatorDefinitions, CONFIG_FILENAME,
},
ZeroizeString,
ZeroizeString, STDIN_INPUTS_FLAG,
};
use clap::{Arg, ArgAction, ArgMatches, Command};
use clap_utils::FLAG_HEADER;
@@ -59,15 +59,6 @@ pub fn cli_app() -> Command {
.action(ArgAction::Set)
.display_order(0),
)
.arg(
Arg::new(STDIN_INPUTS_FLAG)
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.hide(cfg!(windows))
.long(STDIN_INPUTS_FLAG)
.help("If present, read all user inputs from stdin instead of tty.")
.display_order(0),
)
.arg(
Arg::new(REUSE_PASSWORD_FLAG)
.long(REUSE_PASSWORD_FLAG)

View File

@@ -1,9 +1,8 @@
use super::create::STORE_WITHDRAW_FLAG;
use crate::validator::create::COUNT_FLAG;
use crate::wallet::create::STDIN_INPUTS_FLAG;
use crate::SECRETS_DIR_FLAG;
use account_utils::eth2_keystore::{keypair_from_secret, Keystore, KeystoreBuilder};
use account_utils::{random_password, read_mnemonic_from_cli};
use account_utils::{random_password, read_mnemonic_from_cli, STDIN_INPUTS_FLAG};
use clap::{Arg, ArgAction, ArgMatches, Command};
use clap_utils::FLAG_HEADER;
use directory::ensure_dir_exists;
@@ -76,15 +75,6 @@ pub fn cli_app() -> Command {
.help_heading(FLAG_HEADER)
.display_order(0)
)
.arg(
Arg::new(STDIN_INPUTS_FLAG)
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.hide(cfg!(windows))
.long(STDIN_INPUTS_FLAG)
.help("If present, read all user inputs from stdin instead of tty.")
.display_order(0)
)
}
pub fn cli_run(matches: &ArgMatches, validator_dir: PathBuf) -> Result<(), String> {

View File

@@ -2,6 +2,7 @@ use crate::common::read_wallet_name_from_cli;
use crate::WALLETS_DIR_FLAG;
use account_utils::{
is_password_sufficiently_complex, random_password, read_password_from_user, strip_off_newlines,
STDIN_INPUTS_FLAG,
};
use clap::{Arg, ArgAction, ArgMatches, Command};
use eth2_wallet::{
@@ -20,7 +21,6 @@ pub const NAME_FLAG: &str = "name";
pub const PASSWORD_FLAG: &str = "password-file";
pub const TYPE_FLAG: &str = "type";
pub const MNEMONIC_FLAG: &str = "mnemonic-output-path";
pub const STDIN_INPUTS_FLAG: &str = "stdin-inputs";
pub const MNEMONIC_LENGTH_FLAG: &str = "mnemonic-length";
pub const MNEMONIC_TYPES: &[MnemonicType] = &[
MnemonicType::Words12,
@@ -83,14 +83,6 @@ pub fn cli_app() -> Command {
.action(ArgAction::Set)
.display_order(0)
)
.arg(
Arg::new(STDIN_INPUTS_FLAG)
.action(ArgAction::SetTrue)
.hide(cfg!(windows))
.long(STDIN_INPUTS_FLAG)
.help("If present, read all user inputs from stdin instead of tty.")
.display_order(0)
)
.arg(
Arg::new(MNEMONIC_LENGTH_FLAG)
.long(MNEMONIC_LENGTH_FLAG)

View File

@@ -1,6 +1,6 @@
use crate::wallet::create::{create_wallet_from_mnemonic, STDIN_INPUTS_FLAG};
use crate::wallet::create::create_wallet_from_mnemonic;
use crate::wallet::create::{HD_TYPE, NAME_FLAG, PASSWORD_FLAG, TYPE_FLAG};
use account_utils::read_mnemonic_from_cli;
use account_utils::{read_mnemonic_from_cli, STDIN_INPUTS_FLAG};
use clap::{Arg, ArgAction, ArgMatches, Command};
use std::path::PathBuf;
@@ -56,14 +56,6 @@ pub fn cli_app() -> Command {
.default_value(HD_TYPE)
.display_order(0),
)
.arg(
Arg::new(STDIN_INPUTS_FLAG)
.action(ArgAction::SetTrue)
.hide(cfg!(windows))
.long(STDIN_INPUTS_FLAG)
.help("If present, read all user inputs from stdin instead of tty.")
.display_order(0),
)
}
pub fn cli_run(matches: &ArgMatches, wallet_base_dir: PathBuf) -> Result<(), String> {

View File

@@ -44,3 +44,4 @@ sensitive_url = { workspace = true }
http_api = { workspace = true }
unused_port = { workspace = true }
strum = { workspace = true }
account_utils = { workspace = true }

View File

@@ -919,7 +919,15 @@ pub fn cli_app() -> Command {
.long("purge-db")
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.help("If present, the chain database will be deleted. Use with caution.")
.help("If present, the chain database will be deleted. Requires manual confirmation.")
.display_order(0)
)
.arg(
Arg::new("purge-db-force")
.long("purge-db-force")
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.help("If present, the chain database will be deleted without confirmation. Use with caution.")
.display_order(0)
)
.arg(

View File

@@ -1,3 +1,4 @@
use account_utils::{read_input_from_user, STDIN_INPUTS_FLAG};
use beacon_chain::chain_config::{
DisallowedReOrgOffsets, ReOrgThreshold, DEFAULT_PREPARE_PAYLOAD_LOOKAHEAD_FACTOR,
DEFAULT_RE_ORG_HEAD_THRESHOLD, DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION,
@@ -21,6 +22,7 @@ use slog::{info, warn, Logger};
use std::cmp::max;
use std::fmt::Debug;
use std::fs;
use std::io::IsTerminal;
use std::net::Ipv6Addr;
use std::net::{IpAddr, Ipv4Addr, ToSocketAddrs};
use std::num::NonZeroU16;
@@ -30,6 +32,8 @@ use std::time::Duration;
use types::graffiti::GraffitiString;
use types::{Checkpoint, Epoch, EthSpec, Hash256, PublicKeyBytes};
const PURGE_DB_CONFIRMATION: &str = "confirm";
/// Gets the fully-initialized global client.
///
/// The top-level `clap` arguments should be provided as `cli_args`.
@@ -50,26 +54,45 @@ pub fn get_config<E: EthSpec>(
client_config.set_data_dir(get_data_dir(cli_args));
// If necessary, remove any existing database and configuration
if client_config.data_dir().exists() && cli_args.get_flag("purge-db") {
// Remove the chain_db.
let chain_db = client_config.get_db_path();
if chain_db.exists() {
fs::remove_dir_all(chain_db)
.map_err(|err| format!("Failed to remove chain_db: {}", err))?;
}
if client_config.data_dir().exists() {
if cli_args.get_flag("purge-db-force") {
let chain_db = client_config.get_db_path();
let freezer_db = client_config.get_freezer_db_path();
let blobs_db = client_config.get_blobs_db_path();
purge_db(chain_db, freezer_db, blobs_db)?;
} else if cli_args.get_flag("purge-db") {
let stdin_inputs = cfg!(windows) || cli_args.get_flag(STDIN_INPUTS_FLAG);
if std::io::stdin().is_terminal() || stdin_inputs {
info!(
log,
"You are about to delete the chain database. This is irreversable \
and you will need to resync the chain."
);
info!(
log,
"Type 'confirm' to delete the database. Any other input will leave \
the database intact and Lighthouse will exit."
);
let confirmation = read_input_from_user(stdin_inputs)?;
// Remove the freezer db.
let freezer_db = client_config.get_freezer_db_path();
if freezer_db.exists() {
fs::remove_dir_all(freezer_db)
.map_err(|err| format!("Failed to remove freezer_db: {}", err))?;
}
// Remove the blobs db.
let blobs_db = client_config.get_blobs_db_path();
if blobs_db.exists() {
fs::remove_dir_all(blobs_db)
.map_err(|err| format!("Failed to remove blobs_db: {}", err))?;
if confirmation == PURGE_DB_CONFIRMATION {
let chain_db = client_config.get_db_path();
let freezer_db = client_config.get_freezer_db_path();
let blobs_db = client_config.get_blobs_db_path();
purge_db(chain_db, freezer_db, blobs_db)?;
info!(log, "Database was deleted.");
} else {
info!(log, "Database was not deleted. Lighthouse will now close.");
std::process::exit(1);
}
} else {
warn!(
log,
"The `--purge-db` flag was passed, but Lighthouse is not running \
interactively. The database was not purged. Use `--purge-db-force` \
to purge the database without requiring confirmation."
);
}
}
}
@@ -1526,3 +1549,26 @@ where
.next()
.ok_or(format!("Must provide at least one value to {}", flag_name))
}
/// Remove chain, freezer and blobs db.
fn purge_db(chain_db: PathBuf, freezer_db: PathBuf, blobs_db: PathBuf) -> Result<(), String> {
// Remove the chain_db.
if chain_db.exists() {
fs::remove_dir_all(chain_db)
.map_err(|err| format!("Failed to remove chain_db: {}", err))?;
}
// Remove the freezer db.
if freezer_db.exists() {
fs::remove_dir_all(freezer_db)
.map_err(|err| format!("Failed to remove freezer_db: {}", err))?;
}
// Remove the blobs db.
if blobs_db.exists() {
fs::remove_dir_all(blobs_db)
.map_err(|err| format!("Failed to remove blobs_db: {}", err))?;
}
Ok(())
}

View File

@@ -565,7 +565,11 @@ Flags:
being referenced by validator client using the --proposer-node flag.
This configuration is for enabling more secure setups.
--purge-db
If present, the chain database will be deleted. Use with caution.
If present, the chain database will be deleted. Requires manual
confirmation.
--purge-db-force
If present, the chain database will be deleted without confirmation.
Use with caution.
--reconstruct-historic-states
After a checkpoint sync, reconstruct historic states in the database.
This requires syncing all the way back to genesis.
@@ -585,6 +589,8 @@ Flags:
server on localhost:5052 and import deposit logs from the execution
node. This is equivalent to `--http` on merge-ready networks, or
`--http --eth1` pre-merge
--stdin-inputs
If present, read all user inputs from stdin instead of tty.
--subscribe-all-subnets
Subscribe to all subnets regardless of validator count. This will also
advertise the beacon node as being long-lived subscribed to all

View File

@@ -136,6 +136,8 @@ Flags:
contain sensitive information about your validator and so this flag
should be used with caution. For Windows users, the log file
permissions will be inherited from the parent folder.
--stdin-inputs
If present, read all user inputs from stdin instead of tty.
```
<style> .content main {max-width:88%;} </style>

View File

@@ -266,6 +266,8 @@ Flags:
by builders, regardless of payload value.
--produce-block-v3
This flag is deprecated and is no longer in use.
--stdin-inputs
If present, read all user inputs from stdin instead of tty.
--unencrypted-http-transport
This is a safety flag to ensure that the user is aware that the http
transport is unencrypted and using a custom HTTP address is unsafe.

View File

@@ -123,6 +123,8 @@ Flags:
contain sensitive information about your validator and so this flag
should be used with caution. For Windows users, the log file
permissions will be inherited from the parent folder.
--stdin-inputs
If present, read all user inputs from stdin instead of tty.
```
<style> .content main {max-width:88%;} </style>

View File

@@ -121,6 +121,8 @@ Flags:
contain sensitive information about your validator and so this flag
should be used with caution. For Windows users, the log file
permissions will be inherited from the parent folder.
--stdin-inputs
If present, read all user inputs from stdin instead of tty.
```
<style> .content main {max-width:88%;} </style>

View File

@@ -88,8 +88,6 @@ Options:
A HTTP(S) address of a validator client using the keymanager-API. This
validator client is the "source" and contains the validators that are
to be moved.
--stdin-inputs
If present, read all user inputs from stdin instead of tty.
--suggested-fee-recipient <ETH1_ADDRESS>
All created validators will use this value for the suggested fee
recipient. Omit this flag to use the default value from the VC.
@@ -142,6 +140,8 @@ Flags:
contain sensitive information about your validator and so this flag
should be used with caution. For Windows users, the log file
permissions will be inherited from the parent folder.
--stdin-inputs
If present, read all user inputs from stdin instead of tty.
```
<style> .content main {max-width:88%;} </style>

View File

@@ -35,6 +35,8 @@ const DEFAULT_PASSWORD_LEN: usize = 48;
pub const MNEMONIC_PROMPT: &str = "Enter the mnemonic phrase:";
pub const STDIN_INPUTS_FLAG: &str = "stdin-inputs";
/// Returns the "default" path where a wallet should store its password file.
pub fn default_wallet_password_path<P: AsRef<Path>>(wallet_name: &str, secrets_dir: P) -> PathBuf {
secrets_dir.as_ref().join(format!("{}.pass", wallet_name))

View File

@@ -1,6 +1,7 @@
mod cli;
mod metrics;
use account_utils::STDIN_INPUTS_FLAG;
use beacon_node::ProductionBeaconNode;
use clap::FromArgMatches;
use clap::Subcommand;
@@ -104,6 +105,16 @@ fn main() {
)
.long_version(LONG_VERSION.as_str())
.display_order(0)
.arg(
Arg::new(STDIN_INPUTS_FLAG)
.long(STDIN_INPUTS_FLAG)
.action(ArgAction::SetTrue)
.help("If present, read all user inputs from stdin instead of tty.")
.help_heading(FLAG_HEADER)
.hide(cfg!(windows))
.global(true)
.display_order(0),
)
.arg(
Arg::new("env_log")
.short('l')

View File

@@ -15,7 +15,7 @@ use account_manager::{
use account_utils::{
eth2_keystore::KeystoreBuilder,
validator_definitions::{SigningDefinition, ValidatorDefinition, ValidatorDefinitions},
ZeroizeString,
ZeroizeString, STDIN_INPUTS_FLAG,
};
use slashing_protection::{SlashingDatabase, SLASHING_PROTECTION_FILENAME};
use std::env;

View File

@@ -1,3 +1,4 @@
pub use account_utils::STDIN_INPUTS_FLAG;
use account_utils::{strip_off_newlines, ZeroizeString};
use eth2::lighthouse_vc::std_types::{InterchangeJsonStr, KeystoreJsonStr};
use eth2::{
@@ -15,7 +16,6 @@ use tree_hash::TreeHash;
use types::*;
pub const IGNORE_DUPLICATES_FLAG: &str = "ignore-duplicates";
pub const STDIN_INPUTS_FLAG: &str = "stdin-inputs";
pub const COUNT_FLAG: &str = "count";
/// When the `ethereum/staking-deposit-cli` tool generates deposit data JSON, it adds a

View File

@@ -105,15 +105,6 @@ pub fn cli_app() -> Command {
.action(ArgAction::Set)
.display_order(0),
)
.arg(
Arg::new(STDIN_INPUTS_FLAG)
.action(ArgAction::SetTrue)
.hide(cfg!(windows))
.long(STDIN_INPUTS_FLAG)
.help("If present, read all user inputs from stdin instead of tty.")
.display_order(0)
.help_heading(FLAG_HEADER),
)
.arg(
Arg::new(DISABLE_DEPOSITS_FLAG)
.long(DISABLE_DEPOSITS_FLAG)

View File

@@ -184,14 +184,6 @@ pub fn cli_app() -> Command {
.action(ArgAction::Set)
.display_order(0),
)
.arg(
Arg::new(STDIN_INPUTS_FLAG)
.action(ArgAction::SetTrue)
.hide(cfg!(windows))
.long(STDIN_INPUTS_FLAG)
.help("If present, read all user inputs from stdin instead of tty.")
.display_order(0),
)
.arg(
Arg::new(BUILDER_BOOST_FACTOR_FLAG)
.long(BUILDER_BOOST_FACTOR_FLAG)