feat: make more block types generic (#12812)

This commit is contained in:
Arsenii Kulikov
2024-11-25 14:50:10 +04:00
committed by GitHub
parent 02824da4fc
commit dcaa06a01a
62 changed files with 534 additions and 333 deletions

View File

@@ -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;
use reth_primitives::{Block, BlockExt};
use reth_rpc_types_compat::engine::payload::block_to_payload;
use std::time::Instant;
use tracing::{debug, info};
@@ -75,11 +75,11 @@ impl Command {
while let Some((block, head, safe, finalized)) = receiver.recv().await {
// just put gas used here
let gas_used = block.header.gas_used;
let gas_used = block.gas_used;
let block_number = block.header.number;
let versioned_hashes: Vec<B256> =
block.blob_versioned_hashes().into_iter().copied().collect();
block.body.blob_versioned_hashes().into_iter().copied().collect();
let parent_beacon_block_root = block.parent_beacon_block_root;
let payload = block_to_payload(block);

View File

@@ -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;
use reth_primitives::{Block, BlockExt};
use reth_rpc_types_compat::engine::payload::block_to_payload;
use std::time::Instant;
use tracing::{debug, info};
@@ -60,10 +60,10 @@ impl Command {
while let Some(block) = receiver.recv().await {
// just put gas used here
let gas_used = block.header.gas_used;
let gas_used = block.gas_used;
let versioned_hashes: Vec<B256> =
block.blob_versioned_hashes().into_iter().copied().collect();
block.body.blob_versioned_hashes().into_iter().copied().collect();
let parent_beacon_block_root = block.parent_beacon_block_root;
let payload = block_to_payload(block);

View File

@@ -22,11 +22,11 @@ use reth_errors::RethResult;
use reth_evm::execute::{BlockExecutorProvider, Executor};
use reth_execution_types::ExecutionOutcome;
use reth_fs_util as fs;
use reth_node_api::{EngineApiMessageVersion, PayloadBuilderAttributes};
use reth_node_api::{BlockTy, EngineApiMessageVersion, PayloadBuilderAttributes};
use reth_node_ethereum::{EthEvmConfig, EthExecutorProvider};
use reth_primitives::{
BlobTransaction, PooledTransactionsElement, SealedBlock, SealedBlockWithSenders, SealedHeader,
Transaction, TransactionSigned,
BlobTransaction, BlockExt, PooledTransactionsElement, SealedBlock, SealedBlockWithSenders,
SealedHeader, Transaction, TransactionSigned,
};
use reth_provider::{
providers::{BlockchainProvider, ProviderNodeTypes},
@@ -259,7 +259,7 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
let senders = block.senders().expect("sender recovery failed");
let block_with_senders =
SealedBlockWithSenders::new(block.clone(), senders).unwrap();
SealedBlockWithSenders::<BlockTy<N>>::new(block.clone(), senders).unwrap();
let db = StateProviderDatabase::new(blockchain_db.latest()?);
let executor =

View File

@@ -20,6 +20,7 @@ use reth_execution_types::ExecutionOutcome;
use reth_network::{BlockDownloaderProvider, NetworkHandle};
use reth_network_api::NetworkInfo;
use reth_node_ethereum::EthExecutorProvider;
use reth_primitives::BlockExt;
use reth_provider::{
providers::ProviderNodeTypes, writer::UnifiedStorageWriter, AccountExtReader,
ChainSpecProvider, HashingWriter, HeaderProvider, LatestStateProviderRef, OriginalValuesKnown,

View File

@@ -17,6 +17,7 @@ use reth_evm::execute::{BatchExecutor, BlockExecutorProvider};
use reth_network::{BlockDownloaderProvider, NetworkHandle};
use reth_network_api::NetworkInfo;
use reth_network_p2p::full_block::FullBlockClient;
use reth_node_api::BlockTy;
use reth_node_ethereum::EthExecutorProvider;
use reth_provider::{
providers::ProviderNodeTypes, writer::UnifiedStorageWriter, BlockNumReader, BlockWriter,
@@ -144,7 +145,7 @@ impl<C: ChainSpecParser<ChainSpec = ChainSpec>> Command<C> {
for block in blocks.into_iter().rev() {
let block_number = block.number;
let sealed_block = block
.try_seal_with_senders()
.try_seal_with_senders::<BlockTy<N>>()
.map_err(|block| eyre::eyre!("Error sealing block with senders: {block:?}"))?;
trace!(target: "reth::cli", block_number, "Executing block");

View File

@@ -1589,7 +1589,9 @@ mod tests {
body: Vec<TransactionSignedEcRecovered>,
num_of_signer_txs: u64|
-> SealedBlockWithSenders {
let transactions_root = calculate_transaction_root(&body);
let signed_body =
body.clone().into_iter().map(|tx| tx.into_signed()).collect::<Vec<_>>();
let transactions_root = calculate_transaction_root(&signed_body);
let receipts = body
.iter()
.enumerate()
@@ -1635,7 +1637,7 @@ mod tests {
SealedBlock {
header: SealedHeader::seal(header),
body: BlockBody {
transactions: body.clone().into_iter().map(|tx| tx.into_signed()).collect(),
transactions: signed_body,
ommers: Vec::new(),
withdrawals: Some(Withdrawals::default()),
},

View File

@@ -5,24 +5,40 @@ use reth_consensus::Consensus;
use reth_db::{static_file::BlockHashMask, tables};
use reth_db_api::{cursor::DbCursorRO, transaction::DbTx};
use reth_node_types::{FullNodePrimitives, NodeTypesWithDB};
use reth_primitives::{BlockBody, StaticFileSegment};
use reth_primitives::StaticFileSegment;
use reth_provider::{
providers::ProviderNodeTypes, ChainStateBlockReader, ChainStateBlockWriter, ProviderFactory,
StaticFileProviderFactory, StatsReader,
providers::{NodeTypesForProvider, ProviderNodeTypes},
ChainStateBlockReader, ChainStateBlockWriter, ProviderFactory, StaticFileProviderFactory,
StatsReader,
};
use reth_storage_errors::provider::ProviderResult;
use std::{collections::BTreeMap, sync::Arc};
/// A helper trait with requirements for [`ProviderNodeTypes`] to be used within [`TreeExternals`].
pub trait TreeNodeTypes:
ProviderNodeTypes<Primitives: FullNodePrimitives<BlockBody = BlockBody>>
pub trait NodeTypesForTree:
NodeTypesForProvider<
Primitives: FullNodePrimitives<
Block = reth_primitives::Block,
BlockBody = reth_primitives::BlockBody,
>,
>
{
}
impl<T> TreeNodeTypes for T where
T: ProviderNodeTypes<Primitives: FullNodePrimitives<BlockBody = BlockBody>>
impl<T> NodeTypesForTree for T where
T: NodeTypesForProvider<
Primitives: FullNodePrimitives<
Block = reth_primitives::Block,
BlockBody = reth_primitives::BlockBody,
>,
>
{
}
/// A helper trait with requirements for [`ProviderNodeTypes`] to be used within [`TreeExternals`].
pub trait TreeNodeTypes: ProviderNodeTypes + NodeTypesForTree {}
impl<T> TreeNodeTypes for T where T: ProviderNodeTypes + NodeTypesForTree {}
/// A container for external components.
///
/// This is a simple container for external components used throughout the blockchain tree

View File

@@ -139,7 +139,9 @@ impl TestBlockBuilder {
gas_limit: self.chain_spec.max_gas_limit,
mix_hash: B256::random(),
base_fee_per_gas: Some(INITIAL_BASE_FEE),
transactions_root: calculate_transaction_root(&transactions),
transactions_root: calculate_transaction_root(
&transactions.clone().into_iter().map(|tx| tx.into_signed()).collect::<Vec<_>>(),
),
receipts_root: calculate_receipt_root(&receipts),
beneficiary: Address::random(),
state_root: state_root_unhashed(HashMap::from([(

View File

@@ -197,11 +197,21 @@ impl AccessRights {
/// [`NodeTypes`](reth_node_builder::NodeTypes) in CLI.
pub trait CliNodeTypes:
NodeTypesWithEngine
+ NodeTypesForProvider<Primitives: FullNodePrimitives<BlockBody = reth_primitives::BlockBody>>
+ NodeTypesForProvider<
Primitives: FullNodePrimitives<
Block = reth_primitives::Block,
BlockBody = reth_primitives::BlockBody,
>,
>
{
}
impl<N> CliNodeTypes for N where
N: NodeTypesWithEngine
+ NodeTypesForProvider<Primitives: FullNodePrimitives<BlockBody = reth_primitives::BlockBody>>
+ NodeTypesForProvider<
Primitives: FullNodePrimitives<
Block = reth_primitives::Block,
BlockBody = reth_primitives::BlockBody,
>,
>
{
}

View File

@@ -33,7 +33,7 @@ pub fn setup_without_evm<Provider>(
where
Provider: StaticFileProviderFactory
+ StageCheckpointWriter
+ BlockWriter<Body: reth_node_api::BlockBody>,
+ BlockWriter<Block: reth_node_api::Block<Header = reth_primitives::Header>>,
{
info!(target: "reth::cli", "Setting up dummy EVM chain before importing state.");
@@ -64,7 +64,8 @@ fn append_first_block<Provider>(
total_difficulty: U256,
) -> Result<(), eyre::Error>
where
Provider: BlockWriter<Body: reth_node_api::BlockBody> + StaticFileProviderFactory,
Provider: BlockWriter<Block: reth_node_api::Block<Header = reth_primitives::Header>>
+ StaticFileProviderFactory,
{
provider_rw.insert_block(
SealedBlockWithSenders::new(SealedBlock::new(header.clone(), Default::default()), vec![])

View File

@@ -1992,6 +1992,7 @@ mod tests {
use assert_matches::assert_matches;
use reth_chainspec::{ChainSpecBuilder, MAINNET};
use reth_node_types::FullNodePrimitives;
use reth_primitives::BlockExt;
use reth_provider::{BlockWriter, ProviderFactory, StorageLocation};
use reth_rpc_types_compat::engine::payload::block_to_payload_v1;
use reth_stages::{ExecOutput, PipelineError, StageError};

View File

@@ -4,7 +4,9 @@ use alloy_consensus::{constants::MAXIMUM_EXTRA_DATA_SIZE, Header};
use alloy_eips::eip4844::{DATA_GAS_PER_BLOB, MAX_DATA_GAS_PER_BLOCK};
use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_consensus::ConsensusError;
use reth_primitives::{BlockBody, EthereumHardfork, GotExpected, SealedBlock, SealedHeader};
use reth_primitives::{
BlockBody, BlockBodyTxExt, EthereumHardfork, GotExpected, SealedBlock, SealedHeader,
};
use revm_primitives::calc_excess_blob_gas;
/// Gas used needs to be less than gas limit. Gas used is going to be checked after execution.

View File

@@ -5,6 +5,7 @@ use std::sync::Arc;
use node::NodeTestContext;
use reth::{
args::{DiscoveryArgs, NetworkArgs, RpcServerArgs},
blockchain_tree::externals::NodeTypesForTree,
builder::{FullNodePrimitives, NodeBuilder, NodeConfig, NodeHandle},
network::PeersHandleProvider,
rpc::server_types::RpcModuleSelection,
@@ -53,13 +54,12 @@ pub async fn setup<N>(
attributes_generator: impl Fn(u64) -> <<N as NodeTypesWithEngine>::Engine as PayloadTypes>::PayloadBuilderAttributes + Copy + 'static,
) -> eyre::Result<(Vec<NodeHelperType<N, N::AddOns>>, TaskManager, Wallet)>
where
N: Default + Node<TmpNodeAdapter<N>> + NodeTypesForProvider + NodeTypesWithEngine,
N: Default + Node<TmpNodeAdapter<N>> + NodeTypesForTree + NodeTypesWithEngine,
N::ComponentsBuilder: NodeComponentsBuilder<
TmpNodeAdapter<N>,
Components: NodeComponents<TmpNodeAdapter<N>, Network: PeersHandleProvider>,
>,
N::AddOns: RethRpcAddOns<Adapter<N>>,
N::Primitives: FullNodePrimitives<BlockBody = reth_primitives::BlockBody>,
{
let tasks = TaskManager::current();
let exec = tasks.executor();
@@ -134,7 +134,8 @@ where
LocalPayloadAttributesBuilder<N::ChainSpec>: PayloadAttributesBuilder<
<<N as NodeTypesWithEngine>::Engine as PayloadTypes>::PayloadAttributes,
>,
N::Primitives: FullNodePrimitives<BlockBody = reth_primitives::BlockBody>,
N::Primitives:
FullNodePrimitives<Block = reth_primitives::Block, BlockBody = reth_primitives::BlockBody>,
{
let tasks = TaskManager::current();
let exec = tasks.executor();

View File

@@ -216,7 +216,7 @@ where
// get head block from notifications stream and verify the tx has been pushed to the
// pool is actually present in the canonical block
let head = self.engine_api.canonical_stream.next().await.unwrap();
let tx = head.tip().transactions().next();
let tx = head.tip().transactions().first();
assert_eq!(tx.unwrap().hash().as_slice(), tip_tx_hash.as_slice());
loop {

View File

@@ -210,12 +210,13 @@ where
let block = payload.block();
let cancun_fields =
self.provider.chain_spec().is_cancun_active_at_timestamp(block.timestamp).then(|| {
CancunPayloadFields {
parent_beacon_block_root: block.parent_beacon_block_root.unwrap(),
versioned_hashes: block.blob_versioned_hashes().into_iter().copied().collect(),
}
let cancun_fields = self
.provider
.chain_spec()
.is_cancun_active_at_timestamp(block.timestamp)
.then(|| CancunPayloadFields {
parent_beacon_block_root: block.parent_beacon_block_root.unwrap(),
versioned_hashes: block.body.blob_versioned_hashes().into_iter().copied().collect(),
});
let (tx, rx) = oneshot::channel();

View File

@@ -21,11 +21,15 @@ use tracing::{debug, error};
/// A helper trait with requirements for [`ProviderNodeTypes`] to be used within
/// [`PersistenceService`].
pub trait PersistenceNodeTypes:
ProviderNodeTypes<Primitives: FullNodePrimitives<BlockBody = BlockBody>>
ProviderNodeTypes<
Primitives: FullNodePrimitives<Block = reth_primitives::Block, BlockBody = BlockBody>,
>
{
}
impl<T> PersistenceNodeTypes for T where
T: ProviderNodeTypes<Primitives: FullNodePrimitives<BlockBody = BlockBody>>
T: ProviderNodeTypes<
Primitives: FullNodePrimitives<Block = reth_primitives::Block, BlockBody = BlockBody>,
>
{
}
/// Writes parts of reth's in memory tree state to the database and static files.

View File

@@ -2609,6 +2609,7 @@ mod tests {
use reth_engine_primitives::ForkchoiceStatus;
use reth_ethereum_engine_primitives::EthEngineTypes;
use reth_evm::test_utils::MockExecutorProvider;
use reth_primitives::BlockExt;
use reth_provider::test_utils::MockEthProvider;
use reth_rpc_types_compat::engine::{block_to_payload_v1, payload::block_to_payload_v3};
use reth_trie::updates::TrieUpdates;

View File

@@ -18,7 +18,7 @@ use reth_evm::{
ConfigureEvm,
};
use reth_payload_validator::ExecutionPayloadValidator;
use reth_primitives::{proofs, Block, BlockBody, Receipt, Receipts};
use reth_primitives::{proofs, Block, BlockBody, BlockExt, Receipt, Receipts};
use reth_provider::{BlockReader, ExecutionOutcome, ProviderError, StateProviderFactory};
use reth_revm::{
database::StateProviderDatabase,

View File

@@ -319,7 +319,9 @@ mod tests {
BasicBlockExecutorProvider, BatchExecutor, BlockExecutorProvider, Executor,
};
use reth_execution_types::BlockExecutionOutput;
use reth_primitives::{public_key_to_address, Account, Block, BlockBody, Transaction};
use reth_primitives::{
public_key_to_address, Account, Block, BlockBody, BlockExt, Transaction,
};
use reth_revm::{
database::StateProviderDatabase, test_utils::StateProviderTest, TransitionState,
};

View File

@@ -63,7 +63,7 @@ where
let head = notifications.next().await.unwrap();
let tx = head.tip().transactions().next().unwrap();
let tx = &head.tip().transactions()[0];
assert_eq!(tx.hash(), hash);
println!("mined transaction: {hash}");
}

View File

@@ -27,7 +27,7 @@ use reth_payload_builder_primitives::PayloadBuilderError;
use reth_payload_primitives::PayloadBuilderAttributes;
use reth_primitives::{
proofs::{self},
Block, BlockBody, EthereumHardforks, Receipt,
Block, BlockBody, BlockExt, EthereumHardforks, Receipt,
};
use reth_provider::{ChainSpecProvider, StateProviderFactory};
use reth_revm::database::StateProviderDatabase;

View File

@@ -236,7 +236,7 @@ impl<N: NodePrimitives> Chain<N> {
self.blocks().iter().zip(self.execution_outcome.receipts().iter())
{
let mut tx_receipts = Vec::with_capacity(receipts.len());
for (tx, receipt) in block.body.transactions().zip(receipts.iter()) {
for (tx, receipt) in block.body.transactions.iter().zip(receipts.iter()) {
tx_receipts.push((
tx.hash(),
receipt.as_ref().expect("receipts have not been pruned").clone(),
@@ -417,7 +417,7 @@ impl ChainBlocks<'_> {
/// Returns an iterator over all transactions in the chain.
#[inline]
pub fn transactions(&self) -> impl Iterator<Item = &TransactionSigned> + '_ {
self.blocks.values().flat_map(|block| block.body.transactions())
self.blocks.values().flat_map(|block| block.body.transactions.iter())
}
/// Returns an iterator over all transactions and their senders.
@@ -441,7 +441,7 @@ impl ChainBlocks<'_> {
/// Returns an iterator over all transaction hashes in the block
#[inline]
pub fn transaction_hashes(&self) -> impl Iterator<Item = TxHash> + '_ {
self.blocks.values().flat_map(|block| block.transactions().map(|tx| tx.hash()))
self.blocks.values().flat_map(|block| block.transactions().iter().map(|tx| tx.hash()))
}
}

View File

@@ -8,7 +8,7 @@ use alloy_primitives::BlockNumber;
use reth_evm::execute::{
BatchExecutor, BlockExecutionError, BlockExecutionOutput, BlockExecutorProvider, Executor,
};
use reth_primitives::{Block, BlockWithSenders, Receipt};
use reth_primitives::{Block, BlockExt, BlockWithSenders, Receipt};
use reth_primitives_traits::format_gas_throughput;
use reth_provider::{
BlockReader, Chain, HeaderProvider, ProviderError, StateProviderFactory, TransactionVariant,

View File

@@ -11,7 +11,7 @@ use reth_evm::execute::{
use reth_evm_ethereum::execute::EthExecutorProvider;
use reth_node_api::FullNodePrimitives;
use reth_primitives::{
Block, BlockBody, BlockWithSenders, Receipt, SealedBlockWithSenders, Transaction,
Block, BlockBody, BlockExt, BlockWithSenders, Receipt, SealedBlockWithSenders, Transaction,
};
use reth_provider::{
providers::ProviderNodeTypes, BlockWriter as _, ExecutionOutcome, LatestStateProviderRef,
@@ -58,7 +58,12 @@ pub(crate) fn execute_block_and_commit_to_database<N>(
block: &BlockWithSenders,
) -> eyre::Result<BlockExecutionOutput<Receipt>>
where
N: ProviderNodeTypes<Primitives: FullNodePrimitives<BlockBody = reth_primitives::BlockBody>>,
N: ProviderNodeTypes<
Primitives: FullNodePrimitives<
Block = reth_primitives::Block,
BlockBody = reth_primitives::BlockBody,
>,
>,
{
let provider = provider_factory.provider()?;
@@ -162,7 +167,12 @@ pub(crate) fn blocks_and_execution_outputs<N>(
key_pair: Keypair,
) -> eyre::Result<Vec<(SealedBlockWithSenders, BlockExecutionOutput<Receipt>)>>
where
N: ProviderNodeTypes<Primitives: FullNodePrimitives<BlockBody = reth_primitives::BlockBody>>,
N: ProviderNodeTypes<
Primitives: FullNodePrimitives<
Block = reth_primitives::Block,
BlockBody = reth_primitives::BlockBody,
>,
>,
{
let (block1, block2) = blocks(chain_spec.clone(), key_pair)?;
@@ -184,7 +194,7 @@ pub(crate) fn blocks_and_execution_outcome<N>(
) -> eyre::Result<(Vec<SealedBlockWithSenders>, ExecutionOutcome)>
where
N: ProviderNodeTypes,
N::Primitives: FullNodePrimitives<BlockBody = reth_primitives::BlockBody>,
N::Primitives: FullNodePrimitives<Block = reth_primitives::Block>,
{
let (block1, block2) = blocks(chain_spec.clone(), key_pair)?;

View File

@@ -1235,7 +1235,7 @@ mod tests {
genesis_block.number + 1,
BlockParams { parent: Some(genesis_hash), ..Default::default() },
)
.seal_with_senders()
.seal_with_senders::<reth_primitives::Block>()
.unwrap();
let provider_rw = provider_factory.database_provider_rw().unwrap();
provider_rw.insert_block(block.clone(), StorageLocation::Database).unwrap();

View File

@@ -400,7 +400,7 @@ mod tests {
use futures::StreamExt;
use reth_db_common::init::init_genesis;
use reth_evm_ethereum::execute::EthExecutorProvider;
use reth_primitives::Block;
use reth_primitives::{Block, BlockExt};
use reth_provider::{
providers::BlockchainProvider2, test_utils::create_test_provider_factory, BlockWriter,
Chain, DatabaseProviderFactory, StorageLocation,
@@ -567,7 +567,7 @@ mod tests {
genesis_block.number + 1,
BlockParams { parent: Some(genesis_hash), tx_count: Some(0), ..Default::default() },
)
.seal_with_senders()
.seal_with_senders::<reth_primitives::Block>()
.ok_or_eyre("failed to recover senders")?;
let node_head = Head {
number: node_head_block.number,

View File

@@ -268,21 +268,25 @@ mod tests {
// Create 4 canonical blocks and one reorged block with number 2
let blocks = random_block_range(&mut rng, 0..=3, BlockRangeParams::default())
.into_iter()
.map(|block| block.seal_with_senders().ok_or_eyre("failed to recover senders"))
.map(|block| {
block
.seal_with_senders::<reth_primitives::Block>()
.ok_or_eyre("failed to recover senders")
})
.collect::<eyre::Result<Vec<_>>>()?;
let block_1_reorged = random_block(
&mut rng,
1,
BlockParams { parent: Some(blocks[0].hash()), ..Default::default() },
)
.seal_with_senders()
.seal_with_senders::<reth_primitives::Block>()
.ok_or_eyre("failed to recover senders")?;
let block_2_reorged = random_block(
&mut rng,
2,
BlockParams { parent: Some(blocks[1].hash()), ..Default::default() },
)
.seal_with_senders()
.seal_with_senders::<reth_primitives::Block>()
.ok_or_eyre("failed to recover senders")?;
// Create notifications for the above blocks.

View File

@@ -45,7 +45,7 @@ use reth_node_ethereum::{
EthEngineTypes, EthEvmConfig,
};
use reth_payload_builder::noop::NoopPayloadBuilderService;
use reth_primitives::{EthPrimitives, Head, SealedBlockWithSenders};
use reth_primitives::{BlockExt, EthPrimitives, Head, SealedBlockWithSenders};
use reth_provider::{
providers::{BlockchainProvider, StaticFileProvider},
BlockReader, EthStorage, ProviderFactory,
@@ -306,7 +306,7 @@ pub async fn test_exex_context_with_chain_spec(
.block_by_hash(genesis_hash)?
.ok_or_else(|| eyre::eyre!("genesis block not found"))?
.seal_slow()
.seal_with_senders()
.seal_with_senders::<reth_primitives::Block>()
.ok_or_else(|| eyre::eyre!("failed to recover senders"))?;
let head = Head {

View File

@@ -10,6 +10,7 @@ use crate::{
DefaultNodeLauncher, LaunchNode, Node, NodeHandle,
};
use futures::Future;
use reth_blockchain_tree::externals::NodeTypesForTree;
use reth_chainspec::{EthChainSpec, EthereumHardforks, Hardforks};
use reth_cli_util::get_secret_key;
use reth_db_api::{
@@ -358,7 +359,7 @@ where
>,
>
where
N: Node<RethFullAdapter<DB, N>, ChainSpec = ChainSpec> + NodeTypesForProvider,
N: Node<RethFullAdapter<DB, N>, ChainSpec = ChainSpec> + NodeTypesForTree,
N::AddOns: RethRpcAddOns<
NodeAdapter<
RethFullAdapter<DB, N>,
@@ -553,10 +554,9 @@ where
impl<T, DB, CB, AO> WithLaunchContext<NodeBuilderWithComponents<RethFullAdapter<DB, T>, CB, AO>>
where
DB: Database + DatabaseMetrics + DatabaseMetadata + Clone + Unpin + 'static,
T: NodeTypesWithEngine + NodeTypesForProvider,
T: NodeTypesWithEngine + NodeTypesForTree,
CB: NodeComponentsBuilder<RethFullAdapter<DB, T>>,
AO: RethRpcAddOns<NodeAdapter<RethFullAdapter<DB, T>, CB::Components>>,
T::Primitives: FullNodePrimitives<BlockBody = reth_primitives::BlockBody>,
{
/// Launches the node with the [`DefaultNodeLauncher`] that sets up engine API consensus and rpc
pub async fn launch(

View File

@@ -12,6 +12,7 @@ use reth_engine_local::{LocalEngineService, LocalPayloadAttributesBuilder};
use reth_engine_service::service::{ChainEvent, EngineService};
use reth_engine_tree::{
engine::{EngineApiRequest, EngineRequestHandler},
persistence::PersistenceNodeTypes,
tree::TreeConfig,
};
use reth_engine_util::EngineMessageStreamExt;
@@ -19,8 +20,8 @@ use reth_exex::ExExManagerHandle;
use reth_network::{NetworkSyncUpdater, SyncState};
use reth_network_api::BlockDownloaderProvider;
use reth_node_api::{
BuiltPayload, FullNodePrimitives, FullNodeTypes, NodeTypesWithEngine, PayloadAttributesBuilder,
PayloadBuilder, PayloadTypes,
BuiltPayload, FullNodeTypes, NodeTypesWithEngine, PayloadAttributesBuilder, PayloadBuilder,
PayloadTypes,
};
use reth_node_core::{
dirs::{ChainPath, DataDirPath},
@@ -70,14 +71,13 @@ impl EngineNodeLauncher {
impl<Types, T, CB, AO> LaunchNode<NodeBuilderWithComponents<T, CB, AO>> for EngineNodeLauncher
where
Types: ProviderNodeTypes + NodeTypesWithEngine,
Types: ProviderNodeTypes + NodeTypesWithEngine + PersistenceNodeTypes,
T: FullNodeTypes<Types = Types, Provider = BlockchainProvider2<Types>>,
CB: NodeComponentsBuilder<T>,
AO: RethRpcAddOns<NodeAdapter<T, CB::Components>>,
LocalPayloadAttributesBuilder<Types::ChainSpec>: PayloadAttributesBuilder<
<<Types as NodeTypesWithEngine>::Engine as PayloadTypes>::PayloadAttributes,
>,
Types::Primitives: FullNodePrimitives<BlockBody = reth_primitives::BlockBody>,
{
type Node = NodeHandle<NodeAdapter<T, CB::Components>, AO>;

View File

@@ -16,13 +16,15 @@ use reth_beacon_consensus::{
hooks::{EngineHooks, PruneHook, StaticFileHook},
BeaconConsensusEngine,
};
use reth_blockchain_tree::{noop::NoopBlockchainTree, BlockchainTreeConfig};
use reth_blockchain_tree::{
externals::TreeNodeTypes, noop::NoopBlockchainTree, BlockchainTreeConfig,
};
use reth_chainspec::EthChainSpec;
use reth_consensus_debug_client::{DebugConsensusClient, EtherscanBlockProvider, RpcBlockProvider};
use reth_engine_util::EngineMessageStreamExt;
use reth_exex::ExExManagerHandle;
use reth_network::BlockDownloaderProvider;
use reth_node_api::{AddOnsContext, FullNodePrimitives, FullNodeTypes, NodeTypesWithEngine};
use reth_node_api::{AddOnsContext, FullNodeTypes, NodeTypesWithEngine};
use reth_node_core::{
dirs::{ChainPath, DataDirPath},
exit::NodeExitFuture,
@@ -98,11 +100,10 @@ impl DefaultNodeLauncher {
impl<Types, T, CB, AO> LaunchNode<NodeBuilderWithComponents<T, CB, AO>> for DefaultNodeLauncher
where
Types: ProviderNodeTypes + NodeTypesWithEngine,
Types: ProviderNodeTypes + NodeTypesWithEngine + TreeNodeTypes,
T: FullNodeTypes<Provider = BlockchainProvider<Types>, Types = Types>,
CB: NodeComponentsBuilder<T>,
AO: RethRpcAddOns<NodeAdapter<T, CB::Components>>,
Types::Primitives: FullNodePrimitives<BlockBody = reth_primitives::BlockBody>,
{
type Node = NodeHandle<NodeAdapter<T, CB::Components>, AO>;

View File

@@ -14,7 +14,7 @@ use reth_exex::ExExManagerHandle;
use reth_network_p2p::{
bodies::downloader::BodyDownloader, headers::downloader::HeaderDownloader, EthBlockClient,
};
use reth_node_api::{FullNodePrimitives, NodePrimitives};
use reth_node_api::{BodyTy, FullNodePrimitives};
use reth_provider::{providers::ProviderNodeTypes, ProviderFactory};
use reth_stages::{prelude::DefaultStages, stages::ExecutionStage, Pipeline, StageSet};
use reth_static_file::StaticFileProducer;
@@ -87,9 +87,7 @@ pub fn build_pipeline<N, H, B, Executor>(
where
N: ProviderNodeTypes,
H: HeaderDownloader<Header = alloy_consensus::Header> + 'static,
B: BodyDownloader<
Body = <<N::Primitives as NodePrimitives>::Block as reth_node_api::Block>::Body,
> + 'static,
B: BodyDownloader<Body = BodyTy<N>> + 'static,
Executor: BlockExecutorProvider,
N::Primitives: FullNodePrimitives<BlockBody = reth_primitives::BlockBody>,
{

View File

@@ -233,6 +233,9 @@ where
type Engine = E;
}
/// Helper adapter type for accessing [`NodePrimitives::Block`] on [`NodeTypes`].
pub type BlockTy<N> = <<N as NodeTypes>::Primitives as NodePrimitives>::Block;
/// Helper adapter type for accessing [`NodePrimitives::BlockHeader`] on [`NodeTypes`].
pub type HeaderTy<N> = <<N as NodeTypes>::Primitives as NodePrimitives>::BlockHeader;

View File

@@ -18,7 +18,9 @@ use reth_optimism_forks::OpHardforks;
use reth_payload_builder_primitives::PayloadBuilderError;
use reth_payload_primitives::PayloadBuilderAttributes;
use reth_payload_util::PayloadTransactions;
use reth_primitives::{proofs, Block, BlockBody, Receipt, SealedHeader, TransactionSigned, TxType};
use reth_primitives::{
proofs, Block, BlockBody, BlockExt, Receipt, SealedHeader, TransactionSigned, TxType,
};
use reth_provider::{ProviderError, StateProofProvider, StateProviderFactory, StateRootProvider};
use reth_revm::database::StateProviderDatabase;
use reth_transaction_pool::{

View File

@@ -31,7 +31,7 @@
//! use alloy_consensus::Header;
//! use alloy_primitives::U256;
//! use reth_payload_builder::{EthBuiltPayload, PayloadBuilderError, KeepPayloadJobAlive, EthPayloadBuilderAttributes, PayloadJob, PayloadJobGenerator, PayloadKind};
//! use reth_primitives::Block;
//! use reth_primitives::{Block, BlockExt};
//!
//! /// The generator type that creates new jobs that builds empty blocks.
//! pub struct EmptyBlockPayloadJobGenerator;

View File

@@ -9,7 +9,7 @@ use alloy_primitives::U256;
use reth_chain_state::{CanonStateNotification, ExecutedBlock};
use reth_payload_builder_primitives::PayloadBuilderError;
use reth_payload_primitives::{PayloadKind, PayloadTypes};
use reth_primitives::Block;
use reth_primitives::{Block, BlockExt};
use std::{
future::Future,
pin::Pin,

View File

@@ -12,7 +12,7 @@ use alloy_rpc_types::engine::{
ExecutionPayload, ExecutionPayloadSidecar, MaybeCancunPayloadFields, PayloadError,
};
use reth_chainspec::EthereumHardforks;
use reth_primitives::SealedBlock;
use reth_primitives::{BlockExt, SealedBlock};
use reth_rpc_types_compat::engine::payload::try_into_block;
use std::sync::Arc;

View File

@@ -1,6 +1,6 @@
//! Block body abstraction.
use alloc::fmt;
use alloc::{fmt, vec::Vec};
use alloy_consensus::Transaction;
@@ -12,7 +12,6 @@ pub trait FullBlockBody: BlockBody<Transaction: FullSignedTx> {}
impl<T> FullBlockBody for T where T: BlockBody<Transaction: FullSignedTx> {}
/// Abstraction for block's body.
#[auto_impl::auto_impl(&, Arc)]
pub trait BlockBody:
Send
+ Sync
@@ -33,4 +32,7 @@ pub trait BlockBody:
/// Returns reference to transactions in block.
fn transactions(&self) -> &[Self::Transaction];
/// Consume the block body and return a [`Vec`] of transactions.
fn into_transactions(self) -> Vec<Self::Transaction>;
}

View File

@@ -6,7 +6,8 @@ pub mod header;
use alloc::fmt;
use crate::{
BlockHeader, FullBlockBody, FullBlockHeader, InMemorySize, MaybeArbitrary, MaybeSerde,
BlockBody, BlockHeader, FullBlockBody, FullBlockHeader, InMemorySize, MaybeArbitrary,
MaybeSerde,
};
/// Helper trait that unifies all behaviour required by block to support full node operations.
@@ -26,7 +27,6 @@ impl<T> FullBlock for T where
// todo: make sealable super-trait, depends on <https://github.com/paradigmxyz/reth/issues/11449>
// todo: make with senders extension trait, so block can be impl by block type already containing
// senders
#[auto_impl::auto_impl(&, Arc)]
pub trait Block:
Send
+ Sync
@@ -44,11 +44,17 @@ pub trait Block:
type Header: BlockHeader + 'static;
/// The block's body contains the transactions in the block.
type Body: Send + Sync + Unpin + 'static;
type Body: BlockBody + Send + Sync + Unpin + 'static;
/// Create new block instance.
fn new(header: Self::Header, body: Self::Body) -> Self;
/// Returns reference to block header.
fn header(&self) -> &Self::Header;
/// Returns reference to block body.
fn body(&self) -> &Self::Body;
/// Splits the block into its header and body.
fn split(self) -> (Self::Header, Self::Body);
}

View File

@@ -1,13 +1,16 @@
use crate::{GotExpected, SealedHeader, TransactionSigned, TransactionSignedEcRecovered};
use crate::{
traits::BlockExt, transaction::SignedTransactionIntoRecoveredExt, BlockBodyTxExt, GotExpected,
SealedHeader, TransactionSigned, TransactionSignedEcRecovered,
};
use alloc::vec::Vec;
use alloy_consensus::Header;
use alloy_eips::{eip2718::Encodable2718, eip4895::Withdrawals};
use alloy_primitives::{Address, Bytes, Sealable, B256};
use alloy_primitives::{Address, Bytes, B256};
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::InMemorySize;
use reth_primitives_traits::{BlockBody as _, InMemorySize, SignedTransaction};
use serde::{Deserialize, Serialize};
/// Ethereum full block.
@@ -23,73 +26,14 @@ pub struct Block {
pub body: BlockBody,
}
impl Block {
/// Calculate the header hash and seal the block so that it can't be changed.
pub fn seal_slow(self) -> SealedBlock {
SealedBlock { header: SealedHeader::seal(self.header), body: self.body }
}
/// Seal the block with a known hash.
///
/// WARNING: This method does not perform validation whether the hash is correct.
pub fn seal(self, hash: B256) -> SealedBlock {
SealedBlock { header: SealedHeader::new(self.header, hash), body: self.body }
}
/// Expensive operation that recovers transaction signer. See [`SealedBlockWithSenders`].
pub 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]
pub fn with_senders_unchecked(self, senders: Vec<Address>) -> 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.
#[track_caller]
pub fn try_with_senders_unchecked(
self,
senders: Vec<Address>,
) -> Result<BlockWithSenders, Self> {
let senders = if self.body.transactions.len() == senders.len() {
senders
} else {
let Some(senders) = self.body.recover_signers_unchecked() else { return Err(self) };
senders
};
Ok(BlockWithSenders::new_unchecked(self, senders))
}
/// **Expensive**. Transform into a [`BlockWithSenders`] by recovering senders in the contained
/// transactions.
///
/// Returns `None` if a transaction is invalid.
pub fn with_recovered_senders(self) -> Option<BlockWithSenders> {
let senders = self.senders()?;
Some(BlockWithSenders::new_unchecked(self, senders))
}
}
impl reth_primitives_traits::Block for Block {
type Header = Header;
type Body = BlockBody;
fn new(header: Self::Header, body: Self::Body) -> Self {
Self { header, body }
}
fn header(&self) -> &Self::Header {
&self.header
}
@@ -97,6 +41,10 @@ impl reth_primitives_traits::Block for Block {
fn body(&self) -> &Self::Body {
&self.body
}
fn split(self) -> (Self::Header, Self::Body) {
(self.header, self.body)
}
}
impl InMemorySize for Block {
@@ -204,44 +152,44 @@ impl<'a> arbitrary::Arbitrary<'a> for Block {
/// Sealed block with senders recovered from transactions.
#[derive(Debug, Clone, PartialEq, Eq, Default, Deref, DerefMut)]
pub struct BlockWithSenders {
pub struct BlockWithSenders<B = Block> {
/// Block
#[deref]
#[deref_mut]
pub block: Block,
pub block: B,
/// List of senders that match the transactions in the block
pub senders: Vec<Address>,
}
impl BlockWithSenders {
impl<B: reth_primitives_traits::Block> BlockWithSenders<B> {
/// New block with senders
pub const fn new_unchecked(block: Block, senders: Vec<Address>) -> Self {
pub const fn new_unchecked(block: B, senders: Vec<Address>) -> Self {
Self { block, senders }
}
/// New block with senders. Return none if len of tx and senders does not match
pub fn new(block: Block, senders: Vec<Address>) -> Option<Self> {
(block.body.transactions.len() == senders.len()).then_some(Self { block, senders })
pub fn new(block: B, senders: Vec<Address>) -> Option<Self> {
(block.body().transactions().len() == senders.len()).then_some(Self { block, senders })
}
/// Seal the block with a known hash.
///
/// WARNING: This method does not perform validation whether the hash is correct.
#[inline]
pub fn seal(self, hash: B256) -> SealedBlockWithSenders {
pub fn seal(self, hash: B256) -> SealedBlockWithSenders<B> {
let Self { block, senders } = self;
SealedBlockWithSenders { block: block.seal(hash), senders }
SealedBlockWithSenders::<B> { block: block.seal(hash), senders }
}
/// Calculate the header hash and seal the block with senders so that it can't be changed.
#[inline]
pub fn seal_slow(self) -> SealedBlockWithSenders {
pub fn seal_slow(self) -> SealedBlockWithSenders<B> {
SealedBlockWithSenders { block: self.block.seal_slow(), senders: self.senders }
}
/// Split Structure to its components
#[inline]
pub fn into_components(self) -> (Block, Vec<Address>) {
pub fn into_components(self) -> (B, Vec<Address>) {
(self.block, self.senders)
}
@@ -249,18 +197,27 @@ impl BlockWithSenders {
#[inline]
pub fn transactions_with_sender(
&self,
) -> impl Iterator<Item = (&Address, &TransactionSigned)> + '_ {
self.senders.iter().zip(self.block.body.transactions())
) -> impl Iterator<Item = (&Address, &<B::Body as reth_primitives_traits::BlockBody>::Transaction)>
+ '_ {
self.senders.iter().zip(self.block.body().transactions())
}
/// Returns an iterator over all transactions in the chain.
#[inline]
pub fn into_transactions_ecrecovered(
self,
) -> impl Iterator<Item = TransactionSignedEcRecovered> {
) -> impl Iterator<
Item = TransactionSignedEcRecovered<
<B::Body as reth_primitives_traits::BlockBody>::Transaction,
>,
>
where
<B::Body as reth_primitives_traits::BlockBody>::Transaction: SignedTransaction,
{
self.block
.body
.transactions
.split()
.1
.into_transactions()
.into_iter()
.zip(self.senders)
.map(|(tx, sender)| tx.with_signer(sender))
@@ -268,8 +225,10 @@ impl BlockWithSenders {
/// Consumes the block and returns the transactions of the block.
#[inline]
pub fn into_transactions(self) -> Vec<TransactionSigned> {
self.block.body.transactions
pub fn into_transactions(
self,
) -> Vec<<B::Body as reth_primitives_traits::BlockBody>::Transaction> {
self.block.split().1.into_transactions()
}
}
@@ -308,10 +267,9 @@ impl<H, B> SealedBlock<H, B> {
}
impl SealedBlock {
/// Splits the sealed block into underlying components
#[inline]
pub fn split(self) -> (SealedHeader, Vec<TransactionSigned>, Vec<Header>) {
(self.header, self.body.transactions, self.body.ommers)
/// Unseal the block
pub fn unseal(self) -> Block {
Block { header: self.header.unseal(), body: self.body }
}
/// Returns an iterator over all blob transactions of the block
@@ -320,82 +278,6 @@ impl SealedBlock {
self.body.blob_transactions_iter()
}
/// Returns only the blob transactions, if any, from the block body.
#[inline]
pub fn blob_transactions(&self) -> Vec<&TransactionSigned> {
self.blob_transactions_iter().collect()
}
/// Returns an iterator over all blob versioned hashes from the block body.
#[inline]
pub fn blob_versioned_hashes_iter(&self) -> impl Iterator<Item = &B256> + '_ {
self.blob_transactions_iter()
.filter_map(|tx| tx.as_eip4844().map(|blob_tx| &blob_tx.blob_versioned_hashes))
.flatten()
}
/// Returns all blob versioned hashes from the block body.
#[inline]
pub fn blob_versioned_hashes(&self) -> Vec<&B256> {
self.blob_versioned_hashes_iter().collect()
}
/// Expensive operation that recovers transaction signer. See [`SealedBlockWithSenders`].
pub fn senders(&self) -> Option<Vec<Address>> {
self.body.recover_signers()
}
/// Seal sealed block with recovered transaction senders.
pub fn seal_with_senders(self) -> Option<SealedBlockWithSenders> {
self.try_seal_with_senders().ok()
}
/// Seal sealed block with recovered transaction senders.
pub fn try_seal_with_senders(self) -> Result<SealedBlockWithSenders, Self> {
match self.senders() {
Some(senders) => Ok(SealedBlockWithSenders { block: self, senders }),
None => Err(self),
}
}
/// Transform into a [`SealedBlockWithSenders`].
///
/// # 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.
#[track_caller]
pub fn with_senders_unchecked(self, senders: Vec<Address>) -> SealedBlockWithSenders {
self.try_with_senders_unchecked(senders).expect("stored block is valid")
}
/// Transform into a [`SealedBlockWithSenders`] 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.
#[track_caller]
pub fn try_with_senders_unchecked(
self,
senders: Vec<Address>,
) -> Result<SealedBlockWithSenders, Self> {
let senders = if self.body.transactions.len() == senders.len() {
senders
} else {
let Some(senders) = self.body.recover_signers_unchecked() else { return Err(self) };
senders
};
Ok(SealedBlockWithSenders { block: self, senders })
}
/// Unseal the block
pub fn unseal(self) -> Block {
Block { header: self.header.unseal(), body: self.body }
}
/// Calculates the total gas used by blob transactions in the sealed block.
pub fn blob_gas_used(&self) -> u64 {
self.blob_transactions().iter().filter_map(|tx| tx.blob_gas_used()).sum()
@@ -413,6 +295,102 @@ impl SealedBlock {
self.body.has_eip7702_transactions()
}
/// Returns only the blob transactions, if any, from the block body.
#[inline]
pub fn blob_transactions(&self) -> Vec<&TransactionSigned> {
self.blob_transactions_iter().collect()
}
/// Returns an iterator over all blob versioned hashes from the block body.
#[inline]
pub fn blob_versioned_hashes_iter(&self) -> impl Iterator<Item = &B256> + '_ {
self.blob_transactions_iter()
.filter_map(|tx| tx.as_eip4844().map(|blob_tx| &blob_tx.blob_versioned_hashes))
.flatten()
}
}
impl<H, B> SealedBlock<H, B>
where
H: reth_primitives_traits::BlockHeader,
B: reth_primitives_traits::BlockBody,
{
/// Splits the sealed block into underlying components
#[inline]
pub fn split(self) -> (SealedHeader<H>, B) {
(self.header, self.body)
}
/// Expensive operation that recovers transaction signer. See [`SealedBlockWithSenders`].
pub fn senders(&self) -> Option<Vec<Address>>
where
B::Transaction: SignedTransaction,
{
self.body.recover_signers()
}
/// Seal sealed block with recovered transaction senders.
pub fn seal_with_senders<T>(self) -> Option<SealedBlockWithSenders<T>>
where
B::Transaction: SignedTransaction,
T: reth_primitives_traits::Block<Header = H, Body = B>,
{
self.try_seal_with_senders().ok()
}
/// Seal sealed block with recovered transaction senders.
pub fn try_seal_with_senders<T>(self) -> Result<SealedBlockWithSenders<T>, Self>
where
B::Transaction: SignedTransaction,
T: reth_primitives_traits::Block<Header = H, Body = B>,
{
match self.senders() {
Some(senders) => Ok(SealedBlockWithSenders { block: self, senders }),
None => Err(self),
}
}
/// Transform into a [`SealedBlockWithSenders`].
///
/// # 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.
#[track_caller]
pub fn with_senders_unchecked<T>(self, senders: Vec<Address>) -> SealedBlockWithSenders<T>
where
B::Transaction: SignedTransaction,
T: reth_primitives_traits::Block<Header = H, Body = B>,
{
self.try_with_senders_unchecked(senders).expect("stored block is valid")
}
/// Transform into a [`SealedBlockWithSenders`] 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.
#[track_caller]
pub fn try_with_senders_unchecked<T>(
self,
senders: Vec<Address>,
) -> Result<SealedBlockWithSenders<T>, Self>
where
B::Transaction: SignedTransaction,
T: reth_primitives_traits::Block<Header = H, Body = B>,
{
let senders = if self.body.transactions().len() == senders.len() {
senders
} else {
let Some(senders) = self.body.recover_signers_unchecked() else { return Err(self) };
senders
};
Ok(SealedBlockWithSenders { block: self, senders })
}
/// Ensures that the transaction root in the block header is valid.
///
/// The transaction root is the Keccak 256-bit hash of the root node of the trie structure
@@ -425,13 +403,16 @@ impl SealedBlock {
///
/// Returns `Err(error)` if the transaction root validation fails, providing a `GotExpected`
/// error containing the calculated and expected roots.
pub fn ensure_transaction_root_valid(&self) -> Result<(), GotExpected<B256>> {
pub fn ensure_transaction_root_valid(&self) -> Result<(), GotExpected<B256>>
where
B::Transaction: Encodable2718,
{
let calculated_root = self.body.calculate_tx_root();
if self.header.transactions_root != calculated_root {
if self.header.transactions_root() != calculated_root {
return Err(GotExpected {
got: calculated_root,
expected: self.header.transactions_root,
expected: self.header.transactions_root(),
})
}
@@ -440,8 +421,11 @@ impl SealedBlock {
/// Returns a vector of transactions RLP encoded with
/// [`alloy_eips::eip2718::Encodable2718::encoded_2718`].
pub fn raw_transactions(&self) -> Vec<Bytes> {
self.body.transactions().map(|tx| tx.encoded_2718().into()).collect()
pub fn raw_transactions(&self) -> Vec<Bytes>
where
B::Transaction: Encodable2718,
{
self.body.transactions().iter().map(|tx| tx.encoded_2718().into()).collect()
}
}
@@ -477,6 +461,10 @@ where
type Header = H;
type Body = B;
fn new(header: Self::Header, body: Self::Body) -> Self {
Self { header: SealedHeader::seal(header), body }
}
fn header(&self) -> &Self::Header {
self.header.header()
}
@@ -484,6 +472,10 @@ where
fn body(&self) -> &Self::Body {
&self.body
}
fn split(self) -> (Self::Header, Self::Body) {
(self.header.unseal(), self.body)
}
}
#[cfg(any(test, feature = "arbitrary"))]
@@ -499,45 +491,48 @@ where
/// Sealed block with senders recovered from transactions.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Deref, DerefMut)]
pub struct SealedBlockWithSenders<H = Header, B = BlockBody> {
pub struct SealedBlockWithSenders<B: reth_primitives_traits::Block = Block> {
/// Sealed block
#[deref]
#[deref_mut]
pub block: SealedBlock<H, B>,
#[serde(bound = "SealedBlock<B::Header, B::Body>: Serialize + serde::de::DeserializeOwned")]
pub block: SealedBlock<B::Header, B::Body>,
/// List of senders that match transactions from block.
pub senders: Vec<Address>,
}
impl<H: Default + Sealable, B: Default> Default for SealedBlockWithSenders<H, B> {
impl<B: reth_primitives_traits::Block> Default for SealedBlockWithSenders<B> {
fn default() -> Self {
Self { block: SealedBlock::default(), senders: Default::default() }
}
}
impl<H, B: reth_primitives_traits::BlockBody> SealedBlockWithSenders<H, B> {
impl<B: reth_primitives_traits::Block> SealedBlockWithSenders<B> {
/// New sealed block with sender. Return none if len of tx and senders does not match
pub fn new(block: SealedBlock<H, B>, senders: Vec<Address>) -> Option<Self> {
pub fn new(block: SealedBlock<B::Header, B::Body>, senders: Vec<Address>) -> Option<Self> {
(block.body.transactions().len() == senders.len()).then_some(Self { block, senders })
}
}
impl SealedBlockWithSenders {
impl<B: reth_primitives_traits::Block> SealedBlockWithSenders<B> {
/// Split Structure to its components
#[inline]
pub fn into_components(self) -> (SealedBlock, Vec<Address>) {
pub fn into_components(self) -> (SealedBlock<B::Header, B::Body>, Vec<Address>) {
(self.block, self.senders)
}
/// Returns the unsealed [`BlockWithSenders`]
#[inline]
pub fn unseal(self) -> BlockWithSenders {
let Self { block, senders } = self;
BlockWithSenders::new_unchecked(block.unseal(), senders)
pub fn unseal(self) -> BlockWithSenders<B> {
let (block, senders) = self.into_components();
let (header, body) = block.split();
let header = header.unseal();
BlockWithSenders::new_unchecked(B::new(header, body), senders)
}
/// Returns an iterator over all transactions in the block.
#[inline]
pub fn transactions(&self) -> impl Iterator<Item = &TransactionSigned> + '_ {
pub fn transactions(&self) -> &[<B::Body as reth_primitives_traits::BlockBody>::Transaction] {
self.block.body.transactions()
}
@@ -545,24 +540,34 @@ impl SealedBlockWithSenders {
#[inline]
pub fn transactions_with_sender(
&self,
) -> impl Iterator<Item = (&Address, &TransactionSigned)> + '_ {
) -> impl Iterator<Item = (&Address, &<B::Body as reth_primitives_traits::BlockBody>::Transaction)>
+ '_ {
self.senders.iter().zip(self.block.body.transactions())
}
/// Consumes the block and returns the transactions of the block.
#[inline]
pub fn into_transactions(self) -> Vec<TransactionSigned> {
self.block.body.transactions
pub fn into_transactions(
self,
) -> Vec<<B::Body as reth_primitives_traits::BlockBody>::Transaction> {
self.block.body.into_transactions()
}
/// Returns an iterator over all transactions in the chain.
#[inline]
pub fn into_transactions_ecrecovered(
self,
) -> impl Iterator<Item = TransactionSignedEcRecovered> {
) -> impl Iterator<
Item = TransactionSignedEcRecovered<
<B::Body as reth_primitives_traits::BlockBody>::Transaction,
>,
>
where
<B::Body as reth_primitives_traits::BlockBody>::Transaction: SignedTransaction,
{
self.block
.body
.transactions
.into_transactions()
.into_iter()
.zip(self.senders)
.map(|(tx, sender)| tx.with_signer(sender))
@@ -608,11 +613,6 @@ impl BlockBody {
Block { header, body: self }
}
/// Calculate the transaction root for the block body.
pub fn calculate_tx_root(&self) -> B256 {
crate::proofs::calculate_transaction_root(&self.transactions)
}
/// Calculate the ommers root for the block body.
pub fn calculate_ommers_root(&self) -> B256 {
crate::proofs::calculate_ommers_root(&self.ommers)
@@ -624,20 +624,6 @@ impl BlockBody {
self.withdrawals.as_ref().map(|w| crate::proofs::calculate_withdrawals_root(w))
}
/// Recover signer addresses for all transactions in the block body.
pub fn recover_signers(&self) -> Option<Vec<Address>> {
TransactionSigned::recover_signers(&self.transactions, self.transactions.len())
}
/// Recover signer addresses for all transactions in the block body _without ensuring that the
/// signature has a low `s` value_.
///
/// Returns `None`, if some transaction's signature is invalid, see also
/// [`TransactionSigned::recover_signer_unchecked`].
pub fn recover_signers_unchecked(&self) -> Option<Vec<Address>> {
TransactionSigned::recover_signers_unchecked(&self.transactions, self.transactions.len())
}
/// Returns whether or not the block body contains any blob transactions.
#[inline]
pub fn has_blob_transactions(&self) -> bool {
@@ -703,6 +689,10 @@ impl reth_primitives_traits::BlockBody for BlockBody {
fn transactions(&self) -> &[Self::Transaction] {
&self.transactions
}
fn into_transactions(self) -> Vec<Self::Transaction> {
self.transactions
}
}
impl From<Block> for BlockBody {
@@ -1168,9 +1158,9 @@ mod tests {
Some(BlockWithSenders { block: block.clone(), senders: vec![sender] })
);
let sealed = block.seal_slow();
assert_eq!(SealedBlockWithSenders::new(sealed.clone(), vec![]), None);
assert_eq!(SealedBlockWithSenders::<Block>::new(sealed.clone(), vec![]), None);
assert_eq!(
SealedBlockWithSenders::new(sealed.clone(), vec![sender]),
SealedBlockWithSenders::<Block>::new(sealed.clone(), vec![sender]),
Some(SealedBlockWithSenders { block: sealed, senders: vec![sender] })
);
}

View File

@@ -21,6 +21,9 @@
extern crate alloc;
mod traits;
pub use traits::*;
#[cfg(feature = "alloy-compat")]
mod alloy_compat;
mod block;

View File

@@ -1,7 +1,7 @@
//! Helper function for calculating Merkle proofs and hashes.
use crate::{Receipt, ReceiptWithBloom, ReceiptWithBloomRef, TransactionSigned};
use alloc::vec::Vec;
use crate::{Receipt, ReceiptWithBloom, ReceiptWithBloomRef};
use alloc::{borrow::Borrow, vec::Vec};
use alloy_consensus::{Header, EMPTY_OMMER_ROOT_HASH};
use alloy_eips::{eip2718::Encodable2718, eip4895::Withdrawal};
use alloy_primitives::{keccak256, B256};
@@ -12,9 +12,9 @@ use alloy_trie::root::{ordered_trie_root, ordered_trie_root_with_encoder};
/// `(rlp(index), encoded(tx))` pairs.
pub fn calculate_transaction_root<T>(transactions: &[T]) -> B256
where
T: AsRef<TransactionSigned>,
T: Encodable2718,
{
ordered_trie_root_with_encoder(transactions, |tx: &T, buf| tx.as_ref().encode_2718(buf))
ordered_trie_root_with_encoder(transactions, |tx, buf| tx.borrow().encode_2718(buf))
}
/// Calculates the root hash of the withdrawals.

View File

@@ -0,0 +1,123 @@
use crate::{
transaction::{recover_signers, recover_signers_unchecked},
BlockWithSenders, SealedBlock,
};
use alloc::vec::Vec;
use alloy_eips::eip2718::Encodable2718;
use reth_primitives_traits::{Block, BlockBody, SealedHeader, SignedTransaction};
use revm_primitives::{Address, B256};
/// Extension trait for [`reth_primitives_traits::Block`] implementations
/// allowing for conversions into common block parts containers such as [`SealedBlock`],
/// [`BlockWithSenders`], etc.
pub trait BlockExt: Block {
/// 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.split();
SealedBlock { header: SealedHeader::seal(header), body }
}
/// 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.split();
SealedBlock { header: SealedHeader::new(header, hash), body }
}
/// Expensive operation that recovers transaction signer.
fn senders(&self) -> Option<Vec<Address>>
where
<Self::Body as BlockBody>::Transaction: SignedTransaction,
{
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>) -> BlockWithSenders<Self>
where
<Self::Body as BlockBody>::Transaction: SignedTransaction,
{
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 [`recover_signers_unchecked`]
///
/// Returns an error if a signature is invalid.
#[track_caller]
fn try_with_senders_unchecked(
self,
senders: Vec<Address>,
) -> Result<BlockWithSenders<Self>, Self>
where
<Self::Body as BlockBody>::Transaction: SignedTransaction,
{
let senders = if self.body().transactions().len() == senders.len() {
senders
} else {
let Some(senders) = self.body().recover_signers_unchecked() else { return Err(self) };
senders
};
Ok(BlockWithSenders::new_unchecked(self, senders))
}
/// **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>>
where
<Self::Body as BlockBody>::Transaction: SignedTransaction,
{
let senders = self.senders()?;
Some(BlockWithSenders::new_unchecked(self, senders))
}
}
impl<T: Block> BlockExt for T {}
/// Extension trait for [`BlockBody`] adding helper methods operating with transactions.
pub trait BlockBodyTxExt: BlockBody {
/// Calculate the transaction root for the block body.
fn calculate_tx_root(&self) -> B256
where
Self::Transaction: Encodable2718,
{
crate::proofs::calculate_transaction_root(self.transactions())
}
/// Recover signer addresses for all transactions in the block body.
fn recover_signers(&self) -> Option<Vec<Address>>
where
Self::Transaction: SignedTransaction,
{
recover_signers(self.transactions(), self.transactions().len())
}
/// Recover signer addresses for all transactions in the block body _without ensuring that the
/// signature has a low `s` value_.
///
/// Returns `None`, if some transaction's signature is invalid, see also
/// [`recover_signers_unchecked`].
fn recover_signers_unchecked(&self) -> Option<Vec<Address>>
where
Self::Transaction: SignedTransaction,
{
recover_signers_unchecked(self.transactions(), self.transactions().len())
}
}
impl<T: BlockBody> BlockBodyTxExt for T {}

View File

@@ -1,9 +0,0 @@
//! Abstractions of primitive data types
pub mod block;
pub mod transaction;
pub use block::{body::BlockBody, Block};
pub use transaction::signed::SignedTransaction;
pub use alloy_consensus::BlockHeader;

View File

@@ -1712,6 +1712,11 @@ pub trait SignedTransactionIntoRecoveredExt: SignedTransaction {
let signer = self.recover_signer_unchecked()?;
Some(TransactionSignedEcRecovered::from_signed_transaction(self, signer))
}
/// Returns the [`TransactionSignedEcRecovered`] transaction with the given sender.
fn with_signer(self, signer: Address) -> TransactionSignedEcRecovered<Self> {
TransactionSignedEcRecovered::from_signed_transaction(self, signer)
}
}
impl<T> SignedTransactionIntoRecoveredExt for T where T: SignedTransaction {}
@@ -1936,6 +1941,22 @@ where
}
}
/// Recovers a list of signers from a transaction list iterator _without ensuring that the
/// signature has a low `s` value_.
///
/// Returns `None`, if some transaction's signature is invalid.
pub fn recover_signers_unchecked<'a, I, T>(txes: I, num_txes: usize) -> Option<Vec<Address>>
where
T: SignedTransaction,
I: IntoParallelIterator<Item = &'a T> + IntoIterator<Item = &'a T> + Send,
{
if num_txes < *PARALLEL_SENDER_RECOVERY_THRESHOLD {
txes.into_iter().map(|tx| tx.recover_signer_unchecked()).collect()
} else {
txes.into_par_iter().map(|tx| tx.recover_signer_unchecked()).collect()
}
}
#[cfg(test)]
mod tests {
use crate::{

View File

@@ -5,7 +5,7 @@ use alloy_primitives::U64;
use alloy_rpc_types_engine::{ForkchoiceState, PayloadId, TransitionConfiguration};
use jsonrpsee::core::client::{ClientT, SubscriptionClientT};
use reth_ethereum_engine_primitives::EthEngineTypes;
use reth_primitives::Block;
use reth_primitives::{Block, BlockExt};
use reth_rpc_api::clients::EngineApiClient;
use reth_rpc_layer::JwtSecret;
use reth_rpc_types_compat::engine::payload::{

View File

@@ -17,8 +17,8 @@ use reth_evm::{
};
use reth_execution_types::ExecutionOutcome;
use reth_primitives::{
proofs::calculate_transaction_root, Block, BlockBody, Receipt, SealedBlockWithSenders,
SealedHeader, TransactionSignedEcRecovered,
proofs::calculate_transaction_root, Block, BlockBody, BlockExt, Receipt,
SealedBlockWithSenders, SealedHeader, TransactionSignedEcRecovered,
};
use reth_provider::{
BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ProviderError,

View File

@@ -315,7 +315,7 @@ pub trait EthTransactions: LoadTransaction<Provider: BlockReaderIdExt> {
{
async move {
if let Some(block) = self.block_with_senders(block_id).await? {
if let Some(tx) = block.transactions().nth(index) {
if let Some(tx) = block.transactions().get(index) {
return Ok(Some(tx.encoded_2718().into()))
}
}

View File

@@ -43,7 +43,7 @@ pub fn from_block_with_tx_hashes<T>(
block_hash: Option<B256>,
) -> Block<T> {
let block_hash = block_hash.unwrap_or_else(|| block.header.hash_slow());
let transactions = block.body.transactions().map(|tx| tx.hash()).collect();
let transactions = block.body.transactions.iter().map(|tx| tx.hash()).collect();
from_block_with_transactions(
block.length(),

View File

@@ -15,7 +15,7 @@ use alloy_rpc_types_engine::{
};
use reth_primitives::{
proofs::{self},
Block, BlockBody, SealedBlock, TransactionSigned,
Block, BlockBody, BlockExt, SealedBlock, TransactionSigned,
};
/// Converts [`ExecutionPayloadV1`] to [`Block`]
@@ -363,6 +363,7 @@ mod tests {
CancunPayloadFields, ExecutionPayload, ExecutionPayloadSidecar, ExecutionPayloadV1,
ExecutionPayloadV2, ExecutionPayloadV3,
};
use reth_primitives::BlockExt;
#[test]
fn roundtrip_payload_to_block() {

View File

@@ -18,7 +18,7 @@ use reth_evm::{
execute::{BlockExecutorProvider, Executor},
ConfigureEvmEnv,
};
use reth_primitives::{Block, SealedBlockWithSenders};
use reth_primitives::{Block, BlockExt, SealedBlockWithSenders};
use reth_provider::{
BlockReaderIdExt, ChainSpecProvider, HeaderProvider, StateProofProvider, StateProviderFactory,
TransactionVariant,

View File

@@ -5,7 +5,7 @@ use std::{
use futures_util::TryStreamExt;
use reth_codecs::Compact;
use reth_primitives_traits::BlockBody;
use reth_primitives_traits::{Block, BlockBody};
use tracing::*;
use alloy_primitives::TxNumber;
@@ -151,7 +151,7 @@ where
+ StaticFileProviderFactory
+ StatsReader
+ BlockReader
+ BlockWriter<Body = D::Body>,
+ BlockWriter<Block: Block<Body = D::Body>>,
D: BodyDownloader<Body: BlockBody<Transaction: Compact>>,
{
/// Return the id of the stage

View File

@@ -44,7 +44,7 @@ where
.ok_or(ProviderError::BlockBodyIndicesNotFound(block))?;
let mut transactions_cursor = provider.tx_ref().cursor_read::<tables::Transactions<
<<Provider as StaticFileProviderFactory>::Primitives as NodePrimitives>::SignedTx,
<Provider::Primitives as NodePrimitives>::SignedTx,
>>()?;
let transactions_walker =
transactions_cursor.walk_range(block_body_indices.tx_num_range())?;

View File

@@ -793,7 +793,9 @@ mod tests {
use reth_db_api::{cursor::DbCursorRO, transaction::DbTx};
use reth_errors::ProviderError;
use reth_execution_types::{Chain, ExecutionOutcome};
use reth_primitives::{Receipt, SealedBlock, StaticFileSegment, TransactionSignedNoHash};
use reth_primitives::{
BlockExt, Receipt, SealedBlock, StaticFileSegment, TransactionSignedNoHash,
};
use reth_storage_api::{
BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, BlockSource,
ChangeSetReader, DatabaseProviderFactory, HeaderProvider, ReceiptProvider,

View File

@@ -46,9 +46,9 @@ use reth_db_api::{
use reth_evm::ConfigureEvmEnv;
use reth_execution_types::{Chain, ExecutionOutcome};
use reth_network_p2p::headers::downloader::SyncTarget;
use reth_node_types::{NodeTypes, TxTy};
use reth_node_types::{BlockTy, NodeTypes, TxTy};
use reth_primitives::{
Account, Block, BlockBody, BlockWithSenders, Bytecode, GotExpected, NodePrimitives, Receipt,
Account, Block, BlockBody, BlockExt, BlockWithSenders, Bytecode, GotExpected, Receipt,
SealedBlock, SealedBlockWithSenders, SealedHeader, StaticFileSegment, StorageEntry,
TransactionMeta, TransactionSigned, TransactionSignedNoHash,
};
@@ -380,7 +380,7 @@ impl<Tx: DbTx + DbTxMut + 'static, N: NodeTypesForProvider + 'static> DatabasePr
/// Inserts an historical block. **Used for setting up test environments**
pub fn insert_historical_block(
&self,
block: SealedBlockWithSenders<Header, <Self as BlockWriter>::Body>,
block: SealedBlockWithSenders<<Self as BlockWriter>::Block>,
) -> ProviderResult<StoredBlockBodyIndices> {
let ttd = if block.number == 0 {
block.difficulty
@@ -2751,7 +2751,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypesForProvider + 'static> BlockExecu
impl<TX: DbTxMut + DbTx + 'static, N: NodeTypesForProvider + 'static> BlockWriter
for DatabaseProvider<TX, N>
{
type Body = <<N::Primitives as NodePrimitives>::Block as reth_primitives_traits::Block>::Body;
type Block = BlockTy<N>;
/// Inserts the block into the database, always modifying the following tables:
/// * [`CanonicalHeaders`](tables::CanonicalHeaders)
@@ -2775,7 +2775,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypesForProvider + 'static> BlockWrite
/// [`TransactionHashNumbers`](tables::TransactionHashNumbers).
fn insert_block(
&self,
block: SealedBlockWithSenders<Header, Self::Body>,
block: SealedBlockWithSenders<Self::Block>,
write_transactions_to: StorageLocation,
) -> ProviderResult<StoredBlockBodyIndices> {
let block_number = block.number;
@@ -2849,7 +2849,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypesForProvider + 'static> BlockWrite
fn append_block_bodies(
&self,
bodies: Vec<(BlockNumber, Option<Self::Body>)>,
bodies: Vec<(BlockNumber, Option<<Self::Block as reth_primitives_traits::Block>::Body>)>,
write_transactions_to: StorageLocation,
) -> ProviderResult<()> {
let Some(from_block) = bodies.first().map(|(block, _)| *block) else { return Ok(()) };
@@ -2868,11 +2868,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypesForProvider + 'static> BlockWrite
// Initialize cursor if we will be writing transactions to database
let mut tx_cursor = write_transactions_to
.database()
.then(|| {
self.tx.cursor_write::<tables::Transactions<
<Self::Body as reth_primitives_traits::BlockBody>::Transaction,
>>()
})
.then(|| self.tx.cursor_write::<tables::Transactions<TxTy<N>>>())
.transpose()?;
// Get id for the next tx_num of zero if there are no transactions.
@@ -3017,7 +3013,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypesForProvider + 'static> BlockWrite
/// TODO(joshie): this fn should be moved to `UnifiedStorageWriter` eventually
fn append_blocks_with_state(
&self,
blocks: Vec<SealedBlockWithSenders<Header, Self::Body>>,
blocks: Vec<SealedBlockWithSenders<Self::Block>>,
execution_outcome: ExecutionOutcome,
hashed_state: HashedPostStateSorted,
trie_updates: TrieUpdates,

View File

@@ -78,6 +78,7 @@ where
Storage: ChainStorage<Self::Primitives>,
Primitives: FullNodePrimitives<
SignedTx: Value + From<TransactionSigned> + Into<TransactionSigned>,
BlockHeader = alloy_consensus::Header,
>,
>,
{
@@ -89,6 +90,7 @@ impl<T> NodeTypesForProvider for T where
Storage: ChainStorage<T::Primitives>,
Primitives: FullNodePrimitives<
SignedTx: Value + From<TransactionSigned> + Into<TransactionSigned>,
BlockHeader = alloy_consensus::Header,
>,
>
{

View File

@@ -1,4 +1,3 @@
use alloy_consensus::Header;
use alloy_primitives::BlockNumber;
use reth_db_api::models::StoredBlockBodyIndices;
use reth_execution_types::{Chain, ExecutionOutcome};
@@ -62,7 +61,7 @@ pub trait StateReader: Send + Sync {
#[auto_impl::auto_impl(&, Arc, Box)]
pub trait BlockWriter: Send + Sync {
/// The body this writer can write.
type Body: Send + Sync;
type Block: reth_primitives_traits::Block;
/// Insert full block and make it canonical. Parent tx num and transition id is taken from
/// parent block in database.
@@ -71,7 +70,7 @@ pub trait BlockWriter: Send + Sync {
/// transition in the block.
fn insert_block(
&self,
block: SealedBlockWithSenders<Header, Self::Body>,
block: SealedBlockWithSenders<Self::Block>,
write_transactions_to: StorageLocation,
) -> ProviderResult<StoredBlockBodyIndices>;
@@ -82,7 +81,7 @@ pub trait BlockWriter: Send + Sync {
/// Bodies are passed as [`Option`]s, if body is `None` the corresponding block is empty.
fn append_block_bodies(
&self,
bodies: Vec<(BlockNumber, Option<Self::Body>)>,
bodies: Vec<(BlockNumber, Option<<Self::Block as reth_primitives_traits::Block>::Body>)>,
write_transactions_to: StorageLocation,
) -> ProviderResult<()>;
@@ -118,7 +117,7 @@ pub trait BlockWriter: Send + Sync {
/// Returns `Ok(())` on success, or an error if any operation fails.
fn append_blocks_with_state(
&self,
blocks: Vec<SealedBlockWithSenders<Header, Self::Body>>,
blocks: Vec<SealedBlockWithSenders<Self::Block>>,
execution_outcome: ExecutionOutcome,
hashed_state: HashedPostStateSorted,
trie_updates: TrieUpdates,

View File

@@ -15,7 +15,7 @@ use reth_db::{
};
use reth_errors::{ProviderError, ProviderResult};
use reth_execution_types::ExecutionOutcome;
use reth_primitives::{BlockBody, SealedBlock, StaticFileSegment};
use reth_primitives::{SealedBlock, StaticFileSegment};
use reth_stages_types::{StageCheckpoint, StageId};
use reth_storage_api::{
DBProvider, HeaderProvider, ReceiptWriter, StageCheckpointWriter, TransactionsProviderExt,
@@ -148,7 +148,7 @@ impl UnifiedStorageWriter<'_, (), ()> {
impl<ProviderDB> UnifiedStorageWriter<'_, ProviderDB, &StaticFileProvider<ProviderDB::Primitives>>
where
ProviderDB: DBProvider<Tx: DbTx + DbTxMut>
+ BlockWriter<Body = BlockBody>
+ BlockWriter<Block = reth_primitives::Block>
+ TransactionsProviderExt
+ StateChangeWriter
+ TrieWriter

View File

@@ -98,6 +98,7 @@ where
fn process_block(&mut self, block: &SealedBlockWithSenders) {
let txs: Vec<_> = block
.transactions()
.iter()
.filter(|tx| tx.is_eip4844())
.map(|tx| (tx.clone(), tx.blob_versioned_hashes().unwrap().len()))
.collect();
@@ -191,6 +192,7 @@ where
for (_, block) in old.blocks().iter() {
let txs: Vec<BlobTransactionEvent> = block
.transactions()
.iter()
.filter(|tx: &&reth::primitives::TransactionSigned| {
tx.is_eip4844()
})

View File

@@ -50,7 +50,7 @@ async fn main() -> eyre::Result<()> {
let head = notifications.next().await.unwrap();
let tx = head.tip().transactions().next().unwrap();
let tx = &head.tip().transactions()[0];
assert_eq!(tx.hash(), hash);
println!("mined transaction: {hash}");
Ok(())

View File

@@ -9,7 +9,7 @@ use reth::{
use reth_basic_payload_builder::{BasicPayloadJobGeneratorConfig, PayloadBuilder, PayloadConfig};
use reth_node_api::PayloadBuilderAttributes;
use reth_payload_builder::{PayloadBuilderError, PayloadJobGenerator};
use reth_primitives::SealedHeader;
use reth_primitives::{BlockExt, SealedHeader};
use std::sync::Arc;
/// The generator type that creates new jobs that builds empty blocks.

View File

@@ -4,7 +4,7 @@ use reth_chainspec::ChainSpecBuilder;
use reth_db::{open_db_read_only, DatabaseEnv};
use reth_node_ethereum::EthereumNode;
use reth_node_types::NodeTypesWithDBAdapter;
use reth_primitives::{SealedHeader, TransactionSigned};
use reth_primitives::{BlockExt, SealedHeader, TransactionSigned};
use reth_provider::{
providers::StaticFileProvider, AccountReader, BlockReader, BlockSource, HeaderProvider,
ProviderFactory, ReceiptProvider, StateProvider, TransactionsProvider,