Implement graffiti management API (#4951)

* implement get graffiti

* add set graffiti

* add set graffiti

* delete graffiti

* set graffiti

* set graffiti

* fmt

* added tests

* add graffiti file check

* update

* fixed delete req

* remove unused code

* changes based on feedback

* changes based on feedback

* invalid auth test plus lint

* fmt

* remove unneeded async
This commit is contained in:
Eitan Seri-Levi
2023-12-06 17:02:46 -08:00
committed by GitHub
parent d9d84242a7
commit 8ba39cbf2c
7 changed files with 394 additions and 3 deletions

View File

@@ -226,11 +226,32 @@ impl ValidatorClientHttpClient {
ok_or_error(response).await
}
/// Perform a HTTP DELETE request, returning the `Response` for further processing.
async fn delete_response<U: IntoUrl>(&self, url: U) -> Result<Response, Error> {
let response = self
.client
.delete(url)
.headers(self.headers()?)
.send()
.await
.map_err(Error::from)?;
ok_or_error(response).await
}
async fn get<T: DeserializeOwned, U: IntoUrl>(&self, url: U) -> Result<T, Error> {
let response = self.get_response(url).await?;
self.signed_json(response).await
}
async fn delete<U: IntoUrl>(&self, url: U) -> Result<(), Error> {
let response = self.delete_response(url).await?;
if response.status().is_success() {
Ok(())
} else {
Err(Error::StatusCode(response.status()))
}
}
async fn get_unsigned<T: DeserializeOwned, U: IntoUrl>(&self, url: U) -> Result<T, Error> {
self.get_response(url)
.await?
@@ -537,6 +558,18 @@ impl ValidatorClientHttpClient {
Ok(url)
}
fn make_graffiti_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("graffiti");
Ok(url)
}
fn make_gas_limit_url(&self, pubkey: &PublicKeyBytes) -> Result<Url, Error> {
let mut url = self.server.full.clone();
url.path_segments_mut()
@@ -684,6 +717,34 @@ impl ValidatorClientHttpClient {
self.post(path, &()).await
}
/// `GET /eth/v1/validator/{pubkey}/graffiti`
pub async fn get_graffiti(
&self,
pubkey: &PublicKeyBytes,
) -> Result<GetGraffitiResponse, Error> {
let url = self.make_graffiti_url(pubkey)?;
self.get(url)
.await
.map(|generic: GenericResponse<GetGraffitiResponse>| generic.data)
}
/// `POST /eth/v1/validator/{pubkey}/graffiti`
pub async fn set_graffiti(
&self,
pubkey: &PublicKeyBytes,
graffiti: GraffitiString,
) -> Result<(), Error> {
let url = self.make_graffiti_url(pubkey)?;
let set_graffiti_request = SetGraffitiRequest { graffiti };
self.post(url, &set_graffiti_request).await
}
/// `DELETE /eth/v1/validator/{pubkey}/graffiti`
pub async fn delete_graffiti(&self, pubkey: &PublicKeyBytes) -> Result<(), Error> {
let url = self.make_graffiti_url(pubkey)?;
self.delete(url).await
}
}
/// Returns `Ok(response)` if the response is a `200 OK` response or a

View File

@@ -1,7 +1,7 @@
use account_utils::ZeroizeString;
use eth2_keystore::Keystore;
use serde::{Deserialize, Serialize};
use types::{Address, PublicKeyBytes};
use types::{Address, Graffiti, PublicKeyBytes};
pub use slashing_protection::interchange::Interchange;
@@ -172,3 +172,9 @@ pub enum DeleteRemotekeyStatus {
pub struct DeleteRemotekeysResponse {
pub data: Vec<Status<DeleteRemotekeyStatus>>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct GetGraffitiResponse {
pub pubkey: PublicKeyBytes,
pub graffiti: Graffiti,
}

View File

@@ -168,3 +168,8 @@ pub struct SingleExportKeystoresResponse {
#[serde(skip_serializing_if = "Option::is_none")]
pub validating_keystore_password: Option<ZeroizeString>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct SetGraffitiRequest {
pub graffiti: GraffitiString,
}