Merge remote-tracking branch 'origin/deneb-free-blobs' into tree-states

This commit is contained in:
Michael Sproul
2023-09-29 16:34:29 +10:00
253 changed files with 21791 additions and 3122 deletions

View File

@@ -32,14 +32,17 @@ pub const ETH_SYNCING_TIMEOUT: Duration = Duration::from_secs(1);
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_TIMEOUT: Duration = Duration::from_secs(8);
pub const ENGINE_GET_PAYLOAD_V1: &str = "engine_getPayloadV1";
pub const ENGINE_GET_PAYLOAD_V2: &str = "engine_getPayloadV2";
pub const ENGINE_GET_PAYLOAD_V3: &str = "engine_getPayloadV3";
pub const ENGINE_GET_PAYLOAD_TIMEOUT: Duration = Duration::from_secs(2);
pub const ENGINE_FORKCHOICE_UPDATED_V1: &str = "engine_forkchoiceUpdatedV1";
pub const ENGINE_FORKCHOICE_UPDATED_V2: &str = "engine_forkchoiceUpdatedV2";
pub const ENGINE_FORKCHOICE_UPDATED_V3: &str = "engine_forkchoiceUpdatedV3";
pub const ENGINE_FORKCHOICE_UPDATED_TIMEOUT: Duration = Duration::from_secs(8);
pub const ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1: &str = "engine_getPayloadBodiesByHashV1";
@@ -58,10 +61,13 @@ pub const METHOD_NOT_FOUND_CODE: i64 = -32601;
pub static LIGHTHOUSE_CAPABILITIES: &[&str] = &[
ENGINE_NEW_PAYLOAD_V1,
ENGINE_NEW_PAYLOAD_V2,
ENGINE_NEW_PAYLOAD_V3,
ENGINE_GET_PAYLOAD_V1,
ENGINE_GET_PAYLOAD_V2,
ENGINE_GET_PAYLOAD_V3,
ENGINE_FORKCHOICE_UPDATED_V1,
ENGINE_FORKCHOICE_UPDATED_V2,
ENGINE_FORKCHOICE_UPDATED_V3,
ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1,
ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1,
];
@@ -72,12 +78,15 @@ pub static LIGHTHOUSE_CAPABILITIES: &[&str] = &[
pub static PRE_CAPELLA_ENGINE_CAPABILITIES: EngineCapabilities = EngineCapabilities {
new_payload_v1: true,
new_payload_v2: false,
new_payload_v3: false,
forkchoice_updated_v1: true,
forkchoice_updated_v2: false,
forkchoice_updated_v3: false,
get_payload_bodies_by_hash_v1: false,
get_payload_bodies_by_range_v1: false,
get_payload_v1: true,
get_payload_v2: false,
get_payload_v3: false,
};
/// Contains methods to convert arbitrary bytes to an ETH2 deposit contract object.
@@ -741,6 +750,14 @@ impl HttpJsonRpc {
)
.await?,
),
ForkName::Deneb => ExecutionBlockWithTransactions::Deneb(
self.rpc_request(
ETH_GET_BLOCK_BY_HASH,
params,
ETH_GET_BLOCK_BY_HASH_TIMEOUT * self.execution_timeout_multiplier,
)
.await?,
),
ForkName::Base | ForkName::Altair => {
return Err(Error::UnsupportedForkVariant(format!(
"called get_block_by_hash_with_txns with fork {:?}",
@@ -784,6 +801,27 @@ impl HttpJsonRpc {
Ok(response.into())
}
pub async fn new_payload_v3<T: EthSpec>(
&self,
new_payload_request_deneb: NewPayloadRequestDeneb<T>,
) -> Result<PayloadStatusV1, Error> {
let params = json!([
JsonExecutionPayload::V3(new_payload_request_deneb.execution_payload.into()),
new_payload_request_deneb.versioned_hashes,
new_payload_request_deneb.parent_beacon_block_root,
]);
let response: JsonPayloadStatusV1 = self
.rpc_request(
ENGINE_NEW_PAYLOAD_V3,
params,
ENGINE_NEW_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
)
.await?;
Ok(response.into())
}
pub async fn get_payload_v1<T: EthSpec>(
&self,
payload_id: PayloadId,
@@ -835,8 +873,32 @@ impl HttpJsonRpc {
.await?;
Ok(JsonGetPayloadResponse::V2(response).into())
}
ForkName::Base | ForkName::Altair => Err(Error::UnsupportedForkVariant(format!(
"called get_payload_v2 with {}",
ForkName::Base | ForkName::Altair | ForkName::Deneb => Err(
Error::UnsupportedForkVariant(format!("called get_payload_v2 with {}", fork_name)),
),
}
}
pub async fn get_payload_v3<T: EthSpec>(
&self,
fork_name: ForkName,
payload_id: PayloadId,
) -> Result<GetPayloadResponse<T>, Error> {
let params = json!([JsonPayloadIdRequest::from(payload_id)]);
match fork_name {
ForkName::Deneb => {
let response: JsonGetPayloadResponseV3<T> = self
.rpc_request(
ENGINE_GET_PAYLOAD_V3,
params,
ENGINE_GET_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
)
.await?;
Ok(JsonGetPayloadResponse::V3(response).into())
}
_ => Err(Error::UnsupportedForkVariant(format!(
"called get_payload_v3 with {}",
fork_name
))),
}
@@ -884,6 +946,27 @@ impl HttpJsonRpc {
Ok(response.into())
}
pub async fn forkchoice_updated_v3(
&self,
forkchoice_state: ForkchoiceState,
payload_attributes: Option<PayloadAttributes>,
) -> Result<ForkchoiceUpdatedResponse, Error> {
let params = json!([
JsonForkchoiceStateV1::from(forkchoice_state),
payload_attributes.map(JsonPayloadAttributes::from)
]);
let response: JsonForkchoiceUpdatedV1Response = self
.rpc_request(
ENGINE_FORKCHOICE_UPDATED_V3,
params,
ENGINE_FORKCHOICE_UPDATED_TIMEOUT * self.execution_timeout_multiplier,
)
.await?;
Ok(response.into())
}
pub async fn get_payload_bodies_by_hash_v1<E: EthSpec>(
&self,
block_hashes: Vec<ExecutionBlockHash>,
@@ -950,14 +1033,17 @@ impl HttpJsonRpc {
Ok(capabilities) => Ok(EngineCapabilities {
new_payload_v1: capabilities.contains(ENGINE_NEW_PAYLOAD_V1),
new_payload_v2: capabilities.contains(ENGINE_NEW_PAYLOAD_V2),
new_payload_v3: capabilities.contains(ENGINE_NEW_PAYLOAD_V3),
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),
get_payload_bodies_by_hash_v1: capabilities
.contains(ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1),
get_payload_bodies_by_range_v1: capabilities
.contains(ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1),
get_payload_v1: capabilities.contains(ENGINE_GET_PAYLOAD_V1),
get_payload_v2: capabilities.contains(ENGINE_GET_PAYLOAD_V2),
get_payload_v3: capabilities.contains(ENGINE_GET_PAYLOAD_V3),
}),
}
}
@@ -994,15 +1080,28 @@ impl HttpJsonRpc {
// new_payload that the execution engine supports
pub async fn new_payload<T: EthSpec>(
&self,
execution_payload: ExecutionPayload<T>,
new_payload_request: NewPayloadRequest<T>,
) -> Result<PayloadStatusV1, Error> {
let engine_capabilities = self.get_engine_capabilities(None).await?;
if engine_capabilities.new_payload_v2 {
self.new_payload_v2(execution_payload).await
} else if engine_capabilities.new_payload_v1 {
self.new_payload_v1(execution_payload).await
} else {
Err(Error::RequiredMethodUnsupported("engine_newPayload"))
match new_payload_request {
NewPayloadRequest::Merge(_) | NewPayloadRequest::Capella(_) => {
if engine_capabilities.new_payload_v2 {
self.new_payload_v2(new_payload_request.into_execution_payload())
.await
} else if engine_capabilities.new_payload_v1 {
self.new_payload_v1(new_payload_request.into_execution_payload())
.await
} else {
Err(Error::RequiredMethodUnsupported("engine_newPayload"))
}
}
NewPayloadRequest::Deneb(new_payload_request_deneb) => {
if engine_capabilities.new_payload_v3 {
self.new_payload_v3(new_payload_request_deneb).await
} else {
Err(Error::RequiredMethodUnsupported("engine_newPayloadV3"))
}
}
}
}
@@ -1014,12 +1113,27 @@ impl HttpJsonRpc {
payload_id: PayloadId,
) -> Result<GetPayloadResponse<T>, Error> {
let engine_capabilities = self.get_engine_capabilities(None).await?;
if engine_capabilities.get_payload_v2 {
self.get_payload_v2(fork_name, payload_id).await
} else if engine_capabilities.new_payload_v1 {
self.get_payload_v1(payload_id).await
} else {
Err(Error::RequiredMethodUnsupported("engine_getPayload"))
match fork_name {
ForkName::Merge | ForkName::Capella => {
if engine_capabilities.get_payload_v2 {
self.get_payload_v2(fork_name, payload_id).await
} else if engine_capabilities.new_payload_v1 {
self.get_payload_v1(payload_id).await
} else {
Err(Error::RequiredMethodUnsupported("engine_getPayload"))
}
}
ForkName::Deneb => {
if engine_capabilities.get_payload_v3 {
self.get_payload_v3(fork_name, payload_id).await
} else {
Err(Error::RequiredMethodUnsupported("engine_getPayloadV3"))
}
}
ForkName::Base | ForkName::Altair => Err(Error::UnsupportedForkVariant(format!(
"called get_payload with {}",
fork_name
))),
}
}
@@ -1028,14 +1142,41 @@ impl HttpJsonRpc {
pub async fn forkchoice_updated(
&self,
forkchoice_state: ForkchoiceState,
payload_attributes: Option<PayloadAttributes>,
maybe_payload_attributes: Option<PayloadAttributes>,
) -> Result<ForkchoiceUpdatedResponse, Error> {
let engine_capabilities = self.get_engine_capabilities(None).await?;
if engine_capabilities.forkchoice_updated_v2 {
self.forkchoice_updated_v2(forkchoice_state, payload_attributes)
if let Some(payload_attributes) = maybe_payload_attributes.as_ref() {
match payload_attributes {
PayloadAttributes::V1(_) | PayloadAttributes::V2(_) => {
if engine_capabilities.forkchoice_updated_v2 {
self.forkchoice_updated_v2(forkchoice_state, maybe_payload_attributes)
.await
} else if engine_capabilities.forkchoice_updated_v1 {
self.forkchoice_updated_v1(forkchoice_state, maybe_payload_attributes)
.await
} else {
Err(Error::RequiredMethodUnsupported("engine_forkchoiceUpdated"))
}
}
PayloadAttributes::V3(_) => {
if engine_capabilities.forkchoice_updated_v3 {
self.forkchoice_updated_v3(forkchoice_state, maybe_payload_attributes)
.await
} else {
Err(Error::RequiredMethodUnsupported(
"engine_forkchoiceUpdatedV3",
))
}
}
}
} else if engine_capabilities.forkchoice_updated_v3 {
self.forkchoice_updated_v3(forkchoice_state, maybe_payload_attributes)
.await
} else if engine_capabilities.forkchoice_updated_v2 {
self.forkchoice_updated_v2(forkchoice_state, maybe_payload_attributes)
.await
} else if engine_capabilities.forkchoice_updated_v1 {
self.forkchoice_updated_v1(forkchoice_state, payload_attributes)
self.forkchoice_updated_v1(forkchoice_state, maybe_payload_attributes)
.await
} else {
Err(Error::RequiredMethodUnsupported("engine_forkchoiceUpdated"))

View File

@@ -3,9 +3,11 @@ use serde::{Deserialize, Serialize};
use ssz_types::FixedVector;
use strum::EnumString;
use superstruct::superstruct;
use types::beacon_block_body::KzgCommitments;
use types::blob_sidecar::BlobsList;
use types::{
EthSpec, ExecutionBlockHash, ExecutionPayloadCapella, ExecutionPayloadMerge, Transactions,
Unsigned, VariableList, Withdrawal,
EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadCapella, ExecutionPayloadDeneb,
ExecutionPayloadMerge, Transactions, Unsigned, VariableList, Withdrawal,
};
#[derive(Debug, PartialEq, Serialize, Deserialize)]
@@ -62,7 +64,7 @@ pub struct JsonPayloadIdResponse {
}
#[superstruct(
variants(V1, V2),
variants(V1, V2, V3),
variant_attributes(
derive(Debug, PartialEq, Default, Serialize, Deserialize,),
serde(bound = "T: EthSpec", rename_all = "camelCase"),
@@ -95,8 +97,14 @@ pub struct JsonExecutionPayload<T: EthSpec> {
pub block_hash: ExecutionBlockHash,
#[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")]
pub transactions: Transactions<T>,
#[superstruct(only(V2))]
#[superstruct(only(V2, V3))]
pub withdrawals: VariableList<JsonWithdrawal, T::MaxWithdrawalsPerPayload>,
#[superstruct(only(V3))]
#[serde(with = "serde_utils::u64_hex_be")]
pub blob_gas_used: u64,
#[superstruct(only(V3))]
#[serde(with = "serde_utils::u64_hex_be")]
pub excess_blob_gas: u64,
}
impl<T: EthSpec> From<ExecutionPayloadMerge<T>> for JsonExecutionPayloadV1<T> {
@@ -145,12 +153,41 @@ impl<T: EthSpec> From<ExecutionPayloadCapella<T>> for JsonExecutionPayloadV2<T>
}
}
}
impl<T: EthSpec> From<ExecutionPayloadDeneb<T>> for JsonExecutionPayloadV3<T> {
fn from(payload: ExecutionPayloadDeneb<T>) -> Self {
JsonExecutionPayloadV3 {
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: payload
.withdrawals
.into_iter()
.map(Into::into)
.collect::<Vec<_>>()
.into(),
blob_gas_used: payload.blob_gas_used,
excess_blob_gas: payload.excess_blob_gas,
}
}
}
impl<T: EthSpec> From<ExecutionPayload<T>> for JsonExecutionPayload<T> {
fn from(execution_payload: ExecutionPayload<T>) -> Self {
match execution_payload {
ExecutionPayload::Merge(payload) => JsonExecutionPayload::V1(payload.into()),
ExecutionPayload::Capella(payload) => JsonExecutionPayload::V2(payload.into()),
ExecutionPayload::Deneb(payload) => JsonExecutionPayload::V3(payload.into()),
}
}
}
@@ -201,18 +238,47 @@ impl<T: EthSpec> From<JsonExecutionPayloadV2<T>> for ExecutionPayloadCapella<T>
}
}
}
impl<T: EthSpec> From<JsonExecutionPayloadV3<T>> for ExecutionPayloadDeneb<T> {
fn from(payload: JsonExecutionPayloadV3<T>) -> Self {
ExecutionPayloadDeneb {
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: payload
.withdrawals
.into_iter()
.map(Into::into)
.collect::<Vec<_>>()
.into(),
blob_gas_used: payload.blob_gas_used,
excess_blob_gas: payload.excess_blob_gas,
}
}
}
impl<T: EthSpec> From<JsonExecutionPayload<T>> for ExecutionPayload<T> {
fn from(json_execution_payload: JsonExecutionPayload<T>) -> Self {
match json_execution_payload {
JsonExecutionPayload::V1(payload) => ExecutionPayload::Merge(payload.into()),
JsonExecutionPayload::V2(payload) => ExecutionPayload::Capella(payload.into()),
JsonExecutionPayload::V3(payload) => ExecutionPayload::Deneb(payload.into()),
}
}
}
#[superstruct(
variants(V1, V2),
variants(V1, V2, V3),
variant_attributes(
derive(Debug, PartialEq, Serialize, Deserialize),
serde(bound = "T: EthSpec", rename_all = "camelCase")
@@ -227,8 +293,14 @@ pub struct JsonGetPayloadResponse<T: EthSpec> {
pub execution_payload: JsonExecutionPayloadV1<T>,
#[superstruct(only(V2), partial_getter(rename = "execution_payload_v2"))]
pub execution_payload: JsonExecutionPayloadV2<T>,
#[superstruct(only(V3), partial_getter(rename = "execution_payload_v3"))]
pub execution_payload: JsonExecutionPayloadV3<T>,
#[serde(with = "serde_utils::u256_hex_be")]
pub block_value: Uint256,
#[superstruct(only(V3))]
pub blobs_bundle: JsonBlobsBundleV1<T>,
#[superstruct(only(V3))]
pub should_override_builder: bool,
}
impl<T: EthSpec> From<JsonGetPayloadResponse<T>> for GetPayloadResponse<T> {
@@ -246,6 +318,14 @@ impl<T: EthSpec> From<JsonGetPayloadResponse<T>> for GetPayloadResponse<T> {
block_value: response.block_value,
})
}
JsonGetPayloadResponse::V3(response) => {
GetPayloadResponse::Deneb(GetPayloadResponseDeneb {
execution_payload: response.execution_payload.into(),
block_value: response.block_value,
blobs_bundle: response.blobs_bundle.into(),
should_override_builder: response.should_override_builder,
})
}
}
}
}
@@ -285,7 +365,7 @@ impl From<JsonWithdrawal> for Withdrawal {
}
#[superstruct(
variants(V1, V2),
variants(V1, V2, V3),
variant_attributes(
derive(Debug, Clone, PartialEq, Serialize, Deserialize),
serde(rename_all = "camelCase")
@@ -300,8 +380,10 @@ pub struct JsonPayloadAttributes {
pub timestamp: u64,
pub prev_randao: Hash256,
pub suggested_fee_recipient: Address,
#[superstruct(only(V2))]
#[superstruct(only(V2, V3))]
pub withdrawals: Vec<JsonWithdrawal>,
#[superstruct(only(V3))]
pub parent_beacon_block_root: Hash256,
}
impl From<PayloadAttributes> for JsonPayloadAttributes {
@@ -318,6 +400,13 @@ impl From<PayloadAttributes> for JsonPayloadAttributes {
suggested_fee_recipient: pa.suggested_fee_recipient,
withdrawals: pa.withdrawals.into_iter().map(Into::into).collect(),
}),
PayloadAttributes::V3(pa) => Self::V3(JsonPayloadAttributesV3 {
timestamp: pa.timestamp,
prev_randao: pa.prev_randao,
suggested_fee_recipient: pa.suggested_fee_recipient,
withdrawals: pa.withdrawals.into_iter().map(Into::into).collect(),
parent_beacon_block_root: pa.parent_beacon_block_root,
}),
}
}
}
@@ -336,6 +425,41 @@ impl From<JsonPayloadAttributes> for PayloadAttributes {
suggested_fee_recipient: jpa.suggested_fee_recipient,
withdrawals: jpa.withdrawals.into_iter().map(Into::into).collect(),
}),
JsonPayloadAttributes::V3(jpa) => Self::V3(PayloadAttributesV3 {
timestamp: jpa.timestamp,
prev_randao: jpa.prev_randao,
suggested_fee_recipient: jpa.suggested_fee_recipient,
withdrawals: jpa.withdrawals.into_iter().map(Into::into).collect(),
parent_beacon_block_root: jpa.parent_beacon_block_root,
}),
}
}
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(bound = "E: EthSpec", rename_all = "camelCase")]
pub struct JsonBlobsBundleV1<E: EthSpec> {
pub commitments: KzgCommitments<E>,
pub proofs: KzgProofs<E>,
#[serde(with = "ssz_types::serde_utils::list_of_hex_fixed_vec")]
pub blobs: BlobsList<E>,
}
impl<E: EthSpec> From<BlobsBundle<E>> for JsonBlobsBundleV1<E> {
fn from(blobs_bundle: BlobsBundle<E>) -> Self {
Self {
commitments: blobs_bundle.commitments,
proofs: blobs_bundle.proofs,
blobs: blobs_bundle.blobs,
}
}
}
impl<E: EthSpec> From<JsonBlobsBundleV1<E>> for BlobsBundle<E> {
fn from(json_blobs_bundle: JsonBlobsBundleV1<E>) -> Self {
Self {
commitments: json_blobs_bundle.commitments,
proofs: json_blobs_bundle.proofs,
blobs: json_blobs_bundle.blobs,
}
}
}