Implement feerecipient API for keymanager (#3213)

## Issue Addressed

* #3173 

## Proposed Changes

Moved all `fee_recipient_file` related logic inside the `ValidatorStore` as it makes more sense to have this all together there. I tested this with the validators I have on `mainnet-shadow-fork-5` and everything appeared to work well. Only technicality is that I can't get the method to return `401` when the authorization header is not specified (it returns `400` instead). Fixing this is probably quite difficult given that none of `warp`'s rejections have code `401`.. I don't really think this matters too much though as long as it fails.
This commit is contained in:
ethDreamer
2022-07-06 03:51:08 +00:00
parent 3dc323b035
commit d5e2d98970
17 changed files with 583 additions and 374 deletions

View File

@@ -9,10 +9,11 @@ use account_utils::{
mnemonic_from_phrase,
validator_definitions::{SigningDefinition, ValidatorDefinition},
};
pub use api_secret::ApiSecret;
use create_validator::{create_validators_mnemonic, create_validators_web3signer};
use eth2::lighthouse_vc::{
std_types::AuthResponse,
types::{self as api_types, PublicKey, PublicKeyBytes},
std_types::{AuthResponse, GetFeeRecipientResponse},
types::{self as api_types, GenericResponse, PublicKey, PublicKeyBytes},
};
use lighthouse_version::version_with_platform;
use serde::{Deserialize, Serialize};
@@ -35,8 +36,6 @@ use warp::{
Filter,
};
pub use api_secret::ApiSecret;
#[derive(Debug)]
pub enum Error {
Warp(warp::Error),
@@ -562,6 +561,123 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
let std_keystores = eth_v1.and(warp::path("keystores")).and(warp::path::end());
let std_remotekeys = eth_v1.and(warp::path("remotekeys")).and(warp::path::end());
// GET /eth/v1/validator/{pubkey}/feerecipient
let get_fee_recipient = eth_v1
.and(warp::path("validator"))
.and(warp::path::param::<PublicKey>())
.and(warp::path("feerecipient"))
.and(warp::path::end())
.and(validator_store_filter.clone())
.and(signer.clone())
.and_then(
|validator_pubkey: PublicKey, validator_store: Arc<ValidatorStore<T, E>>, signer| {
blocking_signed_json_task(signer, move || {
if validator_store
.initialized_validators()
.read()
.is_enabled(&validator_pubkey)
.is_none()
{
return Err(warp_utils::reject::custom_not_found(format!(
"no validator found with pubkey {:?}",
validator_pubkey
)));
}
validator_store
.get_fee_recipient(&PublicKeyBytes::from(&validator_pubkey))
.map(|fee_recipient| {
GenericResponse::from(GetFeeRecipientResponse {
pubkey: PublicKeyBytes::from(validator_pubkey.clone()),
ethaddress: fee_recipient,
})
})
.ok_or_else(|| {
warp_utils::reject::custom_server_error(
"no fee recipient set".to_string(),
)
})
})
},
);
// POST /eth/v1/validator/{pubkey}/feerecipient
let post_fee_recipient = eth_v1
.and(warp::path("validator"))
.and(warp::path::param::<PublicKey>())
.and(warp::body::json())
.and(warp::path("feerecipient"))
.and(warp::path::end())
.and(validator_store_filter.clone())
.and(signer.clone())
.and_then(
|validator_pubkey: PublicKey,
request: api_types::UpdateFeeRecipientRequest,
validator_store: Arc<ValidatorStore<T, E>>,
signer| {
blocking_signed_json_task(signer, move || {
if validator_store
.initialized_validators()
.read()
.is_enabled(&validator_pubkey)
.is_none()
{
return Err(warp_utils::reject::custom_not_found(format!(
"no validator found with pubkey {:?}",
validator_pubkey
)));
}
validator_store
.initialized_validators()
.write()
.set_validator_fee_recipient(&validator_pubkey, request.ethaddress)
.map_err(|e| {
warp_utils::reject::custom_server_error(format!(
"Error persisting fee recipient: {:?}",
e
))
})
})
},
)
.map(|reply| warp::reply::with_status(reply, warp::http::StatusCode::ACCEPTED));
// DELETE /eth/v1/validator/{pubkey}/feerecipient
let delete_fee_recipient = eth_v1
.and(warp::path("validator"))
.and(warp::path::param::<PublicKey>())
.and(warp::path("feerecipient"))
.and(warp::path::end())
.and(validator_store_filter.clone())
.and(signer.clone())
.and_then(
|validator_pubkey: PublicKey, validator_store: Arc<ValidatorStore<T, E>>, signer| {
blocking_signed_json_task(signer, move || {
if validator_store
.initialized_validators()
.read()
.is_enabled(&validator_pubkey)
.is_none()
{
return Err(warp_utils::reject::custom_not_found(format!(
"no validator found with pubkey {:?}",
validator_pubkey
)));
}
validator_store
.initialized_validators()
.write()
.delete_validator_fee_recipient(&validator_pubkey)
.map_err(|e| {
warp_utils::reject::custom_server_error(format!(
"Error persisting fee recipient removal: {:?}",
e
))
})
})
},
)
.map(|reply| warp::reply::with_status(reply, warp::http::StatusCode::NO_CONTENT));
// GET /eth/v1/keystores
let get_std_keystores = std_keystores
.and(signer.clone())
@@ -647,6 +763,7 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
.or(get_lighthouse_spec)
.or(get_lighthouse_validators)
.or(get_lighthouse_validators_pubkey)
.or(get_fee_recipient)
.or(get_std_keystores)
.or(get_std_remotekeys),
)
@@ -655,11 +772,16 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
.or(post_validators_keystore)
.or(post_validators_mnemonic)
.or(post_validators_web3signer)
.or(post_fee_recipient)
.or(post_std_keystores)
.or(post_std_remotekeys),
))
.or(warp::patch().and(patch_validators))
.or(warp::delete().and(delete_std_keystores.or(delete_std_remotekeys))),
.or(warp::delete().and(
delete_fee_recipient
.or(delete_std_keystores)
.or(delete_std_remotekeys),
)),
)
// The auth route is the only route that is allowed to be accessed without the API token.
.or(warp::get().and(get_auth))