Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add voluntary exit via validator manager #6612

Open
wants to merge 62 commits into
base: unstable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
537c9c8
Exit validator
chong-he Nov 26, 2024
f6d6663
minor fix
chong-he Nov 28, 2024
30c9c8e
Revert "minor fix"
chong-he Nov 28, 2024
36a85e0
Test
chong-he Nov 29, 2024
3c7548c
Spec for vc
chong-he Nov 29, 2024
b40b1b1
Ensure time and genesis validators root match
michaelsproul Dec 3, 2024
036473f
Merge branch 'unstable' into vm-voluntary-exit
chong-he Dec 10, 2024
6f11781
Remove types
chong-he Dec 11, 2024
585498d
make cli
chong-he Dec 11, 2024
4f6426f
Cargo.lock
chong-he Dec 11, 2024
d4bc9f6
Merge branch 'vm-voluntary-exit' of https://github.com/chong-he/light…
chong-he Dec 11, 2024
d9c423d
Add exit multiple validators
chong-he Dec 11, 2024
0301d55
Add "all" to exit all validators
chong-he Dec 12, 2024
63b9a08
check if beacon node is syncing
chong-he Dec 13, 2024
b2b6442
Add validator status after exit
chong-he Dec 16, 2024
28fec0a
For testing
chong-he Dec 16, 2024
04f85e2
Display signature only when the flag is used
chong-he Dec 16, 2024
0f268d7
Merge branch 'vm-voluntary-exit' of https://github.com/chong-he/light…
chong-he Dec 16, 2024
e5d16ec
Fix signature flag
chong-he Dec 16, 2024
93e47b2
Fix signature flag
chong-he Dec 16, 2024
375f8a2
signature flag
chong-he Dec 17, 2024
d7421b0
Add test to lighthouse/tests
chong-he Dec 17, 2024
19f9fe0
Merge branch 'unstable' into vm-voluntary-exit
chong-he Dec 17, 2024
6bf8d58
Update test to compile
chong-he Dec 17, 2024
e4a99d8
simplify
chong-he Dec 17, 2024
48d1a02
Add exit multiple validators
chong-he Dec 17, 2024
8556f85
reduce diff
chong-he Dec 17, 2024
ba45cc5
Add delete all validators
chong-he Dec 17, 2024
97bddf8
update validator data
chong-he Dec 17, 2024
84a70a9
Improve UX
chong-he Dec 17, 2024
2789436
Merge branch 'unstable' into vm-voluntary-exit
chong-he Dec 17, 2024
b417e92
Improve UX sleep only once
chong-he Dec 18, 2024
45932ed
cli
chong-he Dec 18, 2024
f00a347
make cli
chong-he Dec 18, 2024
8d4b6a4
update validator data
chong-he Dec 18, 2024
871692a
remove loop
chong-he Dec 18, 2024
872daed
Add exit status
chong-he Dec 18, 2024
a5f4d2d
Minor fix
chong-he Dec 18, 2024
f8f94b9
Add doc
chong-he Dec 18, 2024
f935b9f
mdlint
chong-he Dec 18, 2024
d1d6442
Update lighthouse/tests
chong-he Dec 18, 2024
02f09d5
Simplify by remove print in test
chong-he Dec 18, 2024
2ee5498
remove debug
chong-he Dec 18, 2024
584c682
Merge branch 'unstable' into vm-voluntary-exit
chong-he Dec 19, 2024
47419b3
Add dependency
chong-he Dec 19, 2024
5a4f928
save exit message to a file
chong-he Dec 19, 2024
6cdc908
Add merge messages to one file
chong-he Dec 20, 2024
2b0163f
fmt
chong-he Dec 20, 2024
6a70f4e
Update doc
chong-he Dec 20, 2024
d327c59
Add more assert in test
chong-he Jan 6, 2025
6fb971e
Merge branch 'unstable' into vm-voluntary-exit
chong-he Jan 6, 2025
2f6ebe1
Merge branch 'unstable' into vm-voluntary-exit
chong-he Jan 22, 2025
419eda7
Remove --merge flag
chong-he Jan 22, 2025
b579d40
revise
chong-he Jan 22, 2025
2407965
Move check status to list_validator
chong-he Jan 23, 2025
6f41a19
Fix test
chong-he Jan 23, 2025
2c96cad
Update doc
chong-he Jan 23, 2025
4fb9f53
mdlint
chong-he Jan 23, 2025
683259d
udpate doc and flags
chong-he Jan 24, 2025
681feeb
Add presign in wordlist.txt
chong-he Jan 24, 2025
929335a
Add cli test
chong-he Jan 25, 2025
49e30fd
rename a bit
chong-he Jan 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.lock

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

4 changes: 4 additions & 0 deletions book/src/help_vm.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ Commands:
delete
Deletes one or more validators from a validator client using the HTTP
API.
exit
Exits one or more validators using the HTTP API. It can also be used
to generate a presign voluntary exit message for a particular future
epoch.
help
Print this message or the help of the given subcommand(s)

Expand Down
79 changes: 78 additions & 1 deletion book/src/validator-manager-api.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,54 @@
# Managing Validators

The `lighthouse validator-manager` uses the [Keymanager API](https://ethereum.github.io/keymanager-APIs/#/) to list, import and delete keystores via the HTTP API. This requires the validator client running with the flag `--http`.
The `lighthouse validator-manager` uses the [Keymanager API](https://ethereum.github.io/keymanager-APIs/#/) to exit, list, import and delete keystores via the HTTP API. This requires the validator client running with the flag `--http`.

## Exit

The `exit` command exits one or more validators from the validator client. To `exit`:

> **Important note: Once the --beacon-node flag is used, it will publish the voluntary exit to the network. This action is irreversible.**

```bash
lighthouse vm exit --vc-token <API-TOKEN-PATH> --validators pubkey1,pubkey2 --beacon-node http://beacon-node-url:5052
```

Example:

```bash
lighthouse vm exit --vc-token ~/.lighthouse/mainnet/validators/api-token.txt --validators 0x8885c29b8f88ee9b9a37b480fd4384fed74bda33d85bc8171a904847e65688b6c9bb4362d6597fd30109fb2def6c3ae4,0xa262dae3dcd2b2e280af534effa16bedb27c06f2959e114d53bd2a248ca324a018dc73179899a066149471a94a1bc92f --beacon-node http://localhost:5052
```

If successful, the following log will be returned:

```text
Successfully validated and published voluntary exit for validator 0x8885c29b8f88ee9b9a37b480fd4384fed74bda33d85bc8171a904847e65688b6c9bb4362d6597fd30109fb2def6c3ae4
Successfully validated and published voluntary exit for validator
0xa262dae3dcd2b2e280af534effa16bedb27c06f2959e114d53bd2a248ca324a018dc73179899a066149471a94a1bc92f
```

To exit all validators on the validator client, use the keyword `all`:

```bash
lighthouse vm exit --vc-token ~/.lighthouse/mainnet/validators/api-token.txt --validators all --beacon-node http://localhost:5052
```

To check the voluntary exit status, refer to [the list command](./validator-manager-api.md#list).

The following command will only generate a presign voluntary exit message and save it to a file named `{validator_pubkey}.json`. It **will not** publish the voluntary exit to the network.

To generate a presign exit message and save it to a file, use the flag `--presign`:

```bash
lighthouse vm exit --vc-token ~/.lighthouse/mainnet/validators/api-token.txt --validators all --presign
```

To generate a presign exit message for a particular (future) epoch, use the flag `--exit-epoch`:

```bash
lighthouse vm exit --vc-token ~/.lighthouse/mainnet/validators/api-token.txt --validators all --presign --exit-epoch 1234567
```

The generated presign exit message will only be valid at or after the specified exit-epoch, in this case, epoch 1234567.

## Delete

Expand All @@ -16,6 +64,12 @@ Example:
lighthouse vm delete --vc-token ~/.lighthouse/mainnet/validators/api-token.txt --validators 0x8885c29b8f88ee9b9a37b480fd4384fed74bda33d85bc8171a904847e65688b6c9bb4362d6597fd30109fb2def6c3ae4,0xa262dae3dcd2b2e280af534effa16bedb27c06f2959e114d53bd2a248ca324a018dc73179899a066149471a94a1bc92f
```

To delete all validators on the validator client, use the keyword `all`:

```bash
lighthouse vm delete --vc-token ~/.lighthouse/mainnet/validators/api-token.txt --validators all
```

## Import

The `import` command imports validator keystores generated by the staking-deposit-cli/ethstaker-deposit-cli. To import a validator keystore:
Expand All @@ -37,3 +91,26 @@ To list the validators running on the validator client:
```bash
lighthouse vm list --vc-token ~/.lighthouse/mainnet/validators/api-token.txt
```

The `list` command can also be used to check the voluntary exit status of validators. To do so, use both `--beacon-node` and `--validators` flags. The `--validators` flag accepts a comma-separated list of validator public keys, or the keyword `all` to check the voluntary exit status of all validators attached to the validator client.

```bash
lighthouse vm list --vc-token ~/.lighthouse/mainnet/validators/api-token.txt --validators 0x8de7ec501d574152f52a962bf588573df2fc3563fd0c6077651208ed20f24f3d8572425706b343117b48bdca56808416 --beacon-node http://localhost:5052
```

If the validator voluntary exit has been accepted by the chain, the following log will be returned:

```text
Voluntary exit for validator 0x8de7ec501d574152f52a962bf588573df2fc3563fd0c6077651208ed20f24f3d8572425706b343117b48bdca56808416 has been accepted into the beacon chain, but not yet finalized. Finalization may take several minutes or longer. Before finalization there is a low probability that the exit may be reverted.
Current epoch: 2, Exit epoch: 7, Withdrawable epoch: 263
Please keep your validator running till exit epoch
Exit epoch in approximately 480 secs
```

When the exit epoch is reached, querying the status will return:

```text
Validator 0x8de7ec501d574152f52a962bf588573df2fc3563fd0c6077651208ed20f24f3d8572425706b343117b48bdca56808416 has exited at epoch: 7
```

You can safely shut down the validator client at this point.
2 changes: 1 addition & 1 deletion book/src/validator-manager.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ The `validator-manager` boasts the following features:

- [Creating and importing validators using the `create` and `import` commands.](./validator-manager-create.md)
- [Moving validators between two VCs using the `move` command.](./validator-manager-move.md)
- [Managing validators such as delete, import and list validators.](./validator-manager-api.md)
- [Managing validators such as exit, delete, import and list validators.](./validator-manager-api.md)
2 changes: 2 additions & 0 deletions book/src/voluntary-exit.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ A validator can initiate a voluntary exit provided that the validator is current
It takes at a minimum 5 epochs (32 minutes) for a validator to exit after initiating a voluntary exit.
This number can be much higher depending on how many other validators are queued to exit.

You can also perform voluntary exit for one or more validators using the validator manager, see [Managing Validators](./validator-manager-api.md#exit) for more details.

## Initiating a voluntary exit

In order to initiate an exit, users can use the `lighthouse account validator exit` command.
Expand Down
112 changes: 112 additions & 0 deletions lighthouse/tests/validator_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use types::*;
use validator_manager::{
create_validators::CreateConfig,
delete_validators::DeleteConfig,
exit_validators::ExitConfig,
import_validators::ImportConfig,
list_validators::ListConfig,
move_validators::{MoveConfig, PasswordSource, Validators},
Expand Down Expand Up @@ -119,6 +120,12 @@ impl CommandLineTest<DeleteConfig> {
}
}

impl CommandLineTest<ExitConfig> {
fn validators_exit() -> Self {
Self::default().flag("exit", None)
}
}

#[test]
pub fn validator_create_without_output_path() {
CommandLineTest::validators_create().assert_failed();
Expand Down Expand Up @@ -443,6 +450,8 @@ pub fn validator_list_defaults() {
let expected = ListConfig {
vc_url: SensitiveUrl::parse("http://localhost:5062").unwrap(),
vc_token_path: PathBuf::from("./token.json"),
beacon_url: None,
validators_to_display: vec![],
};
assert_eq!(expected, config);
});
Expand All @@ -468,3 +477,106 @@ pub fn validator_delete_defaults() {
assert_eq!(expected, config);
});
}

#[test]
pub fn validator_delete_missing_validator_flag() {
CommandLineTest::validators_delete()
.flag("--vc-token", Some("./token.json"))
.assert_failed();
}

#[test]
pub fn validator_exit_defaults() {
CommandLineTest::validators_exit()
.flag(
"--validators",
Some(&format!("{},{}", EXAMPLE_PUBKEY_0, EXAMPLE_PUBKEY_1)),
)
.flag("--vc-token", Some("./token.json"))
.flag("--beacon-node", Some("http://localhost:5052"))
.assert_success(|config| {
let expected = ExitConfig {
vc_url: SensitiveUrl::parse("http://localhost:5062").unwrap(),
vc_token_path: PathBuf::from("./token.json"),
validators_to_exit: vec![
PublicKeyBytes::from_str(EXAMPLE_PUBKEY_0).unwrap(),
PublicKeyBytes::from_str(EXAMPLE_PUBKEY_1).unwrap(),
],
beacon_url: Some(SensitiveUrl::parse("http://localhost:5052").unwrap()),
exit_epoch: None,
presign: false,
};
assert_eq!(expected, config);
});
}

#[test]
pub fn validator_exit_exit_epoch_and_presign_flags() {
CommandLineTest::validators_exit()
.flag(
"--validators",
Some(&format!("{},{}", EXAMPLE_PUBKEY_0, EXAMPLE_PUBKEY_1)),
)
.flag("--vc-token", Some("./token.json"))
.flag("--exit-epoch", Some("1234567"))
.flag("--presign", None)
.assert_success(|config| {
let expected = ExitConfig {
vc_url: SensitiveUrl::parse("http://localhost:5062").unwrap(),
vc_token_path: PathBuf::from("./token.json"),
validators_to_exit: vec![
PublicKeyBytes::from_str(EXAMPLE_PUBKEY_0).unwrap(),
PublicKeyBytes::from_str(EXAMPLE_PUBKEY_1).unwrap(),
],
beacon_url: None,
exit_epoch: Some(Epoch::new(1234567)),
presign: true,
};
assert_eq!(expected, config);
});
}

#[test]
pub fn validator_exit_missing_validator_flag() {
CommandLineTest::validators_exit()
.flag("--vc-token", Some("./token.json"))
.assert_failed();
}

#[test]
pub fn validator_exit_using_beacon_and_presign_flags() {
CommandLineTest::validators_exit()
.flag("--vc-token", Some("./token.json"))
.flag(
"--validators",
Some(&format!("{},{}", EXAMPLE_PUBKEY_0, EXAMPLE_PUBKEY_1)),
)
.flag("--beacon-node", Some("http://localhost:1001"))
.flag("--presign", None)
.assert_failed();
}

#[test]
pub fn validator_exit_using_beacon_and_exit_epoch_flags() {
CommandLineTest::validators_exit()
.flag("--vc-token", Some("./token.json"))
.flag(
"--validators",
Some(&format!("{},{}", EXAMPLE_PUBKEY_0, EXAMPLE_PUBKEY_1)),
)
.flag("--beacon-node", Some("http://localhost:1001"))
.flag("--exit-epoch", Some("1234567"))
.assert_failed();
}

#[test]
pub fn validator_exit_exit_epoch_flag_without_presign_flag() {
CommandLineTest::validators_exit()
.flag("--vc-token", Some("./token.json"))
.flag(
"--validators",
Some(&format!("{},{}", EXAMPLE_PUBKEY_0, EXAMPLE_PUBKEY_1)),
)
.flag("--exit-epoch", Some("1234567"))
.assert_failed();
}
25 changes: 18 additions & 7 deletions validator_client/http_api/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use std::time::Duration;
use task_executor::test_utils::TestRuntime;
use tempfile::{tempdir, TempDir};
use tokio::sync::oneshot;
use types::ChainSpec;
use validator_store::{Config as ValidatorStoreConfig, ValidatorStore};
use zeroize::Zeroizing;

Expand Down Expand Up @@ -62,6 +63,7 @@ pub struct ApiTester {
pub _server_shutdown: oneshot::Sender<()>,
pub validator_dir: TempDir,
pub secrets_dir: TempDir,
pub spec: Arc<ChainSpec>,
}

impl ApiTester {
Expand All @@ -70,6 +72,19 @@ impl ApiTester {
}

pub async fn new_with_http_config(http_config: HttpConfig) -> Self {
let slot_clock =
TestingSlotClock::new(Slot::new(0), Duration::from_secs(0), Duration::from_secs(1));
let genesis_validators_root = Hash256::repeat_byte(42);
let spec = Arc::new(E::default_spec());
Self::new_with_options(http_config, slot_clock, genesis_validators_root, spec).await
}

pub async fn new_with_options(
http_config: HttpConfig,
slot_clock: TestingSlotClock,
genesis_validators_root: Hash256,
spec: Arc<ChainSpec>,
) -> Self {
let log = test_logger();

let validator_dir = tempdir().unwrap();
Expand All @@ -95,20 +110,15 @@ impl ApiTester {
..Default::default()
};

let spec = Arc::new(E::default_spec());

let slashing_db_path = validator_dir.path().join(SLASHING_PROTECTION_FILENAME);
let slashing_protection = SlashingDatabase::open_or_create(&slashing_db_path).unwrap();

let slot_clock =
TestingSlotClock::new(Slot::new(0), Duration::from_secs(0), Duration::from_secs(1));

let test_runtime = TestRuntime::default();

let validator_store = Arc::new(ValidatorStore::<_, E>::new(
initialized_validators,
slashing_protection,
Hash256::repeat_byte(42),
genesis_validators_root,
spec.clone(),
Some(Arc::new(DoppelgangerService::new(log.clone()))),
slot_clock.clone(),
Expand All @@ -132,7 +142,7 @@ impl ApiTester {
validator_store: Some(validator_store.clone()),
graffiti_file: None,
graffiti_flag: Some(Graffiti::default()),
spec,
spec: spec.clone(),
config: http_config,
log,
sse_logging_components: None,
Expand Down Expand Up @@ -168,6 +178,7 @@ impl ApiTester {
_server_shutdown: shutdown_tx,
validator_dir,
secrets_dir,
spec,
}
}

Expand Down
3 changes: 3 additions & 0 deletions validator_manager/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@ ethereum_serde_utils = { workspace = true }
hex = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
slot_clock = { workspace = true }
tokio = { workspace = true }
tree_hash = { workspace = true }
types = { workspace = true }
zeroize = { workspace = true }

[dev-dependencies]
beacon_chain = { workspace = true }
http_api = { workspace = true }
regex = { workspace = true }
tempfile = { workspace = true }
validator_http_api = { workspace = true }
Loading
Loading