mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 04:37:13 +00:00
Engine api changes
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
use crate::engines::ForkchoiceState;
|
||||
use crate::http::{
|
||||
ENGINE_FORKCHOICE_UPDATED_V1, ENGINE_FORKCHOICE_UPDATED_V2, ENGINE_FORKCHOICE_UPDATED_V3,
|
||||
ENGINE_FORKCHOICE_UPDATED_V4, ENGINE_GET_BLOBS_V1, ENGINE_GET_BLOBS_V2, ENGINE_GET_BLOBS_V3,
|
||||
ENGINE_GET_CLIENT_VERSION_V1, 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_GET_PAYLOAD_V6, ENGINE_NEW_PAYLOAD_V1, ENGINE_NEW_PAYLOAD_V2,
|
||||
ENGINE_FORKCHOICE_UPDATED_V4, ENGINE_FORKCHOICE_UPDATED_V5, ENGINE_GET_BLOBS_V1,
|
||||
ENGINE_GET_BLOBS_V2, ENGINE_GET_BLOBS_V3, ENGINE_GET_CLIENT_VERSION_V1,
|
||||
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_GET_PAYLOAD_V6,
|
||||
ENGINE_IS_INCLUSION_LIST_SATISFIED_V1, ENGINE_NEW_PAYLOAD_V1, ENGINE_NEW_PAYLOAD_V2,
|
||||
ENGINE_NEW_PAYLOAD_V3, ENGINE_NEW_PAYLOAD_V4, ENGINE_NEW_PAYLOAD_V5,
|
||||
};
|
||||
use eth2::types::{
|
||||
@@ -159,7 +160,7 @@ impl ExecutionBlock {
|
||||
}
|
||||
|
||||
#[superstruct(
|
||||
variants(V1, V2, V3, V4),
|
||||
variants(V1, V2, V3, V4, V5),
|
||||
variant_attributes(derive(Clone, Debug, Eq, Hash, PartialEq),),
|
||||
cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"),
|
||||
partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant")
|
||||
@@ -172,12 +173,14 @@ pub struct PayloadAttributes {
|
||||
pub prev_randao: Hash256,
|
||||
#[superstruct(getter(copy))]
|
||||
pub suggested_fee_recipient: Address,
|
||||
#[superstruct(only(V2, V3, V4))]
|
||||
#[superstruct(only(V2, V3, V4, V5))]
|
||||
pub withdrawals: Vec<Withdrawal>,
|
||||
#[superstruct(only(V3, V4), partial_getter(copy))]
|
||||
#[superstruct(only(V3, V4, V5), partial_getter(copy))]
|
||||
pub parent_beacon_block_root: Hash256,
|
||||
#[superstruct(only(V4), partial_getter(copy))]
|
||||
#[superstruct(only(V4, V5), partial_getter(copy))]
|
||||
pub slot_number: u64,
|
||||
#[superstruct(only(V5))]
|
||||
pub inclusion_list_transactions: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl PayloadAttributes {
|
||||
@@ -188,9 +191,29 @@ impl PayloadAttributes {
|
||||
withdrawals: Option<Vec<Withdrawal>>,
|
||||
parent_beacon_block_root: Option<Hash256>,
|
||||
slot_number: Option<u64>,
|
||||
inclusion_list_transactions: Option<Vec<Vec<u8>>>,
|
||||
) -> Self {
|
||||
match (withdrawals, parent_beacon_block_root, slot_number) {
|
||||
(Some(withdrawals), Some(parent_beacon_block_root), Some(slot_number)) => {
|
||||
match (
|
||||
withdrawals,
|
||||
parent_beacon_block_root,
|
||||
slot_number,
|
||||
inclusion_list_transactions,
|
||||
) {
|
||||
(
|
||||
Some(withdrawals),
|
||||
Some(parent_beacon_block_root),
|
||||
Some(slot_number),
|
||||
Some(inclusion_list_transactions),
|
||||
) => PayloadAttributes::V5(PayloadAttributesV5 {
|
||||
timestamp,
|
||||
prev_randao,
|
||||
suggested_fee_recipient,
|
||||
withdrawals,
|
||||
parent_beacon_block_root,
|
||||
slot_number,
|
||||
inclusion_list_transactions,
|
||||
}),
|
||||
(Some(withdrawals), Some(parent_beacon_block_root), Some(slot_number), None) => {
|
||||
PayloadAttributes::V4(PayloadAttributesV4 {
|
||||
timestamp,
|
||||
prev_randao,
|
||||
@@ -200,7 +223,7 @@ impl PayloadAttributes {
|
||||
slot_number,
|
||||
})
|
||||
}
|
||||
(Some(withdrawals), Some(parent_beacon_block_root), None) => {
|
||||
(Some(withdrawals), Some(parent_beacon_block_root), None, _) => {
|
||||
PayloadAttributes::V3(PayloadAttributesV3 {
|
||||
timestamp,
|
||||
prev_randao,
|
||||
@@ -209,13 +232,13 @@ impl PayloadAttributes {
|
||||
parent_beacon_block_root,
|
||||
})
|
||||
}
|
||||
(Some(withdrawals), None, _) => PayloadAttributes::V2(PayloadAttributesV2 {
|
||||
(Some(withdrawals), None, _, _) => PayloadAttributes::V2(PayloadAttributesV2 {
|
||||
timestamp,
|
||||
prev_randao,
|
||||
suggested_fee_recipient,
|
||||
withdrawals,
|
||||
}),
|
||||
(None, _, _) => PayloadAttributes::V1(PayloadAttributesV1 {
|
||||
(None, _, _, _) => PayloadAttributes::V1(PayloadAttributesV1 {
|
||||
timestamp,
|
||||
prev_randao,
|
||||
suggested_fee_recipient,
|
||||
@@ -275,6 +298,22 @@ impl From<PayloadAttributes> for SsePayloadAttributes {
|
||||
withdrawals,
|
||||
parent_beacon_block_root,
|
||||
}),
|
||||
// V5 maps to V3 for SSE (slot_number and inclusion_list_transactions are not part of the SSE spec)
|
||||
PayloadAttributes::V5(PayloadAttributesV5 {
|
||||
timestamp,
|
||||
prev_randao,
|
||||
suggested_fee_recipient,
|
||||
withdrawals,
|
||||
parent_beacon_block_root,
|
||||
slot_number: _,
|
||||
inclusion_list_transactions: _,
|
||||
}) => Self::V3(SsePayloadAttributesV3 {
|
||||
timestamp,
|
||||
prev_randao,
|
||||
suggested_fee_recipient,
|
||||
withdrawals,
|
||||
parent_beacon_block_root,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -637,6 +676,8 @@ pub struct EngineCapabilities {
|
||||
pub get_blobs_v2: bool,
|
||||
pub get_inclusion_list_v1: bool,
|
||||
pub get_blobs_v3: bool,
|
||||
pub forkchoice_updated_v5: bool,
|
||||
pub is_inclusion_list_satisfied_v1: bool,
|
||||
}
|
||||
|
||||
impl EngineCapabilities {
|
||||
@@ -708,6 +749,12 @@ impl EngineCapabilities {
|
||||
if self.get_blobs_v3 {
|
||||
response.push(ENGINE_GET_BLOBS_V3);
|
||||
}
|
||||
if self.forkchoice_updated_v5 {
|
||||
response.push(ENGINE_FORKCHOICE_UPDATED_V5);
|
||||
}
|
||||
if self.is_inclusion_list_satisfied_v1 {
|
||||
response.push(ENGINE_IS_INCLUSION_LIST_SATISFIED_V1);
|
||||
}
|
||||
|
||||
response
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ 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_V4: &str = "engine_forkchoiceUpdatedV4";
|
||||
pub const ENGINE_FORKCHOICE_UPDATED_V5: &str = "engine_forkchoiceUpdatedV5";
|
||||
pub const ENGINE_FORKCHOICE_UPDATED_TIMEOUT: Duration = Duration::from_secs(8);
|
||||
|
||||
pub const ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1: &str = "engine_getPayloadBodiesByHashV1";
|
||||
@@ -70,6 +71,9 @@ pub const ENGINE_GET_BLOBS_TIMEOUT: Duration = Duration::from_secs(1);
|
||||
pub const ENGINE_GET_INCLUSION_LIST_V1: &str = "engine_getInclusionListV1";
|
||||
pub const ENGINE_GET_INCLUSION_LIST_TIMEOUT: Duration = Duration::from_secs(1);
|
||||
|
||||
pub const ENGINE_IS_INCLUSION_LIST_SATISFIED_V1: &str = "engine_isInclusionListSatisfiedV1";
|
||||
pub const ENGINE_IS_INCLUSION_LIST_SATISFIED_TIMEOUT: Duration = Duration::from_secs(1);
|
||||
|
||||
/// This error is returned during a `chainId` call by Geth.
|
||||
pub const EIP155_ERROR_STR: &str = "chain not synced beyond EIP-155 replay-protection fork block";
|
||||
/// This code is returned by all clients when a method is not supported
|
||||
@@ -92,12 +96,14 @@ pub static LIGHTHOUSE_CAPABILITIES: &[&str] = &[
|
||||
ENGINE_FORKCHOICE_UPDATED_V2,
|
||||
ENGINE_FORKCHOICE_UPDATED_V3,
|
||||
ENGINE_FORKCHOICE_UPDATED_V4,
|
||||
ENGINE_FORKCHOICE_UPDATED_V5,
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1,
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1,
|
||||
ENGINE_GET_CLIENT_VERSION_V1,
|
||||
ENGINE_GET_BLOBS_V1,
|
||||
ENGINE_GET_BLOBS_V2,
|
||||
ENGINE_GET_INCLUSION_LIST_V1,
|
||||
ENGINE_IS_INCLUSION_LIST_SATISFIED_V1,
|
||||
];
|
||||
|
||||
/// We opt to initialize the JsonClientVersionV1 rather than the ClientVersionV1
|
||||
@@ -1314,6 +1320,47 @@ impl HttpJsonRpc {
|
||||
Ok(response.into())
|
||||
}
|
||||
|
||||
pub async fn forkchoice_updated_v5(
|
||||
&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_V5,
|
||||
params,
|
||||
ENGINE_FORKCHOICE_UPDATED_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(response.into())
|
||||
}
|
||||
|
||||
pub async fn is_inclusion_list_satisfied(
|
||||
&self,
|
||||
execution_payload_hash: ExecutionBlockHash,
|
||||
inclusion_list_transactions: Vec<Vec<u8>>,
|
||||
) -> Result<bool, Error> {
|
||||
let hex_transactions: Vec<String> = inclusion_list_transactions
|
||||
.into_iter()
|
||||
.map(|tx| format!("0x{}", hex::encode(tx)))
|
||||
.collect();
|
||||
|
||||
let params = json!([execution_payload_hash, hex_transactions]);
|
||||
|
||||
self.rpc_request(
|
||||
ENGINE_IS_INCLUSION_LIST_SATISFIED_V1,
|
||||
params,
|
||||
ENGINE_IS_INCLUSION_LIST_SATISFIED_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_payload_bodies_by_hash_v1<E: EthSpec>(
|
||||
&self,
|
||||
block_hashes: Vec<ExecutionBlockHash>,
|
||||
@@ -1402,6 +1449,9 @@ impl HttpJsonRpc {
|
||||
get_blobs_v2: capabilities.contains(ENGINE_GET_BLOBS_V2),
|
||||
get_inclusion_list_v1: capabilities.contains(ENGINE_GET_INCLUSION_LIST_V1),
|
||||
get_blobs_v3: capabilities.contains(ENGINE_GET_BLOBS_V3),
|
||||
forkchoice_updated_v5: capabilities.contains(ENGINE_FORKCHOICE_UPDATED_V5),
|
||||
is_inclusion_list_satisfied_v1: capabilities
|
||||
.contains(ENGINE_IS_INCLUSION_LIST_SATISFIED_V1),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1675,6 +1725,16 @@ impl HttpJsonRpc {
|
||||
))
|
||||
}
|
||||
}
|
||||
PayloadAttributes::V5(_) => {
|
||||
if engine_capabilities.forkchoice_updated_v5 {
|
||||
self.forkchoice_updated_v5(forkchoice_state, maybe_payload_attributes)
|
||||
.await
|
||||
} else {
|
||||
Err(Error::RequiredMethodUnsupported(
|
||||
"engine_forkchoiceUpdatedV5",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if engine_capabilities.forkchoice_updated_v3 {
|
||||
self.forkchoice_updated_v3(forkchoice_state, maybe_payload_attributes)
|
||||
|
||||
@@ -831,7 +831,7 @@ impl<'a> From<&'a JsonWithdrawal> for EncodableJsonWithdrawal<'a> {
|
||||
}
|
||||
|
||||
#[superstruct(
|
||||
variants(V1, V2, V3, V4),
|
||||
variants(V1, V2, V3, V4, V5),
|
||||
variant_attributes(
|
||||
derive(Debug, Clone, PartialEq, Serialize, Deserialize),
|
||||
serde(rename_all = "camelCase")
|
||||
@@ -847,13 +847,15 @@ pub struct JsonPayloadAttributes {
|
||||
pub prev_randao: Hash256,
|
||||
#[serde(with = "serde_utils::address_hex")]
|
||||
pub suggested_fee_recipient: Address,
|
||||
#[superstruct(only(V2, V3, V4))]
|
||||
#[superstruct(only(V2, V3, V4, V5))]
|
||||
pub withdrawals: Vec<JsonWithdrawal>,
|
||||
#[superstruct(only(V3, V4))]
|
||||
#[superstruct(only(V3, V4, V5))]
|
||||
pub parent_beacon_block_root: Hash256,
|
||||
#[superstruct(only(V4))]
|
||||
#[superstruct(only(V4, V5))]
|
||||
#[serde(with = "serde_utils::u64_hex_be")]
|
||||
pub slot_number: u64,
|
||||
#[superstruct(only(V5))]
|
||||
pub inclusion_list_transactions: Vec<String>,
|
||||
}
|
||||
|
||||
impl From<PayloadAttributes> for JsonPayloadAttributes {
|
||||
@@ -885,6 +887,19 @@ impl From<PayloadAttributes> for JsonPayloadAttributes {
|
||||
parent_beacon_block_root: pa.parent_beacon_block_root,
|
||||
slot_number: pa.slot_number,
|
||||
}),
|
||||
PayloadAttributes::V5(pa) => Self::V5(JsonPayloadAttributesV5 {
|
||||
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,
|
||||
slot_number: pa.slot_number,
|
||||
inclusion_list_transactions: pa
|
||||
.inclusion_list_transactions
|
||||
.into_iter()
|
||||
.map(|tx| format!("0x{}", hex::encode(tx)))
|
||||
.collect(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -918,6 +933,21 @@ impl From<JsonPayloadAttributes> for PayloadAttributes {
|
||||
parent_beacon_block_root: jpa.parent_beacon_block_root,
|
||||
slot_number: jpa.slot_number,
|
||||
}),
|
||||
JsonPayloadAttributes::V5(jpa) => Self::V5(PayloadAttributesV5 {
|
||||
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,
|
||||
slot_number: jpa.slot_number,
|
||||
inclusion_list_transactions: jpa
|
||||
.inclusion_list_transactions
|
||||
.into_iter()
|
||||
.map(|s| {
|
||||
hex::decode(s.strip_prefix("0x").unwrap_or(&s)).unwrap_or_default()
|
||||
})
|
||||
.collect(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -806,6 +806,30 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
}),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
PayloadAttributes::V5(pa) => match self.get_fork_at_timestamp(pa.timestamp) {
|
||||
ForkName::Heze => ExecutionPayload::Heze(ExecutionPayloadHeze {
|
||||
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,
|
||||
block_access_list: VariableList::empty(),
|
||||
slot_number: pa.slot_number.into(),
|
||||
}),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
};
|
||||
|
||||
// Store execution requests for this payload if configured.
|
||||
|
||||
@@ -948,6 +948,7 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
expected_withdrawals,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
),
|
||||
ForkName::Deneb | ForkName::Electra | ForkName::Fulu => PayloadAttributes::new(
|
||||
timestamp,
|
||||
@@ -956,6 +957,7 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
expected_withdrawals,
|
||||
Some(head_block_root),
|
||||
None,
|
||||
None,
|
||||
),
|
||||
ForkName::Gloas | ForkName::Heze => PayloadAttributes::new(
|
||||
timestamp,
|
||||
@@ -964,6 +966,7 @@ impl<E: EthSpec> MockBuilder<E> {
|
||||
expected_withdrawals,
|
||||
Some(head_block_root),
|
||||
Some(slot.as_u64()),
|
||||
None,
|
||||
),
|
||||
ForkName::Base | ForkName::Altair => {
|
||||
return Err("invalid fork".to_string());
|
||||
|
||||
@@ -108,6 +108,7 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
// Insert a proposer to ensure the fork choice updated command works.
|
||||
@@ -149,6 +150,7 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
let payload_parameters = PayloadParameters {
|
||||
@@ -202,6 +204,7 @@ impl<E: EthSpec> MockExecutionLayer<E> {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
let payload_parameters = PayloadParameters {
|
||||
|
||||
@@ -61,6 +61,8 @@ pub const DEFAULT_ENGINE_CAPABILITIES: EngineCapabilities = EngineCapabilities {
|
||||
get_blobs_v2: true,
|
||||
get_inclusion_list_v1: true,
|
||||
get_blobs_v3: true,
|
||||
forkchoice_updated_v5: true,
|
||||
is_inclusion_list_satisfied_v1: true,
|
||||
};
|
||||
|
||||
pub static DEFAULT_CLIENT_VERSION: LazyLock<JsonClientVersionV1> =
|
||||
|
||||
Reference in New Issue
Block a user