mirror of
https://github.com/sigp/lighthouse.git
synced 2026-07-03 21:04:28 +00:00
Electra updates for v1.5.0-alpha.6 (#6445)
* Update process_slashing * Update test vectors version * Delete Domain::Consolidation * Rename to get_max_effective_balance * Fix unused; lint * Add the pre-electra slashing processing * lint * Change request json types * Move requests from payload to beacon block body * Refactor engine api * Fix warnings * Update engine api to latest * engine api changed..again * yet again * Merge branch 'engine-requests' into electra-updates * Fix tests * Store reference instead of bytes in NewPayloadRequest * Merge branch 'unstable' into electra-updates * Update beacon_node/execution_layer/src/engine_api/json_structures.rs Co-authored-by: Michael Sproul <micsproul@gmail.com> * Update beacon_node/execution_layer/src/lib.rs Co-authored-by: Michael Sproul <micsproul@gmail.com> * Update beacon_node/execution_layer/src/test_utils/handle_rpc.rs Co-authored-by: Michael Sproul <micsproul@gmail.com>
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -3008,6 +3008,7 @@ dependencies = [
|
||||
"sensitive_url",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.9.9",
|
||||
"slog",
|
||||
"slot_clock",
|
||||
"ssz_types",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{metrics, BeaconChain, BeaconChainError, BeaconChainTypes, BlockProcessStatus};
|
||||
use execution_layer::{ExecutionLayer, ExecutionPayloadBody};
|
||||
use execution_layer::{ExecutionLayer, ExecutionPayloadBodyV1};
|
||||
use slog::{crit, debug, error, Logger};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
@@ -57,7 +57,7 @@ struct BodiesByRange<E: EthSpec> {
|
||||
struct BlockParts<E: EthSpec> {
|
||||
blinded_block: Box<SignedBlindedBeaconBlock<E>>,
|
||||
header: Box<ExecutionPayloadHeader<E>>,
|
||||
body: Option<Box<ExecutionPayloadBody<E>>>,
|
||||
body: Option<Box<ExecutionPayloadBodyV1<E>>>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> BlockParts<E> {
|
||||
|
||||
@@ -5553,10 +5553,15 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
)
|
||||
}
|
||||
BeaconState::Deneb(_) => {
|
||||
let (payload, kzg_commitments, maybe_blobs_and_proofs, execution_payload_value) =
|
||||
block_contents
|
||||
.ok_or(BlockProductionError::MissingExecutionPayload)?
|
||||
.deconstruct();
|
||||
let (
|
||||
payload,
|
||||
kzg_commitments,
|
||||
maybe_blobs_and_proofs,
|
||||
_maybe_requests,
|
||||
execution_payload_value,
|
||||
) = block_contents
|
||||
.ok_or(BlockProductionError::MissingExecutionPayload)?
|
||||
.deconstruct();
|
||||
|
||||
(
|
||||
BeaconBlock::Deneb(BeaconBlockDeneb {
|
||||
@@ -5591,10 +5596,15 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
)
|
||||
}
|
||||
BeaconState::Electra(_) => {
|
||||
let (payload, kzg_commitments, maybe_blobs_and_proofs, execution_payload_value) =
|
||||
block_contents
|
||||
.ok_or(BlockProductionError::MissingExecutionPayload)?
|
||||
.deconstruct();
|
||||
let (
|
||||
payload,
|
||||
kzg_commitments,
|
||||
maybe_blobs_and_proofs,
|
||||
maybe_requests,
|
||||
execution_payload_value,
|
||||
) = block_contents
|
||||
.ok_or(BlockProductionError::MissingExecutionPayload)?
|
||||
.deconstruct();
|
||||
|
||||
(
|
||||
BeaconBlock::Electra(BeaconBlockElectra {
|
||||
@@ -5619,6 +5629,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
bls_to_execution_changes: bls_to_execution_changes.into(),
|
||||
blob_kzg_commitments: kzg_commitments
|
||||
.ok_or(BlockProductionError::InvalidPayloadFork)?,
|
||||
execution_requests: maybe_requests
|
||||
.ok_or(BlockProductionError::MissingExecutionRequests)?,
|
||||
},
|
||||
}),
|
||||
maybe_blobs_and_proofs,
|
||||
|
||||
@@ -294,6 +294,7 @@ pub enum BlockProductionError {
|
||||
InvalidBlockVariant(String),
|
||||
KzgError(kzg::Error),
|
||||
FailedToBuildBlobSidecars(String),
|
||||
MissingExecutionRequests,
|
||||
}
|
||||
|
||||
easy_from_to!(BlockProcessingError, BlockProductionError);
|
||||
|
||||
@@ -52,3 +52,4 @@ alloy-rlp = { workspace = true }
|
||||
alloy-consensus = { workspace = true }
|
||||
lighthouse_version = { workspace = true }
|
||||
fixed_bytes = { workspace = true }
|
||||
sha2 = { workspace = true }
|
||||
|
||||
@@ -2,8 +2,7 @@ use crate::engines::ForkchoiceState;
|
||||
use crate::http::{
|
||||
ENGINE_FORKCHOICE_UPDATED_V1, ENGINE_FORKCHOICE_UPDATED_V2, ENGINE_FORKCHOICE_UPDATED_V3,
|
||||
ENGINE_GET_CLIENT_VERSION_V1, ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1,
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2, ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1,
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V2, ENGINE_GET_PAYLOAD_V1, ENGINE_GET_PAYLOAD_V2,
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1, ENGINE_GET_PAYLOAD_V1, ENGINE_GET_PAYLOAD_V2,
|
||||
ENGINE_GET_PAYLOAD_V3, ENGINE_GET_PAYLOAD_V4, ENGINE_NEW_PAYLOAD_V1, ENGINE_NEW_PAYLOAD_V2,
|
||||
ENGINE_NEW_PAYLOAD_V3, ENGINE_NEW_PAYLOAD_V4,
|
||||
};
|
||||
@@ -18,7 +17,6 @@ use reqwest::StatusCode;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::IntoStaticStr;
|
||||
use superstruct::superstruct;
|
||||
use types::execution_payload::{ConsolidationRequests, DepositRequests, WithdrawalRequests};
|
||||
pub use types::{
|
||||
Address, BeaconBlockRef, ConsolidationRequest, EthSpec, ExecutionBlockHash, ExecutionPayload,
|
||||
ExecutionPayloadHeader, ExecutionPayloadRef, FixedVector, ForkName, Hash256, Transactions,
|
||||
@@ -26,7 +24,7 @@ pub use types::{
|
||||
};
|
||||
use types::{
|
||||
ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb,
|
||||
ExecutionPayloadElectra, KzgProofs,
|
||||
ExecutionPayloadElectra, ExecutionRequests, KzgProofs,
|
||||
};
|
||||
use types::{Graffiti, GRAFFITI_BYTES_LEN};
|
||||
|
||||
@@ -288,6 +286,8 @@ pub struct GetPayloadResponse<E: EthSpec> {
|
||||
pub blobs_bundle: BlobsBundle<E>,
|
||||
#[superstruct(only(Deneb, Electra), partial_getter(copy))]
|
||||
pub should_override_builder: bool,
|
||||
#[superstruct(only(Electra))]
|
||||
pub requests: ExecutionRequests<E>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> GetPayloadResponse<E> {
|
||||
@@ -321,7 +321,12 @@ impl<E: EthSpec> From<GetPayloadResponse<E>> for ExecutionPayload<E> {
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<GetPayloadResponse<E>>
|
||||
for (ExecutionPayload<E>, Uint256, Option<BlobsBundle<E>>)
|
||||
for (
|
||||
ExecutionPayload<E>,
|
||||
Uint256,
|
||||
Option<BlobsBundle<E>>,
|
||||
Option<ExecutionRequests<E>>,
|
||||
)
|
||||
{
|
||||
fn from(response: GetPayloadResponse<E>) -> Self {
|
||||
match response {
|
||||
@@ -329,21 +334,25 @@ impl<E: EthSpec> From<GetPayloadResponse<E>>
|
||||
ExecutionPayload::Bellatrix(inner.execution_payload),
|
||||
inner.block_value,
|
||||
None,
|
||||
None,
|
||||
),
|
||||
GetPayloadResponse::Capella(inner) => (
|
||||
ExecutionPayload::Capella(inner.execution_payload),
|
||||
inner.block_value,
|
||||
None,
|
||||
None,
|
||||
),
|
||||
GetPayloadResponse::Deneb(inner) => (
|
||||
ExecutionPayload::Deneb(inner.execution_payload),
|
||||
inner.block_value,
|
||||
Some(inner.blobs_bundle),
|
||||
None,
|
||||
),
|
||||
GetPayloadResponse::Electra(inner) => (
|
||||
ExecutionPayload::Electra(inner.execution_payload),
|
||||
inner.block_value,
|
||||
Some(inner.blobs_bundle),
|
||||
Some(inner.requests),
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -360,106 +369,25 @@ impl<E: EthSpec> GetPayloadResponse<E> {
|
||||
}
|
||||
}
|
||||
|
||||
#[superstruct(
|
||||
variants(V1, V2),
|
||||
variant_attributes(derive(Clone, Debug),),
|
||||
partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant")
|
||||
)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ExecutionPayloadBody<E: EthSpec> {
|
||||
pub struct ExecutionPayloadBodyV1<E: EthSpec> {
|
||||
pub transactions: Transactions<E>,
|
||||
pub withdrawals: Option<Withdrawals<E>>,
|
||||
#[superstruct(only(V2))]
|
||||
pub deposit_requests: Option<DepositRequests<E>>,
|
||||
#[superstruct(only(V2))]
|
||||
pub withdrawal_requests: Option<WithdrawalRequests<E>>,
|
||||
#[superstruct(only(V2))]
|
||||
pub consolidation_requests: Option<ConsolidationRequests<E>>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> ExecutionPayloadBody<E> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn deconstruct(
|
||||
self,
|
||||
) -> (
|
||||
Transactions<E>,
|
||||
Option<Withdrawals<E>>,
|
||||
Option<DepositRequests<E>>,
|
||||
Option<WithdrawalRequests<E>>,
|
||||
Option<ConsolidationRequests<E>>,
|
||||
) {
|
||||
match self {
|
||||
ExecutionPayloadBody::V1(body) => {
|
||||
(body.transactions, body.withdrawals, None, None, None)
|
||||
}
|
||||
ExecutionPayloadBody::V2(body) => (
|
||||
body.transactions,
|
||||
body.withdrawals,
|
||||
body.deposit_requests,
|
||||
body.withdrawal_requests,
|
||||
body.consolidation_requests,
|
||||
),
|
||||
}
|
||||
}
|
||||
impl<E: EthSpec> ExecutionPayloadBodyV1<E> {
|
||||
pub fn to_payload(
|
||||
self,
|
||||
header: ExecutionPayloadHeader<E>,
|
||||
) -> Result<ExecutionPayload<E>, String> {
|
||||
let header_fork = header.fork_name_unchecked();
|
||||
match &self {
|
||||
Self::V1(_) => {
|
||||
if header_fork.electra_enabled() {
|
||||
return Err(format!(
|
||||
"block {} is {} but response is ExecutionPayloadBodyV1. Does the EL support {}?",
|
||||
header.block_hash(),
|
||||
header_fork,
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2,
|
||||
));
|
||||
}
|
||||
}
|
||||
Self::V2(_) => {}
|
||||
}
|
||||
|
||||
let (
|
||||
transactions,
|
||||
withdrawals,
|
||||
deposit_requests,
|
||||
withdrawal_requests,
|
||||
consolidation_requests,
|
||||
) = self.deconstruct();
|
||||
if !header_fork.capella_enabled() && withdrawals.is_some() {
|
||||
return Err(format!(
|
||||
"block {} is {} but payload body has withdrawals",
|
||||
header.block_hash(),
|
||||
header_fork
|
||||
));
|
||||
}
|
||||
if !header_fork.electra_enabled() {
|
||||
if deposit_requests.is_some() {
|
||||
return Err(format!(
|
||||
"block {} is {} but payload body has deposit_requests",
|
||||
header.block_hash(),
|
||||
header_fork
|
||||
));
|
||||
}
|
||||
if withdrawal_requests.is_some() {
|
||||
return Err(format!(
|
||||
"block {} is {} but payload body has withdrawal_requests",
|
||||
header.block_hash(),
|
||||
header_fork
|
||||
));
|
||||
}
|
||||
if consolidation_requests.is_some() {
|
||||
return Err(format!(
|
||||
"block {} is {} but payload body has consolidation_requests",
|
||||
header.block_hash(),
|
||||
header_fork
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
match header {
|
||||
ExecutionPayloadHeader::Bellatrix(header) => {
|
||||
if self.withdrawals.is_some() {
|
||||
return Err(format!(
|
||||
"block {} is bellatrix but payload body has withdrawals",
|
||||
header.block_hash
|
||||
));
|
||||
}
|
||||
Ok(ExecutionPayload::Bellatrix(ExecutionPayloadBellatrix {
|
||||
parent_hash: header.parent_hash,
|
||||
fee_recipient: header.fee_recipient,
|
||||
@@ -474,108 +402,90 @@ impl<E: EthSpec> ExecutionPayloadBody<E> {
|
||||
extra_data: header.extra_data,
|
||||
base_fee_per_gas: header.base_fee_per_gas,
|
||||
block_hash: header.block_hash,
|
||||
transactions,
|
||||
transactions: self.transactions,
|
||||
}))
|
||||
}
|
||||
ExecutionPayloadHeader::Capella(header) => {
|
||||
let withdrawals = withdrawals.ok_or_else(|| {
|
||||
format!(
|
||||
"block {} is {} but payload body has withdrawals set to null",
|
||||
header.block_hash, header_fork
|
||||
)
|
||||
})?;
|
||||
Ok(ExecutionPayload::Capella(ExecutionPayloadCapella {
|
||||
parent_hash: header.parent_hash,
|
||||
fee_recipient: header.fee_recipient,
|
||||
state_root: header.state_root,
|
||||
receipts_root: header.receipts_root,
|
||||
logs_bloom: header.logs_bloom,
|
||||
prev_randao: header.prev_randao,
|
||||
block_number: header.block_number,
|
||||
gas_limit: header.gas_limit,
|
||||
gas_used: header.gas_used,
|
||||
timestamp: header.timestamp,
|
||||
extra_data: header.extra_data,
|
||||
base_fee_per_gas: header.base_fee_per_gas,
|
||||
block_hash: header.block_hash,
|
||||
transactions,
|
||||
withdrawals,
|
||||
}))
|
||||
if let Some(withdrawals) = self.withdrawals {
|
||||
Ok(ExecutionPayload::Capella(ExecutionPayloadCapella {
|
||||
parent_hash: header.parent_hash,
|
||||
fee_recipient: header.fee_recipient,
|
||||
state_root: header.state_root,
|
||||
receipts_root: header.receipts_root,
|
||||
logs_bloom: header.logs_bloom,
|
||||
prev_randao: header.prev_randao,
|
||||
block_number: header.block_number,
|
||||
gas_limit: header.gas_limit,
|
||||
gas_used: header.gas_used,
|
||||
timestamp: header.timestamp,
|
||||
extra_data: header.extra_data,
|
||||
base_fee_per_gas: header.base_fee_per_gas,
|
||||
block_hash: header.block_hash,
|
||||
transactions: self.transactions,
|
||||
withdrawals,
|
||||
}))
|
||||
} else {
|
||||
Err(format!(
|
||||
"block {} is capella but payload body doesn't have withdrawals",
|
||||
header.block_hash
|
||||
))
|
||||
}
|
||||
}
|
||||
ExecutionPayloadHeader::Deneb(header) => {
|
||||
let withdrawals = withdrawals.ok_or_else(|| {
|
||||
format!(
|
||||
"block {} is {} but payload body has withdrawals set to null",
|
||||
header.block_hash, header_fork
|
||||
)
|
||||
})?;
|
||||
Ok(ExecutionPayload::Deneb(ExecutionPayloadDeneb {
|
||||
parent_hash: header.parent_hash,
|
||||
fee_recipient: header.fee_recipient,
|
||||
state_root: header.state_root,
|
||||
receipts_root: header.receipts_root,
|
||||
logs_bloom: header.logs_bloom,
|
||||
prev_randao: header.prev_randao,
|
||||
block_number: header.block_number,
|
||||
gas_limit: header.gas_limit,
|
||||
gas_used: header.gas_used,
|
||||
timestamp: header.timestamp,
|
||||
extra_data: header.extra_data,
|
||||
base_fee_per_gas: header.base_fee_per_gas,
|
||||
block_hash: header.block_hash,
|
||||
transactions,
|
||||
withdrawals,
|
||||
blob_gas_used: header.blob_gas_used,
|
||||
excess_blob_gas: header.excess_blob_gas,
|
||||
}))
|
||||
if let Some(withdrawals) = self.withdrawals {
|
||||
Ok(ExecutionPayload::Deneb(ExecutionPayloadDeneb {
|
||||
parent_hash: header.parent_hash,
|
||||
fee_recipient: header.fee_recipient,
|
||||
state_root: header.state_root,
|
||||
receipts_root: header.receipts_root,
|
||||
logs_bloom: header.logs_bloom,
|
||||
prev_randao: header.prev_randao,
|
||||
block_number: header.block_number,
|
||||
gas_limit: header.gas_limit,
|
||||
gas_used: header.gas_used,
|
||||
timestamp: header.timestamp,
|
||||
extra_data: header.extra_data,
|
||||
base_fee_per_gas: header.base_fee_per_gas,
|
||||
block_hash: header.block_hash,
|
||||
transactions: self.transactions,
|
||||
withdrawals,
|
||||
blob_gas_used: header.blob_gas_used,
|
||||
excess_blob_gas: header.excess_blob_gas,
|
||||
}))
|
||||
} else {
|
||||
Err(format!(
|
||||
"block {} is post capella but payload body doesn't have withdrawals",
|
||||
header.block_hash
|
||||
))
|
||||
}
|
||||
}
|
||||
ExecutionPayloadHeader::Electra(header) => {
|
||||
let withdrawals = withdrawals.ok_or_else(|| {
|
||||
format!(
|
||||
"block {} is {} but payload body has withdrawals set to null",
|
||||
header.block_hash, header_fork
|
||||
)
|
||||
})?;
|
||||
let deposit_requests = deposit_requests.ok_or_else(|| {
|
||||
format!(
|
||||
"block {} is {} but payload body has deposit_requests set to null",
|
||||
header.block_hash, header_fork
|
||||
)
|
||||
})?;
|
||||
let withdrawal_requests = withdrawal_requests.ok_or_else(|| {
|
||||
format!(
|
||||
"block {} is {} but payload body has withdrawal_requests set to null",
|
||||
header.block_hash, header_fork
|
||||
)
|
||||
})?;
|
||||
let consolidation_requests = consolidation_requests.ok_or_else(|| {
|
||||
format!(
|
||||
"block {} is {} but payload body has consolidation_requests set to null",
|
||||
header.block_hash, header_fork
|
||||
)
|
||||
})?;
|
||||
Ok(ExecutionPayload::Electra(ExecutionPayloadElectra {
|
||||
parent_hash: header.parent_hash,
|
||||
fee_recipient: header.fee_recipient,
|
||||
state_root: header.state_root,
|
||||
receipts_root: header.receipts_root,
|
||||
logs_bloom: header.logs_bloom,
|
||||
prev_randao: header.prev_randao,
|
||||
block_number: header.block_number,
|
||||
gas_limit: header.gas_limit,
|
||||
gas_used: header.gas_used,
|
||||
timestamp: header.timestamp,
|
||||
extra_data: header.extra_data,
|
||||
base_fee_per_gas: header.base_fee_per_gas,
|
||||
block_hash: header.block_hash,
|
||||
transactions,
|
||||
withdrawals,
|
||||
blob_gas_used: header.blob_gas_used,
|
||||
excess_blob_gas: header.excess_blob_gas,
|
||||
deposit_requests,
|
||||
withdrawal_requests,
|
||||
consolidation_requests,
|
||||
}))
|
||||
if let Some(withdrawals) = self.withdrawals {
|
||||
Ok(ExecutionPayload::Electra(ExecutionPayloadElectra {
|
||||
parent_hash: header.parent_hash,
|
||||
fee_recipient: header.fee_recipient,
|
||||
state_root: header.state_root,
|
||||
receipts_root: header.receipts_root,
|
||||
logs_bloom: header.logs_bloom,
|
||||
prev_randao: header.prev_randao,
|
||||
block_number: header.block_number,
|
||||
gas_limit: header.gas_limit,
|
||||
gas_used: header.gas_used,
|
||||
timestamp: header.timestamp,
|
||||
extra_data: header.extra_data,
|
||||
base_fee_per_gas: header.base_fee_per_gas,
|
||||
block_hash: header.block_hash,
|
||||
transactions: self.transactions,
|
||||
withdrawals,
|
||||
blob_gas_used: header.blob_gas_used,
|
||||
excess_blob_gas: header.excess_blob_gas,
|
||||
}))
|
||||
} else {
|
||||
Err(format!(
|
||||
"block {} is post capella but payload body doesn't have withdrawals",
|
||||
header.block_hash
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -592,8 +502,6 @@ pub struct EngineCapabilities {
|
||||
pub forkchoice_updated_v3: bool,
|
||||
pub get_payload_bodies_by_hash_v1: bool,
|
||||
pub get_payload_bodies_by_range_v1: bool,
|
||||
pub get_payload_bodies_by_hash_v2: bool,
|
||||
pub get_payload_bodies_by_range_v2: bool,
|
||||
pub get_payload_v1: bool,
|
||||
pub get_payload_v2: bool,
|
||||
pub get_payload_v3: bool,
|
||||
@@ -631,12 +539,6 @@ impl EngineCapabilities {
|
||||
if self.get_payload_bodies_by_range_v1 {
|
||||
response.push(ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1);
|
||||
}
|
||||
if self.get_payload_bodies_by_hash_v2 {
|
||||
response.push(ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2);
|
||||
}
|
||||
if self.get_payload_bodies_by_range_v2 {
|
||||
response.push(ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V2);
|
||||
}
|
||||
if self.get_payload_v1 {
|
||||
response.push(ENGINE_GET_PAYLOAD_V1);
|
||||
}
|
||||
|
||||
@@ -50,8 +50,6 @@ pub const ENGINE_FORKCHOICE_UPDATED_TIMEOUT: Duration = Duration::from_secs(8);
|
||||
|
||||
pub const ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1: &str = "engine_getPayloadBodiesByHashV1";
|
||||
pub const ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1: &str = "engine_getPayloadBodiesByRangeV1";
|
||||
pub const ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2: &str = "engine_getPayloadBodiesByHashV2";
|
||||
pub const ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V2: &str = "engine_getPayloadBodiesByRangeV2";
|
||||
pub const ENGINE_GET_PAYLOAD_BODIES_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
|
||||
pub const ENGINE_EXCHANGE_CAPABILITIES: &str = "engine_exchangeCapabilities";
|
||||
@@ -80,8 +78,6 @@ pub static LIGHTHOUSE_CAPABILITIES: &[&str] = &[
|
||||
ENGINE_FORKCHOICE_UPDATED_V3,
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1,
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1,
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2,
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V2,
|
||||
ENGINE_GET_CLIENT_VERSION_V1,
|
||||
];
|
||||
|
||||
@@ -797,6 +793,9 @@ impl HttpJsonRpc {
|
||||
JsonExecutionPayload::V4(new_payload_request_electra.execution_payload.clone().into()),
|
||||
new_payload_request_electra.versioned_hashes,
|
||||
new_payload_request_electra.parent_beacon_block_root,
|
||||
new_payload_request_electra
|
||||
.execution_requests_list
|
||||
.get_execution_requests_list(),
|
||||
]);
|
||||
|
||||
let response: JsonPayloadStatusV1 = self
|
||||
@@ -849,7 +848,9 @@ impl HttpJsonRpc {
|
||||
ENGINE_GET_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
Ok(JsonGetPayloadResponse::V1(response).into())
|
||||
JsonGetPayloadResponse::V1(response)
|
||||
.try_into()
|
||||
.map_err(Error::BadResponse)
|
||||
}
|
||||
ForkName::Capella => {
|
||||
let response: JsonGetPayloadResponseV2<E> = self
|
||||
@@ -859,7 +860,9 @@ impl HttpJsonRpc {
|
||||
ENGINE_GET_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
Ok(JsonGetPayloadResponse::V2(response).into())
|
||||
JsonGetPayloadResponse::V2(response)
|
||||
.try_into()
|
||||
.map_err(Error::BadResponse)
|
||||
}
|
||||
ForkName::Base | ForkName::Altair | ForkName::Deneb | ForkName::Electra => Err(
|
||||
Error::UnsupportedForkVariant(format!("called get_payload_v2 with {}", fork_name)),
|
||||
@@ -883,7 +886,9 @@ impl HttpJsonRpc {
|
||||
ENGINE_GET_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
Ok(JsonGetPayloadResponse::V3(response).into())
|
||||
JsonGetPayloadResponse::V3(response)
|
||||
.try_into()
|
||||
.map_err(Error::BadResponse)
|
||||
}
|
||||
ForkName::Base
|
||||
| ForkName::Altair
|
||||
@@ -912,7 +917,9 @@ impl HttpJsonRpc {
|
||||
ENGINE_GET_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
Ok(JsonGetPayloadResponse::V4(response).into())
|
||||
JsonGetPayloadResponse::V4(response)
|
||||
.try_into()
|
||||
.map_err(Error::BadResponse)
|
||||
}
|
||||
ForkName::Base
|
||||
| ForkName::Altair
|
||||
@@ -991,7 +998,7 @@ impl HttpJsonRpc {
|
||||
pub async fn get_payload_bodies_by_hash_v1<E: EthSpec>(
|
||||
&self,
|
||||
block_hashes: Vec<ExecutionBlockHash>,
|
||||
) -> Result<Vec<Option<ExecutionPayloadBody<E>>>, Error> {
|
||||
) -> Result<Vec<Option<ExecutionPayloadBodyV1<E>>>, Error> {
|
||||
let params = json!([block_hashes]);
|
||||
|
||||
let response: Vec<Option<JsonExecutionPayloadBodyV1<E>>> = self
|
||||
@@ -1004,27 +1011,7 @@ impl HttpJsonRpc {
|
||||
|
||||
Ok(response
|
||||
.into_iter()
|
||||
.map(|opt_json| opt_json.map(|v1| JsonExecutionPayloadBody::V1(v1).into()))
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub async fn get_payload_bodies_by_hash_v2<E: EthSpec>(
|
||||
&self,
|
||||
block_hashes: Vec<ExecutionBlockHash>,
|
||||
) -> Result<Vec<Option<ExecutionPayloadBody<E>>>, Error> {
|
||||
let params = json!([block_hashes]);
|
||||
|
||||
let response: Vec<Option<JsonExecutionPayloadBodyV2<E>>> = self
|
||||
.rpc_request(
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2,
|
||||
params,
|
||||
ENGINE_GET_PAYLOAD_BODIES_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(response
|
||||
.into_iter()
|
||||
.map(|opt_json| opt_json.map(|v2| JsonExecutionPayloadBody::V2(v2).into()))
|
||||
.map(|opt_json| opt_json.map(From::from))
|
||||
.collect())
|
||||
}
|
||||
|
||||
@@ -1032,7 +1019,7 @@ impl HttpJsonRpc {
|
||||
&self,
|
||||
start: u64,
|
||||
count: u64,
|
||||
) -> Result<Vec<Option<ExecutionPayloadBody<E>>>, Error> {
|
||||
) -> Result<Vec<Option<ExecutionPayloadBodyV1<E>>>, Error> {
|
||||
#[derive(Serialize)]
|
||||
#[serde(transparent)]
|
||||
struct Quantity(#[serde(with = "serde_utils::u64_hex_be")] u64);
|
||||
@@ -1048,31 +1035,7 @@ impl HttpJsonRpc {
|
||||
|
||||
Ok(response
|
||||
.into_iter()
|
||||
.map(|opt_json| opt_json.map(|v1| JsonExecutionPayloadBody::V1(v1).into()))
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub async fn get_payload_bodies_by_range_v2<E: EthSpec>(
|
||||
&self,
|
||||
start: u64,
|
||||
count: u64,
|
||||
) -> Result<Vec<Option<ExecutionPayloadBody<E>>>, Error> {
|
||||
#[derive(Serialize)]
|
||||
#[serde(transparent)]
|
||||
struct Quantity(#[serde(with = "serde_utils::u64_hex_be")] u64);
|
||||
|
||||
let params = json!([Quantity(start), Quantity(count)]);
|
||||
let response: Vec<Option<JsonExecutionPayloadBodyV2<E>>> = self
|
||||
.rpc_request(
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V2,
|
||||
params,
|
||||
ENGINE_GET_PAYLOAD_BODIES_TIMEOUT * self.execution_timeout_multiplier,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(response
|
||||
.into_iter()
|
||||
.map(|opt_json| opt_json.map(|v2| JsonExecutionPayloadBody::V2(v2).into()))
|
||||
.map(|opt_json| opt_json.map(From::from))
|
||||
.collect())
|
||||
}
|
||||
|
||||
@@ -1099,10 +1062,6 @@ impl HttpJsonRpc {
|
||||
.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_bodies_by_hash_v2: capabilities
|
||||
.contains(ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V2),
|
||||
get_payload_bodies_by_range_v2: capabilities
|
||||
.contains(ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V2),
|
||||
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),
|
||||
@@ -1278,39 +1237,6 @@ impl HttpJsonRpc {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_payload_bodies_by_hash<E: EthSpec>(
|
||||
&self,
|
||||
block_hashes: Vec<ExecutionBlockHash>,
|
||||
) -> Result<Vec<Option<ExecutionPayloadBody<E>>>, Error> {
|
||||
let engine_capabilities = self.get_engine_capabilities(None).await?;
|
||||
if engine_capabilities.get_payload_bodies_by_hash_v2 {
|
||||
self.get_payload_bodies_by_hash_v2(block_hashes).await
|
||||
} else if engine_capabilities.get_payload_bodies_by_hash_v1 {
|
||||
self.get_payload_bodies_by_hash_v1(block_hashes).await
|
||||
} else {
|
||||
Err(Error::RequiredMethodUnsupported(
|
||||
"engine_getPayloadBodiesByHash",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_payload_bodies_by_range<E: EthSpec>(
|
||||
&self,
|
||||
start: u64,
|
||||
count: u64,
|
||||
) -> Result<Vec<Option<ExecutionPayloadBody<E>>>, Error> {
|
||||
let engine_capabilities = self.get_engine_capabilities(None).await?;
|
||||
if engine_capabilities.get_payload_bodies_by_range_v2 {
|
||||
self.get_payload_bodies_by_range_v2(start, count).await
|
||||
} else if engine_capabilities.get_payload_bodies_by_range_v1 {
|
||||
self.get_payload_bodies_by_range_v1(start, count).await
|
||||
} else {
|
||||
Err(Error::RequiredMethodUnsupported(
|
||||
"engine_getPayloadBodiesByRange",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
// automatically selects the latest version of
|
||||
// forkchoice_updated that the execution engine supports
|
||||
pub async fn forkchoice_updated(
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
use super::*;
|
||||
use alloy_rlp::RlpEncodable;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Decode;
|
||||
use strum::EnumString;
|
||||
use superstruct::superstruct;
|
||||
use types::beacon_block_body::KzgCommitments;
|
||||
use types::blob_sidecar::BlobsList;
|
||||
use types::{DepositRequest, FixedVector, PublicKeyBytes, Signature, Unsigned, WithdrawalRequest};
|
||||
use types::execution_requests::{ConsolidationRequests, DepositRequests, WithdrawalRequests};
|
||||
use types::{FixedVector, Unsigned};
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -104,14 +106,6 @@ pub struct JsonExecutionPayload<E: EthSpec> {
|
||||
#[superstruct(only(V3, V4))]
|
||||
#[serde(with = "serde_utils::u64_hex_be")]
|
||||
pub excess_blob_gas: u64,
|
||||
#[superstruct(only(V4))]
|
||||
pub deposit_requests: VariableList<JsonDepositRequest, E::MaxDepositRequestsPerPayload>,
|
||||
#[superstruct(only(V4))]
|
||||
pub withdrawal_requests:
|
||||
VariableList<JsonWithdrawalRequest, E::MaxWithdrawalRequestsPerPayload>,
|
||||
#[superstruct(only(V4))]
|
||||
pub consolidation_requests:
|
||||
VariableList<JsonConsolidationRequest, E::MaxConsolidationRequestsPerPayload>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<ExecutionPayloadBellatrix<E>> for JsonExecutionPayloadV1<E> {
|
||||
@@ -214,24 +208,6 @@ impl<E: EthSpec> From<ExecutionPayloadElectra<E>> for JsonExecutionPayloadV4<E>
|
||||
.into(),
|
||||
blob_gas_used: payload.blob_gas_used,
|
||||
excess_blob_gas: payload.excess_blob_gas,
|
||||
deposit_requests: payload
|
||||
.deposit_requests
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
withdrawal_requests: payload
|
||||
.withdrawal_requests
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
consolidation_requests: payload
|
||||
.consolidation_requests
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -348,24 +324,6 @@ impl<E: EthSpec> From<JsonExecutionPayloadV4<E>> for ExecutionPayloadElectra<E>
|
||||
.into(),
|
||||
blob_gas_used: payload.blob_gas_used,
|
||||
excess_blob_gas: payload.excess_blob_gas,
|
||||
deposit_requests: payload
|
||||
.deposit_requests
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
withdrawal_requests: payload
|
||||
.withdrawal_requests
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
consolidation_requests: payload
|
||||
.consolidation_requests
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>()
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -381,6 +339,71 @@ impl<E: EthSpec> From<JsonExecutionPayload<E>> for ExecutionPayload<E> {
|
||||
}
|
||||
}
|
||||
|
||||
/// This is used to index into the `execution_requests` array.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum RequestPrefix {
|
||||
Deposit,
|
||||
Withdrawal,
|
||||
Consolidation,
|
||||
}
|
||||
|
||||
impl RequestPrefix {
|
||||
pub fn from_prefix(prefix: u8) -> Option<Self> {
|
||||
match prefix {
|
||||
0 => Some(Self::Deposit),
|
||||
1 => Some(Self::Withdrawal),
|
||||
2 => Some(Self::Consolidation),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Format of `ExecutionRequests` received over the engine api.
|
||||
///
|
||||
/// Array of ssz-encoded requests list encoded as hex bytes.
|
||||
/// The prefix of the request type is used to index into the array.
|
||||
///
|
||||
/// For e.g. [0xab, 0xcd, 0xef]
|
||||
/// Here, 0xab are the deposits bytes (prefix and index == 0)
|
||||
/// 0xcd are the withdrawals bytes (prefix and index == 1)
|
||||
/// 0xef are the consolidations bytes (prefix and index == 2)
|
||||
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct JsonExecutionRequests(pub Vec<String>);
|
||||
|
||||
impl<E: EthSpec> TryFrom<JsonExecutionRequests> for ExecutionRequests<E> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(value: JsonExecutionRequests) -> Result<Self, Self::Error> {
|
||||
let mut requests = ExecutionRequests::default();
|
||||
|
||||
for (i, request) in value.0.into_iter().enumerate() {
|
||||
// hex string
|
||||
let decoded_bytes = hex::decode(request).map_err(|e| format!("Invalid hex {:?}", e))?;
|
||||
match RequestPrefix::from_prefix(i as u8) {
|
||||
Some(RequestPrefix::Deposit) => {
|
||||
requests.deposits = DepositRequests::<E>::from_ssz_bytes(&decoded_bytes)
|
||||
.map_err(|e| format!("Failed to decode DepositRequest from EL: {:?}", e))?;
|
||||
}
|
||||
Some(RequestPrefix::Withdrawal) => {
|
||||
requests.withdrawals = WithdrawalRequests::<E>::from_ssz_bytes(&decoded_bytes)
|
||||
.map_err(|e| {
|
||||
format!("Failed to decode WithdrawalRequest from EL: {:?}", e)
|
||||
})?;
|
||||
}
|
||||
Some(RequestPrefix::Consolidation) => {
|
||||
requests.consolidations =
|
||||
ConsolidationRequests::<E>::from_ssz_bytes(&decoded_bytes).map_err(
|
||||
|e| format!("Failed to decode ConsolidationRequest from EL: {:?}", e),
|
||||
)?;
|
||||
}
|
||||
None => return Err("Empty requests string".to_string()),
|
||||
}
|
||||
}
|
||||
Ok(requests)
|
||||
}
|
||||
}
|
||||
|
||||
#[superstruct(
|
||||
variants(V1, V2, V3, V4),
|
||||
variant_attributes(
|
||||
@@ -407,38 +430,42 @@ pub struct JsonGetPayloadResponse<E: EthSpec> {
|
||||
pub blobs_bundle: JsonBlobsBundleV1<E>,
|
||||
#[superstruct(only(V3, V4))]
|
||||
pub should_override_builder: bool,
|
||||
#[superstruct(only(V4))]
|
||||
pub requests: JsonExecutionRequests,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<JsonGetPayloadResponse<E>> for GetPayloadResponse<E> {
|
||||
fn from(json_get_payload_response: JsonGetPayloadResponse<E>) -> Self {
|
||||
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) => {
|
||||
GetPayloadResponse::Bellatrix(GetPayloadResponseBellatrix {
|
||||
Ok(GetPayloadResponse::Bellatrix(GetPayloadResponseBellatrix {
|
||||
execution_payload: response.execution_payload.into(),
|
||||
block_value: response.block_value,
|
||||
})
|
||||
}))
|
||||
}
|
||||
JsonGetPayloadResponse::V2(response) => {
|
||||
GetPayloadResponse::Capella(GetPayloadResponseCapella {
|
||||
Ok(GetPayloadResponse::Capella(GetPayloadResponseCapella {
|
||||
execution_payload: response.execution_payload.into(),
|
||||
block_value: response.block_value,
|
||||
})
|
||||
}))
|
||||
}
|
||||
JsonGetPayloadResponse::V3(response) => {
|
||||
GetPayloadResponse::Deneb(GetPayloadResponseDeneb {
|
||||
Ok(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,
|
||||
})
|
||||
}))
|
||||
}
|
||||
JsonGetPayloadResponse::V4(response) => {
|
||||
GetPayloadResponse::Electra(GetPayloadResponseElectra {
|
||||
Ok(GetPayloadResponse::Electra(GetPayloadResponseElectra {
|
||||
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.requests.try_into()?,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -754,122 +781,36 @@ impl From<ForkchoiceUpdatedResponse> for JsonForkchoiceUpdatedV1Response {
|
||||
}
|
||||
}
|
||||
|
||||
#[superstruct(
|
||||
variants(V1, V2),
|
||||
variant_attributes(
|
||||
derive(Clone, Debug, Serialize, Deserialize),
|
||||
serde(bound = "E: EthSpec", rename_all = "camelCase"),
|
||||
),
|
||||
partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant")
|
||||
)]
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
#[serde(bound = "E: EthSpec", rename_all = "camelCase", untagged)]
|
||||
pub struct JsonExecutionPayloadBody<E: EthSpec> {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
pub struct JsonExecutionPayloadBodyV1<E: EthSpec> {
|
||||
#[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")]
|
||||
pub transactions: Transactions<E>,
|
||||
pub withdrawals: Option<VariableList<JsonWithdrawal, E::MaxWithdrawalsPerPayload>>,
|
||||
#[superstruct(only(V2))]
|
||||
pub deposit_requests: Option<VariableList<JsonDepositRequest, E::MaxDepositRequestsPerPayload>>,
|
||||
#[superstruct(only(V2))]
|
||||
pub withdrawal_requests:
|
||||
Option<VariableList<JsonWithdrawalRequest, E::MaxWithdrawalRequestsPerPayload>>,
|
||||
#[superstruct(only(V2))]
|
||||
pub consolidation_requests:
|
||||
Option<VariableList<ConsolidationRequest, E::MaxConsolidationRequestsPerPayload>>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<JsonExecutionPayloadBodyV1<E>> for ExecutionPayloadBodyV1<E> {
|
||||
fn from(value: JsonExecutionPayloadBodyV1<E>) -> Self {
|
||||
Self {
|
||||
transactions: value.transactions,
|
||||
withdrawals: value.withdrawals.map(|json_withdrawals| {
|
||||
Withdrawals::<E>::from(
|
||||
json_withdrawals
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<ExecutionPayloadBodyV1<E>> for JsonExecutionPayloadBodyV1<E> {
|
||||
fn from(value: ExecutionPayloadBodyV1<E>) -> Self {
|
||||
Self {
|
||||
transactions: value.transactions,
|
||||
withdrawals: value.withdrawals.map(|json_withdrawals| {
|
||||
VariableList::from(
|
||||
json_withdrawals
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<ExecutionPayloadBodyV2<E>> for JsonExecutionPayloadBodyV2<E> {
|
||||
fn from(value: ExecutionPayloadBodyV2<E>) -> Self {
|
||||
Self {
|
||||
transactions: value.transactions,
|
||||
withdrawals: value.withdrawals.map(|json_withdrawals| {
|
||||
VariableList::from(
|
||||
json_withdrawals
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
}),
|
||||
deposit_requests: value.deposit_requests.map(|receipts| {
|
||||
VariableList::from(receipts.into_iter().map(Into::into).collect::<Vec<_>>())
|
||||
}),
|
||||
withdrawal_requests: value.withdrawal_requests.map(|withdrawal_requests| {
|
||||
VariableList::from(
|
||||
withdrawal_requests
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
}),
|
||||
consolidation_requests: value.consolidation_requests.map(|consolidation_requests| {
|
||||
VariableList::from(
|
||||
consolidation_requests
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<JsonExecutionPayloadBody<E>> for ExecutionPayloadBody<E> {
|
||||
fn from(value: JsonExecutionPayloadBody<E>) -> Self {
|
||||
match value {
|
||||
JsonExecutionPayloadBody::V1(body_v1) => Self::V1(ExecutionPayloadBodyV1 {
|
||||
transactions: body_v1.transactions,
|
||||
withdrawals: body_v1.withdrawals.map(|json_withdrawals| {
|
||||
Withdrawals::<E>::from(
|
||||
json_withdrawals
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
}),
|
||||
}),
|
||||
JsonExecutionPayloadBody::V2(body_v2) => Self::V2(ExecutionPayloadBodyV2 {
|
||||
transactions: body_v2.transactions,
|
||||
withdrawals: body_v2.withdrawals.map(|json_withdrawals| {
|
||||
Withdrawals::<E>::from(
|
||||
json_withdrawals
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
}),
|
||||
deposit_requests: body_v2.deposit_requests.map(|json_receipts| {
|
||||
DepositRequests::<E>::from(
|
||||
json_receipts
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
}),
|
||||
withdrawal_requests: body_v2.withdrawal_requests.map(|json_withdrawal_requests| {
|
||||
WithdrawalRequests::<E>::from(
|
||||
json_withdrawal_requests
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
}),
|
||||
consolidation_requests: body_v2.consolidation_requests,
|
||||
withdrawals: value.withdrawals.map(|withdrawals| {
|
||||
VariableList::from(withdrawals.into_iter().map(Into::into).collect::<Vec<_>>())
|
||||
}),
|
||||
}
|
||||
}
|
||||
@@ -950,96 +891,3 @@ impl TryFrom<JsonClientVersionV1> for ClientVersionV1 {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JsonDepositRequest {
|
||||
pub pubkey: PublicKeyBytes,
|
||||
pub withdrawal_credentials: Hash256,
|
||||
#[serde(with = "serde_utils::u64_hex_be")]
|
||||
pub amount: u64,
|
||||
pub signature: Signature,
|
||||
#[serde(with = "serde_utils::u64_hex_be")]
|
||||
pub index: u64,
|
||||
}
|
||||
|
||||
impl From<DepositRequest> for JsonDepositRequest {
|
||||
fn from(deposit: DepositRequest) -> Self {
|
||||
Self {
|
||||
pubkey: deposit.pubkey,
|
||||
withdrawal_credentials: deposit.withdrawal_credentials,
|
||||
amount: deposit.amount,
|
||||
signature: deposit.signature,
|
||||
index: deposit.index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JsonDepositRequest> for DepositRequest {
|
||||
fn from(json_deposit: JsonDepositRequest) -> Self {
|
||||
Self {
|
||||
pubkey: json_deposit.pubkey,
|
||||
withdrawal_credentials: json_deposit.withdrawal_credentials,
|
||||
amount: json_deposit.amount,
|
||||
signature: json_deposit.signature,
|
||||
index: json_deposit.index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JsonWithdrawalRequest {
|
||||
pub source_address: Address,
|
||||
pub validator_pubkey: PublicKeyBytes,
|
||||
#[serde(with = "serde_utils::u64_hex_be")]
|
||||
pub amount: u64,
|
||||
}
|
||||
|
||||
impl From<WithdrawalRequest> for JsonWithdrawalRequest {
|
||||
fn from(withdrawal_request: WithdrawalRequest) -> Self {
|
||||
Self {
|
||||
source_address: withdrawal_request.source_address,
|
||||
validator_pubkey: withdrawal_request.validator_pubkey,
|
||||
amount: withdrawal_request.amount,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JsonWithdrawalRequest> for WithdrawalRequest {
|
||||
fn from(json_withdrawal_request: JsonWithdrawalRequest) -> Self {
|
||||
Self {
|
||||
source_address: json_withdrawal_request.source_address,
|
||||
validator_pubkey: json_withdrawal_request.validator_pubkey,
|
||||
amount: json_withdrawal_request.amount,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JsonConsolidationRequest {
|
||||
pub source_address: Address,
|
||||
pub source_pubkey: PublicKeyBytes,
|
||||
pub target_pubkey: PublicKeyBytes,
|
||||
}
|
||||
|
||||
impl From<ConsolidationRequest> for JsonConsolidationRequest {
|
||||
fn from(consolidation_request: ConsolidationRequest) -> Self {
|
||||
Self {
|
||||
source_address: consolidation_request.source_address,
|
||||
source_pubkey: consolidation_request.source_pubkey,
|
||||
target_pubkey: consolidation_request.target_pubkey,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JsonConsolidationRequest> for ConsolidationRequest {
|
||||
fn from(json_consolidation_request: JsonConsolidationRequest) -> Self {
|
||||
Self {
|
||||
source_address: json_consolidation_request.source_address,
|
||||
source_pubkey: json_consolidation_request.source_pubkey,
|
||||
target_pubkey: json_consolidation_request.target_pubkey,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use types::{
|
||||
};
|
||||
use types::{
|
||||
ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb,
|
||||
ExecutionPayloadElectra,
|
||||
ExecutionPayloadElectra, ExecutionRequests,
|
||||
};
|
||||
|
||||
#[superstruct(
|
||||
@@ -43,6 +43,8 @@ pub struct NewPayloadRequest<'block, E: EthSpec> {
|
||||
pub versioned_hashes: Vec<VersionedHash>,
|
||||
#[superstruct(only(Deneb, Electra))]
|
||||
pub parent_beacon_block_root: Hash256,
|
||||
#[superstruct(only(Electra))]
|
||||
pub execution_requests_list: &'block ExecutionRequests<E>,
|
||||
}
|
||||
|
||||
impl<'block, E: EthSpec> NewPayloadRequest<'block, E> {
|
||||
@@ -183,6 +185,7 @@ impl<'a, E: EthSpec> TryFrom<BeaconBlockRef<'a, E>> for NewPayloadRequest<'a, E>
|
||||
.map(kzg_commitment_to_versioned_hash)
|
||||
.collect(),
|
||||
parent_beacon_block_root: block_ref.parent_root,
|
||||
execution_requests_list: &block_ref.body.execution_requests,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,8 @@ use types::builder_bid::BuilderBid;
|
||||
use types::non_zero_usize::new_non_zero_usize;
|
||||
use types::payload::BlockProductionVersion;
|
||||
use types::{
|
||||
AbstractExecPayload, BlobsList, ExecutionPayloadDeneb, KzgProofs, SignedBlindedBeaconBlock,
|
||||
AbstractExecPayload, BlobsList, ExecutionPayloadDeneb, ExecutionRequests, KzgProofs,
|
||||
SignedBlindedBeaconBlock,
|
||||
};
|
||||
use types::{
|
||||
BeaconStateError, BlindedPayload, ChainSpec, Epoch, ExecPayload, ExecutionPayloadBellatrix,
|
||||
@@ -112,12 +113,15 @@ 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,
|
||||
requests: None,
|
||||
},
|
||||
BuilderBid::Electra(builder_bid) => BlockProposalContents::PayloadAndBlobs {
|
||||
payload: ExecutionPayloadHeader::Electra(builder_bid.header).into(),
|
||||
block_value: builder_bid.value,
|
||||
kzg_commitments: builder_bid.blob_kzg_commitments,
|
||||
blobs_and_proofs: None,
|
||||
// TODO(electra): update this with builder api returning the requests
|
||||
requests: None,
|
||||
},
|
||||
};
|
||||
Ok(ProvenancedPayload::Builder(
|
||||
@@ -194,6 +198,8 @@ pub enum BlockProposalContents<E: EthSpec, Payload: AbstractExecPayload<E>> {
|
||||
kzg_commitments: KzgCommitments<E>,
|
||||
/// `None` for blinded `PayloadAndBlobs`.
|
||||
blobs_and_proofs: Option<(BlobsList<E>, KzgProofs<E>)>,
|
||||
// TODO(electra): this should probably be a separate variant/superstruct
|
||||
requests: Option<ExecutionRequests<E>>,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -214,11 +220,13 @@ impl<E: EthSpec> From<BlockProposalContents<E, FullPayload<E>>>
|
||||
block_value,
|
||||
kzg_commitments,
|
||||
blobs_and_proofs: _,
|
||||
requests,
|
||||
} => BlockProposalContents::PayloadAndBlobs {
|
||||
payload: payload.execution_payload().into(),
|
||||
block_value,
|
||||
kzg_commitments,
|
||||
blobs_and_proofs: None,
|
||||
requests,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -230,13 +238,14 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> TryFrom<GetPayloadResponse<E>>
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(response: GetPayloadResponse<E>) -> Result<Self, Error> {
|
||||
let (execution_payload, block_value, maybe_bundle) = response.into();
|
||||
let (execution_payload, block_value, maybe_bundle, maybe_requests) = response.into();
|
||||
match maybe_bundle {
|
||||
Some(bundle) => Ok(Self::PayloadAndBlobs {
|
||||
payload: execution_payload.into(),
|
||||
block_value,
|
||||
kzg_commitments: bundle.commitments,
|
||||
blobs_and_proofs: Some((bundle.blobs, bundle.proofs)),
|
||||
requests: maybe_requests,
|
||||
}),
|
||||
None => Ok(Self::Payload {
|
||||
payload: execution_payload.into(),
|
||||
@@ -265,22 +274,25 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> BlockProposalContents<E, Paylo
|
||||
Payload,
|
||||
Option<KzgCommitments<E>>,
|
||||
Option<(BlobsList<E>, KzgProofs<E>)>,
|
||||
Option<ExecutionRequests<E>>,
|
||||
Uint256,
|
||||
) {
|
||||
match self {
|
||||
Self::Payload {
|
||||
payload,
|
||||
block_value,
|
||||
} => (payload, None, None, block_value),
|
||||
} => (payload, None, None, None, block_value),
|
||||
Self::PayloadAndBlobs {
|
||||
payload,
|
||||
block_value,
|
||||
kzg_commitments,
|
||||
blobs_and_proofs,
|
||||
requests,
|
||||
} => (
|
||||
payload,
|
||||
Some(kzg_commitments),
|
||||
blobs_and_proofs,
|
||||
requests,
|
||||
block_value,
|
||||
),
|
||||
}
|
||||
@@ -1772,10 +1784,10 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
pub async fn get_payload_bodies_by_hash(
|
||||
&self,
|
||||
hashes: Vec<ExecutionBlockHash>,
|
||||
) -> Result<Vec<Option<ExecutionPayloadBody<E>>>, Error> {
|
||||
) -> Result<Vec<Option<ExecutionPayloadBodyV1<E>>>, Error> {
|
||||
self.engine()
|
||||
.request(|engine: &Engine| async move {
|
||||
engine.api.get_payload_bodies_by_hash(hashes).await
|
||||
engine.api.get_payload_bodies_by_hash_v1(hashes).await
|
||||
})
|
||||
.await
|
||||
.map_err(Box::new)
|
||||
@@ -1786,11 +1798,14 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
&self,
|
||||
start: u64,
|
||||
count: u64,
|
||||
) -> Result<Vec<Option<ExecutionPayloadBody<E>>>, Error> {
|
||||
) -> Result<Vec<Option<ExecutionPayloadBodyV1<E>>>, Error> {
|
||||
let _timer = metrics::start_timer(&metrics::EXECUTION_LAYER_GET_PAYLOAD_BODIES_BY_RANGE);
|
||||
self.engine()
|
||||
.request(|engine: &Engine| async move {
|
||||
engine.api.get_payload_bodies_by_range(start, count).await
|
||||
engine
|
||||
.api
|
||||
.get_payload_bodies_by_range_v1(start, count)
|
||||
.await
|
||||
})
|
||||
.await
|
||||
.map_err(Box::new)
|
||||
@@ -1823,9 +1838,7 @@ impl<E: EthSpec> ExecutionLayer<E> {
|
||||
|
||||
// Use efficient payload bodies by range method if supported.
|
||||
let capabilities = self.get_engine_capabilities(None).await?;
|
||||
if capabilities.get_payload_bodies_by_range_v1
|
||||
|| capabilities.get_payload_bodies_by_range_v2
|
||||
{
|
||||
if capabilities.get_payload_bodies_by_range_v1 {
|
||||
let mut payload_bodies = self.get_payload_bodies_by_range(block_number, 1).await?;
|
||||
|
||||
if payload_bodies.len() != 1 {
|
||||
|
||||
@@ -652,10 +652,6 @@ impl<E: EthSpec> ExecutionBlockGenerator<E> {
|
||||
withdrawals: pa.withdrawals.clone().into(),
|
||||
blob_gas_used: 0,
|
||||
excess_blob_gas: 0,
|
||||
// TODO(electra): consider how to test these fields below
|
||||
deposit_requests: vec![].into(),
|
||||
withdrawal_requests: vec![].into(),
|
||||
consolidation_requests: vec![].into(),
|
||||
}),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|
||||
@@ -373,6 +373,8 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
))?
|
||||
.into(),
|
||||
should_override_builder: false,
|
||||
// TODO(electra): add EL requests in mock el
|
||||
requests: Default::default(),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
@@ -561,60 +563,11 @@ pub async fn handle_rpc<E: EthSpec>(
|
||||
|
||||
match maybe_payload {
|
||||
Some(payload) => {
|
||||
assert!(
|
||||
!payload.fork_name().electra_enabled(),
|
||||
"payload bodies V1 is not supported for Electra blocks"
|
||||
);
|
||||
let payload_body = ExecutionPayloadBodyV1 {
|
||||
let payload_body: ExecutionPayloadBodyV1<E> = ExecutionPayloadBodyV1 {
|
||||
transactions: payload.transactions().clone(),
|
||||
withdrawals: payload.withdrawals().ok().cloned(),
|
||||
};
|
||||
let json_payload_body = JsonExecutionPayloadBody::V1(
|
||||
JsonExecutionPayloadBodyV1::<E>::from(payload_body),
|
||||
);
|
||||
response.push(Some(json_payload_body));
|
||||
}
|
||||
None => response.push(None),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(serde_json::to_value(response).unwrap())
|
||||
}
|
||||
ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V2 => {
|
||||
#[derive(Deserialize)]
|
||||
#[serde(transparent)]
|
||||
struct Quantity(#[serde(with = "serde_utils::u64_hex_be")] pub u64);
|
||||
|
||||
let start = get_param::<Quantity>(params, 0)
|
||||
.map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?
|
||||
.0;
|
||||
let count = get_param::<Quantity>(params, 1)
|
||||
.map_err(|s| (s, BAD_PARAMS_ERROR_CODE))?
|
||||
.0;
|
||||
|
||||
let mut response = vec![];
|
||||
for block_num in start..(start + count) {
|
||||
let maybe_payload = ctx
|
||||
.execution_block_generator
|
||||
.read()
|
||||
.execution_payload_by_number(block_num);
|
||||
|
||||
match maybe_payload {
|
||||
Some(payload) => {
|
||||
// TODO(electra): add testing for:
|
||||
// deposit_requests
|
||||
// withdrawal_requests
|
||||
// consolidation_requests
|
||||
let payload_body = ExecutionPayloadBodyV2 {
|
||||
transactions: payload.transactions().clone(),
|
||||
withdrawals: payload.withdrawals().ok().cloned(),
|
||||
deposit_requests: payload.deposit_requests().ok().cloned(),
|
||||
withdrawal_requests: payload.withdrawal_requests().ok().cloned(),
|
||||
consolidation_requests: payload.consolidation_requests().ok().cloned(),
|
||||
};
|
||||
let json_payload_body = JsonExecutionPayloadBody::V2(
|
||||
JsonExecutionPayloadBodyV2::<E>::from(payload_body),
|
||||
);
|
||||
let json_payload_body = JsonExecutionPayloadBodyV1::from(payload_body);
|
||||
response.push(Some(json_payload_body));
|
||||
}
|
||||
None => response.push(None),
|
||||
|
||||
@@ -20,9 +20,9 @@ use types::builder_bid::{
|
||||
};
|
||||
use types::{
|
||||
Address, BeaconState, ChainSpec, EthSpec, ExecPayload, ExecutionPayload,
|
||||
ExecutionPayloadHeaderRefMut, FixedBytesExtended, ForkName, ForkVersionedResponse, Hash256,
|
||||
PublicKeyBytes, Signature, SignedBlindedBeaconBlock, SignedRoot,
|
||||
SignedValidatorRegistrationData, Slot, Uint256,
|
||||
ExecutionPayloadHeaderRefMut, ExecutionRequests, FixedBytesExtended, ForkName,
|
||||
ForkVersionedResponse, Hash256, PublicKeyBytes, Signature, SignedBlindedBeaconBlock,
|
||||
SignedRoot, SignedValidatorRegistrationData, Slot, Uint256,
|
||||
};
|
||||
use types::{ExecutionBlockHash, SecretKey};
|
||||
use warp::{Filter, Rejection};
|
||||
@@ -542,10 +542,12 @@ pub fn serve<E: EthSpec>(
|
||||
|
||||
let mut message = match payload_response_type {
|
||||
crate::GetPayloadResponseType::Full(payload_response) => {
|
||||
let (payload, _block_value, maybe_blobs_bundle): (
|
||||
#[allow(clippy::type_complexity)]
|
||||
let (payload, _block_value, maybe_blobs_bundle, _maybe_requests): (
|
||||
ExecutionPayload<E>,
|
||||
Uint256,
|
||||
Option<BlobsBundle<E>>,
|
||||
Option<ExecutionRequests<E>>,
|
||||
) = payload_response.into();
|
||||
|
||||
match fork {
|
||||
@@ -593,10 +595,12 @@ pub fn serve<E: EthSpec>(
|
||||
}
|
||||
}
|
||||
crate::GetPayloadResponseType::Blinded(payload_response) => {
|
||||
let (payload, _block_value, maybe_blobs_bundle): (
|
||||
#[allow(clippy::type_complexity)]
|
||||
let (payload, _block_value, maybe_blobs_bundle, _maybe_requests): (
|
||||
ExecutionPayload<E>,
|
||||
Uint256,
|
||||
Option<BlobsBundle<E>>,
|
||||
Option<ExecutionRequests<E>>,
|
||||
) = payload_response.into();
|
||||
match fork {
|
||||
ForkName::Electra => BuilderBid::Electra(BuilderBidElectra {
|
||||
|
||||
@@ -47,9 +47,7 @@ pub const DEFAULT_ENGINE_CAPABILITIES: EngineCapabilities = EngineCapabilities {
|
||||
forkchoice_updated_v2: true,
|
||||
forkchoice_updated_v3: true,
|
||||
get_payload_bodies_by_hash_v1: true,
|
||||
get_payload_bodies_by_hash_v2: true,
|
||||
get_payload_bodies_by_range_v1: true,
|
||||
get_payload_bodies_by_range_v2: true,
|
||||
get_payload_v1: true,
|
||||
get_payload_v2: true,
|
||||
get_payload_v3: true,
|
||||
|
||||
@@ -579,8 +579,7 @@ pub fn get_expected_withdrawals<E: EthSpec>(
|
||||
.get_execution_withdrawal_address(spec)
|
||||
.ok_or(BlockProcessingError::WithdrawalCredentialsInvalid)?,
|
||||
amount: balance.safe_sub(
|
||||
validator
|
||||
.get_validator_max_effective_balance(spec, state.fork_name_unchecked()),
|
||||
validator.get_max_effective_balance(spec, state.fork_name_unchecked()),
|
||||
)?,
|
||||
});
|
||||
withdrawal_index.safe_add_assign(1)?;
|
||||
|
||||
@@ -40,15 +40,13 @@ pub fn process_operations<E: EthSpec, Payload: AbstractExecPayload<E>>(
|
||||
|
||||
if state.fork_name_unchecked().electra_enabled() {
|
||||
state.update_pubkey_cache()?;
|
||||
if let Some(deposit_requests) = block_body.execution_payload()?.deposit_requests()? {
|
||||
process_deposit_requests(state, &deposit_requests, spec)?;
|
||||
}
|
||||
if let Some(withdrawal_requests) = block_body.execution_payload()?.withdrawal_requests()? {
|
||||
process_withdrawal_requests(state, &withdrawal_requests, spec)?;
|
||||
}
|
||||
if let Some(consolidations) = block_body.execution_payload()?.consolidation_requests()? {
|
||||
process_consolidation_requests(state, &consolidations, spec)?;
|
||||
}
|
||||
process_deposit_requests(state, &block_body.execution_requests()?.deposits, spec)?;
|
||||
process_withdrawal_requests(state, &block_body.execution_requests()?.withdrawals, spec)?;
|
||||
process_consolidation_requests(
|
||||
state,
|
||||
&block_body.execution_requests()?.consolidations,
|
||||
spec,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -82,6 +82,7 @@ struct RewardsAndPenaltiesContext {
|
||||
struct SlashingsContext {
|
||||
adjusted_total_slashing_balance: u64,
|
||||
target_withdrawable_epoch: Epoch,
|
||||
penalty_per_effective_balance_increment: u64,
|
||||
}
|
||||
|
||||
struct PendingBalanceDepositsContext {
|
||||
@@ -775,9 +776,16 @@ impl SlashingsContext {
|
||||
.current_epoch
|
||||
.safe_add(E::EpochsPerSlashingsVector::to_u64().safe_div(2)?)?;
|
||||
|
||||
let penalty_per_effective_balance_increment = adjusted_total_slashing_balance.safe_div(
|
||||
state_ctxt
|
||||
.total_active_balance
|
||||
.safe_div(spec.effective_balance_increment)?,
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
adjusted_total_slashing_balance,
|
||||
target_withdrawable_epoch,
|
||||
penalty_per_effective_balance_increment,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -792,14 +800,20 @@ fn process_single_slashing(
|
||||
if validator.slashed && slashings_ctxt.target_withdrawable_epoch == validator.withdrawable_epoch
|
||||
{
|
||||
let increment = spec.effective_balance_increment;
|
||||
let penalty_numerator = validator
|
||||
.effective_balance
|
||||
.safe_div(increment)?
|
||||
.safe_mul(slashings_ctxt.adjusted_total_slashing_balance)?;
|
||||
let penalty = penalty_numerator
|
||||
.safe_div(state_ctxt.total_active_balance)?
|
||||
.safe_mul(increment)?;
|
||||
|
||||
let penalty = if state_ctxt.fork_name.electra_enabled() {
|
||||
let effective_balance_increments = validator.effective_balance.safe_div(increment)?;
|
||||
slashings_ctxt
|
||||
.penalty_per_effective_balance_increment
|
||||
.safe_mul(effective_balance_increments)?
|
||||
} else {
|
||||
let penalty_numerator = validator
|
||||
.effective_balance
|
||||
.safe_div(increment)?
|
||||
.safe_mul(slashings_ctxt.adjusted_total_slashing_balance)?;
|
||||
penalty_numerator
|
||||
.safe_div(state_ctxt.total_active_balance)?
|
||||
.safe_mul(increment)?
|
||||
};
|
||||
*balance.make_mut()? = balance.saturating_sub(penalty);
|
||||
}
|
||||
Ok(())
|
||||
@@ -1022,8 +1036,7 @@ fn process_single_effective_balance_update(
|
||||
) -> Result<(), Error> {
|
||||
// Use the higher effective balance limit if post-Electra and compounding withdrawal credentials
|
||||
// are set.
|
||||
let effective_balance_limit =
|
||||
validator.get_validator_max_effective_balance(spec, state_ctxt.fork_name);
|
||||
let effective_balance_limit = validator.get_max_effective_balance(spec, state_ctxt.fork_name);
|
||||
|
||||
let old_effective_balance = validator.effective_balance;
|
||||
let new_effective_balance = if balance.safe_add(eb_ctxt.downward_threshold)?
|
||||
|
||||
@@ -670,6 +670,7 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockElectra<E, Payload>
|
||||
graffiti: Graffiti::default(),
|
||||
execution_payload: Payload::Electra::default(),
|
||||
blob_kzg_commitments: VariableList::empty(),
|
||||
execution_requests: ExecutionRequests::default(),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -700,6 +701,7 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> EmptyBlock for BeaconBlockElec
|
||||
execution_payload: Payload::Electra::default(),
|
||||
bls_to_execution_changes: VariableList::empty(),
|
||||
blob_kzg_commitments: VariableList::empty(),
|
||||
execution_requests: ExecutionRequests::default(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,8 @@ pub struct BeaconBlockBody<E: EthSpec, Payload: AbstractExecPayload<E> = FullPay
|
||||
VariableList<SignedBlsToExecutionChange, E::MaxBlsToExecutionChanges>,
|
||||
#[superstruct(only(Deneb, Electra))]
|
||||
pub blob_kzg_commitments: KzgCommitments<E>,
|
||||
#[superstruct(only(Electra))]
|
||||
pub execution_requests: ExecutionRequests<E>,
|
||||
#[superstruct(only(Base, Altair))]
|
||||
#[metastruct(exclude_from(fields))]
|
||||
#[ssz(skip_serializing, skip_deserializing)]
|
||||
@@ -662,6 +664,7 @@ impl<E: EthSpec> From<BeaconBlockBodyElectra<E, FullPayload<E>>>
|
||||
execution_payload: FullPayloadElectra { execution_payload },
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
execution_requests,
|
||||
} = body;
|
||||
|
||||
(
|
||||
@@ -680,6 +683,7 @@ impl<E: EthSpec> From<BeaconBlockBodyElectra<E, FullPayload<E>>>
|
||||
},
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments: blob_kzg_commitments.clone(),
|
||||
execution_requests,
|
||||
},
|
||||
Some(execution_payload),
|
||||
)
|
||||
@@ -818,6 +822,7 @@ impl<E: EthSpec> BeaconBlockBodyElectra<E, FullPayload<E>> {
|
||||
execution_payload: FullPayloadElectra { execution_payload },
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
execution_requests,
|
||||
} = self;
|
||||
|
||||
BeaconBlockBodyElectra {
|
||||
@@ -835,6 +840,7 @@ impl<E: EthSpec> BeaconBlockBodyElectra<E, FullPayload<E>> {
|
||||
},
|
||||
bls_to_execution_changes: bls_to_execution_changes.clone(),
|
||||
blob_kzg_commitments: blob_kzg_commitments.clone(),
|
||||
execution_requests: execution_requests.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2131,7 +2131,7 @@ impl<E: EthSpec> BeaconState<E> {
|
||||
let max_effective_balance = self
|
||||
.validators()
|
||||
.get(validator_index)
|
||||
.map(|validator| validator.get_validator_max_effective_balance(spec, current_fork))
|
||||
.map(|validator| validator.get_max_effective_balance(spec, current_fork))
|
||||
.ok_or(Error::UnknownValidator(validator_index))?;
|
||||
Ok(std::cmp::min(
|
||||
*self
|
||||
|
||||
@@ -26,7 +26,6 @@ pub enum Domain {
|
||||
SyncCommittee,
|
||||
ContributionAndProof,
|
||||
SyncCommitteeSelectionProof,
|
||||
Consolidation,
|
||||
ApplicationMask(ApplicationDomain),
|
||||
}
|
||||
|
||||
@@ -111,7 +110,6 @@ pub struct ChainSpec {
|
||||
pub(crate) domain_voluntary_exit: u32,
|
||||
pub(crate) domain_selection_proof: u32,
|
||||
pub(crate) domain_aggregate_and_proof: u32,
|
||||
pub(crate) domain_consolidation: u32,
|
||||
|
||||
/*
|
||||
* Fork choice
|
||||
@@ -479,7 +477,6 @@ impl ChainSpec {
|
||||
Domain::SyncCommitteeSelectionProof => self.domain_sync_committee_selection_proof,
|
||||
Domain::ApplicationMask(application_domain) => application_domain.get_domain_constant(),
|
||||
Domain::BlsToExecutionChange => self.domain_bls_to_execution_change,
|
||||
Domain::Consolidation => self.domain_consolidation,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -704,7 +701,6 @@ impl ChainSpec {
|
||||
domain_voluntary_exit: 4,
|
||||
domain_selection_proof: 5,
|
||||
domain_aggregate_and_proof: 6,
|
||||
domain_consolidation: 0x0B,
|
||||
|
||||
/*
|
||||
* Fork choice
|
||||
@@ -1026,7 +1022,6 @@ impl ChainSpec {
|
||||
domain_voluntary_exit: 4,
|
||||
domain_selection_proof: 5,
|
||||
domain_aggregate_and_proof: 6,
|
||||
domain_consolidation: 0x0B,
|
||||
|
||||
/*
|
||||
* Fork choice
|
||||
@@ -1959,7 +1954,6 @@ mod tests {
|
||||
&spec,
|
||||
);
|
||||
test_domain(Domain::SyncCommittee, spec.domain_sync_committee, &spec);
|
||||
test_domain(Domain::Consolidation, spec.domain_consolidation, &spec);
|
||||
|
||||
// The builder domain index is zero
|
||||
let builder_domain_pre_mask = [0; 4];
|
||||
|
||||
@@ -126,7 +126,6 @@ pub fn get_extra_fields(spec: &ChainSpec) -> HashMap<String, Value> {
|
||||
"compounding_withdrawal_prefix".to_uppercase() => u8_hex(spec.compounding_withdrawal_prefix_byte),
|
||||
"unset_deposit_requests_start_index".to_uppercase() => spec.unset_deposit_requests_start_index.to_string().into(),
|
||||
"full_exit_request_amount".to_uppercase() => spec.full_exit_request_amount.to_string().into(),
|
||||
"domain_consolidation".to_uppercase()=> u32_hex(spec.domain_consolidation),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::{test_utils::TestRandom, Address, PublicKeyBytes, SignedRoot};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Encode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
@@ -24,6 +25,18 @@ pub struct ConsolidationRequest {
|
||||
pub target_pubkey: PublicKeyBytes,
|
||||
}
|
||||
|
||||
impl ConsolidationRequest {
|
||||
pub fn max_size() -> usize {
|
||||
Self {
|
||||
source_address: Address::repeat_byte(0),
|
||||
source_pubkey: PublicKeyBytes::empty(),
|
||||
target_pubkey: PublicKeyBytes::empty(),
|
||||
}
|
||||
.as_ssz_bytes()
|
||||
.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl SignedRoot for ConsolidationRequest {}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{Hash256, PublicKeyBytes, Signature};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Encode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
@@ -29,6 +30,20 @@ pub struct DepositRequest {
|
||||
pub index: u64,
|
||||
}
|
||||
|
||||
impl DepositRequest {
|
||||
pub fn max_size() -> usize {
|
||||
Self {
|
||||
pubkey: PublicKeyBytes::empty(),
|
||||
withdrawal_credentials: Hash256::ZERO,
|
||||
amount: 0,
|
||||
signature: Signature::empty(),
|
||||
index: 0,
|
||||
}
|
||||
.as_ssz_bytes()
|
||||
.len()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -13,12 +13,6 @@ pub type Transactions<E> = VariableList<
|
||||
>;
|
||||
|
||||
pub type Withdrawals<E> = VariableList<Withdrawal, <E as EthSpec>::MaxWithdrawalsPerPayload>;
|
||||
pub type DepositRequests<E> =
|
||||
VariableList<DepositRequest, <E as EthSpec>::MaxDepositRequestsPerPayload>;
|
||||
pub type WithdrawalRequests<E> =
|
||||
VariableList<WithdrawalRequest, <E as EthSpec>::MaxWithdrawalRequestsPerPayload>;
|
||||
pub type ConsolidationRequests<E> =
|
||||
VariableList<ConsolidationRequest, <E as EthSpec>::MaxConsolidationRequestsPerPayload>;
|
||||
|
||||
#[superstruct(
|
||||
variants(Bellatrix, Capella, Deneb, Electra),
|
||||
@@ -96,13 +90,6 @@ pub struct ExecutionPayload<E: EthSpec> {
|
||||
#[superstruct(only(Deneb, Electra), partial_getter(copy))]
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub excess_blob_gas: u64,
|
||||
#[superstruct(only(Electra))]
|
||||
pub deposit_requests: VariableList<DepositRequest, E::MaxDepositRequestsPerPayload>,
|
||||
#[superstruct(only(Electra))]
|
||||
pub withdrawal_requests: VariableList<WithdrawalRequest, E::MaxWithdrawalRequestsPerPayload>,
|
||||
#[superstruct(only(Electra))]
|
||||
pub consolidation_requests:
|
||||
VariableList<ConsolidationRequest, E::MaxConsolidationRequestsPerPayload>,
|
||||
}
|
||||
|
||||
impl<'a, E: EthSpec> ExecutionPayloadRef<'a, E> {
|
||||
|
||||
@@ -86,12 +86,6 @@ pub struct ExecutionPayloadHeader<E: EthSpec> {
|
||||
#[superstruct(only(Deneb, Electra), partial_getter(copy))]
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub excess_blob_gas: u64,
|
||||
#[superstruct(only(Electra), partial_getter(copy))]
|
||||
pub deposit_requests_root: Hash256,
|
||||
#[superstruct(only(Electra), partial_getter(copy))]
|
||||
pub withdrawal_requests_root: Hash256,
|
||||
#[superstruct(only(Electra), partial_getter(copy))]
|
||||
pub consolidation_requests_root: Hash256,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> ExecutionPayloadHeader<E> {
|
||||
@@ -214,9 +208,6 @@ impl<E: EthSpec> ExecutionPayloadHeaderDeneb<E> {
|
||||
withdrawals_root: self.withdrawals_root,
|
||||
blob_gas_used: self.blob_gas_used,
|
||||
excess_blob_gas: self.excess_blob_gas,
|
||||
deposit_requests_root: Hash256::zero(),
|
||||
withdrawal_requests_root: Hash256::zero(),
|
||||
consolidation_requests_root: Hash256::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -308,9 +299,6 @@ impl<'a, E: EthSpec> From<&'a ExecutionPayloadElectra<E>> for ExecutionPayloadHe
|
||||
withdrawals_root: payload.withdrawals.tree_hash_root(),
|
||||
blob_gas_used: payload.blob_gas_used,
|
||||
excess_blob_gas: payload.excess_blob_gas,
|
||||
deposit_requests_root: payload.deposit_requests.tree_hash_root(),
|
||||
withdrawal_requests_root: payload.withdrawal_requests.tree_hash_root(),
|
||||
consolidation_requests_root: payload.consolidation_requests.tree_hash_root(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
59
consensus/types/src/execution_requests.rs
Normal file
59
consensus/types/src/execution_requests.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{ConsolidationRequest, DepositRequest, EthSpec, WithdrawalRequest};
|
||||
use alloy_primitives::Bytes;
|
||||
use derivative::Derivative;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Encode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use ssz_types::VariableList;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
pub type DepositRequests<E> =
|
||||
VariableList<DepositRequest, <E as EthSpec>::MaxDepositRequestsPerPayload>;
|
||||
pub type WithdrawalRequests<E> =
|
||||
VariableList<WithdrawalRequest, <E as EthSpec>::MaxWithdrawalRequestsPerPayload>;
|
||||
pub type ConsolidationRequests<E> =
|
||||
VariableList<ConsolidationRequest, <E as EthSpec>::MaxConsolidationRequestsPerPayload>;
|
||||
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Derivative,
|
||||
Default,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
#[arbitrary(bound = "E: EthSpec")]
|
||||
#[derivative(PartialEq, Eq, Hash(bound = "E: EthSpec"))]
|
||||
pub struct ExecutionRequests<E: EthSpec> {
|
||||
pub deposits: DepositRequests<E>,
|
||||
pub withdrawals: WithdrawalRequests<E>,
|
||||
pub consolidations: ConsolidationRequests<E>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> ExecutionRequests<E> {
|
||||
/// Returns the encoding according to EIP-7685 to send
|
||||
/// to the execution layer over the engine api.
|
||||
pub fn get_execution_requests_list(&self) -> Vec<Bytes> {
|
||||
let deposit_bytes = Bytes::from(self.deposits.as_ssz_bytes());
|
||||
let withdrawal_bytes = Bytes::from(self.withdrawals.as_ssz_bytes());
|
||||
let consolidation_bytes = Bytes::from(self.consolidations.as_ssz_bytes());
|
||||
vec![deposit_bytes, withdrawal_bytes, consolidation_bytes]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::MainnetEthSpec;
|
||||
|
||||
use super::*;
|
||||
|
||||
ssz_and_tree_hash_tests!(ExecutionRequests<MainnetEthSpec>);
|
||||
}
|
||||
@@ -81,6 +81,7 @@ pub mod slot_epoch_macros;
|
||||
pub mod activation_queue;
|
||||
pub mod config_and_preset;
|
||||
pub mod execution_block_header;
|
||||
pub mod execution_requests;
|
||||
pub mod fork_context;
|
||||
pub mod participation_flags;
|
||||
pub mod payload;
|
||||
@@ -169,6 +170,7 @@ pub use crate::execution_payload_header::{
|
||||
ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderRef,
|
||||
ExecutionPayloadHeaderRefMut,
|
||||
};
|
||||
pub use crate::execution_requests::ExecutionRequests;
|
||||
pub use crate::fork::Fork;
|
||||
pub use crate::fork_context::ForkContext;
|
||||
pub use crate::fork_data::ForkData;
|
||||
|
||||
@@ -39,18 +39,6 @@ pub trait ExecPayload<E: EthSpec>: Debug + Clone + PartialEq + Hash + TreeHash +
|
||||
/// fork-specific fields
|
||||
fn withdrawals_root(&self) -> Result<Hash256, Error>;
|
||||
fn blob_gas_used(&self) -> Result<u64, Error>;
|
||||
fn withdrawal_requests(
|
||||
&self,
|
||||
) -> Result<Option<VariableList<WithdrawalRequest, E::MaxWithdrawalRequestsPerPayload>>, Error>;
|
||||
fn deposit_requests(
|
||||
&self,
|
||||
) -> Result<Option<VariableList<DepositRequest, E::MaxDepositRequestsPerPayload>>, Error>;
|
||||
fn consolidation_requests(
|
||||
&self,
|
||||
) -> Result<
|
||||
Option<VariableList<ConsolidationRequest, E::MaxConsolidationRequestsPerPayload>>,
|
||||
Error,
|
||||
>;
|
||||
|
||||
/// Is this a default payload with 0x0 roots for transactions and withdrawals?
|
||||
fn is_default_with_zero_roots(&self) -> bool;
|
||||
@@ -290,51 +278,6 @@ impl<E: EthSpec> ExecPayload<E> for FullPayload<E> {
|
||||
}
|
||||
}
|
||||
|
||||
fn withdrawal_requests(
|
||||
&self,
|
||||
) -> Result<Option<VariableList<WithdrawalRequest, E::MaxWithdrawalRequestsPerPayload>>, Error>
|
||||
{
|
||||
match self {
|
||||
FullPayload::Bellatrix(_) | FullPayload::Capella(_) | FullPayload::Deneb(_) => {
|
||||
Err(Error::IncorrectStateVariant)
|
||||
}
|
||||
FullPayload::Electra(inner) => {
|
||||
Ok(Some(inner.execution_payload.withdrawal_requests.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deposit_requests(
|
||||
&self,
|
||||
) -> Result<Option<VariableList<DepositRequest, E::MaxDepositRequestsPerPayload>>, Error> {
|
||||
match self {
|
||||
FullPayload::Bellatrix(_) | FullPayload::Capella(_) | FullPayload::Deneb(_) => {
|
||||
Err(Error::IncorrectStateVariant)
|
||||
}
|
||||
FullPayload::Electra(inner) => {
|
||||
Ok(Some(inner.execution_payload.deposit_requests.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn consolidation_requests(
|
||||
&self,
|
||||
) -> Result<
|
||||
Option<
|
||||
VariableList<ConsolidationRequest, <E as EthSpec>::MaxConsolidationRequestsPerPayload>,
|
||||
>,
|
||||
Error,
|
||||
> {
|
||||
match self {
|
||||
FullPayload::Bellatrix(_) | FullPayload::Capella(_) | FullPayload::Deneb(_) => {
|
||||
Err(Error::IncorrectStateVariant)
|
||||
}
|
||||
FullPayload::Electra(inner) => {
|
||||
Ok(Some(inner.execution_payload.consolidation_requests.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_default_with_zero_roots<'a>(&'a self) -> bool {
|
||||
map_full_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
|
||||
cons(payload);
|
||||
@@ -467,51 +410,6 @@ impl<'b, E: EthSpec> ExecPayload<E> for FullPayloadRef<'b, E> {
|
||||
}
|
||||
}
|
||||
|
||||
fn withdrawal_requests(
|
||||
&self,
|
||||
) -> Result<Option<VariableList<WithdrawalRequest, E::MaxWithdrawalRequestsPerPayload>>, Error>
|
||||
{
|
||||
match self {
|
||||
FullPayloadRef::Bellatrix(_)
|
||||
| FullPayloadRef::Capella(_)
|
||||
| FullPayloadRef::Deneb(_) => Err(Error::IncorrectStateVariant),
|
||||
FullPayloadRef::Electra(inner) => {
|
||||
Ok(Some(inner.execution_payload.withdrawal_requests.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deposit_requests(
|
||||
&self,
|
||||
) -> Result<Option<VariableList<DepositRequest, E::MaxDepositRequestsPerPayload>>, Error> {
|
||||
match self {
|
||||
FullPayloadRef::Bellatrix(_)
|
||||
| FullPayloadRef::Capella(_)
|
||||
| FullPayloadRef::Deneb(_) => Err(Error::IncorrectStateVariant),
|
||||
FullPayloadRef::Electra(inner) => {
|
||||
Ok(Some(inner.execution_payload.deposit_requests.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn consolidation_requests(
|
||||
&self,
|
||||
) -> Result<
|
||||
Option<
|
||||
VariableList<ConsolidationRequest, <E as EthSpec>::MaxConsolidationRequestsPerPayload>,
|
||||
>,
|
||||
Error,
|
||||
> {
|
||||
match self {
|
||||
FullPayloadRef::Bellatrix(_)
|
||||
| FullPayloadRef::Capella(_)
|
||||
| FullPayloadRef::Deneb(_) => Err(Error::IncorrectStateVariant),
|
||||
FullPayloadRef::Electra(inner) => {
|
||||
Ok(Some(inner.execution_payload.consolidation_requests.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_default_with_zero_roots<'a>(&'a self) -> bool {
|
||||
map_full_payload_ref!(&'a _, self, move |payload, cons| {
|
||||
cons(payload);
|
||||
@@ -692,30 +590,6 @@ impl<E: EthSpec> ExecPayload<E> for BlindedPayload<E> {
|
||||
}
|
||||
}
|
||||
|
||||
fn withdrawal_requests(
|
||||
&self,
|
||||
) -> Result<Option<VariableList<WithdrawalRequest, E::MaxWithdrawalRequestsPerPayload>>, Error>
|
||||
{
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn deposit_requests(
|
||||
&self,
|
||||
) -> Result<Option<VariableList<DepositRequest, E::MaxDepositRequestsPerPayload>>, Error> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn consolidation_requests(
|
||||
&self,
|
||||
) -> Result<
|
||||
Option<
|
||||
VariableList<ConsolidationRequest, <E as EthSpec>::MaxConsolidationRequestsPerPayload>,
|
||||
>,
|
||||
Error,
|
||||
> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn is_default_with_zero_roots(&self) -> bool {
|
||||
self.to_ref().is_default_with_zero_roots()
|
||||
}
|
||||
@@ -817,30 +691,6 @@ impl<'b, E: EthSpec> ExecPayload<E> for BlindedPayloadRef<'b, E> {
|
||||
}
|
||||
}
|
||||
|
||||
fn withdrawal_requests(
|
||||
&self,
|
||||
) -> Result<Option<VariableList<WithdrawalRequest, E::MaxWithdrawalRequestsPerPayload>>, Error>
|
||||
{
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn deposit_requests(
|
||||
&self,
|
||||
) -> Result<Option<VariableList<DepositRequest, E::MaxDepositRequestsPerPayload>>, Error> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn consolidation_requests(
|
||||
&self,
|
||||
) -> Result<
|
||||
Option<
|
||||
VariableList<ConsolidationRequest, <E as EthSpec>::MaxConsolidationRequestsPerPayload>,
|
||||
>,
|
||||
Error,
|
||||
> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn is_default_with_zero_roots<'a>(&'a self) -> bool {
|
||||
map_blinded_payload_ref!(&'b _, self, move |payload, cons| {
|
||||
cons(payload);
|
||||
@@ -867,10 +717,7 @@ macro_rules! impl_exec_payload_common {
|
||||
$is_default_with_empty_roots:block,
|
||||
$f:block,
|
||||
$g:block,
|
||||
$h:block,
|
||||
$i:block,
|
||||
$j:block,
|
||||
$k:block) => {
|
||||
$h:block) => {
|
||||
impl<E: EthSpec> ExecPayload<E> for $wrapper_type<E> {
|
||||
fn block_type() -> BlockType {
|
||||
BlockType::$block_type_variant
|
||||
@@ -933,30 +780,6 @@ macro_rules! impl_exec_payload_common {
|
||||
let h = $h;
|
||||
h(self)
|
||||
}
|
||||
|
||||
fn withdrawal_requests(
|
||||
&self,
|
||||
) -> Result<
|
||||
Option<VariableList<WithdrawalRequest, E::MaxWithdrawalRequestsPerPayload>>,
|
||||
Error,
|
||||
> {
|
||||
let i = $i;
|
||||
i(self)
|
||||
}
|
||||
|
||||
fn deposit_requests(
|
||||
&self,
|
||||
) -> Result<Option<VariableList<DepositRequest, E::MaxDepositRequestsPerPayload>>, Error> {
|
||||
let j = $j;
|
||||
j(self)
|
||||
}
|
||||
|
||||
fn consolidation_requests(
|
||||
&self,
|
||||
) -> Result<Option<VariableList<ConsolidationRequest, <E as EthSpec>::MaxConsolidationRequestsPerPayload>>, Error> {
|
||||
let k = $k;
|
||||
k(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<$wrapped_type<E>> for $wrapper_type<E> {
|
||||
@@ -1002,10 +825,7 @@ macro_rules! impl_exec_payload_for_fork {
|
||||
wrapper_ref_type.blob_gas_used()
|
||||
};
|
||||
c
|
||||
},
|
||||
{ |_| { Ok(None) } },
|
||||
{ |_| { Ok(None) } },
|
||||
{ |_| { Ok(None) } }
|
||||
}
|
||||
);
|
||||
|
||||
impl<E: EthSpec> TryInto<$wrapper_type_header<E>> for BlindedPayload<E> {
|
||||
@@ -1092,47 +912,6 @@ macro_rules! impl_exec_payload_for_fork {
|
||||
wrapper_ref_type.blob_gas_used()
|
||||
};
|
||||
c
|
||||
},
|
||||
{
|
||||
let c: for<'a> fn(
|
||||
&'a $wrapper_type_full<E>,
|
||||
) -> Result<
|
||||
Option<VariableList<WithdrawalRequest, E::MaxWithdrawalRequestsPerPayload>>,
|
||||
Error,
|
||||
> = |payload: &$wrapper_type_full<E>| {
|
||||
let wrapper_ref_type = FullPayloadRef::$fork_variant(&payload);
|
||||
wrapper_ref_type.withdrawal_requests()
|
||||
};
|
||||
c
|
||||
},
|
||||
{
|
||||
let c: for<'a> fn(
|
||||
&'a $wrapper_type_full<E>,
|
||||
) -> Result<
|
||||
Option<VariableList<DepositRequest, E::MaxDepositRequestsPerPayload>>,
|
||||
Error,
|
||||
> = |payload: &$wrapper_type_full<E>| {
|
||||
let wrapper_ref_type = FullPayloadRef::$fork_variant(&payload);
|
||||
wrapper_ref_type.deposit_requests()
|
||||
};
|
||||
c
|
||||
},
|
||||
{
|
||||
let c: for<'a> fn(
|
||||
&'a $wrapper_type_full<E>,
|
||||
) -> Result<
|
||||
Option<
|
||||
VariableList<
|
||||
ConsolidationRequest,
|
||||
<E as EthSpec>::MaxConsolidationRequestsPerPayload,
|
||||
>,
|
||||
>,
|
||||
Error,
|
||||
> = |payload: &$wrapper_type_full<E>| {
|
||||
let wrapper_ref_type = FullPayloadRef::$fork_variant(&payload);
|
||||
wrapper_ref_type.consolidation_requests()
|
||||
};
|
||||
c
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -498,6 +498,7 @@ impl<E: EthSpec> SignedBeaconBlockElectra<E, BlindedPayload<E>> {
|
||||
execution_payload: BlindedPayloadElectra { .. },
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
execution_requests,
|
||||
},
|
||||
},
|
||||
signature,
|
||||
@@ -521,6 +522,7 @@ impl<E: EthSpec> SignedBeaconBlockElectra<E, BlindedPayload<E>> {
|
||||
execution_payload: FullPayloadElectra { execution_payload },
|
||||
bls_to_execution_changes,
|
||||
blob_kzg_commitments,
|
||||
execution_requests,
|
||||
},
|
||||
},
|
||||
signature,
|
||||
|
||||
@@ -236,7 +236,7 @@ impl Validator {
|
||||
spec: &ChainSpec,
|
||||
current_fork: ForkName,
|
||||
) -> bool {
|
||||
let max_effective_balance = self.get_validator_max_effective_balance(spec, current_fork);
|
||||
let max_effective_balance = self.get_max_effective_balance(spec, current_fork);
|
||||
let has_max_effective_balance = self.effective_balance == max_effective_balance;
|
||||
let has_excess_balance = balance > max_effective_balance;
|
||||
self.has_execution_withdrawal_credential(spec)
|
||||
@@ -251,11 +251,7 @@ impl Validator {
|
||||
}
|
||||
|
||||
/// Returns the max effective balance for a validator in gwei.
|
||||
pub fn get_validator_max_effective_balance(
|
||||
&self,
|
||||
spec: &ChainSpec,
|
||||
current_fork: ForkName,
|
||||
) -> u64 {
|
||||
pub fn get_max_effective_balance(&self, spec: &ChainSpec, current_fork: ForkName) -> u64 {
|
||||
if current_fork >= ForkName::Electra {
|
||||
if self.has_compounding_withdrawal_credential(spec) {
|
||||
spec.max_effective_balance_electra
|
||||
@@ -273,7 +269,7 @@ impl Validator {
|
||||
spec: &ChainSpec,
|
||||
current_fork: ForkName,
|
||||
) -> u64 {
|
||||
let max_effective_balance = self.get_validator_max_effective_balance(spec, current_fork);
|
||||
let max_effective_balance = self.get_max_effective_balance(spec, current_fork);
|
||||
std::cmp::min(validator_balance, max_effective_balance)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{Address, PublicKeyBytes};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Encode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
@@ -27,6 +28,18 @@ pub struct WithdrawalRequest {
|
||||
pub amount: u64,
|
||||
}
|
||||
|
||||
impl WithdrawalRequest {
|
||||
pub fn max_size() -> usize {
|
||||
Self {
|
||||
source_address: Address::repeat_byte(0),
|
||||
validator_pubkey: PublicKeyBytes::empty(),
|
||||
amount: 0,
|
||||
}
|
||||
.as_ssz_bytes()
|
||||
.len()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
TESTS_TAG := v1.5.0-alpha.5
|
||||
TESTS_TAG := v1.5.0-alpha.6
|
||||
TESTS = general minimal mainnet
|
||||
TARBALLS = $(patsubst %,%-$(TESTS_TAG).tar.gz,$(TESTS))
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ type_name_generic!(ExecutionPayloadHeaderBellatrix, "ExecutionPayloadHeader");
|
||||
type_name_generic!(ExecutionPayloadHeaderCapella, "ExecutionPayloadHeader");
|
||||
type_name_generic!(ExecutionPayloadHeaderDeneb, "ExecutionPayloadHeader");
|
||||
type_name_generic!(ExecutionPayloadHeaderElectra, "ExecutionPayloadHeader");
|
||||
type_name_generic!(ExecutionRequests);
|
||||
type_name_generic!(BlindedPayload, "ExecutionPayloadHeader");
|
||||
type_name!(Fork);
|
||||
type_name!(ForkData);
|
||||
|
||||
@@ -679,6 +679,14 @@ mod ssz_static {
|
||||
SszStaticHandler::<PendingPartialWithdrawal, MinimalEthSpec>::electra_and_later().run();
|
||||
SszStaticHandler::<PendingPartialWithdrawal, MainnetEthSpec>::electra_and_later().run();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execution_requests() {
|
||||
SszStaticHandler::<ExecutionRequests<MainnetEthSpec>, MainnetEthSpec>::electra_and_later()
|
||||
.run();
|
||||
SszStaticHandler::<ExecutionRequests<MinimalEthSpec>, MinimalEthSpec>::electra_and_later()
|
||||
.run();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user