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: use alloy block types #13518

Merged
merged 8 commits into from
Dec 31, 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
5 changes: 2 additions & 3 deletions bin/reth-bench/src/bench/new_payload_fcu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use clap::Parser;
use csv::Writer;
use reth_cli_runner::CliContext;
use reth_node_core::args::BenchmarkArgs;
use reth_primitives::{Block, BlockExt};
use reth_primitives::SealedBlock;
use reth_rpc_types_compat::engine::payload::block_to_payload;
use std::time::Instant;
use tracing::{debug, info};
Expand Down Expand Up @@ -46,8 +46,7 @@ impl Command {
let block_res =
block_provider.get_block_by_number(next_block.into(), true.into()).await;
let block = block_res.unwrap().unwrap();
let block_hash = block.header.hash;
let block = Block::try_from(block).unwrap().seal(block_hash);
let block: SealedBlock = block.try_into().unwrap();
let head_block_hash = block.hash();
let safe_block_hash = block_provider
.get_block_by_number(block.number.saturating_sub(32).into(), false.into());
Expand Down
5 changes: 2 additions & 3 deletions bin/reth-bench/src/bench/new_payload_only.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use clap::Parser;
use csv::Writer;
use reth_cli_runner::CliContext;
use reth_node_core::args::BenchmarkArgs;
use reth_primitives::{Block, BlockExt};
use reth_primitives::SealedBlock;
use reth_rpc_types_compat::engine::payload::block_to_payload;
use std::time::Instant;
use tracing::{debug, info};
Expand Down Expand Up @@ -46,8 +46,7 @@ impl Command {
let block_res =
block_provider.get_block_by_number(next_block.into(), true.into()).await;
let block = block_res.unwrap().unwrap();
let block_hash = block.header.hash;
let block = Block::try_from(block).unwrap().seal(block_hash);
let block: SealedBlock = block.try_into().unwrap();

next_block += 1;
sender.send(block).await.unwrap();
Expand Down
6 changes: 3 additions & 3 deletions crates/optimism/consensus/src/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub fn validate_block_post_execution(
block.header.logs_bloom,
receipts,
chain_spec,
block.timestamp,
block.header.timestamp,
) {
tracing::debug!(%error, ?receipts, "receipts verification failed");
return Err(error)
Expand All @@ -35,9 +35,9 @@ pub fn validate_block_post_execution(
// Check if gas used matches the value set in header.
let cumulative_gas_used =
receipts.last().map(|receipt| receipt.cumulative_gas_used()).unwrap_or(0);
if block.gas_used != cumulative_gas_used {
if block.header.gas_used != cumulative_gas_used {
return Err(ConsensusError::BlockGasUsed {
gas: GotExpected { got: cumulative_gas_used, expected: block.gas_used },
gas: GotExpected { got: cumulative_gas_used, expected: block.header.gas_used },
gas_spent_by_tx: gas_spent_by_transactions(receipts),
})
}
Expand Down
82 changes: 81 additions & 1 deletion crates/primitives-traits/src/serde_bincode_compat.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use core::fmt::Debug;
use serde::{de::DeserializeOwned, Serialize};

pub use super::header::{serde_bincode_compat as header, serde_bincode_compat::*};
use serde::{de::DeserializeOwned, Serialize};
pub use block_bincode::BlockBody;

/// Trait for types that can be serialized and deserialized using bincode.
pub trait SerdeBincodeCompat: Sized + 'static {
Expand All @@ -12,3 +13,82 @@ pub trait SerdeBincodeCompat: Sized + 'static {
impl SerdeBincodeCompat for alloy_consensus::Header {
type BincodeRepr<'a> = alloy_consensus::serde_bincode_compat::Header<'a>;
}

mod block_bincode {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this I had to move because the trait is defined here and is generic over SerdeBincodeCompat, we could perhaps move this trait entirely to alloy

use crate::serde_bincode_compat::SerdeBincodeCompat;
use alloc::{borrow::Cow, vec::Vec};
use alloy_consensus::serde_bincode_compat::Header;
use alloy_eips::eip4895::Withdrawals;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_with::{DeserializeAs, SerializeAs};

/// Bincode-compatible [`alloy_consensus::BlockBody`] serde implementation.
///
/// Intended to use with the [`serde_with::serde_as`] macro in the following way:
/// ```rust
/// use reth_primitives_traits::serde_bincode_compat::{self, SerdeBincodeCompat};
/// use serde::{Deserialize, Serialize};
/// use serde_with::serde_as;
///
/// #[serde_as]
/// #[derive(Serialize, Deserialize)]
/// struct Data<T: SerdeBincodeCompat> {
/// #[serde_as(as = "serde_bincode_compat::BlockBody<'_, T>")]
/// body: alloy_consensus::BlockBody<T>,
/// }
/// ```
#[derive(derive_more::Debug, Serialize, Deserialize)]
#[debug(bound())]
pub struct BlockBody<'a, T: SerdeBincodeCompat> {
transactions: Vec<T::BincodeRepr<'a>>,
ommers: Vec<Header<'a>>,
withdrawals: Cow<'a, Option<Withdrawals>>,
}

impl<'a, T: SerdeBincodeCompat> From<&'a alloy_consensus::BlockBody<T>> for BlockBody<'a, T> {
fn from(value: &'a alloy_consensus::BlockBody<T>) -> Self {
Self {
transactions: value.transactions.iter().map(Into::into).collect(),
ommers: value.ommers.iter().map(Into::into).collect(),
withdrawals: Cow::Borrowed(&value.withdrawals),
}
}
}

impl<'a, T: SerdeBincodeCompat> From<BlockBody<'a, T>> for alloy_consensus::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(),
withdrawals: value.withdrawals.into_owned(),
}
}
}

impl<T: SerdeBincodeCompat> SerializeAs<alloy_consensus::BlockBody<T>> for BlockBody<'_, T> {
fn serialize_as<S>(
source: &alloy_consensus::BlockBody<T>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
BlockBody::from(source).serialize(serializer)
}
}

impl<'de, T: SerdeBincodeCompat> DeserializeAs<'de, alloy_consensus::BlockBody<T>>
for BlockBody<'de, T>
{
fn deserialize_as<D>(deserializer: D) -> Result<alloy_consensus::BlockBody<T>, D::Error>
where
D: Deserializer<'de>,
{
BlockBody::deserialize(deserializer).map(Into::into)
}
}

impl<T: SerdeBincodeCompat> SerdeBincodeCompat for alloy_consensus::BlockBody<T> {
type BincodeRepr<'a> = BlockBody<'a, T>;
}
}
87 changes: 10 additions & 77 deletions crates/primitives/src/alloy_compat.rs
Original file line number Diff line number Diff line change
@@ -1,92 +1,25 @@
//! Common conversions from alloy types.

use crate::{Block, BlockBody, Transaction, TransactionSigned};
use alloc::{string::ToString, vec::Vec};
use alloy_consensus::{constants::EMPTY_TRANSACTIONS, Header, TxEnvelope};
use alloy_network::{AnyHeader, AnyRpcBlock, AnyRpcTransaction, AnyTxEnvelope};
use crate::{BlockBody, SealedBlock, Transaction, TransactionSigned};
use alloc::string::ToString;
use alloy_consensus::TxEnvelope;
use alloy_network::{AnyRpcBlock, AnyRpcTransaction, AnyTxEnvelope};
use alloy_serde::WithOtherFields;
use op_alloy_rpc_types as _;
use reth_primitives_traits::SealedHeader;

impl TryFrom<AnyRpcBlock> for Block {
impl TryFrom<AnyRpcBlock> for SealedBlock {
type Error = alloy_rpc_types::ConversionError;

fn try_from(block: AnyRpcBlock) -> Result<Self, Self::Error> {
use alloy_rpc_types::ConversionError;

let block = block.inner;

let transactions = {
let transactions: Result<Vec<TransactionSigned>, ConversionError> = match block
.transactions
{
alloy_rpc_types::BlockTransactions::Full(transactions) => {
transactions.into_iter().map(|tx| tx.try_into()).collect()
}
alloy_rpc_types::BlockTransactions::Hashes(_) |
alloy_rpc_types::BlockTransactions::Uncle => {
// alloy deserializes empty blocks into `BlockTransactions::Hashes`, if the tx
// root is the empty root then we can just return an empty vec.
if block.header.transactions_root == EMPTY_TRANSACTIONS {
Ok(Vec::new())
} else {
Err(ConversionError::Custom("missing transactions".to_string()))
}
}
};
transactions?
};

let AnyHeader {
parent_hash,
ommers_hash,
beneficiary,
state_root,
transactions_root,
receipts_root,
logs_bloom,
difficulty,
number,
gas_limit,
gas_used,
timestamp,
extra_data,
mix_hash,
nonce,
base_fee_per_gas,
withdrawals_root,
blob_gas_used,
excess_blob_gas,
parent_beacon_block_root,
requests_hash,
} = block.header.inner;
let block_hash = block.header.hash;
let block = block.try_map_transactions(|tx| tx.try_into())?;

Ok(Self {
header: Header {
parent_hash,
ommers_hash,
beneficiary,
state_root,
transactions_root,
receipts_root,
logs_bloom,
difficulty,
number,
gas_limit,
gas_used,
timestamp,
extra_data,
mix_hash: mix_hash
.ok_or_else(|| ConversionError::Custom("missing mixHash".to_string()))?,
nonce: nonce.ok_or_else(|| ConversionError::Custom("missing nonce".to_string()))?,
base_fee_per_gas,
withdrawals_root,
blob_gas_used,
excess_blob_gas,
parent_beacon_block_root,
requests_hash,
},
header: SealedHeader::new(block.header.inner.into_header_with_defaults(), block_hash),
body: BlockBody {
transactions,
transactions: block.transactions.into_transactions().collect(),
ommers: Default::default(),
withdrawals: block.withdrawals.map(|w| w.into_inner().into()),
},
Expand Down
Loading
Loading