Skip to content

Commit

Permalink
Require manual confirmation to purge database with purge-db (#6154)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
macladson authored Aug 20, 2024
1 parent d957161 commit 32f2e05
Show file tree
Hide file tree
Showing 22 changed files with 117 additions and 105 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 1 addition & 11 deletions account_manager/src/validator/create.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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>(
Expand Down
11 changes: 1 addition & 10 deletions account_manager/src/validator/exit.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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> {
Expand Down
13 changes: 2 additions & 11 deletions account_manager/src/validator/import.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
12 changes: 1 addition & 11 deletions account_manager/src/validator/recover.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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> {
Expand Down
10 changes: 1 addition & 9 deletions account_manager/src/wallet/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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,
Expand Down Expand Up @@ -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)
Expand Down
12 changes: 2 additions & 10 deletions account_manager/src/wallet/recover.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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> {
Expand Down
1 change: 1 addition & 0 deletions beacon_node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ sensitive_url = { workspace = true }
http_api = { workspace = true }
unused_port = { workspace = true }
strum = { workspace = true }
account_utils = { workspace = true }
10 changes: 9 additions & 1 deletion beacon_node/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
86 changes: 66 additions & 20 deletions beacon_node/src/config.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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;
Expand All @@ -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`.
Expand All @@ -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))?;
}

// 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 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)?;

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."
);
}
}
}

Expand Down Expand Up @@ -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(())
}
8 changes: 7 additions & 1 deletion book/src/help_bn.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions book/src/help_general.md
Original file line number Diff line number Diff line change
Expand Up @@ -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>
2 changes: 2 additions & 0 deletions book/src/help_vc.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions book/src/help_vm.md
Original file line number Diff line number Diff line change
Expand Up @@ -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>
2 changes: 2 additions & 0 deletions book/src/help_vm_import.md
Original file line number Diff line number Diff line change
Expand Up @@ -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>
4 changes: 2 additions & 2 deletions book/src/help_vm_move.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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>
2 changes: 2 additions & 0 deletions common/account_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
Loading

0 comments on commit 32f2e05

Please sign in to comment.