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:
Pawan Dhananjay
2024-10-15 10:38:43 -07:00
committed by GitHub
parent 2e440df4f1
commit 83d5c521d7
35 changed files with 445 additions and 913 deletions

View File

@@ -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(),
},
}
}

View File

@@ -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(),
}
}
}

View File

@@ -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

View File

@@ -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];

View File

@@ -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),
}
}

View File

@@ -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)]

View File

@@ -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::*;

View File

@@ -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> {

View File

@@ -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(),
}
}
}

View 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>);
}

View File

@@ -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;

View File

@@ -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
}
);

View File

@@ -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,

View File

@@ -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)
}
}

View File

@@ -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::*;