Merge branch 'unstable' into superstruct-features

This commit is contained in:
Mac L
2024-05-01 15:40:28 +10:00
271 changed files with 9011 additions and 8819 deletions

View File

@@ -1,9 +1,9 @@
use crate::engines::ForkchoiceState;
use crate::http::{
ENGINE_FORKCHOICE_UPDATED_V1, ENGINE_FORKCHOICE_UPDATED_V2, ENGINE_FORKCHOICE_UPDATED_V3,
ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1, ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1,
ENGINE_GET_PAYLOAD_V1, ENGINE_GET_PAYLOAD_V2, ENGINE_GET_PAYLOAD_V3, ENGINE_NEW_PAYLOAD_V1,
ENGINE_NEW_PAYLOAD_V2, ENGINE_NEW_PAYLOAD_V3,
ENGINE_GET_CLIENT_VERSION_V1, ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1,
ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1, ENGINE_GET_PAYLOAD_V1, ENGINE_GET_PAYLOAD_V2,
ENGINE_GET_PAYLOAD_V3, ENGINE_NEW_PAYLOAD_V1, ENGINE_NEW_PAYLOAD_V2, ENGINE_NEW_PAYLOAD_V3,
};
use eth2::types::{
BlobsBundle, SsePayloadAttributes, SsePayloadAttributesV1, SsePayloadAttributesV2,
@@ -24,11 +24,11 @@ pub use types::{
ExecutionPayloadRef, FixedVector, ForkName, Hash256, Transactions, Uint256, VariableList,
Withdrawal, Withdrawals,
};
use types::{
ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadElectra, ExecutionPayloadMerge,
ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadElectra, ExecutionPayloadBellatrix,
FeatureName, KzgProofs,
};
use types::{Graffiti, GRAFFITI_BYTES_LEN};
pub mod auth;
pub mod http;
@@ -36,8 +36,8 @@ pub mod json_structures;
mod new_payload_request;
pub use new_payload_request::{
NewPayloadRequest, NewPayloadRequestCapella, NewPayloadRequestDeneb, NewPayloadRequestElectra,
NewPayloadRequestMerge,
NewPayloadRequest, NewPayloadRequestBellatrix, NewPayloadRequestCapella,
NewPayloadRequestDeneb, NewPayloadRequestElectra,
};
pub const LATEST_TAG: &str = "latest";
@@ -61,13 +61,13 @@ pub enum Error {
ParentHashEqualsBlockHash(ExecutionBlockHash),
PayloadIdUnavailable,
TransitionConfigurationMismatch,
PayloadConversionLogicFlaw,
SszError(ssz_types::Error),
DeserializeWithdrawals(ssz_types::Error),
BuilderApi(builder_client::Error),
IncorrectStateVariant,
RequiredMethodUnsupported(&'static str),
UnsupportedForkVariant(String),
InvalidClientVersion(String),
RlpDecoderError(rlp::DecoderError),
}
@@ -155,7 +155,7 @@ pub struct ExecutionBlock {
/// Representation of an execution block with enough detail to reconstruct a payload.
#[superstruct(
feature(Merge),
feature(Bellatrix),
variants_and_features_from = "FORK_ORDER",
feature_dependencies = "FEATURE_DEPENDENCIES",
variant_type(name = "ForkName", getter = "fork_name"),
@@ -212,26 +212,28 @@ impl<E: EthSpec> TryFrom<ExecutionPayload<E>> for ExecutionBlockWithTransactions
fn try_from(payload: ExecutionPayload<E>) -> Result<Self, Error> {
let json_payload = match payload {
ExecutionPayload::Merge(block) => Self::Merge(ExecutionBlockWithTransactionsMerge {
parent_hash: block.parent_hash,
fee_recipient: block.fee_recipient,
state_root: block.state_root,
receipts_root: block.receipts_root,
logs_bloom: block.logs_bloom,
prev_randao: block.prev_randao,
block_number: block.block_number,
gas_limit: block.gas_limit,
gas_used: block.gas_used,
timestamp: block.timestamp,
extra_data: block.extra_data,
base_fee_per_gas: block.base_fee_per_gas,
block_hash: block.block_hash,
transactions: block
.transactions
.iter()
.map(|tx| Transaction::decode(&Rlp::new(tx)))
.collect::<Result<Vec<_>, _>>()?,
}),
ExecutionPayload::Bellatrix(block) => {
Self::Bellatrix(ExecutionBlockWithTransactionsBellatrix {
parent_hash: block.parent_hash,
fee_recipient: block.fee_recipient,
state_root: block.state_root,
receipts_root: block.receipts_root,
logs_bloom: block.logs_bloom,
prev_randao: block.prev_randao,
block_number: block.block_number,
gas_limit: block.gas_limit,
gas_used: block.gas_used,
timestamp: block.timestamp,
extra_data: block.extra_data,
base_fee_per_gas: block.base_fee_per_gas,
block_hash: block.block_hash,
transactions: block
.transactions
.iter()
.map(|tx| Transaction::decode(&Rlp::new(tx)))
.collect::<Result<Vec<_>, _>>()?,
})
}
ExecutionPayload::Capella(block) => {
Self::Capella(ExecutionBlockWithTransactionsCapella {
parent_hash: block.parent_hash,
@@ -431,7 +433,7 @@ pub struct ProposeBlindedBlockResponse {
}
#[superstruct(
feature(Merge),
feature(Bellatrix),
variants_and_features_from = "FORK_ORDER",
feature_dependencies = "FEATURE_DEPENDENCIES",
variant_type(name = "ForkName", getter = "fork_name"),
@@ -448,8 +450,11 @@ pub struct ProposeBlindedBlockResponse {
)]
#[derive(Clone, Debug, PartialEq)]
pub struct GetPayloadResponse<E: EthSpec> {
#[superstruct(only(Merge), partial_getter(rename = "execution_payload_merge"))]
pub execution_payload: ExecutionPayloadMerge<E>,
#[superstruct(
only(Bellatrix),
partial_getter(rename = "execution_payload_bellatrix")
)]
pub execution_payload: ExecutionPayloadBellatrix<E>,
#[superstruct(only(Capella), partial_getter(rename = "execution_payload_capella"))]
pub execution_payload: ExecutionPayloadCapella<E>,
#[superstruct(only(Deneb), partial_getter(rename = "execution_payload_deneb"))]
@@ -498,8 +503,8 @@ impl<E: EthSpec> From<GetPayloadResponse<E>>
{
fn from(response: GetPayloadResponse<E>) -> Self {
match response {
GetPayloadResponse::Merge(inner) => (
ExecutionPayload::Merge(inner.execution_payload),
GetPayloadResponse::Bellatrix(inner) => (
ExecutionPayload::Bellatrix(inner.execution_payload),
inner.block_value,
None,
),
@@ -545,14 +550,14 @@ impl<E: EthSpec> ExecutionPayloadBodyV1<E> {
header: ExecutionPayloadHeader<E>,
) -> Result<ExecutionPayload<E>, String> {
match header {
ExecutionPayloadHeader::Merge(header) => {
ExecutionPayloadHeader::Bellatrix(header) => {
if self.withdrawals.is_some() {
return Err(format!(
"block {} is merge but payload body has withdrawals",
header.block_hash
));
}
Ok(ExecutionPayload::Merge(ExecutionPayloadMerge {
Ok(ExecutionPayload::Bellatrix(ExecutionPayloadBellatrix {
parent_hash: header.parent_hash,
fee_recipient: header.fee_recipient,
state_root: header.state_root,
@@ -643,6 +648,9 @@ impl<E: EthSpec> ExecutionPayloadBodyV1<E> {
withdrawals,
blob_gas_used: header.blob_gas_used,
excess_blob_gas: header.excess_blob_gas,
// TODO(electra)
deposit_receipts: <_>::default(),
withdrawal_requests: <_>::default(),
}))
} else {
Err(format!(
@@ -668,6 +676,7 @@ pub struct EngineCapabilities {
pub get_payload_v1: bool,
pub get_payload_v2: bool,
pub get_payload_v3: bool,
pub get_client_version_v1: bool,
}
impl EngineCapabilities {
@@ -706,7 +715,141 @@ impl EngineCapabilities {
if self.get_payload_v3 {
response.push(ENGINE_GET_PAYLOAD_V3);
}
if self.get_client_version_v1 {
response.push(ENGINE_GET_CLIENT_VERSION_V1);
}
response
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum ClientCode {
Besu,
EtherumJS,
Erigon,
GoEthereum,
Grandine,
Lighthouse,
Lodestar,
Nethermind,
Nimbus,
Teku,
Prysm,
Reth,
Unknown(String),
}
impl std::fmt::Display for ClientCode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
ClientCode::Besu => "BU",
ClientCode::EtherumJS => "EJ",
ClientCode::Erigon => "EG",
ClientCode::GoEthereum => "GE",
ClientCode::Grandine => "GR",
ClientCode::Lighthouse => "LH",
ClientCode::Lodestar => "LS",
ClientCode::Nethermind => "NM",
ClientCode::Nimbus => "NB",
ClientCode::Teku => "TK",
ClientCode::Prysm => "PM",
ClientCode::Reth => "RH",
ClientCode::Unknown(code) => code,
};
write!(f, "{}", s)
}
}
impl TryFrom<String> for ClientCode {
type Error = String;
fn try_from(code: String) -> Result<Self, Self::Error> {
match code.as_str() {
"BU" => Ok(Self::Besu),
"EJ" => Ok(Self::EtherumJS),
"EG" => Ok(Self::Erigon),
"GE" => Ok(Self::GoEthereum),
"GR" => Ok(Self::Grandine),
"LH" => Ok(Self::Lighthouse),
"LS" => Ok(Self::Lodestar),
"NM" => Ok(Self::Nethermind),
"NB" => Ok(Self::Nimbus),
"TK" => Ok(Self::Teku),
"PM" => Ok(Self::Prysm),
"RH" => Ok(Self::Reth),
string => {
if string.len() == 2 {
Ok(Self::Unknown(code))
} else {
Err(format!("Invalid client code: {}", code))
}
}
}
}
}
#[derive(Clone, Debug)]
pub struct CommitPrefix(pub String);
impl TryFrom<String> for CommitPrefix {
type Error = String;
fn try_from(value: String) -> Result<Self, Self::Error> {
// Check if the input starts with '0x' and strip it if it does
let commit_prefix = value.strip_prefix("0x").unwrap_or(&value);
// Ensure length is exactly 8 characters after '0x' removal
if commit_prefix.len() != 8 {
return Err(
"Input must be exactly 8 characters long (excluding any '0x' prefix)".to_string(),
);
}
// Ensure all characters are valid hex digits
if commit_prefix.chars().all(|c| c.is_ascii_hexdigit()) {
Ok(CommitPrefix(commit_prefix.to_lowercase()))
} else {
Err("Input must contain only hexadecimal characters".to_string())
}
}
}
impl std::fmt::Display for CommitPrefix {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Clone, Debug)]
pub struct ClientVersionV1 {
pub code: ClientCode,
pub name: String,
pub version: String,
pub commit: CommitPrefix,
}
impl ClientVersionV1 {
pub fn calculate_graffiti(&self, lighthouse_commit_prefix: CommitPrefix) -> Graffiti {
let graffiti_string = format!(
"{}{}LH{}",
self.code,
self.commit
.0
.get(..4)
.map_or_else(|| self.commit.0.as_str(), |s| s)
.to_lowercase(),
lighthouse_commit_prefix
.0
.get(..4)
.unwrap_or("0000")
.to_lowercase(),
);
let mut graffiti_bytes = [0u8; GRAFFITI_BYTES_LEN];
let bytes_to_copy = std::cmp::min(graffiti_string.len(), GRAFFITI_BYTES_LEN);
graffiti_bytes[..bytes_to_copy]
.copy_from_slice(&graffiti_string.as_bytes()[..bytes_to_copy]);
Graffiti::from(graffiti_bytes)
}
}