mirror of
https://github.com/sigp/lighthouse.git
synced 2026-07-02 04:14:33 +00:00
Builder deposit requests
This commit is contained in:
@@ -7,7 +7,7 @@ use keccak_hash::KECCAK_EMPTY_LIST_RLP;
|
||||
use triehash::ordered_trie_root;
|
||||
use types::{
|
||||
EncodableExecutionBlockHeader, EthSpec, ExecutionBlockHash, ExecutionBlockHeader,
|
||||
ExecutionPayloadRef, ExecutionRequests, Hash256,
|
||||
ExecutionPayloadRef, ExecutionRequestsRef, Hash256,
|
||||
};
|
||||
|
||||
/// Calculate the block hash of an execution block.
|
||||
@@ -17,7 +17,7 @@ use types::{
|
||||
pub fn calculate_execution_block_hash<E: EthSpec>(
|
||||
payload: ExecutionPayloadRef<E>,
|
||||
parent_beacon_block_root: Option<Hash256>,
|
||||
execution_requests: Option<&ExecutionRequests<E>>,
|
||||
execution_requests: Option<ExecutionRequestsRef<E>>,
|
||||
) -> (ExecutionBlockHash, Hash256) {
|
||||
// Calculate the transactions root.
|
||||
// We're currently using a deprecated Parity library for this. We should move to a
|
||||
|
||||
@@ -844,8 +844,7 @@ impl HttpJsonRpc {
|
||||
),
|
||||
new_payload_request_electra.versioned_hashes,
|
||||
new_payload_request_electra.parent_beacon_block_root,
|
||||
new_payload_request_electra
|
||||
.execution_requests
|
||||
types::ExecutionRequestsRef::Electra(new_payload_request_electra.execution_requests)
|
||||
.get_execution_requests_list(),
|
||||
]);
|
||||
|
||||
@@ -873,8 +872,7 @@ impl HttpJsonRpc {
|
||||
),
|
||||
new_payload_request_fulu.versioned_hashes,
|
||||
new_payload_request_fulu.parent_beacon_block_root,
|
||||
new_payload_request_fulu
|
||||
.execution_requests
|
||||
types::ExecutionRequestsRef::Electra(new_payload_request_fulu.execution_requests)
|
||||
.get_execution_requests_list(),
|
||||
]);
|
||||
|
||||
@@ -902,8 +900,7 @@ impl HttpJsonRpc {
|
||||
),
|
||||
new_payload_request_gloas.versioned_hashes,
|
||||
new_payload_request_gloas.parent_beacon_block_root,
|
||||
new_payload_request_gloas
|
||||
.execution_requests
|
||||
types::ExecutionRequestsRef::Gloas(new_payload_request_gloas.execution_requests)
|
||||
.get_execution_requests_list(),
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
use super::*;
|
||||
use alloy_rlp::RlpEncodable;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::{Decode, Encode, TryFromIter};
|
||||
use ssz::{Decode, TryFromIter};
|
||||
use ssz_types::{FixedVector, VariableList, typenum::Unsigned};
|
||||
use strum::EnumString;
|
||||
use superstruct::superstruct;
|
||||
use types::data::BlobsList;
|
||||
use types::execution::{ConsolidationRequests, DepositRequests, RequestType, WithdrawalRequests};
|
||||
use types::execution::{
|
||||
BuilderDepositRequests, BuilderExitRequests, ConsolidationRequests, DepositRequests,
|
||||
ExecutionRequestsElectra, ExecutionRequestsGloas, RequestType, WithdrawalRequests,
|
||||
};
|
||||
use types::kzg_ext::KzgCommitments;
|
||||
use types::{Blob, KzgProof};
|
||||
|
||||
@@ -483,28 +486,13 @@ pub struct JsonExecutionRequests(pub Vec<String>);
|
||||
|
||||
impl<E: EthSpec> From<ExecutionRequests<E>> for JsonExecutionRequests {
|
||||
fn from(requests: ExecutionRequests<E>) -> Self {
|
||||
let mut result = Vec::new();
|
||||
if !requests.deposits.is_empty() {
|
||||
result.push(format!(
|
||||
"0x{:02x}{}",
|
||||
RequestType::Deposit.to_u8(),
|
||||
hex::encode(requests.deposits.as_ssz_bytes())
|
||||
));
|
||||
}
|
||||
if !requests.withdrawals.is_empty() {
|
||||
result.push(format!(
|
||||
"0x{:02x}{}",
|
||||
RequestType::Withdrawal.to_u8(),
|
||||
hex::encode(requests.withdrawals.as_ssz_bytes())
|
||||
));
|
||||
}
|
||||
if !requests.consolidations.is_empty() {
|
||||
result.push(format!(
|
||||
"0x{:02x}{}",
|
||||
RequestType::Consolidation.to_u8(),
|
||||
hex::encode(requests.consolidations.as_ssz_bytes())
|
||||
));
|
||||
}
|
||||
// Each element is a `RequestType`-prefixed, SSZ-encoded request list (EIP-7685).
|
||||
// The Gloas variant additionally emits builder deposit/exit requests.
|
||||
let result = requests
|
||||
.get_execution_requests_list()
|
||||
.into_iter()
|
||||
.map(|bytes| format!("0x{}", hex::encode(bytes)))
|
||||
.collect();
|
||||
JsonExecutionRequests(result)
|
||||
}
|
||||
}
|
||||
@@ -513,7 +501,15 @@ impl<E: EthSpec> TryFrom<JsonExecutionRequests> for ExecutionRequests<E> {
|
||||
type Error = RequestsError;
|
||||
|
||||
fn try_from(value: JsonExecutionRequests) -> Result<Self, Self::Error> {
|
||||
let mut requests = ExecutionRequests::default();
|
||||
let mut deposits = DepositRequests::<E>::default();
|
||||
let mut withdrawals = WithdrawalRequests::<E>::default();
|
||||
let mut consolidations = ConsolidationRequests::<E>::default();
|
||||
let mut builder_deposits = BuilderDepositRequests::<E>::default();
|
||||
let mut builder_exits = BuilderExitRequests::<E>::default();
|
||||
// [New in Gloas:EIP8282] The presence of builder requests determines the variant: the
|
||||
// EIP-7685 list is fork-agnostic, so we only know it is Gloas-shaped once a builder
|
||||
// request type appears.
|
||||
let mut has_builder_requests = false;
|
||||
let mut prev_prefix: Option<RequestType> = None;
|
||||
for (i, request) in value.0.into_iter().enumerate() {
|
||||
// hex string
|
||||
@@ -540,8 +536,8 @@ impl<E: EthSpec> TryFrom<JsonExecutionRequests> for ExecutionRequests<E> {
|
||||
|
||||
match current_prefix {
|
||||
RequestType::Deposit => {
|
||||
requests.deposits = DepositRequests::<E>::from_ssz_bytes(request_bytes)
|
||||
.map_err(|e| {
|
||||
deposits =
|
||||
DepositRequests::<E>::from_ssz_bytes(request_bytes).map_err(|e| {
|
||||
RequestsError::DecodeError(format!(
|
||||
"Failed to decode DepositRequest from EL: {:?}",
|
||||
e
|
||||
@@ -549,26 +545,64 @@ impl<E: EthSpec> TryFrom<JsonExecutionRequests> for ExecutionRequests<E> {
|
||||
})?;
|
||||
}
|
||||
RequestType::Withdrawal => {
|
||||
requests.withdrawals = WithdrawalRequests::<E>::from_ssz_bytes(request_bytes)
|
||||
.map_err(|e| {
|
||||
RequestsError::DecodeError(format!(
|
||||
"Failed to decode WithdrawalRequest from EL: {:?}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
withdrawals =
|
||||
WithdrawalRequests::<E>::from_ssz_bytes(request_bytes).map_err(|e| {
|
||||
RequestsError::DecodeError(format!(
|
||||
"Failed to decode WithdrawalRequest from EL: {:?}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
}
|
||||
RequestType::Consolidation => {
|
||||
requests.consolidations =
|
||||
ConsolidationRequests::<E>::from_ssz_bytes(request_bytes).map_err(|e| {
|
||||
consolidations = ConsolidationRequests::<E>::from_ssz_bytes(request_bytes)
|
||||
.map_err(|e| {
|
||||
RequestsError::DecodeError(format!(
|
||||
"Failed to decode ConsolidationRequest from EL: {:?}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
}
|
||||
RequestType::BuilderDeposit => {
|
||||
builder_deposits = BuilderDepositRequests::<E>::from_ssz_bytes(request_bytes)
|
||||
.map_err(|e| {
|
||||
RequestsError::DecodeError(format!(
|
||||
"Failed to decode BuilderDepositRequest from EL: {:?}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
has_builder_requests = true;
|
||||
}
|
||||
RequestType::BuilderExit => {
|
||||
builder_exits = BuilderExitRequests::<E>::from_ssz_bytes(request_bytes)
|
||||
.map_err(|e| {
|
||||
RequestsError::DecodeError(format!(
|
||||
"Failed to decode BuilderExitRequest from EL: {:?}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
has_builder_requests = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(requests)
|
||||
|
||||
// Without any builder requests the list is indistinguishable from a pre-Gloas one, so we
|
||||
// produce the Electra-shaped variant. Consumers that require the Gloas variant lift it
|
||||
// (carrying empty builder lists) at their boundary.
|
||||
if has_builder_requests {
|
||||
Ok(ExecutionRequests::Gloas(ExecutionRequestsGloas {
|
||||
deposits,
|
||||
withdrawals,
|
||||
consolidations,
|
||||
builder_deposits,
|
||||
builder_exits,
|
||||
}))
|
||||
} else {
|
||||
Ok(ExecutionRequests::Electra(ExecutionRequestsElectra {
|
||||
deposits,
|
||||
withdrawals,
|
||||
consolidations,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ use types::{
|
||||
};
|
||||
use types::{
|
||||
ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb,
|
||||
ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas, ExecutionRequests,
|
||||
ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas, ExecutionRequestsElectra,
|
||||
ExecutionRequestsGloas, ExecutionRequestsRef,
|
||||
};
|
||||
|
||||
#[superstruct(
|
||||
@@ -47,8 +48,13 @@ pub struct NewPayloadRequest<'block, E: EthSpec> {
|
||||
pub versioned_hashes: Vec<VersionedHash>,
|
||||
#[superstruct(only(Deneb, Electra, Fulu, Gloas))]
|
||||
pub parent_beacon_block_root: Hash256,
|
||||
#[superstruct(only(Electra, Fulu, Gloas))]
|
||||
pub execution_requests: &'block ExecutionRequests<E>,
|
||||
#[superstruct(
|
||||
only(Electra, Fulu),
|
||||
partial_getter(rename = "execution_requests_electra")
|
||||
)]
|
||||
pub execution_requests: &'block ExecutionRequestsElectra<E>,
|
||||
#[superstruct(only(Gloas), partial_getter(rename = "execution_requests_gloas"))]
|
||||
pub execution_requests: &'block ExecutionRequestsGloas<E>,
|
||||
}
|
||||
|
||||
impl<'block, E: EthSpec> NewPayloadRequest<'block, E> {
|
||||
@@ -123,6 +129,16 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the execution requests as a fork-tagged reference, if present.
|
||||
pub fn execution_requests_ref(&self) -> Option<ExecutionRequestsRef<'block, E>> {
|
||||
match self {
|
||||
Self::Bellatrix(_) | Self::Capella(_) | Self::Deneb(_) => None,
|
||||
Self::Electra(r) => Some(ExecutionRequestsRef::Electra(r.execution_requests)),
|
||||
Self::Fulu(r) => Some(ExecutionRequestsRef::Electra(r.execution_requests)),
|
||||
Self::Gloas(r) => Some(ExecutionRequestsRef::Gloas(r.execution_requests)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify the block hash is consistent locally within Lighthouse.
|
||||
///
|
||||
/// ## Specification
|
||||
@@ -143,7 +159,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> {
|
||||
let (header_hash, rlp_transactions_root) = calculate_execution_block_hash(
|
||||
payload,
|
||||
parent_beacon_block_root,
|
||||
self.execution_requests().ok().copied(),
|
||||
self.execution_requests_ref(),
|
||||
);
|
||||
|
||||
if header_hash != self.block_hash() {
|
||||
|
||||
@@ -118,14 +118,14 @@ impl<E: EthSpec> TryFrom<BuilderBid<E>> for ProvenancedPayload<BlockProposalCont
|
||||
block_value: builder_bid.value,
|
||||
kzg_commitments: builder_bid.blob_kzg_commitments,
|
||||
blobs_and_proofs: None,
|
||||
requests: Some(builder_bid.execution_requests),
|
||||
requests: Some(builder_bid.execution_requests.into()),
|
||||
},
|
||||
BuilderBid::Fulu(builder_bid) => BlockProposalContents::PayloadAndBlobs {
|
||||
payload: ExecutionPayloadHeader::Fulu(builder_bid.header).into(),
|
||||
block_value: builder_bid.value,
|
||||
kzg_commitments: builder_bid.blob_kzg_commitments,
|
||||
blobs_and_proofs: None,
|
||||
requests: Some(builder_bid.execution_requests),
|
||||
requests: Some(builder_bid.execution_requests.into()),
|
||||
},
|
||||
};
|
||||
Ok(ProvenancedPayload::Builder(
|
||||
|
||||
@@ -438,7 +438,9 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
should_override_builder: false,
|
||||
execution_requests: maybe_execution_requests
|
||||
.clone()
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_else(|| {
|
||||
types::ExecutionRequests::Electra(Default::default())
|
||||
})
|
||||
.into(),
|
||||
})
|
||||
.unwrap()
|
||||
@@ -461,7 +463,9 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
should_override_builder: false,
|
||||
execution_requests: maybe_execution_requests
|
||||
.clone()
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_else(|| {
|
||||
types::ExecutionRequests::Electra(Default::default())
|
||||
})
|
||||
.into(),
|
||||
})
|
||||
.unwrap()
|
||||
@@ -483,7 +487,9 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
.into(),
|
||||
should_override_builder: false,
|
||||
execution_requests: maybe_execution_requests
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_else(|| {
|
||||
types::ExecutionRequests::Electra(Default::default())
|
||||
})
|
||||
.into(),
|
||||
})
|
||||
.unwrap()
|
||||
|
||||
@@ -35,8 +35,9 @@ use types::builder::{
|
||||
};
|
||||
use types::{
|
||||
Address, BeaconState, ChainSpec, Epoch, EthSpec, ExecPayload, ExecutionPayload,
|
||||
ExecutionPayloadHeaderRefMut, ExecutionRequests, ForkName, ForkVersionDecode, Hash256,
|
||||
SignedBlindedBeaconBlock, SignedRoot, SignedValidatorRegistrationData, Slot, Uint256,
|
||||
ExecutionPayloadHeaderRefMut, ExecutionRequests, ExecutionRequestsElectra, ForkName,
|
||||
ForkVersionDecode, Hash256, SignedBlindedBeaconBlock, SignedRoot,
|
||||
SignedValidatorRegistrationData, Slot, Uint256,
|
||||
};
|
||||
use warp::reply::{self, Reply};
|
||||
use warp::{Filter, Rejection};
|
||||
@@ -603,7 +604,13 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
.unwrap_or_default(),
|
||||
value: self.get_bid_value(value),
|
||||
pubkey: self.builder_sk.public_key().compress(),
|
||||
execution_requests: maybe_requests.unwrap_or_default(),
|
||||
execution_requests: maybe_requests
|
||||
.map(|r| ExecutionRequestsElectra {
|
||||
deposits: r.deposits().clone(),
|
||||
withdrawals: r.withdrawals().clone(),
|
||||
consolidations: r.consolidations().clone(),
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
}),
|
||||
ForkName::Electra => BuilderBid::Electra(BuilderBidElectra {
|
||||
header: payload
|
||||
@@ -615,7 +622,13 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
.unwrap_or_default(),
|
||||
value: self.get_bid_value(value),
|
||||
pubkey: self.builder_sk.public_key().compress(),
|
||||
execution_requests: maybe_requests.unwrap_or_default(),
|
||||
execution_requests: maybe_requests
|
||||
.map(|r| ExecutionRequestsElectra {
|
||||
deposits: r.deposits().clone(),
|
||||
withdrawals: r.withdrawals().clone(),
|
||||
consolidations: r.consolidations().clone(),
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
}),
|
||||
ForkName::Deneb => BuilderBid::Deneb(BuilderBidDeneb {
|
||||
header: payload
|
||||
|
||||
Reference in New Issue
Block a user