mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 04:37:13 +00:00
Resolve merge conflicts
This commit is contained in:
@@ -8,13 +8,14 @@ edition = { workspace = true }
|
||||
alloy-consensus = { workspace = true }
|
||||
alloy-primitives = { workspace = true }
|
||||
alloy-rlp = { workspace = true }
|
||||
alloy-rpc-types-eth = { workspace = true }
|
||||
arc-swap = "1.6.0"
|
||||
bls = { workspace = true }
|
||||
builder_client = { path = "../builder_client" }
|
||||
bytes = { workspace = true }
|
||||
eth2 = { workspace = true }
|
||||
eth2 = { workspace = true, features = ["events", "lighthouse"] }
|
||||
ethereum_serde_utils = { workspace = true }
|
||||
ethereum_ssz = { workspace = true }
|
||||
ethers-core = { workspace = true }
|
||||
fixed_bytes = { workspace = true }
|
||||
fork_choice = { workspace = true }
|
||||
hash-db = "0.15.2"
|
||||
@@ -48,6 +49,7 @@ tracing = { workspace = true }
|
||||
tree_hash = { workspace = true }
|
||||
tree_hash_derive = { workspace = true }
|
||||
triehash = "0.8.4"
|
||||
typenum = { workspace = true }
|
||||
types = { workspace = true }
|
||||
warp = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
json_structures::{EncodableJsonWithdrawal, JsonWithdrawal},
|
||||
keccak::{keccak256, KeccakHasher},
|
||||
keccak::{KeccakHasher, keccak256},
|
||||
};
|
||||
use alloy_rlp::Encodable;
|
||||
use keccak_hash::KECCAK_EMPTY_LIST_RLP;
|
||||
@@ -80,7 +80,7 @@ mod test {
|
||||
use super::*;
|
||||
use hex::FromHex;
|
||||
use std::str::FromStr;
|
||||
use types::{Address, Hash256, Hash64, Uint256};
|
||||
use types::{Address, Hash64, Hash256, Uint256};
|
||||
|
||||
fn test_rlp_encoding(
|
||||
header: &ExecutionBlockHeader,
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::http::{
|
||||
ENGINE_GET_INCLUSION_LIST_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_GET_PAYLOAD_V4, ENGINE_GET_PAYLOAD_V5, ENGINE_NEW_PAYLOAD_V1,
|
||||
ENGINE_NEW_PAYLOAD_V2, ENGINE_NEW_PAYLOAD_V3, ENGINE_NEW_PAYLOAD_V4, ENGINE_NEW_PAYLOAD_V5,
|
||||
ENGINE_NEW_PAYLOAD_V2, ENGINE_NEW_PAYLOAD_V3, ENGINE_NEW_PAYLOAD_V4,
|
||||
};
|
||||
use eth2::types::{
|
||||
BlobsBundle, SsePayloadAttributes, SsePayloadAttributesV1, SsePayloadAttributesV2,
|
||||
@@ -20,15 +20,15 @@ use strum::IntoStaticStr;
|
||||
use superstruct::superstruct;
|
||||
pub use types::{
|
||||
Address, BeaconBlockRef, ConsolidationRequest, EthSpec, ExecutionBlockHash, ExecutionPayload,
|
||||
ExecutionPayloadHeader, ExecutionPayloadRef, FixedVector, ForkName, Hash256, Transaction,
|
||||
Transactions, Uint256, VariableList, Withdrawal, Withdrawals,
|
||||
ExecutionPayloadHeader, ExecutionPayloadRef, ForkName, Hash256, Transactions, Uint256,
|
||||
Withdrawal, Withdrawals,
|
||||
};
|
||||
use types::{
|
||||
ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb,
|
||||
ExecutionPayloadEip7805, ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionRequests,
|
||||
KzgProofs,
|
||||
ExecutionPayloadEip7805, ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas,
|
||||
ExecutionRequests, KzgProofs,
|
||||
};
|
||||
use types::{Graffiti, GRAFFITI_BYTES_LEN};
|
||||
use types::{GRAFFITI_BYTES_LEN, Graffiti};
|
||||
|
||||
pub mod auth;
|
||||
pub mod http;
|
||||
@@ -38,7 +38,7 @@ mod new_payload_request;
|
||||
pub use new_payload_request::{
|
||||
NewPayloadRequest, NewPayloadRequestBellatrix, NewPayloadRequestCapella,
|
||||
NewPayloadRequestDeneb, NewPayloadRequestEip7805, NewPayloadRequestElectra,
|
||||
NewPayloadRequestFulu,
|
||||
NewPayloadRequestFulu, NewPayloadRequestGloas,
|
||||
};
|
||||
|
||||
pub const LATEST_TAG: &str = "latest";
|
||||
@@ -271,7 +271,7 @@ pub struct ProposeBlindedBlockResponse {
|
||||
}
|
||||
|
||||
#[superstruct(
|
||||
variants(Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu),
|
||||
variants(Bellatrix, Capella, Deneb, Electra, Fulu, Eip7805, Gloas),
|
||||
variant_attributes(derive(Clone, Debug, PartialEq),),
|
||||
map_into(ExecutionPayload),
|
||||
map_ref_into(ExecutionPayloadRef),
|
||||
@@ -295,12 +295,14 @@ pub struct GetPayloadResponse<E: EthSpec> {
|
||||
pub execution_payload: ExecutionPayloadEip7805<E>,
|
||||
#[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))]
|
||||
pub execution_payload: ExecutionPayloadFulu<E>,
|
||||
#[superstruct(only(Gloas), partial_getter(rename = "execution_payload_gloas"))]
|
||||
pub execution_payload: ExecutionPayloadGloas<E>,
|
||||
pub block_value: Uint256,
|
||||
#[superstruct(only(Deneb, Electra, Eip7805, Fulu))]
|
||||
#[superstruct(only(Deneb, Electra, Fulu, Eip7805, Gloas))]
|
||||
pub blobs_bundle: BlobsBundle<E>,
|
||||
#[superstruct(only(Deneb, Electra, Eip7805, Fulu), partial_getter(copy))]
|
||||
#[superstruct(only(Deneb, Electra, Fulu, Eip7805, Gloas), partial_getter(copy))]
|
||||
pub should_override_builder: bool,
|
||||
#[superstruct(only(Electra, Eip7805, Fulu))]
|
||||
#[superstruct(only(Electra, Fulu, Eip7805, Gloas))]
|
||||
pub requests: ExecutionRequests<E>,
|
||||
}
|
||||
|
||||
@@ -380,6 +382,12 @@ impl<E: EthSpec> From<GetPayloadResponse<E>>
|
||||
Some(inner.blobs_bundle),
|
||||
Some(inner.requests),
|
||||
),
|
||||
GetPayloadResponse::Gloas(inner) => (
|
||||
ExecutionPayload::Gloas(inner.execution_payload),
|
||||
inner.block_value,
|
||||
Some(inner.blobs_bundle),
|
||||
Some(inner.requests),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -390,7 +398,7 @@ pub enum GetPayloadResponseType<E: EthSpec> {
|
||||
}
|
||||
|
||||
impl<E: EthSpec> GetPayloadResponse<E> {
|
||||
pub fn execution_payload_ref(&self) -> ExecutionPayloadRef<E> {
|
||||
pub fn execution_payload_ref(&self) -> ExecutionPayloadRef<'_, E> {
|
||||
self.to_ref().into()
|
||||
}
|
||||
}
|
||||
@@ -579,7 +587,6 @@ pub struct EngineCapabilities {
|
||||
pub new_payload_v2: bool,
|
||||
pub new_payload_v3: bool,
|
||||
pub new_payload_v4: bool,
|
||||
pub new_payload_v5: bool,
|
||||
pub forkchoice_updated_v1: bool,
|
||||
pub forkchoice_updated_v2: bool,
|
||||
pub forkchoice_updated_v3: bool,
|
||||
@@ -611,9 +618,6 @@ impl EngineCapabilities {
|
||||
if self.new_payload_v4 {
|
||||
response.push(ENGINE_NEW_PAYLOAD_V4);
|
||||
}
|
||||
if self.new_payload_v5 {
|
||||
response.push(ENGINE_NEW_PAYLOAD_V5);
|
||||
}
|
||||
if self.forkchoice_updated_v1 {
|
||||
response.push(ENGINE_FORKCHOICE_UPDATED_V1);
|
||||
}
|
||||
@@ -771,14 +775,18 @@ pub struct ClientVersionV1 {
|
||||
}
|
||||
|
||||
impl ClientVersionV1 {
|
||||
pub fn calculate_graffiti(&self, lighthouse_commit_prefix: CommitPrefix) -> Graffiti {
|
||||
let graffiti_string = format!(
|
||||
pub fn calculate_graffiti(
|
||||
&self,
|
||||
lighthouse_commit_prefix: CommitPrefix,
|
||||
validator_graffiti: Option<Graffiti>,
|
||||
) -> Graffiti {
|
||||
let append_graffiti_full = format!(
|
||||
"{}{}LH{}",
|
||||
self.code,
|
||||
self.commit
|
||||
.0
|
||||
.get(..4)
|
||||
.map_or_else(|| self.commit.0.as_str(), |s| s)
|
||||
.unwrap_or(self.commit.0.as_str())
|
||||
.to_lowercase(),
|
||||
lighthouse_commit_prefix
|
||||
.0
|
||||
@@ -786,6 +794,53 @@ impl ClientVersionV1 {
|
||||
.unwrap_or("0000")
|
||||
.to_lowercase(),
|
||||
);
|
||||
|
||||
// Implement the special case here:
|
||||
// https://hackmd.io/@wmoBhF17RAOH2NZ5bNXJVg/BJX2c9gja#SPECIAL-CASE-the-flexible-standard
|
||||
let append_graffiti_one_byte = format!(
|
||||
"{}{}LH{}",
|
||||
self.code,
|
||||
self.commit
|
||||
.0
|
||||
.get(..2)
|
||||
.unwrap_or(self.commit.0.as_str())
|
||||
.to_lowercase(),
|
||||
lighthouse_commit_prefix
|
||||
.0
|
||||
.get(..2)
|
||||
.unwrap_or("00")
|
||||
.to_lowercase(),
|
||||
);
|
||||
|
||||
let append_graffiti_no_commit = format!("{}LH", self.code);
|
||||
let append_graffiti_only_el = format!("{}", self.code);
|
||||
|
||||
let graffiti_string = if let Some(graffiti) = validator_graffiti {
|
||||
let graffiti_length = graffiti.as_utf8_lossy().len();
|
||||
let graffiti_str = graffiti.as_utf8_lossy();
|
||||
|
||||
// 12 characters for append_graffiti_full, plus one character for spacing
|
||||
// that leaves user specified graffiti to be 32-12-1 = 19 characters max, i.e., <20
|
||||
if graffiti_length < 20 {
|
||||
format!("{} {}", append_graffiti_full, graffiti_str)
|
||||
// user-specified graffiti is between 20-23 characters
|
||||
} else if (20..24).contains(&graffiti_length) {
|
||||
format!("{} {}", append_graffiti_one_byte, graffiti_str)
|
||||
// user-specified graffiti is between 24-27 characters
|
||||
} else if (24..28).contains(&graffiti_length) {
|
||||
format!("{} {}", append_graffiti_no_commit, graffiti_str)
|
||||
// user-specified graffiti is between 28-29 characters
|
||||
} else if (28..30).contains(&graffiti_length) {
|
||||
format!("{} {}", append_graffiti_only_el, graffiti_str)
|
||||
// if user-specified graffiti is between 30-32 characters, append nothing
|
||||
} else {
|
||||
return graffiti;
|
||||
}
|
||||
} else {
|
||||
// if no validator_graffiti (user doesn't specify), use the full client version info graffiti
|
||||
append_graffiti_full
|
||||
};
|
||||
|
||||
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]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use jsonwebtoken::{encode, get_current_timestamp, Algorithm, EncodingKey, Header};
|
||||
use jsonwebtoken::{Algorithm, EncodingKey, Header, encode, get_current_timestamp};
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zeroize::Zeroize;
|
||||
@@ -46,7 +46,7 @@ impl JwtKey {
|
||||
|
||||
/// Generate a random secret.
|
||||
pub fn random() -> Self {
|
||||
Self(rand::thread_rng().gen::<[u8; JWT_SECRET_LENGTH]>())
|
||||
Self(rand::rng().random::<[u8; JWT_SECRET_LENGTH]>())
|
||||
}
|
||||
|
||||
/// Returns a reference to the underlying byte array.
|
||||
|
||||
@@ -35,7 +35,6 @@ pub const ENGINE_NEW_PAYLOAD_V1: &str = "engine_newPayloadV1";
|
||||
pub const ENGINE_NEW_PAYLOAD_V2: &str = "engine_newPayloadV2";
|
||||
pub const ENGINE_NEW_PAYLOAD_V3: &str = "engine_newPayloadV3";
|
||||
pub const ENGINE_NEW_PAYLOAD_V4: &str = "engine_newPayloadV4";
|
||||
pub const ENGINE_NEW_PAYLOAD_V5: &str = "engine_newPayloadV5";
|
||||
pub const ENGINE_NEW_PAYLOAD_TIMEOUT: Duration = Duration::from_secs(8);
|
||||
|
||||
pub const ENGINE_GET_PAYLOAD_V1: &str = "engine_getPayloadV1";
|
||||
@@ -78,7 +77,6 @@ pub static LIGHTHOUSE_CAPABILITIES: &[&str] = &[
|
||||
ENGINE_NEW_PAYLOAD_V2,
|
||||
ENGINE_NEW_PAYLOAD_V3,
|
||||
ENGINE_NEW_PAYLOAD_V4,
|
||||
ENGINE_NEW_PAYLOAD_V5,
|
||||
ENGINE_GET_PAYLOAD_V1,
|
||||
ENGINE_GET_PAYLOAD_V2,
|
||||
ENGINE_GET_PAYLOAD_V3,
|
||||
@@ -109,9 +107,10 @@ pub static LIGHTHOUSE_JSON_CLIENT_VERSION: LazyLock<JsonClientVersionV1> =
|
||||
|
||||
/// Contains methods to convert arbitrary bytes to an ETH2 deposit contract object.
|
||||
pub mod deposit_log {
|
||||
use bls::{PublicKeyBytes, SignatureBytes};
|
||||
use ssz::Decode;
|
||||
use state_processing::per_block_processing::signature_sets::deposit_pubkey_signature_message;
|
||||
use types::{ChainSpec, DepositData, Hash256, PublicKeyBytes, SignatureBytes};
|
||||
use types::{ChainSpec, DepositData, Hash256};
|
||||
|
||||
pub use eth2::lighthouse::DepositLog;
|
||||
|
||||
@@ -230,7 +229,7 @@ pub mod deposit_methods {
|
||||
use super::Log;
|
||||
use crate::HttpJsonRpc;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{json, Value};
|
||||
use serde_json::{Value, json};
|
||||
use std::fmt;
|
||||
use std::ops::Range;
|
||||
use std::str::FromStr;
|
||||
@@ -658,7 +657,7 @@ impl HttpJsonRpc {
|
||||
|
||||
let mut request = self
|
||||
.client
|
||||
.post(self.url.full.clone())
|
||||
.post(self.url.expose_full().clone())
|
||||
.timeout(timeout)
|
||||
.header(CONTENT_TYPE, "application/json")
|
||||
.json(&body);
|
||||
@@ -731,7 +730,7 @@ impl HttpJsonRpc {
|
||||
pub async fn get_blobs_v2<E: EthSpec>(
|
||||
&self,
|
||||
versioned_hashes: Vec<Hash256>,
|
||||
) -> Result<Vec<Option<BlobAndProofV2<E>>>, Error> {
|
||||
) -> Result<Option<Vec<BlobAndProofV2<E>>>, Error> {
|
||||
let params = json!([versioned_hashes]);
|
||||
|
||||
self.rpc_request(
|
||||
@@ -790,7 +789,7 @@ impl HttpJsonRpc {
|
||||
&self,
|
||||
execution_payload: ExecutionPayload<E>,
|
||||
) -> Result<PayloadStatusV1, Error> {
|
||||
let params = json!([JsonExecutionPayload::from(execution_payload)]);
|
||||
let params = json!([JsonExecutionPayload::try_from(execution_payload)?]);
|
||||
|
||||
let response: JsonPayloadStatusV1 = self
|
||||
.rpc_request(
|
||||
@@ -807,7 +806,7 @@ impl HttpJsonRpc {
|
||||
&self,
|
||||
execution_payload: ExecutionPayload<E>,
|
||||
) -> Result<PayloadStatusV1, Error> {
|
||||
let params = json!([JsonExecutionPayload::from(execution_payload)]);
|
||||
let params = json!([JsonExecutionPayload::try_from(execution_payload)?]);
|
||||
|
||||
let response: JsonPayloadStatusV1 = self
|
||||
.rpc_request(
|
||||
@@ -825,7 +824,12 @@ impl HttpJsonRpc {
|
||||
new_payload_request_deneb: NewPayloadRequestDeneb<'_, E>,
|
||||
) -> Result<PayloadStatusV1, Error> {
|
||||
let params = json!([
|
||||
JsonExecutionPayload::V3(new_payload_request_deneb.execution_payload.clone().into()),
|
||||
JsonExecutionPayload::Deneb(
|
||||
new_payload_request_deneb
|
||||
.execution_payload
|
||||
.clone()
|
||||
.try_into()?
|
||||
),
|
||||
new_payload_request_deneb.versioned_hashes,
|
||||
new_payload_request_deneb.parent_beacon_block_root,
|
||||
]);
|
||||
@@ -846,7 +850,12 @@ impl HttpJsonRpc {
|
||||
new_payload_request_electra: NewPayloadRequestElectra<'_, E>,
|
||||
) -> Result<PayloadStatusV1, Error> {
|
||||
let params = json!([
|
||||
JsonExecutionPayload::V4(new_payload_request_electra.execution_payload.clone().into()),
|
||||
JsonExecutionPayload::Electra(
|
||||
new_payload_request_electra
|
||||
.execution_payload
|
||||
.clone()
|
||||
.try_into()?
|
||||
),
|
||||
new_payload_request_electra.versioned_hashes,
|
||||
new_payload_request_electra.parent_beacon_block_root,
|
||||
new_payload_request_electra
|
||||
@@ -865,7 +874,37 @@ impl HttpJsonRpc {
|
||||
Ok(response.into())
|
||||
}
|
||||
|
||||
pub async fn new_payload_v5_eip7805<E: EthSpec>(
|
||||
pub async fn new_payload_v4_fulu<E: EthSpec>(
|
||||
&self,
|
||||
new_payload_request_fulu: NewPayloadRequestFulu<'_, E>,
|
||||
) -> Result<PayloadStatusV1, Error> {
|
||||
let params = json!([
|
||||
JsonExecutionPayload::Fulu(
|
||||
new_payload_request_fulu
|
||||
.execution_payload
|
||||
.clone()
|
||||
.try_into()?
|
||||
),
|
||||
new_payload_request_fulu.versioned_hashes,
|
||||
new_payload_request_fulu.parent_beacon_block_root,
|
||||
new_payload_request_fulu
|
||||
.execution_requests
|
||||
.get_execution_requests_list(),
|
||||
]);
|
||||
|
||||
let response: JsonPayloadStatusV1 = self
|
||||
.rpc_request(
|
||||
ENGINE_NEW_PAYLOAD_V4,
|
||||
params,
|
||||
ENGINE_NEW_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(response.into())
|
||||
}
|
||||
|
||||
// TODO(EIP7805) fix new payload if needed
|
||||
pub async fn new_payload_v4_eip7805<E: EthSpec>(
|
||||
&self,
|
||||
new_payload_request_eip7805: NewPayloadRequestEip7805<'_, E>,
|
||||
) -> Result<PayloadStatusV1, Error> {
|
||||
@@ -879,7 +918,12 @@ impl HttpJsonRpc {
|
||||
.collect();
|
||||
|
||||
let params = json!([
|
||||
JsonExecutionPayload::V5(new_payload_request_eip7805.execution_payload.clone().into()),
|
||||
JsonExecutionPayload::Eip7805(
|
||||
new_payload_request_eip7805
|
||||
.execution_payload
|
||||
.clone()
|
||||
.try_into()?
|
||||
),
|
||||
new_payload_request_eip7805.versioned_hashes,
|
||||
new_payload_request_eip7805.parent_beacon_block_root,
|
||||
new_payload_request_eip7805
|
||||
@@ -888,9 +932,10 @@ impl HttpJsonRpc {
|
||||
il_transactions
|
||||
]);
|
||||
|
||||
// TODO(eip7805) should be v5 i think
|
||||
let response: JsonPayloadStatusV1 = self
|
||||
.rpc_request(
|
||||
ENGINE_NEW_PAYLOAD_V5,
|
||||
ENGINE_NEW_PAYLOAD_V4,
|
||||
params,
|
||||
ENGINE_NEW_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
@@ -899,38 +944,33 @@ impl HttpJsonRpc {
|
||||
Ok(response.into())
|
||||
}
|
||||
|
||||
pub async fn new_payload_v5_fulu<E: EthSpec>(
|
||||
pub async fn new_payload_v4_gloas<E: EthSpec>(
|
||||
&self,
|
||||
_new_payload_request_fulu: NewPayloadRequestFulu<'_, E>,
|
||||
new_payload_request_gloas: NewPayloadRequestGloas<'_, E>,
|
||||
) -> Result<PayloadStatusV1, Error> {
|
||||
unreachable!("new payload fulu");
|
||||
// // TODO(focil) clean this up?
|
||||
// let mut il_transactions = vec![];
|
||||
// for transaction in new_payload_request_fulu.il_transactions {
|
||||
// if let Ok(hex_tx) = String::from_utf8(transaction.into()).map(|v| format!("0x{}", v)) {
|
||||
// il_transactions.push(hex_tx);
|
||||
// }
|
||||
// }
|
||||
let params = json!([
|
||||
JsonExecutionPayload::Gloas(
|
||||
new_payload_request_gloas
|
||||
.execution_payload
|
||||
.clone()
|
||||
.try_into()?
|
||||
),
|
||||
new_payload_request_gloas.versioned_hashes,
|
||||
new_payload_request_gloas.parent_beacon_block_root,
|
||||
new_payload_request_gloas
|
||||
.execution_requests
|
||||
.get_execution_requests_list(),
|
||||
]);
|
||||
|
||||
// let params = json!([
|
||||
// JsonExecutionPayload::V5(new_payload_request_fulu.execution_payload.clone().into()),
|
||||
// new_payload_request_fulu.versioned_hashes,
|
||||
// new_payload_request_fulu.parent_beacon_block_root,
|
||||
// new_payload_request_fulu
|
||||
// .execution_requests
|
||||
// .get_execution_requests_list(),
|
||||
// il_transactions
|
||||
// ]);
|
||||
let response: JsonPayloadStatusV1 = self
|
||||
.rpc_request(
|
||||
ENGINE_NEW_PAYLOAD_V4,
|
||||
params,
|
||||
ENGINE_NEW_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
|
||||
// let response: JsonPayloadStatusV1 = self
|
||||
// .rpc_request(
|
||||
// ENGINE_NEW_PAYLOAD_V5,
|
||||
// params,
|
||||
// ENGINE_NEW_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
|
||||
// )
|
||||
// .await?;
|
||||
|
||||
// Ok(response.into())
|
||||
Ok(response.into())
|
||||
}
|
||||
|
||||
pub async fn get_payload_v1<E: EthSpec>(
|
||||
@@ -939,7 +979,7 @@ impl HttpJsonRpc {
|
||||
) -> Result<GetPayloadResponse<E>, Error> {
|
||||
let params = json!([JsonPayloadIdRequest::from(payload_id)]);
|
||||
|
||||
let payload_v1: JsonExecutionPayloadV1<E> = self
|
||||
let payload_v1: JsonExecutionPayloadBellatrix<E> = self
|
||||
.rpc_request(
|
||||
ENGINE_GET_PAYLOAD_V1,
|
||||
params,
|
||||
@@ -965,26 +1005,26 @@ impl HttpJsonRpc {
|
||||
|
||||
match fork_name {
|
||||
ForkName::Bellatrix => {
|
||||
let response: JsonGetPayloadResponseV1<E> = self
|
||||
let response: JsonGetPayloadResponseBellatrix<E> = self
|
||||
.rpc_request(
|
||||
ENGINE_GET_PAYLOAD_V2,
|
||||
params,
|
||||
ENGINE_GET_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
JsonGetPayloadResponse::V1(response)
|
||||
JsonGetPayloadResponse::Bellatrix(response)
|
||||
.try_into()
|
||||
.map_err(Error::BadResponse)
|
||||
}
|
||||
ForkName::Capella => {
|
||||
let response: JsonGetPayloadResponseV2<E> = self
|
||||
let response: JsonGetPayloadResponseCapella<E> = self
|
||||
.rpc_request(
|
||||
ENGINE_GET_PAYLOAD_V2,
|
||||
params,
|
||||
ENGINE_GET_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
JsonGetPayloadResponse::V2(response)
|
||||
JsonGetPayloadResponse::Capella(response)
|
||||
.try_into()
|
||||
.map_err(Error::BadResponse)
|
||||
}
|
||||
@@ -1004,14 +1044,14 @@ impl HttpJsonRpc {
|
||||
|
||||
match fork_name {
|
||||
ForkName::Deneb => {
|
||||
let response: JsonGetPayloadResponseV3<E> = self
|
||||
let response: JsonGetPayloadResponseDeneb<E> = self
|
||||
.rpc_request(
|
||||
ENGINE_GET_PAYLOAD_V3,
|
||||
params,
|
||||
ENGINE_GET_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
JsonGetPayloadResponse::V3(response)
|
||||
JsonGetPayloadResponse::Deneb(response)
|
||||
.try_into()
|
||||
.map_err(Error::BadResponse)
|
||||
}
|
||||
@@ -1031,19 +1071,19 @@ impl HttpJsonRpc {
|
||||
|
||||
match fork_name {
|
||||
ForkName::Electra => {
|
||||
let response: JsonGetPayloadResponseV4<E> = self
|
||||
let response: JsonGetPayloadResponseElectra<E> = self
|
||||
.rpc_request(
|
||||
ENGINE_GET_PAYLOAD_V4,
|
||||
params,
|
||||
ENGINE_GET_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
JsonGetPayloadResponse::V4(response)
|
||||
JsonGetPayloadResponse::Electra(response)
|
||||
.try_into()
|
||||
.map_err(Error::BadResponse)
|
||||
}
|
||||
ForkName::Eip7805 => {
|
||||
let response: JsonGetPayloadResponseV5<E> = self
|
||||
let response: JsonGetPayloadResponseEip7805<E> = self
|
||||
.rpc_request(
|
||||
ENGINE_GET_PAYLOAD_V4,
|
||||
params,
|
||||
@@ -1051,7 +1091,7 @@ impl HttpJsonRpc {
|
||||
)
|
||||
.await?;
|
||||
|
||||
JsonGetPayloadResponse::V5(response)
|
||||
JsonGetPayloadResponse::Eip7805(response)
|
||||
.try_into()
|
||||
.map_err(Error::BadResponse)
|
||||
}
|
||||
@@ -1070,15 +1110,39 @@ impl HttpJsonRpc {
|
||||
let params = json!([JsonPayloadIdRequest::from(payload_id)]);
|
||||
|
||||
match fork_name {
|
||||
ForkName::Fulu | ForkName::Eip7805 => {
|
||||
let response: JsonGetPayloadResponseV5<E> = self
|
||||
ForkName::Fulu => {
|
||||
let response: JsonGetPayloadResponseFulu<E> = self
|
||||
.rpc_request(
|
||||
ENGINE_GET_PAYLOAD_V5,
|
||||
params,
|
||||
ENGINE_GET_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
JsonGetPayloadResponse::V5(response)
|
||||
JsonGetPayloadResponse::Fulu(response)
|
||||
.try_into()
|
||||
.map_err(Error::BadResponse)
|
||||
}
|
||||
ForkName::Eip7805 => {
|
||||
let response: JsonGetPayloadResponseEip7805<E> = self
|
||||
.rpc_request(
|
||||
ENGINE_GET_PAYLOAD_V5,
|
||||
params,
|
||||
ENGINE_GET_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
JsonGetPayloadResponse::Eip7805(response)
|
||||
.try_into()
|
||||
.map_err(Error::BadResponse)
|
||||
}
|
||||
ForkName::Gloas => {
|
||||
let response: JsonGetPayloadResponseGloas<E> = self
|
||||
.rpc_request(
|
||||
ENGINE_GET_PAYLOAD_V5,
|
||||
params,
|
||||
ENGINE_GET_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
JsonGetPayloadResponse::Gloas(response)
|
||||
.try_into()
|
||||
.map_err(Error::BadResponse)
|
||||
}
|
||||
@@ -1166,10 +1230,14 @@ impl HttpJsonRpc {
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(response
|
||||
response
|
||||
.into_iter()
|
||||
.map(|opt_json| opt_json.map(From::from))
|
||||
.collect())
|
||||
.map(|opt_json| {
|
||||
opt_json
|
||||
.map(|json| json.try_into().map_err(Error::from))
|
||||
.transpose()
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
|
||||
pub async fn get_payload_bodies_by_range_v1<E: EthSpec>(
|
||||
@@ -1190,10 +1258,14 @@ impl HttpJsonRpc {
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(response
|
||||
response
|
||||
.into_iter()
|
||||
.map(|opt_json| opt_json.map(From::from))
|
||||
.collect())
|
||||
.map(|opt_json| {
|
||||
opt_json
|
||||
.map(|json| json.try_into().map_err(Error::from))
|
||||
.transpose()
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
}
|
||||
|
||||
pub async fn exchange_capabilities(&self) -> Result<EngineCapabilities, Error> {
|
||||
@@ -1212,7 +1284,6 @@ impl HttpJsonRpc {
|
||||
new_payload_v2: capabilities.contains(ENGINE_NEW_PAYLOAD_V2),
|
||||
new_payload_v3: capabilities.contains(ENGINE_NEW_PAYLOAD_V3),
|
||||
new_payload_v4: capabilities.contains(ENGINE_NEW_PAYLOAD_V4),
|
||||
new_payload_v5: capabilities.contains(ENGINE_NEW_PAYLOAD_V5),
|
||||
forkchoice_updated_v1: capabilities.contains(ENGINE_FORKCHOICE_UPDATED_V1),
|
||||
forkchoice_updated_v2: capabilities.contains(ENGINE_FORKCHOICE_UPDATED_V2),
|
||||
forkchoice_updated_v3: capabilities.contains(ENGINE_FORKCHOICE_UPDATED_V3),
|
||||
@@ -1319,6 +1390,10 @@ impl HttpJsonRpc {
|
||||
} else {
|
||||
let engine_version = self.get_client_version_v1().await?;
|
||||
*lock = Some(CachedResponse::new(engine_version.clone()));
|
||||
if !engine_version.is_empty() {
|
||||
// reset metric gauge when there's a fresh fetch
|
||||
crate::metrics::reset_execution_layer_info_gauge();
|
||||
}
|
||||
Ok(engine_version)
|
||||
}
|
||||
}
|
||||
@@ -1357,19 +1432,27 @@ impl HttpJsonRpc {
|
||||
Err(Error::RequiredMethodUnsupported("engine_newPayloadV4"))
|
||||
}
|
||||
}
|
||||
NewPayloadRequest::Eip7805(new_payload_request_eip7805) => {
|
||||
if engine_capabilities.new_payload_v5 {
|
||||
self.new_payload_v5_eip7805(new_payload_request_eip7805)
|
||||
.await
|
||||
NewPayloadRequest::Fulu(new_payload_request_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"))
|
||||
}
|
||||
}
|
||||
NewPayloadRequest::Fulu(new_payload_request_fulu) => {
|
||||
if engine_capabilities.new_payload_v5 {
|
||||
self.new_payload_v5_fulu(new_payload_request_fulu).await
|
||||
// TODO(EIP7805) engine capabilties should be v5?
|
||||
NewPayloadRequest::Eip7805(new_payload_request_eip7805) => {
|
||||
if engine_capabilities.new_payload_v4 {
|
||||
self.new_payload_v4_eip7805(new_payload_request_eip7805)
|
||||
.await
|
||||
} else {
|
||||
Err(Error::RequiredMethodUnsupported("engine_newPayloadV5"))
|
||||
Err(Error::RequiredMethodUnsupported("engine_newPayloadV4"))
|
||||
}
|
||||
}
|
||||
NewPayloadRequest::Gloas(new_payload_request_gloas) => {
|
||||
if engine_capabilities.new_payload_v4 {
|
||||
self.new_payload_v4_gloas(new_payload_request_gloas).await
|
||||
} else {
|
||||
Err(Error::RequiredMethodUnsupported("engine_newPayloadV4"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1421,6 +1504,13 @@ impl HttpJsonRpc {
|
||||
Err(Error::RequiredMethodUnsupported("engine_getPayloadv5"))
|
||||
}
|
||||
}
|
||||
ForkName::Gloas => {
|
||||
if engine_capabilities.get_payload_v5 {
|
||||
self.get_payload_v5(fork_name, payload_id).await
|
||||
} else {
|
||||
Err(Error::RequiredMethodUnsupported("engine_getPayloadv5"))
|
||||
}
|
||||
}
|
||||
ForkName::Base | ForkName::Altair => Err(Error::UnsupportedForkVariant(format!(
|
||||
"called get_payload with {}",
|
||||
fork_name
|
||||
@@ -1479,11 +1569,14 @@ impl HttpJsonRpc {
|
||||
mod test {
|
||||
use super::auth::JwtKey;
|
||||
use super::*;
|
||||
use crate::test_utils::{MockServer, DEFAULT_JWT_SECRET};
|
||||
use crate::test_utils::{DEFAULT_JWT_SECRET, MockServer};
|
||||
use fixed_bytes::FixedBytesExtended;
|
||||
use ssz_types::VariableList;
|
||||
use std::future::Future;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use types::{FixedBytesExtended, MainnetEthSpec, Unsigned};
|
||||
use typenum::Unsigned;
|
||||
use types::MainnetEthSpec;
|
||||
|
||||
struct Tester {
|
||||
server: MockServer<MainnetEthSpec>,
|
||||
@@ -1493,8 +1586,7 @@ mod test {
|
||||
|
||||
impl Tester {
|
||||
pub fn new(with_auth: bool) -> Self {
|
||||
let spec = Arc::new(MainnetEthSpec::default_spec());
|
||||
let server = MockServer::unit_testing(spec);
|
||||
let server = MockServer::unit_testing();
|
||||
|
||||
let rpc_url = SensitiveUrl::parse(&server.url()).unwrap();
|
||||
let echo_url = SensitiveUrl::parse(&format!("{}/echo", server.url())).unwrap();
|
||||
@@ -1590,10 +1682,11 @@ mod test {
|
||||
fn encode_transactions<E: EthSpec>(
|
||||
transactions: Transactions<E>,
|
||||
) -> Result<serde_json::Value, serde_json::Error> {
|
||||
let ep: JsonExecutionPayload<E> = JsonExecutionPayload::V1(JsonExecutionPayloadV1 {
|
||||
transactions,
|
||||
..<_>::default()
|
||||
});
|
||||
let ep: JsonExecutionPayload<E> =
|
||||
JsonExecutionPayload::Bellatrix(JsonExecutionPayloadBellatrix {
|
||||
transactions,
|
||||
..<_>::default()
|
||||
});
|
||||
let json = serde_json::to_value(ep)?;
|
||||
Ok(json.get("transactions").unwrap().clone())
|
||||
}
|
||||
@@ -1853,16 +1946,16 @@ mod test {
|
||||
fee_recipient: Address::repeat_byte(1),
|
||||
state_root: Hash256::repeat_byte(1),
|
||||
receipts_root: Hash256::repeat_byte(0),
|
||||
logs_bloom: vec![1; 256].into(),
|
||||
logs_bloom: vec![1; 256].try_into().unwrap(),
|
||||
prev_randao: Hash256::repeat_byte(1),
|
||||
block_number: 0,
|
||||
gas_limit: 1,
|
||||
gas_used: 2,
|
||||
timestamp: 42,
|
||||
extra_data: vec![].into(),
|
||||
extra_data: vec![].try_into().unwrap(),
|
||||
base_fee_per_gas: Uint256::from(1),
|
||||
block_hash: ExecutionBlockHash::repeat_byte(1),
|
||||
transactions: vec![].into(),
|
||||
transactions: vec![].try_into().unwrap(),
|
||||
},
|
||||
))
|
||||
.await;
|
||||
@@ -1900,16 +1993,16 @@ mod test {
|
||||
fee_recipient: Address::repeat_byte(1),
|
||||
state_root: Hash256::repeat_byte(1),
|
||||
receipts_root: Hash256::repeat_byte(0),
|
||||
logs_bloom: vec![1; 256].into(),
|
||||
logs_bloom: vec![1; 256].try_into().unwrap(),
|
||||
prev_randao: Hash256::repeat_byte(1),
|
||||
block_number: 0,
|
||||
gas_limit: 1,
|
||||
gas_used: 2,
|
||||
timestamp: 42,
|
||||
extra_data: vec![].into(),
|
||||
extra_data: vec![].try_into().unwrap(),
|
||||
base_fee_per_gas: Uint256::from(1),
|
||||
block_hash: ExecutionBlockHash::repeat_byte(1),
|
||||
transactions: vec![].into(),
|
||||
transactions: vec![].try_into().unwrap(),
|
||||
},
|
||||
))
|
||||
.await
|
||||
@@ -2110,16 +2203,16 @@ mod test {
|
||||
fee_recipient: Address::from_str("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap(),
|
||||
state_root: Hash256::from_str("0xca3149fa9e37db08d1cd49c9061db1002ef1cd58db2210f2115c8c989b2bdf45").unwrap(),
|
||||
receipts_root: Hash256::from_str("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").unwrap(),
|
||||
logs_bloom: vec![0; 256].into(),
|
||||
logs_bloom: vec![0; 256].try_into().unwrap(),
|
||||
prev_randao: Hash256::zero(),
|
||||
block_number: 1,
|
||||
gas_limit: u64::from_str_radix("1c95111",16).unwrap(),
|
||||
gas_used: 0,
|
||||
timestamp: 5,
|
||||
extra_data: vec![].into(),
|
||||
extra_data: vec![].try_into().unwrap(),
|
||||
base_fee_per_gas: Uint256::from(7),
|
||||
block_hash: ExecutionBlockHash::from_str("0x6359b8381a370e2f54072a5784ddd78b6ed024991558c511d4452eb4f6ac898c").unwrap(),
|
||||
transactions: vec![].into(),
|
||||
transactions: vec![].try_into().unwrap(),
|
||||
});
|
||||
|
||||
assert_eq!(payload, expected);
|
||||
@@ -2135,16 +2228,16 @@ mod test {
|
||||
fee_recipient: Address::from_str("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap(),
|
||||
state_root: Hash256::from_str("0xca3149fa9e37db08d1cd49c9061db1002ef1cd58db2210f2115c8c989b2bdf45").unwrap(),
|
||||
receipts_root: Hash256::from_str("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").unwrap(),
|
||||
logs_bloom: vec![0; 256].into(),
|
||||
logs_bloom: vec![0; 256].try_into().unwrap(),
|
||||
prev_randao: Hash256::zero(),
|
||||
block_number: 1,
|
||||
gas_limit: u64::from_str_radix("1c9c380",16).unwrap(),
|
||||
gas_used: 0,
|
||||
timestamp: 5,
|
||||
extra_data: vec![].into(),
|
||||
extra_data: vec![].try_into().unwrap(),
|
||||
base_fee_per_gas: Uint256::from(7),
|
||||
block_hash: ExecutionBlockHash::from_str("0x3559e851470f6e7bbed1db474980683e8c315bfce99b2a6ef47c057c04de7858").unwrap(),
|
||||
transactions: vec![].into(),
|
||||
transactions: vec![].try_into().unwrap(),
|
||||
}))
|
||||
.await;
|
||||
},
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use super::*;
|
||||
use alloy_rlp::RlpEncodable;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Decode;
|
||||
use ssz::{Decode, TryFromIter};
|
||||
use ssz_types::{FixedVector, VariableList, typenum::Unsigned};
|
||||
use strum::EnumString;
|
||||
use superstruct::superstruct;
|
||||
use types::beacon_block_body::KzgCommitments;
|
||||
@@ -9,7 +10,7 @@ use types::blob_sidecar::BlobsList;
|
||||
use types::execution_requests::{
|
||||
ConsolidationRequests, DepositRequests, RequestType, WithdrawalRequests,
|
||||
};
|
||||
use types::{Blob, FixedVector, KzgProof, Unsigned};
|
||||
use types::{Blob, KzgProof};
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -65,7 +66,7 @@ pub struct JsonPayloadIdResponse {
|
||||
}
|
||||
|
||||
#[superstruct(
|
||||
variants(V1, V2, V3, V4, V5, V6),
|
||||
variants(Bellatrix, Capella, Deneb, Electra, Fulu, Eip7805, Gloas),
|
||||
variant_attributes(
|
||||
derive(Debug, PartialEq, Default, Serialize, Deserialize,),
|
||||
serde(bound = "E: EthSpec", rename_all = "camelCase"),
|
||||
@@ -100,19 +101,19 @@ pub struct JsonExecutionPayload<E: EthSpec> {
|
||||
pub block_hash: ExecutionBlockHash,
|
||||
#[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")]
|
||||
pub transactions: Transactions<E>,
|
||||
#[superstruct(only(V2, V3, V4, V5, V6))]
|
||||
#[superstruct(only(Capella, Deneb, Electra, Fulu, Eip7805, Gloas))]
|
||||
pub withdrawals: VariableList<JsonWithdrawal, E::MaxWithdrawalsPerPayload>,
|
||||
#[superstruct(only(V3, V4, V5, V6))]
|
||||
#[superstruct(only(Deneb, Electra, Fulu, Eip7805, Gloas))]
|
||||
#[serde(with = "serde_utils::u64_hex_be")]
|
||||
pub blob_gas_used: u64,
|
||||
#[superstruct(only(V3, V4, V5, V6))]
|
||||
#[superstruct(only(Deneb, Electra, Fulu, Eip7805, Gloas))]
|
||||
#[serde(with = "serde_utils::u64_hex_be")]
|
||||
pub excess_blob_gas: u64,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<ExecutionPayloadBellatrix<E>> for JsonExecutionPayloadV1<E> {
|
||||
impl<E: EthSpec> From<ExecutionPayloadBellatrix<E>> for JsonExecutionPayloadBellatrix<E> {
|
||||
fn from(payload: ExecutionPayloadBellatrix<E>) -> Self {
|
||||
JsonExecutionPayloadV1 {
|
||||
JsonExecutionPayloadBellatrix {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
@@ -130,9 +131,11 @@ impl<E: EthSpec> From<ExecutionPayloadBellatrix<E>> for JsonExecutionPayloadV1<E
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<E: EthSpec> From<ExecutionPayloadCapella<E>> for JsonExecutionPayloadV2<E> {
|
||||
fn from(payload: ExecutionPayloadCapella<E>) -> Self {
|
||||
JsonExecutionPayloadV2 {
|
||||
impl<E: EthSpec> TryFrom<ExecutionPayloadCapella<E>> for JsonExecutionPayloadCapella<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(payload: ExecutionPayloadCapella<E>) -> Result<Self, Self::Error> {
|
||||
Ok(JsonExecutionPayloadCapella {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
@@ -147,18 +150,15 @@ impl<E: EthSpec> From<ExecutionPayloadCapella<E>> for JsonExecutionPayloadV2<E>
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
block_hash: payload.block_hash,
|
||||
transactions: payload.transactions,
|
||||
withdrawals: payload
|
||||
.withdrawals
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
}
|
||||
withdrawals: withdrawals_to_json(payload.withdrawals)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
impl<E: EthSpec> From<ExecutionPayloadDeneb<E>> for JsonExecutionPayloadV3<E> {
|
||||
fn from(payload: ExecutionPayloadDeneb<E>) -> Self {
|
||||
JsonExecutionPayloadV3 {
|
||||
impl<E: EthSpec> TryFrom<ExecutionPayloadDeneb<E>> for JsonExecutionPayloadDeneb<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(payload: ExecutionPayloadDeneb<E>) -> Result<Self, Self::Error> {
|
||||
Ok(JsonExecutionPayloadDeneb {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
@@ -173,21 +173,18 @@ impl<E: EthSpec> From<ExecutionPayloadDeneb<E>> for JsonExecutionPayloadV3<E> {
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
block_hash: payload.block_hash,
|
||||
transactions: payload.transactions,
|
||||
withdrawals: payload
|
||||
.withdrawals
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
withdrawals: withdrawals_to_json(payload.withdrawals)?,
|
||||
blob_gas_used: payload.blob_gas_used,
|
||||
excess_blob_gas: payload.excess_blob_gas,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<ExecutionPayloadElectra<E>> for JsonExecutionPayloadV4<E> {
|
||||
fn from(payload: ExecutionPayloadElectra<E>) -> Self {
|
||||
JsonExecutionPayloadV4 {
|
||||
impl<E: EthSpec> TryFrom<ExecutionPayloadElectra<E>> for JsonExecutionPayloadElectra<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(payload: ExecutionPayloadElectra<E>) -> Result<Self, Self::Error> {
|
||||
Ok(JsonExecutionPayloadElectra {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
@@ -202,21 +199,18 @@ impl<E: EthSpec> From<ExecutionPayloadElectra<E>> for JsonExecutionPayloadV4<E>
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
block_hash: payload.block_hash,
|
||||
transactions: payload.transactions,
|
||||
withdrawals: payload
|
||||
.withdrawals
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
withdrawals: withdrawals_to_json(payload.withdrawals)?,
|
||||
blob_gas_used: payload.blob_gas_used,
|
||||
excess_blob_gas: payload.excess_blob_gas,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<ExecutionPayloadEip7805<E>> for JsonExecutionPayloadV5<E> {
|
||||
fn from(payload: ExecutionPayloadEip7805<E>) -> Self {
|
||||
JsonExecutionPayloadV5 {
|
||||
impl<E: EthSpec> TryFrom<ExecutionPayloadFulu<E>> for JsonExecutionPayloadFulu<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(payload: ExecutionPayloadFulu<E>) -> Result<Self, Self::Error> {
|
||||
Ok(JsonExecutionPayloadFulu {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
@@ -231,21 +225,18 @@ impl<E: EthSpec> From<ExecutionPayloadEip7805<E>> for JsonExecutionPayloadV5<E>
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
block_hash: payload.block_hash,
|
||||
transactions: payload.transactions,
|
||||
withdrawals: payload
|
||||
.withdrawals
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
withdrawals: withdrawals_to_json(payload.withdrawals)?,
|
||||
blob_gas_used: payload.blob_gas_used,
|
||||
excess_blob_gas: payload.excess_blob_gas,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<ExecutionPayloadFulu<E>> for JsonExecutionPayloadV6<E> {
|
||||
fn from(payload: ExecutionPayloadFulu<E>) -> Self {
|
||||
JsonExecutionPayloadV6 {
|
||||
impl<E: EthSpec> TryFrom<ExecutionPayloadEip7805<E>> for JsonExecutionPayloadEip7805<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(payload: ExecutionPayloadEip7805<E>) -> Result<Self, Self::Error> {
|
||||
Ok(JsonExecutionPayloadEip7805 {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
@@ -260,33 +251,69 @@ impl<E: EthSpec> From<ExecutionPayloadFulu<E>> for JsonExecutionPayloadV6<E> {
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
block_hash: payload.block_hash,
|
||||
transactions: payload.transactions,
|
||||
withdrawals: payload
|
||||
.withdrawals
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
withdrawals: withdrawals_to_json(payload.withdrawals)?,
|
||||
blob_gas_used: payload.blob_gas_used,
|
||||
excess_blob_gas: payload.excess_blob_gas,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<ExecutionPayload<E>> for JsonExecutionPayload<E> {
|
||||
fn from(execution_payload: ExecutionPayload<E>) -> Self {
|
||||
impl<E: EthSpec> TryFrom<ExecutionPayloadGloas<E>> for JsonExecutionPayloadGloas<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(payload: ExecutionPayloadGloas<E>) -> Result<Self, Self::Error> {
|
||||
Ok(JsonExecutionPayloadGloas {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
receipts_root: payload.receipts_root,
|
||||
logs_bloom: payload.logs_bloom,
|
||||
prev_randao: payload.prev_randao,
|
||||
block_number: payload.block_number,
|
||||
gas_limit: payload.gas_limit,
|
||||
gas_used: payload.gas_used,
|
||||
timestamp: payload.timestamp,
|
||||
extra_data: payload.extra_data,
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
block_hash: payload.block_hash,
|
||||
transactions: payload.transactions,
|
||||
withdrawals: withdrawals_to_json(payload.withdrawals)?,
|
||||
blob_gas_used: payload.blob_gas_used,
|
||||
excess_blob_gas: payload.excess_blob_gas,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> TryFrom<ExecutionPayload<E>> for JsonExecutionPayload<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(execution_payload: ExecutionPayload<E>) -> Result<Self, Self::Error> {
|
||||
match execution_payload {
|
||||
ExecutionPayload::Bellatrix(payload) => JsonExecutionPayload::V1(payload.into()),
|
||||
ExecutionPayload::Capella(payload) => JsonExecutionPayload::V2(payload.into()),
|
||||
ExecutionPayload::Deneb(payload) => JsonExecutionPayload::V3(payload.into()),
|
||||
ExecutionPayload::Electra(payload) => JsonExecutionPayload::V4(payload.into()),
|
||||
ExecutionPayload::Eip7805(payload) => JsonExecutionPayload::V5(payload.into()),
|
||||
ExecutionPayload::Fulu(payload) => JsonExecutionPayload::V6(payload.into()),
|
||||
ExecutionPayload::Bellatrix(payload) => {
|
||||
Ok(JsonExecutionPayload::Bellatrix(payload.into()))
|
||||
}
|
||||
ExecutionPayload::Capella(payload) => {
|
||||
Ok(JsonExecutionPayload::Capella(payload.try_into()?))
|
||||
}
|
||||
ExecutionPayload::Deneb(payload) => {
|
||||
Ok(JsonExecutionPayload::Deneb(payload.try_into()?))
|
||||
}
|
||||
ExecutionPayload::Electra(payload) => {
|
||||
Ok(JsonExecutionPayload::Electra(payload.try_into()?))
|
||||
}
|
||||
ExecutionPayload::Fulu(payload) => Ok(JsonExecutionPayload::Fulu(payload.try_into()?)),
|
||||
ExecutionPayload::Eip7805(payload) => {
|
||||
Ok(JsonExecutionPayload::Eip7805(payload.try_into()?))
|
||||
}
|
||||
ExecutionPayload::Gloas(payload) => {
|
||||
Ok(JsonExecutionPayload::Gloas(payload.try_into()?))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<JsonExecutionPayloadV1<E>> for ExecutionPayloadBellatrix<E> {
|
||||
fn from(payload: JsonExecutionPayloadV1<E>) -> Self {
|
||||
impl<E: EthSpec> From<JsonExecutionPayloadBellatrix<E>> for ExecutionPayloadBellatrix<E> {
|
||||
fn from(payload: JsonExecutionPayloadBellatrix<E>) -> Self {
|
||||
ExecutionPayloadBellatrix {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
@@ -305,9 +332,11 @@ impl<E: EthSpec> From<JsonExecutionPayloadV1<E>> for ExecutionPayloadBellatrix<E
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<E: EthSpec> From<JsonExecutionPayloadV2<E>> for ExecutionPayloadCapella<E> {
|
||||
fn from(payload: JsonExecutionPayloadV2<E>) -> Self {
|
||||
ExecutionPayloadCapella {
|
||||
impl<E: EthSpec> TryFrom<JsonExecutionPayloadCapella<E>> for ExecutionPayloadCapella<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(payload: JsonExecutionPayloadCapella<E>) -> Result<Self, Self::Error> {
|
||||
Ok(ExecutionPayloadCapella {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
@@ -322,19 +351,16 @@ impl<E: EthSpec> From<JsonExecutionPayloadV2<E>> for ExecutionPayloadCapella<E>
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
block_hash: payload.block_hash,
|
||||
transactions: payload.transactions,
|
||||
withdrawals: payload
|
||||
.withdrawals
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
}
|
||||
withdrawals: withdrawals_from_json(payload.withdrawals)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<JsonExecutionPayloadV3<E>> for ExecutionPayloadDeneb<E> {
|
||||
fn from(payload: JsonExecutionPayloadV3<E>) -> Self {
|
||||
ExecutionPayloadDeneb {
|
||||
impl<E: EthSpec> TryFrom<JsonExecutionPayloadDeneb<E>> for ExecutionPayloadDeneb<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(payload: JsonExecutionPayloadDeneb<E>) -> Result<Self, Self::Error> {
|
||||
Ok(ExecutionPayloadDeneb {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
@@ -349,21 +375,18 @@ impl<E: EthSpec> From<JsonExecutionPayloadV3<E>> for ExecutionPayloadDeneb<E> {
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
block_hash: payload.block_hash,
|
||||
transactions: payload.transactions,
|
||||
withdrawals: payload
|
||||
.withdrawals
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
withdrawals: withdrawals_from_json(payload.withdrawals)?,
|
||||
blob_gas_used: payload.blob_gas_used,
|
||||
excess_blob_gas: payload.excess_blob_gas,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<JsonExecutionPayloadV4<E>> for ExecutionPayloadElectra<E> {
|
||||
fn from(payload: JsonExecutionPayloadV4<E>) -> Self {
|
||||
ExecutionPayloadElectra {
|
||||
impl<E: EthSpec> TryFrom<JsonExecutionPayloadElectra<E>> for ExecutionPayloadElectra<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(payload: JsonExecutionPayloadElectra<E>) -> Result<Self, Self::Error> {
|
||||
Ok(ExecutionPayloadElectra {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
@@ -378,21 +401,18 @@ impl<E: EthSpec> From<JsonExecutionPayloadV4<E>> for ExecutionPayloadElectra<E>
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
block_hash: payload.block_hash,
|
||||
transactions: payload.transactions,
|
||||
withdrawals: payload
|
||||
.withdrawals
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
withdrawals: withdrawals_from_json(payload.withdrawals)?,
|
||||
blob_gas_used: payload.blob_gas_used,
|
||||
excess_blob_gas: payload.excess_blob_gas,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<JsonExecutionPayloadV5<E>> for ExecutionPayloadEip7805<E> {
|
||||
fn from(payload: JsonExecutionPayloadV5<E>) -> Self {
|
||||
ExecutionPayloadEip7805 {
|
||||
impl<E: EthSpec> TryFrom<JsonExecutionPayloadFulu<E>> for ExecutionPayloadFulu<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(payload: JsonExecutionPayloadFulu<E>) -> Result<Self, Self::Error> {
|
||||
Ok(ExecutionPayloadFulu {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
@@ -407,21 +427,18 @@ impl<E: EthSpec> From<JsonExecutionPayloadV5<E>> for ExecutionPayloadEip7805<E>
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
block_hash: payload.block_hash,
|
||||
transactions: payload.transactions,
|
||||
withdrawals: payload
|
||||
.withdrawals
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
withdrawals: withdrawals_from_json(payload.withdrawals)?,
|
||||
blob_gas_used: payload.blob_gas_used,
|
||||
excess_blob_gas: payload.excess_blob_gas,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<JsonExecutionPayloadV6<E>> for ExecutionPayloadFulu<E> {
|
||||
fn from(payload: JsonExecutionPayloadV6<E>) -> Self {
|
||||
ExecutionPayloadFulu {
|
||||
impl<E: EthSpec> TryFrom<JsonExecutionPayloadEip7805<E>> for ExecutionPayloadEip7805<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(payload: JsonExecutionPayloadEip7805<E>) -> Result<Self, Self::Error> {
|
||||
Ok(ExecutionPayloadEip7805 {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
@@ -436,27 +453,63 @@ impl<E: EthSpec> From<JsonExecutionPayloadV6<E>> for ExecutionPayloadFulu<E> {
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
block_hash: payload.block_hash,
|
||||
transactions: payload.transactions,
|
||||
withdrawals: payload
|
||||
.withdrawals
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
withdrawals: withdrawals_from_json(payload.withdrawals)?,
|
||||
blob_gas_used: payload.blob_gas_used,
|
||||
excess_blob_gas: payload.excess_blob_gas,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<JsonExecutionPayload<E>> for ExecutionPayload<E> {
|
||||
fn from(json_execution_payload: JsonExecutionPayload<E>) -> Self {
|
||||
impl<E: EthSpec> TryFrom<JsonExecutionPayloadGloas<E>> for ExecutionPayloadGloas<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(payload: JsonExecutionPayloadGloas<E>) -> Result<Self, Self::Error> {
|
||||
Ok(ExecutionPayloadGloas {
|
||||
parent_hash: payload.parent_hash,
|
||||
fee_recipient: payload.fee_recipient,
|
||||
state_root: payload.state_root,
|
||||
receipts_root: payload.receipts_root,
|
||||
logs_bloom: payload.logs_bloom,
|
||||
prev_randao: payload.prev_randao,
|
||||
block_number: payload.block_number,
|
||||
gas_limit: payload.gas_limit,
|
||||
gas_used: payload.gas_used,
|
||||
timestamp: payload.timestamp,
|
||||
extra_data: payload.extra_data,
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
block_hash: payload.block_hash,
|
||||
transactions: payload.transactions,
|
||||
withdrawals: withdrawals_from_json(payload.withdrawals)?,
|
||||
blob_gas_used: payload.blob_gas_used,
|
||||
excess_blob_gas: payload.excess_blob_gas,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> TryFrom<JsonExecutionPayload<E>> for ExecutionPayload<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(json_execution_payload: JsonExecutionPayload<E>) -> Result<Self, Self::Error> {
|
||||
match json_execution_payload {
|
||||
JsonExecutionPayload::V1(payload) => ExecutionPayload::Bellatrix(payload.into()),
|
||||
JsonExecutionPayload::V2(payload) => ExecutionPayload::Capella(payload.into()),
|
||||
JsonExecutionPayload::V3(payload) => ExecutionPayload::Deneb(payload.into()),
|
||||
JsonExecutionPayload::V4(payload) => ExecutionPayload::Electra(payload.into()),
|
||||
JsonExecutionPayload::V5(payload) => ExecutionPayload::Eip7805(payload.into()),
|
||||
JsonExecutionPayload::V6(payload) => ExecutionPayload::Fulu(payload.into()),
|
||||
JsonExecutionPayload::Bellatrix(payload) => {
|
||||
Ok(ExecutionPayload::Bellatrix(payload.into()))
|
||||
}
|
||||
JsonExecutionPayload::Capella(payload) => {
|
||||
Ok(ExecutionPayload::Capella(payload.try_into()?))
|
||||
}
|
||||
JsonExecutionPayload::Deneb(payload) => {
|
||||
Ok(ExecutionPayload::Deneb(payload.try_into()?))
|
||||
}
|
||||
JsonExecutionPayload::Electra(payload) => {
|
||||
Ok(ExecutionPayload::Electra(payload.try_into()?))
|
||||
}
|
||||
JsonExecutionPayload::Fulu(payload) => Ok(ExecutionPayload::Fulu(payload.try_into()?)),
|
||||
JsonExecutionPayload::Eip7805(payload) => {
|
||||
Ok(ExecutionPayload::Eip7805(payload.try_into()?))
|
||||
}
|
||||
JsonExecutionPayload::Gloas(payload) => {
|
||||
Ok(ExecutionPayload::Gloas(payload.try_into()?))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -500,10 +553,10 @@ impl<E: EthSpec> TryFrom<JsonExecutionRequests> for ExecutionRequests<E> {
|
||||
// Elements of the list **MUST** be ordered by `request_type` in ascending order
|
||||
let current_prefix = RequestType::from_u8(*prefix_byte)
|
||||
.ok_or(RequestsError::InvalidPrefix(*prefix_byte))?;
|
||||
if let Some(prev) = prev_prefix {
|
||||
if prev.to_u8() >= current_prefix.to_u8() {
|
||||
return Err(RequestsError::InvalidOrdering);
|
||||
}
|
||||
if let Some(prev) = prev_prefix
|
||||
&& prev.to_u8() >= current_prefix.to_u8()
|
||||
{
|
||||
return Err(RequestsError::InvalidOrdering);
|
||||
}
|
||||
prev_prefix = Some(current_prefix);
|
||||
|
||||
@@ -542,7 +595,7 @@ impl<E: EthSpec> TryFrom<JsonExecutionRequests> for ExecutionRequests<E> {
|
||||
}
|
||||
|
||||
#[superstruct(
|
||||
variants(V1, V2, V3, V4, V5, V6),
|
||||
variants(Bellatrix, Capella, Deneb, Electra, Fulu, Eip7805, Gloas),
|
||||
variant_attributes(
|
||||
derive(Debug, PartialEq, Serialize, Deserialize),
|
||||
serde(bound = "E: EthSpec", rename_all = "camelCase")
|
||||
@@ -553,25 +606,30 @@ impl<E: EthSpec> TryFrom<JsonExecutionRequests> for ExecutionRequests<E> {
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub struct JsonGetPayloadResponse<E: EthSpec> {
|
||||
#[superstruct(only(V1), partial_getter(rename = "execution_payload_v1"))]
|
||||
pub execution_payload: JsonExecutionPayloadV1<E>,
|
||||
#[superstruct(only(V2), partial_getter(rename = "execution_payload_v2"))]
|
||||
pub execution_payload: JsonExecutionPayloadV2<E>,
|
||||
#[superstruct(only(V3), partial_getter(rename = "execution_payload_v3"))]
|
||||
pub execution_payload: JsonExecutionPayloadV3<E>,
|
||||
#[superstruct(only(V4), partial_getter(rename = "execution_payload_v4"))]
|
||||
pub execution_payload: JsonExecutionPayloadV4<E>,
|
||||
#[superstruct(only(V5), partial_getter(rename = "execution_payload_v5"))]
|
||||
pub execution_payload: JsonExecutionPayloadV5<E>,
|
||||
#[superstruct(only(V6), partial_getter(rename = "execution_payload_v6"))]
|
||||
pub execution_payload: JsonExecutionPayloadV6<E>,
|
||||
#[superstruct(
|
||||
only(Bellatrix),
|
||||
partial_getter(rename = "execution_payload_bellatrix")
|
||||
)]
|
||||
pub execution_payload: JsonExecutionPayloadBellatrix<E>,
|
||||
#[superstruct(only(Capella), partial_getter(rename = "execution_payload_capella"))]
|
||||
pub execution_payload: JsonExecutionPayloadCapella<E>,
|
||||
#[superstruct(only(Deneb), partial_getter(rename = "execution_payload_deneb"))]
|
||||
pub execution_payload: JsonExecutionPayloadDeneb<E>,
|
||||
#[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))]
|
||||
pub execution_payload: JsonExecutionPayloadElectra<E>,
|
||||
#[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))]
|
||||
pub execution_payload: JsonExecutionPayloadFulu<E>,
|
||||
#[superstruct(only(Eip7805), partial_getter(rename = "execution_payload_eip7805"))]
|
||||
pub execution_payload: JsonExecutionPayloadEip7805<E>,
|
||||
#[superstruct(only(Gloas), partial_getter(rename = "execution_payload_gloas"))]
|
||||
pub execution_payload: JsonExecutionPayloadGloas<E>,
|
||||
#[serde(with = "serde_utils::u256_hex_be")]
|
||||
pub block_value: Uint256,
|
||||
#[superstruct(only(V3, V4, V5, V6))]
|
||||
#[superstruct(only(Deneb, Electra, Fulu, Eip7805, Gloas))]
|
||||
pub blobs_bundle: JsonBlobsBundleV1<E>,
|
||||
#[superstruct(only(V3, V4, V5, V6))]
|
||||
#[superstruct(only(Deneb, Electra, Fulu, Eip7805, Gloas))]
|
||||
pub should_override_builder: bool,
|
||||
#[superstruct(only(V4, V5, V6))]
|
||||
#[superstruct(only(Electra, Fulu, Eip7805, Gloas))]
|
||||
pub execution_requests: JsonExecutionRequests,
|
||||
}
|
||||
|
||||
@@ -579,56 +637,79 @@ impl<E: EthSpec> TryFrom<JsonGetPayloadResponse<E>> for GetPayloadResponse<E> {
|
||||
type Error = String;
|
||||
fn try_from(json_get_payload_response: JsonGetPayloadResponse<E>) -> Result<Self, Self::Error> {
|
||||
match json_get_payload_response {
|
||||
JsonGetPayloadResponse::V1(response) => {
|
||||
JsonGetPayloadResponse::Bellatrix(response) => {
|
||||
Ok(GetPayloadResponse::Bellatrix(GetPayloadResponseBellatrix {
|
||||
execution_payload: response.execution_payload.into(),
|
||||
block_value: response.block_value,
|
||||
}))
|
||||
}
|
||||
JsonGetPayloadResponse::V2(response) => {
|
||||
JsonGetPayloadResponse::Capella(response) => {
|
||||
Ok(GetPayloadResponse::Capella(GetPayloadResponseCapella {
|
||||
execution_payload: response.execution_payload.into(),
|
||||
execution_payload: response.execution_payload.try_into().map_err(|e| {
|
||||
format!("Failed to convert json to execution payload: {:?}", e)
|
||||
})?,
|
||||
block_value: response.block_value,
|
||||
}))
|
||||
}
|
||||
JsonGetPayloadResponse::V3(response) => {
|
||||
JsonGetPayloadResponse::Deneb(response) => {
|
||||
Ok(GetPayloadResponse::Deneb(GetPayloadResponseDeneb {
|
||||
execution_payload: response.execution_payload.into(),
|
||||
execution_payload: response.execution_payload.try_into().map_err(|e| {
|
||||
format!("Failed to convert json to execution payload: {:?}", e)
|
||||
})?,
|
||||
block_value: response.block_value,
|
||||
blobs_bundle: response.blobs_bundle.into(),
|
||||
should_override_builder: response.should_override_builder,
|
||||
}))
|
||||
}
|
||||
JsonGetPayloadResponse::V4(response) => {
|
||||
JsonGetPayloadResponse::Electra(response) => {
|
||||
Ok(GetPayloadResponse::Electra(GetPayloadResponseElectra {
|
||||
execution_payload: response.execution_payload.into(),
|
||||
execution_payload: response.execution_payload.try_into().map_err(|e| {
|
||||
format!("Failed to convert json to execution payload: {:?}", e)
|
||||
})?,
|
||||
block_value: response.block_value,
|
||||
blobs_bundle: response.blobs_bundle.into(),
|
||||
should_override_builder: response.should_override_builder,
|
||||
requests: response.execution_requests.try_into().map_err(|e| {
|
||||
format!("Failed to convert json to execution requests : {:?}", e)
|
||||
format!("Failed to convert json to execution requests: {:?}", e)
|
||||
})?,
|
||||
}))
|
||||
}
|
||||
JsonGetPayloadResponse::V5(response) => {
|
||||
Ok(GetPayloadResponse::Eip7805(GetPayloadResponseEip7805 {
|
||||
execution_payload: response.execution_payload.into(),
|
||||
block_value: response.block_value,
|
||||
blobs_bundle: response.blobs_bundle.into(),
|
||||
should_override_builder: response.should_override_builder,
|
||||
requests: response.execution_requests.try_into().map_err(|e| {
|
||||
format!("Failed to convert json to execution requests {:?}", e)
|
||||
})?,
|
||||
}))
|
||||
}
|
||||
JsonGetPayloadResponse::V6(response) => {
|
||||
JsonGetPayloadResponse::Fulu(response) => {
|
||||
Ok(GetPayloadResponse::Fulu(GetPayloadResponseFulu {
|
||||
execution_payload: response.execution_payload.into(),
|
||||
execution_payload: response.execution_payload.try_into().map_err(|e| {
|
||||
format!("Failed to convert json to execution payload: {:?}", e)
|
||||
})?,
|
||||
block_value: response.block_value,
|
||||
blobs_bundle: response.blobs_bundle.into(),
|
||||
should_override_builder: response.should_override_builder,
|
||||
requests: response.execution_requests.try_into().map_err(|e| {
|
||||
format!("Failed to convert json to execution requests {:?}", e)
|
||||
format!("Failed to convert json to execution requests: {:?}", e)
|
||||
})?,
|
||||
}))
|
||||
}
|
||||
JsonGetPayloadResponse::Eip7805(response) => {
|
||||
Ok(GetPayloadResponse::Eip7805(GetPayloadResponseEip7805 {
|
||||
execution_payload: response.execution_payload.try_into().map_err(|e| {
|
||||
format!("Failed to convert json to execution payload: {:?}", e)
|
||||
})?,
|
||||
block_value: response.block_value,
|
||||
blobs_bundle: response.blobs_bundle.into(),
|
||||
should_override_builder: response.should_override_builder,
|
||||
requests: response.execution_requests.try_into().map_err(|e| {
|
||||
format!("Failed to convert json to execution requests: {:?}", e)
|
||||
})?,
|
||||
}))
|
||||
}
|
||||
JsonGetPayloadResponse::Gloas(response) => {
|
||||
Ok(GetPayloadResponse::Gloas(GetPayloadResponseGloas {
|
||||
execution_payload: response.execution_payload.try_into().map_err(|e| {
|
||||
format!("Failed to convert json to execution payload: {:?}", e)
|
||||
})?,
|
||||
block_value: response.block_value,
|
||||
blobs_bundle: response.blobs_bundle.into(),
|
||||
should_override_builder: response.should_override_builder,
|
||||
requests: response.execution_requests.try_into().map_err(|e| {
|
||||
format!("Failed to convert json to execution requests: {:?}", e)
|
||||
})?,
|
||||
}))
|
||||
}
|
||||
@@ -670,6 +751,26 @@ impl From<JsonWithdrawal> for Withdrawal {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions to convert between `VariableList<Withdrawal>` and `VariableList<JsonWithdrawal>`.
|
||||
fn withdrawals_to_json<N>(
|
||||
list: VariableList<Withdrawal, N>,
|
||||
) -> Result<VariableList<JsonWithdrawal, N>, ssz_types::Error>
|
||||
where
|
||||
N: Unsigned,
|
||||
{
|
||||
VariableList::try_from_iter(list.into_iter().map(Into::into))
|
||||
}
|
||||
|
||||
fn withdrawals_from_json<N>(
|
||||
list: VariableList<JsonWithdrawal, N>,
|
||||
) -> Result<VariableList<Withdrawal, N>, ssz_types::Error>
|
||||
where
|
||||
N: Unsigned,
|
||||
{
|
||||
VariableList::try_from_iter(list.into_iter().map(Into::into))
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, RlpEncodable)]
|
||||
pub struct EncodableJsonWithdrawal<'a> {
|
||||
pub index: u64,
|
||||
@@ -973,30 +1074,25 @@ pub struct JsonExecutionPayloadBodyV1<E: EthSpec> {
|
||||
pub withdrawals: Option<VariableList<JsonWithdrawal, E::MaxWithdrawalsPerPayload>>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<JsonExecutionPayloadBodyV1<E>> for ExecutionPayloadBodyV1<E> {
|
||||
fn from(value: JsonExecutionPayloadBodyV1<E>) -> Self {
|
||||
Self {
|
||||
impl<E: EthSpec> TryFrom<JsonExecutionPayloadBodyV1<E>> for ExecutionPayloadBodyV1<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(value: JsonExecutionPayloadBodyV1<E>) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
transactions: value.transactions,
|
||||
withdrawals: value.withdrawals.map(|json_withdrawals| {
|
||||
Withdrawals::<E>::from(
|
||||
json_withdrawals
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
}),
|
||||
}
|
||||
withdrawals: value.withdrawals.map(withdrawals_from_json).transpose()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<ExecutionPayloadBodyV1<E>> for JsonExecutionPayloadBodyV1<E> {
|
||||
fn from(value: ExecutionPayloadBodyV1<E>) -> Self {
|
||||
Self {
|
||||
impl<E: EthSpec> TryFrom<ExecutionPayloadBodyV1<E>> for JsonExecutionPayloadBodyV1<E> {
|
||||
type Error = ssz_types::Error;
|
||||
|
||||
fn try_from(value: ExecutionPayloadBodyV1<E>) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
transactions: value.transactions,
|
||||
withdrawals: value.withdrawals.map(|withdrawals| {
|
||||
VariableList::from(withdrawals.into_iter().map(Into::into).collect::<Vec<_>>())
|
||||
}),
|
||||
}
|
||||
withdrawals: value.withdrawals.map(withdrawals_to_json).transpose()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1078,10 +1174,10 @@ impl TryFrom<JsonClientVersionV1> for ClientVersionV1 {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use bls::{PublicKeyBytes, SignatureBytes};
|
||||
use ssz::Encode;
|
||||
use types::{
|
||||
ConsolidationRequest, DepositRequest, MainnetEthSpec, PublicKeyBytes, RequestType,
|
||||
SignatureBytes, WithdrawalRequest,
|
||||
ConsolidationRequest, DepositRequest, MainnetEthSpec, RequestType, WithdrawalRequest,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{block_hash::calculate_execution_block_hash, metrics, Error, Transactions};
|
||||
use crate::{Error, block_hash::calculate_execution_block_hash, metrics};
|
||||
|
||||
use crate::versioned_hashes::verify_versioned_hashes;
|
||||
use state_processing::per_block_processing::deneb::kzg_commitment_to_versioned_hash;
|
||||
@@ -9,11 +9,12 @@ use types::{
|
||||
};
|
||||
use types::{
|
||||
ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb,
|
||||
ExecutionPayloadEip7805, ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionRequests,
|
||||
ExecutionPayloadEip7805, ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas,
|
||||
ExecutionRequests, Transactions,
|
||||
};
|
||||
|
||||
#[superstruct(
|
||||
variants(Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu),
|
||||
variants(Bellatrix, Capella, Deneb, Electra, Fulu, Eip7805, Gloas),
|
||||
variant_attributes(derive(Clone, Debug, PartialEq),),
|
||||
map_into(ExecutionPayload),
|
||||
map_ref_into(ExecutionPayloadRef),
|
||||
@@ -39,17 +40,19 @@ pub struct NewPayloadRequest<'block, E: EthSpec> {
|
||||
pub execution_payload: &'block ExecutionPayloadDeneb<E>,
|
||||
#[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))]
|
||||
pub execution_payload: &'block ExecutionPayloadElectra<E>,
|
||||
#[superstruct(only(Eip7805), partial_getter(rename = "execution_payload_eip7805"))]
|
||||
pub execution_payload: &'block ExecutionPayloadEip7805<E>,
|
||||
#[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))]
|
||||
pub execution_payload: &'block ExecutionPayloadFulu<E>,
|
||||
#[superstruct(only(Deneb, Electra, Eip7805, Fulu))]
|
||||
#[superstruct(only(Eip7805), partial_getter(rename = "execution_payload_eip7805"))]
|
||||
pub execution_payload: &'block ExecutionPayloadEip7805<E>,
|
||||
#[superstruct(only(Gloas), partial_getter(rename = "execution_payload_gloas"))]
|
||||
pub execution_payload: &'block ExecutionPayloadGloas<E>,
|
||||
#[superstruct(only(Deneb, Electra, Fulu, Eip7805, Gloas))]
|
||||
pub versioned_hashes: Vec<VersionedHash>,
|
||||
#[superstruct(only(Deneb, Electra, Eip7805, Fulu))]
|
||||
#[superstruct(only(Deneb, Electra, Fulu, Eip7805, Gloas))]
|
||||
pub parent_beacon_block_root: Hash256,
|
||||
#[superstruct(only(Electra, Eip7805, Fulu))]
|
||||
#[superstruct(only(Electra, Fulu, Eip7805, Gloas))]
|
||||
pub execution_requests: &'block ExecutionRequests<E>,
|
||||
#[superstruct(only(Eip7805, Fulu))]
|
||||
#[superstruct(only(Eip7805, Gloas))]
|
||||
pub il_transactions: Transactions<E>,
|
||||
}
|
||||
|
||||
@@ -62,6 +65,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> {
|
||||
Self::Electra(payload) => payload.execution_payload.parent_hash,
|
||||
Self::Eip7805(payload) => payload.execution_payload.parent_hash,
|
||||
Self::Fulu(payload) => payload.execution_payload.parent_hash,
|
||||
Self::Gloas(payload) => payload.execution_payload.parent_hash,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +77,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> {
|
||||
Self::Electra(payload) => payload.execution_payload.block_hash,
|
||||
Self::Eip7805(payload) => payload.execution_payload.block_hash,
|
||||
Self::Fulu(payload) => payload.execution_payload.block_hash,
|
||||
Self::Gloas(payload) => payload.execution_payload.block_hash,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +89,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> {
|
||||
Self::Electra(payload) => payload.execution_payload.block_number,
|
||||
Self::Eip7805(payload) => payload.execution_payload.block_number,
|
||||
Self::Fulu(payload) => payload.execution_payload.block_number,
|
||||
Self::Gloas(payload) => payload.execution_payload.block_number,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +101,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> {
|
||||
Self::Electra(request) => ExecutionPayloadRef::Electra(request.execution_payload),
|
||||
Self::Eip7805(request) => ExecutionPayloadRef::Eip7805(request.execution_payload),
|
||||
Self::Fulu(request) => ExecutionPayloadRef::Fulu(request.execution_payload),
|
||||
Self::Gloas(request) => ExecutionPayloadRef::Gloas(request.execution_payload),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +115,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> {
|
||||
Self::Electra(request) => ExecutionPayload::Electra(request.execution_payload.clone()),
|
||||
Self::Eip7805(request) => ExecutionPayload::Eip7805(request.execution_payload.clone()),
|
||||
Self::Fulu(request) => ExecutionPayload::Fulu(request.execution_payload.clone()),
|
||||
Self::Gloas(request) => ExecutionPayload::Gloas(request.execution_payload.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +220,18 @@ impl<'a, E: EthSpec> NewPayloadRequest<'a, E> {
|
||||
parent_beacon_block_root: block_ref.parent_root,
|
||||
execution_requests: &block_ref.body.execution_requests,
|
||||
})),
|
||||
|
||||
BeaconBlockRef::Fulu(block_ref) => Ok(Self::Fulu(NewPayloadRequestFulu {
|
||||
execution_payload: &block_ref.body.execution_payload.execution_payload,
|
||||
versioned_hashes: block_ref
|
||||
.body
|
||||
.blob_kzg_commitments
|
||||
.iter()
|
||||
.map(kzg_commitment_to_versioned_hash)
|
||||
.collect(),
|
||||
parent_beacon_block_root: block_ref.parent_root,
|
||||
execution_requests: &block_ref.body.execution_requests,
|
||||
})),
|
||||
BeaconBlockRef::Eip7805(block_ref) => Ok(Self::Eip7805(NewPayloadRequestEip7805 {
|
||||
execution_payload: &block_ref.body.execution_payload.execution_payload,
|
||||
versioned_hashes: block_ref
|
||||
@@ -224,22 +244,12 @@ impl<'a, E: EthSpec> NewPayloadRequest<'a, E> {
|
||||
execution_requests: &block_ref.body.execution_requests,
|
||||
il_transactions,
|
||||
})),
|
||||
BeaconBlockRef::Fulu(block_ref) => Ok(Self::Fulu(NewPayloadRequestFulu {
|
||||
execution_payload: &block_ref.body.execution_payload.execution_payload,
|
||||
versioned_hashes: block_ref
|
||||
.body
|
||||
.blob_kzg_commitments
|
||||
.iter()
|
||||
.map(kzg_commitment_to_versioned_hash)
|
||||
.collect(),
|
||||
parent_beacon_block_root: block_ref.parent_root,
|
||||
execution_requests: &block_ref.body.execution_requests,
|
||||
il_transactions,
|
||||
})),
|
||||
_ => Err(BeaconStateError::IncorrectStateVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO(EIP7732): Consider implementing these as methods on the NewPayloadRequest struct
|
||||
impl<'a, E: EthSpec> TryFrom<BeaconBlockRef<'a, E>> for NewPayloadRequest<'a, E> {
|
||||
type Error = BeaconStateError;
|
||||
|
||||
@@ -277,18 +287,6 @@ impl<'a, E: EthSpec> TryFrom<BeaconBlockRef<'a, E>> for NewPayloadRequest<'a, E>
|
||||
parent_beacon_block_root: block_ref.parent_root,
|
||||
execution_requests: &block_ref.body.execution_requests,
|
||||
})),
|
||||
BeaconBlockRef::Eip7805(block_ref) => Ok(Self::Eip7805(NewPayloadRequestEip7805 {
|
||||
execution_payload: &block_ref.body.execution_payload.execution_payload,
|
||||
versioned_hashes: block_ref
|
||||
.body
|
||||
.blob_kzg_commitments
|
||||
.iter()
|
||||
.map(kzg_commitment_to_versioned_hash)
|
||||
.collect(),
|
||||
parent_beacon_block_root: block_ref.parent_root,
|
||||
execution_requests: &block_ref.body.execution_requests,
|
||||
il_transactions: vec![].into(),
|
||||
})),
|
||||
BeaconBlockRef::Fulu(block_ref) => Ok(Self::Fulu(NewPayloadRequestFulu {
|
||||
execution_payload: &block_ref.body.execution_payload.execution_payload,
|
||||
versioned_hashes: block_ref
|
||||
@@ -299,8 +297,20 @@ impl<'a, E: EthSpec> TryFrom<BeaconBlockRef<'a, E>> for NewPayloadRequest<'a, E>
|
||||
.collect(),
|
||||
parent_beacon_block_root: block_ref.parent_root,
|
||||
execution_requests: &block_ref.body.execution_requests,
|
||||
il_transactions: vec![].into(),
|
||||
})),
|
||||
BeaconBlockRef::Eip7805(block_ref) => Ok(Self::Eip7805(NewPayloadRequestEip7805 {
|
||||
execution_payload: &block_ref.body.execution_payload.execution_payload,
|
||||
versioned_hashes: block_ref
|
||||
.body
|
||||
.blob_kzg_commitments
|
||||
.iter()
|
||||
.map(kzg_commitment_to_versioned_hash)
|
||||
.collect(),
|
||||
parent_beacon_block_root: block_ref.parent_root,
|
||||
execution_requests: &block_ref.body.execution_requests,
|
||||
il_transactions: vec![].try_into()?,
|
||||
})),
|
||||
BeaconBlockRef::Gloas(_) => Err(Self::Error::IncorrectStateVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,10 +332,15 @@ impl<'a, E: EthSpec> TryFrom<ExecutionPayloadRef<'a, E>> for NewPayloadRequest<'
|
||||
ExecutionPayloadRef::Electra(_) => Err(Self::Error::IncorrectStateVariant),
|
||||
ExecutionPayloadRef::Eip7805(_) => Err(Self::Error::IncorrectStateVariant),
|
||||
ExecutionPayloadRef::Fulu(_) => Err(Self::Error::IncorrectStateVariant),
|
||||
//TODO(EIP7732): Probably time to just get rid of this
|
||||
ExecutionPayloadRef::Gloas(_) => Err(Self::Error::IncorrectStateVariant),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(EIP-7732) build out the following when it's needed like in Mark's branch
|
||||
// impl<'a, E: EthSpec> TryFrom<ExecutionEnvelopeRef<'a, E>> for NewPayloadRequest<E> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::versioned_hashes::Error as VersionedHashError;
|
||||
@@ -407,7 +422,7 @@ mod test {
|
||||
*beacon_block
|
||||
.body_mut()
|
||||
.blob_kzg_commitments_mut()
|
||||
.expect("should get commitments") = commitments.into();
|
||||
.expect("should get commitments") = commitments.try_into().unwrap();
|
||||
|
||||
let new_payload_request = NewPayloadRequest::try_from(beacon_block.to_ref())
|
||||
.expect("should create new payload request");
|
||||
|
||||
@@ -11,11 +11,11 @@ use std::num::NonZeroUsize;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use task_executor::TaskExecutor;
|
||||
use tokio::sync::{watch, Mutex, RwLock};
|
||||
use tokio::sync::{Mutex, RwLock, watch};
|
||||
use tokio_stream::wrappers::WatchStream;
|
||||
use tracing::{debug, error, info, warn};
|
||||
use types::non_zero_usize::new_non_zero_usize;
|
||||
use types::ExecutionBlockHash;
|
||||
use types::non_zero_usize::new_non_zero_usize;
|
||||
|
||||
/// The number of payload IDs that will be stored for each `Engine`.
|
||||
///
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
use hash256_std_hasher::Hash256StdHasher;
|
||||
use hash_db::Hasher;
|
||||
use hash256_std_hasher::Hash256StdHasher;
|
||||
use types::Hash256;
|
||||
|
||||
pub fn keccak256(bytes: &[u8]) -> Hash256 {
|
||||
|
||||
@@ -7,28 +7,29 @@
|
||||
use crate::json_structures::{BlobAndProofV1, BlobAndProofV2};
|
||||
use crate::payload_cache::PayloadCache;
|
||||
use arc_swap::ArcSwapOption;
|
||||
use auth::{strip_prefix, Auth, JwtKey};
|
||||
use auth::{Auth, JwtKey, strip_prefix};
|
||||
pub use block_hash::calculate_execution_block_hash;
|
||||
use bls::{PublicKeyBytes, Signature};
|
||||
use builder_client::BuilderHttpClient;
|
||||
pub use engine_api::EngineCapabilities;
|
||||
use engine_api::Error as ApiError;
|
||||
pub use engine_api::*;
|
||||
pub use engine_api::{http, http::deposit_methods, http::HttpJsonRpc};
|
||||
pub use engine_api::{http, http::HttpJsonRpc, http::deposit_methods};
|
||||
use engines::{Engine, EngineError};
|
||||
pub use engines::{EngineState, ForkchoiceState};
|
||||
use eth2::types::{builder_bid::SignedBuilderBid, ForkVersionedResponse};
|
||||
use eth2::types::{BlobsBundle, FullPayloadContents};
|
||||
use ethers_core::types::Transaction as EthersTransaction;
|
||||
use eth2::types::{ForkVersionedResponse, builder_bid::SignedBuilderBid};
|
||||
use fixed_bytes::UintExtended;
|
||||
use fork_choice::ForkchoiceUpdateParameters;
|
||||
use logging::crit;
|
||||
use lru::LruCache;
|
||||
use payload_status::process_payload_status;
|
||||
pub use payload_status::PayloadStatus;
|
||||
use payload_status::process_payload_status;
|
||||
use sensitive_url::SensitiveUrl;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use slot_clock::SlotClock;
|
||||
use std::collections::{hash_map::Entry, HashMap};
|
||||
use ssz_types::VariableList;
|
||||
use std::collections::{HashMap, hash_map::Entry};
|
||||
use std::fmt;
|
||||
use std::future::Future;
|
||||
use std::io::Write;
|
||||
@@ -43,7 +44,7 @@ use tokio::{
|
||||
time::sleep,
|
||||
};
|
||||
use tokio_stream::wrappers::WatchStream;
|
||||
use tracing::{debug, error, info, warn};
|
||||
use tracing::{Instrument, debug, debug_span, error, info, instrument, warn};
|
||||
use tree_hash::TreeHash;
|
||||
use types::beacon_block_body::KzgCommitments;
|
||||
use types::builder_bid::BuilderBid;
|
||||
@@ -56,7 +57,7 @@ use types::{
|
||||
use types::{
|
||||
BeaconStateError, BlindedPayload, ChainSpec, Epoch, ExecPayload, ExecutionPayloadBellatrix,
|
||||
ExecutionPayloadCapella, ExecutionPayloadEip7805, ExecutionPayloadElectra,
|
||||
ExecutionPayloadFulu, FullPayload, ProposerPreparationData, PublicKeyBytes, Signature, Slot,
|
||||
ExecutionPayloadFulu, FullPayload, ProposerPreparationData, Slot,
|
||||
};
|
||||
|
||||
mod block_hash;
|
||||
@@ -136,8 +137,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(fulu): update this with builder api returning the requests
|
||||
requests: None,
|
||||
requests: Some(builder_bid.execution_requests),
|
||||
},
|
||||
};
|
||||
Ok(ProvenancedPayload::Builder(
|
||||
@@ -172,6 +172,7 @@ pub enum Error {
|
||||
InvalidPayloadBody(String),
|
||||
InvalidPayloadConversion,
|
||||
InvalidBlobConversion(String),
|
||||
SszTypesError(ssz_types::Error),
|
||||
BeaconStateError(BeaconStateError),
|
||||
PayloadTypeMismatch,
|
||||
VerifyingVersionedHashes(versioned_hashes::Error),
|
||||
@@ -376,11 +377,11 @@ impl ProposerPreparationDataEntry {
|
||||
// Update `gas_limit` if `updated.gas_limit` is `Some` and:
|
||||
// - `self.gas_limit` is `None`, or
|
||||
// - both are `Some` but the values differ.
|
||||
if let Some(updated_gas_limit) = updated.gas_limit {
|
||||
if self.gas_limit != Some(updated_gas_limit) {
|
||||
self.gas_limit = Some(updated_gas_limit);
|
||||
changed = true;
|
||||
}
|
||||
if let Some(updated_gas_limit) = updated.gas_limit
|
||||
&& self.gas_limit != Some(updated_gas_limit)
|
||||
{
|
||||
self.gas_limit = Some(updated_gas_limit);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// Update `update_epoch` if it differs
|
||||
@@ -433,6 +434,11 @@ pub enum FailedCondition {
|
||||
EpochsSinceFinalization,
|
||||
}
|
||||
|
||||
pub enum SubmitBlindedBlockResponse<E: EthSpec> {
|
||||
V1(Box<FullPayloadContents<E>>),
|
||||
V2,
|
||||
}
|
||||
|
||||
type PayloadContentsRefTuple<'a, E> = (ExecutionPayloadRef<'a, E>, Option<&'a BlobsBundle<E>>);
|
||||
|
||||
struct Inner<E: EthSpec> {
|
||||
@@ -757,18 +763,18 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
/// Returns the `Self::is_synced` response if unable to get latest block.
|
||||
pub async fn is_synced_for_notifier(&self, current_slot: Slot) -> bool {
|
||||
let synced = self.is_synced().await;
|
||||
if synced {
|
||||
if let Ok(Some(block)) = self
|
||||
if synced
|
||||
&& let Ok(Some(block)) = self
|
||||
.engine()
|
||||
.api
|
||||
.get_block_by_number(BlockByNumberQuery::Tag(LATEST_TAG))
|
||||
.await
|
||||
{
|
||||
if block.block_number == 0 && current_slot > 0 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
&& block.block_number == 0
|
||||
&& current_slot > 0
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
synced
|
||||
}
|
||||
|
||||
@@ -861,6 +867,7 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
}
|
||||
|
||||
/// Returns the fee-recipient address that should be used to build a block
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub async fn get_suggested_fee_recipient(&self, proposer_index: u64) -> Address {
|
||||
if let Some(preparation_data_entry) =
|
||||
self.proposer_preparation_data().await.get(&proposer_index)
|
||||
@@ -885,6 +892,7 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub async fn get_proposer_gas_limit(&self, proposer_index: u64) -> Option<u64> {
|
||||
self.proposer_preparation_data()
|
||||
.await
|
||||
@@ -901,6 +909,7 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
///
|
||||
/// The result will be returned from the first node that returns successfully. No more nodes
|
||||
/// will be contacted.
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub async fn get_payload(
|
||||
&self,
|
||||
payload_parameters: PayloadParameters<'_>,
|
||||
@@ -1006,6 +1015,7 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
timed_future(metrics::GET_BLINDED_PAYLOAD_BUILDER, async {
|
||||
builder
|
||||
.get_builder_header::<E>(slot, parent_hash, pubkey)
|
||||
.instrument(debug_span!("get_builder_header"))
|
||||
.await
|
||||
}),
|
||||
timed_future(metrics::GET_BLINDED_PAYLOAD_LOCAL, async {
|
||||
@@ -1247,6 +1257,7 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
.await
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
async fn get_full_payload_with(
|
||||
&self,
|
||||
payload_parameters: PayloadParameters<'_>,
|
||||
@@ -1366,6 +1377,7 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
}
|
||||
|
||||
/// Maps to the `engine_newPayload` JSON-RPC call.
|
||||
/// TODO(EIP-7732) figure out how and why Mark relaxed new_payload_request param's typ to NewPayloadRequest<E>
|
||||
pub async fn notify_new_payload(
|
||||
&self,
|
||||
new_payload_request: NewPayloadRequest<'_, E>,
|
||||
@@ -1497,17 +1509,17 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
let payload_attributes = self.payload_attributes(next_slot, head_block_root).await;
|
||||
|
||||
// Compute the "lookahead", the time between when the payload will be produced and now.
|
||||
if let Some(ref payload_attributes) = payload_attributes {
|
||||
if let Ok(now) = SystemTime::now().duration_since(UNIX_EPOCH) {
|
||||
let timestamp = Duration::from_secs(payload_attributes.timestamp());
|
||||
if let Some(lookahead) = timestamp.checked_sub(now) {
|
||||
metrics::observe_duration(
|
||||
&metrics::EXECUTION_LAYER_PAYLOAD_ATTRIBUTES_LOOKAHEAD,
|
||||
lookahead,
|
||||
);
|
||||
} else {
|
||||
debug!(?timestamp, ?now, "Late payload attributes")
|
||||
}
|
||||
if let Some(ref payload_attributes) = payload_attributes
|
||||
&& let Ok(now) = SystemTime::now().duration_since(UNIX_EPOCH)
|
||||
{
|
||||
let timestamp = Duration::from_secs(payload_attributes.timestamp());
|
||||
if let Some(lookahead) = timestamp.checked_sub(now) {
|
||||
metrics::observe_duration(
|
||||
&metrics::EXECUTION_LAYER_PAYLOAD_ATTRIBUTES_LOOKAHEAD,
|
||||
lookahead,
|
||||
);
|
||||
} else {
|
||||
debug!(?timestamp, ?now, "Late payload attributes")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1577,10 +1589,14 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
&self,
|
||||
age_limit: Option<Duration>,
|
||||
) -> Result<Vec<ClientVersionV1>, Error> {
|
||||
self.engine()
|
||||
let versions = self
|
||||
.engine()
|
||||
.request(|engine| engine.get_engine_version(age_limit))
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
.map_err(Into::<Error>::into)?;
|
||||
metrics::expose_execution_layer_info(&versions);
|
||||
|
||||
Ok(versions)
|
||||
}
|
||||
|
||||
/// Used during block production to determine if the merge has been triggered.
|
||||
@@ -1731,14 +1747,13 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
|
||||
self.engine()
|
||||
.request(|engine| async move {
|
||||
if let Some(pow_block) = self.get_pow_block(engine, block_hash).await? {
|
||||
if let Some(pow_parent) =
|
||||
if let Some(pow_block) = self.get_pow_block(engine, block_hash).await?
|
||||
&& let Some(pow_parent) =
|
||||
self.get_pow_block(engine, pow_block.parent_hash).await?
|
||||
{
|
||||
return Ok(Some(
|
||||
self.is_valid_terminal_pow_block(pow_block, pow_parent, spec),
|
||||
));
|
||||
}
|
||||
{
|
||||
return Ok(Some(
|
||||
self.is_valid_terminal_pow_block(pow_block, pow_parent, spec),
|
||||
));
|
||||
}
|
||||
Ok(None)
|
||||
})
|
||||
@@ -1839,6 +1854,9 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
ForkName::Base | ForkName::Altair => {
|
||||
return Err(Error::InvalidForkForPayload);
|
||||
}
|
||||
ForkName::Gloas => {
|
||||
return Err(Error::InvalidForkForPayload);
|
||||
}
|
||||
};
|
||||
return Ok(Some(payload));
|
||||
}
|
||||
@@ -1884,7 +1902,7 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
pub async fn get_blobs_v2(
|
||||
&self,
|
||||
query: Vec<Hash256>,
|
||||
) -> Result<Vec<Option<BlobAndProofV2<E>>>, Error> {
|
||||
) -> Result<Option<Vec<BlobAndProofV2<E>>>, Error> {
|
||||
let capabilities = self.get_engine_capabilities(None).await?;
|
||||
|
||||
if capabilities.get_blobs_v2 {
|
||||
@@ -1913,9 +1931,35 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
&self,
|
||||
block_root: Hash256,
|
||||
block: &SignedBlindedBeaconBlock<E>,
|
||||
) -> Result<FullPayloadContents<E>, Error> {
|
||||
spec: &ChainSpec,
|
||||
) -> Result<SubmitBlindedBlockResponse<E>, Error> {
|
||||
debug!(?block_root, "Sending block to builder");
|
||||
if spec.is_fulu_scheduled() {
|
||||
let resp = self
|
||||
.post_builder_blinded_blocks_v2(block_root, block)
|
||||
.await
|
||||
.map(|()| SubmitBlindedBlockResponse::V2);
|
||||
// Fallback to v1 if v2 fails because the relay doesn't support it.
|
||||
// Note: we should remove the fallback post fulu when all relays have support for v2.
|
||||
if resp.is_err() {
|
||||
self.post_builder_blinded_blocks_v1(block_root, block)
|
||||
.await
|
||||
.map(|full_payload| SubmitBlindedBlockResponse::V1(Box::new(full_payload)))
|
||||
} else {
|
||||
resp
|
||||
}
|
||||
} else {
|
||||
self.post_builder_blinded_blocks_v1(block_root, block)
|
||||
.await
|
||||
.map(|full_payload| SubmitBlindedBlockResponse::V1(Box::new(full_payload)))
|
||||
}
|
||||
}
|
||||
|
||||
async fn post_builder_blinded_blocks_v1(
|
||||
&self,
|
||||
block_root: Hash256,
|
||||
block: &SignedBlindedBeaconBlock<E>,
|
||||
) -> Result<FullPayloadContents<E>, Error> {
|
||||
if let Some(builder) = self.builder() {
|
||||
let (payload_result, duration) =
|
||||
timed_future(metrics::POST_BLINDED_PAYLOAD_BUILDER, async {
|
||||
@@ -1923,16 +1967,16 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
debug!(
|
||||
?block_root,
|
||||
ssz = ssz_enabled,
|
||||
"Calling submit_blinded_block on builder"
|
||||
"Calling submit_blinded_block v1 on builder"
|
||||
);
|
||||
if ssz_enabled {
|
||||
builder
|
||||
.post_builder_blinded_blocks_ssz(block)
|
||||
.post_builder_blinded_blocks_v1_ssz(block)
|
||||
.await
|
||||
.map_err(Error::Builder)
|
||||
} else {
|
||||
builder
|
||||
.post_builder_blinded_blocks(block)
|
||||
.post_builder_blinded_blocks_v1(block)
|
||||
.await
|
||||
.map_err(Error::Builder)
|
||||
.map(|d| d.data)
|
||||
@@ -1994,14 +2038,75 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
|
||||
let Some(raw_transactions) = raw_transactions else {
|
||||
debug!(%parent_hash, "The EL sent an empty inclusion list");
|
||||
return Ok(transactions.into());
|
||||
return Ok(transactions.try_into()?);
|
||||
};
|
||||
for raw_tx in raw_transactions {
|
||||
let decoded_hex_tx =
|
||||
VariableList::new(hex::decode(raw_tx.strip_prefix("0x").unwrap_or(&raw_tx))?)?;
|
||||
transactions.push(decoded_hex_tx);
|
||||
}
|
||||
Ok(transactions.into())
|
||||
Ok(transactions.try_into()?)
|
||||
}
|
||||
|
||||
async fn post_builder_blinded_blocks_v2(
|
||||
&self,
|
||||
block_root: Hash256,
|
||||
block: &SignedBlindedBeaconBlock<E>,
|
||||
) -> Result<(), Error> {
|
||||
if let Some(builder) = self.builder() {
|
||||
let (result, duration) = timed_future(metrics::POST_BLINDED_PAYLOAD_BUILDER, async {
|
||||
let ssz_enabled = builder.is_ssz_available();
|
||||
debug!(
|
||||
?block_root,
|
||||
ssz = ssz_enabled,
|
||||
"Calling submit_blinded_block v2 on builder"
|
||||
);
|
||||
if ssz_enabled {
|
||||
builder
|
||||
.post_builder_blinded_blocks_v2_ssz(block)
|
||||
.await
|
||||
.map_err(Error::Builder)
|
||||
} else {
|
||||
builder
|
||||
.post_builder_blinded_blocks_v2(block)
|
||||
.await
|
||||
.map_err(Error::Builder)
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(()) => {
|
||||
metrics::inc_counter_vec(
|
||||
&metrics::EXECUTION_LAYER_BUILDER_REVEAL_PAYLOAD_OUTCOME,
|
||||
&[metrics::SUCCESS],
|
||||
);
|
||||
info!(
|
||||
relay_response_ms = duration.as_millis(),
|
||||
?block_root,
|
||||
"Successfully submitted blinded block to the builder"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
metrics::inc_counter_vec(
|
||||
&metrics::EXECUTION_LAYER_BUILDER_REVEAL_PAYLOAD_OUTCOME,
|
||||
&[metrics::FAILURE],
|
||||
);
|
||||
error!(
|
||||
info = "this may result in a missed block proposal",
|
||||
error = ?e,
|
||||
relay_response_ms = duration.as_millis(),
|
||||
?block_root,
|
||||
"Failed to submit blinded block to the builder"
|
||||
);
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(Error::NoPayloadBuilder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2040,6 +2145,7 @@ enum InvalidBuilderPayload {
|
||||
payload: u64,
|
||||
expected: u64,
|
||||
},
|
||||
SszTypesError(ssz_types::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for InvalidBuilderPayload {
|
||||
@@ -2081,6 +2187,7 @@ impl fmt::Display for InvalidBuilderPayload {
|
||||
InvalidBuilderPayload::GasLimitMismatch { payload, expected } => {
|
||||
write!(f, "payload gas limit was {} not {}", payload, expected)
|
||||
}
|
||||
Self::SszTypesError(e) => write!(f, "{:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2136,7 +2243,13 @@ fn verify_builder_bid<E: EthSpec>(
|
||||
.withdrawals()
|
||||
.ok()
|
||||
.cloned()
|
||||
.map(|withdrawals| Withdrawals::<E>::from(withdrawals).tree_hash_root());
|
||||
.map(|withdrawals| {
|
||||
Withdrawals::<E>::try_from(withdrawals)
|
||||
.map_err(InvalidBuilderPayload::SszTypesError)
|
||||
.map(|w| w.tree_hash_root())
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
let payload_withdrawals_root = header.withdrawals_root().ok();
|
||||
let expected_gas_limit = proposer_gas_limit
|
||||
.and_then(|target_gas_limit| expected_gas_limit(parent_gas_limit, target_gas_limit, spec));
|
||||
@@ -2263,12 +2376,13 @@ mod test {
|
||||
let (mock, block_hash) = MockExecutionLayer::default_params(runtime.task_executor.clone())
|
||||
.move_to_terminal_block()
|
||||
.produce_forked_pow_block();
|
||||
assert!(mock
|
||||
.el
|
||||
.is_valid_terminal_pow_block_hash(block_hash, &mock.spec)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap());
|
||||
assert!(
|
||||
mock.el
|
||||
.is_valid_terminal_pow_block_hash(block_hash, &mock.spec)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -41,17 +41,17 @@ pub static EXECUTION_LAYER_REQUEST_TIMES: LazyLock<Result<HistogramVec>> = LazyL
|
||||
pub static EXECUTION_LAYER_PAYLOAD_ATTRIBUTES_LOOKAHEAD: LazyLock<Result<Histogram>> =
|
||||
LazyLock::new(|| {
|
||||
try_create_histogram(
|
||||
"execution_layer_payload_attributes_lookahead",
|
||||
"Duration between an fcU call with PayloadAttributes and when the block should be produced",
|
||||
)
|
||||
"execution_layer_payload_attributes_lookahead",
|
||||
"Duration between an fcU call with PayloadAttributes and when the block should be produced",
|
||||
)
|
||||
});
|
||||
pub static EXECUTION_LAYER_PRE_PREPARED_PAYLOAD_ID: LazyLock<Result<IntCounterVec>> = LazyLock::new(
|
||||
|| {
|
||||
try_create_int_counter_vec(
|
||||
"execution_layer_pre_prepared_payload_id",
|
||||
"Indicates hits or misses for already having prepared a payload id before payload production",
|
||||
&["event"]
|
||||
)
|
||||
"execution_layer_pre_prepared_payload_id",
|
||||
"Indicates hits or misses for already having prepared a payload id before payload production",
|
||||
&["event"],
|
||||
)
|
||||
},
|
||||
);
|
||||
pub static EXECUTION_LAYER_GET_PAYLOAD_BODIES_BY_RANGE: LazyLock<Result<Histogram>> =
|
||||
@@ -113,6 +113,32 @@ pub static EXECUTION_LAYER_PAYLOAD_BIDS: LazyLock<Result<IntGaugeVec>> = LazyLoc
|
||||
try_create_int_gauge_vec(
|
||||
"execution_layer_payload_bids",
|
||||
"The gwei bid value of payloads received by local EEs or builders. Only shows values up to i64::MAX.",
|
||||
&["source"]
|
||||
&["source"],
|
||||
)
|
||||
});
|
||||
pub static EXECUTION_LAYER_INFO: LazyLock<Result<IntGaugeVec>> = LazyLock::new(|| {
|
||||
try_create_int_gauge_vec(
|
||||
"execution_layer_info",
|
||||
"The build of the execution layer connected to lighthouse",
|
||||
&["code", "name", "version", "commit"],
|
||||
)
|
||||
});
|
||||
|
||||
pub fn reset_execution_layer_info_gauge() {
|
||||
let _ = EXECUTION_LAYER_INFO.as_ref().map(|gauge| gauge.reset());
|
||||
}
|
||||
|
||||
pub fn expose_execution_layer_info(els: &Vec<crate::ClientVersionV1>) {
|
||||
for el in els {
|
||||
set_gauge_vec(
|
||||
&EXECUTION_LAYER_INFO,
|
||||
&[
|
||||
&el.code.to_string(),
|
||||
&el.name,
|
||||
&el.version,
|
||||
&el.commit.to_string(),
|
||||
],
|
||||
1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,8 +44,7 @@ pub fn process_payload_status(
|
||||
} else {
|
||||
let error = format!(
|
||||
"new_payload: response.status = VALID but invalid latest_valid_hash. Expected({:?}) Found({:?})",
|
||||
head_block_hash,
|
||||
response.latest_valid_hash
|
||||
head_block_hash, response.latest_valid_hash
|
||||
);
|
||||
Err(EngineError::Api {
|
||||
error: ApiError::BadResponse(error),
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
use crate::engine_api::{
|
||||
ExecutionBlock, PayloadAttributes, PayloadId, PayloadStatusV1, PayloadStatusV1Status,
|
||||
json_structures::{
|
||||
JsonForkchoiceUpdatedV1Response, JsonPayloadStatusV1, JsonPayloadStatusV1Status,
|
||||
},
|
||||
ExecutionBlock, PayloadAttributes, PayloadId, PayloadStatusV1, PayloadStatusV1Status,
|
||||
};
|
||||
use crate::engines::ForkchoiceState;
|
||||
use crate::EthersTransaction;
|
||||
use alloy_consensus::TxEnvelope;
|
||||
use alloy_rpc_types_eth::Transaction as AlloyTransaction;
|
||||
use eth2::types::BlobsBundle;
|
||||
use fixed_bytes::FixedBytesExtended;
|
||||
use kzg::{Kzg, KzgCommitment, KzgProof};
|
||||
use parking_lot::Mutex;
|
||||
use rand::{rngs::StdRng, Rng, SeedableRng};
|
||||
use rand::{Rng, SeedableRng, rngs::StdRng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Decode;
|
||||
use ssz_types::VariableList;
|
||||
use std::cmp::max;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tree_hash::TreeHash;
|
||||
@@ -20,7 +23,7 @@ use tree_hash_derive::TreeHash;
|
||||
use types::{
|
||||
Blob, ChainSpec, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadBellatrix,
|
||||
ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadEip7805,
|
||||
ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadHeader, FixedBytesExtended,
|
||||
ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadGloas, ExecutionPayloadHeader,
|
||||
ForkName, Hash256, KzgProofs, Transaction, Transactions, Uint256,
|
||||
};
|
||||
|
||||
@@ -29,7 +32,7 @@ use super::DEFAULT_TERMINAL_BLOCK;
|
||||
const TEST_BLOB_BUNDLE: &[u8] = include_bytes!("fixtures/mainnet/test_blobs_bundle.ssz");
|
||||
const TEST_BLOB_BUNDLE_V2: &[u8] = include_bytes!("fixtures/mainnet/test_blobs_bundle_v2.ssz");
|
||||
|
||||
pub const DEFAULT_GAS_LIMIT: u64 = 30_000_000;
|
||||
pub const DEFAULT_GAS_LIMIT: u64 = 60_000_000;
|
||||
const GAS_USED: u64 = DEFAULT_GAS_LIMIT - 1;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@@ -39,8 +42,8 @@ pub enum Block<E: EthSpec> {
|
||||
PoS(ExecutionPayload<E>),
|
||||
}
|
||||
|
||||
pub fn mock_el_extra_data<E: EthSpec>() -> types::VariableList<u8, E::MaxExtraDataBytes> {
|
||||
"block gen was here".as_bytes().to_vec().into()
|
||||
pub fn mock_el_extra_data<E: EthSpec>() -> VariableList<u8, E::MaxExtraDataBytes> {
|
||||
"block gen was here".as_bytes().to_vec().try_into().unwrap()
|
||||
}
|
||||
|
||||
impl<E: EthSpec> Block<E> {
|
||||
@@ -142,21 +145,22 @@ pub struct ExecutionBlockGenerator<E: EthSpec> {
|
||||
pub pending_payloads: HashMap<ExecutionBlockHash, ExecutionPayload<E>>,
|
||||
pub next_payload_id: u64,
|
||||
pub payload_ids: HashMap<PayloadId, ExecutionPayload<E>>,
|
||||
min_blobs_count: usize,
|
||||
/*
|
||||
* Post-merge fork triggers
|
||||
*/
|
||||
pub shanghai_time: Option<u64>, // capella
|
||||
pub cancun_time: Option<u64>, // deneb
|
||||
pub prague_time: Option<u64>, // electra
|
||||
pub eip7805_time: Option<u64>, // eip7805
|
||||
pub osaka_time: Option<u64>, // fulu
|
||||
pub shanghai_time: Option<u64>, // capella
|
||||
pub cancun_time: Option<u64>, // deneb
|
||||
pub prague_time: Option<u64>, // electra
|
||||
pub osaka_time: Option<u64>, // fulu
|
||||
pub eip7805_time: Option<u64>, // eip7805
|
||||
pub amsterdam_time: Option<u64>, // gloas
|
||||
/*
|
||||
* deneb stuff
|
||||
*/
|
||||
pub blobs_bundles: HashMap<PayloadId, BlobsBundle<E>>,
|
||||
pub kzg: Option<Arc<Kzg>>,
|
||||
rng: Arc<Mutex<StdRng>>,
|
||||
spec: Arc<ChainSpec>,
|
||||
}
|
||||
|
||||
fn make_rng() -> Arc<Mutex<StdRng>> {
|
||||
@@ -176,10 +180,10 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
prague_time: Option<u64>,
|
||||
eip7805_time: Option<u64>,
|
||||
osaka_time: Option<u64>,
|
||||
spec: Arc<ChainSpec>,
|
||||
amsterdam_time: Option<u64>,
|
||||
kzg: Option<Arc<Kzg>>,
|
||||
) -> Self {
|
||||
let mut gen = Self {
|
||||
let mut generator = Self {
|
||||
head_block: <_>::default(),
|
||||
finalized_block_hash: <_>::default(),
|
||||
blocks: <_>::default(),
|
||||
@@ -190,20 +194,21 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
pending_payloads: <_>::default(),
|
||||
next_payload_id: 0,
|
||||
payload_ids: <_>::default(),
|
||||
min_blobs_count: 0,
|
||||
shanghai_time,
|
||||
cancun_time,
|
||||
prague_time,
|
||||
eip7805_time,
|
||||
osaka_time,
|
||||
amsterdam_time,
|
||||
blobs_bundles: <_>::default(),
|
||||
kzg,
|
||||
rng: make_rng(),
|
||||
spec,
|
||||
};
|
||||
|
||||
gen.insert_pow_block(0).unwrap();
|
||||
generator.insert_pow_block(0).unwrap();
|
||||
|
||||
gen
|
||||
generator
|
||||
}
|
||||
|
||||
pub fn latest_block(&self) -> Option<Block<E>> {
|
||||
@@ -244,22 +249,24 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
}
|
||||
|
||||
pub fn get_fork_at_timestamp(&self, timestamp: u64) -> ForkName {
|
||||
match self.osaka_time {
|
||||
Some(fork_time) if timestamp >= fork_time => ForkName::Fulu,
|
||||
_ => match self.eip7805_time {
|
||||
Some(fork_time) if timestamp >= fork_time => ForkName::Eip7805,
|
||||
_ => match self.prague_time {
|
||||
Some(fork_time) if timestamp >= fork_time => ForkName::Electra,
|
||||
_ => match self.cancun_time {
|
||||
Some(fork_time) if timestamp >= fork_time => ForkName::Deneb,
|
||||
_ => match self.shanghai_time {
|
||||
Some(fork_time) if timestamp >= fork_time => ForkName::Capella,
|
||||
_ => ForkName::Bellatrix,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
let forks = [
|
||||
(self.amsterdam_time, ForkName::Gloas),
|
||||
(self.eip7805_time, ForkName::Eip7805),
|
||||
(self.osaka_time, ForkName::Fulu),
|
||||
(self.prague_time, ForkName::Electra),
|
||||
(self.cancun_time, ForkName::Deneb),
|
||||
(self.shanghai_time, ForkName::Capella),
|
||||
];
|
||||
|
||||
for (fork_time, fork_name) in forks {
|
||||
if let Some(time) = fork_time
|
||||
&& timestamp >= time
|
||||
{
|
||||
return fork_name;
|
||||
}
|
||||
}
|
||||
|
||||
ForkName::Bellatrix
|
||||
}
|
||||
|
||||
pub fn execution_block_by_number(&self, number: u64) -> Option<ExecutionBlock> {
|
||||
@@ -324,6 +331,10 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_min_blob_count(&mut self, count: usize) {
|
||||
self.min_blobs_count = count;
|
||||
}
|
||||
|
||||
pub fn insert_pow_block(&mut self, block_number: u64) -> Result<(), String> {
|
||||
if let Some(finalized_block_hash) = self.finalized_block_hash {
|
||||
return Err(format!(
|
||||
@@ -509,10 +520,10 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
// This is meant to cover starting post-merge transition at genesis. Useful for
|
||||
// testing Capella forks and later.
|
||||
let head_block_hash = forkchoice_state.head_block_hash;
|
||||
if let Some(genesis_pow_block) = self.block_by_number(0) {
|
||||
if genesis_pow_block.block_hash() == head_block_hash {
|
||||
self.terminal_block_hash = head_block_hash;
|
||||
}
|
||||
if let Some(genesis_pow_block) = self.block_by_number(0)
|
||||
&& genesis_pow_block.block_hash() == head_block_hash
|
||||
{
|
||||
self.terminal_block_hash = head_block_hash;
|
||||
}
|
||||
|
||||
if let Some(payload) = self.pending_payloads.remove(&head_block_hash) {
|
||||
@@ -595,7 +606,7 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
fee_recipient: pa.suggested_fee_recipient,
|
||||
receipts_root: Hash256::repeat_byte(42),
|
||||
state_root: Hash256::repeat_byte(43),
|
||||
logs_bloom: vec![0; 256].into(),
|
||||
logs_bloom: vec![0; 256].try_into().unwrap(),
|
||||
prev_randao: pa.prev_randao,
|
||||
block_number: parent.block_number() + 1,
|
||||
gas_limit: DEFAULT_GAS_LIMIT,
|
||||
@@ -604,7 +615,7 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
extra_data: mock_el_extra_data::<E>(),
|
||||
base_fee_per_gas: Uint256::from(1u64),
|
||||
block_hash: ExecutionBlockHash::zero(),
|
||||
transactions: vec![].into(),
|
||||
transactions: vec![].try_into().unwrap(),
|
||||
}),
|
||||
PayloadAttributes::V2(pa) => match self.get_fork_at_timestamp(pa.timestamp) {
|
||||
ForkName::Bellatrix => ExecutionPayload::Bellatrix(ExecutionPayloadBellatrix {
|
||||
@@ -612,7 +623,7 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
fee_recipient: pa.suggested_fee_recipient,
|
||||
receipts_root: Hash256::repeat_byte(42),
|
||||
state_root: Hash256::repeat_byte(43),
|
||||
logs_bloom: vec![0; 256].into(),
|
||||
logs_bloom: vec![0; 256].try_into().unwrap(),
|
||||
prev_randao: pa.prev_randao,
|
||||
block_number: parent.block_number() + 1,
|
||||
gas_limit: DEFAULT_GAS_LIMIT,
|
||||
@@ -621,14 +632,14 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
extra_data: mock_el_extra_data::<E>(),
|
||||
base_fee_per_gas: Uint256::from(1u64),
|
||||
block_hash: ExecutionBlockHash::zero(),
|
||||
transactions: vec![].into(),
|
||||
transactions: vec![].try_into().unwrap(),
|
||||
}),
|
||||
ForkName::Capella => ExecutionPayload::Capella(ExecutionPayloadCapella {
|
||||
parent_hash: head_block_hash,
|
||||
fee_recipient: pa.suggested_fee_recipient,
|
||||
receipts_root: Hash256::repeat_byte(42),
|
||||
state_root: Hash256::repeat_byte(43),
|
||||
logs_bloom: vec![0; 256].into(),
|
||||
logs_bloom: vec![0; 256].try_into().unwrap(),
|
||||
prev_randao: pa.prev_randao,
|
||||
block_number: parent.block_number() + 1,
|
||||
gas_limit: DEFAULT_GAS_LIMIT,
|
||||
@@ -637,8 +648,8 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
extra_data: mock_el_extra_data::<E>(),
|
||||
base_fee_per_gas: Uint256::from(1u64),
|
||||
block_hash: ExecutionBlockHash::zero(),
|
||||
transactions: vec![].into(),
|
||||
withdrawals: pa.withdrawals.clone().into(),
|
||||
transactions: vec![].try_into().unwrap(),
|
||||
withdrawals: pa.withdrawals.clone().try_into().unwrap(),
|
||||
}),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
@@ -648,7 +659,7 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
fee_recipient: pa.suggested_fee_recipient,
|
||||
receipts_root: Hash256::repeat_byte(42),
|
||||
state_root: Hash256::repeat_byte(43),
|
||||
logs_bloom: vec![0; 256].into(),
|
||||
logs_bloom: vec![0; 256].try_into().unwrap(),
|
||||
prev_randao: pa.prev_randao,
|
||||
block_number: parent.block_number() + 1,
|
||||
gas_limit: DEFAULT_GAS_LIMIT,
|
||||
@@ -657,8 +668,8 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
extra_data: mock_el_extra_data::<E>(),
|
||||
base_fee_per_gas: Uint256::from(1u64),
|
||||
block_hash: ExecutionBlockHash::zero(),
|
||||
transactions: vec![].into(),
|
||||
withdrawals: pa.withdrawals.clone().into(),
|
||||
transactions: vec![].try_into().unwrap(),
|
||||
withdrawals: pa.withdrawals.clone().try_into().unwrap(),
|
||||
blob_gas_used: 0,
|
||||
excess_blob_gas: 0,
|
||||
}),
|
||||
@@ -667,7 +678,7 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
fee_recipient: pa.suggested_fee_recipient,
|
||||
receipts_root: Hash256::repeat_byte(42),
|
||||
state_root: Hash256::repeat_byte(43),
|
||||
logs_bloom: vec![0; 256].into(),
|
||||
logs_bloom: vec![0; 256].try_into().unwrap(),
|
||||
prev_randao: pa.prev_randao,
|
||||
block_number: parent.block_number() + 1,
|
||||
gas_limit: DEFAULT_GAS_LIMIT,
|
||||
@@ -676,27 +687,8 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
extra_data: mock_el_extra_data::<E>(),
|
||||
base_fee_per_gas: Uint256::from(1u64),
|
||||
block_hash: ExecutionBlockHash::zero(),
|
||||
transactions: vec![].into(),
|
||||
withdrawals: pa.withdrawals.clone().into(),
|
||||
blob_gas_used: 0,
|
||||
excess_blob_gas: 0,
|
||||
}),
|
||||
ForkName::Eip7805 => ExecutionPayload::Eip7805(ExecutionPayloadEip7805 {
|
||||
parent_hash: head_block_hash,
|
||||
fee_recipient: pa.suggested_fee_recipient,
|
||||
receipts_root: Hash256::repeat_byte(42),
|
||||
state_root: Hash256::repeat_byte(43),
|
||||
logs_bloom: vec![0; 256].into(),
|
||||
prev_randao: pa.prev_randao,
|
||||
block_number: parent.block_number() + 1,
|
||||
gas_limit: DEFAULT_GAS_LIMIT,
|
||||
gas_used: GAS_USED,
|
||||
timestamp: pa.timestamp,
|
||||
extra_data: mock_el_extra_data::<E>(),
|
||||
base_fee_per_gas: Uint256::from(1u64),
|
||||
block_hash: ExecutionBlockHash::zero(),
|
||||
transactions: vec![].into(),
|
||||
withdrawals: pa.withdrawals.clone().into(),
|
||||
transactions: vec![].try_into().unwrap(),
|
||||
withdrawals: pa.withdrawals.clone().try_into().unwrap(),
|
||||
blob_gas_used: 0,
|
||||
excess_blob_gas: 0,
|
||||
}),
|
||||
@@ -705,17 +697,55 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
fee_recipient: pa.suggested_fee_recipient,
|
||||
receipts_root: Hash256::repeat_byte(42),
|
||||
state_root: Hash256::repeat_byte(43),
|
||||
logs_bloom: vec![0; 256].into(),
|
||||
logs_bloom: vec![0; 256].try_into().unwrap(),
|
||||
prev_randao: pa.prev_randao,
|
||||
block_number: parent.block_number() + 1,
|
||||
gas_limit: DEFAULT_GAS_LIMIT,
|
||||
gas_used: GAS_USED,
|
||||
timestamp: pa.timestamp,
|
||||
extra_data: "block gen was here".as_bytes().to_vec().into(),
|
||||
extra_data: "block gen was here".as_bytes().to_vec().try_into().unwrap(),
|
||||
base_fee_per_gas: Uint256::from(1u64),
|
||||
block_hash: ExecutionBlockHash::zero(),
|
||||
transactions: vec![].into(),
|
||||
withdrawals: pa.withdrawals.clone().into(),
|
||||
transactions: vec![].try_into().unwrap(),
|
||||
withdrawals: pa.withdrawals.clone().try_into().unwrap(),
|
||||
blob_gas_used: 0,
|
||||
excess_blob_gas: 0,
|
||||
}),
|
||||
ForkName::Eip7805 => ExecutionPayload::Eip7805(ExecutionPayloadEip7805 {
|
||||
parent_hash: head_block_hash,
|
||||
fee_recipient: pa.suggested_fee_recipient,
|
||||
receipts_root: Hash256::repeat_byte(42),
|
||||
state_root: Hash256::repeat_byte(43),
|
||||
logs_bloom: vec![0; 256].try_into().unwrap(),
|
||||
prev_randao: pa.prev_randao,
|
||||
block_number: parent.block_number() + 1,
|
||||
gas_limit: DEFAULT_GAS_LIMIT,
|
||||
gas_used: GAS_USED,
|
||||
timestamp: pa.timestamp,
|
||||
extra_data: mock_el_extra_data::<E>(),
|
||||
base_fee_per_gas: Uint256::from(1u64),
|
||||
block_hash: ExecutionBlockHash::zero(),
|
||||
transactions: vec![].try_into().unwrap(),
|
||||
withdrawals: pa.withdrawals.clone().try_into().unwrap(),
|
||||
blob_gas_used: 0,
|
||||
excess_blob_gas: 0,
|
||||
}),
|
||||
ForkName::Gloas => ExecutionPayload::Gloas(ExecutionPayloadGloas {
|
||||
parent_hash: head_block_hash,
|
||||
fee_recipient: pa.suggested_fee_recipient,
|
||||
receipts_root: Hash256::repeat_byte(42),
|
||||
state_root: Hash256::repeat_byte(43),
|
||||
logs_bloom: vec![0; 256].try_into().unwrap(),
|
||||
prev_randao: pa.prev_randao,
|
||||
block_number: parent.block_number() + 1,
|
||||
gas_limit: DEFAULT_GAS_LIMIT,
|
||||
gas_used: GAS_USED,
|
||||
timestamp: pa.timestamp,
|
||||
extra_data: "block gen was here".as_bytes().to_vec().try_into().unwrap(),
|
||||
base_fee_per_gas: Uint256::from(1u64),
|
||||
block_hash: ExecutionBlockHash::zero(),
|
||||
transactions: vec![].try_into().unwrap(),
|
||||
withdrawals: pa.withdrawals.clone().try_into().unwrap(),
|
||||
blob_gas_used: 0,
|
||||
excess_blob_gas: 0,
|
||||
}),
|
||||
@@ -725,10 +755,11 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
|
||||
let fork_name = execution_payload.fork_name();
|
||||
if fork_name.deneb_enabled() {
|
||||
// get random number between 0 and Max Blobs
|
||||
// get random number between 0 and 1 blobs by default
|
||||
// For tests that need higher blob count, consider adding a `set_max_blob_count` method
|
||||
let mut rng = self.rng.lock();
|
||||
let max_blobs = self.spec.max_blobs_per_block_by_fork(fork_name) as usize;
|
||||
let num_blobs = rng.gen::<usize>() % (max_blobs + 1);
|
||||
let max_blobs = max(1, self.min_blobs_count);
|
||||
let num_blobs = rng.random_range(self.min_blobs_count..=max_blobs);
|
||||
let (bundle, transactions) = generate_blobs(num_blobs, fork_name)?;
|
||||
for tx in Vec::from(transactions) {
|
||||
execution_payload
|
||||
@@ -770,8 +801,8 @@ pub fn load_test_blobs_bundle_v1<E: EthSpec>() -> Result<(KzgCommitment, KzgProo
|
||||
))
|
||||
}
|
||||
|
||||
pub fn load_test_blobs_bundle_v2<E: EthSpec>(
|
||||
) -> Result<(KzgCommitment, KzgProofs<E>, Blob<E>), String> {
|
||||
pub fn load_test_blobs_bundle_v2<E: EthSpec>()
|
||||
-> Result<(KzgCommitment, KzgProofs<E>, Blob<E>), String> {
|
||||
let BlobsBundle::<E> {
|
||||
commitments,
|
||||
proofs,
|
||||
@@ -804,29 +835,30 @@ pub fn generate_blobs<E: EthSpec>(
|
||||
let bundle = if fork_name.fulu_enabled() {
|
||||
let (kzg_commitment, kzg_proofs, blob) = load_test_blobs_bundle_v2::<E>()?;
|
||||
BlobsBundle {
|
||||
commitments: vec![kzg_commitment; n_blobs].into(),
|
||||
commitments: vec![kzg_commitment; n_blobs].try_into().unwrap(),
|
||||
proofs: vec![kzg_proofs.to_vec(); n_blobs]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
blobs: vec![blob; n_blobs].into(),
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
blobs: vec![blob; n_blobs].try_into().unwrap(),
|
||||
}
|
||||
} else {
|
||||
let (kzg_commitment, kzg_proof, blob) = load_test_blobs_bundle_v1::<E>()?;
|
||||
BlobsBundle {
|
||||
commitments: vec![kzg_commitment; n_blobs].into(),
|
||||
proofs: vec![kzg_proof; n_blobs].into(),
|
||||
blobs: vec![blob; n_blobs].into(),
|
||||
commitments: vec![kzg_commitment; n_blobs].try_into().unwrap(),
|
||||
proofs: vec![kzg_proof; n_blobs].try_into().unwrap(),
|
||||
blobs: vec![blob; n_blobs].try_into().unwrap(),
|
||||
}
|
||||
};
|
||||
|
||||
Ok((bundle, transactions.into()))
|
||||
Ok((bundle, transactions.try_into().unwrap()))
|
||||
}
|
||||
|
||||
pub fn static_valid_tx<E: EthSpec>() -> Result<Transaction<E::MaxBytesPerTransaction>, String> {
|
||||
// This is a real transaction hex encoded, but we don't care about the contents of the transaction.
|
||||
let transaction: EthersTransaction = serde_json::from_str(
|
||||
let transaction: AlloyTransaction = serde_json::from_str(
|
||||
r#"{
|
||||
"blockHash":"0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2",
|
||||
"blockNumber":"0x5daf3b",
|
||||
@@ -845,7 +877,8 @@ pub fn static_valid_tx<E: EthSpec>() -> Result<Transaction<E::MaxBytesPerTransac
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
VariableList::new(transaction.rlp().to_vec())
|
||||
|
||||
VariableList::new(alloy_rlp::encode::<TxEnvelope>(transaction.into()).to_vec())
|
||||
.map_err(|e| format!("Failed to convert transaction to SSZ: {:?}", e))
|
||||
}
|
||||
|
||||
@@ -905,6 +938,8 @@ pub fn generate_genesis_header<E: EthSpec>(
|
||||
*header.transactions_root_mut() = empty_transactions_root;
|
||||
Some(header)
|
||||
}
|
||||
// TODO(EIP-7732): need to look into this
|
||||
ForkName::Gloas => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -960,7 +995,7 @@ pub fn generate_pow_block(
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use kzg::{trusted_setup::get_trusted_setup, Bytes48, CellRef, KzgBlobRef, TrustedSetup};
|
||||
use kzg::{Bytes48, CellRef, KzgBlobRef, trusted_setup::get_trusted_setup};
|
||||
use types::{MainnetEthSpec, MinimalEthSpec};
|
||||
|
||||
#[test]
|
||||
@@ -968,7 +1003,6 @@ mod test {
|
||||
const TERMINAL_DIFFICULTY: u64 = 10;
|
||||
const TERMINAL_BLOCK: u64 = 10;
|
||||
const DIFFICULTY_INCREMENT: u64 = 1;
|
||||
let spec = Arc::new(MainnetEthSpec::default_spec());
|
||||
|
||||
let mut generator: ExecutionBlockGenerator<MainnetEthSpec> = ExecutionBlockGenerator::new(
|
||||
Uint256::from(TERMINAL_DIFFICULTY),
|
||||
@@ -979,7 +1013,7 @@ mod test {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
spec,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
@@ -1080,10 +1114,7 @@ mod test {
|
||||
}
|
||||
|
||||
fn load_kzg() -> Result<Kzg, String> {
|
||||
let trusted_setup: TrustedSetup =
|
||||
serde_json::from_reader(get_trusted_setup().as_slice())
|
||||
.map_err(|e| format!("Unable to read trusted setup file: {e:?}"))?;
|
||||
Kzg::new_from_trusted_setup(trusted_setup)
|
||||
Kzg::new_from_trusted_setup(&get_trusted_setup())
|
||||
.map_err(|e| format!("Failed to load trusted setup: {e:?}"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,10 @@ use super::Context;
|
||||
use crate::engine_api::{http::*, *};
|
||||
use crate::json_structures::*;
|
||||
use crate::test_utils::{DEFAULT_CLIENT_VERSION, DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI};
|
||||
use crate::EthersTransaction;
|
||||
use crate::Transactions;
|
||||
use serde::{de::DeserializeOwned, Deserialize};
|
||||
use serde::{Deserialize, de::DeserializeOwned};
|
||||
use serde_json::Value as JsonValue;
|
||||
use std::sync::Arc;
|
||||
use types::Transaction;
|
||||
|
||||
pub const GENERIC_ERROR_CODE: i64 = -1234;
|
||||
pub const BAD_PARAMS_ERROR_CODE: i64 = -32602;
|
||||
@@ -101,35 +100,37 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
ENGINE_NEW_PAYLOAD_V1
|
||||
| ENGINE_NEW_PAYLOAD_V2
|
||||
| ENGINE_NEW_PAYLOAD_V3
|
||||
| ENGINE_NEW_PAYLOAD_V4
|
||||
| ENGINE_NEW_PAYLOAD_V5 => {
|
||||
| ENGINE_NEW_PAYLOAD_V4 => {
|
||||
let request = match method {
|
||||
ENGINE_NEW_PAYLOAD_V1 => JsonExecutionPayload::V1(
|
||||
get_param::<JsonExecutionPayloadV1<E>>(params, 0)
|
||||
ENGINE_NEW_PAYLOAD_V1 => JsonExecutionPayload::Bellatrix(
|
||||
get_param::<JsonExecutionPayloadBellatrix<E>>(params, 0)
|
||||
.map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?,
|
||||
),
|
||||
ENGINE_NEW_PAYLOAD_V2 => get_param::<JsonExecutionPayloadV2<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::V2(jep))
|
||||
ENGINE_NEW_PAYLOAD_V2 => get_param::<JsonExecutionPayloadCapella<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::Capella(jep))
|
||||
.or_else(|_| {
|
||||
get_param::<JsonExecutionPayloadV1<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::V1(jep))
|
||||
get_param::<JsonExecutionPayloadBellatrix<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::Bellatrix(jep))
|
||||
})
|
||||
.map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?,
|
||||
// From v3 onwards, we use the newPayload version only for the corresponding
|
||||
// ExecutionPayload version. So we return an error instead of falling back to
|
||||
// older versions of newPayload
|
||||
ENGINE_NEW_PAYLOAD_V3 => get_param::<JsonExecutionPayloadV3<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::V3(jep))
|
||||
ENGINE_NEW_PAYLOAD_V3 => get_param::<JsonExecutionPayloadDeneb<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::Deneb(jep))
|
||||
.map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?,
|
||||
ENGINE_NEW_PAYLOAD_V4 => get_param::<JsonExecutionPayloadV4<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::V4(jep))
|
||||
.map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?,
|
||||
ENGINE_NEW_PAYLOAD_V5 => get_param::<JsonExecutionPayloadV5<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::V5(jep))
|
||||
.map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?,
|
||||
ENGINE_NEW_PAYLOAD_V5 => get_param::<JsonExecutionPayloadV5<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::V5(jep))
|
||||
ENGINE_NEW_PAYLOAD_V4 => get_param::<JsonExecutionPayloadGloas<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::Gloas(jep))
|
||||
.or_else(|_| {
|
||||
get_param::<JsonExecutionPayloadFulu<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::Fulu(jep))
|
||||
})
|
||||
.or_else(|_| {
|
||||
get_param::<JsonExecutionPayloadElectra<E>>(params, 0)
|
||||
.map(|jep| JsonExecutionPayload::Electra(jep))
|
||||
})
|
||||
.map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?,
|
||||
// TODO(EIP7805) fix
|
||||
// ENGINE_NEW_PAYLOAD_V5 => get_param::<JsonExecutionPayloadV5<E>>(params, 0)
|
||||
// .map(|jep| JsonExecutionPayload::V5(jep))
|
||||
// .map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
@@ -140,10 +141,10 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
// validate method called correctly according to fork time
|
||||
match fork {
|
||||
ForkName::Bellatrix => {
|
||||
if matches!(request, JsonExecutionPayload::V2(_)) {
|
||||
if matches!(request, JsonExecutionPayload::Capella(_)) {
|
||||
return Err((
|
||||
format!(
|
||||
"{} called with `ExecutionPayloadV2` before Capella fork!",
|
||||
"{} called with `ExecutionPayloadCapella` before Capella fork!",
|
||||
method
|
||||
),
|
||||
GENERIC_ERROR_CODE,
|
||||
@@ -157,10 +158,10 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
GENERIC_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
if matches!(request, JsonExecutionPayload::V1(_)) {
|
||||
if matches!(request, JsonExecutionPayload::Bellatrix(_)) {
|
||||
return Err((
|
||||
format!(
|
||||
"{} called with `ExecutionPayloadV1` after Capella fork!",
|
||||
"{} called with `ExecutionPayloadBellatrix` after Capella fork!",
|
||||
method
|
||||
),
|
||||
GENERIC_ERROR_CODE,
|
||||
@@ -174,7 +175,7 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
GENERIC_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
if matches!(request, JsonExecutionPayload::V1(_)) {
|
||||
if matches!(request, JsonExecutionPayload::Bellatrix(_)) {
|
||||
return Err((
|
||||
format!(
|
||||
"{} called with `ExecutionPayloadV1` after Deneb fork!",
|
||||
@@ -183,7 +184,7 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
GENERIC_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
if matches!(request, JsonExecutionPayload::V2(_)) {
|
||||
if matches!(request, JsonExecutionPayload::Capella(_)) {
|
||||
return Err((
|
||||
format!(
|
||||
"{} called with `ExecutionPayloadV2` after Deneb fork!",
|
||||
@@ -193,7 +194,7 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
));
|
||||
}
|
||||
}
|
||||
ForkName::Electra => {
|
||||
ForkName::Electra | ForkName::Fulu | ForkName::Eip7805 | ForkName::Gloas => {
|
||||
if method == ENGINE_NEW_PAYLOAD_V1
|
||||
|| method == ENGINE_NEW_PAYLOAD_V2
|
||||
|| method == ENGINE_NEW_PAYLOAD_V3
|
||||
@@ -203,122 +204,34 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
GENERIC_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
if matches!(request, JsonExecutionPayload::V1(_)) {
|
||||
if matches!(request, JsonExecutionPayload::Bellatrix(_)) {
|
||||
return Err((
|
||||
format!(
|
||||
"{} called with `ExecutionPayloadV1` after Electra fork!",
|
||||
"{} called with `ExecutionPayloadBellatrix after Electra fork!",
|
||||
method
|
||||
),
|
||||
GENERIC_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
if matches!(request, JsonExecutionPayload::V2(_)) {
|
||||
if matches!(request, JsonExecutionPayload::Capella(_)) {
|
||||
return Err((
|
||||
format!(
|
||||
"{} called with `ExecutionPayloadV2` after Electra fork!",
|
||||
"{} called with `ExecutionPayloadCapella` after Electra fork!",
|
||||
method
|
||||
),
|
||||
GENERIC_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
if matches!(request, JsonExecutionPayload::V3(_)) {
|
||||
if matches!(request, JsonExecutionPayload::Deneb(_)) {
|
||||
return Err((
|
||||
format!(
|
||||
"{} called with `ExecutionPayloadV3` after Electra fork!",
|
||||
"{} called with `ExecutionPayloadDeneb` after Electra fork!",
|
||||
method
|
||||
),
|
||||
GENERIC_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
}
|
||||
ForkName::Eip7805 => {
|
||||
if method == ENGINE_NEW_PAYLOAD_V1
|
||||
|| method == ENGINE_NEW_PAYLOAD_V2
|
||||
|| method == ENGINE_NEW_PAYLOAD_V3
|
||||
{
|
||||
return Err((
|
||||
format!("{} called after Electra fork!", method),
|
||||
GENERIC_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
if matches!(request, JsonExecutionPayload::V1(_)) {
|
||||
return Err((
|
||||
format!(
|
||||
"{} called with `ExecutionPayloadV1` after Electra fork!",
|
||||
method
|
||||
),
|
||||
GENERIC_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
if matches!(request, JsonExecutionPayload::V2(_)) {
|
||||
return Err((
|
||||
format!(
|
||||
"{} called with `ExecutionPayloadV2` after Eip7805 fork!",
|
||||
method
|
||||
),
|
||||
GENERIC_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
if matches!(request, JsonExecutionPayload::V3(_)) {
|
||||
return Err((
|
||||
format!(
|
||||
"{} called with `ExecutionPayloadV3` after Eip7805 fork!",
|
||||
method
|
||||
),
|
||||
GENERIC_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
}
|
||||
ForkName::Fulu => {
|
||||
if method == ENGINE_NEW_PAYLOAD_V1
|
||||
|| method == ENGINE_NEW_PAYLOAD_V2
|
||||
|| method == ENGINE_NEW_PAYLOAD_V3
|
||||
// TODO(fulu): Uncomment this once v5 method is ready for Fulu
|
||||
// || method == ENGINE_NEW_PAYLOAD_V4
|
||||
{
|
||||
return Err((
|
||||
format!("{} called after Fulu fork!", method),
|
||||
GENERIC_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
if matches!(request, JsonExecutionPayload::V1(_)) {
|
||||
return Err((
|
||||
format!(
|
||||
"{} called with `ExecutionPayloadV1` after Fulu fork!",
|
||||
method
|
||||
),
|
||||
GENERIC_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
if matches!(request, JsonExecutionPayload::V2(_)) {
|
||||
return Err((
|
||||
format!(
|
||||
"{} called with `ExecutionPayloadV2` after Fulu fork!",
|
||||
method
|
||||
),
|
||||
GENERIC_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
if matches!(request, JsonExecutionPayload::V3(_)) {
|
||||
return Err((
|
||||
format!(
|
||||
"{} called with `ExecutionPayloadV3` 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!(),
|
||||
};
|
||||
|
||||
@@ -344,7 +257,7 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
Some(
|
||||
ctx.execution_block_generator
|
||||
.write()
|
||||
.new_payload(request.into()),
|
||||
.new_payload(request.try_into().unwrap()),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
@@ -417,23 +330,7 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
));
|
||||
}
|
||||
|
||||
// validate method called correctly according to prague fork time
|
||||
if ctx
|
||||
.execution_block_generator
|
||||
.read()
|
||||
.get_fork_at_timestamp(response.timestamp())
|
||||
== ForkName::Eip7805
|
||||
&& (method == ENGINE_GET_PAYLOAD_V1
|
||||
|| method == ENGINE_GET_PAYLOAD_V2
|
||||
|| method == ENGINE_GET_PAYLOAD_V3)
|
||||
{
|
||||
return Err((
|
||||
format!("{} called after EIP7805 fork!", method),
|
||||
FORK_REQUEST_MISMATCH_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
|
||||
// validate method called correctly according to fulu fork time
|
||||
// validate method called correctly according to osaka fork time
|
||||
if ctx
|
||||
.execution_block_generator
|
||||
.read()
|
||||
@@ -449,98 +346,141 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
));
|
||||
}
|
||||
|
||||
// validate method called correctly according to amsterdam fork time
|
||||
if ctx
|
||||
.execution_block_generator
|
||||
.read()
|
||||
.get_fork_at_timestamp(response.timestamp())
|
||||
== ForkName::Gloas
|
||||
&& (method == ENGINE_GET_PAYLOAD_V1
|
||||
|| method == ENGINE_GET_PAYLOAD_V2
|
||||
|| method == ENGINE_GET_PAYLOAD_V3
|
||||
|| method == ENGINE_GET_PAYLOAD_V4)
|
||||
{
|
||||
return Err((
|
||||
format!("{} called after Gloas fork!", method),
|
||||
FORK_REQUEST_MISMATCH_ERROR_CODE,
|
||||
));
|
||||
}
|
||||
|
||||
match method {
|
||||
ENGINE_GET_PAYLOAD_V1 => {
|
||||
Ok(serde_json::to_value(JsonExecutionPayload::from(response)).unwrap())
|
||||
ENGINE_GET_PAYLOAD_V1 => Ok(serde_json::to_value(
|
||||
JsonExecutionPayload::try_from(response).unwrap(),
|
||||
)
|
||||
.unwrap()),
|
||||
ENGINE_GET_PAYLOAD_V2 => {
|
||||
Ok(match JsonExecutionPayload::try_from(response).unwrap() {
|
||||
JsonExecutionPayload::Bellatrix(execution_payload) => {
|
||||
serde_json::to_value(JsonGetPayloadResponseBellatrix {
|
||||
execution_payload,
|
||||
block_value: Uint256::from(DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
JsonExecutionPayload::Capella(execution_payload) => {
|
||||
serde_json::to_value(JsonGetPayloadResponseCapella {
|
||||
execution_payload,
|
||||
block_value: Uint256::from(DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
ENGINE_GET_PAYLOAD_V2 => Ok(match JsonExecutionPayload::from(response) {
|
||||
JsonExecutionPayload::V1(execution_payload) => {
|
||||
serde_json::to_value(JsonGetPayloadResponseV1 {
|
||||
execution_payload,
|
||||
block_value: Uint256::from(DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
JsonExecutionPayload::V2(execution_payload) => {
|
||||
serde_json::to_value(JsonGetPayloadResponseV2 {
|
||||
execution_payload,
|
||||
block_value: Uint256::from(DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}),
|
||||
// From v3 onwards, we use the getPayload version only for the corresponding
|
||||
// ExecutionPayload version. So we return an error if the ExecutionPayload version
|
||||
// we get does not correspond to the getPayload version.
|
||||
ENGINE_GET_PAYLOAD_V3 => Ok(match JsonExecutionPayload::from(response) {
|
||||
JsonExecutionPayload::V3(execution_payload) => {
|
||||
serde_json::to_value(JsonGetPayloadResponseV3 {
|
||||
execution_payload,
|
||||
block_value: Uint256::from(DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI),
|
||||
blobs_bundle: maybe_blobs
|
||||
.ok_or((
|
||||
"No blobs returned despite V3 Payload".to_string(),
|
||||
GENERIC_ERROR_CODE,
|
||||
))?
|
||||
.into(),
|
||||
should_override_builder: false,
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}),
|
||||
ENGINE_GET_PAYLOAD_V4 => Ok(match JsonExecutionPayload::from(response) {
|
||||
JsonExecutionPayload::V4(execution_payload) => {
|
||||
serde_json::to_value(JsonGetPayloadResponseV4 {
|
||||
execution_payload,
|
||||
block_value: Uint256::from(DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI),
|
||||
blobs_bundle: maybe_blobs
|
||||
.ok_or((
|
||||
"No blobs returned despite V4 Payload".to_string(),
|
||||
GENERIC_ERROR_CODE,
|
||||
))?
|
||||
.into(),
|
||||
should_override_builder: false,
|
||||
// TODO(electra): add EL requests in mock el
|
||||
execution_requests: Default::default(),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
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,
|
||||
// TODO(electra): add EL requests in mock el
|
||||
execution_requests: Default::default(),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
JsonExecutionPayload::V6(execution_payload) => {
|
||||
serde_json::to_value(JsonGetPayloadResponseV6 {
|
||||
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,
|
||||
// TODO(electra): add EL requests in mock el
|
||||
execution_requests: Default::default(),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}),
|
||||
ENGINE_GET_PAYLOAD_V3 => {
|
||||
Ok(match JsonExecutionPayload::try_from(response).unwrap() {
|
||||
JsonExecutionPayload::Deneb(execution_payload) => {
|
||||
serde_json::to_value(JsonGetPayloadResponseDeneb {
|
||||
execution_payload,
|
||||
block_value: Uint256::from(DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI),
|
||||
blobs_bundle: maybe_blobs
|
||||
.ok_or((
|
||||
"No blobs returned despite V3 Payload".to_string(),
|
||||
GENERIC_ERROR_CODE,
|
||||
))?
|
||||
.into(),
|
||||
should_override_builder: false,
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
ENGINE_GET_PAYLOAD_V4 => {
|
||||
Ok(match JsonExecutionPayload::try_from(response).unwrap() {
|
||||
JsonExecutionPayload::Electra(execution_payload) => {
|
||||
serde_json::to_value(JsonGetPayloadResponseElectra {
|
||||
execution_payload,
|
||||
block_value: Uint256::from(DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI),
|
||||
blobs_bundle: maybe_blobs
|
||||
.ok_or((
|
||||
"No blobs returned despite V4 Payload".to_string(),
|
||||
GENERIC_ERROR_CODE,
|
||||
))?
|
||||
.into(),
|
||||
should_override_builder: false,
|
||||
// TODO(electra): add EL requests in mock el
|
||||
execution_requests: Default::default(),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
/* TODO(EIP7805) new payload handling
|
||||
ENGINE_GET_PAYLOAD_V5 => {
|
||||
Ok(match JsonExecutionPayload::try_from(response).unwrap() {
|
||||
JsonExecutionPayload::Fulu(execution_payload) => {
|
||||
serde_json::to_value(JsonGetPayloadResponseFulu {
|
||||
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()
|
||||
}
|
||||
JsonExecutionPayload::Eip7805(execution_payload) => {
|
||||
serde_json::to_value(JsonGetPayloadResponseEip7805 {
|
||||
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()
|
||||
}
|
||||
JsonExecutionPayload::Gloas(execution_payload) => {
|
||||
serde_json::to_value(JsonGetPayloadResponseGloas {
|
||||
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!(),
|
||||
})
|
||||
}*/
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -575,7 +515,8 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
ForkName::Capella
|
||||
| ForkName::Deneb
|
||||
| ForkName::Electra
|
||||
| ForkName::Fulu => {
|
||||
| ForkName::Fulu
|
||||
| ForkName::Gloas => {
|
||||
get_param::<Option<JsonPayloadAttributesV2>>(params, 1)
|
||||
.map(|opt| opt.map(JsonPayloadAttributes::V2))
|
||||
.transpose()
|
||||
@@ -639,7 +580,11 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
));
|
||||
}
|
||||
}
|
||||
ForkName::Deneb | ForkName::Electra | ForkName::Eip7805 | ForkName::Fulu => {
|
||||
ForkName::Deneb
|
||||
| ForkName::Electra
|
||||
| ForkName::Fulu
|
||||
| ForkName::Eip7805
|
||||
| ForkName::Gloas => {
|
||||
if method == ENGINE_FORKCHOICE_UPDATED_V1 {
|
||||
return Err((
|
||||
format!("{} called after Deneb fork!", method),
|
||||
@@ -731,7 +676,8 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
transactions: payload.transactions().clone(),
|
||||
withdrawals: payload.withdrawals().ok().cloned(),
|
||||
};
|
||||
let json_payload_body = JsonExecutionPayloadBodyV1::from(payload_body);
|
||||
let json_payload_body: JsonExecutionPayloadBodyV1<E> =
|
||||
payload_body.try_into().unwrap();
|
||||
response.push(Some(json_payload_body));
|
||||
}
|
||||
None => response.push(None),
|
||||
@@ -742,8 +688,7 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
}
|
||||
ENGINE_GET_INCLUSION_LIST_V1 => {
|
||||
// This is a real transaction hex encoded, but we don't care about the contents of the transaction.
|
||||
let transaction: EthersTransaction = serde_json::from_str(
|
||||
r#"{
|
||||
let transaction: Transaction<<E as EthSpec>::MaxBytesPerTransaction> = serde_json::from_str(r#"{
|
||||
"blockHash":"0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2",
|
||||
"blockNumber":"0x5daf3b",
|
||||
"from":"0xa7d9ddbe1f17865597fbd27ec712455208b6b76d",
|
||||
@@ -761,7 +706,7 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
let tx_list: Transactions<E> = vec![transaction.rlp().to_vec().into()].into();
|
||||
let tx_list: Transactions<E> = vec![transaction].try_into().unwrap();
|
||||
|
||||
Ok(serde_json::to_value(tx_list).unwrap())
|
||||
}
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
use crate::test_utils::{DEFAULT_BUILDER_PAYLOAD_VALUE_WEI, DEFAULT_JWT_SECRET};
|
||||
use crate::{Config, ExecutionLayer, PayloadAttributes, PayloadParameters};
|
||||
use bls::{PublicKeyBytes, SecretKey, Signature};
|
||||
use bytes::Bytes;
|
||||
use eth2::beacon_response::ForkVersionedResponse;
|
||||
use eth2::types::PublishBlockRequest;
|
||||
use eth2::types::{
|
||||
BlobsBundle, BlockId, BroadcastValidation, EventKind, EventTopic, FullPayloadContents,
|
||||
ProposerData, StateId, ValidatorId,
|
||||
BlobsBundle, BlockId, BroadcastValidation, EndpointVersion, EventKind, EventTopic,
|
||||
FullPayloadContents, ProposerData, StateId, ValidatorId,
|
||||
};
|
||||
use eth2::{
|
||||
BeaconNodeHttpClient, Timeouts, CONSENSUS_VERSION_HEADER, CONTENT_TYPE_HEADER,
|
||||
SSZ_CONTENT_TYPE_HEADER,
|
||||
BeaconNodeHttpClient, CONSENSUS_VERSION_HEADER, CONTENT_TYPE_HEADER, SSZ_CONTENT_TYPE_HEADER,
|
||||
Timeouts,
|
||||
};
|
||||
use fork_choice::ForkchoiceUpdateParameters;
|
||||
use parking_lot::RwLock;
|
||||
use sensitive_url::SensitiveUrl;
|
||||
use ssz::Encode;
|
||||
use ssz_types::VariableList;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
use std::future::Future;
|
||||
@@ -25,22 +28,21 @@ use tempfile::NamedTempFile;
|
||||
use tokio_stream::StreamExt;
|
||||
use tracing::{debug, error, info, warn};
|
||||
use tree_hash::TreeHash;
|
||||
use types::ExecutionBlockHash;
|
||||
use types::builder_bid::{
|
||||
BuilderBid, BuilderBidBellatrix, BuilderBidCapella, BuilderBidDeneb, BuilderBidEip7805,
|
||||
BuilderBidElectra, BuilderBidFulu, SignedBuilderBid,
|
||||
};
|
||||
use types::{
|
||||
Address, BeaconState, ChainSpec, Epoch, EthSpec, ExecPayload, ExecutionPayload,
|
||||
ExecutionPayloadHeaderRefMut, ExecutionRequests, ForkName, ForkVersionDecode,
|
||||
ForkVersionedResponse, Hash256, PublicKeyBytes, Signature, SignedBlindedBeaconBlock,
|
||||
SignedRoot, SignedValidatorRegistrationData, Slot, Uint256,
|
||||
ExecutionPayloadHeaderRefMut, ExecutionRequests, ForkName, ForkVersionDecode, Hash256,
|
||||
SignedBlindedBeaconBlock, SignedRoot, SignedValidatorRegistrationData, Slot, Uint256,
|
||||
};
|
||||
use types::{ExecutionBlockHash, SecretKey};
|
||||
use warp::reply::{self, Reply};
|
||||
use warp::{Filter, Rejection};
|
||||
|
||||
pub const DEFAULT_FEE_RECIPIENT: Address = Address::repeat_byte(42);
|
||||
pub const DEFAULT_GAS_LIMIT: u64 = 30_000_000;
|
||||
pub const DEFAULT_GAS_LIMIT: u64 = 60_000_000;
|
||||
pub const DEFAULT_BUILDER_PRIVATE_KEY: &str =
|
||||
"607a11b45a7219cc61a3d9c5fd08c7eebd602a6a19a977f8d3771d5711a550f2";
|
||||
|
||||
@@ -71,8 +73,8 @@ impl Operation {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mock_builder_extra_data<E: EthSpec>() -> types::VariableList<u8, E::MaxExtraDataBytes> {
|
||||
"mock_builder".as_bytes().to_vec().into()
|
||||
pub fn mock_builder_extra_data<E: EthSpec>() -> VariableList<u8, E::MaxExtraDataBytes> {
|
||||
"mock_builder".as_bytes().to_vec().try_into().unwrap()
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -332,6 +334,10 @@ pub struct MockBuilder<E: EthSpec> {
|
||||
payload_id_cache: Arc<RwLock<HashMap<ExecutionBlockHash, PayloadParametersCloned>>>,
|
||||
/// If set to `true`, sets the bid returned by `get_header` to Uint256::MAX
|
||||
max_bid: bool,
|
||||
/// Broadcast the full block with payload to the attached beacon node (simulating the relay).
|
||||
///
|
||||
/// Turning this off is useful for testing.
|
||||
broadcast_to_bn: bool,
|
||||
/// A cache that stores the proposers index for a given epoch
|
||||
proposers_cache: Arc<RwLock<HashMap<Epoch, Vec<ProposerData>>>>,
|
||||
}
|
||||
@@ -340,6 +346,9 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
pub fn new_for_testing(
|
||||
mock_el_url: SensitiveUrl,
|
||||
beacon_url: SensitiveUrl,
|
||||
validate_pubkey: bool,
|
||||
apply_operations: bool,
|
||||
broadcast_to_bn: bool,
|
||||
spec: Arc<ChainSpec>,
|
||||
executor: TaskExecutor,
|
||||
) -> (Self, (SocketAddr, impl Future<Output = ()>)) {
|
||||
@@ -357,12 +366,15 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
|
||||
let el = ExecutionLayer::from_config(config, executor.clone()).unwrap();
|
||||
|
||||
let max_bid = false;
|
||||
|
||||
let builder = MockBuilder::new(
|
||||
el,
|
||||
BeaconNodeHttpClient::new(beacon_url, Timeouts::set_all(Duration::from_secs(1))),
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
validate_pubkey,
|
||||
apply_operations,
|
||||
broadcast_to_bn,
|
||||
max_bid,
|
||||
spec,
|
||||
None,
|
||||
);
|
||||
@@ -378,6 +390,7 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
beacon_client: BeaconNodeHttpClient,
|
||||
validate_pubkey: bool,
|
||||
apply_operations: bool,
|
||||
broadcast_to_bn: bool,
|
||||
max_bid: bool,
|
||||
spec: Arc<ChainSpec>,
|
||||
sk: Option<&[u8]>,
|
||||
@@ -407,6 +420,7 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
proposers_cache: Arc::new(RwLock::new(HashMap::new())),
|
||||
apply_operations,
|
||||
max_bid,
|
||||
broadcast_to_bn,
|
||||
genesis_time: None,
|
||||
}
|
||||
}
|
||||
@@ -485,15 +499,25 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
SignedBlindedBeaconBlock::Fulu(block) => {
|
||||
block.message.body.execution_payload.tree_hash_root()
|
||||
}
|
||||
SignedBlindedBeaconBlock::Gloas(_) => {
|
||||
// TODO(EIP7732) Check if this is how we want to do error handling for gloas
|
||||
return Err("invalid fork".to_string());
|
||||
}
|
||||
};
|
||||
let block_hash = block
|
||||
.message()
|
||||
.body()
|
||||
.execution_payload()
|
||||
.unwrap()
|
||||
.block_hash();
|
||||
info!(
|
||||
block_hash = %root,
|
||||
execution_payload_root = %root,
|
||||
?block_hash,
|
||||
"Submitting blinded beacon block to builder"
|
||||
);
|
||||
let payload = self
|
||||
.el
|
||||
.get_payload_by_root(&root)
|
||||
.ok_or_else(|| "missing payload for tx root".to_string())?;
|
||||
let payload = self.el.get_payload_by_root(&root).ok_or_else(|| {
|
||||
format!("missing payload for root: {root:?}, block_hash: {block_hash:?}",)
|
||||
})?;
|
||||
|
||||
let (payload, blobs) = payload.deconstruct();
|
||||
let full_block = block
|
||||
@@ -502,16 +526,28 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
debug!(
|
||||
txs_count = payload.transactions().len(),
|
||||
blob_count = blobs.as_ref().map(|b| b.commitments.len()),
|
||||
"Got full payload, sending to local beacon node for propagation"
|
||||
"Got full payload"
|
||||
);
|
||||
let publish_block_request = PublishBlockRequest::new(
|
||||
Arc::new(full_block),
|
||||
blobs.clone().map(|b| (b.proofs, b.blobs)),
|
||||
);
|
||||
self.beacon_client
|
||||
.post_beacon_blocks_v2(&publish_block_request, Some(BroadcastValidation::Gossip))
|
||||
.await
|
||||
.map_err(|e| format!("Failed to post blinded block {:?}", e))?;
|
||||
if self.broadcast_to_bn {
|
||||
debug!(
|
||||
block_hash = ?payload.block_hash(),
|
||||
"Broadcasting builder block to BN"
|
||||
);
|
||||
let publish_block_request = PublishBlockRequest::new(
|
||||
Arc::new(full_block),
|
||||
blobs.clone().map(|b| (b.proofs, b.blobs)),
|
||||
);
|
||||
self.beacon_client
|
||||
.post_beacon_blocks_v2(
|
||||
&publish_block_request,
|
||||
Some(BroadcastValidation::ConsensusAndEquivocation),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
// XXX: this should really be a 400 but warp makes that annoyingly difficult
|
||||
format!("Failed to post blinded block {e:?}")
|
||||
})?;
|
||||
}
|
||||
Ok(FullPayloadContents::new(payload, blobs))
|
||||
}
|
||||
|
||||
@@ -542,16 +578,29 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
info!("Got payload params");
|
||||
|
||||
let fork = self.fork_name_at_slot(slot);
|
||||
|
||||
let payload_response_type = self
|
||||
.el
|
||||
.get_full_payload_caching(PayloadParameters {
|
||||
parent_hash: payload_parameters.parent_hash,
|
||||
parent_gas_limit: payload_parameters.parent_gas_limit,
|
||||
proposer_gas_limit: payload_parameters.proposer_gas_limit,
|
||||
payload_attributes: &payload_parameters.payload_attributes,
|
||||
forkchoice_update_params: &payload_parameters.forkchoice_update_params,
|
||||
current_fork: payload_parameters.current_fork,
|
||||
})
|
||||
.get_full_payload_with(
|
||||
PayloadParameters {
|
||||
parent_hash: payload_parameters.parent_hash,
|
||||
parent_gas_limit: payload_parameters.parent_gas_limit,
|
||||
proposer_gas_limit: payload_parameters.proposer_gas_limit,
|
||||
payload_attributes: &payload_parameters.payload_attributes,
|
||||
forkchoice_update_params: &payload_parameters.forkchoice_update_params,
|
||||
current_fork: payload_parameters.current_fork,
|
||||
},
|
||||
// If apply_operations is set, do NOT cache the payload at this point, we are about
|
||||
// to mutate it and it would be incorrect to cache the unmutated payload.
|
||||
//
|
||||
// This is a flaw in apply_operations generally, if you want the mock builder to
|
||||
// actually return payloads then this option should be turned off.
|
||||
if self.apply_operations {
|
||||
|_, _| None
|
||||
} else {
|
||||
ExecutionLayer::cache_payload
|
||||
},
|
||||
)
|
||||
.await
|
||||
.map_err(|e| format!("couldn't get payload {:?}", e))?;
|
||||
|
||||
@@ -568,6 +617,10 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
) = payload_response.into();
|
||||
|
||||
match fork {
|
||||
ForkName::Gloas => {
|
||||
// TODO(EIP7732) Check if this is how we want to do error handling for gloas
|
||||
return Err("invalid fork".to_string());
|
||||
}
|
||||
ForkName::Fulu => BuilderBid::Fulu(BuilderBidFulu {
|
||||
header: payload
|
||||
.as_fulu()
|
||||
@@ -799,7 +852,7 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
.beacon_client
|
||||
.get_beacon_blocks::<E>(BlockId::Finalized)
|
||||
.await
|
||||
.map_err(|_| "couldn't get finalized block".to_string())?
|
||||
.map_err(|e| format!("couldn't get finalized block: {e:?}"))?
|
||||
.ok_or_else(|| "missing finalized block".to_string())?
|
||||
.data()
|
||||
.message()
|
||||
@@ -812,7 +865,7 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
.beacon_client
|
||||
.get_beacon_blocks::<E>(BlockId::Justified)
|
||||
.await
|
||||
.map_err(|_| "couldn't get justified block".to_string())?
|
||||
.map_err(|e| format!("couldn't get justified block: {e:?}"))?
|
||||
.ok_or_else(|| "missing justified block".to_string())?
|
||||
.data()
|
||||
.message()
|
||||
@@ -885,15 +938,17 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
expected_withdrawals,
|
||||
None,
|
||||
),
|
||||
ForkName::Deneb | ForkName::Electra | ForkName::Eip7805 | ForkName::Fulu => {
|
||||
PayloadAttributes::new(
|
||||
timestamp,
|
||||
*prev_randao,
|
||||
fee_recipient,
|
||||
expected_withdrawals,
|
||||
Some(head_block_root),
|
||||
)
|
||||
}
|
||||
ForkName::Deneb
|
||||
| ForkName::Electra
|
||||
| ForkName::Fulu
|
||||
| ForkName::Eip7805
|
||||
| ForkName::Gloas => PayloadAttributes::new(
|
||||
timestamp,
|
||||
*prev_randao,
|
||||
fee_recipient,
|
||||
expected_withdrawals,
|
||||
Some(head_block_root),
|
||||
),
|
||||
ForkName::Base | ForkName::Altair => {
|
||||
return Err("invalid fork".to_string());
|
||||
}
|
||||
@@ -958,11 +1013,21 @@ pub fn serve<E: EthSpec>(
|
||||
let inner_ctx = builder.clone();
|
||||
let ctx_filter = warp::any().map(move || inner_ctx.clone());
|
||||
|
||||
let prefix = warp::path("eth")
|
||||
let prefix_v1 = warp::path("eth")
|
||||
.and(warp::path("v1"))
|
||||
.and(warp::path("builder"));
|
||||
|
||||
let validators = prefix
|
||||
let prefix_either = warp::path("eth")
|
||||
.and(
|
||||
warp::path::param::<EndpointVersion>().or_else(|_| async move {
|
||||
Err(warp::reject::custom(Custom(
|
||||
"Invalid EndpointVersion".to_string(),
|
||||
)))
|
||||
}),
|
||||
)
|
||||
.and(warp::path("builder"));
|
||||
|
||||
let validators = prefix_v1
|
||||
.and(warp::path("validators"))
|
||||
.and(warp::body::json())
|
||||
.and(warp::path::end())
|
||||
@@ -974,61 +1039,89 @@ pub fn serve<E: EthSpec>(
|
||||
.register_validators(registrations)
|
||||
.await
|
||||
.map_err(|e| warp::reject::custom(Custom(e)))?;
|
||||
Ok::<_, Rejection>(warp::reply())
|
||||
},
|
||||
)
|
||||
.boxed();
|
||||
|
||||
let blinded_block_ssz = prefix
|
||||
.and(warp::path("blinded_blocks"))
|
||||
.and(warp::body::bytes())
|
||||
.and(warp::header::header::<ForkName>(CONSENSUS_VERSION_HEADER))
|
||||
.and(warp::path::end())
|
||||
.and(ctx_filter.clone())
|
||||
.and_then(
|
||||
|block_bytes: Bytes, fork_name: ForkName, builder: MockBuilder<E>| async move {
|
||||
let block =
|
||||
SignedBlindedBeaconBlock::<E>::from_ssz_bytes_by_fork(&block_bytes, fork_name)
|
||||
.map_err(|e| warp::reject::custom(Custom(format!("{:?}", e))))?;
|
||||
let payload = builder
|
||||
.submit_blinded_block(block)
|
||||
.await
|
||||
.map_err(|e| warp::reject::custom(Custom(e)))?;
|
||||
|
||||
Ok::<_, warp::reject::Rejection>(
|
||||
warp::http::Response::builder()
|
||||
.status(200)
|
||||
.body(payload.as_ssz_bytes())
|
||||
.map(add_ssz_content_type_header)
|
||||
.map(|res| add_consensus_version_header(res, fork_name))
|
||||
.unwrap(),
|
||||
)
|
||||
Ok::<_, Rejection>(warp::reply().into_response())
|
||||
},
|
||||
);
|
||||
|
||||
let blinded_block =
|
||||
prefix
|
||||
let blinded_block_ssz =
|
||||
prefix_either
|
||||
.and(warp::path("blinded_blocks"))
|
||||
.and(warp::body::json())
|
||||
.and(warp::body::bytes())
|
||||
.and(warp::header::header::<ForkName>(CONSENSUS_VERSION_HEADER))
|
||||
.and(warp::path::end())
|
||||
.and(ctx_filter.clone())
|
||||
.and_then(
|
||||
|block: SignedBlindedBeaconBlock<E>,
|
||||
|endpoint_version,
|
||||
block_bytes: Bytes,
|
||||
fork_name: ForkName,
|
||||
builder: MockBuilder<E>| async move {
|
||||
if endpoint_version != EndpointVersion(1)
|
||||
&& endpoint_version != EndpointVersion(2)
|
||||
{
|
||||
return Err(warp::reject::custom(Custom(format!(
|
||||
"Unsupported version: {endpoint_version}"
|
||||
))));
|
||||
}
|
||||
let block = SignedBlindedBeaconBlock::<E>::from_ssz_bytes_by_fork(
|
||||
&block_bytes,
|
||||
fork_name,
|
||||
)
|
||||
.map_err(|e| warp::reject::custom(Custom(format!("{:?}", e))))?;
|
||||
let payload = builder
|
||||
.submit_blinded_block(block)
|
||||
.await
|
||||
.map_err(|e| warp::reject::custom(Custom(e)))?;
|
||||
let resp: ForkVersionedResponse<_> = ForkVersionedResponse {
|
||||
version: fork_name,
|
||||
metadata: Default::default(),
|
||||
data: payload,
|
||||
};
|
||||
|
||||
let json_payload = serde_json::to_string(&resp)
|
||||
.map_err(|_| reject("coudn't serialize response"))?;
|
||||
if endpoint_version == EndpointVersion(1) {
|
||||
Ok::<_, warp::reject::Rejection>(
|
||||
warp::http::Response::builder()
|
||||
.status(200)
|
||||
.body(payload.as_ssz_bytes())
|
||||
.map(add_ssz_content_type_header)
|
||||
.map(|res| add_consensus_version_header(res, fork_name))
|
||||
.unwrap(),
|
||||
)
|
||||
} else {
|
||||
Ok(warp::http::Response::builder()
|
||||
.status(202)
|
||||
.body(&[] as &'static [u8])
|
||||
.map(|res| add_consensus_version_header(res, fork_name))
|
||||
.unwrap())
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let blinded_block = prefix_either
|
||||
.and(warp::path("blinded_blocks"))
|
||||
.and(warp::body::json())
|
||||
.and(warp::header::header::<ForkName>(CONSENSUS_VERSION_HEADER))
|
||||
.and(warp::path::end())
|
||||
.and(ctx_filter.clone())
|
||||
.and_then(
|
||||
|endpoint_version,
|
||||
block: SignedBlindedBeaconBlock<E>,
|
||||
fork_name: ForkName,
|
||||
builder: MockBuilder<E>| async move {
|
||||
if endpoint_version != EndpointVersion(1) && endpoint_version != EndpointVersion(2)
|
||||
{
|
||||
return Err(warp::reject::custom(Custom(format!(
|
||||
"Unsupported version: {endpoint_version}"
|
||||
))));
|
||||
}
|
||||
let payload = builder
|
||||
.submit_blinded_block(block)
|
||||
.await
|
||||
.map_err(|e| warp::reject::custom(Custom(e)))?;
|
||||
let resp: ForkVersionedResponse<_> = ForkVersionedResponse {
|
||||
version: fork_name,
|
||||
metadata: Default::default(),
|
||||
data: payload,
|
||||
};
|
||||
|
||||
let json_payload = serde_json::to_string(&resp)
|
||||
.map_err(|_| reject("coudn't serialize response"))?;
|
||||
|
||||
if endpoint_version == EndpointVersion(1) {
|
||||
Ok::<_, warp::reject::Rejection>(
|
||||
warp::http::Response::builder()
|
||||
.status(200)
|
||||
@@ -1036,16 +1129,24 @@ pub fn serve<E: EthSpec>(
|
||||
serde_json::to_string(&json_payload)
|
||||
.map_err(|_| reject("invalid JSON"))?,
|
||||
)
|
||||
.map(|res| add_consensus_version_header(res, fork_name))
|
||||
.unwrap(),
|
||||
)
|
||||
},
|
||||
);
|
||||
} else {
|
||||
Ok(warp::http::Response::builder()
|
||||
.status(202)
|
||||
.body("".to_string())
|
||||
.map(|res| add_consensus_version_header(res, fork_name))
|
||||
.unwrap())
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let status = prefix
|
||||
let status = prefix_v1
|
||||
.and(warp::path("status"))
|
||||
.then(|| async { warp::reply() });
|
||||
.then(|| async { warp::reply().into_response() });
|
||||
|
||||
let header = prefix
|
||||
let header = prefix_v1
|
||||
.and(warp::path("header"))
|
||||
.and(warp::path::param::<Slot>().or_else(|_| async { Err(reject("Invalid slot")) }))
|
||||
.and(
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
use crate::{
|
||||
test_utils::{
|
||||
MockServer, DEFAULT_JWT_SECRET, DEFAULT_TERMINAL_BLOCK, DEFAULT_TERMINAL_DIFFICULTY,
|
||||
DEFAULT_JWT_SECRET, DEFAULT_TERMINAL_BLOCK, DEFAULT_TERMINAL_DIFFICULTY, MockServer,
|
||||
},
|
||||
*,
|
||||
};
|
||||
use alloy_primitives::B256 as H256;
|
||||
use fixed_bytes::FixedBytesExtended;
|
||||
use kzg::Kzg;
|
||||
use tempfile::NamedTempFile;
|
||||
use types::{FixedBytesExtended, MainnetEthSpec};
|
||||
use types::MainnetEthSpec;
|
||||
|
||||
pub struct MockExecutionLayer<E: EthSpec> {
|
||||
pub server: MockServer<E>,
|
||||
@@ -30,6 +31,7 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Some(JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap()),
|
||||
Arc::new(spec),
|
||||
None,
|
||||
@@ -45,6 +47,7 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
prague_time: Option<u64>,
|
||||
eip7805_time: Option<u64>,
|
||||
osaka_time: Option<u64>,
|
||||
amsterdam_time: Option<u64>,
|
||||
jwt_key: Option<JwtKey>,
|
||||
spec: Arc<ChainSpec>,
|
||||
kzg: Option<Arc<Kzg>>,
|
||||
@@ -63,7 +66,7 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
prague_time,
|
||||
eip7805_time,
|
||||
osaka_time,
|
||||
spec.clone(),
|
||||
amsterdam_time,
|
||||
kzg,
|
||||
);
|
||||
|
||||
@@ -171,10 +174,11 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
assert_eq!(payload.prev_randao(), prev_randao);
|
||||
|
||||
// Ensure the payload cache is empty.
|
||||
assert!(self
|
||||
.el
|
||||
.get_payload_by_root(&payload.tree_hash_root())
|
||||
.is_none());
|
||||
assert!(
|
||||
self.el
|
||||
.get_payload_by_root(&payload.tree_hash_root())
|
||||
.is_none()
|
||||
);
|
||||
let builder_params = BuilderParams {
|
||||
pubkey: PublicKeyBytes::empty(),
|
||||
slot,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use crate::engine_api::auth::JwtKey;
|
||||
use crate::engine_api::{
|
||||
auth::Auth, http::JSONRPC_VERSION, ExecutionBlock, PayloadStatusV1, PayloadStatusV1Status,
|
||||
ExecutionBlock, PayloadStatusV1, PayloadStatusV1Status, auth::Auth, http::JSONRPC_VERSION,
|
||||
};
|
||||
use crate::json_structures::JsonClientVersionV1;
|
||||
use bytes::Bytes;
|
||||
@@ -22,17 +22,17 @@ use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||
use std::sync::{Arc, LazyLock};
|
||||
use tokio::{runtime, sync::oneshot};
|
||||
use tracing::info;
|
||||
use types::{ChainSpec, EthSpec, ExecutionBlockHash, Uint256};
|
||||
use warp::{http::StatusCode, Filter, Rejection};
|
||||
use types::{EthSpec, ExecutionBlockHash, Uint256};
|
||||
use warp::{Filter, Rejection, http::StatusCode};
|
||||
|
||||
use crate::EngineCapabilities;
|
||||
pub use execution_block_generator::DEFAULT_GAS_LIMIT;
|
||||
pub use execution_block_generator::{
|
||||
generate_blobs, generate_genesis_block, generate_genesis_header, generate_pow_block,
|
||||
mock_el_extra_data, static_valid_tx, Block, ExecutionBlockGenerator,
|
||||
Block, ExecutionBlockGenerator, generate_blobs, generate_genesis_block,
|
||||
generate_genesis_header, generate_pow_block, mock_el_extra_data, static_valid_tx,
|
||||
};
|
||||
pub use hook::Hook;
|
||||
pub use mock_builder::{mock_builder_extra_data, MockBuilder, Operation};
|
||||
pub use mock_builder::{MockBuilder, Operation, mock_builder_extra_data};
|
||||
pub use mock_execution_layer::MockExecutionLayer;
|
||||
|
||||
pub const DEFAULT_TERMINAL_DIFFICULTY: u64 = 6400;
|
||||
@@ -45,7 +45,6 @@ pub const DEFAULT_ENGINE_CAPABILITIES: EngineCapabilities = EngineCapabilities {
|
||||
new_payload_v2: true,
|
||||
new_payload_v3: true,
|
||||
new_payload_v4: true,
|
||||
new_payload_v5: true,
|
||||
forkchoice_updated_v1: true,
|
||||
forkchoice_updated_v2: true,
|
||||
forkchoice_updated_v3: true,
|
||||
@@ -89,6 +88,7 @@ pub struct MockExecutionConfig {
|
||||
pub prague_time: Option<u64>,
|
||||
pub eip7805_time: Option<u64>,
|
||||
pub osaka_time: Option<u64>,
|
||||
pub amsterdam_time: Option<u64>,
|
||||
}
|
||||
|
||||
impl Default for MockExecutionConfig {
|
||||
@@ -104,6 +104,7 @@ impl Default for MockExecutionConfig {
|
||||
prague_time: None,
|
||||
eip7805_time: None,
|
||||
osaka_time: None,
|
||||
amsterdam_time: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,7 +117,7 @@ pub struct MockServer<E: EthSpec> {
|
||||
}
|
||||
|
||||
impl<E: EthSpec> MockServer<E> {
|
||||
pub fn unit_testing(chain_spec: Arc<ChainSpec>) -> Self {
|
||||
pub fn unit_testing() -> Self {
|
||||
Self::new(
|
||||
&runtime::Handle::current(),
|
||||
JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap(),
|
||||
@@ -128,7 +129,7 @@ impl<E: EthSpec> MockServer<E> {
|
||||
None, // FIXME(electra): should this be the default?
|
||||
None,
|
||||
None, // FIXME(fulu): should this be the default?
|
||||
chain_spec,
|
||||
None, // FIXME(gloas): should this be the default?
|
||||
None,
|
||||
)
|
||||
}
|
||||
@@ -136,7 +137,6 @@ impl<E: EthSpec> MockServer<E> {
|
||||
pub fn new_with_config(
|
||||
handle: &runtime::Handle,
|
||||
config: MockExecutionConfig,
|
||||
spec: Arc<ChainSpec>,
|
||||
kzg: Option<Arc<Kzg>>,
|
||||
) -> Self {
|
||||
create_test_tracing_subscriber();
|
||||
@@ -151,6 +151,7 @@ impl<E: EthSpec> MockServer<E> {
|
||||
prague_time,
|
||||
eip7805_time,
|
||||
osaka_time,
|
||||
amsterdam_time,
|
||||
} = config;
|
||||
let last_echo_request = Arc::new(RwLock::new(None));
|
||||
let preloaded_responses = Arc::new(Mutex::new(vec![]));
|
||||
@@ -163,7 +164,7 @@ impl<E: EthSpec> MockServer<E> {
|
||||
prague_time,
|
||||
eip7805_time,
|
||||
osaka_time,
|
||||
spec,
|
||||
amsterdam_time,
|
||||
kzg,
|
||||
);
|
||||
|
||||
@@ -228,7 +229,7 @@ impl<E: EthSpec> MockServer<E> {
|
||||
prague_time: Option<u64>,
|
||||
eip7805_time: Option<u64>,
|
||||
osaka_time: Option<u64>,
|
||||
spec: Arc<ChainSpec>,
|
||||
amsterdam_time: Option<u64>,
|
||||
kzg: Option<Arc<Kzg>>,
|
||||
) -> Self {
|
||||
Self::new_with_config(
|
||||
@@ -244,8 +245,8 @@ impl<E: EthSpec> MockServer<E> {
|
||||
prague_time,
|
||||
eip7805_time,
|
||||
osaka_time,
|
||||
amsterdam_time,
|
||||
},
|
||||
spec,
|
||||
kzg,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use alloy_consensus::TxEnvelope;
|
||||
use alloy_rlp::Decodable;
|
||||
use types::{EthSpec, ExecutionPayloadRef, Hash256, Unsigned, VersionedHash};
|
||||
use typenum::Unsigned;
|
||||
use types::{EthSpec, ExecutionPayloadRef, Hash256, VersionedHash};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
|
||||
Reference in New Issue
Block a user