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:
@@ -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 }
|
||||
|
||||
@@ -17,6 +17,8 @@ pub enum Error {
|
||||
#[cfg(feature = "events")]
|
||||
/// The `reqwest_eventsource` client raised an error.
|
||||
SseClient(Box<reqwest_eventsource::Error>),
|
||||
#[cfg(feature = "events")]
|
||||
SseEventSource(reqwest_eventsource::CannotCloneRequestError),
|
||||
/// 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.
|
||||
@@ -100,6 +102,8 @@ 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(),
|
||||
Error::StatusCode(status) => Some(*status),
|
||||
|
||||
@@ -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,21 +33,25 @@ 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, EventSource};
|
||||
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;
|
||||
use types::{PayloadAttestationData, PayloadAttestationMessage};
|
||||
|
||||
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";
|
||||
@@ -72,10 +74,13 @@ const HTTP_PROPOSER_DUTIES_TIMEOUT_QUOTIENT: u32 = 4;
|
||||
const HTTP_SYNC_COMMITTEE_CONTRIBUTION_TIMEOUT_QUOTIENT: u32 = 4;
|
||||
const HTTP_SYNC_DUTIES_TIMEOUT_QUOTIENT: u32 = 4;
|
||||
const HTTP_SYNC_AGGREGATOR_TIMEOUT_QUOTIENT: u32 = 24; // For DVT involving middleware only
|
||||
// TODO(EIP-7732): Determine what this quotient should be
|
||||
const HTTP_PTC_DUTIES_TIMEOUT_QUOTIENT: u32 = 4;
|
||||
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;
|
||||
const HTTP_PAYLOAD_ATTESTATION_TIMEOUT_QUOTIENT: u32 = 4;
|
||||
const HTTP_DEFAULT_TIMEOUT_QUOTIENT: u32 = 4;
|
||||
|
||||
/// A struct to define a variety of different timeouts for different validator tasks to ensure
|
||||
@@ -94,10 +99,12 @@ pub struct Timeouts {
|
||||
pub sync_aggregators: Duration,
|
||||
pub inclusion_list: Duration,
|
||||
pub inclusion_list_duties: Duration,
|
||||
pub ptc_duties: Duration,
|
||||
pub get_beacon_blocks_ssz: Duration,
|
||||
pub get_debug_beacon_states: Duration,
|
||||
pub get_deposit_snapshot: Duration,
|
||||
pub get_validator_block: Duration,
|
||||
pub payload_attestation: Duration,
|
||||
pub default: Duration,
|
||||
}
|
||||
|
||||
@@ -116,10 +123,12 @@ impl Timeouts {
|
||||
sync_aggregators: timeout,
|
||||
inclusion_list: timeout,
|
||||
inclusion_list_duties: timeout,
|
||||
ptc_duties: timeout,
|
||||
get_beacon_blocks_ssz: timeout,
|
||||
get_debug_beacon_states: timeout,
|
||||
get_deposit_snapshot: timeout,
|
||||
get_validator_block: timeout,
|
||||
payload_attestation: timeout,
|
||||
default: timeout,
|
||||
}
|
||||
}
|
||||
@@ -141,10 +150,12 @@ impl Timeouts {
|
||||
inclusion_list_duties: base_timeout,
|
||||
inclusion_list: base_timeout,
|
||||
sync_aggregators: base_timeout / HTTP_SYNC_AGGREGATOR_TIMEOUT_QUOTIENT,
|
||||
ptc_duties: base_timeout / HTTP_PTC_DUTIES_TIMEOUT_QUOTIENT,
|
||||
get_beacon_blocks_ssz: base_timeout / HTTP_GET_BEACON_BLOCK_SSZ_TIMEOUT_QUOTIENT,
|
||||
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,
|
||||
payload_attestation: base_timeout / HTTP_PAYLOAD_ATTESTATION_TIMEOUT_QUOTIENT,
|
||||
default: base_timeout / HTTP_DEFAULT_TIMEOUT_QUOTIENT,
|
||||
}
|
||||
}
|
||||
@@ -904,6 +915,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.
|
||||
@@ -1744,6 +1796,48 @@ impl BeaconNodeHttpClient {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// `POST beacon/pool/payload_attestations` (JSON)
|
||||
pub async fn post_beacon_pool_payload_attestations(
|
||||
&self,
|
||||
messages: &[PayloadAttestationMessage],
|
||||
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("pool")
|
||||
.push("payload_attestations");
|
||||
|
||||
self.post_generic_with_consensus_version(path, &messages, None, fork_name)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// `POST beacon/pool/payload_attestations` (SSZ)
|
||||
pub async fn post_beacon_pool_payload_attestations_ssz(
|
||||
&self,
|
||||
messages: &[PayloadAttestationMessage],
|
||||
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("pool")
|
||||
.push("payload_attestations");
|
||||
|
||||
let ssz_body: Vec<u8> = messages.iter().flat_map(|m| m.as_ssz_bytes()).collect();
|
||||
|
||||
self.post_generic_with_consensus_version_and_ssz_body(path, ssz_body, None, fork_name)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// `POST beacon/pool/bls_to_execution_changes`
|
||||
pub async fn post_beacon_pool_bls_to_execution_changes(
|
||||
&self,
|
||||
@@ -1786,7 +1880,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()
|
||||
@@ -1803,7 +1897,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()
|
||||
@@ -1821,7 +1915,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()
|
||||
@@ -1960,6 +2054,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)?;
|
||||
|
||||
@@ -2007,9 +2102,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)?;
|
||||
|
||||
@@ -2017,7 +2113,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
|
||||
}
|
||||
@@ -2167,6 +2263,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,
|
||||
@@ -2425,6 +2539,326 @@ 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(())
|
||||
}
|
||||
|
||||
/// Path for `v1/beacon/execution_payload_envelope/{block_id}`
|
||||
pub fn get_beacon_execution_payload_envelope_path(
|
||||
&self,
|
||||
block_id: BlockId,
|
||||
) -> Result<Url, 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")
|
||||
.push(&block_id.to_string());
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
/// `GET v1/beacon/execution_payload_envelope/{block_id}`
|
||||
///
|
||||
/// Returns `Ok(None)` on a 404 error.
|
||||
pub async fn get_beacon_execution_payload_envelope<E: EthSpec>(
|
||||
&self,
|
||||
block_id: BlockId,
|
||||
) -> Result<
|
||||
Option<ExecutionOptimisticFinalizedBeaconResponse<SignedExecutionPayloadEnvelope<E>>>,
|
||||
Error,
|
||||
> {
|
||||
let path = self.get_beacon_execution_payload_envelope_path(block_id)?;
|
||||
self.get_opt(path)
|
||||
.await
|
||||
.map(|opt| opt.map(BeaconResponse::ForkVersioned))
|
||||
}
|
||||
|
||||
/// `GET v1/beacon/execution_payload_envelope/{block_id}` in SSZ format
|
||||
///
|
||||
/// Returns `Ok(None)` on a 404 error.
|
||||
pub async fn get_beacon_execution_payload_envelope_ssz<E: EthSpec>(
|
||||
&self,
|
||||
block_id: BlockId,
|
||||
) -> Result<Option<SignedExecutionPayloadEnvelope<E>>, Error> {
|
||||
let path = self.get_beacon_execution_payload_envelope_path(block_id)?;
|
||||
let opt_response = self
|
||||
.get_bytes_opt_accept_header(path, Accept::Ssz, self.timeouts.get_beacon_blocks_ssz)
|
||||
.await?;
|
||||
match opt_response {
|
||||
Some(bytes) => SignedExecutionPayloadEnvelope::from_ssz_bytes(&bytes)
|
||||
.map(Some)
|
||||
.map_err(Error::InvalidSsz),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
/// `GET v2/validator/blocks/{slot}` in ssz format
|
||||
pub async fn get_validator_blocks_ssz<E: EthSpec>(
|
||||
&self,
|
||||
@@ -2581,6 +3015,46 @@ impl BeaconNodeHttpClient {
|
||||
self.get_with_timeout(path, self.timeouts.attestation).await
|
||||
}
|
||||
|
||||
/// `GET validator/payload_attestation_data/{slot}`
|
||||
pub async fn get_validator_payload_attestation_data(
|
||||
&self,
|
||||
slot: Slot,
|
||||
) -> Result<BeaconResponse<PayloadAttestationData>, Error> {
|
||||
let mut path = self.eth_path(V1)?;
|
||||
|
||||
path.path_segments_mut()
|
||||
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
||||
.push("validator")
|
||||
.push("payload_attestation_data")
|
||||
.push(&slot.to_string());
|
||||
|
||||
self.get_with_timeout(path, self.timeouts.payload_attestation)
|
||||
.await
|
||||
.map(BeaconResponse::ForkVersioned)
|
||||
}
|
||||
|
||||
/// `GET validator/payload_attestation_data/{slot}` in SSZ format
|
||||
pub async fn get_validator_payload_attestation_data_ssz(
|
||||
&self,
|
||||
slot: Slot,
|
||||
) -> Result<PayloadAttestationData, Error> {
|
||||
let mut path = self.eth_path(V1)?;
|
||||
|
||||
path.path_segments_mut()
|
||||
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
||||
.push("validator")
|
||||
.push("payload_attestation_data")
|
||||
.push(&slot.to_string());
|
||||
|
||||
let opt_response = self
|
||||
.get_bytes_opt_accept_header(path, Accept::Ssz, self.timeouts.payload_attestation)
|
||||
.await?;
|
||||
|
||||
let response_bytes = opt_response.ok_or(Error::StatusCode(StatusCode::NOT_FOUND))?;
|
||||
|
||||
PayloadAttestationData::from_ssz_bytes(&response_bytes).map_err(Error::InvalidSsz)
|
||||
}
|
||||
|
||||
/// `GET v1/validator/aggregate_attestation?slot,attestation_data_root`
|
||||
pub async fn get_validator_aggregate_attestation_v1<E: EthSpec>(
|
||||
&self,
|
||||
@@ -2868,7 +3342,16 @@ impl BeaconNodeHttpClient {
|
||||
.join(",");
|
||||
path.query_pairs_mut().append_pair("topics", &topic_string);
|
||||
|
||||
let mut es = EventSource::get(path);
|
||||
// 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(Duration::MAX)
|
||||
.eventsource()
|
||||
.map_err(Error::SseEventSource)?;
|
||||
// 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
|
||||
@@ -2951,4 +3434,29 @@ impl BeaconNodeHttpClient {
|
||||
self.post_with_timeout_and_response(path, &selections, self.timeouts.sync_aggregators)
|
||||
.await
|
||||
}
|
||||
|
||||
// TODO(EIP-7732): Create corresponding beacon node response endpoint per spec
|
||||
// https://github.com/ethereum/beacon-APIs/pull/552
|
||||
/// `POST validator/duties/ptc/{epoch}`
|
||||
pub async fn post_validator_duties_ptc(
|
||||
&self,
|
||||
epoch: Epoch,
|
||||
indices: &[u64],
|
||||
) -> Result<DutiesResponse<Vec<PtcDuty>>, Error> {
|
||||
let mut path = self.eth_path(V1)?;
|
||||
|
||||
path.path_segments_mut()
|
||||
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
|
||||
.push("validator")
|
||||
.push("duties")
|
||||
.push("ptc")
|
||||
.push(&epoch.to_string());
|
||||
|
||||
self.post_with_timeout_and_response(
|
||||
path,
|
||||
&ValidatorIndexDataRef(indices),
|
||||
self.timeouts.ptc_duties,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
//! This module contains endpoints that are non-standard and only available on Lighthouse servers.
|
||||
|
||||
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},
|
||||
};
|
||||
@@ -16,13 +13,6 @@ use serde::{Deserialize, Serialize};
|
||||
use ssz::four_byte_option_impl;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
|
||||
pub use attestation_performance::{
|
||||
AttestationPerformance, AttestationPerformanceQuery, AttestationPerformanceStatistics,
|
||||
};
|
||||
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
|
||||
@@ -312,73 +302,4 @@ impl BeaconNodeHttpClient {
|
||||
|
||||
self.post_with_response(path, &req).await
|
||||
}
|
||||
|
||||
/*
|
||||
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,
|
||||
start_epoch: Epoch,
|
||||
end_epoch: Epoch,
|
||||
) -> Result<Vec<BlockPackingEfficiency>, 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_packing_efficiency");
|
||||
|
||||
path.query_pairs_mut()
|
||||
.append_pair("start_epoch", &start_epoch.to_string())
|
||||
.append_pair("end_epoch", &end_epoch.to_string());
|
||||
|
||||
self.get(path).await
|
||||
}
|
||||
|
||||
/// `GET` lighthouse/analysis/attestation_performance/{index}?start_epoch,end_epoch
|
||||
pub async fn get_lighthouse_analysis_attestation_performance(
|
||||
&self,
|
||||
start_epoch: Epoch,
|
||||
end_epoch: Epoch,
|
||||
target: String,
|
||||
) -> Result<Vec<AttestationPerformance>, 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("attestation_performance")
|
||||
.push(&target);
|
||||
|
||||
path.query_pairs_mut()
|
||||
.append_pair("start_epoch", &start_epoch.to_string())
|
||||
.append_pair("end_epoch", &end_epoch.to_string());
|
||||
|
||||
self.get(path).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use types::Epoch;
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct AttestationPerformanceStatistics {
|
||||
pub active: bool,
|
||||
pub head: bool,
|
||||
pub target: bool,
|
||||
pub source: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub delay: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct AttestationPerformance {
|
||||
pub index: u64,
|
||||
pub epochs: HashMap<u64, AttestationPerformanceStatistics>,
|
||||
}
|
||||
|
||||
impl AttestationPerformance {
|
||||
pub fn initialize(indices: Vec<u64>) -> Vec<Self> {
|
||||
let mut vec = Vec::with_capacity(indices.len());
|
||||
for index in indices {
|
||||
vec.push(Self {
|
||||
index,
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
vec
|
||||
}
|
||||
}
|
||||
|
||||
/// Query parameters for the `/lighthouse/analysis/attestation_performance` endpoint.
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct AttestationPerformanceQuery {
|
||||
pub start_epoch: Epoch,
|
||||
pub end_epoch: Epoch,
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use types::{Epoch, Hash256, Slot};
|
||||
|
||||
type CommitteePosition = usize;
|
||||
type Committee = u64;
|
||||
type ValidatorIndex = u64;
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
|
||||
pub struct UniqueAttestation {
|
||||
pub slot: Slot,
|
||||
pub committee_index: Committee,
|
||||
pub committee_position: CommitteePosition,
|
||||
}
|
||||
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct ProposerInfo {
|
||||
pub validator_index: ValidatorIndex,
|
||||
pub graffiti: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct BlockPackingEfficiency {
|
||||
pub slot: Slot,
|
||||
pub block_hash: Hash256,
|
||||
pub proposer_info: ProposerInfo,
|
||||
pub available_attestations: usize,
|
||||
pub included_attestations: usize,
|
||||
pub prior_skip_slots: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub struct BlockPackingEfficiencyQuery {
|
||||
pub start_epoch: Epoch,
|
||||
pub end_epoch: Epoch,
|
||||
}
|
||||
@@ -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)]
|
||||
@@ -759,6 +770,14 @@ pub enum GraffitiPolicy {
|
||||
AppendClientVersions,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct PtcDuty {
|
||||
pub pubkey: PublicKeyBytes,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub validator_index: u64,
|
||||
pub slot: Slot,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize)]
|
||||
pub struct ValidatorBlocksQuery {
|
||||
pub randao_reveal: SignatureBytes,
|
||||
@@ -1021,14 +1040,18 @@ impl SseDataColumnSidecar {
|
||||
pub fn from_data_column_sidecar<E: EthSpec>(
|
||||
data_column_sidecar: &DataColumnSidecar<E>,
|
||||
) -> SseDataColumnSidecar {
|
||||
let kzg_commitments = data_column_sidecar.kzg_commitments.to_vec();
|
||||
// TODO(gloas): fetch kzg_commitments from block for Gloas SSE events
|
||||
let kzg_commitments: Vec<KzgCommitment> = match data_column_sidecar {
|
||||
DataColumnSidecar::Fulu(dc) => dc.kzg_commitments.to_vec(),
|
||||
DataColumnSidecar::Gloas(_) => vec![],
|
||||
};
|
||||
let versioned_hashes = kzg_commitments
|
||||
.iter()
|
||||
.map(|c| c.calculate_versioned_hash())
|
||||
.collect();
|
||||
SseDataColumnSidecar {
|
||||
block_root: data_column_sidecar.block_root(),
|
||||
index: data_column_sidecar.index,
|
||||
index: *data_column_sidecar.index(),
|
||||
slot: data_column_sidecar.slot(),
|
||||
kzg_commitments,
|
||||
versioned_hashes,
|
||||
@@ -1067,6 +1090,31 @@ pub struct BlockGossip {
|
||||
pub slot: Slot,
|
||||
pub block: Hash256,
|
||||
}
|
||||
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct SseExecutionPayload {
|
||||
pub slot: Slot,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub builder_index: u64,
|
||||
pub block_hash: ExecutionBlockHash,
|
||||
pub block_root: Hash256,
|
||||
pub execution_optimistic: bool,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct SseExecutionPayloadGossip {
|
||||
pub slot: Slot,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub builder_index: u64,
|
||||
pub block_hash: ExecutionBlockHash,
|
||||
pub block_root: Hash256,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct SseExecutionPayloadAvailable {
|
||||
pub slot: Slot,
|
||||
pub block_root: Hash256,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct SseChainReorg {
|
||||
pub slot: Slot,
|
||||
@@ -1131,6 +1179,8 @@ pub struct SseExtendedPayloadAttributesGeneric<T> {
|
||||
|
||||
pub type SseExtendedPayloadAttributes = SseExtendedPayloadAttributesGeneric<SsePayloadAttributes>;
|
||||
pub type VersionedSsePayloadAttributes = ForkVersionedResponse<SseExtendedPayloadAttributes>;
|
||||
pub type VersionedSseExecutionPayloadBid<E> = ForkVersionedResponse<SignedExecutionPayloadBid<E>>;
|
||||
pub type VersionedSsePayloadAttestationMessage = ForkVersionedResponse<PayloadAttestationMessage>;
|
||||
|
||||
impl<'de> ContextDeserialize<'de, ForkName> for SsePayloadAttributes {
|
||||
fn context_deserialize<D>(deserializer: D, context: ForkName) -> Result<Self, D::Error>
|
||||
@@ -1206,14 +1256,17 @@ 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>>),
|
||||
BlsToExecutionChange(Box<SignedBlsToExecutionChange>),
|
||||
BlockGossip(Box<BlockGossip>),
|
||||
InclusionList(SseInclusionList<E>),
|
||||
ExecutionPayload(SseExecutionPayload),
|
||||
ExecutionPayloadGossip(SseExecutionPayloadGossip),
|
||||
ExecutionPayloadAvailable(SseExecutionPayloadAvailable),
|
||||
ExecutionPayloadBid(Box<VersionedSseExecutionPayloadBid<E>>),
|
||||
PayloadAttestationMessage(Box<VersionedSsePayloadAttestationMessage>),
|
||||
}
|
||||
|
||||
impl<E: EthSpec> EventKind<E> {
|
||||
@@ -1233,13 +1286,16 @@ 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",
|
||||
EventKind::BlockGossip(_) => "block_gossip",
|
||||
EventKind::InclusionList(_) => "inclusion_list",
|
||||
EventKind::ExecutionPayload(_) => "execution_payload",
|
||||
EventKind::ExecutionPayloadGossip(_) => "execution_payload_gossip",
|
||||
EventKind::ExecutionPayloadAvailable(_) => "execution_payload_available",
|
||||
EventKind::ExecutionPayloadBid(_) => "execution_payload_bid",
|
||||
EventKind::PayloadAttestationMessage(_) => "payload_attestation_message",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1311,10 +1367,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))
|
||||
@@ -1338,6 +1390,40 @@ impl<E: EthSpec> EventKind<E> {
|
||||
ServerError::InvalidServerSentEvent(format!("Inclusion List {:?}", e))
|
||||
})?,
|
||||
)),
|
||||
"execution_payload" => Ok(EventKind::ExecutionPayload(
|
||||
serde_json::from_str(data).map_err(|e| {
|
||||
ServerError::InvalidServerSentEvent(format!("Execution Payload: {:?}", e))
|
||||
})?,
|
||||
)),
|
||||
"execution_payload_gossip" => Ok(EventKind::ExecutionPayloadGossip(
|
||||
serde_json::from_str(data).map_err(|e| {
|
||||
ServerError::InvalidServerSentEvent(format!(
|
||||
"Execution Payload Gossip: {:?}",
|
||||
e
|
||||
))
|
||||
})?,
|
||||
)),
|
||||
"execution_payload_available" => Ok(EventKind::ExecutionPayloadAvailable(
|
||||
serde_json::from_str(data).map_err(|e| {
|
||||
ServerError::InvalidServerSentEvent(format!(
|
||||
"Execution Payload Available: {:?}",
|
||||
e
|
||||
))
|
||||
})?,
|
||||
)),
|
||||
"execution_payload_bid" => Ok(EventKind::ExecutionPayloadBid(Box::new(
|
||||
serde_json::from_str(data).map_err(|e| {
|
||||
ServerError::InvalidServerSentEvent(format!("Execution Payload Bid: {:?}", e))
|
||||
})?,
|
||||
))),
|
||||
"payload_attestation_message" => Ok(EventKind::PayloadAttestationMessage(Box::new(
|
||||
serde_json::from_str(data).map_err(|e| {
|
||||
ServerError::InvalidServerSentEvent(format!(
|
||||
"Payload Attestation Message: {:?}",
|
||||
e
|
||||
))
|
||||
})?,
|
||||
))),
|
||||
_ => Err(ServerError::InvalidServerSentEvent(
|
||||
"Could not parse event tag".to_string(),
|
||||
)),
|
||||
@@ -1369,13 +1455,16 @@ pub enum EventTopic {
|
||||
PayloadAttributes,
|
||||
LightClientFinalityUpdate,
|
||||
LightClientOptimisticUpdate,
|
||||
#[cfg(feature = "lighthouse")]
|
||||
BlockReward,
|
||||
AttesterSlashing,
|
||||
ProposerSlashing,
|
||||
BlsToExecutionChange,
|
||||
BlockGossip,
|
||||
InclusionList,
|
||||
ExecutionPayload,
|
||||
ExecutionPayloadGossip,
|
||||
ExecutionPayloadAvailable,
|
||||
ExecutionPayloadBid,
|
||||
PayloadAttestationMessage,
|
||||
}
|
||||
|
||||
impl FromStr for EventTopic {
|
||||
@@ -1397,13 +1486,16 @@ 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),
|
||||
"block_gossip" => Ok(EventTopic::BlockGossip),
|
||||
"inclusion_list" => Ok(EventTopic::InclusionList),
|
||||
"execution_payload" => Ok(EventTopic::ExecutionPayload),
|
||||
"execution_payload_gossip" => Ok(EventTopic::ExecutionPayloadGossip),
|
||||
"execution_payload_available" => Ok(EventTopic::ExecutionPayloadAvailable),
|
||||
"execution_payload_bid" => Ok(EventTopic::ExecutionPayloadBid),
|
||||
"payload_attestation_message" => Ok(EventTopic::PayloadAttestationMessage),
|
||||
_ => Err("event topic cannot be parsed.".to_string()),
|
||||
}
|
||||
}
|
||||
@@ -1426,13 +1518,20 @@ 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"),
|
||||
EventTopic::BlockGossip => write!(f, "block_gossip"),
|
||||
EventTopic::InclusionList => write!(f, "inclusion_list",),
|
||||
EventTopic::InclusionList => write!(f, "inclusion_list"),
|
||||
EventTopic::ExecutionPayload => write!(f, "execution_payload"),
|
||||
EventTopic::ExecutionPayloadGossip => write!(f, "execution_payload_gossip"),
|
||||
EventTopic::ExecutionPayloadAvailable => {
|
||||
write!(f, "execution_payload_available")
|
||||
}
|
||||
EventTopic::ExecutionPayloadBid => write!(f, "execution_payload_bid"),
|
||||
EventTopic::PayloadAttestationMessage => {
|
||||
write!(f, "payload_attestation_message")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1621,7 +1720,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>
|
||||
@@ -1740,7 +1839,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>),
|
||||
}
|
||||
|
||||
@@ -1768,6 +1867,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 {
|
||||
@@ -1924,6 +2037,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)]
|
||||
@@ -1971,7 +2105,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>>()?;
|
||||
|
||||
Reference in New Issue
Block a user