Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: make block <-> payload conversions generic over transaction #13389

Merged
merged 3 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/consensus/beacon/src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2061,7 +2061,7 @@ mod tests {
// consensus engine is still idle because no FCUs were received
let _ = env
.send_new_payload(
block_to_payload_v1(SealedBlock::default()),
block_to_payload_v1(SealedBlock::<_>::default()),
ExecutionPayloadSidecar::none(),
)
.await;
Expand Down
2 changes: 1 addition & 1 deletion crates/consensus/common/src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ mod tests {
};

// Single withdrawal
let block = create_block_with_withdrawals(&[1]);
let block: SealedBlock = create_block_with_withdrawals(&[1]);
assert_eq!(validate_block_pre_execution(&block, &chain_spec), Ok(()));

// Multiple increasing withdrawals
Expand Down
2 changes: 1 addition & 1 deletion crates/engine/tree/src/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3222,7 +3222,7 @@ mod tests {
async fn test_holesky_payload() {
let s = include_str!("../../test-data/holesky/1.rlp");
let data = Bytes::from_str(s).unwrap();
let block = Block::decode(&mut data.as_ref()).unwrap();
let block: Block = Block::decode(&mut data.as_ref()).unwrap();
let sealed = block.seal_slow();
let payload = block_to_payload_v1(sealed);

Expand Down
94 changes: 57 additions & 37 deletions crates/primitives/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,36 @@ use alloy_rlp::{Decodable, Encodable, RlpDecodable, RlpEncodable};
use derive_more::{Deref, DerefMut};
#[cfg(any(test, feature = "arbitrary"))]
pub use reth_primitives_traits::test_utils::{generate_valid_header, valid_header_strategy};
use reth_primitives_traits::{BlockBody as _, InMemorySize, SignedTransaction, Transaction};
use reth_primitives_traits::{
BlockBody as _, InMemorySize, MaybeSerdeBincodeCompat, SignedTransaction, Transaction,
};
use serde::{Deserialize, Serialize};

/// Ethereum full block.
///
/// Withdrawals can be optionally included at the end of the RLP encoded message.
#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(rlp, 25))]
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize, Deref)]
pub struct Block {
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Deref)]
pub struct Block<T = TransactionSigned> {
/// Block header.
#[deref]
pub header: Header,
/// Block body.
pub body: BlockBody,
pub body: BlockBody<T>,
}

impl reth_primitives_traits::Block for Block {
impl<T> Default for Block<T> {
fn default() -> Self {
Self { header: Default::default(), body: Default::default() }
}
}

impl<T> reth_primitives_traits::Block for Block<T>
where
T: SignedTransaction + Encodable + Decodable + MaybeSerdeBincodeCompat,
{
type Header = Header;
type Body = BlockBody;
type Body = BlockBody<T>;

fn new(header: Self::Header, body: Self::Body) -> Self {
Self { header, body }
Expand All @@ -47,7 +58,7 @@ impl reth_primitives_traits::Block for Block {
}
}

impl InMemorySize for Block {
impl<T: InMemorySize> InMemorySize for Block<T> {
/// Calculates a heuristic for the in-memory size of the [`Block`].
#[inline]
fn size(&self) -> usize {
Expand All @@ -62,24 +73,24 @@ mod block_rlp {

#[derive(RlpDecodable)]
#[rlp(trailing)]
struct Helper<H> {
struct Helper<H, T> {
header: H,
transactions: Vec<TransactionSigned>,
transactions: Vec<T>,
ommers: Vec<Header>,
withdrawals: Option<Withdrawals>,
}

#[derive(RlpEncodable)]
#[rlp(trailing)]
struct HelperRef<'a, H> {
struct HelperRef<'a, H, T = TransactionSigned> {
header: &'a H,
transactions: &'a Vec<TransactionSigned>,
transactions: &'a Vec<T>,
ommers: &'a Vec<Header>,
withdrawals: Option<&'a Withdrawals>,
}

impl<'a> From<&'a Block> for HelperRef<'a, Header> {
fn from(block: &'a Block) -> Self {
impl<'a, T> From<&'a Block<T>> for HelperRef<'a, Header, T> {
fn from(block: &'a Block<T>) -> Self {
let Block { header, body: BlockBody { transactions, ommers, withdrawals } } = block;
Self { header, transactions, ommers, withdrawals: withdrawals.as_ref() }
}
Expand All @@ -93,7 +104,7 @@ mod block_rlp {
}
}

impl Decodable for Block {
impl<T: Decodable> Decodable for Block<T> {
fn decode(b: &mut &[u8]) -> alloy_rlp::Result<Self> {
let Helper { header, transactions, ommers, withdrawals } = Helper::decode(b)?;
Ok(Self { header, body: BlockBody { transactions, ommers, withdrawals } })
Expand All @@ -107,26 +118,26 @@ mod block_rlp {
}
}

impl Encodable for Block {
impl<T: Encodable> Encodable for Block<T> {
fn encode(&self, out: &mut dyn bytes::BufMut) {
let helper: HelperRef<'_, _> = self.into();
let helper: HelperRef<'_, _, _> = self.into();
helper.encode(out)
}

fn length(&self) -> usize {
let helper: HelperRef<'_, _> = self.into();
let helper: HelperRef<'_, _, _> = self.into();
helper.length()
}
}

impl Encodable for SealedBlock {
fn encode(&self, out: &mut dyn bytes::BufMut) {
let helper: HelperRef<'_, _> = self.into();
let helper: HelperRef<'_, _, _> = self.into();
helper.encode(out)
}

fn length(&self) -> usize {
let helper: HelperRef<'_, _> = self.into();
let helper: HelperRef<'_, _, _> = self.into();
helper.length()
}
}
Expand Down Expand Up @@ -231,7 +242,6 @@ impl<B: reth_primitives_traits::Block> BlockWithSenders<B> {
/// Sealed Ethereum full block.
///
/// Withdrawals can be optionally included at the end of the RLP encoded message.
#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(rlp, 32))]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Deref, DerefMut)]
pub struct SealedBlock<H = Header, B = BlockBody> {
/// Locked block header.
Expand Down Expand Up @@ -560,9 +570,7 @@ impl<'a> arbitrary::Arbitrary<'a> for SealedBlockWithSenders {
///
/// Withdrawals can be optionally included at the end of the RLP encoded message.
#[cfg_attr(any(test, feature = "reth-codec"), reth_codecs::add_arbitrary_tests(rlp, 10))]
#[derive(
Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize, RlpEncodable, RlpDecodable,
)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RlpEncodable, RlpDecodable)]
#[rlp(trailing)]
pub struct BlockBody<T = TransactionSigned> {
/// Transactions in the block
Expand All @@ -573,6 +581,16 @@ pub struct BlockBody<T = TransactionSigned> {
pub withdrawals: Option<Withdrawals>,
}

impl<T> Default for BlockBody<T> {
fn default() -> Self {
Self {
transactions: Default::default(),
ommers: Default::default(),
withdrawals: Default::default(),
}
}
}

impl BlockBody {
/// Create a [`Block`] from the body and its header.
pub const fn into_block(self, header: Header) -> Block {
Expand Down Expand Up @@ -641,8 +659,11 @@ impl<T: InMemorySize> InMemorySize for BlockBody<T> {
}
}

impl reth_primitives_traits::BlockBody for BlockBody {
type Transaction = TransactionSigned;
impl<T> reth_primitives_traits::BlockBody for BlockBody<T>
where
T: SignedTransaction + MaybeSerdeBincodeCompat,
{
type Transaction = T;
type OmmerHeader = Header;

fn transactions(&self) -> &[Self::Transaction] {
Expand Down Expand Up @@ -704,8 +725,6 @@ pub(super) mod serde_bincode_compat {
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_with::{DeserializeAs, SerializeAs};

use crate::transaction::serde_bincode_compat::TransactionSigned;

/// Bincode-compatible [`super::BlockBody`] serde implementation.
///
/// Intended to use with the [`serde_with::serde_as`] macro in the following way:
Expand All @@ -721,15 +740,16 @@ pub(super) mod serde_bincode_compat {
/// body: BlockBody,
/// }
/// ```
#[derive(Debug, Serialize, Deserialize)]
pub struct BlockBody<'a> {
transactions: Vec<TransactionSigned<'a>>,
#[derive(derive_more::Debug, Serialize, Deserialize)]
#[debug(bound())]
pub struct BlockBody<'a, T: SerdeBincodeCompat = super::TransactionSigned> {
transactions: Vec<T::BincodeRepr<'a>>,
ommers: Vec<Header<'a>>,
withdrawals: Cow<'a, Option<Withdrawals>>,
}

impl<'a> From<&'a super::BlockBody> for BlockBody<'a> {
fn from(value: &'a super::BlockBody) -> Self {
impl<'a, T: SerdeBincodeCompat> From<&'a super::BlockBody<T>> for BlockBody<'a, T> {
fn from(value: &'a super::BlockBody<T>) -> Self {
Self {
transactions: value.transactions.iter().map(Into::into).collect(),
ommers: value.ommers.iter().map(Into::into).collect(),
Expand All @@ -738,8 +758,8 @@ pub(super) mod serde_bincode_compat {
}
}

impl<'a> From<BlockBody<'a>> for super::BlockBody {
fn from(value: BlockBody<'a>) -> Self {
impl<'a, T: SerdeBincodeCompat> From<BlockBody<'a, T>> for super::BlockBody<T> {
fn from(value: BlockBody<'a, T>) -> Self {
Self {
transactions: value.transactions.into_iter().map(Into::into).collect(),
ommers: value.ommers.into_iter().map(Into::into).collect(),
Expand All @@ -766,8 +786,8 @@ pub(super) mod serde_bincode_compat {
}
}

impl SerdeBincodeCompat for super::BlockBody {
type BincodeRepr<'a> = BlockBody<'a>;
impl<T: SerdeBincodeCompat> SerdeBincodeCompat for super::BlockBody<T> {
type BincodeRepr<'a> = BlockBody<'a, T>;
}

/// Bincode-compatible [`super::SealedBlock`] serde implementation.
Expand Down Expand Up @@ -1128,7 +1148,7 @@ mod tests {
fn encode_decode_raw_block() {
let bytes = hex!("f90288f90218a0fe21bb173f43067a9f90cfc59bbb6830a7a2929b5de4a61f372a9db28e87f9aea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a061effbbcca94f0d3e02e5bd22e986ad57142acabf0cb3d129a6ad8d0f8752e94a0d911c25e97e27898680d242b7780b6faef30995c355a2d5de92e6b9a7212ad3aa0056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008003834c4b408252081e80a00000000000000000000000000000000000000000000000000000000000000000880000000000000000842806be9da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421f869f86702842806be9e82520894658bdf435d810c91414ec09147daa6db624063798203e880820a95a040ce7918eeb045ebf8c8b1887ca139d076bda00fa828a07881d442a72626c42da0156576a68e456e295e4c9cf67cf9f53151f329438916e0f24fc69d6bbb7fbacfc0c0");
let bytes_buf = &mut bytes.as_ref();
let block = Block::decode(bytes_buf).unwrap();
let block: Block = Block::decode(bytes_buf).unwrap();
let mut encoded_buf = Vec::with_capacity(bytes.len());
block.encode(&mut encoded_buf);
assert_eq!(bytes[..], encoded_buf);
Expand Down
2 changes: 1 addition & 1 deletion crates/primitives/src/proofs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use crate::Receipt;
use alloy_eips::eip2718::Encodable2718;
use alloy_primitives::B256;
use alloy_trie::root::ordered_trie_root_with_encoder;
pub use alloy_trie::root::ordered_trie_root_with_encoder;

pub use alloy_consensus::proofs::calculate_receipt_root;

Expand Down
5 changes: 5 additions & 0 deletions crates/primitives/src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1637,6 +1637,7 @@ pub mod serde_bincode_compat {
TxEip4844,
};
use alloy_primitives::{PrimitiveSignature as Signature, TxHash};
use reth_primitives_traits::serde_bincode_compat::SerdeBincodeCompat;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_with::{DeserializeAs, SerializeAs};

Expand Down Expand Up @@ -1778,6 +1779,10 @@ pub mod serde_bincode_compat {
}
}

impl SerdeBincodeCompat for super::TransactionSigned {
type BincodeRepr<'a> = TransactionSigned<'a>;
}

#[cfg(test)]
mod tests {
use super::super::{serde_bincode_compat, Transaction, TransactionSigned};
Expand Down
3 changes: 2 additions & 1 deletion crates/rpc/rpc-engine-api/tests/it/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ fn payload_validation() {
payload_with_invalid_txs.transactions.iter_mut().for_each(|tx| {
*tx = Bytes::new();
});
let payload_with_invalid_txs = try_payload_v1_to_block(payload_with_invalid_txs);
let payload_with_invalid_txs =
try_payload_v1_to_block::<TransactionSigned>(payload_with_invalid_txs);
assert_matches!(payload_with_invalid_txs, Err(PayloadError::Decode(RlpError::InputTooShort)));

// Non empty ommers
Expand Down
Loading
Loading