Clean up blockv3 metadata and client (#5015)
* Improve block production v3 client * Delete wayward line * Overhaul JSON endpoint as well * Rename timeout param * Update tests * I broke everything * Ah this is an insane fix * Remove unnecessary optionals * Doc fix
This commit is contained in:
parent
a7e5926a1f
commit
af11e78ae1
@ -501,14 +501,14 @@ impl<E: EthSpec> BeaconBlockResponseWrapper<E> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execution_payload_value(&self) -> Option<Uint256> {
|
pub fn execution_payload_value(&self) -> Uint256 {
|
||||||
match self {
|
match self {
|
||||||
BeaconBlockResponseWrapper::Full(resp) => resp.execution_payload_value,
|
BeaconBlockResponseWrapper::Full(resp) => resp.execution_payload_value,
|
||||||
BeaconBlockResponseWrapper::Blinded(resp) => resp.execution_payload_value,
|
BeaconBlockResponseWrapper::Blinded(resp) => resp.execution_payload_value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn consensus_block_value(&self) -> Option<u64> {
|
pub fn consensus_block_value(&self) -> u64 {
|
||||||
match self {
|
match self {
|
||||||
BeaconBlockResponseWrapper::Full(resp) => resp.consensus_block_value,
|
BeaconBlockResponseWrapper::Full(resp) => resp.consensus_block_value,
|
||||||
BeaconBlockResponseWrapper::Blinded(resp) => resp.consensus_block_value,
|
BeaconBlockResponseWrapper::Blinded(resp) => resp.consensus_block_value,
|
||||||
@ -529,9 +529,9 @@ pub struct BeaconBlockResponse<T: EthSpec, Payload: AbstractExecPayload<T>> {
|
|||||||
/// The Blobs / Proofs associated with the new block
|
/// The Blobs / Proofs associated with the new block
|
||||||
pub blob_items: Option<(KzgProofs<T>, BlobsList<T>)>,
|
pub blob_items: Option<(KzgProofs<T>, BlobsList<T>)>,
|
||||||
/// The execution layer reward for the block
|
/// The execution layer reward for the block
|
||||||
pub execution_payload_value: Option<Uint256>,
|
pub execution_payload_value: Uint256,
|
||||||
/// The consensus layer reward to the proposer
|
/// The consensus layer reward to the proposer
|
||||||
pub consensus_block_value: Option<u64>,
|
pub consensus_block_value: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FinalizationAndCanonicity {
|
impl FinalizationAndCanonicity {
|
||||||
@ -5286,8 +5286,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
block,
|
block,
|
||||||
state,
|
state,
|
||||||
blob_items,
|
blob_items,
|
||||||
execution_payload_value: Some(execution_payload_value),
|
execution_payload_value,
|
||||||
consensus_block_value: Some(consensus_block_value),
|
consensus_block_value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5563,6 +5563,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
parent_block_hash: forkchoice_update_params.head_hash.unwrap_or_default(),
|
parent_block_hash: forkchoice_update_params.head_hash.unwrap_or_default(),
|
||||||
payload_attributes: payload_attributes.into(),
|
payload_attributes: payload_attributes.into(),
|
||||||
},
|
},
|
||||||
|
metadata: Default::default(),
|
||||||
version: Some(self.spec.fork_name_at_slot::<T::EthSpec>(prepare_slot)),
|
version: Some(self.spec.fork_name_at_slot::<T::EthSpec>(prepare_slot)),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -335,8 +335,9 @@ pub fn serve<E: EthSpec>(
|
|||||||
.el
|
.el
|
||||||
.get_payload_by_root(&root)
|
.get_payload_by_root(&root)
|
||||||
.ok_or_else(|| reject("missing payload for tx root"))?;
|
.ok_or_else(|| reject("missing payload for tx root"))?;
|
||||||
let resp = ForkVersionedResponse {
|
let resp: ForkVersionedResponse<_> = ForkVersionedResponse {
|
||||||
version: Some(fork_name),
|
version: Some(fork_name),
|
||||||
|
metadata: Default::default(),
|
||||||
data: payload,
|
data: payload,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -616,8 +617,9 @@ pub fn serve<E: EthSpec>(
|
|||||||
.spec
|
.spec
|
||||||
.fork_name_at_epoch(slot.epoch(E::slots_per_epoch()));
|
.fork_name_at_epoch(slot.epoch(E::slots_per_epoch()));
|
||||||
let signed_bid = SignedBuilderBid { message, signature };
|
let signed_bid = SignedBuilderBid { message, signature };
|
||||||
let resp = ForkVersionedResponse {
|
let resp: ForkVersionedResponse<_> = ForkVersionedResponse {
|
||||||
version: Some(fork_name),
|
version: Some(fork_name),
|
||||||
|
metadata: Default::default(),
|
||||||
data: signed_bid,
|
data: signed_bid,
|
||||||
};
|
};
|
||||||
let json_bid = serde_json::to_string(&resp)
|
let json_bid = serde_json::to_string(&resp)
|
||||||
|
@ -77,12 +77,12 @@ use tokio_stream::{
|
|||||||
StreamExt,
|
StreamExt,
|
||||||
};
|
};
|
||||||
use types::{
|
use types::{
|
||||||
Attestation, AttestationData, AttestationShufflingId, AttesterSlashing, BeaconStateError,
|
fork_versioned_response::EmptyMetadata, Attestation, AttestationData, AttestationShufflingId,
|
||||||
CommitteeCache, ConfigAndPreset, Epoch, EthSpec, ForkName, ForkVersionedResponse, Hash256,
|
AttesterSlashing, BeaconStateError, CommitteeCache, ConfigAndPreset, Epoch, EthSpec, ForkName,
|
||||||
ProposerPreparationData, ProposerSlashing, RelativeEpoch, SignedAggregateAndProof,
|
ForkVersionedResponse, Hash256, ProposerPreparationData, ProposerSlashing, RelativeEpoch,
|
||||||
SignedBlindedBeaconBlock, SignedBlsToExecutionChange, SignedContributionAndProof,
|
SignedAggregateAndProof, SignedBlindedBeaconBlock, SignedBlsToExecutionChange,
|
||||||
SignedValidatorRegistrationData, SignedVoluntaryExit, Slot, SyncCommitteeMessage,
|
SignedContributionAndProof, SignedValidatorRegistrationData, SignedVoluntaryExit, Slot,
|
||||||
SyncContributionData,
|
SyncCommitteeMessage, SyncContributionData,
|
||||||
};
|
};
|
||||||
use validator::pubkey_to_validator_index;
|
use validator::pubkey_to_validator_index;
|
||||||
use version::{
|
use version::{
|
||||||
@ -2399,6 +2399,7 @@ pub fn serve<T: BeaconChainTypes>(
|
|||||||
}),
|
}),
|
||||||
_ => Ok(warp::reply::json(&ForkVersionedResponse {
|
_ => Ok(warp::reply::json(&ForkVersionedResponse {
|
||||||
version: Some(fork_name),
|
version: Some(fork_name),
|
||||||
|
metadata: EmptyMetadata {},
|
||||||
data: bootstrap,
|
data: bootstrap,
|
||||||
})
|
})
|
||||||
.into_response()),
|
.into_response()),
|
||||||
@ -2446,6 +2447,7 @@ pub fn serve<T: BeaconChainTypes>(
|
|||||||
}),
|
}),
|
||||||
_ => Ok(warp::reply::json(&ForkVersionedResponse {
|
_ => Ok(warp::reply::json(&ForkVersionedResponse {
|
||||||
version: Some(fork_name),
|
version: Some(fork_name),
|
||||||
|
metadata: EmptyMetadata {},
|
||||||
data: update,
|
data: update,
|
||||||
})
|
})
|
||||||
.into_response()),
|
.into_response()),
|
||||||
@ -2493,6 +2495,7 @@ pub fn serve<T: BeaconChainTypes>(
|
|||||||
}),
|
}),
|
||||||
_ => Ok(warp::reply::json(&ForkVersionedResponse {
|
_ => Ok(warp::reply::json(&ForkVersionedResponse {
|
||||||
version: Some(fork_name),
|
version: Some(fork_name),
|
||||||
|
metadata: EmptyMetadata {},
|
||||||
data: update,
|
data: update,
|
||||||
})
|
})
|
||||||
.into_response()),
|
.into_response()),
|
||||||
@ -3193,7 +3196,7 @@ pub fn serve<T: BeaconChainTypes>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if endpoint_version == V3 {
|
if endpoint_version == V3 {
|
||||||
produce_block_v3(endpoint_version, accept_header, chain, slot, query).await
|
produce_block_v3(accept_header, chain, slot, query).await
|
||||||
} else {
|
} else {
|
||||||
produce_block_v2(endpoint_version, accept_header, chain, slot, query).await
|
produce_block_v2(endpoint_version, accept_header, chain, slot, query).await
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,3 @@
|
|||||||
use bytes::Bytes;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use types::{payload::BlockProductionVersion, *};
|
|
||||||
|
|
||||||
use beacon_chain::{
|
|
||||||
BeaconBlockResponseWrapper, BeaconChain, BeaconChainTypes, ProduceBlockVerification,
|
|
||||||
};
|
|
||||||
use eth2::types::{self as api_types, EndpointVersion, SkipRandaoVerification};
|
|
||||||
use ssz::Encode;
|
|
||||||
use warp::{
|
|
||||||
hyper::{Body, Response},
|
|
||||||
Reply,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
build_block_contents,
|
build_block_contents,
|
||||||
version::{
|
version::{
|
||||||
@ -20,6 +6,20 @@ use crate::{
|
|||||||
fork_versioned_response, inconsistent_fork_rejection,
|
fork_versioned_response, inconsistent_fork_rejection,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use beacon_chain::{
|
||||||
|
BeaconBlockResponseWrapper, BeaconChain, BeaconChainTypes, ProduceBlockVerification,
|
||||||
|
};
|
||||||
|
use bytes::Bytes;
|
||||||
|
use eth2::types::{
|
||||||
|
self as api_types, EndpointVersion, ProduceBlockV3Metadata, SkipRandaoVerification,
|
||||||
|
};
|
||||||
|
use ssz::Encode;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use types::{payload::BlockProductionVersion, *};
|
||||||
|
use warp::{
|
||||||
|
hyper::{Body, Response},
|
||||||
|
Reply,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn get_randao_verification(
|
pub fn get_randao_verification(
|
||||||
query: &api_types::ValidatorBlocksQuery,
|
query: &api_types::ValidatorBlocksQuery,
|
||||||
@ -40,7 +40,6 @@ pub fn get_randao_verification(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn produce_block_v3<T: BeaconChainTypes>(
|
pub async fn produce_block_v3<T: BeaconChainTypes>(
|
||||||
endpoint_version: EndpointVersion,
|
|
||||||
accept_header: Option<api_types::Accept>,
|
accept_header: Option<api_types::Accept>,
|
||||||
chain: Arc<BeaconChain<T>>,
|
chain: Arc<BeaconChain<T>>,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
@ -68,13 +67,12 @@ pub async fn produce_block_v3<T: BeaconChainTypes>(
|
|||||||
warp_utils::reject::custom_bad_request(format!("failed to fetch a block: {:?}", e))
|
warp_utils::reject::custom_bad_request(format!("failed to fetch a block: {:?}", e))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
build_response_v3(chain, block_response_type, endpoint_version, accept_header)
|
build_response_v3(chain, block_response_type, accept_header)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_response_v3<T: BeaconChainTypes>(
|
pub fn build_response_v3<T: BeaconChainTypes>(
|
||||||
chain: Arc<BeaconChain<T>>,
|
chain: Arc<BeaconChain<T>>,
|
||||||
block_response: BeaconBlockResponseWrapper<T::EthSpec>,
|
block_response: BeaconBlockResponseWrapper<T::EthSpec>,
|
||||||
endpoint_version: EndpointVersion,
|
|
||||||
accept_header: Option<api_types::Accept>,
|
accept_header: Option<api_types::Accept>,
|
||||||
) -> Result<Response<Body>, warp::Rejection> {
|
) -> Result<Response<Body>, warp::Rejection> {
|
||||||
let fork_name = block_response
|
let fork_name = block_response
|
||||||
@ -84,6 +82,13 @@ pub fn build_response_v3<T: BeaconChainTypes>(
|
|||||||
let consensus_block_value = block_response.consensus_block_value();
|
let consensus_block_value = block_response.consensus_block_value();
|
||||||
let execution_payload_blinded = block_response.is_blinded();
|
let execution_payload_blinded = block_response.is_blinded();
|
||||||
|
|
||||||
|
let metadata = ProduceBlockV3Metadata {
|
||||||
|
consensus_version: fork_name,
|
||||||
|
execution_payload_blinded,
|
||||||
|
execution_payload_value,
|
||||||
|
consensus_block_value,
|
||||||
|
};
|
||||||
|
|
||||||
let block_contents = build_block_contents::build_block_contents(fork_name, block_response)?;
|
let block_contents = build_block_contents::build_block_contents(fork_name, block_response)?;
|
||||||
|
|
||||||
match accept_header {
|
match accept_header {
|
||||||
@ -100,12 +105,17 @@ pub fn build_response_v3<T: BeaconChainTypes>(
|
|||||||
.map_err(|e| -> warp::Rejection {
|
.map_err(|e| -> warp::Rejection {
|
||||||
warp_utils::reject::custom_server_error(format!("failed to create response: {}", e))
|
warp_utils::reject::custom_server_error(format!("failed to create response: {}", e))
|
||||||
}),
|
}),
|
||||||
_ => fork_versioned_response(endpoint_version, fork_name, block_contents)
|
_ => Ok(warp::reply::json(&ForkVersionedResponse {
|
||||||
.map(|response| warp::reply::json(&response).into_response())
|
version: Some(fork_name),
|
||||||
.map(|res| add_consensus_version_header(res, fork_name))
|
metadata,
|
||||||
.map(|res| add_execution_payload_blinded_header(res, execution_payload_blinded))
|
data: block_contents,
|
||||||
.map(|res| add_execution_payload_value_header(res, execution_payload_value))
|
})
|
||||||
.map(|res| add_consensus_block_value_header(res, consensus_block_value)),
|
.into_response())
|
||||||
|
.map(|res| res.into_response())
|
||||||
|
.map(|res| add_consensus_version_header(res, fork_name))
|
||||||
|
.map(|res| add_execution_payload_blinded_header(res, execution_payload_blinded))
|
||||||
|
.map(|res| add_execution_payload_value_header(res, execution_payload_value))
|
||||||
|
.map(|res| add_consensus_block_value_header(res, consensus_block_value)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
use crate::api_types::fork_versioned_response::ExecutionOptimisticFinalizedForkVersionedResponse;
|
|
||||||
use crate::api_types::EndpointVersion;
|
use crate::api_types::EndpointVersion;
|
||||||
use eth2::{
|
use eth2::{
|
||||||
CONSENSUS_BLOCK_VALUE_HEADER, CONSENSUS_VERSION_HEADER, EXECUTION_PAYLOAD_BLINDED_HEADER,
|
CONSENSUS_BLOCK_VALUE_HEADER, CONSENSUS_VERSION_HEADER, EXECUTION_PAYLOAD_BLINDED_HEADER,
|
||||||
EXECUTION_PAYLOAD_VALUE_HEADER,
|
EXECUTION_PAYLOAD_VALUE_HEADER,
|
||||||
};
|
};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use types::{ForkName, ForkVersionedResponse, InconsistentFork, Uint256};
|
use types::{
|
||||||
|
fork_versioned_response::{
|
||||||
|
ExecutionOptimisticFinalizedForkVersionedResponse, ExecutionOptimisticFinalizedMetadata,
|
||||||
|
},
|
||||||
|
ForkName, ForkVersionedResponse, InconsistentFork, Uint256,
|
||||||
|
};
|
||||||
use warp::reply::{self, Reply, Response};
|
use warp::reply::{self, Reply, Response};
|
||||||
|
|
||||||
pub const V1: EndpointVersion = EndpointVersion(1);
|
pub const V1: EndpointVersion = EndpointVersion(1);
|
||||||
@ -26,6 +30,7 @@ pub fn fork_versioned_response<T: Serialize>(
|
|||||||
};
|
};
|
||||||
Ok(ForkVersionedResponse {
|
Ok(ForkVersionedResponse {
|
||||||
version: fork_name,
|
version: fork_name,
|
||||||
|
metadata: Default::default(),
|
||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -46,8 +51,10 @@ pub fn execution_optimistic_finalized_fork_versioned_response<T: Serialize>(
|
|||||||
};
|
};
|
||||||
Ok(ExecutionOptimisticFinalizedForkVersionedResponse {
|
Ok(ExecutionOptimisticFinalizedForkVersionedResponse {
|
||||||
version: fork_name,
|
version: fork_name,
|
||||||
execution_optimistic: Some(execution_optimistic),
|
metadata: ExecutionOptimisticFinalizedMetadata {
|
||||||
finalized: Some(finalized),
|
execution_optimistic: Some(execution_optimistic),
|
||||||
|
finalized: Some(finalized),
|
||||||
|
},
|
||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -73,12 +80,12 @@ pub fn add_execution_payload_blinded_header<T: Reply>(
|
|||||||
/// Add the `Eth-Execution-Payload-Value` header to a response.
|
/// Add the `Eth-Execution-Payload-Value` header to a response.
|
||||||
pub fn add_execution_payload_value_header<T: Reply>(
|
pub fn add_execution_payload_value_header<T: Reply>(
|
||||||
reply: T,
|
reply: T,
|
||||||
execution_payload_value: Option<Uint256>,
|
execution_payload_value: Uint256,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
reply::with_header(
|
reply::with_header(
|
||||||
reply,
|
reply,
|
||||||
EXECUTION_PAYLOAD_VALUE_HEADER,
|
EXECUTION_PAYLOAD_VALUE_HEADER,
|
||||||
execution_payload_value.unwrap_or_default().to_string(),
|
execution_payload_value.to_string(),
|
||||||
)
|
)
|
||||||
.into_response()
|
.into_response()
|
||||||
}
|
}
|
||||||
@ -86,12 +93,12 @@ pub fn add_execution_payload_value_header<T: Reply>(
|
|||||||
/// Add the `Eth-Consensus-Block-Value` header to a response.
|
/// Add the `Eth-Consensus-Block-Value` header to a response.
|
||||||
pub fn add_consensus_block_value_header<T: Reply>(
|
pub fn add_consensus_block_value_header<T: Reply>(
|
||||||
reply: T,
|
reply: T,
|
||||||
consensus_payload_value: Option<u64>,
|
consensus_payload_value: u64,
|
||||||
) -> Response {
|
) -> Response {
|
||||||
reply::with_header(
|
reply::with_header(
|
||||||
reply,
|
reply,
|
||||||
CONSENSUS_BLOCK_VALUE_HEADER,
|
CONSENSUS_BLOCK_VALUE_HEADER,
|
||||||
consensus_payload_value.unwrap_or_default().to_string(),
|
consensus_payload_value.to_string(),
|
||||||
)
|
)
|
||||||
.into_response()
|
.into_response()
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ use beacon_chain::{
|
|||||||
test_utils::{AttestationStrategy, BlockStrategy, SyncCommitteeStrategy},
|
test_utils::{AttestationStrategy, BlockStrategy, SyncCommitteeStrategy},
|
||||||
ChainConfig,
|
ChainConfig,
|
||||||
};
|
};
|
||||||
|
use eth2::types::ProduceBlockV3Response;
|
||||||
use eth2::types::{DepositContractData, StateId};
|
use eth2::types::{DepositContractData, StateId};
|
||||||
use execution_layer::{ForkchoiceState, PayloadAttributes};
|
use execution_layer::{ForkchoiceState, PayloadAttributes};
|
||||||
use http_api::test_utils::InteractiveTester;
|
use http_api::test_utils::InteractiveTester;
|
||||||
@ -21,8 +22,6 @@ use types::{
|
|||||||
MinimalEthSpec, ProposerPreparationData, Slot,
|
MinimalEthSpec, ProposerPreparationData, Slot,
|
||||||
};
|
};
|
||||||
|
|
||||||
use eth2::types::ForkVersionedBeaconBlockType::{Blinded, Full};
|
|
||||||
|
|
||||||
type E = MainnetEthSpec;
|
type E = MainnetEthSpec;
|
||||||
|
|
||||||
// Test that the deposit_contract endpoint returns the correct chain_id and address.
|
// Test that the deposit_contract endpoint returns the correct chain_id and address.
|
||||||
@ -113,8 +112,8 @@ async fn state_by_root_pruned_from_fork_choice() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(response.finalized.unwrap());
|
assert!(response.metadata.finalized.unwrap());
|
||||||
assert!(!response.execution_optimistic.unwrap());
|
assert!(!response.metadata.execution_optimistic.unwrap());
|
||||||
|
|
||||||
let mut state = response.data;
|
let mut state = response.data;
|
||||||
assert_eq!(state.update_tree_hash_cache().unwrap(), state_root);
|
assert_eq!(state.update_tree_hash_cache().unwrap(), state_root);
|
||||||
@ -619,15 +618,17 @@ pub async fn proposer_boost_re_org_test(
|
|||||||
let randao_reveal = harness
|
let randao_reveal = harness
|
||||||
.sign_randao_reveal(&state_b, proposer_index, slot_c)
|
.sign_randao_reveal(&state_b, proposer_index, slot_c)
|
||||||
.into();
|
.into();
|
||||||
let unsigned_block_type = tester
|
let (unsigned_block_type, _) = tester
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(slot_c, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(slot_c, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let (unsigned_block_c, block_c_blobs) = match unsigned_block_type {
|
let (unsigned_block_c, block_c_blobs) = match unsigned_block_type.data {
|
||||||
Full(unsigned_block_contents_c) => unsigned_block_contents_c.data.deconstruct(),
|
ProduceBlockV3Response::Full(unsigned_block_contents_c) => {
|
||||||
Blinded(_) => {
|
unsigned_block_contents_c.deconstruct()
|
||||||
|
}
|
||||||
|
ProduceBlockV3Response::Blinded(_) => {
|
||||||
panic!("Should not be a blinded block");
|
panic!("Should not be a blinded block");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,9 @@ use environment::null_logger;
|
|||||||
use eth2::{
|
use eth2::{
|
||||||
mixin::{RequestAccept, ResponseForkName, ResponseOptional},
|
mixin::{RequestAccept, ResponseForkName, ResponseOptional},
|
||||||
reqwest::RequestBuilder,
|
reqwest::RequestBuilder,
|
||||||
types::{BlockId as CoreBlockId, ForkChoiceNode, StateId as CoreStateId, *},
|
types::{
|
||||||
|
BlockId as CoreBlockId, ForkChoiceNode, ProduceBlockV3Response, StateId as CoreStateId, *,
|
||||||
|
},
|
||||||
BeaconNodeHttpClient, Error, StatusCode, Timeouts,
|
BeaconNodeHttpClient, Error, StatusCode, Timeouts,
|
||||||
};
|
};
|
||||||
use execution_layer::test_utils::{
|
use execution_layer::test_utils::{
|
||||||
@ -38,8 +40,6 @@ use types::{
|
|||||||
MainnetEthSpec, RelativeEpoch, SelectionProof, SignedRoot, Slot,
|
MainnetEthSpec, RelativeEpoch, SelectionProof, SignedRoot, Slot,
|
||||||
};
|
};
|
||||||
|
|
||||||
use eth2::types::ForkVersionedBeaconBlockType::{Blinded, Full};
|
|
||||||
|
|
||||||
type E = MainnetEthSpec;
|
type E = MainnetEthSpec;
|
||||||
|
|
||||||
const SECONDS_PER_SLOT: u64 = 12;
|
const SECONDS_PER_SLOT: u64 = 12;
|
||||||
@ -655,6 +655,7 @@ impl ApiTester {
|
|||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
.metadata
|
||||||
.finalized
|
.finalized
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -691,6 +692,7 @@ impl ApiTester {
|
|||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
.metadata
|
||||||
.finalized
|
.finalized
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -728,6 +730,7 @@ impl ApiTester {
|
|||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
.metadata
|
||||||
.finalized
|
.finalized
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -2725,52 +2728,57 @@ impl ApiTester {
|
|||||||
sk.sign(message).into()
|
sk.sign(message).into()
|
||||||
};
|
};
|
||||||
|
|
||||||
let (fork_version_response_bytes, is_blinded_payload) = self
|
let (response, metadata) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3_ssz::<E>(slot, &randao_reveal, None)
|
.get_validator_blocks_v3_ssz::<E>(slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
if is_blinded_payload {
|
match response {
|
||||||
let blinded_block = <BlindedBeaconBlock<E>>::from_ssz_bytes(
|
ProduceBlockV3Response::Blinded(blinded_block) => {
|
||||||
&fork_version_response_bytes.unwrap(),
|
assert!(metadata.execution_payload_blinded);
|
||||||
&self.chain.spec,
|
assert_eq!(
|
||||||
)
|
metadata.consensus_version,
|
||||||
.expect("block contents bytes can be decoded");
|
blinded_block.to_ref().fork_name(&self.chain.spec).unwrap()
|
||||||
|
);
|
||||||
|
let signed_blinded_block =
|
||||||
|
blinded_block.sign(&sk, &fork, genesis_validators_root, &self.chain.spec);
|
||||||
|
|
||||||
let signed_blinded_block =
|
self.client
|
||||||
blinded_block.sign(&sk, &fork, genesis_validators_root, &self.chain.spec);
|
.post_beacon_blinded_blocks_ssz(&signed_blinded_block)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
self.client
|
let head_block = self.chain.head_beacon_block().clone_as_blinded();
|
||||||
.post_beacon_blinded_blocks_ssz(&signed_blinded_block)
|
assert_eq!(head_block, signed_blinded_block);
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let head_block = self.chain.head_beacon_block().clone_as_blinded();
|
self.chain.slot_clock.set_slot(slot.as_u64() + 1);
|
||||||
assert_eq!(head_block, signed_blinded_block);
|
}
|
||||||
|
ProduceBlockV3Response::Full(block_contents) => {
|
||||||
|
assert!(!metadata.execution_payload_blinded);
|
||||||
|
assert_eq!(
|
||||||
|
metadata.consensus_version,
|
||||||
|
block_contents
|
||||||
|
.block()
|
||||||
|
.to_ref()
|
||||||
|
.fork_name(&self.chain.spec)
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
let signed_block_contents =
|
||||||
|
block_contents.sign(&sk, &fork, genesis_validators_root, &self.chain.spec);
|
||||||
|
|
||||||
self.chain.slot_clock.set_slot(slot.as_u64() + 1);
|
self.client
|
||||||
} else {
|
.post_beacon_blocks_ssz(&signed_block_contents)
|
||||||
let block_contents = <FullBlockContents<E>>::from_ssz_bytes(
|
.await
|
||||||
&fork_version_response_bytes.unwrap(),
|
.unwrap();
|
||||||
&self.chain.spec,
|
|
||||||
)
|
|
||||||
.expect("block contents bytes can be decoded");
|
|
||||||
|
|
||||||
let signed_block_contents =
|
assert_eq!(
|
||||||
block_contents.sign(&sk, &fork, genesis_validators_root, &self.chain.spec);
|
self.chain.head_beacon_block().as_ref(),
|
||||||
|
signed_block_contents.signed_block()
|
||||||
|
);
|
||||||
|
|
||||||
self.client
|
self.chain.slot_clock.set_slot(slot.as_u64() + 1);
|
||||||
.post_beacon_blocks_ssz(&signed_block_contents)
|
}
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
self.chain.head_beacon_block().as_ref(),
|
|
||||||
signed_block_contents.signed_block()
|
|
||||||
);
|
|
||||||
|
|
||||||
self.chain.slot_clock.set_slot(slot.as_u64() + 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3543,15 +3551,17 @@ impl ApiTester {
|
|||||||
|
|
||||||
let (proposer_index, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
let (proposer_index, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let payload: BlindedPayload<E> = match payload_type {
|
let payload: BlindedPayload<E> = match payload_type.data {
|
||||||
Blinded(payload) => payload.data.body().execution_payload().unwrap().into(),
|
ProduceBlockV3Response::Blinded(payload) => {
|
||||||
Full(_) => panic!("Expecting a blinded payload"),
|
payload.body().execution_payload().unwrap().into()
|
||||||
|
}
|
||||||
|
ProduceBlockV3Response::Full(_) => panic!("Expecting a blinded payload"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index as u64);
|
let expected_fee_recipient = Address::from_low_u64_be(proposer_index as u64);
|
||||||
@ -3645,15 +3655,17 @@ impl ApiTester {
|
|||||||
|
|
||||||
let (proposer_index, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
let (proposer_index, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let payload: BlindedPayload<E> = match payload_type {
|
let payload: BlindedPayload<E> = match payload_type.data {
|
||||||
Blinded(payload) => payload.data.body().execution_payload().unwrap().into(),
|
ProduceBlockV3Response::Blinded(payload) => {
|
||||||
Full(_) => panic!("Expecting a blinded payload"),
|
payload.body().execution_payload().unwrap().into()
|
||||||
|
}
|
||||||
|
ProduceBlockV3Response::Full(_) => panic!("Expecting a blinded payload"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index as u64);
|
let expected_fee_recipient = Address::from_low_u64_be(proposer_index as u64);
|
||||||
@ -3719,15 +3731,17 @@ impl ApiTester {
|
|||||||
|
|
||||||
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let payload: BlindedPayload<E> = match payload_type {
|
let payload: BlindedPayload<E> = match payload_type.data {
|
||||||
Blinded(payload) => payload.data.body().execution_payload().unwrap().into(),
|
ProduceBlockV3Response::Blinded(payload) => {
|
||||||
Full(_) => panic!("Expecting a blinded payload"),
|
payload.body().execution_payload().unwrap().into()
|
||||||
|
}
|
||||||
|
ProduceBlockV3Response::Full(_) => panic!("Expecting a blinded payload"),
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(payload.fee_recipient(), test_fee_recipient);
|
assert_eq!(payload.fee_recipient(), test_fee_recipient);
|
||||||
@ -3807,21 +3821,17 @@ impl ApiTester {
|
|||||||
|
|
||||||
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let payload: FullPayload<E> = match payload_type {
|
let payload: FullPayload<E> = match payload_type.data {
|
||||||
Full(payload) => payload
|
ProduceBlockV3Response::Full(payload) => {
|
||||||
.data
|
payload.block().body().execution_payload().unwrap().into()
|
||||||
.block()
|
}
|
||||||
.body()
|
ProduceBlockV3Response::Blinded(_) => panic!("Expecting a blinded payload"),
|
||||||
.execution_payload()
|
|
||||||
.unwrap()
|
|
||||||
.into(),
|
|
||||||
Blinded(_) => panic!("Expecting a blinded payload"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(payload.parent_hash(), expected_parent_hash);
|
assert_eq!(payload.parent_hash(), expected_parent_hash);
|
||||||
@ -3897,21 +3907,17 @@ impl ApiTester {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let payload: FullPayload<E> = match payload_type {
|
let payload: FullPayload<E> = match payload_type.data {
|
||||||
Full(payload) => payload
|
ProduceBlockV3Response::Full(payload) => {
|
||||||
.data
|
payload.block().body().execution_payload().unwrap().into()
|
||||||
.block()
|
}
|
||||||
.body()
|
ProduceBlockV3Response::Blinded(_) => panic!("Expecting a full payload"),
|
||||||
.execution_payload()
|
|
||||||
.unwrap()
|
|
||||||
.into(),
|
|
||||||
Blinded(_) => panic!("Expecting a full payload"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(payload.prev_randao(), expected_prev_randao);
|
assert_eq!(payload.prev_randao(), expected_prev_randao);
|
||||||
@ -3987,21 +3993,17 @@ impl ApiTester {
|
|||||||
|
|
||||||
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let payload: FullPayload<E> = match payload_type {
|
let payload: FullPayload<E> = match payload_type.data {
|
||||||
Full(payload) => payload
|
ProduceBlockV3Response::Full(payload) => {
|
||||||
.data
|
payload.block().body().execution_payload().unwrap().into()
|
||||||
.block()
|
}
|
||||||
.body()
|
ProduceBlockV3Response::Blinded(_) => panic!("Expecting a full payload"),
|
||||||
.execution_payload()
|
|
||||||
.unwrap()
|
|
||||||
.into(),
|
|
||||||
Blinded(_) => panic!("Expecting a full payload"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(payload.block_number(), expected_block_number);
|
assert_eq!(payload.block_number(), expected_block_number);
|
||||||
@ -4075,21 +4077,17 @@ impl ApiTester {
|
|||||||
|
|
||||||
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let payload: FullPayload<E> = match payload_type {
|
let payload: FullPayload<E> = match payload_type.data {
|
||||||
Full(payload) => payload
|
ProduceBlockV3Response::Full(payload) => {
|
||||||
.data
|
payload.block().body().execution_payload().unwrap().into()
|
||||||
.block()
|
}
|
||||||
.body()
|
ProduceBlockV3Response::Blinded(_) => panic!("Expecting a blinded payload"),
|
||||||
.execution_payload()
|
|
||||||
.unwrap()
|
|
||||||
.into(),
|
|
||||||
Blinded(_) => panic!("Expecting a blinded payload"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(payload.timestamp() > min_expected_timestamp);
|
assert!(payload.timestamp() > min_expected_timestamp);
|
||||||
@ -4135,15 +4133,15 @@ impl ApiTester {
|
|||||||
|
|
||||||
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
match payload_type {
|
match payload_type.data {
|
||||||
Full(_) => (),
|
ProduceBlockV3Response::Full(_) => (),
|
||||||
Blinded(_) => panic!("Expecting a full payload"),
|
ProduceBlockV3Response::Blinded(_) => panic!("Expecting a full payload"),
|
||||||
};
|
};
|
||||||
|
|
||||||
self
|
self
|
||||||
@ -4201,15 +4199,15 @@ impl ApiTester {
|
|||||||
|
|
||||||
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
match payload_type {
|
match payload_type.data {
|
||||||
Full(_) => (),
|
ProduceBlockV3Response::Full(_) => (),
|
||||||
Blinded(_) => panic!("Expecting a full payload"),
|
ProduceBlockV3Response::Blinded(_) => panic!("Expecting a full payload"),
|
||||||
};
|
};
|
||||||
|
|
||||||
self
|
self
|
||||||
@ -4309,15 +4307,15 @@ impl ApiTester {
|
|||||||
.get_test_randao(next_slot, next_slot.epoch(E::slots_per_epoch()))
|
.get_test_randao(next_slot, next_slot.epoch(E::slots_per_epoch()))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(next_slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(next_slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
match payload_type {
|
match payload_type.data {
|
||||||
Blinded(_) => (),
|
ProduceBlockV3Response::Blinded(_) => (),
|
||||||
Full(_) => panic!("Expecting a blinded payload"),
|
ProduceBlockV3Response::Full(_) => panic!("Expecting a blinded payload"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Without proposing, advance into the next slot, this should make us cross the threshold
|
// Without proposing, advance into the next slot, this should make us cross the threshold
|
||||||
@ -4329,15 +4327,15 @@ impl ApiTester {
|
|||||||
.get_test_randao(next_slot, next_slot.epoch(E::slots_per_epoch()))
|
.get_test_randao(next_slot, next_slot.epoch(E::slots_per_epoch()))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(next_slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(next_slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
match payload_type {
|
match payload_type.data {
|
||||||
Full(_) => (),
|
ProduceBlockV3Response::Full(_) => (),
|
||||||
Blinded(_) => panic!("Expecting a full payload"),
|
ProduceBlockV3Response::Blinded(_) => panic!("Expecting a full payload"),
|
||||||
};
|
};
|
||||||
|
|
||||||
self
|
self
|
||||||
@ -4457,15 +4455,15 @@ impl ApiTester {
|
|||||||
.get_test_randao(next_slot, next_slot.epoch(E::slots_per_epoch()))
|
.get_test_randao(next_slot, next_slot.epoch(E::slots_per_epoch()))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(next_slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(next_slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
match payload_type {
|
match payload_type.data {
|
||||||
Full(_) => (),
|
ProduceBlockV3Response::Full(_) => (),
|
||||||
Blinded(_) => panic!("Expecting a full payload"),
|
ProduceBlockV3Response::Blinded(_) => panic!("Expecting a full payload"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fill another epoch with blocks, should be enough to finalize. (Sneaky plus 1 because this
|
// Fill another epoch with blocks, should be enough to finalize. (Sneaky plus 1 because this
|
||||||
@ -4487,15 +4485,15 @@ impl ApiTester {
|
|||||||
.get_test_randao(next_slot, next_slot.epoch(E::slots_per_epoch()))
|
.get_test_randao(next_slot, next_slot.epoch(E::slots_per_epoch()))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(next_slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(next_slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
match payload_type {
|
match payload_type.data {
|
||||||
Blinded(_) => (),
|
ProduceBlockV3Response::Blinded(_) => (),
|
||||||
Full(_) => panic!("Expecting a blinded payload"),
|
ProduceBlockV3Response::Full(_) => panic!("Expecting a blinded payload"),
|
||||||
};
|
};
|
||||||
|
|
||||||
self
|
self
|
||||||
@ -4567,21 +4565,17 @@ impl ApiTester {
|
|||||||
|
|
||||||
let (proposer_index, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
let (proposer_index, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let payload: FullPayload<E> = match payload_type {
|
let payload: FullPayload<E> = match payload_type.data {
|
||||||
Full(payload) => payload
|
ProduceBlockV3Response::Full(payload) => {
|
||||||
.data
|
payload.block().body().execution_payload().unwrap().into()
|
||||||
.block()
|
}
|
||||||
.body()
|
ProduceBlockV3Response::Blinded(_) => panic!("Expecting a full payload"),
|
||||||
.execution_payload()
|
|
||||||
.unwrap()
|
|
||||||
.into(),
|
|
||||||
Blinded(_) => panic!("Expecting a full payload"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let expected_fee_recipient = Address::from_low_u64_be(proposer_index as u64);
|
let expected_fee_recipient = Address::from_low_u64_be(proposer_index as u64);
|
||||||
@ -4640,15 +4634,15 @@ impl ApiTester {
|
|||||||
|
|
||||||
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
match payload_type {
|
match payload_type.data {
|
||||||
Full(_) => (),
|
ProduceBlockV3Response::Full(_) => (),
|
||||||
Blinded(_) => panic!("Expecting a full payload"),
|
ProduceBlockV3Response::Blinded(_) => panic!("Expecting a full payload"),
|
||||||
};
|
};
|
||||||
|
|
||||||
self
|
self
|
||||||
@ -4704,15 +4698,15 @@ impl ApiTester {
|
|||||||
|
|
||||||
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
match payload_type {
|
match payload_type.data {
|
||||||
Blinded(_) => (),
|
ProduceBlockV3Response::Blinded(_) => (),
|
||||||
Full(_) => panic!("Expecting a blinded payload"),
|
ProduceBlockV3Response::Full(_) => panic!("Expecting a blinded payload"),
|
||||||
};
|
};
|
||||||
|
|
||||||
self
|
self
|
||||||
@ -4768,15 +4762,15 @@ impl ApiTester {
|
|||||||
|
|
||||||
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
match payload_type {
|
match payload_type.data {
|
||||||
Full(_) => (),
|
ProduceBlockV3Response::Full(_) => (),
|
||||||
Blinded(_) => panic!("Expecting a full payload"),
|
ProduceBlockV3Response::Blinded(_) => panic!("Expecting a full payload"),
|
||||||
};
|
};
|
||||||
|
|
||||||
self
|
self
|
||||||
@ -4832,15 +4826,15 @@ impl ApiTester {
|
|||||||
|
|
||||||
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
match payload_type {
|
match payload_type.data {
|
||||||
Full(_) => (),
|
ProduceBlockV3Response::Full(_) => (),
|
||||||
Blinded(_) => panic!("Expecting a full payload"),
|
ProduceBlockV3Response::Blinded(_) => panic!("Expecting a full payload"),
|
||||||
};
|
};
|
||||||
|
|
||||||
self
|
self
|
||||||
@ -4894,15 +4888,15 @@ impl ApiTester {
|
|||||||
let epoch = self.chain.epoch().unwrap();
|
let epoch = self.chain.epoch().unwrap();
|
||||||
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let _block_contents = match payload_type {
|
let _block_contents = match payload_type.data {
|
||||||
Blinded(payload) => payload.data,
|
ProduceBlockV3Response::Blinded(payload) => payload,
|
||||||
Full(_) => panic!("Expecting a blinded payload"),
|
ProduceBlockV3Response::Full(_) => panic!("Expecting a blinded payload"),
|
||||||
};
|
};
|
||||||
|
|
||||||
self
|
self
|
||||||
@ -4966,15 +4960,15 @@ impl ApiTester {
|
|||||||
let epoch = self.chain.epoch().unwrap();
|
let epoch = self.chain.epoch().unwrap();
|
||||||
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
let (_, randao_reveal) = self.get_test_randao(slot, epoch).await;
|
||||||
|
|
||||||
let payload_type = self
|
let (payload_type, _) = self
|
||||||
.client
|
.client
|
||||||
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
.get_validator_blocks_v3::<E>(slot, &randao_reveal, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
match payload_type {
|
match payload_type.data {
|
||||||
Full(_) => (),
|
ProduceBlockV3Response::Full(_) => (),
|
||||||
Blinded(_) => panic!("Expecting a full payload"),
|
ProduceBlockV3Response::Blinded(_) => panic!("Expecting a full payload"),
|
||||||
};
|
};
|
||||||
|
|
||||||
self
|
self
|
||||||
|
@ -31,6 +31,7 @@ use serde::{de::DeserializeOwned, Serialize};
|
|||||||
use ssz::Encode;
|
use ssz::Encode;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::future::Future;
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@ -67,6 +68,8 @@ pub enum Error {
|
|||||||
InvalidJson(serde_json::Error),
|
InvalidJson(serde_json::Error),
|
||||||
/// The server returned an invalid server-sent event.
|
/// The server returned an invalid server-sent event.
|
||||||
InvalidServerSentEvent(String),
|
InvalidServerSentEvent(String),
|
||||||
|
/// The server sent invalid response headers.
|
||||||
|
InvalidHeaders(String),
|
||||||
/// The server returned an invalid SSZ response.
|
/// The server returned an invalid SSZ response.
|
||||||
InvalidSsz(ssz::DecodeError),
|
InvalidSsz(ssz::DecodeError),
|
||||||
/// An I/O error occurred while loading an API token from disk.
|
/// An I/O error occurred while loading an API token from disk.
|
||||||
@ -97,6 +100,7 @@ impl Error {
|
|||||||
Error::MissingSignatureHeader => None,
|
Error::MissingSignatureHeader => None,
|
||||||
Error::InvalidJson(_) => None,
|
Error::InvalidJson(_) => None,
|
||||||
Error::InvalidServerSentEvent(_) => None,
|
Error::InvalidServerSentEvent(_) => None,
|
||||||
|
Error::InvalidHeaders(_) => None,
|
||||||
Error::InvalidSsz(_) => None,
|
Error::InvalidSsz(_) => None,
|
||||||
Error::TokenReadError(..) => None,
|
Error::TokenReadError(..) => None,
|
||||||
Error::NoServerPubkey | Error::NoToken => None,
|
Error::NoServerPubkey | Error::NoToken => None,
|
||||||
@ -124,7 +128,7 @@ pub struct Timeouts {
|
|||||||
pub get_beacon_blocks_ssz: Duration,
|
pub get_beacon_blocks_ssz: Duration,
|
||||||
pub get_debug_beacon_states: Duration,
|
pub get_debug_beacon_states: Duration,
|
||||||
pub get_deposit_snapshot: Duration,
|
pub get_deposit_snapshot: Duration,
|
||||||
pub get_validator_block_ssz: Duration,
|
pub get_validator_block: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Timeouts {
|
impl Timeouts {
|
||||||
@ -140,7 +144,7 @@ impl Timeouts {
|
|||||||
get_beacon_blocks_ssz: timeout,
|
get_beacon_blocks_ssz: timeout,
|
||||||
get_debug_beacon_states: timeout,
|
get_debug_beacon_states: timeout,
|
||||||
get_deposit_snapshot: timeout,
|
get_deposit_snapshot: timeout,
|
||||||
get_validator_block_ssz: timeout,
|
get_validator_block: timeout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -273,27 +277,28 @@ impl BeaconNodeHttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Perform a HTTP GET request using an 'accept' header, returning `None` on a 404 error.
|
/// Perform a HTTP GET request using an 'accept' header, returning `None` on a 404 error.
|
||||||
pub async fn get_bytes_response_with_response_headers<U: IntoUrl>(
|
pub async fn get_response_with_response_headers<U: IntoUrl, F, T>(
|
||||||
&self,
|
&self,
|
||||||
url: U,
|
url: U,
|
||||||
accept_header: Accept,
|
accept_header: Accept,
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
) -> Result<(Option<Vec<u8>>, Option<HeaderMap>), Error> {
|
parser: impl FnOnce(Response, HeaderMap) -> F,
|
||||||
|
) -> Result<Option<T>, Error>
|
||||||
|
where
|
||||||
|
F: Future<Output = Result<T, Error>>,
|
||||||
|
{
|
||||||
let opt_response = self
|
let opt_response = self
|
||||||
.get_response(url, |b| b.accept(accept_header).timeout(timeout))
|
.get_response(url, |b| b.accept(accept_header).timeout(timeout))
|
||||||
.await
|
.await
|
||||||
.optional()?;
|
.optional()?;
|
||||||
|
|
||||||
// let headers = opt_response.headers();
|
|
||||||
match opt_response {
|
match opt_response {
|
||||||
Some(resp) => {
|
Some(resp) => {
|
||||||
let response_headers = resp.headers().clone();
|
let response_headers = resp.headers().clone();
|
||||||
Ok((
|
let parsed_response = parser(resp, response_headers).await?;
|
||||||
Some(resp.bytes().await?.into_iter().collect::<Vec<_>>()),
|
Ok(Some(parsed_response))
|
||||||
Some(response_headers),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
None => Ok((None, None)),
|
None => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1816,7 +1821,7 @@ impl BeaconNodeHttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// returns `GET v3/validator/blocks/{slot}` URL path
|
/// returns `GET v3/validator/blocks/{slot}` URL path
|
||||||
pub async fn get_validator_blocks_v3_path<T: EthSpec>(
|
pub async fn get_validator_blocks_v3_path(
|
||||||
&self,
|
&self,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
randao_reveal: &SignatureBytes,
|
randao_reveal: &SignatureBytes,
|
||||||
@ -1853,7 +1858,7 @@ impl BeaconNodeHttpClient {
|
|||||||
slot: Slot,
|
slot: Slot,
|
||||||
randao_reveal: &SignatureBytes,
|
randao_reveal: &SignatureBytes,
|
||||||
graffiti: Option<&Graffiti>,
|
graffiti: Option<&Graffiti>,
|
||||||
) -> Result<ForkVersionedBeaconBlockType<T>, Error> {
|
) -> Result<(JsonProduceBlockV3Response<T>, ProduceBlockV3Metadata), Error> {
|
||||||
self.get_validator_blocks_v3_modular(
|
self.get_validator_blocks_v3_modular(
|
||||||
slot,
|
slot,
|
||||||
randao_reveal,
|
randao_reveal,
|
||||||
@ -1870,35 +1875,41 @@ impl BeaconNodeHttpClient {
|
|||||||
randao_reveal: &SignatureBytes,
|
randao_reveal: &SignatureBytes,
|
||||||
graffiti: Option<&Graffiti>,
|
graffiti: Option<&Graffiti>,
|
||||||
skip_randao_verification: SkipRandaoVerification,
|
skip_randao_verification: SkipRandaoVerification,
|
||||||
) -> Result<ForkVersionedBeaconBlockType<T>, Error> {
|
) -> Result<(JsonProduceBlockV3Response<T>, ProduceBlockV3Metadata), Error> {
|
||||||
let path = self
|
let path = self
|
||||||
.get_validator_blocks_v3_path::<T>(
|
.get_validator_blocks_v3_path(slot, randao_reveal, graffiti, skip_randao_verification)
|
||||||
slot,
|
.await?;
|
||||||
randao_reveal,
|
|
||||||
graffiti,
|
let opt_result = self
|
||||||
skip_randao_verification,
|
.get_response_with_response_headers(
|
||||||
|
path,
|
||||||
|
Accept::Json,
|
||||||
|
self.timeouts.get_validator_block,
|
||||||
|
|response, headers| async move {
|
||||||
|
let header_metadata = ProduceBlockV3Metadata::try_from(&headers)
|
||||||
|
.map_err(Error::InvalidHeaders)?;
|
||||||
|
if header_metadata.execution_payload_blinded {
|
||||||
|
let blinded_response = response
|
||||||
|
.json::<ForkVersionedResponse<BlindedBeaconBlock<T>,
|
||||||
|
ProduceBlockV3Metadata>>()
|
||||||
|
.await?
|
||||||
|
.map_data(ProduceBlockV3Response::Blinded);
|
||||||
|
Ok((blinded_response, header_metadata))
|
||||||
|
} else {
|
||||||
|
let full_block_response= response
|
||||||
|
.json::<ForkVersionedResponse<FullBlockContents<T>,
|
||||||
|
ProduceBlockV3Metadata>>()
|
||||||
|
.await?
|
||||||
|
.map_data(ProduceBlockV3Response::Full);
|
||||||
|
Ok((full_block_response, header_metadata))
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let response = self.get_response(path, |b| b).await?;
|
// Generic handler is optional but this route should never 404 unless unimplemented, so
|
||||||
|
// treat that as an error.
|
||||||
let is_blinded_payload = response
|
opt_result.ok_or(Error::StatusCode(StatusCode::NOT_FOUND))
|
||||||
.headers()
|
|
||||||
.get(EXECUTION_PAYLOAD_BLINDED_HEADER)
|
|
||||||
.map(|value| value.to_str().unwrap_or_default().to_lowercase() == "true")
|
|
||||||
.unwrap_or(false);
|
|
||||||
|
|
||||||
if is_blinded_payload {
|
|
||||||
let blinded_payload = response
|
|
||||||
.json::<ForkVersionedResponse<BlindedBeaconBlock<T>>>()
|
|
||||||
.await?;
|
|
||||||
Ok(ForkVersionedBeaconBlockType::Blinded(blinded_payload))
|
|
||||||
} else {
|
|
||||||
let full_payload = response
|
|
||||||
.json::<ForkVersionedResponse<FullBlockContents<T>>>()
|
|
||||||
.await?;
|
|
||||||
Ok(ForkVersionedBeaconBlockType::Full(full_payload))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `GET v3/validator/blocks/{slot}` in ssz format
|
/// `GET v3/validator/blocks/{slot}` in ssz format
|
||||||
@ -1907,7 +1918,7 @@ impl BeaconNodeHttpClient {
|
|||||||
slot: Slot,
|
slot: Slot,
|
||||||
randao_reveal: &SignatureBytes,
|
randao_reveal: &SignatureBytes,
|
||||||
graffiti: Option<&Graffiti>,
|
graffiti: Option<&Graffiti>,
|
||||||
) -> Result<(Option<Vec<u8>>, bool), Error> {
|
) -> Result<(ProduceBlockV3Response<T>, ProduceBlockV3Metadata), Error> {
|
||||||
self.get_validator_blocks_v3_modular_ssz::<T>(
|
self.get_validator_blocks_v3_modular_ssz::<T>(
|
||||||
slot,
|
slot,
|
||||||
randao_reveal,
|
randao_reveal,
|
||||||
@ -1924,33 +1935,48 @@ impl BeaconNodeHttpClient {
|
|||||||
randao_reveal: &SignatureBytes,
|
randao_reveal: &SignatureBytes,
|
||||||
graffiti: Option<&Graffiti>,
|
graffiti: Option<&Graffiti>,
|
||||||
skip_randao_verification: SkipRandaoVerification,
|
skip_randao_verification: SkipRandaoVerification,
|
||||||
) -> Result<(Option<Vec<u8>>, bool), Error> {
|
) -> Result<(ProduceBlockV3Response<T>, ProduceBlockV3Metadata), Error> {
|
||||||
let path = self
|
let path = self
|
||||||
.get_validator_blocks_v3_path::<T>(
|
.get_validator_blocks_v3_path(slot, randao_reveal, graffiti, skip_randao_verification)
|
||||||
slot,
|
|
||||||
randao_reveal,
|
|
||||||
graffiti,
|
|
||||||
skip_randao_verification,
|
|
||||||
)
|
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let (response_content, response_headers) = self
|
let opt_response = self
|
||||||
.get_bytes_response_with_response_headers(
|
.get_response_with_response_headers(
|
||||||
path,
|
path,
|
||||||
Accept::Ssz,
|
Accept::Ssz,
|
||||||
self.timeouts.get_validator_block_ssz,
|
self.timeouts.get_validator_block,
|
||||||
|
|response, headers| async move {
|
||||||
|
let metadata = ProduceBlockV3Metadata::try_from(&headers)
|
||||||
|
.map_err(Error::InvalidHeaders)?;
|
||||||
|
let response_bytes = response.bytes().await?;
|
||||||
|
|
||||||
|
// Parse bytes based on metadata.
|
||||||
|
let response = if metadata.execution_payload_blinded {
|
||||||
|
ProduceBlockV3Response::Blinded(
|
||||||
|
BlindedBeaconBlock::from_ssz_bytes_for_fork(
|
||||||
|
&response_bytes,
|
||||||
|
metadata.consensus_version,
|
||||||
|
)
|
||||||
|
.map_err(Error::InvalidSsz)?,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
ProduceBlockV3Response::Full(
|
||||||
|
FullBlockContents::from_ssz_bytes_for_fork(
|
||||||
|
&response_bytes,
|
||||||
|
metadata.consensus_version,
|
||||||
|
)
|
||||||
|
.map_err(Error::InvalidSsz)?,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((response, metadata))
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let is_blinded_payload = match response_headers {
|
// Generic handler is optional but this route should never 404 unless unimplemented, so
|
||||||
Some(headers) => headers
|
// treat that as an error.
|
||||||
.get(EXECUTION_PAYLOAD_BLINDED_HEADER)
|
opt_response.ok_or(Error::StatusCode(StatusCode::NOT_FOUND))
|
||||||
.map(|value| value.to_str().unwrap_or_default().to_lowercase() == "true")
|
|
||||||
.unwrap_or(false),
|
|
||||||
None => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok((response_content, is_blinded_payload))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `GET v2/validator/blocks/{slot}` in ssz format
|
/// `GET v2/validator/blocks/{slot}` in ssz format
|
||||||
@ -1981,7 +2007,7 @@ impl BeaconNodeHttpClient {
|
|||||||
.get_validator_blocks_path::<T>(slot, randao_reveal, graffiti, skip_randao_verification)
|
.get_validator_blocks_path::<T>(slot, randao_reveal, graffiti, skip_randao_verification)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
self.get_bytes_opt_accept_header(path, Accept::Ssz, self.timeouts.get_validator_block_ssz)
|
self.get_bytes_opt_accept_header(path, Accept::Ssz, self.timeouts.get_validator_block)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2085,7 +2111,7 @@ impl BeaconNodeHttpClient {
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
self.get_bytes_opt_accept_header(path, Accept::Ssz, self.timeouts.get_validator_block_ssz)
|
self.get_bytes_opt_accept_header(path, Accept::Ssz, self.timeouts.get_validator_block)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
//! This module exposes a superset of the `types` crate. It adds additional types that are only
|
//! This module exposes a superset of the `types` crate. It adds additional types that are only
|
||||||
//! required for the HTTP API.
|
//! required for the HTTP API.
|
||||||
|
|
||||||
use crate::Error as ServerError;
|
use crate::{
|
||||||
|
Error as ServerError, CONSENSUS_BLOCK_VALUE_HEADER, CONSENSUS_VERSION_HEADER,
|
||||||
|
EXECUTION_PAYLOAD_BLINDED_HEADER, EXECUTION_PAYLOAD_VALUE_HEADER,
|
||||||
|
};
|
||||||
use lighthouse_network::{ConnectionDirection, Enr, Multiaddr, PeerConnectionStatus};
|
use lighthouse_network::{ConnectionDirection, Enr, Multiaddr, PeerConnectionStatus};
|
||||||
use mediatype::{names, MediaType, MediaTypeList};
|
use mediatype::{names, MediaType, MediaTypeList};
|
||||||
|
use reqwest::header::HeaderMap;
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use ssz::{Decode, DecodeError};
|
use ssz::{Decode, DecodeError};
|
||||||
@ -1430,11 +1434,6 @@ pub mod serde_status_code {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ForkVersionedBeaconBlockType<T: EthSpec> {
|
|
||||||
Full(ForkVersionedResponse<FullBlockContents<T>>),
|
|
||||||
Blinded(ForkVersionedResponse<BlindedBeaconBlock<T>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -1521,6 +1520,9 @@ pub enum ProduceBlockV3Response<E: EthSpec> {
|
|||||||
Blinded(BlindedBeaconBlock<E>),
|
Blinded(BlindedBeaconBlock<E>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type JsonProduceBlockV3Response<E> =
|
||||||
|
ForkVersionedResponse<ProduceBlockV3Response<E>, ProduceBlockV3Metadata>;
|
||||||
|
|
||||||
/// A wrapper over a [`BeaconBlock`] or a [`BlockContents`].
|
/// A wrapper over a [`BeaconBlock`] or a [`BlockContents`].
|
||||||
#[derive(Debug, Encode, Serialize, Deserialize)]
|
#[derive(Debug, Encode, Serialize, Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
@ -1535,6 +1537,27 @@ pub enum FullBlockContents<T: EthSpec> {
|
|||||||
|
|
||||||
pub type BlockContentsTuple<T> = (BeaconBlock<T>, Option<(KzgProofs<T>, BlobsList<T>)>);
|
pub type BlockContentsTuple<T> = (BeaconBlock<T>, Option<(KzgProofs<T>, BlobsList<T>)>);
|
||||||
|
|
||||||
|
// This value should never be used
|
||||||
|
fn dummy_consensus_version() -> ForkName {
|
||||||
|
ForkName::Base
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Metadata about a `ProduceBlockV3Response` which is returned in the body & headers.
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub struct ProduceBlockV3Metadata {
|
||||||
|
// The consensus version is serialized & deserialized by `ForkVersionedResponse`.
|
||||||
|
#[serde(
|
||||||
|
skip_serializing,
|
||||||
|
skip_deserializing,
|
||||||
|
default = "dummy_consensus_version"
|
||||||
|
)]
|
||||||
|
pub consensus_version: ForkName,
|
||||||
|
pub execution_payload_blinded: bool,
|
||||||
|
pub execution_payload_value: Uint256,
|
||||||
|
#[serde(with = "serde_utils::quoted_u64")]
|
||||||
|
pub consensus_block_value: u64,
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: EthSpec> FullBlockContents<T> {
|
impl<T: EthSpec> FullBlockContents<T> {
|
||||||
pub fn new(block: BeaconBlock<T>, blob_data: Option<(KzgProofs<T>, BlobsList<T>)>) -> Self {
|
pub fn new(block: BeaconBlock<T>, blob_data: Option<(KzgProofs<T>, BlobsList<T>)>) -> Self {
|
||||||
match blob_data {
|
match blob_data {
|
||||||
@ -1556,13 +1579,19 @@ impl<T: EthSpec> FullBlockContents<T> {
|
|||||||
len: bytes.len(),
|
len: bytes.len(),
|
||||||
expected: slot_len,
|
expected: slot_len,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let slot = Slot::from_ssz_bytes(slot_bytes)?;
|
let slot = Slot::from_ssz_bytes(slot_bytes)?;
|
||||||
let fork_at_slot = spec.fork_name_at_slot::<T>(slot);
|
let fork_at_slot = spec.fork_name_at_slot::<T>(slot);
|
||||||
|
Self::from_ssz_bytes_for_fork(bytes, fork_at_slot)
|
||||||
|
}
|
||||||
|
|
||||||
match fork_at_slot {
|
/// SSZ decode with fork variant passed in explicitly.
|
||||||
|
pub fn from_ssz_bytes_for_fork(
|
||||||
|
bytes: &[u8],
|
||||||
|
fork_name: ForkName,
|
||||||
|
) -> Result<Self, ssz::DecodeError> {
|
||||||
|
match fork_name {
|
||||||
ForkName::Base | ForkName::Altair | ForkName::Merge | ForkName::Capella => {
|
ForkName::Base | ForkName::Altair | ForkName::Merge | ForkName::Capella => {
|
||||||
BeaconBlock::from_ssz_bytes(bytes, spec)
|
BeaconBlock::from_ssz_bytes_for_fork(bytes, fork_name)
|
||||||
.map(|block| FullBlockContents::Block(block))
|
.map(|block| FullBlockContents::Block(block))
|
||||||
}
|
}
|
||||||
ForkName::Deneb => {
|
ForkName::Deneb => {
|
||||||
@ -1573,8 +1602,9 @@ impl<T: EthSpec> FullBlockContents<T> {
|
|||||||
builder.register_type::<BlobsList<T>>()?;
|
builder.register_type::<BlobsList<T>>()?;
|
||||||
|
|
||||||
let mut decoder = builder.build()?;
|
let mut decoder = builder.build()?;
|
||||||
let block =
|
let block = decoder.decode_next_with(|bytes| {
|
||||||
decoder.decode_next_with(|bytes| BeaconBlock::from_ssz_bytes(bytes, spec))?;
|
BeaconBlock::from_ssz_bytes_for_fork(bytes, fork_name)
|
||||||
|
})?;
|
||||||
let kzg_proofs = decoder.decode_next()?;
|
let kzg_proofs = decoder.decode_next()?;
|
||||||
let blobs = decoder.decode_next()?;
|
let blobs = decoder.decode_next()?;
|
||||||
|
|
||||||
@ -1643,6 +1673,52 @@ impl<T: EthSpec> Into<BeaconBlock<T>> for FullBlockContents<T> {
|
|||||||
|
|
||||||
pub type SignedBlockContentsTuple<T> = (SignedBeaconBlock<T>, Option<(KzgProofs<T>, BlobsList<T>)>);
|
pub type SignedBlockContentsTuple<T> = (SignedBeaconBlock<T>, Option<(KzgProofs<T>, BlobsList<T>)>);
|
||||||
|
|
||||||
|
fn parse_required_header<T>(
|
||||||
|
headers: &HeaderMap,
|
||||||
|
header_name: &str,
|
||||||
|
parse: impl FnOnce(&str) -> Result<T, String>,
|
||||||
|
) -> Result<T, String> {
|
||||||
|
let str_value = headers
|
||||||
|
.get(header_name)
|
||||||
|
.ok_or_else(|| format!("missing required header {header_name}"))?
|
||||||
|
.to_str()
|
||||||
|
.map_err(|e| format!("invalid value in {header_name}: {e}"))?;
|
||||||
|
parse(str_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&HeaderMap> for ProduceBlockV3Metadata {
|
||||||
|
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 execution_payload_blinded =
|
||||||
|
parse_required_header(headers, EXECUTION_PAYLOAD_BLINDED_HEADER, |s| {
|
||||||
|
s.parse::<bool>()
|
||||||
|
.map_err(|e| format!("invalid {EXECUTION_PAYLOAD_BLINDED_HEADER}: {e:?}"))
|
||||||
|
})?;
|
||||||
|
let execution_payload_value =
|
||||||
|
parse_required_header(headers, EXECUTION_PAYLOAD_VALUE_HEADER, |s| {
|
||||||
|
s.parse::<Uint256>()
|
||||||
|
.map_err(|e| format!("invalid {EXECUTION_PAYLOAD_VALUE_HEADER}: {e:?}"))
|
||||||
|
})?;
|
||||||
|
let consensus_block_value =
|
||||||
|
parse_required_header(headers, CONSENSUS_BLOCK_VALUE_HEADER, |s| {
|
||||||
|
s.parse::<u64>()
|
||||||
|
.map_err(|e| format!("invalid {CONSENSUS_BLOCK_VALUE_HEADER}: {e:?}"))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(ProduceBlockV3Metadata {
|
||||||
|
consensus_version,
|
||||||
|
execution_payload_blinded,
|
||||||
|
execution_payload_value,
|
||||||
|
consensus_block_value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A wrapper over a [`SignedBeaconBlock`] or a [`SignedBlockContents`].
|
/// A wrapper over a [`SignedBeaconBlock`] or a [`SignedBlockContents`].
|
||||||
#[derive(Clone, Debug, Encode, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Encode, Serialize, Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
|
@ -112,12 +112,15 @@ impl<T: EthSpec, Payload: AbstractExecPayload<T>> BeaconBlock<T, Payload> {
|
|||||||
|
|
||||||
let slot = Slot::from_ssz_bytes(slot_bytes)?;
|
let slot = Slot::from_ssz_bytes(slot_bytes)?;
|
||||||
let fork_at_slot = spec.fork_name_at_slot::<T>(slot);
|
let fork_at_slot = spec.fork_name_at_slot::<T>(slot);
|
||||||
|
Self::from_ssz_bytes_for_fork(bytes, fork_at_slot)
|
||||||
|
}
|
||||||
|
|
||||||
Ok(map_fork_name!(
|
/// Custom SSZ decoder that takes a `ForkName` as context.
|
||||||
fork_at_slot,
|
pub fn from_ssz_bytes_for_fork(
|
||||||
Self,
|
bytes: &[u8],
|
||||||
<_>::from_ssz_bytes(bytes)?
|
fork_name: ForkName,
|
||||||
))
|
) -> Result<Self, ssz::DecodeError> {
|
||||||
|
Ok(map_fork_name!(fork_name, Self, <_>::from_ssz_bytes(bytes)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try decoding each beacon block variant in sequence.
|
/// Try decoding each beacon block variant in sequence.
|
||||||
|
@ -4,47 +4,6 @@ use serde::{Deserialize, Deserializer, Serialize};
|
|||||||
use serde_json::value::Value;
|
use serde_json::value::Value;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
// Deserialize is only implemented for types that implement ForkVersionDeserialize
|
|
||||||
#[derive(Debug, PartialEq, Clone, Serialize)]
|
|
||||||
pub struct ExecutionOptimisticFinalizedForkVersionedResponse<T> {
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub version: Option<ForkName>,
|
|
||||||
pub execution_optimistic: Option<bool>,
|
|
||||||
pub finalized: Option<bool>,
|
|
||||||
pub data: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de, F> serde::Deserialize<'de> for ExecutionOptimisticFinalizedForkVersionedResponse<F>
|
|
||||||
where
|
|
||||||
F: ForkVersionDeserialize,
|
|
||||||
{
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct Helper {
|
|
||||||
version: Option<ForkName>,
|
|
||||||
execution_optimistic: Option<bool>,
|
|
||||||
finalized: Option<bool>,
|
|
||||||
data: serde_json::Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
let helper = Helper::deserialize(deserializer)?;
|
|
||||||
let data = match helper.version {
|
|
||||||
Some(fork_name) => F::deserialize_by_fork::<'de, D>(helper.data, fork_name)?,
|
|
||||||
None => serde_json::from_value(helper.data).map_err(serde::de::Error::custom)?,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(ExecutionOptimisticFinalizedForkVersionedResponse {
|
|
||||||
version: helper.version,
|
|
||||||
execution_optimistic: helper.execution_optimistic,
|
|
||||||
finalized: helper.finalized,
|
|
||||||
data,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ForkVersionDeserialize: Sized + DeserializeOwned {
|
pub trait ForkVersionDeserialize: Sized + DeserializeOwned {
|
||||||
fn deserialize_by_fork<'de, D: Deserializer<'de>>(
|
fn deserialize_by_fork<'de, D: Deserializer<'de>>(
|
||||||
value: Value,
|
value: Value,
|
||||||
@ -52,17 +11,41 @@ pub trait ForkVersionDeserialize: Sized + DeserializeOwned {
|
|||||||
) -> Result<Self, D::Error>;
|
) -> Result<Self, D::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deserialize is only implemented for types that implement ForkVersionDeserialize
|
/// Deserialize is only implemented for types that implement ForkVersionDeserialize.
|
||||||
|
///
|
||||||
|
/// The metadata of type M should be set to `EmptyMetadata` if you don't care about adding fields other than
|
||||||
|
/// version. If you *do* care about adding other fields you can mix in any type that implements
|
||||||
|
/// `Deserialize`.
|
||||||
#[derive(Debug, PartialEq, Clone, Serialize)]
|
#[derive(Debug, PartialEq, Clone, Serialize)]
|
||||||
pub struct ForkVersionedResponse<T> {
|
pub struct ForkVersionedResponse<T, M = EmptyMetadata> {
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub version: Option<ForkName>,
|
pub version: Option<ForkName>,
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub metadata: M,
|
||||||
pub data: T,
|
pub data: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de, F> serde::Deserialize<'de> for ForkVersionedResponse<F>
|
/// Metadata type similar to unit (i.e. `()`) but deserializes from a map (`serde_json::Value`).
|
||||||
|
///
|
||||||
|
/// Unfortunately the braces are semantically significant, i.e. `struct EmptyMetadata;` does not
|
||||||
|
/// work.
|
||||||
|
#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
|
||||||
|
pub struct EmptyMetadata {}
|
||||||
|
|
||||||
|
/// Fork versioned response with extra information about finalization & optimistic execution.
|
||||||
|
pub type ExecutionOptimisticFinalizedForkVersionedResponse<T> =
|
||||||
|
ForkVersionedResponse<T, ExecutionOptimisticFinalizedMetadata>;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ExecutionOptimisticFinalizedMetadata {
|
||||||
|
pub execution_optimistic: Option<bool>,
|
||||||
|
pub finalized: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de, F, M> serde::Deserialize<'de> for ForkVersionedResponse<F, M>
|
||||||
where
|
where
|
||||||
F: ForkVersionDeserialize,
|
F: ForkVersionDeserialize,
|
||||||
|
M: DeserializeOwned,
|
||||||
{
|
{
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
@ -71,6 +54,8 @@ where
|
|||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Helper {
|
struct Helper {
|
||||||
version: Option<ForkName>,
|
version: Option<ForkName>,
|
||||||
|
#[serde(flatten)]
|
||||||
|
metadata: serde_json::Value,
|
||||||
data: serde_json::Value,
|
data: serde_json::Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,9 +64,11 @@ where
|
|||||||
Some(fork_name) => F::deserialize_by_fork::<'de, D>(helper.data, fork_name)?,
|
Some(fork_name) => F::deserialize_by_fork::<'de, D>(helper.data, fork_name)?,
|
||||||
None => serde_json::from_value(helper.data).map_err(serde::de::Error::custom)?,
|
None => serde_json::from_value(helper.data).map_err(serde::de::Error::custom)?,
|
||||||
};
|
};
|
||||||
|
let metadata = serde_json::from_value(helper.metadata).map_err(serde::de::Error::custom)?;
|
||||||
|
|
||||||
Ok(ForkVersionedResponse {
|
Ok(ForkVersionedResponse {
|
||||||
version: helper.version,
|
version: helper.version,
|
||||||
|
metadata,
|
||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -98,6 +85,22 @@ impl<F: ForkVersionDeserialize> ForkVersionDeserialize for Arc<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T, M> ForkVersionedResponse<T, M> {
|
||||||
|
/// Apply a function to the inner `data`, potentially changing its type.
|
||||||
|
pub fn map_data<U>(self, f: impl FnOnce(T) -> U) -> ForkVersionedResponse<U, M> {
|
||||||
|
let ForkVersionedResponse {
|
||||||
|
version,
|
||||||
|
metadata,
|
||||||
|
data,
|
||||||
|
} = self;
|
||||||
|
ForkVersionedResponse {
|
||||||
|
version,
|
||||||
|
metadata,
|
||||||
|
data: f(data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod fork_version_response_tests {
|
mod fork_version_response_tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -112,6 +115,7 @@ mod fork_version_response_tests {
|
|||||||
let response_json =
|
let response_json =
|
||||||
serde_json::to_string(&json!(ForkVersionedResponse::<ExecutionPayload<E>> {
|
serde_json::to_string(&json!(ForkVersionedResponse::<ExecutionPayload<E>> {
|
||||||
version: Some(ForkName::Merge),
|
version: Some(ForkName::Merge),
|
||||||
|
metadata: Default::default(),
|
||||||
data: ExecutionPayload::Merge(ExecutionPayloadMerge::default()),
|
data: ExecutionPayload::Merge(ExecutionPayloadMerge::default()),
|
||||||
}))
|
}))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -129,6 +133,7 @@ mod fork_version_response_tests {
|
|||||||
let response_json =
|
let response_json =
|
||||||
serde_json::to_string(&json!(ForkVersionedResponse::<ExecutionPayload<E>> {
|
serde_json::to_string(&json!(ForkVersionedResponse::<ExecutionPayload<E>> {
|
||||||
version: Some(ForkName::Capella),
|
version: Some(ForkName::Capella),
|
||||||
|
metadata: Default::default(),
|
||||||
data: ExecutionPayload::Merge(ExecutionPayloadMerge::default()),
|
data: ExecutionPayload::Merge(ExecutionPayloadMerge::default()),
|
||||||
}))
|
}))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -83,7 +83,7 @@ const HTTP_SYNC_DUTIES_TIMEOUT_QUOTIENT: u32 = 4;
|
|||||||
const HTTP_GET_BEACON_BLOCK_SSZ_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_DEBUG_BEACON_STATE_QUOTIENT: u32 = 4;
|
||||||
const HTTP_GET_DEPOSIT_SNAPSHOT_QUOTIENT: u32 = 4;
|
const HTTP_GET_DEPOSIT_SNAPSHOT_QUOTIENT: u32 = 4;
|
||||||
const HTTP_GET_VALIDATOR_BLOCK_SSZ_TIMEOUT_QUOTIENT: u32 = 4;
|
const HTTP_GET_VALIDATOR_BLOCK_TIMEOUT_QUOTIENT: u32 = 4;
|
||||||
|
|
||||||
const DOPPELGANGER_SERVICE_NAME: &str = "doppelganger";
|
const DOPPELGANGER_SERVICE_NAME: &str = "doppelganger";
|
||||||
|
|
||||||
@ -311,8 +311,7 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
|
|||||||
/ HTTP_GET_BEACON_BLOCK_SSZ_TIMEOUT_QUOTIENT,
|
/ HTTP_GET_BEACON_BLOCK_SSZ_TIMEOUT_QUOTIENT,
|
||||||
get_debug_beacon_states: slot_duration / HTTP_GET_DEBUG_BEACON_STATE_QUOTIENT,
|
get_debug_beacon_states: slot_duration / HTTP_GET_DEBUG_BEACON_STATE_QUOTIENT,
|
||||||
get_deposit_snapshot: slot_duration / HTTP_GET_DEPOSIT_SNAPSHOT_QUOTIENT,
|
get_deposit_snapshot: slot_duration / HTTP_GET_DEPOSIT_SNAPSHOT_QUOTIENT,
|
||||||
get_validator_block_ssz: slot_duration
|
get_validator_block: slot_duration / HTTP_GET_VALIDATOR_BLOCK_TIMEOUT_QUOTIENT,
|
||||||
/ HTTP_GET_VALIDATOR_BLOCK_SSZ_TIMEOUT_QUOTIENT,
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Timeouts::set_all(slot_duration)
|
Timeouts::set_all(slot_duration)
|
||||||
|
Loading…
Reference in New Issue
Block a user