Merge branch 'unstable' into electra-focil

This commit is contained in:
jacobkaufmann
2024-12-26 12:54:09 -05:00
230 changed files with 3831 additions and 3317 deletions

View File

@@ -27,6 +27,7 @@ use reqwest::{
Body, IntoUrl, RequestBuilder, Response,
};
pub use reqwest::{StatusCode, Url};
use reqwest_eventsource::{Event, EventSource};
pub use sensitive_url::{SensitiveError, SensitiveUrl};
use serde::{de::DeserializeOwned, Serialize};
use ssz::Encode;
@@ -52,6 +53,8 @@ pub const SSZ_CONTENT_TYPE_HEADER: &str = "application/octet-stream";
pub enum Error {
/// The `reqwest` client raised an error.
HttpClient(PrettyReqwestError),
/// The `reqwest_eventsource` client raised an error.
SseClient(reqwest_eventsource::Error),
/// The server returned an error message where the body was able to be parsed.
ServerMessage(ErrorMessage),
/// The server returned an error message with an array of errors.
@@ -93,6 +96,13 @@ impl Error {
pub fn status(&self) -> Option<StatusCode> {
match self {
Error::HttpClient(error) => error.inner().status(),
Error::SseClient(error) => {
if let reqwest_eventsource::Error::InvalidStatusCode(status, _) = error {
Some(*status)
} else {
None
}
}
Error::ServerMessage(msg) => StatusCode::try_from(msg.code).ok(),
Error::ServerIndexedMessage(msg) => StatusCode::try_from(msg.code).ok(),
Error::StatusCode(status) => Some(*status),
@@ -2657,16 +2667,29 @@ impl BeaconNodeHttpClient {
.join(",");
path.query_pairs_mut().append_pair("topics", &topic_string);
Ok(self
.client
.get(path)
.send()
.await?
.bytes_stream()
.map(|next| match next {
Ok(bytes) => EventKind::from_sse_bytes(bytes.as_ref()),
Err(e) => Err(Error::HttpClient(e.into())),
}))
let mut es = EventSource::get(path);
// If we don't await `Event::Open` here, then the consumer
// will not get any Message events until they start awaiting the stream.
// This is a way to register the stream with the sse server before
// message events start getting emitted.
while let Some(event) = es.next().await {
match event {
Ok(Event::Open) => break,
Err(err) => return Err(Error::SseClient(err)),
// This should never happen as we are guaranteed to get the
// Open event before any message starts coming through.
Ok(Event::Message(_)) => continue,
}
}
Ok(Box::pin(es.filter_map(|event| async move {
match event {
Ok(Event::Open) => None,
Ok(Event::Message(message)) => {
Some(EventKind::from_sse_bytes(&message.event, &message.data))
}
Err(err) => Some(Err(Error::SseClient(err))),
}
})))
}
/// `POST validator/duties/sync/{epoch}`

View File

@@ -1,6 +1,5 @@
use super::types::*;
use crate::Error;
use account_utils::ZeroizeString;
use reqwest::{
header::{HeaderMap, HeaderValue},
IntoUrl,
@@ -14,6 +13,7 @@ use std::path::Path;
pub use reqwest;
pub use reqwest::{Response, StatusCode, Url};
use types::graffiti::GraffitiString;
use zeroize::Zeroizing;
/// A wrapper around `reqwest::Client` which provides convenience methods for interfacing with a
/// Lighthouse Validator Client HTTP server (`validator_client/src/http_api`).
@@ -21,7 +21,7 @@ use types::graffiti::GraffitiString;
pub struct ValidatorClientHttpClient {
client: reqwest::Client,
server: SensitiveUrl,
api_token: Option<ZeroizeString>,
api_token: Option<Zeroizing<String>>,
authorization_header: AuthorizationHeader,
}
@@ -79,18 +79,18 @@ impl ValidatorClientHttpClient {
}
/// Get a reference to this client's API token, if any.
pub fn api_token(&self) -> Option<&ZeroizeString> {
pub fn api_token(&self) -> Option<&Zeroizing<String>> {
self.api_token.as_ref()
}
/// Read an API token from the specified `path`, stripping any trailing whitespace.
pub fn load_api_token_from_file(path: &Path) -> Result<ZeroizeString, Error> {
pub fn load_api_token_from_file(path: &Path) -> Result<Zeroizing<String>, Error> {
let token = fs::read_to_string(path).map_err(|e| Error::TokenReadError(path.into(), e))?;
Ok(ZeroizeString::from(token.trim_end().to_string()))
Ok(token.trim_end().to_string().into())
}
/// Add an authentication token to use when making requests.
pub fn add_auth_token(&mut self, token: ZeroizeString) -> Result<(), Error> {
pub fn add_auth_token(&mut self, token: Zeroizing<String>) -> Result<(), Error> {
self.api_token = Some(token);
self.authorization_header = AuthorizationHeader::Bearer;

View File

@@ -1,7 +1,7 @@
use account_utils::ZeroizeString;
use eth2_keystore::Keystore;
use serde::{Deserialize, Serialize};
use types::{Address, Graffiti, PublicKeyBytes};
use zeroize::Zeroizing;
pub use slashing_protection::interchange::Interchange;
@@ -41,7 +41,7 @@ pub struct SingleKeystoreResponse {
#[serde(deny_unknown_fields)]
pub struct ImportKeystoresRequest {
pub keystores: Vec<KeystoreJsonStr>,
pub passwords: Vec<ZeroizeString>,
pub passwords: Vec<Zeroizing<String>>,
pub slashing_protection: Option<InterchangeJsonStr>,
}

View File

@@ -1,13 +1,12 @@
use account_utils::ZeroizeString;
pub use crate::lighthouse::Health;
pub use crate::lighthouse_vc::std_types::*;
pub use crate::types::{GenericResponse, VersionData};
use eth2_keystore::Keystore;
use graffiti::GraffitiString;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
pub use crate::lighthouse::Health;
pub use crate::lighthouse_vc::std_types::*;
pub use crate::types::{GenericResponse, VersionData};
pub use types::*;
use zeroize::Zeroizing;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ValidatorData {
@@ -44,7 +43,7 @@ pub struct ValidatorRequest {
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct CreateValidatorsMnemonicRequest {
pub mnemonic: ZeroizeString,
pub mnemonic: Zeroizing<String>,
#[serde(with = "serde_utils::quoted_u32")]
pub key_derivation_path_offset: u32,
pub validators: Vec<ValidatorRequest>,
@@ -74,7 +73,7 @@ pub struct CreatedValidator {
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct PostValidatorsResponseData {
pub mnemonic: ZeroizeString,
pub mnemonic: Zeroizing<String>,
pub validators: Vec<CreatedValidator>,
}
@@ -102,7 +101,7 @@ pub struct ValidatorPatchRequest {
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct KeystoreValidatorsPostRequest {
pub password: ZeroizeString,
pub password: Zeroizing<String>,
pub enable: bool,
pub keystore: Keystore,
#[serde(default)]
@@ -191,7 +190,7 @@ pub struct SingleExportKeystoresResponse {
#[serde(skip_serializing_if = "Option::is_none")]
pub validating_keystore: Option<KeystoreJsonStr>,
#[serde(skip_serializing_if = "Option::is_none")]
pub validating_keystore_password: Option<ZeroizeString>,
pub validating_keystore_password: Option<Zeroizing<String>>,
}
#[derive(Serialize, Deserialize, Debug)]

View File

@@ -13,7 +13,7 @@ use serde_json::Value;
use ssz::{Decode, DecodeError};
use ssz_derive::{Decode, Encode};
use std::fmt::{self, Display};
use std::str::{from_utf8, FromStr};
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;
use types::beacon_block_body::KzgCommitments;
@@ -1166,24 +1166,7 @@ impl<E: EthSpec> EventKind<E> {
}
}
pub fn from_sse_bytes(message: &[u8]) -> Result<Self, ServerError> {
let s = from_utf8(message)
.map_err(|e| ServerError::InvalidServerSentEvent(format!("{:?}", e)))?;
let mut split = s.split('\n');
let event = split
.next()
.ok_or_else(|| {
ServerError::InvalidServerSentEvent("Could not parse event tag".to_string())
})?
.trim_start_matches("event:");
let data = split
.next()
.ok_or_else(|| {
ServerError::InvalidServerSentEvent("Could not parse data tag".to_string())
})?
.trim_start_matches("data:");
pub fn from_sse_bytes(event: &str, data: &str) -> Result<Self, ServerError> {
match event {
"attestation" => Ok(EventKind::Attestation(serde_json::from_str(data).map_err(
|e| ServerError::InvalidServerSentEvent(format!("Attestation: {:?}", e)),