Skip to content

Commit

Permalink
feat: replace duplicate Withdrawal type with alloy (paradigmxyz#7931)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattsse authored Apr 27, 2024
1 parent 5f15af5 commit 2deb259
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 142 deletions.
14 changes: 2 additions & 12 deletions crates/ethereum/engine-primitives/src/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
}
}
Expand Down
11 changes: 2 additions & 9 deletions crates/payload/optimism/src/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
};

Expand Down
112 changes: 61 additions & 51 deletions crates/primitives/src/withdrawal.rs
Original file line number Diff line number Diff line change
@@ -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::<Self>()
}
}

impl From<reth_rpc_types::Withdrawal> 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]
Expand All @@ -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::<Withdrawal>()
self.capacity() * std::mem::size_of::<Withdrawal>()
}

/// 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::<Withdrawal>()
}

/// Get an iterator over the Withdrawals.
Expand Down Expand Up @@ -115,15 +76,45 @@ impl DerefMut for Withdrawals {
}
}

impl From<Vec<reth_rpc_types::Withdrawal>> for Withdrawals {
fn from(withdrawals: Vec<reth_rpc_types::Withdrawal>) -> Self {
Self(withdrawals.into_iter().map(Into::into).collect())
impl From<Vec<Withdrawal>> for Withdrawals {
fn from(withdrawals: Vec<Withdrawal>) -> 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<Withdrawal> 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
}
}

// <https://github.com/paradigmxyz/reth/issues/1614>
#[test]
Expand All @@ -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::<u8>::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::<u8>::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);
}
);
}
2 changes: 1 addition & 1 deletion crates/revm/src/state_change.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<u128>();
}
}
}
Expand Down
10 changes: 3 additions & 7 deletions crates/rpc/rpc-engine-api/tests/it/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<F: FnOnce(Block) -> Block>(src: SealedBlock, f: F) -> ExecutionPayload {
Expand Down Expand Up @@ -46,11 +46,7 @@ fn payload_body_roundtrip() {
.map(|x| TransactionSigned::decode(&mut &x[..]))
.collect::<Result<Vec<_>, _>>(),
);
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);
}
}
Expand Down
5 changes: 1 addition & 4 deletions crates/rpc/rpc-types-compat/src/engine/mod.rs
Original file line number Diff line number Diff line change
@@ -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};
70 changes: 12 additions & 58 deletions crates/rpc/rpc-types-compat/src/engine/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -65,11 +65,8 @@ pub fn try_payload_v2_to_block(payload: ExecutionPayloadV2) -> Result<Block, Pay
// this performs the same conversion as the underlying V1 payload, but calculates the
// withdrawals root and adds withdrawals
let mut base_sealed_block = try_payload_v1_to_block(payload.payload_inner)?;
let withdrawals = Withdrawals::new(
payload.withdrawals.iter().map(|w| convert_standalone_withdraw_to_withdrawal(*w)).collect(),
);
let withdrawals_root = proofs::calculate_withdrawals_root(&withdrawals);
base_sealed_block.withdrawals = Some(withdrawals);
let withdrawals_root = proofs::calculate_withdrawals_root(&payload.withdrawals);
base_sealed_block.withdrawals = Some(payload.withdrawals.into());
base_sealed_block.header.withdrawals_root = Some(withdrawals_root);
Ok(base_sealed_block)
}
Expand Down Expand Up @@ -124,13 +121,6 @@ pub fn try_block_to_payload_v1(value: SealedBlock) -> ExecutionPayloadV1 {
/// Converts [SealedBlock] to [ExecutionPayloadV2]
pub fn try_block_to_payload_v2(value: SealedBlock) -> ExecutionPayloadV2 {
let transactions = value.raw_transactions();
let standalone_withdrawals: Vec<reth_rpc_types::Withdrawal> = value
.withdrawals
.clone()
.unwrap_or_default()
.into_iter()
.map(convert_withdrawal_to_standalone_withdraw)
.collect();

ExecutionPayloadV2 {
payload_inner: ExecutionPayloadV1 {
Expand All @@ -149,23 +139,17 @@ 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(),
}
}

/// Converts [SealedBlock] to [ExecutionPayloadV3]
pub fn block_to_payload_v3(value: SealedBlock) -> ExecutionPayloadV3 {
let transactions = value.raw_transactions();

let withdrawals: Vec<reth_rpc_types::Withdrawal> = 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,
Expand All @@ -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(),
}
}

Expand Down Expand Up @@ -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::<Vec<_>>()
});
ExecutionPayloadInputV2 {
withdrawals: withdraw,
withdrawals: value.withdrawals.clone().map(Withdrawals::into_inner),
execution_payload: try_block_to_payload_v1(value),
}
}
Expand Down Expand Up @@ -295,41 +273,17 @@ 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| {
let mut out = Vec::new();
tx.encode_enveloped(&mut out);
out.into()
});
let withdraw: Option<Vec<reth_rpc_types::Withdrawal>> = value.withdrawals.map(|withdrawals| {
withdrawals.into_iter().map(convert_withdrawal_to_standalone_withdraw).collect::<Vec<_>>()
});
ExecutionPayloadBodyV1 { transactions: transactions.collect(), withdrawals: withdraw }
ExecutionPayloadBodyV1 {
transactions: transactions.collect(),
withdrawals: value.withdrawals.map(Withdrawals::into_inner),
}
}

/// Transforms a [SealedBlock] into a [ExecutionPayloadV1]
Expand Down

0 comments on commit 2deb259

Please sign in to comment.