Allow per validator fee recipient via flag or file in validator client (similar to graffiti / graffiti-file) (#2924)

## Issue Addressed

#2883 

## Proposed Changes

* Added `suggested-fee-recipient` & `suggested-fee-recipient-file` flags to validator client (similar to graffiti / graffiti-file implementation).
* Added proposer preparation service to VC, which sends the fee-recipient of all known validators to the BN via [/eth/v1/validator/prepare_beacon_proposer](https://github.com/ethereum/beacon-APIs/pull/178) api once per slot
* Added [/eth/v1/validator/prepare_beacon_proposer](https://github.com/ethereum/beacon-APIs/pull/178) api endpoint and preparation data caching
* Added cleanup routine to remove cached proposer preparations when not updated for 2 epochs

## Additional Info

Changed the Implementation following the discussion in #2883.



Co-authored-by: pk910 <philipp@pk910.de>
Co-authored-by: Paul Hauner <paul@paulhauner.com>
Co-authored-by: Philipp K <philipp@pk910.de>
This commit is contained in:
Philipp K
2022-02-08 19:52:20 +00:00
parent d172c0b9fc
commit 5388183884
33 changed files with 1060 additions and 40 deletions

View File

@@ -493,6 +493,7 @@ fn validator_import_launchpad() {
enabled: false,
description: "".into(),
graffiti: None,
suggested_fee_recipient: None,
voting_public_key: keystore.public_key().unwrap(),
signing_definition: SigningDefinition::LocalKeystore {
voting_keystore_path,
@@ -612,6 +613,7 @@ fn validator_import_launchpad_no_password_then_add_password() {
enabled: true,
description: "".into(),
graffiti: None,
suggested_fee_recipient: None,
voting_public_key: keystore.public_key().unwrap(),
signing_definition: SigningDefinition::LocalKeystore {
voting_keystore_path,
@@ -635,6 +637,7 @@ fn validator_import_launchpad_no_password_then_add_password() {
enabled: true,
description: "".into(),
graffiti: None,
suggested_fee_recipient: None,
voting_public_key: keystore.public_key().unwrap(),
signing_definition: SigningDefinition::LocalKeystore {
voting_keystore_path: dst_keystore_dir.join(KEYSTORE_NAME),
@@ -734,6 +737,7 @@ fn validator_import_launchpad_password_file() {
description: "".into(),
voting_public_key: keystore.public_key().unwrap(),
graffiti: None,
suggested_fee_recipient: None,
signing_definition: SigningDefinition::LocalKeystore {
voting_keystore_path,
voting_keystore_password_path: None,

View File

@@ -212,7 +212,7 @@ fn merge_fee_recipient_flag() {
CommandLineTest::new()
.flag("merge", None)
.flag(
"fee-recipient",
"suggested-fee-recipient",
Some("0x00000000219ab540356cbb839cbe05303d7705fa"),
)
.run_with_zero_port()

View File

@@ -7,8 +7,10 @@ use std::io::Write;
use std::net::Ipv4Addr;
use std::path::PathBuf;
use std::process::Command;
use std::str::FromStr;
use std::string::ToString;
use tempfile::TempDir;
use types::Address;
/// Returns the `lighthouse validator_client` command.
fn base_cmd() -> Command {
@@ -218,6 +220,83 @@ fn graffiti_file_with_pk_flag() {
});
}
// Tests for suggested-fee-recipient flags.
#[test]
fn fee_recipient_flag() {
CommandLineTest::new()
.flag(
"suggested-fee-recipient",
Some("0x00000000219ab540356cbb839cbe05303d7705fa"),
)
.run()
.with_config(|config| {
assert_eq!(
config.fee_recipient,
Some(Address::from_str("0x00000000219ab540356cbb839cbe05303d7705fa").unwrap())
)
});
}
#[test]
fn fee_recipient_file_flag() {
let dir = TempDir::new().expect("Unable to create temporary directory");
let mut file =
File::create(dir.path().join("fee_recipient.txt")).expect("Unable to create file");
let new_key = Keypair::random();
let pubkeybytes = PublicKeyBytes::from(new_key.pk);
let contents = "default:0x00000000219ab540356cbb839cbe05303d7705fa";
file.write_all(contents.as_bytes())
.expect("Unable to write to file");
CommandLineTest::new()
.flag(
"suggested-fee-recipient-file",
dir.path().join("fee_recipient.txt").as_os_str().to_str(),
)
.run()
.with_config(|config| {
// Public key not present so load default.
assert_eq!(
config
.fee_recipient_file
.clone()
.unwrap()
.load_fee_recipient(&pubkeybytes)
.unwrap(),
Some(Address::from_str("0x00000000219ab540356cbb839cbe05303d7705fa").unwrap())
)
});
}
#[test]
fn fee_recipient_file_with_pk_flag() {
let dir = TempDir::new().expect("Unable to create temporary directory");
let mut file =
File::create(dir.path().join("fee_recipient.txt")).expect("Unable to create file");
let new_key = Keypair::random();
let pubkeybytes = PublicKeyBytes::from(new_key.pk);
let contents = format!(
"{}:0x00000000219ab540356cbb839cbe05303d7705fa",
pubkeybytes.to_string()
);
file.write_all(contents.as_bytes())
.expect("Unable to write to file");
CommandLineTest::new()
.flag(
"suggested-fee-recipient-file",
dir.path().join("fee_recipient.txt").as_os_str().to_str(),
)
.run()
.with_config(|config| {
assert_eq!(
config
.fee_recipient_file
.clone()
.unwrap()
.load_fee_recipient(&pubkeybytes)
.unwrap(),
Some(Address::from_str("0x00000000219ab540356cbb839cbe05303d7705fa").unwrap())
)
});
}
// Tests for HTTP flags.
#[test]
fn http_flag() {