Skip to content

Commit 32f2e05

Browse files
authored
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
1 parent d957161 commit 32f2e05

File tree

22 files changed

+117
-105
lines changed

22 files changed

+117
-105
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

account_manager/src/validator/create.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::common::read_wallet_name_from_cli;
2-
use crate::wallet::create::STDIN_INPUTS_FLAG;
32
use crate::{SECRETS_DIR_FLAG, WALLETS_DIR_FLAG};
43
use account_utils::{
54
random_password, read_password_from_user, strip_off_newlines, validator_definitions, PlainText,
5+
STDIN_INPUTS_FLAG,
66
};
77
use clap::{Arg, ArgAction, ArgMatches, Command};
88
use clap_utils::FLAG_HEADER;
@@ -114,16 +114,6 @@ pub fn cli_app() -> Command {
114114
.action(ArgAction::Set)
115115
.display_order(0)
116116
)
117-
.arg(
118-
Arg::new(STDIN_INPUTS_FLAG)
119-
.action(ArgAction::SetTrue)
120-
.help_heading(FLAG_HEADER)
121-
.hide(cfg!(windows))
122-
.long(STDIN_INPUTS_FLAG)
123-
.help("If present, read all user inputs from stdin instead of tty.")
124-
.display_order(0)
125-
.action(ArgAction::SetTrue)
126-
)
127117
}
128118

129119
pub fn cli_run<E: EthSpec>(

account_manager/src/validator/exit.rs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::wallet::create::STDIN_INPUTS_FLAG;
1+
use account_utils::STDIN_INPUTS_FLAG;
22
use bls::{Keypair, PublicKey};
33
use clap::{Arg, ArgAction, ArgMatches, Command};
44
use clap_utils::FLAG_HEADER;
@@ -74,15 +74,6 @@ pub fn cli_app() -> Command {
7474
.action(ArgAction::SetTrue)
7575
.help_heading(FLAG_HEADER)
7676
)
77-
.arg(
78-
Arg::new(STDIN_INPUTS_FLAG)
79-
.action(ArgAction::SetTrue)
80-
.help_heading(FLAG_HEADER)
81-
.hide(cfg!(windows))
82-
.long(STDIN_INPUTS_FLAG)
83-
.help("If present, read all user inputs from stdin instead of tty.")
84-
.display_order(0)
85-
)
8677
}
8778

8879
pub fn cli_run<E: EthSpec>(matches: &ArgMatches, env: Environment<E>) -> Result<(), String> {

account_manager/src/validator/import.rs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::wallet::create::{PASSWORD_FLAG, STDIN_INPUTS_FLAG};
1+
use crate::wallet::create::PASSWORD_FLAG;
22
use account_utils::validator_definitions::SigningDefinition;
33
use account_utils::{
44
eth2_keystore::Keystore,
@@ -7,7 +7,7 @@ use account_utils::{
77
recursively_find_voting_keystores, PasswordStorage, ValidatorDefinition,
88
ValidatorDefinitions, CONFIG_FILENAME,
99
},
10-
ZeroizeString,
10+
ZeroizeString, STDIN_INPUTS_FLAG,
1111
};
1212
use clap::{Arg, ArgAction, ArgMatches, Command};
1313
use clap_utils::FLAG_HEADER;
@@ -59,15 +59,6 @@ pub fn cli_app() -> Command {
5959
.action(ArgAction::Set)
6060
.display_order(0),
6161
)
62-
.arg(
63-
Arg::new(STDIN_INPUTS_FLAG)
64-
.action(ArgAction::SetTrue)
65-
.help_heading(FLAG_HEADER)
66-
.hide(cfg!(windows))
67-
.long(STDIN_INPUTS_FLAG)
68-
.help("If present, read all user inputs from stdin instead of tty.")
69-
.display_order(0),
70-
)
7162
.arg(
7263
Arg::new(REUSE_PASSWORD_FLAG)
7364
.long(REUSE_PASSWORD_FLAG)

account_manager/src/validator/recover.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use super::create::STORE_WITHDRAW_FLAG;
22
use crate::validator::create::COUNT_FLAG;
3-
use crate::wallet::create::STDIN_INPUTS_FLAG;
43
use crate::SECRETS_DIR_FLAG;
54
use account_utils::eth2_keystore::{keypair_from_secret, Keystore, KeystoreBuilder};
6-
use account_utils::{random_password, read_mnemonic_from_cli};
5+
use account_utils::{random_password, read_mnemonic_from_cli, STDIN_INPUTS_FLAG};
76
use clap::{Arg, ArgAction, ArgMatches, Command};
87
use clap_utils::FLAG_HEADER;
98
use directory::ensure_dir_exists;
@@ -76,15 +75,6 @@ pub fn cli_app() -> Command {
7675
.help_heading(FLAG_HEADER)
7776
.display_order(0)
7877
)
79-
.arg(
80-
Arg::new(STDIN_INPUTS_FLAG)
81-
.action(ArgAction::SetTrue)
82-
.help_heading(FLAG_HEADER)
83-
.hide(cfg!(windows))
84-
.long(STDIN_INPUTS_FLAG)
85-
.help("If present, read all user inputs from stdin instead of tty.")
86-
.display_order(0)
87-
)
8878
}
8979

9080
pub fn cli_run(matches: &ArgMatches, validator_dir: PathBuf) -> Result<(), String> {

account_manager/src/wallet/create.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::common::read_wallet_name_from_cli;
22
use crate::WALLETS_DIR_FLAG;
33
use account_utils::{
44
is_password_sufficiently_complex, random_password, read_password_from_user, strip_off_newlines,
5+
STDIN_INPUTS_FLAG,
56
};
67
use clap::{Arg, ArgAction, ArgMatches, Command};
78
use eth2_wallet::{
@@ -20,7 +21,6 @@ pub const NAME_FLAG: &str = "name";
2021
pub const PASSWORD_FLAG: &str = "password-file";
2122
pub const TYPE_FLAG: &str = "type";
2223
pub const MNEMONIC_FLAG: &str = "mnemonic-output-path";
23-
pub const STDIN_INPUTS_FLAG: &str = "stdin-inputs";
2424
pub const MNEMONIC_LENGTH_FLAG: &str = "mnemonic-length";
2525
pub const MNEMONIC_TYPES: &[MnemonicType] = &[
2626
MnemonicType::Words12,
@@ -83,14 +83,6 @@ pub fn cli_app() -> Command {
8383
.action(ArgAction::Set)
8484
.display_order(0)
8585
)
86-
.arg(
87-
Arg::new(STDIN_INPUTS_FLAG)
88-
.action(ArgAction::SetTrue)
89-
.hide(cfg!(windows))
90-
.long(STDIN_INPUTS_FLAG)
91-
.help("If present, read all user inputs from stdin instead of tty.")
92-
.display_order(0)
93-
)
9486
.arg(
9587
Arg::new(MNEMONIC_LENGTH_FLAG)
9688
.long(MNEMONIC_LENGTH_FLAG)

account_manager/src/wallet/recover.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use crate::wallet::create::{create_wallet_from_mnemonic, STDIN_INPUTS_FLAG};
1+
use crate::wallet::create::create_wallet_from_mnemonic;
22
use crate::wallet::create::{HD_TYPE, NAME_FLAG, PASSWORD_FLAG, TYPE_FLAG};
3-
use account_utils::read_mnemonic_from_cli;
3+
use account_utils::{read_mnemonic_from_cli, STDIN_INPUTS_FLAG};
44
use clap::{Arg, ArgAction, ArgMatches, Command};
55
use std::path::PathBuf;
66

@@ -56,14 +56,6 @@ pub fn cli_app() -> Command {
5656
.default_value(HD_TYPE)
5757
.display_order(0),
5858
)
59-
.arg(
60-
Arg::new(STDIN_INPUTS_FLAG)
61-
.action(ArgAction::SetTrue)
62-
.hide(cfg!(windows))
63-
.long(STDIN_INPUTS_FLAG)
64-
.help("If present, read all user inputs from stdin instead of tty.")
65-
.display_order(0),
66-
)
6759
}
6860

6961
pub fn cli_run(matches: &ArgMatches, wallet_base_dir: PathBuf) -> Result<(), String> {

beacon_node/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,4 @@ sensitive_url = { workspace = true }
4444
http_api = { workspace = true }
4545
unused_port = { workspace = true }
4646
strum = { workspace = true }
47+
account_utils = { workspace = true }

beacon_node/src/cli.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,15 @@ pub fn cli_app() -> Command {
919919
.long("purge-db")
920920
.action(ArgAction::SetTrue)
921921
.help_heading(FLAG_HEADER)
922-
.help("If present, the chain database will be deleted. Use with caution.")
922+
.help("If present, the chain database will be deleted. Requires manual confirmation.")
923+
.display_order(0)
924+
)
925+
.arg(
926+
Arg::new("purge-db-force")
927+
.long("purge-db-force")
928+
.action(ArgAction::SetTrue)
929+
.help_heading(FLAG_HEADER)
930+
.help("If present, the chain database will be deleted without confirmation. Use with caution.")
923931
.display_order(0)
924932
)
925933
.arg(

beacon_node/src/config.rs

Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use account_utils::{read_input_from_user, STDIN_INPUTS_FLAG};
12
use beacon_chain::chain_config::{
23
DisallowedReOrgOffsets, ReOrgThreshold, DEFAULT_PREPARE_PAYLOAD_LOOKAHEAD_FACTOR,
34
DEFAULT_RE_ORG_HEAD_THRESHOLD, DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION,
@@ -21,6 +22,7 @@ use slog::{info, warn, Logger};
2122
use std::cmp::max;
2223
use std::fmt::Debug;
2324
use std::fs;
25+
use std::io::IsTerminal;
2426
use std::net::Ipv6Addr;
2527
use std::net::{IpAddr, Ipv4Addr, ToSocketAddrs};
2628
use std::num::NonZeroU16;
@@ -30,6 +32,8 @@ use std::time::Duration;
3032
use types::graffiti::GraffitiString;
3133
use types::{Checkpoint, Epoch, EthSpec, Hash256, PublicKeyBytes};
3234

35+
const PURGE_DB_CONFIRMATION: &str = "confirm";
36+
3337
/// Gets the fully-initialized global client.
3438
///
3539
/// The top-level `clap` arguments should be provided as `cli_args`.
@@ -50,26 +54,45 @@ pub fn get_config<E: EthSpec>(
5054
client_config.set_data_dir(get_data_dir(cli_args));
5155

5256
// If necessary, remove any existing database and configuration
53-
if client_config.data_dir().exists() && cli_args.get_flag("purge-db") {
54-
// Remove the chain_db.
55-
let chain_db = client_config.get_db_path();
56-
if chain_db.exists() {
57-
fs::remove_dir_all(chain_db)
58-
.map_err(|err| format!("Failed to remove chain_db: {}", err))?;
59-
}
60-
61-
// Remove the freezer db.
62-
let freezer_db = client_config.get_freezer_db_path();
63-
if freezer_db.exists() {
64-
fs::remove_dir_all(freezer_db)
65-
.map_err(|err| format!("Failed to remove freezer_db: {}", err))?;
66-
}
67-
68-
// Remove the blobs db.
69-
let blobs_db = client_config.get_blobs_db_path();
70-
if blobs_db.exists() {
71-
fs::remove_dir_all(blobs_db)
72-
.map_err(|err| format!("Failed to remove blobs_db: {}", err))?;
57+
if client_config.data_dir().exists() {
58+
if cli_args.get_flag("purge-db-force") {
59+
let chain_db = client_config.get_db_path();
60+
let freezer_db = client_config.get_freezer_db_path();
61+
let blobs_db = client_config.get_blobs_db_path();
62+
purge_db(chain_db, freezer_db, blobs_db)?;
63+
} else if cli_args.get_flag("purge-db") {
64+
let stdin_inputs = cfg!(windows) || cli_args.get_flag(STDIN_INPUTS_FLAG);
65+
if std::io::stdin().is_terminal() || stdin_inputs {
66+
info!(
67+
log,
68+
"You are about to delete the chain database. This is irreversable \
69+
and you will need to resync the chain."
70+
);
71+
info!(
72+
log,
73+
"Type 'confirm' to delete the database. Any other input will leave \
74+
the database intact and Lighthouse will exit."
75+
);
76+
let confirmation = read_input_from_user(stdin_inputs)?;
77+
78+
if confirmation == PURGE_DB_CONFIRMATION {
79+
let chain_db = client_config.get_db_path();
80+
let freezer_db = client_config.get_freezer_db_path();
81+
let blobs_db = client_config.get_blobs_db_path();
82+
purge_db(chain_db, freezer_db, blobs_db)?;
83+
info!(log, "Database was deleted.");
84+
} else {
85+
info!(log, "Database was not deleted. Lighthouse will now close.");
86+
std::process::exit(1);
87+
}
88+
} else {
89+
warn!(
90+
log,
91+
"The `--purge-db` flag was passed, but Lighthouse is not running \
92+
interactively. The database was not purged. Use `--purge-db-force` \
93+
to purge the database without requiring confirmation."
94+
);
95+
}
7396
}
7497
}
7598

@@ -1526,3 +1549,26 @@ where
15261549
.next()
15271550
.ok_or(format!("Must provide at least one value to {}", flag_name))
15281551
}
1552+
1553+
/// Remove chain, freezer and blobs db.
1554+
fn purge_db(chain_db: PathBuf, freezer_db: PathBuf, blobs_db: PathBuf) -> Result<(), String> {
1555+
// Remove the chain_db.
1556+
if chain_db.exists() {
1557+
fs::remove_dir_all(chain_db)
1558+
.map_err(|err| format!("Failed to remove chain_db: {}", err))?;
1559+
}
1560+
1561+
// Remove the freezer db.
1562+
if freezer_db.exists() {
1563+
fs::remove_dir_all(freezer_db)
1564+
.map_err(|err| format!("Failed to remove freezer_db: {}", err))?;
1565+
}
1566+
1567+
// Remove the blobs db.
1568+
if blobs_db.exists() {
1569+
fs::remove_dir_all(blobs_db)
1570+
.map_err(|err| format!("Failed to remove blobs_db: {}", err))?;
1571+
}
1572+
1573+
Ok(())
1574+
}

0 commit comments

Comments
 (0)