mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 20:57:10 +00:00
Resolve merge conflicts
This commit is contained in:
@@ -6,7 +6,7 @@ edition = { workspace = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
arbitrary-fuzz = ["dep:arbitrary", "types/arbitrary"]
|
||||
arbitrary = ["dep:arbitrary", "types/arbitrary"]
|
||||
json = ["dep:serde_json"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
@@ -13,7 +13,7 @@ pub enum Error {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
pub struct InterchangeMetadata {
|
||||
#[serde(with = "serde_utils::quoted_u64::require_quotes")]
|
||||
pub interchange_format_version: u64,
|
||||
@@ -22,7 +22,7 @@ pub struct InterchangeMetadata {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
pub struct InterchangeData {
|
||||
pub pubkey: PublicKeyBytes,
|
||||
pub signed_blocks: Vec<SignedBlock>,
|
||||
@@ -31,7 +31,7 @@ pub struct InterchangeData {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
pub struct SignedBlock {
|
||||
#[serde(with = "serde_utils::quoted_u64::require_quotes")]
|
||||
pub slot: Slot,
|
||||
@@ -41,7 +41,7 @@ pub struct SignedBlock {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
pub struct SignedAttestation {
|
||||
#[serde(with = "serde_utils::quoted_u64::require_quotes")]
|
||||
pub source_epoch: Epoch,
|
||||
@@ -52,7 +52,7 @@ pub struct SignedAttestation {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
pub struct Interchange {
|
||||
pub metadata: InterchangeMetadata,
|
||||
pub data: Vec<InterchangeData>,
|
||||
|
||||
@@ -8,19 +8,23 @@ edition = { workspace = true }
|
||||
default = []
|
||||
lighthouse = ["proto_array", "eth2_keystore", "eip_3076", "zeroize"]
|
||||
events = ["reqwest-eventsource", "futures", "futures-util"]
|
||||
network = ["libp2p-identity", "enr", "multiaddr"]
|
||||
|
||||
[dependencies]
|
||||
bls = { workspace = true }
|
||||
context_deserialize = { workspace = true }
|
||||
educe = { workspace = true }
|
||||
eip_3076 = { workspace = true, optional = true }
|
||||
enr = { version = "0.13.0", features = ["ed25519"], optional = true }
|
||||
eth2_keystore = { workspace = true, optional = true }
|
||||
ethereum_serde_utils = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
ethereum_ssz_derive = { workspace = true }
|
||||
futures = { workspace = true, optional = true }
|
||||
futures-util = { version = "0.3.8", optional = true }
|
||||
libp2p-identity = { version = "0.2", features = ["peerid"], optional = true }
|
||||
mediatype = "0.19.13"
|
||||
multiaddr = { version = "0.18.2", optional = true }
|
||||
pretty_reqwest_error = { workspace = true }
|
||||
proto_array = { workspace = true, optional = true }
|
||||
reqwest = { workspace = true }
|
||||
|
||||
@@ -102,6 +102,7 @@ impl Error {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "events")]
|
||||
Error::SseEventSource(_) => None,
|
||||
Error::ServerMessage(msg) => StatusCode::try_from(msg.code).ok(),
|
||||
Error::ServerIndexedMessage(msg) => StatusCode::try_from(msg.code).ok(),
|
||||
|
||||
@@ -22,8 +22,6 @@ pub use beacon_response::{
|
||||
};
|
||||
|
||||
pub use self::error::{Error, ok_or_error, success_or_error};
|
||||
pub use reqwest;
|
||||
pub use reqwest::{StatusCode, Url};
|
||||
pub use sensitive_url::SensitiveUrl;
|
||||
|
||||
use self::mixin::{RequestAccept, ResponseOptional};
|
||||
@@ -35,14 +33,16 @@ use educe::Educe;
|
||||
use futures::Stream;
|
||||
#[cfg(feature = "events")]
|
||||
use futures_util::StreamExt;
|
||||
#[cfg(feature = "network")]
|
||||
use libp2p_identity::PeerId;
|
||||
use reqwest::{
|
||||
Body, IntoUrl, RequestBuilder, Response,
|
||||
Body, IntoUrl, RequestBuilder, Response, StatusCode, Url,
|
||||
header::{HeaderMap, HeaderValue},
|
||||
};
|
||||
#[cfg(feature = "events")]
|
||||
use reqwest_eventsource::{Event, RequestBuilderExt};
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
use ssz::Encode;
|
||||
use ssz::{Decode, Encode};
|
||||
use std::fmt;
|
||||
use std::future::Future;
|
||||
use std::time::Duration;
|
||||
@@ -50,6 +50,7 @@ use std::time::Duration;
|
||||
pub const V1: EndpointVersion = EndpointVersion(1);
|
||||
pub const V2: EndpointVersion = EndpointVersion(2);
|
||||
pub const V3: EndpointVersion = EndpointVersion(3);
|
||||
pub const V4: EndpointVersion = EndpointVersion(4);
|
||||
|
||||
pub const CONSENSUS_VERSION_HEADER: &str = "Eth-Consensus-Version";
|
||||
pub const EXECUTION_PAYLOAD_BLINDED_HEADER: &str = "Eth-Execution-Payload-Blinded";
|
||||
@@ -76,8 +77,6 @@ const HTTP_GET_BEACON_BLOCK_SSZ_TIMEOUT_QUOTIENT: u32 = 4;
|
||||
const HTTP_GET_DEBUG_BEACON_STATE_QUOTIENT: u32 = 4;
|
||||
const HTTP_GET_DEPOSIT_SNAPSHOT_QUOTIENT: u32 = 4;
|
||||
const HTTP_GET_VALIDATOR_BLOCK_TIMEOUT_QUOTIENT: u32 = 4;
|
||||
// Generally the timeout for events should be longer than a slot.
|
||||
const HTTP_GET_EVENTS_TIMEOUT_MULTIPLIER: u32 = 50;
|
||||
const HTTP_DEFAULT_TIMEOUT_QUOTIENT: u32 = 4;
|
||||
|
||||
/// A struct to define a variety of different timeouts for different validator tasks to ensure
|
||||
@@ -98,7 +97,6 @@ pub struct Timeouts {
|
||||
pub get_debug_beacon_states: Duration,
|
||||
pub get_deposit_snapshot: Duration,
|
||||
pub get_validator_block: Duration,
|
||||
pub events: Duration,
|
||||
pub default: Duration,
|
||||
}
|
||||
|
||||
@@ -119,7 +117,6 @@ impl Timeouts {
|
||||
get_debug_beacon_states: timeout,
|
||||
get_deposit_snapshot: timeout,
|
||||
get_validator_block: timeout,
|
||||
events: HTTP_GET_EVENTS_TIMEOUT_MULTIPLIER * timeout,
|
||||
default: timeout,
|
||||
}
|
||||
}
|
||||
@@ -142,7 +139,6 @@ impl Timeouts {
|
||||
get_debug_beacon_states: base_timeout / HTTP_GET_DEBUG_BEACON_STATE_QUOTIENT,
|
||||
get_deposit_snapshot: base_timeout / HTTP_GET_DEPOSIT_SNAPSHOT_QUOTIENT,
|
||||
get_validator_block: base_timeout / HTTP_GET_VALIDATOR_BLOCK_TIMEOUT_QUOTIENT,
|
||||
events: HTTP_GET_EVENTS_TIMEOUT_MULTIPLIER * base_timeout,
|
||||
default: base_timeout / HTTP_DEFAULT_TIMEOUT_QUOTIENT,
|
||||
}
|
||||
}
|
||||
@@ -902,6 +898,47 @@ impl BeaconNodeHttpClient {
|
||||
.map(|opt| opt.map(BeaconResponse::ForkVersioned))
|
||||
}
|
||||
|
||||
/// `GET beacon/states/{state_id}/proposer_lookahead`
|
||||
///
|
||||
/// Returns `Ok(None)` on a 404 error.
|
||||
pub async fn get_beacon_states_proposer_lookahead(
|
||||
&self,
|
||||
state_id: StateId,
|
||||
) -> Result<Option<ExecutionOptimisticFinalizedBeaconResponse<ValidatorIndexData>>, Error> {
|
||||
let mut path = self.eth_path(V1)?;
|
||||
|
||||
path.path_segments_mut()
|
||||
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
||||
.push("beacon")
|
||||
.push("states")
|
||||
.push(&state_id.to_string())
|
||||
.push("proposer_lookahead");
|
||||
|
||||
self.get_fork_contextual(path, |fork| fork)
|
||||
.await
|
||||
.map(|opt| opt.map(BeaconResponse::ForkVersioned))
|
||||
}
|
||||
|
||||
/// `GET beacon/states/{state_id}/proposer_lookahead`
|
||||
///
|
||||
/// Returns `Ok(None)` on a 404 error.
|
||||
pub async fn get_beacon_states_proposer_lookahead_ssz(
|
||||
&self,
|
||||
state_id: StateId,
|
||||
) -> Result<Option<Vec<u8>>, Error> {
|
||||
let mut path = self.eth_path(V1)?;
|
||||
|
||||
path.path_segments_mut()
|
||||
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
||||
.push("beacon")
|
||||
.push("states")
|
||||
.push(&state_id.to_string())
|
||||
.push("proposer_lookahead");
|
||||
|
||||
self.get_bytes_opt_accept_header(path, Accept::Ssz, self.timeouts.default)
|
||||
.await
|
||||
}
|
||||
|
||||
/// `GET beacon/light_client/updates`
|
||||
///
|
||||
/// Returns `Ok(None)` on a 404 error.
|
||||
@@ -1765,7 +1802,7 @@ impl BeaconNodeHttpClient {
|
||||
&self,
|
||||
block_id: BlockId,
|
||||
validators: &[ValidatorId],
|
||||
) -> Result<GenericResponse<Vec<SyncCommitteeReward>>, Error> {
|
||||
) -> Result<ExecutionOptimisticFinalizedResponse<Vec<SyncCommitteeReward>>, Error> {
|
||||
let mut path = self.eth_path(V1)?;
|
||||
|
||||
path.path_segments_mut()
|
||||
@@ -1782,7 +1819,7 @@ impl BeaconNodeHttpClient {
|
||||
pub async fn get_beacon_rewards_blocks(
|
||||
&self,
|
||||
block_id: BlockId,
|
||||
) -> Result<GenericResponse<StandardBlockReward>, Error> {
|
||||
) -> Result<ExecutionOptimisticFinalizedResponse<StandardBlockReward>, Error> {
|
||||
let mut path = self.eth_path(V1)?;
|
||||
|
||||
path.path_segments_mut()
|
||||
@@ -1800,7 +1837,7 @@ impl BeaconNodeHttpClient {
|
||||
&self,
|
||||
epoch: Epoch,
|
||||
validators: &[ValidatorId],
|
||||
) -> Result<StandardAttestationRewards, Error> {
|
||||
) -> Result<ExecutionOptimisticFinalizedResponse<StandardAttestationRewards>, Error> {
|
||||
let mut path = self.eth_path(V1)?;
|
||||
|
||||
path.path_segments_mut()
|
||||
@@ -1939,6 +1976,7 @@ impl BeaconNodeHttpClient {
|
||||
}
|
||||
|
||||
/// `GET node/identity`
|
||||
#[cfg(feature = "network")]
|
||||
pub async fn get_node_identity(&self) -> Result<GenericResponse<IdentityData>, Error> {
|
||||
let mut path = self.eth_path(V1)?;
|
||||
|
||||
@@ -1986,9 +2024,10 @@ impl BeaconNodeHttpClient {
|
||||
}
|
||||
|
||||
/// `GET node/peers/{peer_id}`
|
||||
#[cfg(feature = "network")]
|
||||
pub async fn get_node_peers_by_id(
|
||||
&self,
|
||||
peer_id: &str,
|
||||
peer_id: PeerId,
|
||||
) -> Result<GenericResponse<PeerData>, Error> {
|
||||
let mut path = self.eth_path(V1)?;
|
||||
|
||||
@@ -1996,7 +2035,7 @@ impl BeaconNodeHttpClient {
|
||||
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
||||
.push("node")
|
||||
.push("peers")
|
||||
.push(peer_id);
|
||||
.push(&peer_id.to_string());
|
||||
|
||||
self.get(path).await
|
||||
}
|
||||
@@ -2146,6 +2185,24 @@ impl BeaconNodeHttpClient {
|
||||
.await
|
||||
}
|
||||
|
||||
/// `GET v2/validator/duties/proposer/{epoch}`
|
||||
pub async fn get_validator_duties_proposer_v2(
|
||||
&self,
|
||||
epoch: Epoch,
|
||||
) -> Result<DutiesResponse<Vec<ProposerData>>, Error> {
|
||||
let mut path = self.eth_path(V2)?;
|
||||
|
||||
path.path_segments_mut()
|
||||
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
||||
.push("validator")
|
||||
.push("duties")
|
||||
.push("proposer")
|
||||
.push(&epoch.to_string());
|
||||
|
||||
self.get_with_timeout(path, self.timeouts.proposer_duties)
|
||||
.await
|
||||
}
|
||||
|
||||
/// `GET v2/validator/blocks/{slot}`
|
||||
pub async fn get_validator_blocks<E: EthSpec>(
|
||||
&self,
|
||||
@@ -2404,6 +2461,277 @@ impl BeaconNodeHttpClient {
|
||||
opt_response.ok_or(Error::StatusCode(StatusCode::NOT_FOUND))
|
||||
}
|
||||
|
||||
/// returns `GET v4/validator/blocks/{slot}` URL path
|
||||
pub async fn get_validator_blocks_v4_path(
|
||||
&self,
|
||||
slot: Slot,
|
||||
randao_reveal: &SignatureBytes,
|
||||
graffiti: Option<&Graffiti>,
|
||||
skip_randao_verification: SkipRandaoVerification,
|
||||
builder_booster_factor: Option<u64>,
|
||||
graffiti_policy: Option<GraffitiPolicy>,
|
||||
) -> Result<Url, Error> {
|
||||
let mut path = self.eth_path(V4)?;
|
||||
|
||||
path.path_segments_mut()
|
||||
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
||||
.push("validator")
|
||||
.push("blocks")
|
||||
.push(&slot.to_string());
|
||||
|
||||
path.query_pairs_mut()
|
||||
.append_pair("randao_reveal", &randao_reveal.to_string());
|
||||
|
||||
if let Some(graffiti) = graffiti {
|
||||
path.query_pairs_mut()
|
||||
.append_pair("graffiti", &graffiti.to_string());
|
||||
}
|
||||
|
||||
if skip_randao_verification == SkipRandaoVerification::Yes {
|
||||
path.query_pairs_mut()
|
||||
.append_pair("skip_randao_verification", "");
|
||||
}
|
||||
|
||||
if let Some(builder_booster_factor) = builder_booster_factor {
|
||||
path.query_pairs_mut()
|
||||
.append_pair("builder_boost_factor", &builder_booster_factor.to_string());
|
||||
}
|
||||
|
||||
if let Some(GraffitiPolicy::AppendClientVersions) = graffiti_policy {
|
||||
path.query_pairs_mut()
|
||||
.append_pair("graffiti_policy", "AppendClientVersions");
|
||||
}
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
/// `GET v4/validator/blocks/{slot}`
|
||||
pub async fn get_validator_blocks_v4<E: EthSpec>(
|
||||
&self,
|
||||
slot: Slot,
|
||||
randao_reveal: &SignatureBytes,
|
||||
graffiti: Option<&Graffiti>,
|
||||
builder_booster_factor: Option<u64>,
|
||||
graffiti_policy: Option<GraffitiPolicy>,
|
||||
) -> Result<
|
||||
(
|
||||
ForkVersionedResponse<BeaconBlock<E>, ProduceBlockV4Metadata>,
|
||||
ProduceBlockV4Metadata,
|
||||
),
|
||||
Error,
|
||||
> {
|
||||
self.get_validator_blocks_v4_modular(
|
||||
slot,
|
||||
randao_reveal,
|
||||
graffiti,
|
||||
SkipRandaoVerification::No,
|
||||
builder_booster_factor,
|
||||
graffiti_policy,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// `GET v4/validator/blocks/{slot}`
|
||||
pub async fn get_validator_blocks_v4_modular<E: EthSpec>(
|
||||
&self,
|
||||
slot: Slot,
|
||||
randao_reveal: &SignatureBytes,
|
||||
graffiti: Option<&Graffiti>,
|
||||
skip_randao_verification: SkipRandaoVerification,
|
||||
builder_booster_factor: Option<u64>,
|
||||
graffiti_policy: Option<GraffitiPolicy>,
|
||||
) -> Result<
|
||||
(
|
||||
ForkVersionedResponse<BeaconBlock<E>, ProduceBlockV4Metadata>,
|
||||
ProduceBlockV4Metadata,
|
||||
),
|
||||
Error,
|
||||
> {
|
||||
let path = self
|
||||
.get_validator_blocks_v4_path(
|
||||
slot,
|
||||
randao_reveal,
|
||||
graffiti,
|
||||
skip_randao_verification,
|
||||
builder_booster_factor,
|
||||
graffiti_policy,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let opt_result = self
|
||||
.get_response_with_response_headers(
|
||||
path,
|
||||
Accept::Json,
|
||||
self.timeouts.get_validator_block,
|
||||
|response, headers| async move {
|
||||
let header_metadata = ProduceBlockV4Metadata::try_from(&headers)
|
||||
.map_err(Error::InvalidHeaders)?;
|
||||
let block_response = response
|
||||
.json::<ForkVersionedResponse<BeaconBlock<E>, ProduceBlockV4Metadata>>()
|
||||
.await?;
|
||||
Ok((block_response, header_metadata))
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
opt_result.ok_or(Error::StatusCode(StatusCode::NOT_FOUND))
|
||||
}
|
||||
|
||||
/// `GET v4/validator/blocks/{slot}` in ssz format
|
||||
pub async fn get_validator_blocks_v4_ssz<E: EthSpec>(
|
||||
&self,
|
||||
slot: Slot,
|
||||
randao_reveal: &SignatureBytes,
|
||||
graffiti: Option<&Graffiti>,
|
||||
builder_booster_factor: Option<u64>,
|
||||
graffiti_policy: Option<GraffitiPolicy>,
|
||||
) -> Result<(BeaconBlock<E>, ProduceBlockV4Metadata), Error> {
|
||||
self.get_validator_blocks_v4_modular_ssz::<E>(
|
||||
slot,
|
||||
randao_reveal,
|
||||
graffiti,
|
||||
SkipRandaoVerification::No,
|
||||
builder_booster_factor,
|
||||
graffiti_policy,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// `GET v4/validator/blocks/{slot}` in ssz format
|
||||
pub async fn get_validator_blocks_v4_modular_ssz<E: EthSpec>(
|
||||
&self,
|
||||
slot: Slot,
|
||||
randao_reveal: &SignatureBytes,
|
||||
graffiti: Option<&Graffiti>,
|
||||
skip_randao_verification: SkipRandaoVerification,
|
||||
builder_booster_factor: Option<u64>,
|
||||
graffiti_policy: Option<GraffitiPolicy>,
|
||||
) -> Result<(BeaconBlock<E>, ProduceBlockV4Metadata), Error> {
|
||||
let path = self
|
||||
.get_validator_blocks_v4_path(
|
||||
slot,
|
||||
randao_reveal,
|
||||
graffiti,
|
||||
skip_randao_verification,
|
||||
builder_booster_factor,
|
||||
graffiti_policy,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let opt_response = self
|
||||
.get_response_with_response_headers(
|
||||
path,
|
||||
Accept::Ssz,
|
||||
self.timeouts.get_validator_block,
|
||||
|response, headers| async move {
|
||||
let metadata = ProduceBlockV4Metadata::try_from(&headers)
|
||||
.map_err(Error::InvalidHeaders)?;
|
||||
let response_bytes = response.bytes().await?;
|
||||
|
||||
let block = BeaconBlock::from_ssz_bytes_for_fork(
|
||||
&response_bytes,
|
||||
metadata.consensus_version,
|
||||
)
|
||||
.map_err(Error::InvalidSsz)?;
|
||||
|
||||
Ok((block, metadata))
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
opt_response.ok_or(Error::StatusCode(StatusCode::NOT_FOUND))
|
||||
}
|
||||
|
||||
/// `GET v1/validator/execution_payload_envelope/{slot}/{builder_index}`
|
||||
pub async fn get_validator_execution_payload_envelope<E: EthSpec>(
|
||||
&self,
|
||||
slot: Slot,
|
||||
builder_index: u64,
|
||||
) -> Result<ForkVersionedResponse<ExecutionPayloadEnvelope<E>>, Error> {
|
||||
let mut path = self.eth_path(V1)?;
|
||||
|
||||
path.path_segments_mut()
|
||||
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
||||
.push("validator")
|
||||
.push("execution_payload_envelope")
|
||||
.push(&slot.to_string())
|
||||
.push(&builder_index.to_string());
|
||||
|
||||
self.get(path).await
|
||||
}
|
||||
|
||||
/// `GET v1/validator/execution_payload_envelope/{slot}/{builder_index}` in SSZ format
|
||||
pub async fn get_validator_execution_payload_envelope_ssz<E: EthSpec>(
|
||||
&self,
|
||||
slot: Slot,
|
||||
builder_index: u64,
|
||||
) -> Result<ExecutionPayloadEnvelope<E>, Error> {
|
||||
let mut path = self.eth_path(V1)?;
|
||||
|
||||
path.path_segments_mut()
|
||||
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
||||
.push("validator")
|
||||
.push("execution_payload_envelope")
|
||||
.push(&slot.to_string())
|
||||
.push(&builder_index.to_string());
|
||||
|
||||
let opt_response = self
|
||||
.get_bytes_opt_accept_header(path, Accept::Ssz, self.timeouts.get_validator_block)
|
||||
.await?;
|
||||
|
||||
let response_bytes = opt_response.ok_or(Error::StatusCode(StatusCode::NOT_FOUND))?;
|
||||
|
||||
ExecutionPayloadEnvelope::from_ssz_bytes(&response_bytes).map_err(Error::InvalidSsz)
|
||||
}
|
||||
|
||||
/// `POST v1/beacon/execution_payload_envelope`
|
||||
pub async fn post_beacon_execution_payload_envelope<E: EthSpec>(
|
||||
&self,
|
||||
envelope: &SignedExecutionPayloadEnvelope<E>,
|
||||
fork_name: ForkName,
|
||||
) -> Result<(), Error> {
|
||||
let mut path = self.eth_path(V1)?;
|
||||
|
||||
path.path_segments_mut()
|
||||
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
||||
.push("beacon")
|
||||
.push("execution_payload_envelope");
|
||||
|
||||
self.post_generic_with_consensus_version(
|
||||
path,
|
||||
envelope,
|
||||
Some(self.timeouts.proposal),
|
||||
fork_name,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// `POST v1/beacon/execution_payload_envelope` in SSZ format
|
||||
pub async fn post_beacon_execution_payload_envelope_ssz<E: EthSpec>(
|
||||
&self,
|
||||
envelope: &SignedExecutionPayloadEnvelope<E>,
|
||||
fork_name: ForkName,
|
||||
) -> Result<(), Error> {
|
||||
let mut path = self.eth_path(V1)?;
|
||||
|
||||
path.path_segments_mut()
|
||||
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
||||
.push("beacon")
|
||||
.push("execution_payload_envelope");
|
||||
|
||||
self.post_generic_with_consensus_version_and_ssz_body(
|
||||
path,
|
||||
envelope.as_ssz_bytes(),
|
||||
Some(self.timeouts.proposal),
|
||||
fork_name,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// `GET v2/validator/blocks/{slot}` in ssz format
|
||||
pub async fn get_validator_blocks_ssz<E: EthSpec>(
|
||||
&self,
|
||||
@@ -2805,10 +3133,14 @@ impl BeaconNodeHttpClient {
|
||||
.join(",");
|
||||
path.query_pairs_mut().append_pair("topics", &topic_string);
|
||||
|
||||
// Do not use a timeout for the events endpoint. Using a regular timeout will trigger a
|
||||
// timeout every `timeout` seconds, regardless of any data streamed from the endpoint.
|
||||
// In future we could add a read_timeout, but that can only be configured globally on the
|
||||
// Client.
|
||||
let mut es = self
|
||||
.client
|
||||
.get(path)
|
||||
.timeout(self.timeouts.events)
|
||||
.timeout(Duration::MAX)
|
||||
.eventsource()
|
||||
.map_err(Error::SseEventSource)?;
|
||||
// If we don't await `Event::Open` here, then the consumer
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
mod attestation_performance;
|
||||
mod block_packing_efficiency;
|
||||
mod block_rewards;
|
||||
mod custody;
|
||||
pub mod sync_state;
|
||||
|
||||
use crate::{
|
||||
BeaconNodeHttpClient, DepositData, Error, Hash256, Slot,
|
||||
BeaconNodeHttpClient, DepositData, Error, Hash256,
|
||||
lighthouse::sync_state::SyncState,
|
||||
types::{AdminPeer, Epoch, GenericResponse, ValidatorId},
|
||||
};
|
||||
@@ -22,7 +21,6 @@ pub use attestation_performance::{
|
||||
pub use block_packing_efficiency::{
|
||||
BlockPackingEfficiency, BlockPackingEfficiencyQuery, ProposerInfo, UniqueAttestation,
|
||||
};
|
||||
pub use block_rewards::{AttestationRewards, BlockReward, BlockRewardMeta, BlockRewardsQuery};
|
||||
pub use custody::CustodyInfo;
|
||||
|
||||
// Define "legacy" implementations of `Option<T>` which use four bytes for encoding the union
|
||||
@@ -317,27 +315,6 @@ impl BeaconNodeHttpClient {
|
||||
Analysis endpoints.
|
||||
*/
|
||||
|
||||
/// `GET` lighthouse/analysis/block_rewards?start_slot,end_slot
|
||||
pub async fn get_lighthouse_analysis_block_rewards(
|
||||
&self,
|
||||
start_slot: Slot,
|
||||
end_slot: Slot,
|
||||
) -> Result<Vec<BlockReward>, Error> {
|
||||
let mut path = self.server.expose_full().clone();
|
||||
|
||||
path.path_segments_mut()
|
||||
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
||||
.push("lighthouse")
|
||||
.push("analysis")
|
||||
.push("block_rewards");
|
||||
|
||||
path.query_pairs_mut()
|
||||
.append_pair("start_slot", &start_slot.to_string())
|
||||
.append_pair("end_slot", &end_slot.to_string());
|
||||
|
||||
self.get(path).await
|
||||
}
|
||||
|
||||
/// `GET` lighthouse/analysis/block_packing?start_epoch,end_epoch
|
||||
pub async fn get_lighthouse_analysis_block_packing(
|
||||
&self,
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use types::{AttestationData, Hash256, Slot};
|
||||
|
||||
/// Details about the rewards paid to a block proposer for proposing a block.
|
||||
///
|
||||
/// All rewards in GWei.
|
||||
///
|
||||
/// Presently this only counts attestation rewards, but in future should be expanded
|
||||
/// to include information on slashings and sync committee aggregates too.
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct BlockReward {
|
||||
/// Sum of all reward components.
|
||||
pub total: u64,
|
||||
/// Block root of the block that these rewards are for.
|
||||
pub block_root: Hash256,
|
||||
/// Metadata about the block, particularly reward-relevant metadata.
|
||||
pub meta: BlockRewardMeta,
|
||||
/// Rewards due to attestations.
|
||||
pub attestation_rewards: AttestationRewards,
|
||||
/// Sum of rewards due to sync committee signatures.
|
||||
pub sync_committee_rewards: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct BlockRewardMeta {
|
||||
pub slot: Slot,
|
||||
pub parent_slot: Slot,
|
||||
pub proposer_index: u64,
|
||||
pub graffiti: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct AttestationRewards {
|
||||
/// Total block reward from attestations included.
|
||||
pub total: u64,
|
||||
/// Total rewards from previous epoch attestations.
|
||||
pub prev_epoch_total: u64,
|
||||
/// Total rewards from current epoch attestations.
|
||||
pub curr_epoch_total: u64,
|
||||
/// Vec of attestation rewards for each attestation included.
|
||||
///
|
||||
/// Each element of the vec is a map from validator index to reward.
|
||||
pub per_attestation_rewards: Vec<HashMap<u64, u64>>,
|
||||
/// The attestations themselves (optional).
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub attestations: Vec<AttestationData>,
|
||||
}
|
||||
|
||||
/// Query parameters for the `/lighthouse/block_rewards` endpoint.
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct BlockRewardsQuery {
|
||||
/// Lower slot limit for block rewards returned (inclusive).
|
||||
pub start_slot: Slot,
|
||||
/// Upper slot limit for block rewards returned (inclusive).
|
||||
pub end_slot: Slot,
|
||||
/// Include the full attestations themselves?
|
||||
#[serde(default)]
|
||||
pub include_attestations: bool,
|
||||
}
|
||||
@@ -9,7 +9,11 @@ use crate::{
|
||||
};
|
||||
use bls::{PublicKeyBytes, SecretKey, Signature, SignatureBytes};
|
||||
use context_deserialize::ContextDeserialize;
|
||||
#[cfg(feature = "network")]
|
||||
use enr::{CombinedKey, Enr};
|
||||
use mediatype::{MediaType, MediaTypeList, names};
|
||||
#[cfg(feature = "network")]
|
||||
use multiaddr::Multiaddr;
|
||||
use reqwest::header::HeaderMap;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use serde_utils::quoted_u64::Quoted;
|
||||
@@ -33,9 +37,6 @@ pub mod beacon_response {
|
||||
pub use crate::beacon_response::*;
|
||||
}
|
||||
|
||||
#[cfg(feature = "lighthouse")]
|
||||
use crate::lighthouse::BlockReward;
|
||||
|
||||
// Re-export error types from the unified error module
|
||||
pub use crate::error::{ErrorMessage, Failure, IndexedErrorMessage, ResponseError as Error};
|
||||
|
||||
@@ -559,12 +560,13 @@ pub struct ChainHeadData {
|
||||
pub execution_optimistic: Option<bool>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "network")]
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct IdentityData {
|
||||
pub peer_id: String,
|
||||
pub enr: String,
|
||||
pub p2p_addresses: Vec<String>,
|
||||
pub discovery_addresses: Vec<String>,
|
||||
pub enr: Enr<CombinedKey>,
|
||||
pub p2p_addresses: Vec<Multiaddr>,
|
||||
pub discovery_addresses: Vec<Multiaddr>,
|
||||
pub metadata: MetaData,
|
||||
}
|
||||
|
||||
@@ -706,6 +708,15 @@ pub struct DataColumnIndicesQuery {
|
||||
#[serde(transparent)]
|
||||
pub struct ValidatorIndexData(#[serde(with = "serde_utils::quoted_u64_vec")] pub Vec<u64>);
|
||||
|
||||
impl<'de, T> ContextDeserialize<'de, T> for ValidatorIndexData {
|
||||
fn context_deserialize<D>(deserializer: D, _context: T) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Self::deserialize(deserializer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Borrowed variant of `ValidatorIndexData`, for serializing/sending.
|
||||
#[derive(Clone, Copy, Serialize)]
|
||||
#[serde(transparent)]
|
||||
@@ -1194,8 +1205,6 @@ pub enum EventKind<E: EthSpec> {
|
||||
LateHead(SseLateHead),
|
||||
LightClientFinalityUpdate(Box<BeaconResponse<LightClientFinalityUpdate<E>>>),
|
||||
LightClientOptimisticUpdate(Box<BeaconResponse<LightClientOptimisticUpdate<E>>>),
|
||||
#[cfg(feature = "lighthouse")]
|
||||
BlockReward(BlockReward),
|
||||
PayloadAttributes(VersionedSsePayloadAttributes),
|
||||
ProposerSlashing(Box<ProposerSlashing>),
|
||||
AttesterSlashing(Box<AttesterSlashing<E>>),
|
||||
@@ -1220,8 +1229,6 @@ impl<E: EthSpec> EventKind<E> {
|
||||
EventKind::LateHead(_) => "late_head",
|
||||
EventKind::LightClientFinalityUpdate(_) => "light_client_finality_update",
|
||||
EventKind::LightClientOptimisticUpdate(_) => "light_client_optimistic_update",
|
||||
#[cfg(feature = "lighthouse")]
|
||||
EventKind::BlockReward(_) => "block_reward",
|
||||
EventKind::ProposerSlashing(_) => "proposer_slashing",
|
||||
EventKind::AttesterSlashing(_) => "attester_slashing",
|
||||
EventKind::BlsToExecutionChange(_) => "bls_to_execution_change",
|
||||
@@ -1297,10 +1304,6 @@ impl<E: EthSpec> EventKind<E> {
|
||||
})?),
|
||||
)))
|
||||
}
|
||||
#[cfg(feature = "lighthouse")]
|
||||
"block_reward" => Ok(EventKind::BlockReward(serde_json::from_str(data).map_err(
|
||||
|e| ServerError::InvalidServerSentEvent(format!("Block Reward: {:?}", e)),
|
||||
)?)),
|
||||
"attester_slashing" => Ok(EventKind::AttesterSlashing(
|
||||
serde_json::from_str(data).map_err(|e| {
|
||||
ServerError::InvalidServerSentEvent(format!("Attester Slashing: {:?}", e))
|
||||
@@ -1350,8 +1353,6 @@ pub enum EventTopic {
|
||||
PayloadAttributes,
|
||||
LightClientFinalityUpdate,
|
||||
LightClientOptimisticUpdate,
|
||||
#[cfg(feature = "lighthouse")]
|
||||
BlockReward,
|
||||
AttesterSlashing,
|
||||
ProposerSlashing,
|
||||
BlsToExecutionChange,
|
||||
@@ -1377,8 +1378,6 @@ impl FromStr for EventTopic {
|
||||
"late_head" => Ok(EventTopic::LateHead),
|
||||
"light_client_finality_update" => Ok(EventTopic::LightClientFinalityUpdate),
|
||||
"light_client_optimistic_update" => Ok(EventTopic::LightClientOptimisticUpdate),
|
||||
#[cfg(feature = "lighthouse")]
|
||||
"block_reward" => Ok(EventTopic::BlockReward),
|
||||
"attester_slashing" => Ok(EventTopic::AttesterSlashing),
|
||||
"proposer_slashing" => Ok(EventTopic::ProposerSlashing),
|
||||
"bls_to_execution_change" => Ok(EventTopic::BlsToExecutionChange),
|
||||
@@ -1405,8 +1404,6 @@ impl fmt::Display for EventTopic {
|
||||
EventTopic::LateHead => write!(f, "late_head"),
|
||||
EventTopic::LightClientFinalityUpdate => write!(f, "light_client_finality_update"),
|
||||
EventTopic::LightClientOptimisticUpdate => write!(f, "light_client_optimistic_update"),
|
||||
#[cfg(feature = "lighthouse")]
|
||||
EventTopic::BlockReward => write!(f, "block_reward"),
|
||||
EventTopic::AttesterSlashing => write!(f, "attester_slashing"),
|
||||
EventTopic::ProposerSlashing => write!(f, "proposer_slashing"),
|
||||
EventTopic::BlsToExecutionChange => write!(f, "bls_to_execution_change"),
|
||||
@@ -1599,7 +1596,7 @@ pub struct BroadcastValidationQuery {
|
||||
}
|
||||
|
||||
pub mod serde_status_code {
|
||||
use crate::StatusCode;
|
||||
use reqwest::StatusCode;
|
||||
use serde::{Deserialize, Serialize, de::Error};
|
||||
|
||||
pub fn serialize<S>(status_code: &StatusCode, ser: S) -> Result<S::Ok, S::Error>
|
||||
@@ -1718,7 +1715,7 @@ pub type JsonProduceBlockV3Response<E> =
|
||||
pub enum FullBlockContents<E: EthSpec> {
|
||||
/// This is a full deneb variant with block and blobs.
|
||||
BlockContents(BlockContents<E>),
|
||||
/// This variant is for all pre-deneb full blocks.
|
||||
/// This variant is for all pre-deneb full blocks or post-gloas beacon block.
|
||||
Block(BeaconBlock<E>),
|
||||
}
|
||||
|
||||
@@ -1746,6 +1743,20 @@ pub struct ProduceBlockV3Metadata {
|
||||
pub consensus_block_value: Uint256,
|
||||
}
|
||||
|
||||
/// Metadata about a `produce_block_v4` response which is returned in the body & headers.
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct ProduceBlockV4Metadata {
|
||||
// The consensus version is serialized & deserialized by `ForkVersionedResponse`.
|
||||
#[serde(
|
||||
skip_serializing,
|
||||
skip_deserializing,
|
||||
default = "dummy_consensus_version"
|
||||
)]
|
||||
pub consensus_version: ForkName,
|
||||
#[serde(with = "serde_utils::u256_dec")]
|
||||
pub consensus_block_value: Uint256,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> FullBlockContents<E> {
|
||||
pub fn new(block: BeaconBlock<E>, blob_data: Option<(KzgProofs<E>, BlobsList<E>)>) -> Self {
|
||||
match blob_data {
|
||||
@@ -1907,6 +1918,27 @@ impl TryFrom<&HeaderMap> for ProduceBlockV3Metadata {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&HeaderMap> for ProduceBlockV4Metadata {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(headers: &HeaderMap) -> Result<Self, Self::Error> {
|
||||
let consensus_version = parse_required_header(headers, CONSENSUS_VERSION_HEADER, |s| {
|
||||
s.parse::<ForkName>()
|
||||
.map_err(|e| format!("invalid {CONSENSUS_VERSION_HEADER}: {e:?}"))
|
||||
})?;
|
||||
let consensus_block_value =
|
||||
parse_required_header(headers, CONSENSUS_BLOCK_VALUE_HEADER, |s| {
|
||||
Uint256::from_str_radix(s, 10)
|
||||
.map_err(|e| format!("invalid {CONSENSUS_BLOCK_VALUE_HEADER}: {e:?}"))
|
||||
})?;
|
||||
|
||||
Ok(ProduceBlockV4Metadata {
|
||||
consensus_version,
|
||||
consensus_block_value,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper over a [`SignedBeaconBlock`] or a [`SignedBlockContents`].
|
||||
#[derive(Clone, Debug, PartialEq, Encode, Serialize)]
|
||||
#[serde(untagged)]
|
||||
@@ -1954,7 +1986,7 @@ impl<E: EthSpec> PublishBlockRequest<E> {
|
||||
|
||||
/// SSZ decode with fork variant determined by `fork_name`.
|
||||
pub fn from_ssz_bytes(bytes: &[u8], fork_name: ForkName) -> Result<Self, DecodeError> {
|
||||
if fork_name.deneb_enabled() {
|
||||
if fork_name.deneb_enabled() && !fork_name.gloas_enabled() {
|
||||
let mut builder = ssz::SszDecoderBuilder::new(bytes);
|
||||
builder.register_anonymous_variable_length_item()?;
|
||||
builder.register_type::<KzgProofs<E>>()?;
|
||||
|
||||
@@ -49,7 +49,7 @@ ELECTRA_FORK_VERSION: 0x0500006f
|
||||
ELECTRA_FORK_EPOCH: 948224 # Thu Mar 6 2025 09:43:40 GMT+0000
|
||||
# Fulu
|
||||
FULU_FORK_VERSION: 0x0600006f
|
||||
FULU_FORK_EPOCH: 18446744073709551615
|
||||
FULU_FORK_EPOCH: 1353216 # Mon Mar 16 2026 09:33:00 UTC
|
||||
# Gloas
|
||||
GLOAS_FORK_VERSION: 0x0700006f
|
||||
GLOAS_FORK_EPOCH: 18446744073709551615
|
||||
|
||||
@@ -121,7 +121,7 @@ impl Observe for ProcessHealth {
|
||||
pid_mem_shared_memory_size: process_mem.shared(),
|
||||
pid_process_seconds_total: process_times.busy().as_secs()
|
||||
+ process_times.children_system().as_secs()
|
||||
+ process_times.children_system().as_secs(),
|
||||
+ process_times.children_user().as_secs(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ authors = ["blacktemplar <blacktemplar@a1.net>"]
|
||||
edition = { workspace = true }
|
||||
|
||||
[features]
|
||||
test_logger = [] # Print log output to stderr when running tests instead of dropping it
|
||||
# Print log output to stderr when running tests instead of dropping it.
|
||||
test_logger = []
|
||||
|
||||
[dependencies]
|
||||
chrono = { version = "0.4", default-features = false, features = ["clock", "std"] }
|
||||
@@ -13,7 +14,7 @@ logroller = { workspace = true }
|
||||
metrics = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
tokio = { workspace = true, features = [ "time" ] }
|
||||
tokio = { workspace = true, features = ["time"] }
|
||||
tracing = { workspace = true }
|
||||
tracing-appender = { workspace = true }
|
||||
tracing-core = { workspace = true }
|
||||
|
||||
@@ -35,7 +35,4 @@ tikv-jemallocator = { version = "0.6.0", optional = true, features = ["stats"] }
|
||||
|
||||
# Jemalloc's background_threads feature requires Linux (pthreads).
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
tikv-jemallocator = { version = "0.6.0", optional = true, features = [
|
||||
"stats",
|
||||
"background_threads",
|
||||
] }
|
||||
tikv-jemallocator = { version = "0.6.0", optional = true, features = ["stats", "background_threads"] }
|
||||
|
||||
@@ -9,6 +9,7 @@ edition = { workspace = true }
|
||||
bytes = { workspace = true }
|
||||
eth2 = { workspace = true }
|
||||
headers = "0.3.2"
|
||||
reqwest = { workspace = true }
|
||||
safe_arith = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_array_query = "0.1.0"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use eth2::StatusCode;
|
||||
use reqwest::StatusCode;
|
||||
use warp::Rejection;
|
||||
|
||||
/// Convert from a "new" `http::StatusCode` to a `warp` compatible one.
|
||||
|
||||
Reference in New Issue
Block a user