mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-27 08:08:15 -05:00
chore(sdk): move block traits into reth-primitives-traits (#11780)
This commit is contained in:
99
crates/primitives-traits/src/block.rs
Normal file
99
crates/primitives-traits/src/block.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
//! Block abstraction.
|
||||
|
||||
pub mod body;
|
||||
|
||||
use alloc::fmt;
|
||||
use core::ops;
|
||||
|
||||
use alloy_consensus::BlockHeader;
|
||||
use alloy_primitives::{Address, Sealable, B256};
|
||||
|
||||
use crate::{traits::BlockBody, BlockWithSenders, SealedBlock, SealedHeader};
|
||||
|
||||
/// Abstraction of block data type.
|
||||
pub trait Block:
|
||||
fmt::Debug
|
||||
+ Clone
|
||||
+ PartialEq
|
||||
+ Eq
|
||||
+ Default
|
||||
+ serde::Serialize
|
||||
+ for<'a> serde::Deserialize<'a>
|
||||
+ From<(Self::Header, Self::Body)>
|
||||
+ Into<(Self::Header, Self::Body)>
|
||||
{
|
||||
/// Header part of the block.
|
||||
type Header: BlockHeader + Sealable;
|
||||
|
||||
/// The block's body contains the transactions in the block.
|
||||
type Body: BlockBody;
|
||||
|
||||
/// A block and block hash.
|
||||
type SealedBlock<H = Self::Header, B = Self::Body>;
|
||||
|
||||
/// A block and addresses of senders of transactions in it.
|
||||
type BlockWithSenders<T = Self>;
|
||||
|
||||
/// Returns reference to [`BlockHeader`] type.
|
||||
fn header(&self) -> &Self::Header;
|
||||
|
||||
/// Returns reference to [`BlockBody`] type.
|
||||
fn body(&self) -> &Self::Body;
|
||||
|
||||
/// Calculate the header hash and seal the block so that it can't be changed.
|
||||
// todo: can be default impl if sealed block type is made generic over header and body and
|
||||
// migrated to alloy
|
||||
fn seal_slow(self) -> Self::SealedBlock;
|
||||
|
||||
/// Seal the block with a known hash.
|
||||
///
|
||||
/// WARNING: This method does not perform validation whether the hash is correct.
|
||||
// todo: can be default impl if sealed block type is made generic over header and body and
|
||||
// migrated to alloy
|
||||
fn seal(self, hash: B256) -> Self::SealedBlock;
|
||||
|
||||
/// Expensive operation that recovers transaction signer. See
|
||||
/// [`SealedBlockWithSenders`](reth_primitives::SealedBlockWithSenders).
|
||||
fn senders(&self) -> Option<Vec<Address>> {
|
||||
self.body().recover_signers()
|
||||
}
|
||||
|
||||
/// Transform into a [`BlockWithSenders`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the number of senders does not match the number of transactions in the block
|
||||
/// and the signer recovery for one of the transactions fails.
|
||||
///
|
||||
/// Note: this is expected to be called with blocks read from disk.
|
||||
#[track_caller]
|
||||
fn with_senders_unchecked(self, senders: Vec<Address>) -> Self::BlockWithSenders {
|
||||
self.try_with_senders_unchecked(senders).expect("stored block is valid")
|
||||
}
|
||||
|
||||
/// Transform into a [`BlockWithSenders`] using the given senders.
|
||||
///
|
||||
/// If the number of senders does not match the number of transactions in the block, this falls
|
||||
/// back to manually recovery, but _without ensuring that the signature has a low `s` value_.
|
||||
/// See also [`TransactionSigned::recover_signer_unchecked`]
|
||||
///
|
||||
/// Returns an error if a signature is invalid.
|
||||
// todo: can be default impl if block with senders type is made generic over block and migrated
|
||||
// to alloy
|
||||
#[track_caller]
|
||||
fn try_with_senders_unchecked(
|
||||
self,
|
||||
senders: Vec<Address>,
|
||||
) -> Result<Self::BlockWithSenders, Self>;
|
||||
|
||||
/// **Expensive**. Transform into a [`BlockWithSenders`] by recovering senders in the contained
|
||||
/// transactions.
|
||||
///
|
||||
/// Returns `None` if a transaction is invalid.
|
||||
// todo: can be default impl if sealed block type is made generic over header and body and
|
||||
// migrated to alloy
|
||||
fn with_recovered_senders(self) -> Option<Self::BlockWithSenders>;
|
||||
|
||||
/// Calculates a heuristic for the in-memory size of the [`Block`].
|
||||
fn size(&self) -> usize;
|
||||
}
|
||||
@@ -3,10 +3,11 @@
|
||||
use alloc::fmt;
|
||||
use core::ops;
|
||||
|
||||
use alloy_consensus::{BlockHeader, Transaction, TxType};
|
||||
use alloy_consensus::{BlockHeader,Request, Transaction, TxType};
|
||||
use alloy_primitives::{Address, B256};
|
||||
use alloy_eips::eip1559::Withdrawal;
|
||||
|
||||
use crate::{proofs, traits::Block, Requests, Withdrawals};
|
||||
use crate::Block;
|
||||
|
||||
/// Abstraction for block's body.
|
||||
pub trait BlockBody:
|
||||
@@ -27,18 +28,24 @@ pub trait BlockBody:
|
||||
/// Header type (uncle blocks).
|
||||
type Header: BlockHeader;
|
||||
|
||||
/// Withdrawals in block.
|
||||
type Withdrawals: Iterator<Item = Withdrawal>;
|
||||
|
||||
/// Requests in block.
|
||||
type Requests: Iterator<Item = Request>;
|
||||
|
||||
/// Returns reference to transactions in block.
|
||||
fn transactions(&self) -> &[Self::SignedTransaction];
|
||||
|
||||
/// Returns [`Withdrawals`] in the block, if any.
|
||||
// todo: branch out into extension trait
|
||||
fn withdrawals(&self) -> Option<&Withdrawals>;
|
||||
fn withdrawals(&self) -> Option<&Self::Withdrawals>;
|
||||
|
||||
/// Returns reference to uncle block headers.
|
||||
fn ommers(&self) -> &[Self::Header];
|
||||
|
||||
/// Returns [`Request`] in block, if any.
|
||||
fn requests(&self) -> Option<&Requests>;
|
||||
fn requests(&self) -> Option<&Self::Requests>;
|
||||
|
||||
/// Create a [`Block`] from the body and its header.
|
||||
fn into_block<T: Block<Header = Self::Header, Body = Self>>(self, header: Self::Header) -> T {
|
||||
@@ -53,15 +60,15 @@ pub trait BlockBody:
|
||||
|
||||
/// Calculate the withdrawals root for the block body, if withdrawals exist. If there are no
|
||||
/// withdrawals, this will return `None`.
|
||||
fn calculate_withdrawals_root(&self) -> Option<B256> {
|
||||
Some(proofs::calculate_withdrawals_root(self.withdrawals()?))
|
||||
}
|
||||
// todo: can be default impl if `calculate_withdrawals_root` made into a method on
|
||||
// `Withdrawals` and `Withdrawals` moved to alloy
|
||||
fn calculate_withdrawals_root(&self) -> Option<B256>;
|
||||
|
||||
/// Calculate the requests root for the block body, if requests exist. If there are no
|
||||
/// requests, this will return `None`.
|
||||
fn calculate_requests_root(&self) -> Option<B256> {
|
||||
Some(proofs::calculate_requests_root(self.requests()?))
|
||||
}
|
||||
// todo: can be default impl if `calculate_requests_root` made into a method on
|
||||
// `Requests` and `Requests` moved to alloy
|
||||
fn calculate_requests_root(&self) -> Option<B256>;
|
||||
|
||||
/// Recover signer addresses for all transactions in the block body.
|
||||
fn recover_signers(&self) -> Option<Vec<Address>>;
|
||||
@@ -28,6 +28,12 @@ pub trait Block:
|
||||
/// The block's body contains the transactions in the block.
|
||||
type Body: BlockBody;
|
||||
|
||||
/// A block and block hash.
|
||||
type SealedBlock<H = Self::Header, B = Self::Body>;
|
||||
|
||||
/// A block and addresses of senders of transactions in it.
|
||||
type BlockWithSenders<T = Self>;
|
||||
|
||||
/// Returns reference to [`BlockHeader`] type.
|
||||
fn header(&self) -> &Self::Header;
|
||||
|
||||
@@ -35,20 +41,16 @@ pub trait Block:
|
||||
fn body(&self) -> &Self::Body;
|
||||
|
||||
/// Calculate the header hash and seal the block so that it can't be changed.
|
||||
fn seal_slow(self) -> SealedBlock<Self::Header, Self::Body> {
|
||||
let (header, body) = self.into();
|
||||
let sealed = header.seal_slow();
|
||||
let (header, seal) = sealed.into_parts();
|
||||
SealedBlock { header: SealedHeader::new(header, seal), body }
|
||||
}
|
||||
// todo: can be default impl if sealed block type is made generic over header and body and
|
||||
// migrated to alloy
|
||||
fn seal_slow(self) -> Self::SealedBlock;
|
||||
|
||||
/// Seal the block with a known hash.
|
||||
///
|
||||
/// WARNING: This method does not perform validation whether the hash is correct.
|
||||
fn seal(self, hash: B256) -> SealedBlock<Self::Header, Self::Body> {
|
||||
let (header, body) = self.into();
|
||||
SealedBlock { header: SealedHeader::new(header, hash), body }
|
||||
}
|
||||
// todo: can be default impl if sealed block type is made generic over header and body and
|
||||
// migrated to alloy
|
||||
fn seal(self, hash: B256) -> Self::SealedBlock;
|
||||
|
||||
/// Expensive operation that recovers transaction signer. See
|
||||
/// [`SealedBlockWithSenders`](reth_primitives::SealedBlockWithSenders).
|
||||
@@ -65,7 +67,7 @@ pub trait Block:
|
||||
///
|
||||
/// Note: this is expected to be called with blocks read from disk.
|
||||
#[track_caller]
|
||||
fn with_senders_unchecked(self, senders: Vec<Address>) -> BlockWithSenders<Self> {
|
||||
fn with_senders_unchecked(self, senders: Vec<Address>) -> Self::BlockWithSenders {
|
||||
self.try_with_senders_unchecked(senders).expect("stored block is valid")
|
||||
}
|
||||
|
||||
@@ -76,62 +78,22 @@ pub trait Block:
|
||||
/// See also [`TransactionSigned::recover_signer_unchecked`]
|
||||
///
|
||||
/// Returns an error if a signature is invalid.
|
||||
// todo: can be default impl if block with senders type is made generic over block and migrated
|
||||
// to alloy
|
||||
#[track_caller]
|
||||
fn try_with_senders_unchecked(
|
||||
self,
|
||||
senders: Vec<Address>,
|
||||
) -> Result<BlockWithSenders<Self>, Self> {
|
||||
let senders = if self.body().transactions().len() == senders.len() {
|
||||
senders
|
||||
} else {
|
||||
let Some(senders) = self.body().recover_signers() else { return Err(self) };
|
||||
senders
|
||||
};
|
||||
|
||||
Ok(BlockWithSenders { block: self, senders })
|
||||
}
|
||||
) -> Result<Self::BlockWithSenders, Self>;
|
||||
|
||||
/// **Expensive**. Transform into a [`BlockWithSenders`] by recovering senders in the contained
|
||||
/// transactions.
|
||||
///
|
||||
/// Returns `None` if a transaction is invalid.
|
||||
fn with_recovered_senders(self) -> Option<BlockWithSenders<Self>> {
|
||||
let senders = self.senders()?;
|
||||
Some(BlockWithSenders { block: self, senders })
|
||||
}
|
||||
// todo: can be default impl if sealed block type is made generic over header and body and
|
||||
// migrated to alloy
|
||||
fn with_recovered_senders(self) -> Option<Self::BlockWithSenders>;
|
||||
|
||||
/// Calculates a heuristic for the in-memory size of the [`Block`].
|
||||
fn size(&self) -> usize;
|
||||
}
|
||||
|
||||
impl<T> Block for T
|
||||
where
|
||||
T: ops::Deref<Target: Block>
|
||||
+ fmt::Debug
|
||||
+ Clone
|
||||
+ PartialEq
|
||||
+ Eq
|
||||
+ Default
|
||||
+ serde::Serialize
|
||||
+ for<'a> serde::Deserialize<'a>
|
||||
+ From<(<T::Target as Block>::Header, <T::Target as Block>::Body)>
|
||||
+ Into<(<T::Target as Block>::Header, <T::Target as Block>::Body)>,
|
||||
{
|
||||
type Header = <T::Target as Block>::Header;
|
||||
type Body = <T::Target as Block>::Body;
|
||||
|
||||
#[inline]
|
||||
fn header(&self) -> &Self::Header {
|
||||
self.deref().header()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn body(&self) -> &Self::Body {
|
||||
self.deref().body()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size(&self) -> usize {
|
||||
self.deref().size()
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
//! Abstractions of primitive data types
|
||||
|
||||
pub mod block;
|
||||
|
||||
pub use block::{body::BlockBody, Block};
|
||||
|
||||
pub use alloy_consensus::BlockHeader;
|
||||
Reference in New Issue
Block a user