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

Diff for: Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: account_manager/src/validator/create.rs

+1-11
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>(

Diff for: account_manager/src/validator/exit.rs

+1-10
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> {

Diff for: account_manager/src/validator/import.rs

+2-11
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)

Diff for: account_manager/src/validator/recover.rs

+1-11
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> {

Diff for: account_manager/src/wallet/create.rs

+1-9
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)

Diff for: account_manager/src/wallet/recover.rs

+2-10
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> {

Diff for: beacon_node/Cargo.toml

+1
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 }

Diff for: beacon_node/src/cli.rs

+9-1
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(

Diff for: beacon_node/src/config.rs

+66-20
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+
}

Diff for: book/src/help_bn.md

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

Diff for: book/src/help_general.md

+2
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ Flags:
136136
contain sensitive information about your validator and so this flag
137137
should be used with caution. For Windows users, the log file
138138
permissions will be inherited from the parent folder.
139+
--stdin-inputs
140+
If present, read all user inputs from stdin instead of tty.
139141
```
140142

141143
<style> .content main {max-width:88%;} </style>

Diff for: book/src/help_vc.md

+2
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,8 @@ Flags:
266266
by builders, regardless of payload value.
267267
--produce-block-v3
268268
This flag is deprecated and is no longer in use.
269+
--stdin-inputs
270+
If present, read all user inputs from stdin instead of tty.
269271
--unencrypted-http-transport
270272
This is a safety flag to ensure that the user is aware that the http
271273
transport is unencrypted and using a custom HTTP address is unsafe.

Diff for: book/src/help_vm.md

+2
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ Flags:
123123
contain sensitive information about your validator and so this flag
124124
should be used with caution. For Windows users, the log file
125125
permissions will be inherited from the parent folder.
126+
--stdin-inputs
127+
If present, read all user inputs from stdin instead of tty.
126128
```
127129

128130
<style> .content main {max-width:88%;} </style>

Diff for: book/src/help_vm_import.md

+2
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ Flags:
121121
contain sensitive information about your validator and so this flag
122122
should be used with caution. For Windows users, the log file
123123
permissions will be inherited from the parent folder.
124+
--stdin-inputs
125+
If present, read all user inputs from stdin instead of tty.
124126
```
125127

126128
<style> .content main {max-width:88%;} </style>

Diff for: book/src/help_vm_move.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,6 @@ Options:
8888
A HTTP(S) address of a validator client using the keymanager-API. This
8989
validator client is the "source" and contains the validators that are
9090
to be moved.
91-
--stdin-inputs
92-
If present, read all user inputs from stdin instead of tty.
9391
--suggested-fee-recipient <ETH1_ADDRESS>
9492
All created validators will use this value for the suggested fee
9593
recipient. Omit this flag to use the default value from the VC.
@@ -142,6 +140,8 @@ Flags:
142140
contain sensitive information about your validator and so this flag
143141
should be used with caution. For Windows users, the log file
144142
permissions will be inherited from the parent folder.
143+
--stdin-inputs
144+
If present, read all user inputs from stdin instead of tty.
145145
```
146146

147147
<style> .content main {max-width:88%;} </style>

Diff for: common/account_utils/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ const DEFAULT_PASSWORD_LEN: usize = 48;
3535

3636
pub const MNEMONIC_PROMPT: &str = "Enter the mnemonic phrase:";
3737

38+
pub const STDIN_INPUTS_FLAG: &str = "stdin-inputs";
39+
3840
/// Returns the "default" path where a wallet should store its password file.
3941
pub fn default_wallet_password_path<P: AsRef<Path>>(wallet_name: &str, secrets_dir: P) -> PathBuf {
4042
secrets_dir.as_ref().join(format!("{}.pass", wallet_name))

0 commit comments

Comments
 (0)