Merge branch 'unstable' into into-anchor

This commit is contained in:
Daniel Knopik
2025-02-10 08:41:20 +01:00
207 changed files with 8646 additions and 4714 deletions

View File

@@ -829,7 +829,8 @@ impl HttpJsonRpc {
Ok(response.into())
}
pub async fn new_payload_v5_fulu<E: EthSpec>(
// TODO(fulu): switch to v5 endpoint when the EL is ready for Fulu
pub async fn new_payload_v4_fulu<E: EthSpec>(
&self,
new_payload_request_fulu: NewPayloadRequestFulu<'_, E>,
) -> Result<PayloadStatusV1, Error> {
@@ -844,7 +845,7 @@ impl HttpJsonRpc {
let response: JsonPayloadStatusV1 = self
.rpc_request(
ENGINE_NEW_PAYLOAD_V5,
ENGINE_NEW_PAYLOAD_V4,
params,
ENGINE_NEW_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
)
@@ -962,6 +963,19 @@ impl HttpJsonRpc {
.try_into()
.map_err(Error::BadResponse)
}
// TODO(fulu): remove when v5 method is ready.
ForkName::Fulu => {
let response: JsonGetPayloadResponseV5<E> = self
.rpc_request(
ENGINE_GET_PAYLOAD_V4,
params,
ENGINE_GET_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
)
.await?;
JsonGetPayloadResponse::V5(response)
.try_into()
.map_err(Error::BadResponse)
}
_ => Err(Error::UnsupportedForkVariant(format!(
"called get_payload_v4 with {}",
fork_name
@@ -1263,10 +1277,11 @@ impl HttpJsonRpc {
}
}
NewPayloadRequest::Fulu(new_payload_request_fulu) => {
if engine_capabilities.new_payload_v5 {
self.new_payload_v5_fulu(new_payload_request_fulu).await
// TODO(fulu): switch to v5 endpoint when the EL is ready for Fulu
if engine_capabilities.new_payload_v4 {
self.new_payload_v4_fulu(new_payload_request_fulu).await
} else {
Err(Error::RequiredMethodUnsupported("engine_newPayloadV5"))
Err(Error::RequiredMethodUnsupported("engine_newPayloadV4"))
}
}
}
@@ -1305,8 +1320,9 @@ impl HttpJsonRpc {
}
}
ForkName::Fulu => {
if engine_capabilities.get_payload_v5 {
self.get_payload_v5(fork_name, payload_id).await
// TODO(fulu): switch to v5 when the EL is ready
if engine_capabilities.get_payload_v4 {
self.get_payload_v4(fork_name, payload_id).await
} else {
Err(Error::RequiredMethodUnsupported("engine_getPayloadv5"))
}

View File

@@ -991,3 +991,154 @@ impl TryFrom<JsonClientVersionV1> for ClientVersionV1 {
})
}
}
#[cfg(test)]
mod tests {
use ssz::Encode;
use types::{
ConsolidationRequest, DepositRequest, MainnetEthSpec, PublicKeyBytes, RequestType,
SignatureBytes, WithdrawalRequest,
};
use super::*;
fn create_request_string<T: Encode>(prefix: u8, request_bytes: &T) -> String {
format!(
"0x{:02x}{}",
prefix,
hex::encode(request_bytes.as_ssz_bytes())
)
}
/// Tests all error conditions except ssz decoding errors
///
/// ***
/// Elements of the list MUST be ordered by request_type in ascending order.
/// Elements with empty request_data MUST be excluded from the list.
/// If any element is out of order, has a length of 1-byte or shorter,
/// or more than one element has the same type byte, client software MUST return -32602: Invalid params error.
/// ***
#[test]
fn test_invalid_execution_requests() {
let deposit_request = DepositRequest {
pubkey: PublicKeyBytes::empty(),
withdrawal_credentials: Hash256::random(),
amount: 32,
signature: SignatureBytes::empty(),
index: 0,
};
let consolidation_request = ConsolidationRequest {
source_address: Address::random(),
source_pubkey: PublicKeyBytes::empty(),
target_pubkey: PublicKeyBytes::empty(),
};
let withdrawal_request = WithdrawalRequest {
amount: 32,
source_address: Address::random(),
validator_pubkey: PublicKeyBytes::empty(),
};
// First check a valid request with all requests
assert!(
ExecutionRequests::<MainnetEthSpec>::try_from(JsonExecutionRequests(vec![
create_request_string(RequestType::Deposit.to_u8(), &deposit_request),
create_request_string(RequestType::Withdrawal.to_u8(), &withdrawal_request),
create_request_string(RequestType::Consolidation.to_u8(), &consolidation_request),
]))
.is_ok()
);
// Single requests
assert!(
ExecutionRequests::<MainnetEthSpec>::try_from(JsonExecutionRequests(vec![
create_request_string(RequestType::Deposit.to_u8(), &deposit_request),
]))
.is_ok()
);
assert!(
ExecutionRequests::<MainnetEthSpec>::try_from(JsonExecutionRequests(vec![
create_request_string(RequestType::Withdrawal.to_u8(), &withdrawal_request),
]))
.is_ok()
);
assert!(
ExecutionRequests::<MainnetEthSpec>::try_from(JsonExecutionRequests(vec![
create_request_string(RequestType::Consolidation.to_u8(), &consolidation_request),
]))
.is_ok()
);
// Out of order
assert!(matches!(
ExecutionRequests::<MainnetEthSpec>::try_from(JsonExecutionRequests(vec![
create_request_string(RequestType::Withdrawal.to_u8(), &withdrawal_request),
create_request_string(RequestType::Deposit.to_u8(), &deposit_request),
]))
.unwrap_err(),
RequestsError::InvalidOrdering
));
assert!(matches!(
ExecutionRequests::<MainnetEthSpec>::try_from(JsonExecutionRequests(vec![
create_request_string(RequestType::Consolidation.to_u8(), &consolidation_request),
create_request_string(RequestType::Withdrawal.to_u8(), &withdrawal_request),
]))
.unwrap_err(),
RequestsError::InvalidOrdering
));
assert!(matches!(
ExecutionRequests::<MainnetEthSpec>::try_from(JsonExecutionRequests(vec![
create_request_string(RequestType::Consolidation.to_u8(), &consolidation_request),
create_request_string(RequestType::Deposit.to_u8(), &deposit_request),
]))
.unwrap_err(),
RequestsError::InvalidOrdering
));
// Multiple requests of same type
assert!(matches!(
ExecutionRequests::<MainnetEthSpec>::try_from(JsonExecutionRequests(vec![
create_request_string(RequestType::Deposit.to_u8(), &deposit_request),
create_request_string(RequestType::Deposit.to_u8(), &deposit_request),
]))
.unwrap_err(),
RequestsError::InvalidOrdering
));
// Invalid prefix
assert!(matches!(
ExecutionRequests::<MainnetEthSpec>::try_from(JsonExecutionRequests(vec![
create_request_string(42, &deposit_request),
]))
.unwrap_err(),
RequestsError::InvalidPrefix(42)
));
// Prefix followed by no data
assert!(matches!(
ExecutionRequests::<MainnetEthSpec>::try_from(JsonExecutionRequests(vec![
create_request_string(RequestType::Deposit.to_u8(), &deposit_request),
create_request_string(
RequestType::Consolidation.to_u8(),
&Vec::<ConsolidationRequest>::new()
),
]))
.unwrap_err(),
RequestsError::EmptyRequest(1)
));
// Empty request
assert!(matches!(
ExecutionRequests::<MainnetEthSpec>::try_from(JsonExecutionRequests(vec![
create_request_string(RequestType::Deposit.to_u8(), &deposit_request),
"0x".to_string()
]))
.unwrap_err(),
RequestsError::EmptyRequest(1)
));
}
}

View File

@@ -121,8 +121,7 @@ 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,
// TODO(electra): update this with builder api returning the requests
requests: None,
requests: Some(builder_bid.execution_requests),
},
BuilderBid::Fulu(builder_bid) => BlockProposalContents::PayloadAndBlobs {
payload: ExecutionPayloadHeader::Fulu(builder_bid.header).into(),
@@ -159,6 +158,7 @@ pub enum Error {
},
ZeroLengthTransaction,
PayloadBodiesByRangeNotSupported,
GetBlobsNotSupported,
InvalidJWTSecret(String),
InvalidForkForPayload,
InvalidPayloadBody(String),
@@ -330,7 +330,7 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> BlockProposalContents<E, Paylo
// This just groups together a bunch of parameters that commonly
// get passed around together in calls to get_payload.
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Debug)]
pub struct PayloadParameters<'a> {
pub parent_hash: ExecutionBlockHash,
pub parent_gas_limit: u64,
@@ -1872,7 +1872,7 @@ impl<E: EthSpec> ExecutionLayer<E> {
.map_err(Box::new)
.map_err(Error::EngineError)
} else {
Ok(vec![None; query.len()])
Err(Error::GetBlobsNotSupported)
}
}
@@ -1901,11 +1901,18 @@ impl<E: EthSpec> ExecutionLayer<E> {
if let Some(builder) = self.builder() {
let (payload_result, duration) =
timed_future(metrics::POST_BLINDED_PAYLOAD_BUILDER, async {
builder
.post_builder_blinded_blocks(block)
.await
.map_err(Error::Builder)
.map(|d| d.data)
if builder.is_ssz_enabled() {
builder
.post_builder_blinded_blocks_ssz(block)
.await
.map_err(Error::Builder)
} else {
builder
.post_builder_blinded_blocks(block)
.await
.map_err(Error::Builder)
.map(|d| d.data)
}
})
.await;

View File

@@ -230,7 +230,8 @@ pub async fn handle_rpc<E: EthSpec>(
if method == ENGINE_NEW_PAYLOAD_V1
|| method == ENGINE_NEW_PAYLOAD_V2
|| method == ENGINE_NEW_PAYLOAD_V3
|| method == ENGINE_NEW_PAYLOAD_V4
// TODO(fulu): Uncomment this once v5 method is ready for Fulu
// || method == ENGINE_NEW_PAYLOAD_V4
{
return Err((
format!("{} called after Fulu fork!", method),
@@ -264,15 +265,16 @@ pub async fn handle_rpc<E: EthSpec>(
GENERIC_ERROR_CODE,
));
}
if matches!(request, JsonExecutionPayload::V4(_)) {
return Err((
format!(
"{} called with `ExecutionPayloadV4` after Fulu fork!",
method
),
GENERIC_ERROR_CODE,
));
}
// TODO(fulu): remove once we switch to v5
// if matches!(request, JsonExecutionPayload::V4(_)) {
// return Err((
// format!(
// "{} called with `ExecutionPayloadV4` after Fulu fork!",
// method
// ),
// GENERIC_ERROR_CODE,
// ));
// }
}
_ => unreachable!(),
};
@@ -381,8 +383,9 @@ pub async fn handle_rpc<E: EthSpec>(
== ForkName::Fulu
&& (method == ENGINE_GET_PAYLOAD_V1
|| method == ENGINE_GET_PAYLOAD_V2
|| method == ENGINE_GET_PAYLOAD_V3
|| method == ENGINE_GET_PAYLOAD_V4)
|| method == ENGINE_GET_PAYLOAD_V3)
// TODO(fulu): Uncomment this once v5 method is ready for Fulu
// || method == ENGINE_GET_PAYLOAD_V4)
{
return Err((
format!("{} called after Fulu fork!", method),
@@ -448,6 +451,22 @@ pub async fn handle_rpc<E: EthSpec>(
})
.unwrap()
}
// TODO(fulu): remove this once we switch to v5 method
JsonExecutionPayload::V5(execution_payload) => {
serde_json::to_value(JsonGetPayloadResponseV5 {
execution_payload,
block_value: Uint256::from(DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI),
blobs_bundle: maybe_blobs
.ok_or((
"No blobs returned despite V5 Payload".to_string(),
GENERIC_ERROR_CODE,
))?
.into(),
should_override_builder: false,
execution_requests: Default::default(),
})
.unwrap()
}
_ => unreachable!(),
}),
ENGINE_GET_PAYLOAD_V5 => Ok(match JsonExecutionPayload::from(response) {

File diff suppressed because it is too large Load Diff