Merge remote-tracking branch 'origin/unstable' into tree-states

This commit is contained in:
Michael Sproul
2023-11-12 22:19:07 +03:00
161 changed files with 3635 additions and 2227 deletions

View File

@@ -467,6 +467,11 @@ impl<T: EthSpec> From<GetPayloadResponse<T>>
}
}
pub enum GetPayloadResponseType<E: EthSpec> {
Full(GetPayloadResponse<E>),
Blinded(GetPayloadResponse<E>),
}
impl<T: EthSpec> GetPayloadResponse<T> {
pub fn execution_payload_ref(&self) -> ExecutionPayloadRef<T> {
self.to_ref().into()

View File

@@ -387,8 +387,8 @@ pub struct JsonPayloadAttributes {
}
impl From<PayloadAttributes> for JsonPayloadAttributes {
fn from(payload_atributes: PayloadAttributes) -> Self {
match payload_atributes {
fn from(payload_attributes: PayloadAttributes) -> Self {
match payload_attributes {
PayloadAttributes::V1(pa) => Self::V1(JsonPayloadAttributesV1 {
timestamp: pa.timestamp,
prev_randao: pa.prev_randao,

View File

@@ -42,13 +42,13 @@ use tokio_stream::wrappers::WatchStream;
use tree_hash::TreeHash;
use types::beacon_block_body::KzgCommitments;
use types::builder_bid::BuilderBid;
use types::payload::BlockProductionVersion;
use types::sidecar::{BlobItems, Sidecar};
use types::KzgProofs;
use types::{AbstractExecPayload, ExecutionPayloadDeneb, KzgProofs};
use types::{
AbstractExecPayload, BeaconStateError, BlindedPayload, BlockType, ChainSpec, Epoch,
ExecPayload, ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadMerge,
BeaconStateError, BlindedPayload, ChainSpec, Epoch, ExecPayload, ExecutionPayloadCapella,
ExecutionPayloadMerge, FullPayload, ProposerPreparationData, PublicKeyBytes, Signature, Slot,
};
use types::{ProposerPreparationData, PublicKeyBytes, Signature, Slot};
mod block_hash;
mod engine_api;
@@ -87,9 +87,7 @@ pub enum ProvenancedPayload<P> {
Builder(P),
}
impl<E: EthSpec, Payload: AbstractExecPayload<E>> TryFrom<BuilderBid<E>>
for ProvenancedPayload<BlockProposalContents<E, Payload>>
{
impl<E: EthSpec> TryFrom<BuilderBid<E>> for ProvenancedPayload<BlockProposalContentsType<E>> {
type Error = Error;
fn try_from(value: BuilderBid<E>) -> Result<Self, Error> {
@@ -112,12 +110,16 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> TryFrom<BuilderBid<E>>
.map_err(|_| Error::InvalidPayloadConversion)?,
block_value: builder_bid.value,
kzg_commitments: builder_bid.blinded_blobs_bundle.commitments,
blobs: BlobItems::try_from_blob_roots(builder_bid.blinded_blobs_bundle.blob_roots)
.map_err(Error::InvalidBlobConversion)?,
blobs: BlobItems::<E>::try_from_blob_roots(
builder_bid.blinded_blobs_bundle.blob_roots,
)
.map_err(Error::InvalidBlobConversion)?,
proofs: builder_bid.blinded_blobs_bundle.proofs,
},
};
Ok(ProvenancedPayload::Builder(block_proposal_contents))
Ok(ProvenancedPayload::Builder(
BlockProposalContentsType::Blinded(block_proposal_contents),
))
}
}
@@ -145,6 +147,7 @@ pub enum Error {
InvalidPayloadConversion,
InvalidBlobConversion(String),
BeaconStateError(BeaconStateError),
PayloadTypeMismatch,
}
impl From<BeaconStateError> for Error {
@@ -159,6 +162,11 @@ impl From<ApiError> for Error {
}
}
pub enum BlockProposalContentsType<E: EthSpec> {
Full(BlockProposalContents<E, FullPayload<E>>),
Blinded(BlockProposalContents<E, BlindedPayload<E>>),
}
pub enum BlockProposalContents<T: EthSpec, Payload: AbstractExecPayload<T>> {
Payload {
payload: Payload,
@@ -173,6 +181,22 @@ pub enum BlockProposalContents<T: EthSpec, Payload: AbstractExecPayload<T>> {
},
}
impl<T: EthSpec> From<BlockProposalContents<T, FullPayload<T>>>
for BlockProposalContents<T, BlindedPayload<T>>
{
fn from(item: BlockProposalContents<T, FullPayload<T>>) -> Self {
let block_value = item.block_value().to_owned();
let blinded_payload: BlockProposalContents<T, BlindedPayload<T>> =
BlockProposalContents::Payload {
payload: item.to_payload().execution_payload().into(),
block_value,
};
blinded_payload
}
}
impl<E: EthSpec, Payload: AbstractExecPayload<E>> TryFrom<GetPayloadResponse<E>>
for BlockProposalContents<E, Payload>
{
@@ -197,6 +221,17 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> TryFrom<GetPayloadResponse<E>>
}
}
impl<E: EthSpec> TryFrom<GetPayloadResponseType<E>> for BlockProposalContentsType<E> {
type Error = Error;
fn try_from(response_type: GetPayloadResponseType<E>) -> Result<Self, Error> {
match response_type {
GetPayloadResponseType::Full(response) => Ok(Self::Full(response.try_into()?)),
GetPayloadResponseType::Blinded(response) => Ok(Self::Blinded(response.try_into()?)),
}
}
}
#[allow(clippy::type_complexity)]
impl<T: EthSpec, Payload: AbstractExecPayload<T>> BlockProposalContents<T, Payload> {
pub fn deconstruct(
@@ -206,19 +241,26 @@ impl<T: EthSpec, Payload: AbstractExecPayload<T>> BlockProposalContents<T, Paylo
Option<KzgCommitments<T>>,
Option<<Payload::Sidecar as Sidecar<T>>::BlobItems>,
Option<KzgProofs<T>>,
Uint256,
) {
match self {
Self::Payload {
payload,
block_value: _,
} => (payload, None, None, None),
block_value,
} => (payload, None, None, None, block_value),
Self::PayloadAndBlobs {
payload,
block_value: _,
block_value,
kzg_commitments,
blobs,
proofs,
} => (payload, Some(kzg_commitments), Some(blobs), Some(proofs)),
} => (
payload,
Some(kzg_commitments),
Some(blobs),
Some(proofs),
block_value,
),
}
}
@@ -795,7 +837,8 @@ impl<T: EthSpec> ExecutionLayer<T> {
///
/// The result will be returned from the first node that returns successfully. No more nodes
/// will be contacted.
pub async fn get_payload<Payload: AbstractExecPayload<T>>(
#[allow(clippy::too_many_arguments)]
pub async fn get_payload(
&self,
parent_hash: ExecutionBlockHash,
payload_attributes: &PayloadAttributes,
@@ -803,14 +846,11 @@ impl<T: EthSpec> ExecutionLayer<T> {
builder_params: BuilderParams,
current_fork: ForkName,
spec: &ChainSpec,
) -> Result<BlockProposalContents<T, Payload>, Error> {
let payload_result = match Payload::block_type() {
BlockType::Blinded => {
let _timer = metrics::start_timer_vec(
&metrics::EXECUTION_LAYER_REQUEST_TIMES,
&[metrics::GET_BLINDED_PAYLOAD],
);
self.get_blinded_payload(
block_production_version: BlockProductionVersion,
) -> Result<BlockProposalContentsType<T>, Error> {
let payload_result_type = match block_production_version {
BlockProductionVersion::V3 => match self
.determine_and_fetch_payload(
parent_hash,
payload_attributes,
forkchoice_update_params,
@@ -819,27 +859,51 @@ impl<T: EthSpec> ExecutionLayer<T> {
spec,
)
.await
}
BlockType::Full => {
{
Ok(payload) => payload,
Err(e) => {
metrics::inc_counter_vec(
&metrics::EXECUTION_LAYER_GET_PAYLOAD_OUTCOME,
&[metrics::FAILURE],
);
return Err(e);
}
},
BlockProductionVersion::BlindedV2 => {
let _timer = metrics::start_timer_vec(
&metrics::EXECUTION_LAYER_REQUEST_TIMES,
&[metrics::GET_PAYLOAD],
&[metrics::GET_BLINDED_PAYLOAD],
);
self.get_full_payload(
self.determine_and_fetch_payload(
parent_hash,
payload_attributes,
forkchoice_update_params,
builder_params,
current_fork,
spec,
)
.await?
}
BlockProductionVersion::FullV2 => self
.get_full_payload_with(
parent_hash,
payload_attributes,
forkchoice_update_params,
current_fork,
noop,
)
.await
.and_then(GetPayloadResponse::try_into)
.map(ProvenancedPayload::Local)
}
.and_then(GetPayloadResponseType::try_into)
.map(ProvenancedPayload::Local)?,
};
// Track some metrics and return the result.
match payload_result {
Ok(ProvenancedPayload::Local(block_proposal_contents)) => {
let block_proposal_content_type = match payload_result_type {
ProvenancedPayload::Local(local_payload) => local_payload,
ProvenancedPayload::Builder(builder_payload) => builder_payload,
};
match block_proposal_content_type {
BlockProposalContentsType::Full(block_proposal_contents) => {
metrics::inc_counter_vec(
&metrics::EXECUTION_LAYER_GET_PAYLOAD_OUTCOME,
&[metrics::SUCCESS],
@@ -848,9 +912,15 @@ impl<T: EthSpec> ExecutionLayer<T> {
&metrics::EXECUTION_LAYER_GET_PAYLOAD_SOURCE,
&[metrics::LOCAL],
);
Ok(block_proposal_contents)
if matches!(block_production_version, BlockProductionVersion::BlindedV2) {
Ok(BlockProposalContentsType::Blinded(
block_proposal_contents.into(),
))
} else {
Ok(BlockProposalContentsType::Full(block_proposal_contents))
}
}
Ok(ProvenancedPayload::Builder(block_proposal_contents)) => {
BlockProposalContentsType::Blinded(block_proposal_contents) => {
metrics::inc_counter_vec(
&metrics::EXECUTION_LAYER_GET_PAYLOAD_OUTCOME,
&[metrics::SUCCESS],
@@ -859,19 +929,12 @@ impl<T: EthSpec> ExecutionLayer<T> {
&metrics::EXECUTION_LAYER_GET_PAYLOAD_SOURCE,
&[metrics::BUILDER],
);
Ok(block_proposal_contents)
}
Err(e) => {
metrics::inc_counter_vec(
&metrics::EXECUTION_LAYER_GET_PAYLOAD_OUTCOME,
&[metrics::FAILURE],
);
Err(e)
Ok(BlockProposalContentsType::Blinded(block_proposal_contents))
}
}
}
async fn get_blinded_payload<Payload: AbstractExecPayload<T>>(
async fn determine_and_fetch_payload(
&self,
parent_hash: ExecutionBlockHash,
payload_attributes: &PayloadAttributes,
@@ -879,11 +942,10 @@ impl<T: EthSpec> ExecutionLayer<T> {
builder_params: BuilderParams,
current_fork: ForkName,
spec: &ChainSpec,
) -> Result<ProvenancedPayload<BlockProposalContents<T, Payload>>, Error> {
) -> Result<ProvenancedPayload<BlockProposalContentsType<T>>, Error> {
if let Some(builder) = self.builder() {
let slot = builder_params.slot;
let pubkey = builder_params.pubkey;
match builder_params.chain_health {
ChainHealth::Healthy => {
info!(
@@ -895,7 +957,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
);
// Wait for the builder *and* local EL to produce a payload (or return an error).
let ((relay_result, relay_duration), (local_result, local_duration)) = tokio::join!(
let ((relay_result, relay_duration), (local_result_type, local_duration)) = tokio::join!(
timed_future(metrics::GET_BLINDED_PAYLOAD_BUILDER, async {
builder
.get_builder_header::<T>(slot, parent_hash, &pubkey)
@@ -912,6 +974,11 @@ impl<T: EthSpec> ExecutionLayer<T> {
})
);
let local_result = match local_result_type? {
GetPayloadResponseType::Full(payload) => Ok(payload),
GetPayloadResponseType::Blinded(_) => Err(Error::PayloadTypeMismatch),
};
info!(
self.log(),
"Requested blinded execution payload";
@@ -939,7 +1006,9 @@ impl<T: EthSpec> ExecutionLayer<T> {
"local_block_hash" => ?local.block_hash(),
"parent_hash" => ?parent_hash,
);
Ok(ProvenancedPayload::Local(local.try_into()?))
Ok(ProvenancedPayload::Local(BlockProposalContentsType::Full(
local.try_into()?,
)))
}
(Ok(None), Ok(local)) => {
info!(
@@ -949,7 +1018,9 @@ impl<T: EthSpec> ExecutionLayer<T> {
"local_block_hash" => ?local.block_hash(),
"parent_hash" => ?parent_hash,
);
Ok(ProvenancedPayload::Local(local.try_into()?))
Ok(ProvenancedPayload::Local(BlockProposalContentsType::Full(
local.try_into()?,
)))
}
(Ok(Some(relay)), Ok(local)) => {
let header = &relay.data.message.header();
@@ -973,7 +1044,9 @@ impl<T: EthSpec> ExecutionLayer<T> {
"local_block_value" => %local_value,
"relay_value" => %relay_value
);
return Ok(ProvenancedPayload::Local(local.try_into()?));
return Ok(ProvenancedPayload::Local(
BlockProposalContentsType::Full(local.try_into()?),
));
} else if local.should_override_builder().unwrap_or(false) {
let percentage_difference =
percentage_difference_u256(local_value, *relay_value);
@@ -989,7 +1062,9 @@ impl<T: EthSpec> ExecutionLayer<T> {
"local_block_value" => %local_value,
"relay_value" => %relay_value
);
return Ok(ProvenancedPayload::Local(local.try_into()?));
return Ok(ProvenancedPayload::Local(
BlockProposalContentsType::Full(local.try_into()?),
));
}
} else {
info!(
@@ -1020,7 +1095,9 @@ impl<T: EthSpec> ExecutionLayer<T> {
"relay_block_hash" => ?header.block_hash(),
"parent_hash" => ?parent_hash,
);
Ok(ProvenancedPayload::Local(local.try_into()?))
Ok(ProvenancedPayload::Local(BlockProposalContentsType::Full(
local.try_into()?,
)))
}
Err(reason) => {
metrics::inc_counter_vec(
@@ -1035,7 +1112,9 @@ impl<T: EthSpec> ExecutionLayer<T> {
"relay_block_hash" => ?header.block_hash(),
"parent_hash" => ?parent_hash,
);
Ok(ProvenancedPayload::Local(local.try_into()?))
Ok(ProvenancedPayload::Local(BlockProposalContentsType::Full(
local.try_into()?,
)))
}
}
}
@@ -1132,28 +1211,10 @@ impl<T: EthSpec> ExecutionLayer<T> {
current_fork,
)
.await
.and_then(GetPayloadResponse::try_into)
.and_then(GetPayloadResponseType::try_into)
.map(ProvenancedPayload::Local)
}
/// Get a full payload without caching its result in the execution layer's payload cache.
async fn get_full_payload(
&self,
parent_hash: ExecutionBlockHash,
payload_attributes: &PayloadAttributes,
forkchoice_update_params: ForkchoiceUpdateParameters,
current_fork: ForkName,
) -> Result<GetPayloadResponse<T>, Error> {
self.get_full_payload_with(
parent_hash,
payload_attributes,
forkchoice_update_params,
current_fork,
noop,
)
.await
}
/// Get a full payload and cache its result in the execution layer's payload cache.
async fn get_full_payload_caching(
&self,
@@ -1161,7 +1222,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
payload_attributes: &PayloadAttributes,
forkchoice_update_params: ForkchoiceUpdateParameters,
current_fork: ForkName,
) -> Result<GetPayloadResponse<T>, Error> {
) -> Result<GetPayloadResponseType<T>, Error> {
self.get_full_payload_with(
parent_hash,
payload_attributes,
@@ -1182,7 +1243,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
&ExecutionLayer<T>,
PayloadContentsRefTuple<T>,
) -> Option<FullPayloadContents<T>>,
) -> Result<GetPayloadResponse<T>, Error> {
) -> Result<GetPayloadResponseType<T>, Error> {
self.engine()
.request(move |engine| async move {
let payload_id = if let Some(id) = engine
@@ -1244,6 +1305,10 @@ impl<T: EthSpec> ExecutionLayer<T> {
"timestamp" => payload_attributes.timestamp(),
"parent_hash" => ?parent_hash,
);
let _timer = metrics::start_timer_vec(
&metrics::EXECUTION_LAYER_REQUEST_TIMES,
&[metrics::GET_PAYLOAD],
);
engine.api.get_payload::<T>(current_fork, payload_id).await
}.await?;
@@ -1268,7 +1333,7 @@ impl<T: EthSpec> ExecutionLayer<T> {
);
}
Ok(payload_response)
Ok(GetPayloadResponseType::Full(payload_response))
})
.await
.map_err(Box::new)
@@ -1799,13 +1864,11 @@ impl<T: EthSpec> ExecutionLayer<T> {
};
}
let block = if let Some(block) = engine
let Some(block) = engine
.api
.get_block_by_hash_with_txns::<T>(hash, fork)
.await?
{
block
} else {
else {
return Ok(None);
};

View File

@@ -14,22 +14,21 @@ use kzg::{Kzg, KzgCommitment, KzgProof};
use parking_lot::Mutex;
use rand::{rngs::StdRng, Rng, SeedableRng};
use serde::{Deserialize, Serialize};
use ssz::Decode;
use ssz_types::VariableList;
use std::collections::HashMap;
use std::sync::Arc;
use tree_hash::TreeHash;
use tree_hash_derive::TreeHash;
use types::{
Blob, ChainSpec, EthSpec, EthSpecId, ExecutionBlockHash, ExecutionPayload,
ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadHeader, ExecutionPayloadMerge,
ForkName, Hash256, Transaction, Transactions, Uint256,
Blob, ChainSpec, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadCapella,
ExecutionPayloadDeneb, ExecutionPayloadHeader, ExecutionPayloadMerge, ForkName, Hash256,
Transaction, Transactions, Uint256,
};
use super::DEFAULT_TERMINAL_BLOCK;
use ssz::Decode;
const TEST_BLOB_BUNDLE_MAINNET: &[u8] = include_bytes!("fixtures/mainnet/test_blobs_bundle.ssz");
const TEST_BLOB_BUNDLE_MINIMAL: &[u8] = include_bytes!("fixtures/minimal/test_blobs_bundle.ssz");
const TEST_BLOB_BUNDLE: &[u8] = include_bytes!("fixtures/mainnet/test_blobs_bundle.ssz");
const GAS_LIMIT: u64 = 16384;
const GAS_USED: u64 = GAS_LIMIT - 1;
@@ -137,7 +136,7 @@ pub struct ExecutionBlockGenerator<T: EthSpec> {
* deneb stuff
*/
pub blobs_bundles: HashMap<PayloadId, BlobsBundle<T>>,
pub kzg: Option<Arc<Kzg<T::Kzg>>>,
pub kzg: Option<Arc<Kzg>>,
rng: Arc<Mutex<StdRng>>,
}
@@ -154,7 +153,7 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
terminal_block_hash: ExecutionBlockHash,
shanghai_time: Option<u64>,
cancun_time: Option<u64>,
kzg: Option<Kzg<T::Kzg>>,
kzg: Option<Kzg>,
) -> Self {
let mut gen = Self {
head_block: <_>::default(),
@@ -427,9 +426,7 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
}
pub fn new_payload(&mut self, payload: ExecutionPayload<T>) -> PayloadStatusV1 {
let parent = if let Some(parent) = self.blocks.get(&payload.parent_hash()) {
parent
} else {
let Some(parent) = self.blocks.get(&payload.parent_hash()) else {
return PayloadStatusV1 {
status: PayloadStatusV1Status::Syncing,
latest_valid_hash: None,
@@ -649,20 +646,12 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
}
pub fn load_test_blobs_bundle<E: EthSpec>() -> Result<(KzgCommitment, KzgProof, Blob<E>), String> {
let blob_bundle_bytes = match E::spec_name() {
EthSpecId::Mainnet => TEST_BLOB_BUNDLE_MAINNET,
EthSpecId::Minimal => TEST_BLOB_BUNDLE_MINIMAL,
EthSpecId::Gnosis => {
return Err("Test blobs bundle not available for Gnosis preset".to_string())
}
};
let BlobsBundle {
let BlobsBundle::<E> {
commitments,
proofs,
blobs,
} = BlobsBundle::<E>::from_ssz_bytes(blob_bundle_bytes)
.map_err(|e| format!("Unable to decode SSZ: {:?}", e))?;
} = BlobsBundle::from_ssz_bytes(TEST_BLOB_BUNDLE)
.map_err(|e| format!("Unable to decode ssz: {:?}", e))?;
Ok((
commitments
@@ -821,6 +810,7 @@ pub fn generate_pow_block(
#[cfg(test)]
mod test {
use super::*;
use eth2_network_config::TRUSTED_SETUP_BYTES;
use kzg::TrustedSetup;
use types::{MainnetEthSpec, MinimalEthSpec};
@@ -898,18 +888,17 @@ mod test {
}
fn validate_blob<E: EthSpec>() -> Result<bool, String> {
let kzg = load_kzg::<E>()?;
let kzg = load_kzg()?;
let (kzg_commitment, kzg_proof, blob) = load_test_blobs_bundle::<E>()?;
let kzg_blob = E::blob_from_bytes(blob.as_ref())
let kzg_blob = kzg::Blob::from_bytes(blob.as_ref())
.map_err(|e| format!("Error converting blob to kzg blob: {e:?}"))?;
kzg.verify_blob_kzg_proof(&kzg_blob, kzg_commitment, kzg_proof)
.map_err(|e| format!("Invalid blobs bundle: {e:?}"))
}
fn load_kzg<E: EthSpec>() -> Result<Kzg<E::Kzg>, String> {
let trusted_setup: TrustedSetup =
serde_json::from_reader(eth2_network_config::get_trusted_setup::<E::Kzg>())
.map_err(|e| format!("Unable to read trusted setup file: {e:?}"))?;
fn load_kzg() -> Result<Kzg, String> {
let trusted_setup: TrustedSetup = serde_json::from_reader(TRUSTED_SETUP_BYTES)
.map_err(|e| format!("Unable to read trusted setup file: {e:?}"))?;
Kzg::new_from_trusted_setup(trusted_setup)
.map_err(|e| format!("Failed to load trusted setup: {e:?}"))
}

View File

@@ -508,11 +508,7 @@ pub fn serve<E: EthSpec>(
finalized_hash: Some(finalized_execution_hash),
};
let (payload, _block_value, maybe_blobs_bundle): (
ExecutionPayload<E>,
Uint256,
Option<BlobsBundle<E>>,
) = builder
let payload_response_type = builder
.el
.get_full_payload_caching(
head_execution_hash,
@@ -521,38 +517,88 @@ pub fn serve<E: EthSpec>(
fork,
)
.await
.map_err(|_| reject("couldn't get payload"))?
.into();
.map_err(|_| reject("couldn't get payload"))?;
let mut message = match fork {
ForkName::Deneb => BuilderBid::Deneb(BuilderBidDeneb {
header: payload
.as_deneb()
.map_err(|_| reject("incorrect payload variant"))?
.into(),
blinded_blobs_bundle: maybe_blobs_bundle
.map(Into::into)
.unwrap_or_default(),
value: Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI),
pubkey: builder.builder_sk.public_key().compress(),
}),
ForkName::Capella => BuilderBid::Capella(BuilderBidCapella {
header: payload
.as_capella()
.map_err(|_| reject("incorrect payload variant"))?
.into(),
value: Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI),
pubkey: builder.builder_sk.public_key().compress(),
}),
ForkName::Merge => BuilderBid::Merge(BuilderBidMerge {
header: payload
.as_merge()
.map_err(|_| reject("incorrect payload variant"))?
.into(),
value: Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI),
pubkey: builder.builder_sk.public_key().compress(),
}),
ForkName::Base | ForkName::Altair => return Err(reject("invalid fork")),
let mut message = match payload_response_type {
crate::GetPayloadResponseType::Full(payload_response) => {
let (payload, _block_value, maybe_blobs_bundle): (
ExecutionPayload<E>,
Uint256,
Option<BlobsBundle<E>>,
) = payload_response.into();
match fork {
ForkName::Deneb => BuilderBid::Deneb(BuilderBidDeneb {
header: payload
.as_deneb()
.map_err(|_| reject("incorrect payload variant"))?
.into(),
blinded_blobs_bundle: maybe_blobs_bundle
.map(Into::into)
.unwrap_or_default(),
value: Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI),
pubkey: builder.builder_sk.public_key().compress(),
}),
ForkName::Capella => BuilderBid::Capella(BuilderBidCapella {
header: payload
.as_capella()
.map_err(|_| reject("incorrect payload variant"))?
.into(),
value: Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI),
pubkey: builder.builder_sk.public_key().compress(),
}),
ForkName::Merge => BuilderBid::Merge(BuilderBidMerge {
header: payload
.as_merge()
.map_err(|_| reject("incorrect payload variant"))?
.into(),
value: Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI),
pubkey: builder.builder_sk.public_key().compress(),
}),
ForkName::Base | ForkName::Altair => {
return Err(reject("invalid fork"))
}
}
}
crate::GetPayloadResponseType::Blinded(payload_response) => {
let (payload, _block_value, maybe_blobs_bundle): (
ExecutionPayload<E>,
Uint256,
Option<BlobsBundle<E>>,
) = payload_response.into();
match fork {
ForkName::Deneb => BuilderBid::Deneb(BuilderBidDeneb {
header: payload
.as_deneb()
.map_err(|_| reject("incorrect payload variant"))?
.into(),
blinded_blobs_bundle: maybe_blobs_bundle
.map(Into::into)
.unwrap_or_default(),
value: Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI),
pubkey: builder.builder_sk.public_key().compress(),
}),
ForkName::Capella => BuilderBid::Capella(BuilderBidCapella {
header: payload
.as_capella()
.map_err(|_| reject("incorrect payload variant"))?
.into(),
value: Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI),
pubkey: builder.builder_sk.public_key().compress(),
}),
ForkName::Merge => BuilderBid::Merge(BuilderBidMerge {
header: payload
.as_merge()
.map_err(|_| reject("incorrect payload variant"))?
.into(),
value: Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI),
pubkey: builder.builder_sk.public_key().compress(),
}),
ForkName::Base | ForkName::Altair => {
return Err(reject("invalid fork"))
}
}
}
};
message.set_gas_limit(cached_data.gas_limit);

View File

@@ -5,12 +5,12 @@ use crate::{
},
Config, *,
};
use keccak_hash::H256;
use kzg::Kzg;
use sensitive_url::SensitiveUrl;
use task_executor::TaskExecutor;
use tempfile::NamedTempFile;
use tree_hash::TreeHash;
use types::{Address, ChainSpec, Epoch, EthSpec, FullPayload, Hash256, MainnetEthSpec};
use types::{Address, ChainSpec, Epoch, EthSpec, Hash256, MainnetEthSpec};
pub struct MockExecutionLayer<T: EthSpec> {
pub server: MockServer<T>,
@@ -46,7 +46,7 @@ impl<T: EthSpec> MockExecutionLayer<T> {
builder_threshold: Option<u128>,
jwt_key: Option<JwtKey>,
spec: ChainSpec,
kzg: Option<Kzg<T::Kzg>>,
kzg: Option<Kzg>,
) -> Self {
let handle = executor.handle().unwrap();
@@ -133,20 +133,25 @@ impl<T: EthSpec> MockExecutionLayer<T> {
let suggested_fee_recipient = self.el.get_suggested_fee_recipient(validator_index).await;
let payload_attributes =
PayloadAttributes::new(timestamp, prev_randao, suggested_fee_recipient, None, None);
let payload: ExecutionPayload<T> = self
let block_proposal_content_type = self
.el
.get_payload::<FullPayload<T>>(
.get_payload(
parent_hash,
&payload_attributes,
forkchoice_update_params,
builder_params,
ForkName::Merge,
&self.spec,
BlockProductionVersion::FullV2,
)
.await
.unwrap()
.to_payload()
.into();
.unwrap();
let payload: ExecutionPayload<T> = match block_proposal_content_type {
BlockProposalContentsType::Full(block) => block.to_payload().into(),
BlockProposalContentsType::Blinded(_) => panic!("Should always be a full payload"),
};
let block_hash = payload.block_hash();
assert_eq!(payload.parent_hash(), parent_hash);
@@ -167,20 +172,64 @@ impl<T: EthSpec> MockExecutionLayer<T> {
let suggested_fee_recipient = self.el.get_suggested_fee_recipient(validator_index).await;
let payload_attributes =
PayloadAttributes::new(timestamp, prev_randao, suggested_fee_recipient, None, None);
let payload_header = self
let block_proposal_content_type = self
.el
.get_payload::<BlindedPayload<T>>(
.get_payload(
parent_hash,
&payload_attributes,
forkchoice_update_params,
builder_params,
ForkName::Merge,
&self.spec,
BlockProductionVersion::BlindedV2,
)
.await
.unwrap()
.to_payload();
.unwrap();
match block_proposal_content_type {
BlockProposalContentsType::Full(block) => {
let payload_header = block.to_payload();
self.assert_valid_execution_payload_on_head(
payload,
payload_header,
block_hash,
parent_hash,
block_number,
timestamp,
prev_randao,
)
.await;
}
BlockProposalContentsType::Blinded(block) => {
let payload_header = block.to_payload();
self.assert_valid_execution_payload_on_head(
payload,
payload_header,
block_hash,
parent_hash,
block_number,
timestamp,
prev_randao,
)
.await;
}
};
self
}
#[allow(clippy::too_many_arguments)]
pub async fn assert_valid_execution_payload_on_head<Payload: AbstractExecPayload<T>>(
&self,
payload: ExecutionPayload<T>,
payload_header: Payload,
block_hash: ExecutionBlockHash,
parent_hash: ExecutionBlockHash,
block_number: u64,
timestamp: u64,
prev_randao: H256,
) {
assert_eq!(payload_header.block_hash(), block_hash);
assert_eq!(payload_header.parent_hash(), parent_hash);
assert_eq!(payload_header.block_number(), block_number);
@@ -224,8 +273,6 @@ impl<T: EthSpec> MockExecutionLayer<T> {
assert_eq!(head_execution_block.block_number(), block_number);
assert_eq!(head_execution_block.block_hash(), block_hash);
assert_eq!(head_execution_block.parent_hash(), parent_hash);
self
}
pub fn move_to_block_prior_to_terminal_block(self) -> Self {

View File

@@ -107,7 +107,7 @@ impl<T: EthSpec> MockServer<T> {
pub fn new_with_config(
handle: &runtime::Handle,
config: MockExecutionConfig,
kzg: Option<Kzg<T::Kzg>>,
kzg: Option<Kzg>,
) -> Self {
let MockExecutionConfig {
jwt_key,
@@ -188,7 +188,7 @@ impl<T: EthSpec> MockServer<T> {
terminal_block_hash: ExecutionBlockHash,
shanghai_time: Option<u64>,
cancun_time: Option<u64>,
kzg: Option<Kzg<T::Kzg>>,
kzg: Option<Kzg>,
) -> Self {
Self::new_with_config(
handle,