mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: make Block generic over transaction (#13388)
This commit is contained in:
@ -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
|
||||
|
||||
@ -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 }
|
||||
@ -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 {
|
||||
@ -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() }
|
||||
}
|
||||
@ -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 } })
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
@ -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.
|
||||
@ -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
|
||||
@ -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 {
|
||||
@ -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] {
|
||||
@ -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:
|
||||
@ -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(),
|
||||
@ -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(),
|
||||
@ -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.
|
||||
@ -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);
|
||||
|
||||
@ -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};
|
||||
|
||||
@ -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};
|
||||
|
||||
Reference in New Issue
Block a user