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

@@ -303,11 +303,11 @@ impl ValidatorClientHttpClient {
}
/// Perform a HTTP DELETE request.
async fn delete_with_unsigned_response<T: Serialize, U: IntoUrl, V: DeserializeOwned>(
async fn delete_with_raw_response<T: Serialize, U: IntoUrl>(
&self,
url: U,
body: &T,
) -> Result<V, Error> {
) -> Result<Response, Error> {
let response = self
.client
.delete(url)
@@ -316,7 +316,16 @@ impl ValidatorClientHttpClient {
.send()
.await
.map_err(Error::Reqwest)?;
let response = ok_or_error(response).await?;
ok_or_error(response).await
}
/// Perform a HTTP DELETE request.
async fn delete_with_unsigned_response<T: Serialize, U: IntoUrl, V: DeserializeOwned>(
&self,
url: U,
body: &T,
) -> Result<V, Error> {
let response = self.delete_with_raw_response(url, body).await?;
Ok(response.json().await?)
}
@@ -486,6 +495,18 @@ impl ValidatorClientHttpClient {
Ok(url)
}
fn make_fee_recipient_url(&self, pubkey: &PublicKeyBytes) -> Result<Url, Error> {
let mut url = self.server.full.clone();
url.path_segments_mut()
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
.push("eth")
.push("v1")
.push("validator")
.push(&pubkey.to_string())
.push("feerecipient");
Ok(url)
}
/// `GET lighthouse/auth`
pub async fn get_auth(&self) -> Result<AuthResponse, Error> {
let mut url = self.server.full.clone();
@@ -543,14 +564,44 @@ impl ValidatorClientHttpClient {
let url = self.make_remotekeys_url()?;
self.delete_with_unsigned_response(url, req).await
}
/// `GET /eth/v1/validator/{pubkey}/feerecipient`
pub async fn get_fee_recipient(
&self,
pubkey: &PublicKeyBytes,
) -> Result<GetFeeRecipientResponse, Error> {
let url = self.make_fee_recipient_url(pubkey)?;
self.get(url)
.await
.map(|generic: GenericResponse<GetFeeRecipientResponse>| generic.data)
}
/// `POST /eth/v1/validator/{pubkey}/feerecipient`
pub async fn post_fee_recipient(
&self,
pubkey: &PublicKeyBytes,
req: &UpdateFeeRecipientRequest,
) -> Result<Response, Error> {
let url = self.make_fee_recipient_url(pubkey)?;
self.post_with_raw_response(url, req).await
}
/// `POST /eth/v1/validator/{pubkey}/feerecipient`
pub async fn delete_fee_recipient(&self, pubkey: &PublicKeyBytes) -> Result<Response, Error> {
let url = self.make_fee_recipient_url(pubkey)?;
self.delete_with_raw_response(url, &()).await
}
}
/// Returns `Ok(response)` if the response is a `200 OK` response. Otherwise, creates an
/// appropriate error message.
/// Returns `Ok(response)` if the response is a `200 OK` response or a
/// `202 Accepted` response. Otherwise, creates an appropriate error message.
async fn ok_or_error(response: Response) -> Result<Response, Error> {
let status = response.status();
if status == StatusCode::OK {
if status == StatusCode::OK
|| status == StatusCode::ACCEPTED
|| status == StatusCode::NO_CONTENT
{
Ok(response)
} else if let Ok(message) = response.json().await {
Err(Error::ServerMessage(message))

View File

@@ -2,7 +2,13 @@ use account_utils::ZeroizeString;
use eth2_keystore::Keystore;
use serde::{Deserialize, Serialize};
use slashing_protection::interchange::Interchange;
use types::PublicKeyBytes;
use types::{Address, PublicKeyBytes};
#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct GetFeeRecipientResponse {
pub pubkey: PublicKeyBytes,
pub ethaddress: Address,
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
pub struct AuthResponse {

View File

@@ -97,3 +97,8 @@ pub struct Web3SignerValidatorRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub client_identity_password: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct UpdateFeeRecipientRequest {
pub ethaddress: Address,
}