diff --git a/crates/ethereum/engine-primitives/src/payload.rs b/crates/ethereum/engine-primitives/src/payload.rs index a6c47ebde910..a354e0588844 100644 --- a/crates/ethereum/engine-primitives/src/payload.rs +++ b/crates/ethereum/engine-primitives/src/payload.rs @@ -11,8 +11,7 @@ use reth_rpc_types::engine::{ PayloadId, }; use reth_rpc_types_compat::engine::payload::{ - block_to_payload_v3, convert_block_to_payload_field_v2, - convert_standalone_withdraw_to_withdrawal, try_block_to_payload_v1, + block_to_payload_v3, convert_block_to_payload_field_v2, try_block_to_payload_v1, }; use revm_primitives::{BlobExcessGasAndPrice, BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, SpecId}; use std::convert::Infallible; @@ -159,22 +158,13 @@ impl EthPayloadBuilderAttributes { pub fn new(parent: B256, attributes: PayloadAttributes) -> Self { let id = payload_id(&parent, &attributes); - let withdraw = attributes.withdrawals.map(|withdrawals| { - Withdrawals::new( - withdrawals - .into_iter() - .map(convert_standalone_withdraw_to_withdrawal) // Removed the parentheses here - .collect(), - ) - }); - Self { id, parent, timestamp: attributes.timestamp, suggested_fee_recipient: attributes.suggested_fee_recipient, prev_randao: attributes.prev_randao, - withdrawals: withdraw.unwrap_or_default(), + withdrawals: attributes.withdrawals.unwrap_or_default().into(), parent_beacon_block_root: attributes.parent_beacon_block_root, } } diff --git a/crates/payload/optimism/src/payload.rs b/crates/payload/optimism/src/payload.rs index d753370fd2b7..b90d05d5f7e8 100644 --- a/crates/payload/optimism/src/payload.rs +++ b/crates/payload/optimism/src/payload.rs @@ -16,8 +16,7 @@ use reth_rpc_types::engine::{ OptimismPayloadAttributes, PayloadId, }; use reth_rpc_types_compat::engine::payload::{ - block_to_payload_v3, convert_block_to_payload_field_v2, - convert_standalone_withdraw_to_withdrawal, try_block_to_payload_v1, + block_to_payload_v3, convert_block_to_payload_field_v2, try_block_to_payload_v1, }; use revm::primitives::HandlerCfg; use std::sync::Arc; @@ -54,19 +53,13 @@ impl PayloadBuilderAttributes for OptimismPayloadBuilderAttributes { (payload_id_optimism(&parent, &attributes, &transactions), transactions) }; - let withdraw = attributes.payload_attributes.withdrawals.map(|withdrawals| { - Withdrawals::new( - withdrawals.into_iter().map(convert_standalone_withdraw_to_withdrawal).collect(), - ) - }); - let payload_attributes = EthPayloadBuilderAttributes { id, parent, timestamp: attributes.payload_attributes.timestamp, suggested_fee_recipient: attributes.payload_attributes.suggested_fee_recipient, prev_randao: attributes.payload_attributes.prev_randao, - withdrawals: withdraw.unwrap_or_default(), + withdrawals: attributes.payload_attributes.withdrawals.unwrap_or_default().into(), parent_beacon_block_root: attributes.payload_attributes.parent_beacon_block_root, }; diff --git a/crates/primitives/src/withdrawal.rs b/crates/primitives/src/withdrawal.rs index a348b6a051c3..e47b2816a80b 100644 --- a/crates/primitives/src/withdrawal.rs +++ b/crates/primitives/src/withdrawal.rs @@ -1,51 +1,12 @@ -use crate::{constants::GWEI_TO_WEI, serde_helper::u64_via_ruint, Address}; -use alloy_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper}; -use reth_codecs::{main_codec, Compact}; -use std::{ - mem, - ops::{Deref, DerefMut}, -}; +//! [EIP-4895](https://eips.ethereum.org/EIPS/eip-4895) Withdrawal types. -/// Withdrawal represents a validator withdrawal from the consensus layer. -#[main_codec] -#[derive(Debug, Clone, PartialEq, Eq, Default, Hash, RlpEncodable, RlpDecodable)] -pub struct Withdrawal { - /// Monotonically increasing identifier issued by consensus layer. - #[serde(with = "u64_via_ruint")] - pub index: u64, - /// Index of validator associated with withdrawal. - #[serde(with = "u64_via_ruint", rename = "validatorIndex")] - pub validator_index: u64, - /// Target address for withdrawn ether. - pub address: Address, - /// Value of the withdrawal in gwei. - #[serde(with = "u64_via_ruint")] - pub amount: u64, -} +use alloy_rlp::{RlpDecodableWrapper, RlpEncodableWrapper}; +use reth_codecs::{main_codec, Compact}; +use std::ops::{Deref, DerefMut}; -impl Withdrawal { - /// Return the withdrawal amount in wei. - pub fn amount_wei(&self) -> u128 { - self.amount as u128 * GWEI_TO_WEI as u128 - } - - /// Calculate a heuristic for the in-memory size of the [Withdrawal]. - #[inline] - pub fn size(&self) -> usize { - mem::size_of::() - } -} - -impl From for Withdrawal { - fn from(withdrawal: reth_rpc_types::Withdrawal) -> Self { - Self { - index: withdrawal.index, - validator_index: withdrawal.index, - address: withdrawal.address, - amount: withdrawal.amount, - } - } -} +/// Re-export from `alloy_eips`. +#[doc(inline)] +pub use alloy_eips::eip4895::Withdrawal; /// Represents a collection of Withdrawals. #[main_codec] @@ -61,13 +22,13 @@ impl Withdrawals { /// Calculate the total size, including capacity, of the Withdrawals. #[inline] pub fn total_size(&self) -> usize { - self.size() + self.capacity() * std::mem::size_of::() + self.capacity() * std::mem::size_of::() } /// Calculate a heuristic for the in-memory size of the [Withdrawals]. #[inline] pub fn size(&self) -> usize { - self.iter().map(Withdrawal::size).sum() + self.len() * std::mem::size_of::() } /// Get an iterator over the Withdrawals. @@ -115,15 +76,45 @@ impl DerefMut for Withdrawals { } } -impl From> for Withdrawals { - fn from(withdrawals: Vec) -> Self { - Self(withdrawals.into_iter().map(Into::into).collect()) +impl From> for Withdrawals { + fn from(withdrawals: Vec) -> Self { + Self(withdrawals) } } #[cfg(test)] mod tests { use super::*; + use crate::{serde_helper::u64_via_ruint, Address}; + use alloy_rlp::{RlpDecodable, RlpEncodable}; + use proptest::proptest; + + /// This type is kept for compatibility tests after the codec support was added to alloy-eips + /// Withdrawal type natively + #[main_codec] + #[derive(Debug, Clone, PartialEq, Eq, Default, Hash, RlpEncodable, RlpDecodable)] + struct RethWithdrawal { + /// Monotonically increasing identifier issued by consensus layer. + #[serde(with = "u64_via_ruint")] + index: u64, + /// Index of validator associated with withdrawal. + #[serde(with = "u64_via_ruint", rename = "validatorIndex")] + validator_index: u64, + /// Target address for withdrawn ether. + address: Address, + /// Value of the withdrawal in gwei. + #[serde(with = "u64_via_ruint")] + amount: u64, + } + + impl PartialEq for RethWithdrawal { + fn eq(&self, other: &Withdrawal) -> bool { + self.index == other.index && + self.validator_index == other.validator_index && + self.address == other.address && + self.amount == other.amount + } + } // #[test] @@ -134,4 +125,23 @@ mod tests { let s = serde_json::to_string(&withdrawals).unwrap(); assert_eq!(input, s); } + + proptest!( + #[test] + fn test_roundtrip_withdrawal_compat(withdrawal: RethWithdrawal) { + // Convert to buffer and then create alloy_access_list from buffer and + // compare + let mut compacted_reth_withdrawal = Vec::::new(); + let len = withdrawal.clone().to_compact(&mut compacted_reth_withdrawal); + + // decode the compacted buffer to AccessList + let alloy_withdrawal = Withdrawal::from_compact(&compacted_reth_withdrawal, len).0; + assert_eq!(withdrawal, alloy_withdrawal); + + let mut compacted_alloy_withdrawal = Vec::::new(); + let alloy_len = alloy_withdrawal.to_compact(&mut compacted_alloy_withdrawal); + assert_eq!(len, alloy_len); + assert_eq!(compacted_reth_withdrawal, compacted_alloy_withdrawal); + } + ); } diff --git a/crates/revm/src/state_change.rs b/crates/revm/src/state_change.rs index 5d38c656e35b..d2b0a6b5b380 100644 --- a/crates/revm/src/state_change.rs +++ b/crates/revm/src/state_change.rs @@ -152,7 +152,7 @@ pub fn insert_post_block_withdrawals_balance_increments( for withdrawal in withdrawals.iter() { if withdrawal.amount > 0 { *balance_increments.entry(withdrawal.address).or_default() += - withdrawal.amount_wei(); + withdrawal.amount_wei().to::(); } } } diff --git a/crates/rpc/rpc-engine-api/tests/it/payload.rs b/crates/rpc/rpc-engine-api/tests/it/payload.rs index 8853b5c88b97..0979af400cca 100644 --- a/crates/rpc/rpc-engine-api/tests/it/payload.rs +++ b/crates/rpc/rpc-engine-api/tests/it/payload.rs @@ -13,8 +13,8 @@ use reth_rpc_types::engine::{ ExecutionPayload, ExecutionPayloadBodyV1, ExecutionPayloadV1, PayloadError, }; use reth_rpc_types_compat::engine::payload::{ - convert_standalone_withdraw_to_withdrawal, convert_to_payload_body_v1, try_block_to_payload, - try_block_to_payload_v1, try_into_sealed_block, try_payload_v1_to_block, + convert_to_payload_body_v1, try_block_to_payload, try_block_to_payload_v1, + try_into_sealed_block, try_payload_v1_to_block, }; fn transform_block Block>(src: SealedBlock, f: F) -> ExecutionPayload { @@ -46,11 +46,7 @@ fn payload_body_roundtrip() { .map(|x| TransactionSigned::decode(&mut &x[..])) .collect::, _>>(), ); - let withdraw = payload_body.withdrawals.map(|withdrawals| { - Withdrawals::new( - withdrawals.into_iter().map(convert_standalone_withdraw_to_withdrawal).collect(), - ) - }); + let withdraw = payload_body.withdrawals.map(Withdrawals::new); assert_eq!(block.withdrawals, withdraw); } } diff --git a/crates/rpc/rpc-types-compat/src/engine/mod.rs b/crates/rpc/rpc-types-compat/src/engine/mod.rs index e03ba6f4cd8d..e14b8350051c 100644 --- a/crates/rpc/rpc-types-compat/src/engine/mod.rs +++ b/crates/rpc/rpc-types-compat/src/engine/mod.rs @@ -1,6 +1,3 @@ //! Standalone functions for engine specific rpc type conversions pub mod payload; -pub use payload::{ - convert_standalone_withdraw_to_withdrawal, convert_withdrawal_to_standalone_withdraw, - try_block_to_payload_v1, try_into_sealed_block, try_payload_v1_to_block, -}; +pub use payload::{try_block_to_payload_v1, try_into_sealed_block, try_payload_v1_to_block}; diff --git a/crates/rpc/rpc-types-compat/src/engine/payload.rs b/crates/rpc/rpc-types-compat/src/engine/payload.rs index 46947530103c..fdacab4e6225 100644 --- a/crates/rpc/rpc-types-compat/src/engine/payload.rs +++ b/crates/rpc/rpc-types-compat/src/engine/payload.rs @@ -4,7 +4,7 @@ use reth_primitives::{ constants::{EMPTY_OMMER_ROOT_HASH, MAXIMUM_EXTRA_DATA_SIZE, MIN_PROTOCOL_BASE_FEE_U256}, proofs::{self}, - Block, Header, SealedBlock, TransactionSigned, UintTryTo, Withdrawal, Withdrawals, B256, U256, + Block, Header, SealedBlock, TransactionSigned, UintTryTo, Withdrawals, B256, U256, }; use reth_rpc_types::engine::{ payload::{ExecutionPayloadBodyV1, ExecutionPayloadFieldV2, ExecutionPayloadInputV2}, @@ -65,11 +65,8 @@ pub fn try_payload_v2_to_block(payload: ExecutionPayloadV2) -> Result ExecutionPayloadV1 { /// Converts [SealedBlock] to [ExecutionPayloadV2] pub fn try_block_to_payload_v2(value: SealedBlock) -> ExecutionPayloadV2 { let transactions = value.raw_transactions(); - let standalone_withdrawals: Vec = value - .withdrawals - .clone() - .unwrap_or_default() - .into_iter() - .map(convert_withdrawal_to_standalone_withdraw) - .collect(); ExecutionPayloadV2 { payload_inner: ExecutionPayloadV1 { @@ -149,7 +139,7 @@ pub fn try_block_to_payload_v2(value: SealedBlock) -> ExecutionPayloadV2 { block_hash: value.hash(), transactions, }, - withdrawals: standalone_withdrawals, + withdrawals: value.withdrawals.unwrap_or_default().into_inner(), } } @@ -157,15 +147,9 @@ pub fn try_block_to_payload_v2(value: SealedBlock) -> ExecutionPayloadV2 { pub fn block_to_payload_v3(value: SealedBlock) -> ExecutionPayloadV3 { let transactions = value.raw_transactions(); - let withdrawals: Vec = value - .withdrawals - .clone() - .unwrap_or_default() - .into_iter() - .map(convert_withdrawal_to_standalone_withdraw) - .collect(); - ExecutionPayloadV3 { + blob_gas_used: value.blob_gas_used.unwrap_or_default(), + excess_blob_gas: value.excess_blob_gas.unwrap_or_default(), payload_inner: ExecutionPayloadV2 { payload_inner: ExecutionPayloadV1 { parent_hash: value.parent_hash, @@ -183,11 +167,8 @@ pub fn block_to_payload_v3(value: SealedBlock) -> ExecutionPayloadV3 { block_hash: value.hash(), transactions, }, - withdrawals, + withdrawals: value.withdrawals.unwrap_or_default().into_inner(), }, - - blob_gas_used: value.blob_gas_used.unwrap_or_default(), - excess_blob_gas: value.excess_blob_gas.unwrap_or_default(), } } @@ -222,11 +203,8 @@ pub fn convert_payload_input_v2_to_payload(value: ExecutionPayloadInputV2) -> Ex /// Converts [SealedBlock] to [ExecutionPayloadInputV2] pub fn convert_block_to_payload_input_v2(value: SealedBlock) -> ExecutionPayloadInputV2 { - let withdraw = value.withdrawals.clone().map(|withdrawals| { - withdrawals.into_iter().map(convert_withdrawal_to_standalone_withdraw).collect::>() - }); ExecutionPayloadInputV2 { - withdrawals: withdraw, + withdrawals: value.withdrawals.clone().map(Withdrawals::into_inner), execution_payload: try_block_to_payload_v1(value), } } @@ -295,30 +273,6 @@ pub fn validate_block_hash( Ok(sealed_block) } -/// Converts [Withdrawal] to [reth_rpc_types::Withdrawal] -pub fn convert_withdrawal_to_standalone_withdraw( - withdrawal: Withdrawal, -) -> reth_rpc_types::Withdrawal { - reth_rpc_types::Withdrawal { - index: withdrawal.index, - validator_index: withdrawal.validator_index, - address: withdrawal.address, - amount: withdrawal.amount, - } -} - -/// Converts [reth_rpc_types::Withdrawal] to [Withdrawal] -pub fn convert_standalone_withdraw_to_withdrawal( - standalone: reth_rpc_types::Withdrawal, -) -> Withdrawal { - Withdrawal { - index: standalone.index, - validator_index: standalone.validator_index, - address: standalone.address, - amount: standalone.amount, - } -} - /// Converts [Block] to [ExecutionPayloadBodyV1] pub fn convert_to_payload_body_v1(value: Block) -> ExecutionPayloadBodyV1 { let transactions = value.body.into_iter().map(|tx| { @@ -326,10 +280,10 @@ pub fn convert_to_payload_body_v1(value: Block) -> ExecutionPayloadBodyV1 { tx.encode_enveloped(&mut out); out.into() }); - let withdraw: Option> = value.withdrawals.map(|withdrawals| { - withdrawals.into_iter().map(convert_withdrawal_to_standalone_withdraw).collect::>() - }); - ExecutionPayloadBodyV1 { transactions: transactions.collect(), withdrawals: withdraw } + ExecutionPayloadBodyV1 { + transactions: transactions.collect(), + withdrawals: value.withdrawals.map(Withdrawals::into_inner), + } } /// Transforms a [SealedBlock] into a [ExecutionPayloadV1]