feat: add Primitives AT to BlockExecutorProvider (#12994)

This commit is contained in:
Arsenii Kulikov
2024-11-29 16:53:25 +04:00
committed by GitHub
parent b6b8c474ab
commit 29289ccaec
52 changed files with 591 additions and 409 deletions

View File

@ -1,10 +1,10 @@
use futures_util::TryStreamExt;
use reth::{api::FullNodeComponents, primitives::Block, providers::BlockReader};
use reth::{api::FullNodeComponents, builder::NodeTypes, primitives::EthPrimitives};
use reth_exex::{ExExContext, ExExEvent, ExExNotification};
use reth_node_ethereum::EthereumNode;
use reth_tracing::tracing::info;
async fn my_exex<Node: FullNodeComponents<Provider: BlockReader<Block = Block>>>(
async fn my_exex<Node: FullNodeComponents<Types: NodeTypes<Primitives = EthPrimitives>>>(
mut ctx: ExExContext<Node>,
) -> eyre::Result<()> {
while let Some(notification) = ctx.notifications.try_next().await? {

View File

@ -3,7 +3,7 @@ use remote_exex::proto::{
self,
remote_ex_ex_server::{RemoteExEx, RemoteExExServer},
};
use reth::{primitives::Block, providers::BlockReader};
use reth::{builder::NodeTypes, primitives::EthPrimitives};
use reth_exex::{ExExContext, ExExEvent, ExExNotification};
use reth_node_api::FullNodeComponents;
use reth_node_ethereum::EthereumNode;
@ -45,7 +45,7 @@ impl RemoteExEx for ExExService {
}
}
async fn remote_exex<Node: FullNodeComponents<Provider: BlockReader<Block = Block>>>(
async fn remote_exex<Node: FullNodeComponents<Types: NodeTypes<Primitives = EthPrimitives>>>(
mut ctx: ExExContext<Node>,
notifications: Arc<broadcast::Sender<ExExNotification>>,
) -> eyre::Result<()> {

View File

@ -3,7 +3,7 @@ use remote_exex::proto::{
self,
remote_ex_ex_server::{RemoteExEx, RemoteExExServer},
};
use reth::{primitives::Block, providers::BlockReader};
use reth::{builder::NodeTypes, primitives::EthPrimitives};
use reth_exex::{ExExContext, ExExEvent, ExExNotification};
use reth_node_api::FullNodeComponents;
use reth_node_ethereum::EthereumNode;
@ -47,7 +47,7 @@ impl RemoteExEx for ExExService {
// ANCHOR: snippet
#[allow(dead_code)]
async fn remote_exex<Node: FullNodeComponents<Provider: BlockReader<Block = Block>>>(
async fn remote_exex<Node: FullNodeComponents<Types: NodeTypes<Primitives = EthPrimitives>>>(
mut ctx: ExExContext<Node>,
notifications: Arc<broadcast::Sender<ExExNotification>>,
) -> eyre::Result<()> {

View File

@ -5,7 +5,7 @@ use std::{
};
use futures_util::{FutureExt, TryStreamExt};
use reth::{api::FullNodeComponents, primitives::Block, providers::BlockReader};
use reth::{api::FullNodeComponents, builder::NodeTypes, primitives::EthPrimitives};
use reth_exex::{ExExContext, ExExEvent, ExExNotification};
use reth_node_ethereum::EthereumNode;
use reth_tracing::tracing::info;
@ -14,7 +14,9 @@ struct MyExEx<Node: FullNodeComponents> {
ctx: ExExContext<Node>,
}
impl<Node: FullNodeComponents<Provider: BlockReader<Block = Block>>> Future for MyExEx<Node> {
impl<Node: FullNodeComponents<Types: NodeTypes<Primitives = EthPrimitives>>> Future
for MyExEx<Node>
{
type Output = eyre::Result<()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {

View File

@ -6,7 +6,7 @@ use std::{
use alloy_primitives::BlockNumber;
use futures_util::{FutureExt, TryStreamExt};
use reth::{api::FullNodeComponents, primitives::Block, providers::BlockReader};
use reth::{api::FullNodeComponents, builder::NodeTypes, primitives::EthPrimitives};
use reth_exex::{ExExContext, ExExEvent};
use reth_node_ethereum::EthereumNode;
use reth_tracing::tracing::info;
@ -25,7 +25,9 @@ impl<Node: FullNodeComponents> MyExEx<Node> {
}
}
impl<Node: FullNodeComponents<Provider: BlockReader<Block = Block>>> Future for MyExEx<Node> {
impl<Node: FullNodeComponents<Types: NodeTypes<Primitives = EthPrimitives>>> Future
for MyExEx<Node>
{
type Output = eyre::Result<()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {

View File

@ -95,7 +95,7 @@ impl<N: NodeTypesWithDB, E> BlockchainTree<N, E> {
impl<N, E> BlockchainTree<N, E>
where
N: TreeNodeTypes,
E: BlockExecutorProvider,
E: BlockExecutorProvider<Primitives = N::Primitives>,
{
/// Builds the blockchain tree for the node.
///

View File

@ -17,7 +17,7 @@ use reth_execution_errors::BlockExecutionError;
use reth_execution_types::{Chain, ExecutionOutcome};
use reth_primitives::{GotExpected, SealedBlockWithSenders, SealedHeader};
use reth_provider::{
providers::{BundleStateProvider, ConsistentDbView, ProviderNodeTypes},
providers::{BundleStateProvider, ConsistentDbView, TreeNodeTypes},
DBProvider, FullExecutionDataProvider, ProviderError, StateRootProvider,
TryIntoHistoricalStateProvider,
};
@ -76,8 +76,8 @@ impl AppendableChain {
block_validation_kind: BlockValidationKind,
) -> Result<Self, InsertBlockErrorKind>
where
N: ProviderNodeTypes,
E: BlockExecutorProvider,
N: TreeNodeTypes,
E: BlockExecutorProvider<Primitives = N::Primitives>,
{
let execution_outcome = ExecutionOutcome::default();
let empty = BTreeMap::new();
@ -114,8 +114,8 @@ impl AppendableChain {
block_validation_kind: BlockValidationKind,
) -> Result<Self, InsertBlockErrorKind>
where
N: ProviderNodeTypes,
E: BlockExecutorProvider,
N: TreeNodeTypes,
E: BlockExecutorProvider<Primitives = N::Primitives>,
{
let parent_number =
block.number.checked_sub(1).ok_or(BlockchainTreeError::GenesisBlockHasNoParent)?;
@ -177,8 +177,8 @@ impl AppendableChain {
) -> Result<(ExecutionOutcome, Option<TrieUpdates>), BlockExecutionError>
where
EDP: FullExecutionDataProvider,
N: ProviderNodeTypes,
E: BlockExecutorProvider,
N: TreeNodeTypes,
E: BlockExecutorProvider<Primitives = N::Primitives>,
{
// some checks are done before blocks comes here.
externals.consensus.validate_header_against_parent(&block, parent_block)?;
@ -284,8 +284,8 @@ impl AppendableChain {
block_validation_kind: BlockValidationKind,
) -> Result<(), InsertBlockErrorKind>
where
N: ProviderNodeTypes,
E: BlockExecutorProvider,
N: TreeNodeTypes,
E: BlockExecutorProvider<Primitives = N::Primitives>,
{
let parent_block = self.chain.tip();

View File

@ -39,7 +39,7 @@ impl<N: NodeTypesWithDB, E> ShareableBlockchainTree<N, E> {
impl<N, E> BlockchainTreeEngine for ShareableBlockchainTree<N, E>
where
N: TreeNodeTypes,
E: BlockExecutorProvider,
E: BlockExecutorProvider<Primitives = N::Primitives>,
{
fn buffer_block(&self, block: SealedBlockWithSenders) -> Result<(), InsertBlockError> {
let mut tree = self.tree.write();
@ -110,7 +110,7 @@ where
impl<N, E> BlockchainTreeViewer for ShareableBlockchainTree<N, E>
where
N: TreeNodeTypes,
E: BlockExecutorProvider,
E: BlockExecutorProvider<Primitives = N::Primitives>,
{
fn header_by_hash(&self, hash: BlockHash) -> Option<SealedHeader> {
trace!(target: "blockchain_tree", ?hash, "Returning header by hash");
@ -173,7 +173,7 @@ where
impl<N, E> BlockchainTreePendingStateProvider for ShareableBlockchainTree<N, E>
where
N: TreeNodeTypes,
E: BlockExecutorProvider,
E: BlockExecutorProvider<Primitives = N::Primitives>,
{
fn find_pending_state_provider(
&self,

View File

@ -60,7 +60,7 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> ImportComm
pub async fn execute<N, E, F>(self, executor: F) -> eyre::Result<()>
where
N: CliNodeTypes<ChainSpec = C::ChainSpec>,
E: BlockExecutorProvider,
E: BlockExecutorProvider<Primitives = N::Primitives>,
F: FnOnce(Arc<N::ChainSpec>) -> E,
{
info!(target: "reth::cli", "reth {} starting", SHORT_VERSION);
@ -169,7 +169,7 @@ pub fn build_import_pipeline<N, C, E>(
where
N: ProviderNodeTypes + CliNodeTypes,
C: Consensus + 'static,
E: BlockExecutorProvider,
E: BlockExecutorProvider<Primitives = N::Primitives>,
{
if !file_client.has_canonical_blocks() {
eyre::bail!("unable to import non canonical blocks");

View File

@ -33,7 +33,7 @@ where
Receipt = reth_primitives::Receipt,
>,
>,
E: BlockExecutorProvider,
E: BlockExecutorProvider<Primitives = N::Primitives>,
{
let (output_db, tip_block_number) = setup(from, to, &output_datadir.db(), db_tool)?;
@ -188,7 +188,7 @@ where
Receipt = reth_primitives::Receipt,
>,
>,
E: BlockExecutorProvider,
E: BlockExecutorProvider<Primitives = N::Primitives>,
{
info!(target: "reth::cli", "Executing stage. [dry-run]");

View File

@ -93,7 +93,7 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C>
pub async fn execute<N, E, F>(self, executor: F) -> eyre::Result<()>
where
N: CliNodeTypes<ChainSpec = C::ChainSpec>,
E: BlockExecutorProvider,
E: BlockExecutorProvider<Primitives = N::Primitives>,
F: FnOnce(Arc<C::ChainSpec>) -> E,
{
let Environment { provider_factory, .. } = self.env.init::<N>(AccessRights::RO)?;

View File

@ -44,7 +44,7 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C>
pub async fn execute<N, E, F>(self, ctx: CliContext, executor: F) -> eyre::Result<()>
where
N: CliNodeTypes<ChainSpec = C::ChainSpec>,
E: BlockExecutorProvider,
E: BlockExecutorProvider<Primitives = N::Primitives>,
F: FnOnce(Arc<C::ChainSpec>) -> E,
{
match self.command {

View File

@ -107,7 +107,7 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C>
pub async fn execute<N, E, F>(self, ctx: CliContext, executor: F) -> eyre::Result<()>
where
N: CliNodeTypes<ChainSpec = C::ChainSpec>,
E: BlockExecutorProvider,
E: BlockExecutorProvider<Primitives = N::Primitives>,
F: FnOnce(Arc<C::ChainSpec>) -> E,
{
// Raise the fd limit of the process.

View File

@ -1,7 +1,6 @@
use alloy_consensus::TxEnvelope;
use alloy_network::eip2718::Decodable2718;
use alloy_primitives::{Bytes, B256};
use alloy_rlp::Encodable;
use reth_chainspec::EthereumHardforks;
use reth_node_api::{FullNodeComponents, NodePrimitives};
use reth_node_builder::{rpc::RpcRegistry, NodeTypes};
@ -21,7 +20,10 @@ where
Node: FullNodeComponents<
Types: NodeTypes<
ChainSpec: EthereumHardforks,
Primitives: NodePrimitives<Block: Encodable, Receipt = reth_primitives::Receipt>,
Primitives: NodePrimitives<
Block = reth_primitives::Block,
Receipt = reth_primitives::Receipt,
>,
>,
>,
EthApi: EthApiSpec + EthTransactions + TraceExt,

View File

@ -65,7 +65,7 @@ where
#[allow(clippy::too_many_arguments)]
pub fn new<B, V>(
consensus: Arc<dyn Consensus>,
executor_factory: impl BlockExecutorProvider,
executor_factory: impl BlockExecutorProvider<Primitives = N::Primitives>,
provider: ProviderFactory<N>,
blockchain_db: BlockchainProvider2<N>,
pruner: PrunerWithFactory<ProviderFactory<N>>,

View File

@ -60,7 +60,7 @@ impl<N, Client, E> EngineService<N, Client, E>
where
N: EngineNodeTypes + PersistenceNodeTypes,
Client: EthBlockClient + 'static,
E: BlockExecutorProvider + 'static,
E: BlockExecutorProvider<Primitives = N::Primitives> + 'static,
{
/// Constructor for `EngineService`.
#[allow(clippy::too_many_arguments)]

View File

@ -540,7 +540,7 @@ impl<N, P: Debug, E: Debug, T: EngineTypes + Debug, V: Debug> std::fmt::Debug
impl<N, P, E, T, V> EngineApiTreeHandler<N, P, E, T, V>
where
N: NodePrimitives,
N: NodePrimitives<Block = reth_primitives::Block, Receipt = reth_primitives::Receipt>,
P: DatabaseProviderFactory
+ BlockReader<Block = reth_primitives::Block>
+ StateProviderFactory
@ -548,7 +548,7 @@ where
+ Clone
+ 'static,
<P as DatabaseProviderFactory>::Provider: BlockReader,
E: BlockExecutorProvider,
E: BlockExecutorProvider<Primitives = N>,
T: EngineTypes,
V: EngineValidator<T, Block = reth_primitives::Block>,
{

View File

@ -20,7 +20,7 @@ use reth_evm::{
system_calls::{OnStateHook, SystemCaller},
ConfigureEvm, TxEnvOverrides,
};
use reth_primitives::{BlockWithSenders, Receipt};
use reth_primitives::{BlockWithSenders, EthPrimitives, Receipt};
use reth_revm::db::State;
use revm_primitives::{
db::{Database, DatabaseCommit},
@ -60,6 +60,8 @@ where
EvmConfig:
Clone + Unpin + Sync + Send + 'static + ConfigureEvm<Header = alloy_consensus::Header>,
{
type Primitives = EthPrimitives;
type Strategy<DB: Database<Error: Into<ProviderError> + Display>> =
EthExecutionStrategy<DB, EvmConfig>;
@ -122,13 +124,16 @@ where
}
}
impl<DB, EvmConfig> BlockExecutionStrategy<DB> for EthExecutionStrategy<DB, EvmConfig>
impl<DB, EvmConfig> BlockExecutionStrategy for EthExecutionStrategy<DB, EvmConfig>
where
DB: Database<Error: Into<ProviderError> + Display>,
EvmConfig: ConfigureEvm<Header = alloy_consensus::Header>,
{
type DB = DB;
type Error = BlockExecutionError;
type Primitives = EthPrimitives;
fn init(&mut self, tx_env_overrides: Box<dyn TxEnvOverrides>) {
self.tx_env_overrides = Some(tx_env_overrides);
}

View File

@ -133,7 +133,7 @@ pub struct EthereumExecutorBuilder;
impl<Types, Node> ExecutorBuilder<Node> for EthereumExecutorBuilder
where
Types: NodeTypesWithEngine<ChainSpec = ChainSpec>,
Types: NodeTypesWithEngine<ChainSpec = ChainSpec, Primitives = EthPrimitives>,
Node: FullNodeTypes<Types = Types>,
{
type EVM = EthEvmConfig;

View File

@ -8,9 +8,6 @@ use crate::{
};
use alloc::boxed::Box;
use alloy_primitives::BlockNumber;
use reth_execution_errors::BlockExecutionError;
use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput, ExecutionOutcome};
use reth_primitives::{BlockWithSenders, Receipt};
use reth_prune_types::PruneModes;
use reth_storage_errors::provider::ProviderError;
use revm_primitives::db::Database;
@ -22,8 +19,10 @@ use revm::State;
impl<A, B> BlockExecutorProvider for Either<A, B>
where
A: BlockExecutorProvider,
B: BlockExecutorProvider,
B: BlockExecutorProvider<Primitives = A::Primitives>,
{
type Primitives = A::Primitives;
type Executor<DB: Database<Error: Into<ProviderError> + Display>> =
Either<A::Executor<DB>, B::Executor<DB>>;
@ -53,23 +52,13 @@ where
impl<A, B, DB> Executor<DB> for Either<A, B>
where
A: for<'a> Executor<
DB,
Input<'a> = BlockExecutionInput<'a, BlockWithSenders>,
Output = BlockExecutionOutput<Receipt>,
Error = BlockExecutionError,
>,
B: for<'a> Executor<
DB,
Input<'a> = BlockExecutionInput<'a, BlockWithSenders>,
Output = BlockExecutionOutput<Receipt>,
Error = BlockExecutionError,
>,
A: Executor<DB>,
B: for<'a> Executor<DB, Input<'a> = A::Input<'a>, Output = A::Output, Error = A::Error>,
DB: Database<Error: Into<ProviderError> + Display>,
{
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
type Output = BlockExecutionOutput<Receipt>;
type Error = BlockExecutionError;
type Input<'a> = A::Input<'a>;
type Output = A::Output;
type Error = A::Error;
fn init(&mut self, tx_env_overrides: Box<dyn crate::TxEnvOverrides>) {
match self {
@ -116,23 +105,13 @@ where
impl<A, B, DB> BatchExecutor<DB> for Either<A, B>
where
A: for<'a> BatchExecutor<
DB,
Input<'a> = BlockExecutionInput<'a, BlockWithSenders>,
Output = ExecutionOutcome,
Error = BlockExecutionError,
>,
B: for<'a> BatchExecutor<
DB,
Input<'a> = BlockExecutionInput<'a, BlockWithSenders>,
Output = ExecutionOutcome,
Error = BlockExecutionError,
>,
A: BatchExecutor<DB>,
B: for<'a> BatchExecutor<DB, Input<'a> = A::Input<'a>, Output = A::Output, Error = A::Error>,
DB: Database<Error: Into<ProviderError> + Display>,
{
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
type Output = ExecutionOutcome;
type Error = BlockExecutionError;
type Input<'a> = A::Input<'a>;
type Output = A::Output;
type Error = A::Error;
fn execute_and_verify_one(&mut self, input: Self::Input<'_>) -> Result<(), Self::Error> {
match self {

View File

@ -1,19 +1,21 @@
//! Traits for execution.
use alloy_consensus::BlockHeader;
// Re-export execution types
pub use reth_execution_errors::{
BlockExecutionError, BlockValidationError, InternalBlockExecutionError,
};
pub use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput, ExecutionOutcome};
use reth_primitives_traits::Block as _;
pub use reth_storage_errors::provider::ProviderError;
use crate::{system_calls::OnStateHook, TxEnvOverrides};
use alloc::{boxed::Box, vec::Vec};
use alloy_eips::eip7685::Requests;
use alloy_primitives::BlockNumber;
use core::{fmt::Display, marker::PhantomData};
use core::fmt::Display;
use reth_consensus::ConsensusError;
use reth_primitives::{BlockWithSenders, Receipt};
use reth_primitives::{BlockWithSenders, NodePrimitives, Receipt};
use reth_prune_types::PruneModes;
use reth_revm::batch::BlockBatchRecord;
use revm::{
@ -130,6 +132,9 @@ pub trait BatchExecutor<DB> {
/// A type that can create a new executor for block execution.
pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static {
/// Receipt type.
type Primitives: NodePrimitives;
/// An executor that can execute a single block given a database.
///
/// # Verification
@ -143,16 +148,22 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static {
/// the returned state.
type Executor<DB: Database<Error: Into<ProviderError> + Display>>: for<'a> Executor<
DB,
Input<'a> = BlockExecutionInput<'a, BlockWithSenders>,
Output = BlockExecutionOutput<Receipt>,
Input<'a> = BlockExecutionInput<
'a,
BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
>,
Output = BlockExecutionOutput<<Self::Primitives as NodePrimitives>::Receipt>,
Error = BlockExecutionError,
>;
/// An executor that can execute a batch of blocks given a database.
type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>>: for<'a> BatchExecutor<
DB,
Input<'a> = BlockExecutionInput<'a, BlockWithSenders>,
Output = ExecutionOutcome,
Input<'a> = BlockExecutionInput<
'a,
BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
>,
Output = ExecutionOutcome<<Self::Primitives as NodePrimitives>::Receipt>,
Error = BlockExecutionError,
>;
@ -174,18 +185,21 @@ pub trait BlockExecutorProvider: Send + Sync + Clone + Unpin + 'static {
/// Helper type for the output of executing a block.
#[derive(Debug, Clone)]
pub struct ExecuteOutput {
pub struct ExecuteOutput<R = Receipt> {
/// Receipts obtained after executing a block.
pub receipts: Vec<Receipt>,
pub receipts: Vec<R>,
/// Cumulative gas used in the block execution.
pub gas_used: u64,
}
/// Defines the strategy for executing a single block.
pub trait BlockExecutionStrategy<DB>
where
DB: Database,
{
pub trait BlockExecutionStrategy {
/// Database this strategy operates on.
type DB: Database;
/// Primitive types used by the strategy.
type Primitives: NodePrimitives;
/// The error type returned by this strategy's methods.
type Error: From<ProviderError> + core::error::Error;
@ -195,30 +209,30 @@ where
/// Applies any necessary changes before executing the block's transactions.
fn apply_pre_execution_changes(
&mut self,
block: &BlockWithSenders,
block: &BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
total_difficulty: U256,
) -> Result<(), Self::Error>;
/// Executes all transactions in the block.
fn execute_transactions(
&mut self,
block: &BlockWithSenders,
block: &BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
total_difficulty: U256,
) -> Result<ExecuteOutput, Self::Error>;
) -> Result<ExecuteOutput<<Self::Primitives as NodePrimitives>::Receipt>, Self::Error>;
/// Applies any necessary changes after executing the block's transactions.
fn apply_post_execution_changes(
&mut self,
block: &BlockWithSenders,
block: &BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
total_difficulty: U256,
receipts: &[Receipt],
receipts: &[<Self::Primitives as NodePrimitives>::Receipt],
) -> Result<Requests, Self::Error>;
/// Returns a reference to the current state.
fn state_ref(&self) -> &State<DB>;
fn state_ref(&self) -> &State<Self::DB>;
/// Returns a mutable reference to the current state.
fn state_mut(&mut self) -> &mut State<DB>;
fn state_mut(&mut self) -> &mut State<Self::DB>;
/// Sets a hook to be called after each state change during execution.
fn with_state_hook(&mut self, _hook: Option<Box<dyn OnStateHook>>) {}
@ -232,8 +246,8 @@ where
/// Validate a block with regard to execution results.
fn validate_block_post_execution(
&self,
_block: &BlockWithSenders,
_receipts: &[Receipt],
_block: &BlockWithSenders<<Self::Primitives as NodePrimitives>::Block>,
_receipts: &[<Self::Primitives as NodePrimitives>::Receipt],
_requests: &Requests,
) -> Result<(), ConsensusError> {
Ok(())
@ -242,9 +256,13 @@ where
/// A strategy factory that can create block execution strategies.
pub trait BlockExecutionStrategyFactory: Send + Sync + Clone + Unpin + 'static {
/// Primitive types used by the strategy.
type Primitives: NodePrimitives;
/// Associated strategy type.
type Strategy<DB: Database<Error: Into<ProviderError> + Display>>: BlockExecutionStrategy<
DB,
DB = DB,
Primitives = Self::Primitives,
Error = BlockExecutionError,
>;
@ -280,11 +298,13 @@ impl<F> BlockExecutorProvider for BasicBlockExecutorProvider<F>
where
F: BlockExecutionStrategyFactory,
{
type Primitives = F::Primitives;
type Executor<DB: Database<Error: Into<ProviderError> + Display>> =
BasicBlockExecutor<F::Strategy<DB>, DB>;
BasicBlockExecutor<F::Strategy<DB>>;
type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> =
BasicBatchExecutor<F::Strategy<DB>, DB>;
BasicBatchExecutor<F::Strategy<DB>>;
fn executor<DB>(&self, db: DB) -> Self::Executor<DB>
where
@ -307,34 +327,26 @@ where
/// A generic block executor that uses a [`BlockExecutionStrategy`] to
/// execute blocks.
#[allow(missing_debug_implementations, dead_code)]
pub struct BasicBlockExecutor<S, DB>
where
S: BlockExecutionStrategy<DB>,
DB: Database,
{
pub struct BasicBlockExecutor<S> {
/// Block execution strategy.
pub(crate) strategy: S,
_phantom: PhantomData<DB>,
}
impl<S, DB> BasicBlockExecutor<S, DB>
where
S: BlockExecutionStrategy<DB>,
DB: Database,
{
impl<S> BasicBlockExecutor<S> {
/// Creates a new `BasicBlockExecutor` with the given strategy.
pub const fn new(strategy: S) -> Self {
Self { strategy, _phantom: PhantomData }
Self { strategy }
}
}
impl<S, DB> Executor<DB> for BasicBlockExecutor<S, DB>
impl<S, DB> Executor<DB> for BasicBlockExecutor<S>
where
S: BlockExecutionStrategy<DB>,
S: BlockExecutionStrategy<DB = DB>,
DB: Database<Error: Into<ProviderError> + Display>,
{
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
type Output = BlockExecutionOutput<Receipt>;
type Input<'a> =
BlockExecutionInput<'a, BlockWithSenders<<S::Primitives as NodePrimitives>::Block>>;
type Output = BlockExecutionOutput<<S::Primitives as NodePrimitives>::Receipt>;
type Error = S::Error;
fn init(&mut self, env_overrides: Box<dyn TxEnvOverrides>) {
@ -404,43 +416,44 @@ where
/// A generic batch executor that uses a [`BlockExecutionStrategy`] to
/// execute batches.
#[allow(missing_debug_implementations)]
pub struct BasicBatchExecutor<S, DB>
pub struct BasicBatchExecutor<S>
where
S: BlockExecutionStrategy<DB>,
DB: Database,
S: BlockExecutionStrategy,
{
/// Batch execution strategy.
pub(crate) strategy: S,
/// Keeps track of batch execution receipts and requests.
pub(crate) batch_record: BlockBatchRecord,
_phantom: PhantomData<DB>,
pub(crate) batch_record: BlockBatchRecord<<S::Primitives as NodePrimitives>::Receipt>,
}
impl<S, DB> BasicBatchExecutor<S, DB>
impl<S> BasicBatchExecutor<S>
where
S: BlockExecutionStrategy<DB>,
DB: Database,
S: BlockExecutionStrategy,
{
/// Creates a new `BasicBatchExecutor` with the given strategy.
pub const fn new(strategy: S, batch_record: BlockBatchRecord) -> Self {
Self { strategy, batch_record, _phantom: PhantomData }
pub const fn new(
strategy: S,
batch_record: BlockBatchRecord<<S::Primitives as NodePrimitives>::Receipt>,
) -> Self {
Self { strategy, batch_record }
}
}
impl<S, DB> BatchExecutor<DB> for BasicBatchExecutor<S, DB>
impl<S, DB> BatchExecutor<DB> for BasicBatchExecutor<S>
where
S: BlockExecutionStrategy<DB, Error = BlockExecutionError>,
S: BlockExecutionStrategy<DB = DB, Error = BlockExecutionError>,
DB: Database<Error: Into<ProviderError> + Display>,
{
type Input<'a> = BlockExecutionInput<'a, BlockWithSenders>;
type Output = ExecutionOutcome;
type Input<'a> =
BlockExecutionInput<'a, BlockWithSenders<<S::Primitives as NodePrimitives>::Block>>;
type Output = ExecutionOutcome<<S::Primitives as NodePrimitives>::Receipt>;
type Error = BlockExecutionError;
fn execute_and_verify_one(&mut self, input: Self::Input<'_>) -> Result<(), Self::Error> {
let BlockExecutionInput { block, total_difficulty } = input;
if self.batch_record.first_block().is_none() {
self.batch_record.set_first_block(block.number);
self.batch_record.set_first_block(block.header().number());
}
self.strategy.apply_pre_execution_changes(block, total_difficulty)?;
@ -452,7 +465,7 @@ where
self.strategy.validate_block_post_execution(block, &receipts, &requests)?;
// prepare the state according to the prune mode
let retention = self.batch_record.bundle_retention(block.number);
let retention = self.batch_record.bundle_retention(block.header().number());
self.strategy.state_mut().merge_transitions(retention);
// store receipts in the set
@ -490,7 +503,9 @@ where
mod tests {
use super::*;
use alloy_primitives::U256;
use core::marker::PhantomData;
use reth_chainspec::{ChainSpec, MAINNET};
use reth_primitives::EthPrimitives;
use revm::db::{CacheDB, EmptyDBTyped};
use revm_primitives::{bytes, TxEnv};
use std::sync::Arc;
@ -499,6 +514,7 @@ mod tests {
struct TestExecutorProvider;
impl BlockExecutorProvider for TestExecutorProvider {
type Primitives = EthPrimitives;
type Executor<DB: Database<Error: Into<ProviderError> + Display>> = TestExecutor<DB>;
type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> = TestExecutor<DB>;
@ -596,6 +612,7 @@ mod tests {
}
impl BlockExecutionStrategyFactory for TestExecutorStrategyFactory {
type Primitives = EthPrimitives;
type Strategy<DB: Database<Error: Into<ProviderError> + Display>> =
TestExecutorStrategy<DB, TestEvmConfig>;
@ -622,10 +639,12 @@ mod tests {
}
}
impl<DB> BlockExecutionStrategy<DB> for TestExecutorStrategy<DB, TestEvmConfig>
impl<DB> BlockExecutionStrategy for TestExecutorStrategy<DB, TestEvmConfig>
where
DB: Database,
{
type DB = DB;
type Primitives = EthPrimitives;
type Error = BlockExecutionError;
fn apply_pre_execution_changes(

View File

@ -3,6 +3,7 @@
//! Block processing related to syncing should take care to update the metrics by using either
//! [`ExecutorMetrics::execute_metered`] or [`ExecutorMetrics::metered_one`].
use crate::{execute::Executor, system_calls::OnStateHook};
use alloy_consensus::BlockHeader;
use metrics::{Counter, Gauge, Histogram};
use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput};
use reth_metrics::Metrics;
@ -69,9 +70,10 @@ pub struct ExecutorMetrics {
}
impl ExecutorMetrics {
fn metered<F, R>(&self, block: &BlockWithSenders, f: F) -> R
fn metered<F, R, B>(&self, block: &BlockWithSenders<B>, f: F) -> R
where
F: FnOnce() -> R,
B: reth_primitives_traits::Block,
{
// Execute the block and record the elapsed time.
let execute_start = Instant::now();
@ -79,8 +81,8 @@ impl ExecutorMetrics {
let execution_duration = execute_start.elapsed().as_secs_f64();
// Update gas metrics.
self.gas_processed_total.increment(block.gas_used);
self.gas_per_second.set(block.gas_used as f64 / execution_duration);
self.gas_processed_total.increment(block.header().gas_used());
self.gas_per_second.set(block.header().gas_used() as f64 / execution_duration);
self.execution_histogram.record(execution_duration);
self.execution_duration.set(execution_duration);
@ -94,19 +96,20 @@ impl ExecutorMetrics {
/// of accounts, storage slots and bytecodes loaded and updated.
/// Execute the given block using the provided [`Executor`] and update metrics for the
/// execution.
pub fn execute_metered<'a, E, DB, O, Error>(
pub fn execute_metered<'a, E, DB, O, Error, B>(
&self,
executor: E,
input: BlockExecutionInput<'a, BlockWithSenders>,
input: BlockExecutionInput<'a, BlockWithSenders<B>>,
state_hook: Box<dyn OnStateHook>,
) -> Result<BlockExecutionOutput<O>, Error>
where
E: Executor<
DB,
Input<'a> = BlockExecutionInput<'a, BlockWithSenders>,
Input<'a> = BlockExecutionInput<'a, BlockWithSenders<B>>,
Output = BlockExecutionOutput<O>,
Error = Error,
>,
B: reth_primitives_traits::Block,
{
// clone here is cheap, all the metrics are Option<Arc<_>>. additionally
// they are gloally registered so that the data recorded in the hook will
@ -133,9 +136,14 @@ impl ExecutorMetrics {
}
/// Execute the given block and update metrics for the execution.
pub fn metered_one<F, R>(&self, input: BlockExecutionInput<'_, BlockWithSenders>, f: F) -> R
pub fn metered_one<F, R, B>(
&self,
input: BlockExecutionInput<'_, BlockWithSenders<B>>,
f: F,
) -> R
where
F: FnOnce(BlockExecutionInput<'_, BlockWithSenders>) -> R,
F: FnOnce(BlockExecutionInput<'_, BlockWithSenders<B>>) -> R,
B: reth_primitives_traits::Block,
{
self.metered(input.block, || f(input))
}

View File

@ -4,7 +4,7 @@ use alloy_primitives::BlockNumber;
use core::fmt::Display;
use reth_execution_errors::BlockExecutionError;
use reth_execution_types::{BlockExecutionInput, BlockExecutionOutput, ExecutionOutcome};
use reth_primitives::{BlockWithSenders, Receipt};
use reth_primitives::{BlockWithSenders, EthPrimitives, Receipt};
use reth_prune_types::PruneModes;
use reth_storage_errors::provider::ProviderError;
use revm::State;
@ -23,6 +23,8 @@ const UNAVAILABLE_FOR_NOOP: &str = "execution unavailable for noop";
pub struct NoopBlockExecutorProvider;
impl BlockExecutorProvider for NoopBlockExecutorProvider {
type Primitives = EthPrimitives;
type Executor<DB: Database<Error: Into<ProviderError> + Display>> = Self;
type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> = Self;

View File

@ -12,7 +12,7 @@ use alloy_primitives::BlockNumber;
use parking_lot::Mutex;
use reth_execution_errors::BlockExecutionError;
use reth_execution_types::ExecutionOutcome;
use reth_primitives::{BlockWithSenders, Receipt, Receipts};
use reth_primitives::{BlockWithSenders, EthPrimitives, NodePrimitives, Receipt, Receipts};
use reth_prune_types::PruneModes;
use reth_storage_errors::provider::ProviderError;
use revm::State;
@ -33,6 +33,8 @@ impl MockExecutorProvider {
}
impl BlockExecutorProvider for MockExecutorProvider {
type Primitives = EthPrimitives;
type Executor<DB: Database<Error: Into<ProviderError> + Display>> = Self;
type BatchExecutor<DB: Database<Error: Into<ProviderError> + Display>> = Self;
@ -116,15 +118,14 @@ impl<DB> BatchExecutor<DB> for MockExecutorProvider {
}
}
impl<S, DB> BasicBlockExecutor<S, DB>
impl<S> BasicBlockExecutor<S>
where
S: BlockExecutionStrategy<DB>,
DB: Database,
S: BlockExecutionStrategy,
{
/// Provides safe read access to the state
pub fn with_state<F, R>(&self, f: F) -> R
where
F: FnOnce(&State<DB>) -> R,
F: FnOnce(&State<S::DB>) -> R,
{
f(self.strategy.state_ref())
}
@ -132,21 +133,20 @@ where
/// Provides safe write access to the state
pub fn with_state_mut<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&mut State<DB>) -> R,
F: FnOnce(&mut State<S::DB>) -> R,
{
f(self.strategy.state_mut())
}
}
impl<S, DB> BasicBatchExecutor<S, DB>
impl<S> BasicBatchExecutor<S>
where
S: BlockExecutionStrategy<DB>,
DB: Database,
S: BlockExecutionStrategy,
{
/// Provides safe read access to the state
pub fn with_state<F, R>(&self, f: F) -> R
where
F: FnOnce(&State<DB>) -> R,
F: FnOnce(&State<S::DB>) -> R,
{
f(self.strategy.state_ref())
}
@ -154,13 +154,13 @@ where
/// Provides safe write access to the state
pub fn with_state_mut<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&mut State<DB>) -> R,
F: FnOnce(&mut State<S::DB>) -> R,
{
f(self.strategy.state_mut())
}
/// Accessor for batch executor receipts.
pub const fn receipts(&self) -> &Receipts {
pub const fn receipts(&self) -> &Receipts<<S::Primitives as NodePrimitives>::Receipt> {
self.batch_record.receipts()
}
}

View File

@ -9,7 +9,7 @@ use alloy_primitives::BlockNumber;
use reth_evm::execute::{
BatchExecutor, BlockExecutionError, BlockExecutionOutput, BlockExecutorProvider, Executor,
};
use reth_node_api::{Block as _, BlockBody as _};
use reth_node_api::{Block as _, BlockBody as _, NodePrimitives};
use reth_primitives::{BlockExt, BlockWithSenders, Receipt};
use reth_primitives_traits::{format_gas_throughput, SignedTransaction};
use reth_provider::{
@ -38,12 +38,10 @@ pub struct BackfillJob<E, P> {
impl<E, P> Iterator for BackfillJob<E, P>
where
E: BlockExecutorProvider,
P: HeaderProvider
+ BlockReader<Transaction: SignedTransaction, Block = reth_primitives::Block>
+ StateProviderFactory,
E: BlockExecutorProvider<Primitives: NodePrimitives<Block = P::Block>>,
P: HeaderProvider + BlockReader<Transaction: SignedTransaction> + StateProviderFactory,
{
type Item = BackfillJobResult<Chain>;
type Item = BackfillJobResult<Chain<E::Primitives>>;
fn next(&mut self) -> Option<Self::Item> {
if self.range.is_empty() {
@ -56,10 +54,8 @@ where
impl<E, P> BackfillJob<E, P>
where
E: BlockExecutorProvider,
P: BlockReader<Transaction: SignedTransaction, Block = reth_primitives::Block>
+ HeaderProvider
+ StateProviderFactory,
E: BlockExecutorProvider<Primitives: NodePrimitives<Block = P::Block>>,
P: BlockReader<Transaction: SignedTransaction> + HeaderProvider + StateProviderFactory,
{
/// Converts the backfill job into a single block backfill job.
pub fn into_single_blocks(self) -> SingleBlockBackfillJob<E, P> {
@ -67,11 +63,11 @@ where
}
/// Converts the backfill job into a stream.
pub fn into_stream(self) -> StreamBackfillJob<E, P, Chain> {
pub fn into_stream(self) -> StreamBackfillJob<E, P, Chain<E::Primitives>> {
self.into()
}
fn execute_range(&mut self) -> BackfillJobResult<Chain> {
fn execute_range(&mut self) -> BackfillJobResult<Chain<E::Primitives>> {
debug!(
target: "exex::backfill",
range = ?self.range,
@ -169,10 +165,13 @@ pub struct SingleBlockBackfillJob<E, P> {
impl<E, P> Iterator for SingleBlockBackfillJob<E, P>
where
E: BlockExecutorProvider,
P: HeaderProvider + BlockReader<Block = reth_primitives::Block> + StateProviderFactory,
E: BlockExecutorProvider<Primitives: NodePrimitives<Block = P::Block>>,
P: HeaderProvider + BlockReader + StateProviderFactory,
{
type Item = BackfillJobResult<(BlockWithSenders, BlockExecutionOutput<Receipt>)>;
type Item = BackfillJobResult<(
BlockWithSenders<P::Block>,
BlockExecutionOutput<<E::Primitives as NodePrimitives>::Receipt>,
)>;
fn next(&mut self) -> Option<Self::Item> {
self.range.next().map(|block_number| self.execute_block(block_number))
@ -181,8 +180,8 @@ where
impl<E, P> SingleBlockBackfillJob<E, P>
where
E: BlockExecutorProvider,
P: HeaderProvider + BlockReader<Block = reth_primitives::Block> + StateProviderFactory,
E: BlockExecutorProvider<Primitives: NodePrimitives<Block = P::Block>>,
P: HeaderProvider + BlockReader + StateProviderFactory,
{
/// Converts the single block backfill job into a stream.
pub fn into_stream(
@ -191,10 +190,14 @@ where
self.into()
}
#[expect(clippy::type_complexity)]
pub(crate) fn execute_block(
&self,
block_number: u64,
) -> BackfillJobResult<(BlockWithSenders<P::Block>, BlockExecutionOutput<Receipt>)> {
) -> BackfillJobResult<(
BlockWithSenders<P::Block>,
BlockExecutionOutput<<E::Primitives as NodePrimitives>::Receipt>,
)> {
let td = self
.provider
.header_td_by_number(block_number)?

View File

@ -11,7 +11,8 @@ use futures::{
StreamExt,
};
use reth_evm::execute::{BlockExecutionError, BlockExecutionOutput, BlockExecutorProvider};
use reth_primitives::{BlockWithSenders, Receipt};
use reth_node_api::NodePrimitives;
use reth_primitives::{BlockWithSenders, EthPrimitives};
use reth_provider::{BlockReader, Chain, HeaderProvider, StateProviderFactory};
use reth_prune_types::PruneModes;
use reth_stages_api::ExecutionStageThresholds;
@ -38,8 +39,11 @@ struct BackfillTaskOutput<T> {
/// Ordered queue of [`JoinHandle`]s that yield [`BackfillTaskOutput`]s.
type BackfillTasks<T> = FuturesOrdered<JoinHandle<BackfillTaskOutput<T>>>;
type SingleBlockStreamItem = (BlockWithSenders, BlockExecutionOutput<Receipt>);
type BatchBlockStreamItem = Chain;
type SingleBlockStreamItem<N = EthPrimitives> = (
BlockWithSenders<<N as NodePrimitives>::Block>,
BlockExecutionOutput<<N as NodePrimitives>::Receipt>,
);
type BatchBlockStreamItem<N = EthPrimitives> = Chain<N>;
/// Stream for processing backfill jobs asynchronously.
///
@ -100,18 +104,12 @@ where
}
}
impl<E, P> Stream for StreamBackfillJob<E, P, SingleBlockStreamItem>
impl<E, P> Stream for StreamBackfillJob<E, P, SingleBlockStreamItem<E::Primitives>>
where
E: BlockExecutorProvider + Clone + Send + 'static,
P: HeaderProvider
+ BlockReader<Block = reth_primitives::Block>
+ StateProviderFactory
+ Clone
+ Send
+ Unpin
+ 'static,
E: BlockExecutorProvider<Primitives: NodePrimitives<Block = P::Block>> + Clone + Send + 'static,
P: HeaderProvider + BlockReader + StateProviderFactory + Clone + Send + Unpin + 'static,
{
type Item = BackfillJobResult<SingleBlockStreamItem>;
type Item = BackfillJobResult<SingleBlockStreamItem<E::Primitives>>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.get_mut();
@ -139,18 +137,12 @@ where
}
}
impl<E, P> Stream for StreamBackfillJob<E, P, BatchBlockStreamItem>
impl<E, P> Stream for StreamBackfillJob<E, P, BatchBlockStreamItem<E::Primitives>>
where
E: BlockExecutorProvider + Clone + Send + 'static,
P: HeaderProvider
+ BlockReader<Block = reth_primitives::Block>
+ StateProviderFactory
+ Clone
+ Send
+ Unpin
+ 'static,
E: BlockExecutorProvider<Primitives: NodePrimitives<Block = P::Block>> + Clone + Send + 'static,
P: HeaderProvider + BlockReader + StateProviderFactory + Clone + Send + Unpin + 'static,
{
type Item = BackfillJobResult<BatchBlockStreamItem>;
type Item = BackfillJobResult<BatchBlockStreamItem<E::Primitives>>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.get_mut();
@ -200,7 +192,10 @@ impl<E, P> From<SingleBlockBackfillJob<E, P>> for StreamBackfillJob<E, P, Single
}
}
impl<E, P> From<BackfillJob<E, P>> for StreamBackfillJob<E, P, BatchBlockStreamItem> {
impl<E, P> From<BackfillJob<E, P>> for StreamBackfillJob<E, P, BatchBlockStreamItem<E::Primitives>>
where
E: BlockExecutorProvider,
{
fn from(job: BackfillJob<E, P>) -> Self {
let batch_size = job.thresholds.max_blocks.map_or(DEFAULT_BATCH_SIZE, |max| max as usize);
Self {

View File

@ -1,6 +1,6 @@
use crate::{ExExContextDyn, ExExEvent, ExExNotifications, ExExNotificationsStream};
use reth_exex_types::ExExHead;
use reth_node_api::{FullNodeComponents, NodeTypes};
use reth_node_api::{FullNodeComponents, NodePrimitives, NodeTypes};
use reth_node_core::node_config::NodeConfig;
use reth_primitives::Head;
use reth_provider::BlockReader;
@ -57,11 +57,12 @@ where
impl<Node> ExExContext<Node>
where
Node: FullNodeComponents,
Node::Provider: Debug + BlockReader<Block = reth_primitives::Block>,
Node::Provider: Debug + BlockReader,
Node::Executor: Debug,
Node::Types: NodeTypes<Primitives: NodePrimitives>,
{
/// Returns dynamic version of the context
pub fn into_dyn(self) -> ExExContextDyn {
pub fn into_dyn(self) -> ExExContextDyn<<Node::Types as NodeTypes>::Primitives> {
ExExContextDyn::from(self)
}
}
@ -69,6 +70,7 @@ where
impl<Node> ExExContext<Node>
where
Node: FullNodeComponents,
Node::Types: NodeTypes<Primitives: NodePrimitives>,
{
/// Returns the transaction pool of the node.
pub fn pool(&self) -> &Node::Pool {
@ -107,19 +109,13 @@ where
/// Sets notifications stream to [`crate::ExExNotificationsWithoutHead`], a stream of
/// notifications without a head.
pub fn set_notifications_without_head(&mut self)
where
Node::Provider: BlockReader<Block = reth_primitives::Block>,
{
pub fn set_notifications_without_head(&mut self) {
self.notifications.set_without_head();
}
/// Sets notifications stream to [`crate::ExExNotificationsWithHead`], a stream of notifications
/// with the provided head.
pub fn set_notifications_with_head(&mut self, head: ExExHead)
where
Node::Provider: BlockReader<Block = reth_primitives::Block>,
{
pub fn set_notifications_with_head(&mut self, head: ExExHead) {
self.notifications.set_with_head(head);
}
}
@ -142,7 +138,7 @@ mod tests {
impl<Node: FullNodeComponents> ExEx<Node>
where
Node::Provider: BlockReader<Block = reth_primitives::Block>,
Node::Provider: BlockReader,
{
async fn _test_bounds(mut self) -> eyre::Result<()> {
self.ctx.pool();

View File

@ -4,8 +4,9 @@
use std::fmt::Debug;
use reth_chainspec::{EthChainSpec, Head};
use reth_node_api::FullNodeComponents;
use reth_node_api::{FullNodeComponents, NodePrimitives, NodeTypes};
use reth_node_core::node_config::NodeConfig;
use reth_primitives::EthPrimitives;
use reth_provider::BlockReader;
use tokio::sync::mpsc;
@ -13,7 +14,7 @@ use crate::{ExExContext, ExExEvent, ExExNotificationsStream};
// TODO(0xurb) - add `node` after abstractions
/// Captures the context that an `ExEx` has access to.
pub struct ExExContextDyn {
pub struct ExExContextDyn<N: NodePrimitives = EthPrimitives> {
/// The current head of the blockchain at launch.
pub head: Head,
/// The config of the node
@ -34,10 +35,10 @@ pub struct ExExContextDyn {
///
/// Once an [`ExExNotification`](crate::ExExNotification) is sent over the channel, it is
/// considered delivered by the node.
pub notifications: Box<dyn ExExNotificationsStream>,
pub notifications: Box<dyn ExExNotificationsStream<N>>,
}
impl Debug for ExExContextDyn {
impl<N: NodePrimitives> Debug for ExExContextDyn<N> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ExExContext")
.field("head", &self.head)
@ -49,16 +50,16 @@ impl Debug for ExExContextDyn {
}
}
impl<Node> From<ExExContext<Node>> for ExExContextDyn
impl<Node> From<ExExContext<Node>> for ExExContextDyn<<Node::Types as NodeTypes>::Primitives>
where
Node: FullNodeComponents,
Node::Provider: Debug + BlockReader<Block = reth_primitives::Block>,
Node: FullNodeComponents<Types: NodeTypes<Primitives: NodePrimitives>>,
Node::Provider: Debug + BlockReader,
Node::Executor: Debug,
{
fn from(ctx: ExExContext<Node>) -> Self {
let config =
ctx.config.map_chainspec(|chainspec| Box::new(chainspec) as Box<dyn EthChainSpec>);
let notifications = Box::new(ctx.notifications) as Box<dyn ExExNotificationsStream>;
let notifications = Box::new(ctx.notifications) as Box<_>;
Self {
head: ctx.head,

View File

@ -1,14 +1,17 @@
use crate::{
wal::Wal, ExExEvent, ExExNotification, ExExNotifications, FinishedExExHeight, WalHandle,
};
use alloy_consensus::BlockHeader;
use alloy_eips::BlockNumHash;
use futures::StreamExt;
use itertools::Itertools;
use metrics::Gauge;
use reth_chain_state::ForkChoiceStream;
use reth_chainspec::Head;
use reth_evm::execute::BlockExecutorProvider;
use reth_metrics::{metrics::Counter, Metrics};
use reth_primitives::SealedHeader;
use reth_node_api::NodePrimitives;
use reth_primitives::{EthPrimitives, SealedHeader};
use reth_provider::HeaderProvider;
use reth_tracing::tracing::{debug, warn};
use std::{
@ -69,13 +72,13 @@ struct ExExMetrics {
/// [`ExExHandle::new`] should be given to the `ExEx`, while the handle itself should be given to
/// the manager in [`ExExManager::new`].
#[derive(Debug)]
pub struct ExExHandle {
pub struct ExExHandle<N: NodePrimitives = EthPrimitives> {
/// The execution extension's ID.
id: String,
/// Metrics for an `ExEx`.
metrics: ExExMetrics,
/// Channel to send [`ExExNotification`]s to the `ExEx`.
sender: PollSender<ExExNotification>,
sender: PollSender<ExExNotification<N>>,
/// Channel to receive [`ExExEvent`]s from the `ExEx`.
receiver: UnboundedReceiver<ExExEvent>,
/// The ID of the next notification to send to this `ExEx`.
@ -86,17 +89,17 @@ pub struct ExExHandle {
finished_height: Option<BlockNumHash>,
}
impl ExExHandle {
impl<N: NodePrimitives> ExExHandle<N> {
/// Create a new handle for the given `ExEx`.
///
/// Returns the handle, as well as a [`UnboundedSender`] for [`ExExEvent`]s and a
/// [`mpsc::Receiver`] for [`ExExNotification`]s that should be given to the `ExEx`.
pub fn new<P, E>(
pub fn new<P, E: BlockExecutorProvider<Primitives = N>>(
id: String,
node_head: Head,
provider: P,
executor: E,
wal_handle: WalHandle,
wal_handle: WalHandle<N>,
) -> (Self, UnboundedSender<ExExEvent>, ExExNotifications<P, E>) {
let (notification_tx, notification_rx) = mpsc::channel(1);
let (event_tx, event_rx) = mpsc::unbounded_channel();
@ -124,21 +127,21 @@ impl ExExHandle {
fn send(
&mut self,
cx: &mut Context<'_>,
(notification_id, notification): &(usize, ExExNotification),
) -> Poll<Result<(), PollSendError<ExExNotification>>> {
(notification_id, notification): &(usize, ExExNotification<N>),
) -> Poll<Result<(), PollSendError<ExExNotification<N>>>> {
if let Some(finished_height) = self.finished_height {
match notification {
ExExNotification::ChainCommitted { new } => {
// Skip the chain commit notification if the finished height of the ExEx is
// higher than or equal to the tip of the new notification.
// I.e., the ExEx has already processed the notification.
if finished_height.number >= new.tip().number {
if finished_height.number >= new.tip().number() {
debug!(
target: "exex::manager",
exex_id = %self.id,
%notification_id,
?finished_height,
new_tip = %new.tip().number,
new_tip = %new.tip().number(),
"Skipping notification"
);
@ -208,15 +211,15 @@ pub struct ExExManagerMetrics {
/// - Error handling
/// - Monitoring
#[derive(Debug)]
pub struct ExExManager<P> {
pub struct ExExManager<P, N: NodePrimitives> {
/// Provider for querying headers.
provider: P,
/// Handles to communicate with the `ExEx`'s.
exex_handles: Vec<ExExHandle>,
exex_handles: Vec<ExExHandle<N>>,
/// [`ExExNotification`] channel from the [`ExExManagerHandle`]s.
handle_rx: UnboundedReceiver<(ExExNotificationSource, ExExNotification)>,
handle_rx: UnboundedReceiver<(ExExNotificationSource, ExExNotification<N>)>,
/// The minimum notification ID currently present in the buffer.
min_id: usize,
@ -226,7 +229,7 @@ pub struct ExExManager<P> {
///
/// The first element of the tuple is a monotonically increasing ID unique to the notification
/// (the second element of the tuple).
buffer: VecDeque<(usize, ExExNotification)>,
buffer: VecDeque<(usize, ExExNotification<N>)>,
/// Max size of the internal state notifications buffer.
max_capacity: usize,
/// Current state notifications buffer capacity.
@ -241,17 +244,20 @@ pub struct ExExManager<P> {
finished_height: watch::Sender<FinishedExExHeight>,
/// Write-Ahead Log for the [`ExExNotification`]s.
wal: Wal,
wal: Wal<N>,
/// A stream of finalized headers.
finalized_header_stream: ForkChoiceStream<SealedHeader>,
/// A handle to the `ExEx` manager.
handle: ExExManagerHandle,
handle: ExExManagerHandle<N>,
/// Metrics for the `ExEx` manager.
metrics: ExExManagerMetrics,
}
impl<P> ExExManager<P> {
impl<P, N> ExExManager<P, N>
where
N: NodePrimitives,
{
/// Create a new [`ExExManager`].
///
/// You must provide an [`ExExHandle`] for each `ExEx` and the maximum capacity of the
@ -261,9 +267,9 @@ impl<P> ExExManager<P> {
/// notifications over [`ExExManagerHandle`]s until there is capacity again.
pub fn new(
provider: P,
handles: Vec<ExExHandle>,
handles: Vec<ExExHandle<N>>,
max_capacity: usize,
wal: Wal,
wal: Wal<N>,
finalized_header_stream: ForkChoiceStream<SealedHeader>,
) -> Self {
let num_exexs = handles.len();
@ -314,7 +320,7 @@ impl<P> ExExManager<P> {
}
/// Returns the handle to the manager.
pub fn handle(&self) -> ExExManagerHandle {
pub fn handle(&self) -> ExExManagerHandle<N> {
self.handle.clone()
}
@ -333,16 +339,17 @@ impl<P> ExExManager<P> {
/// Pushes a new notification into the managers internal buffer, assigning the notification a
/// unique ID.
fn push_notification(&mut self, notification: ExExNotification) {
fn push_notification(&mut self, notification: ExExNotification<N>) {
let next_id = self.next_id;
self.buffer.push_back((next_id, notification));
self.next_id += 1;
}
}
impl<P> ExExManager<P>
impl<P, N> ExExManager<P, N>
where
P: HeaderProvider,
N: NodePrimitives,
{
/// Finalizes the WAL according to the passed finalized header.
///
@ -413,9 +420,10 @@ where
}
}
impl<P> Future for ExExManager<P>
impl<P, N> Future for ExExManager<P, N>
where
P: HeaderProvider + Unpin + 'static,
N: NodePrimitives,
{
type Output = eyre::Result<()>;
@ -456,8 +464,9 @@ where
// Drain handle notifications
while this.buffer.len() < this.max_capacity {
if let Poll::Ready(Some((source, notification))) = this.handle_rx.poll_recv(cx) {
let committed_tip = notification.committed_chain().map(|chain| chain.tip().number);
let reverted_tip = notification.reverted_chain().map(|chain| chain.tip().number);
let committed_tip =
notification.committed_chain().map(|chain| chain.tip().number());
let reverted_tip = notification.reverted_chain().map(|chain| chain.tip().number());
debug!(target: "exex::manager", ?committed_tip, ?reverted_tip, "Received new notification");
// Commit to WAL only notifications from blockchain tree. Pipeline notifications
@ -524,9 +533,9 @@ where
/// A handle to communicate with the [`ExExManager`].
#[derive(Debug)]
pub struct ExExManagerHandle {
pub struct ExExManagerHandle<N: NodePrimitives = EthPrimitives> {
/// Channel to send notifications to the `ExEx` manager.
exex_tx: UnboundedSender<(ExExNotificationSource, ExExNotification)>,
exex_tx: UnboundedSender<(ExExNotificationSource, ExExNotification<N>)>,
/// The number of `ExEx`'s running on the node.
num_exexs: usize,
/// A watch channel denoting whether the manager is ready for new notifications or not.
@ -544,7 +553,7 @@ pub struct ExExManagerHandle {
finished_height: watch::Receiver<FinishedExExHeight>,
}
impl ExExManagerHandle {
impl<N: NodePrimitives> ExExManagerHandle<N> {
/// Creates an empty manager handle.
///
/// Use this if there is no manager present.
@ -571,8 +580,8 @@ impl ExExManagerHandle {
pub fn send(
&self,
source: ExExNotificationSource,
notification: ExExNotification,
) -> Result<(), SendError<(ExExNotificationSource, ExExNotification)>> {
notification: ExExNotification<N>,
) -> Result<(), SendError<(ExExNotificationSource, ExExNotification<N>)>> {
self.exex_tx.send((source, notification))
}
@ -583,8 +592,8 @@ impl ExExManagerHandle {
pub async fn send_async(
&mut self,
source: ExExNotificationSource,
notification: ExExNotification,
) -> Result<(), SendError<(ExExNotificationSource, ExExNotification)>> {
notification: ExExNotification<N>,
) -> Result<(), SendError<(ExExNotificationSource, ExExNotification<N>)>> {
self.ready().await;
self.exex_tx.send((source, notification))
}
@ -633,7 +642,7 @@ async fn make_wait_future(mut rx: watch::Receiver<bool>) -> watch::Receiver<bool
rx
}
impl Clone for ExExManagerHandle {
impl<N: NodePrimitives> Clone for ExExManagerHandle<N> {
fn clone(&self) -> Self {
Self {
exex_tx: self.exex_tx.clone(),
@ -653,6 +662,7 @@ mod tests {
use futures::{StreamExt, TryStreamExt};
use rand::Rng;
use reth_db_common::init::init_genesis;
use reth_evm::test_utils::MockExecutorProvider;
use reth_evm_ethereum::execute::EthExecutorProvider;
use reth_primitives::SealedBlockWithSenders;
use reth_provider::{
@ -673,8 +683,13 @@ mod tests {
let temp_dir = tempfile::tempdir().unwrap();
let wal = Wal::new(temp_dir.path()).unwrap();
let (mut exex_handle, event_tx, mut _notification_rx) =
ExExHandle::new("test_exex".to_string(), Head::default(), (), (), wal.handle());
let (mut exex_handle, event_tx, mut _notification_rx) = ExExHandle::new(
"test_exex".to_string(),
Head::default(),
(),
MockExecutorProvider::default(),
wal.handle(),
);
// Send an event and check that it's delivered correctly
let event = ExExEvent::FinishedHeight(BlockNumHash::new(42, B256::random()));
@ -688,8 +703,13 @@ mod tests {
let temp_dir = tempfile::tempdir().unwrap();
let wal = Wal::new(temp_dir.path()).unwrap();
let (exex_handle_1, _, _) =
ExExHandle::new("test_exex_1".to_string(), Head::default(), (), (), wal.handle());
let (exex_handle_1, _, _) = ExExHandle::new(
"test_exex_1".to_string(),
Head::default(),
(),
MockExecutorProvider::default(),
wal.handle(),
);
assert!(!ExExManager::new((), vec![], 0, wal.clone(), empty_finalized_header_stream())
.handle
@ -705,8 +725,13 @@ mod tests {
let temp_dir = tempfile::tempdir().unwrap();
let wal = Wal::new(temp_dir.path()).unwrap();
let (exex_handle_1, _, _) =
ExExHandle::new("test_exex_1".to_string(), Head::default(), (), (), wal.handle());
let (exex_handle_1, _, _) = ExExHandle::new(
"test_exex_1".to_string(),
Head::default(),
(),
MockExecutorProvider::default(),
wal.handle(),
);
assert!(!ExExManager::new((), vec![], 0, wal.clone(), empty_finalized_header_stream())
.handle
@ -728,8 +753,13 @@ mod tests {
let temp_dir = tempfile::tempdir().unwrap();
let wal = Wal::new(temp_dir.path()).unwrap();
let (exex_handle, _, _) =
ExExHandle::new("test_exex".to_string(), Head::default(), (), (), wal.handle());
let (exex_handle, _, _) = ExExHandle::new(
"test_exex".to_string(),
Head::default(),
(),
MockExecutorProvider::default(),
wal.handle(),
);
// Create a mock ExExManager and add the exex_handle to it
let mut exex_manager =
@ -778,8 +808,13 @@ mod tests {
let temp_dir = tempfile::tempdir().unwrap();
let wal = Wal::new(temp_dir.path()).unwrap();
let (exex_handle, _, _) =
ExExHandle::new("test_exex".to_string(), Head::default(), (), (), wal.handle());
let (exex_handle, _, _) = ExExHandle::new(
"test_exex".to_string(),
Head::default(),
(),
MockExecutorProvider::default(),
wal.handle(),
);
// Create a mock ExExManager and add the exex_handle to it
let max_capacity = 5;
@ -824,8 +859,13 @@ mod tests {
let provider_factory = create_test_provider_factory();
let (exex_handle, event_tx, mut _notification_rx) =
ExExHandle::new("test_exex".to_string(), Head::default(), (), (), wal.handle());
let (exex_handle, event_tx, mut _notification_rx) = ExExHandle::new(
"test_exex".to_string(),
Head::default(),
(),
MockExecutorProvider::default(),
wal.handle(),
);
// Check initial block height
assert!(exex_handle.finished_height.is_none());
@ -874,10 +914,20 @@ mod tests {
let provider_factory = create_test_provider_factory();
// Create two `ExExHandle` instances
let (exex_handle1, event_tx1, _) =
ExExHandle::new("test_exex1".to_string(), Head::default(), (), (), wal.handle());
let (exex_handle2, event_tx2, _) =
ExExHandle::new("test_exex2".to_string(), Head::default(), (), (), wal.handle());
let (exex_handle1, event_tx1, _) = ExExHandle::new(
"test_exex1".to_string(),
Head::default(),
(),
MockExecutorProvider::default(),
wal.handle(),
);
let (exex_handle2, event_tx2, _) = ExExHandle::new(
"test_exex2".to_string(),
Head::default(),
(),
MockExecutorProvider::default(),
wal.handle(),
);
let block1 = BlockNumHash::new(42, B256::random());
let block2 = BlockNumHash::new(10, B256::random());
@ -921,10 +971,20 @@ mod tests {
let provider_factory = create_test_provider_factory();
// Create two `ExExHandle` instances
let (exex_handle1, event_tx1, _) =
ExExHandle::new("test_exex1".to_string(), Head::default(), (), (), wal.handle());
let (exex_handle2, event_tx2, _) =
ExExHandle::new("test_exex2".to_string(), Head::default(), (), (), wal.handle());
let (exex_handle1, event_tx1, _) = ExExHandle::new(
"test_exex1".to_string(),
Head::default(),
(),
MockExecutorProvider::default(),
wal.handle(),
);
let (exex_handle2, event_tx2, _) = ExExHandle::new(
"test_exex2".to_string(),
Head::default(),
(),
MockExecutorProvider::default(),
wal.handle(),
);
// Assert that the initial block height is `None` for the first `ExExHandle`.
assert!(exex_handle1.finished_height.is_none());
@ -974,8 +1034,13 @@ mod tests {
let provider_factory = create_test_provider_factory();
let (exex_handle_1, _, _) =
ExExHandle::new("test_exex_1".to_string(), Head::default(), (), (), wal.handle());
let (exex_handle_1, _, _) = ExExHandle::new(
"test_exex_1".to_string(),
Head::default(),
(),
MockExecutorProvider::default(),
wal.handle(),
);
// Create an ExExManager with a small max capacity
let max_capacity = 2;

View File

@ -1,8 +1,11 @@
use crate::{BackfillJobFactory, ExExNotification, StreamBackfillJob, WalHandle};
use alloy_consensus::BlockHeader;
use futures::{Stream, StreamExt};
use reth_chainspec::Head;
use reth_evm::execute::BlockExecutorProvider;
use reth_exex_types::ExExHead;
use reth_node_api::NodePrimitives;
use reth_primitives::EthPrimitives;
use reth_provider::{BlockReader, Chain, HeaderProvider, StateProviderFactory};
use reth_tracing::tracing::debug;
use std::{
@ -17,14 +20,19 @@ use tokio::sync::mpsc::Receiver;
/// stream is configured with a head via [`ExExNotifications::set_with_head`] or
/// [`ExExNotifications::with_head`], it will run backfill jobs to catch up to the node head.
#[derive(Debug)]
pub struct ExExNotifications<P, E> {
pub struct ExExNotifications<P, E>
where
E: BlockExecutorProvider,
{
inner: ExExNotificationsInner<P, E>,
}
/// A trait, that represents a stream of [`ExExNotification`]s. The stream will emit notifications
/// for all blocks. If the stream is configured with a head via [`ExExNotifications::set_with_head`]
/// or [`ExExNotifications::with_head`], it will run backfill jobs to catch up to the node head.
pub trait ExExNotificationsStream: Stream<Item = eyre::Result<ExExNotification>> + Unpin {
pub trait ExExNotificationsStream<N: NodePrimitives = EthPrimitives>:
Stream<Item = eyre::Result<ExExNotification<N>>> + Unpin
{
/// Sets [`ExExNotificationsStream`] to a stream of [`ExExNotification`]s without a head.
///
/// It's a no-op if the stream has already been configured without a head.
@ -56,7 +64,10 @@ pub trait ExExNotificationsStream: Stream<Item = eyre::Result<ExExNotification>>
}
#[derive(Debug)]
enum ExExNotificationsInner<P, E> {
enum ExExNotificationsInner<P, E>
where
E: BlockExecutorProvider,
{
/// A stream of [`ExExNotification`]s. The stream will emit notifications for all blocks.
WithoutHead(ExExNotificationsWithoutHead<P, E>),
/// A stream of [`ExExNotification`]s. The stream will only emit notifications for blocks that
@ -67,14 +78,17 @@ enum ExExNotificationsInner<P, E> {
Invalid,
}
impl<P, E> ExExNotifications<P, E> {
impl<P, E> ExExNotifications<P, E>
where
E: BlockExecutorProvider,
{
/// Creates a new stream of [`ExExNotifications`] without a head.
pub const fn new(
node_head: Head,
provider: P,
executor: E,
notifications: Receiver<ExExNotification>,
wal_handle: WalHandle,
notifications: Receiver<ExExNotification<E::Primitives>>,
wal_handle: WalHandle<E::Primitives>,
) -> Self {
Self {
inner: ExExNotificationsInner::WithoutHead(ExExNotificationsWithoutHead::new(
@ -88,15 +102,13 @@ impl<P, E> ExExNotifications<P, E> {
}
}
impl<P, E> ExExNotificationsStream for ExExNotifications<P, E>
impl<P, E> ExExNotificationsStream<E::Primitives> for ExExNotifications<P, E>
where
P: BlockReader<Block = reth_primitives::Block>
+ HeaderProvider
+ StateProviderFactory
P: BlockReader + HeaderProvider + StateProviderFactory + Clone + Unpin + 'static,
E: BlockExecutorProvider<Primitives: NodePrimitives<Block = P::Block>>
+ Clone
+ Unpin
+ 'static,
E: BlockExecutorProvider + Clone + Unpin + 'static,
{
fn set_without_head(&mut self) {
let current = std::mem::replace(&mut self.inner, ExExNotificationsInner::Invalid);
@ -144,15 +156,13 @@ where
impl<P, E> Stream for ExExNotifications<P, E>
where
P: BlockReader<Block = reth_primitives::Block>
+ HeaderProvider
+ StateProviderFactory
P: BlockReader + HeaderProvider + StateProviderFactory + Clone + Unpin + 'static,
E: BlockExecutorProvider<Primitives: NodePrimitives<Block = P::Block>>
+ Clone
+ Unpin
+ 'static,
E: BlockExecutorProvider + Clone + Unpin + 'static,
{
type Item = eyre::Result<ExExNotification>;
type Item = eyre::Result<ExExNotification<E::Primitives>>;
fn poll_next(
self: std::pin::Pin<&mut Self>,
@ -169,15 +179,21 @@ where
}
/// A stream of [`ExExNotification`]s. The stream will emit notifications for all blocks.
pub struct ExExNotificationsWithoutHead<P, E> {
pub struct ExExNotificationsWithoutHead<P, E>
where
E: BlockExecutorProvider,
{
node_head: Head,
provider: P,
executor: E,
notifications: Receiver<ExExNotification>,
wal_handle: WalHandle,
notifications: Receiver<ExExNotification<E::Primitives>>,
wal_handle: WalHandle<E::Primitives>,
}
impl<P: Debug, E: Debug> Debug for ExExNotificationsWithoutHead<P, E> {
impl<P: Debug, E> Debug for ExExNotificationsWithoutHead<P, E>
where
E: Debug + BlockExecutorProvider,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ExExNotifications")
.field("provider", &self.provider)
@ -187,14 +203,17 @@ impl<P: Debug, E: Debug> Debug for ExExNotificationsWithoutHead<P, E> {
}
}
impl<P, E> ExExNotificationsWithoutHead<P, E> {
impl<P, E> ExExNotificationsWithoutHead<P, E>
where
E: BlockExecutorProvider,
{
/// Creates a new instance of [`ExExNotificationsWithoutHead`].
const fn new(
node_head: Head,
provider: P,
executor: E,
notifications: Receiver<ExExNotification>,
wal_handle: WalHandle,
notifications: Receiver<ExExNotification<E::Primitives>>,
wal_handle: WalHandle<E::Primitives>,
) -> Self {
Self { node_head, provider, executor, notifications, wal_handle }
}
@ -212,8 +231,11 @@ impl<P, E> ExExNotificationsWithoutHead<P, E> {
}
}
impl<P: Unpin, E: Unpin> Stream for ExExNotificationsWithoutHead<P, E> {
type Item = ExExNotification;
impl<P: Unpin, E> Stream for ExExNotificationsWithoutHead<P, E>
where
E: Unpin + BlockExecutorProvider,
{
type Item = ExExNotification<E::Primitives>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.get_mut().notifications.poll_recv(cx)
@ -229,12 +251,15 @@ impl<P: Unpin, E: Unpin> Stream for ExExNotificationsWithoutHead<P, E> {
/// `exex_head.number` of 10 indicates that the ExEx has processed up to block 10, and is ready to
/// process block 11.
#[derive(Debug)]
pub struct ExExNotificationsWithHead<P, E> {
pub struct ExExNotificationsWithHead<P, E>
where
E: BlockExecutorProvider,
{
node_head: Head,
provider: P,
executor: E,
notifications: Receiver<ExExNotification>,
wal_handle: WalHandle,
notifications: Receiver<ExExNotification<E::Primitives>>,
wal_handle: WalHandle<E::Primitives>,
exex_head: ExExHead,
/// If true, then we need to check if the ExEx head is on the canonical chain and if not,
/// revert its head.
@ -243,17 +268,20 @@ pub struct ExExNotificationsWithHead<P, E> {
/// the missing blocks.
pending_check_backfill: bool,
/// The backfill job to run before consuming any notifications.
backfill_job: Option<StreamBackfillJob<E, P, Chain>>,
backfill_job: Option<StreamBackfillJob<E, P, Chain<E::Primitives>>>,
}
impl<P, E> ExExNotificationsWithHead<P, E> {
impl<P, E> ExExNotificationsWithHead<P, E>
where
E: BlockExecutorProvider,
{
/// Creates a new [`ExExNotificationsWithHead`].
const fn new(
node_head: Head,
provider: P,
executor: E,
notifications: Receiver<ExExNotification>,
wal_handle: WalHandle,
notifications: Receiver<ExExNotification<E::Primitives>>,
wal_handle: WalHandle<E::Primitives>,
exex_head: ExExHead,
) -> Self {
Self {
@ -272,20 +300,18 @@ impl<P, E> ExExNotificationsWithHead<P, E> {
impl<P, E> ExExNotificationsWithHead<P, E>
where
P: BlockReader<Block = reth_primitives::Block>
+ HeaderProvider
+ StateProviderFactory
P: BlockReader + HeaderProvider + StateProviderFactory + Clone + Unpin + 'static,
E: BlockExecutorProvider<Primitives: NodePrimitives<Block = P::Block>>
+ Clone
+ Unpin
+ 'static,
E: BlockExecutorProvider + Clone + Unpin + 'static,
{
/// Checks if the ExEx head is on the canonical chain.
///
/// If the head block is not found in the database or it's ahead of the node head, it means
/// we're not on the canonical chain and we need to revert the notification with the ExEx
/// head block.
fn check_canonical(&mut self) -> eyre::Result<Option<ExExNotification>> {
fn check_canonical(&mut self) -> eyre::Result<Option<ExExNotification<E::Primitives>>> {
if self.provider.is_known(&self.exex_head.block.hash)? &&
self.exex_head.block.number <= self.node_head.number
{
@ -309,7 +335,7 @@ where
// Update the head block hash to the parent hash of the first committed block.
let committed_chain = notification.committed_chain().unwrap();
let new_exex_head =
(committed_chain.first().parent_hash, committed_chain.first().number - 1).into();
(committed_chain.first().parent_hash(), committed_chain.first().number() - 1).into();
debug!(target: "exex::notifications", old_exex_head = ?self.exex_head.block, new_exex_head = ?new_exex_head, "ExEx head updated");
self.exex_head.block = new_exex_head;
@ -354,15 +380,13 @@ where
impl<P, E> Stream for ExExNotificationsWithHead<P, E>
where
P: BlockReader<Block = reth_primitives::Block>
+ HeaderProvider
+ StateProviderFactory
P: BlockReader + HeaderProvider + StateProviderFactory + Clone + Unpin + 'static,
E: BlockExecutorProvider<Primitives: NodePrimitives<Block = P::Block>>
+ Clone
+ Unpin
+ 'static,
E: BlockExecutorProvider + Clone + Unpin + 'static,
{
type Item = eyre::Result<ExExNotification>;
type Item = eyre::Result<ExExNotification<E::Primitives>>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let this = self.get_mut();
@ -402,7 +426,7 @@ where
this.exex_head.block = committed_chain.tip().num_hash();
} else if let Some(reverted_chain) = notification.reverted_chain() {
let first_block = reverted_chain.first();
this.exex_head.block = (first_block.parent_hash, first_block.number - 1).into();
this.exex_head.block = (first_block.parent_hash(), first_block.number() - 1).into();
}
Poll::Ready(Some(Ok(notification)))

View File

@ -3,9 +3,11 @@ use std::{
collections::{BinaryHeap, HashSet},
};
use alloy_consensus::BlockHeader;
use alloy_eips::BlockNumHash;
use alloy_primitives::{map::FbHashMap, BlockNumber, B256};
use reth_exex_types::ExExNotification;
use reth_node_api::NodePrimitives;
/// The block cache of the WAL.
///
@ -91,16 +93,16 @@ impl BlockCache {
}
/// Inserts the blocks from the notification into the cache with the given file ID.
pub(super) fn insert_notification_blocks_with_file_id(
pub(super) fn insert_notification_blocks_with_file_id<N: NodePrimitives>(
&mut self,
file_id: u32,
notification: &ExExNotification,
notification: &ExExNotification<N>,
) {
let reverted_chain = notification.reverted_chain();
let committed_chain = notification.committed_chain();
let max_block =
reverted_chain.iter().chain(&committed_chain).map(|chain| chain.tip().number).max();
reverted_chain.iter().chain(&committed_chain).map(|chain| chain.tip().number()).max();
if let Some(max_block) = max_block {
self.notification_max_blocks.push(Reverse((max_block, file_id)));
}
@ -108,13 +110,13 @@ impl BlockCache {
if let Some(committed_chain) = &committed_chain {
for block in committed_chain.blocks().values() {
let cached_block = CachedBlock {
block: (block.number, block.hash()).into(),
parent_hash: block.parent_hash,
block: (block.number(), block.hash()).into(),
parent_hash: block.parent_hash(),
};
self.committed_blocks.insert(block.hash(), (file_id, cached_block));
}
self.highest_committed_block_height = Some(committed_chain.tip().number);
self.highest_committed_block_height = Some(committed_chain.tip().number());
}
}

View File

@ -3,6 +3,8 @@
mod cache;
pub use cache::BlockCache;
mod storage;
use reth_node_api::NodePrimitives;
use reth_primitives::EthPrimitives;
pub use storage::Storage;
mod metrics;
use metrics::Metrics;
@ -32,23 +34,26 @@ use reth_tracing::tracing::{debug, instrument};
/// 2. When the chain is finalized, call [`Wal::finalize`] to prevent the infinite growth of the
/// WAL.
#[derive(Debug, Clone)]
pub struct Wal {
inner: Arc<WalInner>,
pub struct Wal<N: NodePrimitives = EthPrimitives> {
inner: Arc<WalInner<N>>,
}
impl Wal {
impl<N> Wal<N>
where
N: NodePrimitives,
{
/// Creates a new instance of [`Wal`].
pub fn new(directory: impl AsRef<Path>) -> eyre::Result<Self> {
Ok(Self { inner: Arc::new(WalInner::new(directory)?) })
}
/// Returns a read-only handle to the WAL.
pub fn handle(&self) -> WalHandle {
pub fn handle(&self) -> WalHandle<N> {
WalHandle { wal: self.inner.clone() }
}
/// Commits the notification to WAL.
pub fn commit(&self, notification: &ExExNotification) -> eyre::Result<()> {
pub fn commit(&self, notification: &ExExNotification<N>) -> eyre::Result<()> {
self.inner.commit(notification)
}
@ -63,7 +68,7 @@ impl Wal {
/// Returns an iterator over all notifications in the WAL.
pub fn iter_notifications(
&self,
) -> eyre::Result<Box<dyn Iterator<Item = eyre::Result<ExExNotification>> + '_>> {
) -> eyre::Result<Box<dyn Iterator<Item = eyre::Result<ExExNotification<N>>> + '_>> {
self.inner.iter_notifications()
}
@ -75,16 +80,19 @@ impl Wal {
/// Inner type for the WAL.
#[derive(Debug)]
struct WalInner {
struct WalInner<N: NodePrimitives> {
next_file_id: AtomicU32,
/// The underlying WAL storage backed by a file.
storage: Storage,
storage: Storage<N>,
/// WAL block cache. See [`cache::BlockCache`] docs for more details.
block_cache: RwLock<BlockCache>,
metrics: Metrics,
}
impl WalInner {
impl<N> WalInner<N>
where
N: NodePrimitives,
{
fn new(directory: impl AsRef<Path>) -> eyre::Result<Self> {
let mut wal = Self {
next_file_id: AtomicU32::new(0),
@ -137,7 +145,7 @@ impl WalInner {
reverted_block_range = ?notification.reverted_chain().as_ref().map(|chain| chain.range()),
committed_block_range = ?notification.committed_chain().as_ref().map(|chain| chain.range())
))]
fn commit(&self, notification: &ExExNotification) -> eyre::Result<()> {
fn commit(&self, notification: &ExExNotification<N>) -> eyre::Result<()> {
let mut block_cache = self.block_cache.write();
let file_id = self.next_file_id.fetch_add(1, Ordering::Relaxed);
@ -187,7 +195,7 @@ impl WalInner {
/// Returns an iterator over all notifications in the WAL.
fn iter_notifications(
&self,
) -> eyre::Result<Box<dyn Iterator<Item = eyre::Result<ExExNotification>> + '_>> {
) -> eyre::Result<Box<dyn Iterator<Item = eyre::Result<ExExNotification<N>>> + '_>> {
let Some(range) = self.storage.files_range()? else {
return Ok(Box::new(std::iter::empty()))
};
@ -198,16 +206,19 @@ impl WalInner {
/// A read-only handle to the WAL that can be shared.
#[derive(Debug)]
pub struct WalHandle {
wal: Arc<WalInner>,
pub struct WalHandle<N: NodePrimitives> {
wal: Arc<WalInner<N>>,
}
impl WalHandle {
impl<N> WalHandle<N>
where
N: NodePrimitives,
{
/// Returns the notification for the given committed block hash if it exists.
pub fn get_committed_notification_by_block_hash(
&self,
block_hash: &B256,
) -> eyre::Result<Option<ExExNotification>> {
) -> eyre::Result<Option<ExExNotification<N>>> {
let Some(file_id) = self.wal.block_cache().get_file_id_by_committed_block_hash(block_hash)
else {
return Ok(None)

View File

@ -6,6 +6,8 @@ use std::{
use eyre::OptionExt;
use reth_exex_types::ExExNotification;
use reth_node_api::NodePrimitives;
use reth_primitives::EthPrimitives;
use reth_tracing::tracing::debug;
use tracing::instrument;
@ -16,18 +18,22 @@ static FILE_EXTENSION: &str = "wal";
/// Each notification is represented by a single file that contains a MessagePack-encoded
/// notification.
#[derive(Debug, Clone)]
pub struct Storage {
pub struct Storage<N: NodePrimitives = EthPrimitives> {
/// The path to the WAL file.
path: PathBuf,
_pd: std::marker::PhantomData<N>,
}
impl Storage {
impl<N> Storage<N>
where
N: NodePrimitives,
{
/// Creates a new instance of [`Storage`] backed by the file at the given path and creates
/// it doesn't exist.
pub(super) fn new(path: impl AsRef<Path>) -> eyre::Result<Self> {
reth_fs_util::create_dir_all(&path)?;
Ok(Self { path: path.as_ref().to_path_buf() })
Ok(Self { path: path.as_ref().to_path_buf(), _pd: std::marker::PhantomData })
}
fn file_path(&self, id: u32) -> PathBuf {
@ -110,7 +116,7 @@ impl Storage {
pub(super) fn iter_notifications(
&self,
range: RangeInclusive<u32>,
) -> impl Iterator<Item = eyre::Result<(u32, u64, ExExNotification)>> + '_ {
) -> impl Iterator<Item = eyre::Result<(u32, u64, ExExNotification<N>)>> + '_ {
range.map(move |id| {
let (notification, size) =
self.read_notification(id)?.ok_or_eyre("notification {id} not found")?;
@ -124,7 +130,7 @@ impl Storage {
pub(super) fn read_notification(
&self,
file_id: u32,
) -> eyre::Result<Option<(ExExNotification, u64)>> {
) -> eyre::Result<Option<(ExExNotification<N>, u64)>> {
let file_path = self.file_path(file_id);
debug!(target: "exex::wal::storage", ?file_path, "Reading notification from WAL");
@ -136,7 +142,7 @@ impl Storage {
let size = file.metadata()?.len();
// Deserialize using the bincode- and msgpack-compatible serde wrapper
let notification: reth_exex_types::serde_bincode_compat::ExExNotification<'_> =
let notification: reth_exex_types::serde_bincode_compat::ExExNotification<'_, N> =
rmp_serde::decode::from_read(&mut file).map_err(|err| {
eyre::eyre!("failed to decode notification from {file_path:?}: {err:?}")
})?;
@ -153,14 +159,14 @@ impl Storage {
pub(super) fn write_notification(
&self,
file_id: u32,
notification: &ExExNotification,
notification: &ExExNotification<N>,
) -> eyre::Result<u64> {
let file_path = self.file_path(file_id);
debug!(target: "exex::wal::storage", ?file_path, "Writing notification to WAL");
// Serialize using the bincode- and msgpack-compatible serde wrapper
let notification =
reth_exex_types::serde_bincode_compat::ExExNotification::from(notification);
reth_exex_types::serde_bincode_compat::ExExNotification::<N>::from(notification);
reth_fs_util::atomic_write_file(&file_path, |file| {
rmp_serde::encode::write(file, &notification)
@ -186,7 +192,7 @@ mod tests {
let mut rng = generators::rng();
let temp_dir = tempfile::tempdir()?;
let storage = Storage::new(&temp_dir)?;
let storage: Storage = Storage::new(&temp_dir)?;
let old_block = random_block(&mut rng, 0, Default::default())
.seal_with_senders()
@ -215,7 +221,7 @@ mod tests {
#[test]
fn test_files_range() -> eyre::Result<()> {
let temp_dir = tempfile::tempdir()?;
let storage = Storage::new(&temp_dir)?;
let storage: Storage = Storage::new(&temp_dir)?;
// Create WAL files
File::create(storage.file_path(1))?;

View File

@ -80,7 +80,7 @@ pub struct TestExecutorBuilder;
impl<Node> ExecutorBuilder<Node> for TestExecutorBuilder
where
Node: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec>>,
Node: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec, Primitives = EthPrimitives>>,
{
type EVM = EthEvmConfig;
type Executor = MockExecutorProvider;

View File

@ -7,30 +7,30 @@ use reth_primitives_traits::NodePrimitives;
/// Notifications sent to an `ExEx`.
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ExExNotification<P: NodePrimitives = reth_chain_state::EthPrimitives> {
pub enum ExExNotification<N: NodePrimitives = reth_chain_state::EthPrimitives> {
/// Chain got committed without a reorg, and only the new chain is returned.
ChainCommitted {
/// The new chain after commit.
new: Arc<Chain<P>>,
new: Arc<Chain<N>>,
},
/// Chain got reorged, and both the old and the new chains are returned.
ChainReorged {
/// The old chain before reorg.
old: Arc<Chain<P>>,
old: Arc<Chain<N>>,
/// The new chain after reorg.
new: Arc<Chain<P>>,
new: Arc<Chain<N>>,
},
/// Chain got reverted, and only the old chain is returned.
ChainReverted {
/// The old chain before reversion.
old: Arc<Chain<P>>,
old: Arc<Chain<N>>,
},
}
impl ExExNotification {
impl<N: NodePrimitives> ExExNotification<N> {
/// Returns the committed chain from the [`Self::ChainCommitted`] and [`Self::ChainReorged`]
/// variants, if any.
pub fn committed_chain(&self) -> Option<Arc<Chain>> {
pub fn committed_chain(&self) -> Option<Arc<Chain<N>>> {
match self {
Self::ChainCommitted { new } | Self::ChainReorged { old: _, new } => Some(new.clone()),
Self::ChainReverted { .. } => None,
@ -39,7 +39,7 @@ impl ExExNotification {
/// Returns the reverted chain from the [`Self::ChainReorged`] and [`Self::ChainReverted`]
/// variants, if any.
pub fn reverted_chain(&self) -> Option<Arc<Chain>> {
pub fn reverted_chain(&self) -> Option<Arc<Chain<N>>> {
match self {
Self::ChainReorged { old, new: _ } | Self::ChainReverted { old } => Some(old.clone()),
Self::ChainCommitted { .. } => None,

View File

@ -53,7 +53,7 @@ pub trait FullNodeComponents: FullNodeTypes + Clone + 'static {
type Evm: ConfigureEvm<Header = Header>;
/// The type that knows how to execute blocks.
type Executor: BlockExecutorProvider;
type Executor: BlockExecutorProvider<Primitives = <Self::Types as NodeTypes>::Primitives>;
/// The consensus type of the node.
type Consensus: Consensus + Clone + Unpin + 'static;

View File

@ -10,7 +10,7 @@ use crate::{
use alloy_consensus::Header;
use reth_consensus::Consensus;
use reth_evm::execute::BlockExecutorProvider;
use reth_node_api::NodeTypesWithEngine;
use reth_node_api::{NodeTypes, NodeTypesWithEngine};
use reth_payload_builder::PayloadBuilderHandle;
use reth_transaction_pool::TransactionPool;
use std::{future::Future, marker::PhantomData};
@ -377,7 +377,7 @@ where
Fut: Future<Output = eyre::Result<Components<Node, Pool, EVM, Executor, Cons>>> + Send,
Pool: TransactionPool + Unpin + 'static,
EVM: ConfigureEvm<Header = Header>,
Executor: BlockExecutorProvider,
Executor: BlockExecutorProvider<Primitives = <Node::Types as NodeTypes>::Primitives>,
Cons: Consensus + Clone + Unpin + 'static,
{
type Components = Components<Node, Pool, EVM, Executor, Cons>;

View File

@ -13,7 +13,9 @@ pub trait ExecutorBuilder<Node: FullNodeTypes>: Send {
type EVM: ConfigureEvm<Header = Header>;
/// The type that knows how to execute blocks.
type Executor: BlockExecutorProvider;
type Executor: BlockExecutorProvider<
Primitives = <Node::Types as reth_node_api::NodeTypes>::Primitives,
>;
/// Creates the EVM config.
fn build_evm(
@ -26,7 +28,8 @@ impl<Node, F, Fut, EVM, Executor> ExecutorBuilder<Node> for F
where
Node: FullNodeTypes,
EVM: ConfigureEvm<Header = Header>,
Executor: BlockExecutorProvider,
Executor:
BlockExecutorProvider<Primitives = <Node::Types as reth_node_api::NodeTypes>::Primitives>,
F: FnOnce(&BuilderContext<Node>) -> Fut + Send,
Fut: Future<Output = eyre::Result<(EVM, Executor)>> + Send,
{

View File

@ -27,7 +27,7 @@ use reth_consensus::Consensus;
use reth_evm::execute::BlockExecutorProvider;
use reth_network::NetworkHandle;
use reth_network_api::FullNetwork;
use reth_node_api::NodeTypesWithEngine;
use reth_node_api::{NodeTypes, NodeTypesWithEngine};
use reth_payload_builder::PayloadBuilderHandle;
use reth_transaction_pool::TransactionPool;
@ -44,7 +44,7 @@ pub trait NodeComponents<T: FullNodeTypes>: Clone + Unpin + Send + Sync + 'stati
type Evm: ConfigureEvm<Header = Header>;
/// The type that knows how to execute blocks.
type Executor: BlockExecutorProvider;
type Executor: BlockExecutorProvider<Primitives = <T::Types as NodeTypes>::Primitives>;
/// The consensus type of the node.
type Consensus: Consensus + Clone + Unpin + 'static;
@ -99,7 +99,7 @@ where
Node: FullNodeTypes,
Pool: TransactionPool + Unpin + 'static,
EVM: ConfigureEvm<Header = Header>,
Executor: BlockExecutorProvider,
Executor: BlockExecutorProvider<Primitives = <Node::Types as NodeTypes>::Primitives>,
Cons: Consensus + Clone + Unpin + 'static,
{
type Pool = Pool;

View File

@ -35,12 +35,12 @@ pub fn build_networked_pipeline<N, Client, Executor>(
max_block: Option<BlockNumber>,
static_file_producer: StaticFileProducer<ProviderFactory<N>>,
executor: Executor,
exex_manager_handle: ExExManagerHandle,
exex_manager_handle: ExExManagerHandle<N::Primitives>,
) -> eyre::Result<Pipeline<N>>
where
N: ProviderNodeTypes,
Client: EthBlockClient + 'static,
Executor: BlockExecutorProvider,
Executor: BlockExecutorProvider<Primitives = N::Primitives>,
N::Primitives: FullNodePrimitives<
Block = reth_primitives::Block,
BlockBody = reth_primitives::BlockBody,
@ -86,13 +86,13 @@ pub fn build_pipeline<N, H, B, Executor>(
prune_config: Option<PruneConfig>,
static_file_producer: StaticFileProducer<ProviderFactory<N>>,
executor: Executor,
exex_manager_handle: ExExManagerHandle,
exex_manager_handle: ExExManagerHandle<N::Primitives>,
) -> eyre::Result<Pipeline<N>>
where
N: ProviderNodeTypes,
H: HeaderDownloader<Header = alloy_consensus::Header> + 'static,
B: BodyDownloader<Body = BodyTy<N>> + 'static,
Executor: BlockExecutorProvider,
Executor: BlockExecutorProvider<Primitives = N::Primitives>,
N::Primitives: FullNodePrimitives<
Block = reth_primitives::Block,
BlockBody = reth_primitives::BlockBody,

View File

@ -32,6 +32,7 @@ alloy-consensus.workspace = true
reth-optimism-consensus.workspace = true
reth-optimism-chainspec.workspace = true
reth-optimism-forks.workspace = true
reth-optimism-primitives.workspace = true
# revm
revm.workspace = true

View File

@ -20,6 +20,7 @@ use reth_evm::{
use reth_optimism_chainspec::OpChainSpec;
use reth_optimism_consensus::validate_block_post_execution;
use reth_optimism_forks::OpHardfork;
use reth_optimism_primitives::OpPrimitives;
use reth_primitives::{BlockWithSenders, Receipt, TxType};
use reth_revm::{Database, State};
use revm_primitives::{db::DatabaseCommit, EnvWithHandlerCfg, ResultAndState, U256};
@ -53,6 +54,7 @@ where
EvmConfig:
Clone + Unpin + Sync + Send + 'static + ConfigureEvm<Header = alloy_consensus::Header>,
{
type Primitives = OpPrimitives;
type Strategy<DB: Database<Error: Into<ProviderError> + Display>> =
OpExecutionStrategy<DB, EvmConfig>;
@ -109,11 +111,13 @@ where
}
}
impl<DB, EvmConfig> BlockExecutionStrategy<DB> for OpExecutionStrategy<DB, EvmConfig>
impl<DB, EvmConfig> BlockExecutionStrategy for OpExecutionStrategy<DB, EvmConfig>
where
DB: Database<Error: Into<ProviderError> + Display>,
EvmConfig: ConfigureEvm<Header = alloy_consensus::Header>,
{
type DB = DB;
type Primitives = OpPrimitives;
type Error = BlockExecutionError;
fn init(&mut self, tx_env_overrides: Box<dyn TxEnvOverrides>) {

View File

@ -277,7 +277,7 @@ pub struct OpExecutorBuilder;
impl<Node> ExecutorBuilder<Node> for OpExecutorBuilder
where
Node: FullNodeTypes<Types: NodeTypes<ChainSpec = OpChainSpec>>,
Node: FullNodeTypes<Types: NodeTypes<ChainSpec = OpChainSpec, Primitives = OpPrimitives>>,
{
type EVM = OpEvmConfig;
type Executor = BasicBlockExecutorProvider<OpExecutionStrategyFactory>;

View File

@ -14,7 +14,7 @@ use revm::db::states::bundle_state::BundleRetention;
/// - recording receipts during execution of multiple blocks.
/// - pruning receipts according to the pruning configuration.
/// - batch range if known
#[derive(Debug, Default)]
#[derive(Debug)]
pub struct BlockBatchRecord<T = reth_primitives::Receipt> {
/// Pruning configuration.
prune_modes: PruneModes,
@ -43,6 +43,19 @@ pub struct BlockBatchRecord<T = reth_primitives::Receipt> {
tip: Option<BlockNumber>,
}
impl<T> Default for BlockBatchRecord<T> {
fn default() -> Self {
Self {
prune_modes: Default::default(),
receipts: Default::default(),
requests: Default::default(),
pruning_address_filter: Default::default(),
first_block: Default::default(),
tip: Default::default(),
}
}
}
impl<T> BlockBatchRecord<T> {
/// Create a new receipts recorder with the given pruning configuration.
pub fn new(prune_modes: PruneModes) -> Self
@ -83,10 +96,7 @@ impl<T> BlockBatchRecord<T> {
}
/// Returns all recorded receipts.
pub fn take_receipts(&mut self) -> Receipts<T>
where
T: Default,
{
pub fn take_receipts(&mut self) -> Receipts<T> {
core::mem::take(&mut self.receipts)
}

View File

@ -48,7 +48,7 @@
//! Events:
//! CanonStateSubscriptions<Primitives = reth_primitives::EthPrimitives> + Clone + 'static,
//! EvmConfig: ConfigureEvm<Header = Header>,
//! BlockExecutor: BlockExecutorProvider,
//! BlockExecutor: BlockExecutorProvider<Primitives = Events::Primitives>,
//! Consensus: reth_consensus::Consensus + Clone + 'static,
//! {
//! // configure the rpc module per transport
@ -130,7 +130,7 @@
//! EngineApi: EngineApiServer<EngineT>,
//! EngineT: EngineTypes,
//! EvmConfig: ConfigureEvm<Header = Header>,
//! BlockExecutor: BlockExecutorProvider,
//! BlockExecutor: BlockExecutorProvider<Primitives = Events::Primitives>,
//! Consensus: reth_consensus::Consensus + Clone + 'static,
//! {
//! // configure the rpc module per transport
@ -198,7 +198,7 @@ use reth_consensus::Consensus;
use reth_engine_primitives::EngineTypes;
use reth_evm::{execute::BlockExecutorProvider, ConfigureEvm};
use reth_network_api::{noop::NoopNetwork, NetworkInfo, Peers};
use reth_primitives::EthPrimitives;
use reth_primitives::{EthPrimitives, NodePrimitives};
use reth_provider::{
AccountReader, BlockReader, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader,
EvmEnvProvider, FullRpcProvider, ReceiptProvider, StateProviderFactory,
@ -278,7 +278,12 @@ where
Events: CanonStateSubscriptions<Primitives = EthPrimitives> + Clone + 'static,
EvmConfig: ConfigureEvm<Header = alloy_consensus::Header>,
EthApi: FullEthApiServer,
BlockExecutor: BlockExecutorProvider,
BlockExecutor: BlockExecutorProvider<
Primitives: NodePrimitives<
Block = reth_primitives::Block,
Receipt = reth_primitives::Receipt,
>,
>,
{
let module_config = module_config.into();
server_config
@ -630,7 +635,12 @@ where
Tasks: TaskSpawner + Clone + 'static,
Events: CanonStateSubscriptions<Primitives = EthPrimitives> + Clone + 'static,
EvmConfig: ConfigureEvm<Header = Header>,
BlockExecutor: BlockExecutorProvider,
BlockExecutor: BlockExecutorProvider<
Primitives: NodePrimitives<
Block = reth_primitives::Block,
Receipt = reth_primitives::Receipt,
>,
>,
Consensus: reth_consensus::Consensus + Clone + 'static,
{
/// Configures all [`RpcModule`]s specific to the given [`TransportRpcModuleConfig`] which can
@ -1104,7 +1114,8 @@ where
RpcBlock<EthApi::NetworkTypes>,
RpcReceipt<EthApi::NetworkTypes>,
> + EthApiTypes,
BlockExecutor: BlockExecutorProvider,
BlockExecutor:
BlockExecutorProvider<Primitives: NodePrimitives<Block = reth_primitives::Block>>,
{
/// Register Eth Namespace
///
@ -1250,7 +1261,8 @@ where
pub fn debug_api(&self) -> DebugApi<Provider, EthApi, BlockExecutor>
where
EthApi: EthApiSpec + EthTransactions + TraceExt,
BlockExecutor: BlockExecutorProvider,
BlockExecutor:
BlockExecutorProvider<Primitives: NodePrimitives<Block = reth_primitives::Block>>,
{
DebugApi::new(
self.provider.clone(),
@ -1306,7 +1318,12 @@ where
Tasks: TaskSpawner + Clone + 'static,
Events: CanonStateSubscriptions<Primitives = EthPrimitives> + Clone + 'static,
EthApi: FullEthApiServer,
BlockExecutor: BlockExecutorProvider,
BlockExecutor: BlockExecutorProvider<
Primitives: NodePrimitives<
Block = reth_primitives::Block,
Receipt = reth_primitives::Receipt,
>,
>,
Consensus: reth_consensus::Consensus + Clone + 'static,
{
/// Configures the auth module that includes the

View File

@ -18,17 +18,17 @@ use reth_evm::{
execute::{BlockExecutorProvider, Executor},
ConfigureEvmEnv,
};
use reth_primitives::{Block, BlockExt, SealedBlockWithSenders};
use reth_primitives::{Block, BlockExt, NodePrimitives, SealedBlockWithSenders};
use reth_primitives_traits::SignedTransaction;
use reth_provider::{
BlockReaderIdExt, ChainSpecProvider, HeaderProvider, StateProofProvider, StateProviderFactory,
TransactionVariant,
BlockReader, BlockReaderIdExt, ChainSpecProvider, HeaderProvider, StateProofProvider,
StateProviderFactory, TransactionVariant,
};
use reth_revm::{database::StateProviderDatabase, witness::ExecutionWitnessRecord};
use reth_rpc_api::DebugApiServer;
use reth_rpc_eth_api::{
helpers::{EthApiSpec, EthTransactions, TraceExt},
EthApiTypes, FromEthApiError,
EthApiTypes, FromEthApiError, RpcNodeCore,
};
use reth_rpc_eth_types::{EthApiError, StateCacheDb};
use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
@ -81,7 +81,9 @@ where
+ StateProviderFactory
+ 'static,
Eth: EthApiTypes + TraceExt + 'static,
BlockExecutor: BlockExecutorProvider,
BlockExecutor: BlockExecutorProvider<
Primitives: NodePrimitives<Block = <<Eth as RpcNodeCore>::Provider as BlockReader>::Block>,
>,
{
/// Acquires a permit to execute a tracing call.
async fn acquire_trace_permit(&self) -> Result<OwnedSemaphorePermit, AcquireError> {
@ -800,7 +802,9 @@ where
+ StateProviderFactory
+ 'static,
Eth: EthApiSpec + EthTransactions + TraceExt + 'static,
BlockExecutor: BlockExecutorProvider,
BlockExecutor: BlockExecutorProvider<
Primitives: NodePrimitives<Block = <<Eth as RpcNodeCore>::Provider as BlockReader>::Block>,
>,
{
/// Handler for `debug_getRawHeader`
async fn raw_header(&self, block_id: BlockId) -> RpcResult<Bytes> {

View File

@ -1,4 +1,4 @@
use alloy_consensus::{BlobTransactionValidationError, EnvKzgSettings, Transaction};
use alloy_consensus::{BlobTransactionValidationError, EnvKzgSettings, Transaction, TxReceipt};
use alloy_eips::eip4844::kzg_to_versioned_hash;
use alloy_rpc_types_beacon::relay::{
BidTrace, BuilderBlockValidationRequest, BuilderBlockValidationRequestV2,
@ -15,7 +15,7 @@ use reth_errors::{BlockExecutionError, ConsensusError, ProviderError};
use reth_ethereum_consensus::GAS_LIMIT_BOUND_DIVISOR;
use reth_evm::execute::{BlockExecutorProvider, Executor};
use reth_payload_validator::ExecutionPayloadValidator;
use reth_primitives::{Block, GotExpected, Receipt, SealedBlockWithSenders, SealedHeader};
use reth_primitives::{Block, GotExpected, NodePrimitives, SealedBlockWithSenders, SealedHeader};
use reth_provider::{
AccountReader, BlockExecutionInput, BlockExecutionOutput, BlockReaderIdExt, HeaderProvider,
StateProviderFactory, WithdrawalsProvider,
@ -95,7 +95,12 @@ where
+ AccountReader
+ WithdrawalsProvider
+ 'static,
E: BlockExecutorProvider,
E: BlockExecutorProvider<
Primitives: NodePrimitives<
Block = reth_primitives::Block,
Receipt = reth_primitives::Receipt,
>,
>,
{
/// Validates the given block and a [`BidTrace`] against it.
pub async fn validate_message_against_block(
@ -258,7 +263,7 @@ where
fn ensure_payment(
&self,
block: &Block,
output: &BlockExecutionOutput<Receipt>,
output: &BlockExecutionOutput<<E::Primitives as NodePrimitives>::Receipt>,
message: &BidTrace,
) -> Result<(), ValidationApiError> {
let (mut balance_before, balance_after) = if let Some(acc) =
@ -292,7 +297,7 @@ where
.zip(block.body.transactions.last())
.ok_or(ValidationApiError::ProposerPayment)?;
if !receipt.success {
if !receipt.status() {
return Err(ValidationApiError::ProposerPayment)
}
@ -407,7 +412,12 @@ where
+ WithdrawalsProvider
+ Clone
+ 'static,
E: BlockExecutorProvider,
E: BlockExecutorProvider<
Primitives: NodePrimitives<
Block = reth_primitives::Block,
Receipt = reth_primitives::Receipt,
>,
>,
{
async fn validate_builder_submission_v1(
&self,

View File

@ -20,8 +20,9 @@
//! # use reth_static_file::StaticFileProducer;
//! # use reth_config::config::StageConfig;
//! # use reth_evm::execute::BlockExecutorProvider;
//! # use reth_primitives::EthPrimitives;
//!
//! # fn create(exec: impl BlockExecutorProvider) {
//! # fn create(exec: impl BlockExecutorProvider<Primitives = EthPrimitives>) {
//!
//! let provider_factory = create_test_provider_factory();
//! let static_file_producer =

View File

@ -67,7 +67,10 @@ use super::missing_static_data_error;
/// values to [`tables::PlainStorageState`]
// false positive, we cannot derive it if !DB: Debug.
#[allow(missing_debug_implementations)]
pub struct ExecutionStage<E> {
pub struct ExecutionStage<E>
where
E: BlockExecutorProvider,
{
/// The stage's internal block executor
executor_provider: E,
/// The commit thresholds of the execution stage.
@ -82,25 +85,28 @@ pub struct ExecutionStage<E> {
/// Input for the post execute commit hook.
/// Set after every [`ExecutionStage::execute`] and cleared after
/// [`ExecutionStage::post_execute_commit`].
post_execute_commit_input: Option<Chain>,
post_execute_commit_input: Option<Chain<E::Primitives>>,
/// Input for the post unwind commit hook.
/// Set after every [`ExecutionStage::unwind`] and cleared after
/// [`ExecutionStage::post_unwind_commit`].
post_unwind_commit_input: Option<Chain>,
post_unwind_commit_input: Option<Chain<E::Primitives>>,
/// Handle to communicate with `ExEx` manager.
exex_manager_handle: ExExManagerHandle,
exex_manager_handle: ExExManagerHandle<E::Primitives>,
/// Executor metrics.
metrics: ExecutorMetrics,
}
impl<E> ExecutionStage<E> {
impl<E> ExecutionStage<E>
where
E: BlockExecutorProvider,
{
/// Create new execution stage with specified config.
pub fn new(
executor_provider: E,
thresholds: ExecutionStageThresholds,
external_clean_threshold: u64,
prune_modes: PruneModes,
exex_manager_handle: ExExManagerHandle,
exex_manager_handle: ExExManagerHandle<E::Primitives>,
) -> Self {
Self {
external_clean_threshold,
@ -257,13 +263,13 @@ impl<E> ExecutionStage<E> {
impl<E, Provider> Stage<Provider> for ExecutionStage<E>
where
E: BlockExecutorProvider,
E: BlockExecutorProvider<Primitives: NodePrimitives<BlockHeader = alloy_consensus::Header>>,
Provider: DBProvider
+ BlockReader<Block = reth_primitives::Block>
+ BlockReader<Block = <E::Primitives as NodePrimitives>::Block>
+ StaticFileProviderFactory
+ StatsReader
+ BlockHashReader
+ StateWriter<Receipt = reth_primitives::Receipt>
+ StateWriter<Receipt = <E::Primitives as NodePrimitives>::Receipt>
+ StateCommitmentProvider,
{
/// Return the id of the stage
@ -373,7 +379,7 @@ where
}
stage_progress = block_number;
stage_checkpoint.progress.processed += block.gas_used();
stage_checkpoint.progress.processed += block.header().gas_used();
// If we have ExExes we need to save the block in memory for later
if self.exex_manager_handle.has_exexs() {
@ -512,7 +518,8 @@ where
stage_checkpoint.progress.processed -= provider
.block_by_number(block_number)?
.ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?
.gas_used;
.header()
.gas_used();
}
}
let checkpoint = if let Some(stage_checkpoint) = stage_checkpoint {

View File

@ -26,7 +26,7 @@ use reth_evm::execute::{
};
use reth_evm_ethereum::EthEvmConfig;
use reth_node_ethereum::{node::EthereumAddOns, BasicBlockExecutorProvider, EthereumNode};
use reth_primitives::{BlockWithSenders, Receipt};
use reth_primitives::{BlockWithSenders, EthPrimitives, Receipt};
use std::{fmt::Display, sync::Arc};
pub const SYSTEM_ADDRESS: Address = address!("fffffffffffffffffffffffffffffffffffffffe");
@ -59,7 +59,7 @@ pub struct CustomExecutorBuilder;
impl<Types, Node> ExecutorBuilder<Node> for CustomExecutorBuilder
where
Types: NodeTypesWithEngine<ChainSpec = ChainSpec>,
Types: NodeTypesWithEngine<ChainSpec = ChainSpec, Primitives = EthPrimitives>,
Node: FullNodeTypes<Types = Types>,
{
type EVM = EthEvmConfig;
@ -88,6 +88,7 @@ pub struct CustomExecutorStrategyFactory {
}
impl BlockExecutionStrategyFactory for CustomExecutorStrategyFactory {
type Primitives = EthPrimitives;
type Strategy<DB: Database<Error: Into<ProviderError> + Display>> = CustomExecutorStrategy<DB>;
fn create_strategy<DB>(&self, db: DB) -> Self::Strategy<DB>
@ -135,10 +136,12 @@ where
}
}
impl<DB> BlockExecutionStrategy<DB> for CustomExecutorStrategy<DB>
impl<DB> BlockExecutionStrategy for CustomExecutorStrategy<DB>
where
DB: Database<Error: Into<ProviderError> + Display>,
{
type DB = DB;
type Primitives = EthPrimitives;
type Error = BlockExecutionError;
fn apply_pre_execution_changes(

View File

@ -153,7 +153,7 @@ pub struct MyExecutorBuilder;
impl<Node> ExecutorBuilder<Node> for MyExecutorBuilder
where
Node: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec>>,
Node: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec, Primitives = EthPrimitives>>,
{
type EVM = MyEvmConfig;
type Executor = BasicBlockExecutorProvider<EthExecutionStrategyFactory<Self::EVM>>;

View File

@ -28,7 +28,7 @@ use reth_node_ethereum::{
node::EthereumAddOns, BasicBlockExecutorProvider, EthEvmConfig, EthExecutionStrategyFactory,
EthereumNode,
};
use reth_primitives::TransactionSigned;
use reth_primitives::{EthPrimitives, TransactionSigned};
use reth_tracing::{RethTracer, Tracer};
use schnellru::{ByLength, LruMap};
use std::{collections::HashMap, convert::Infallible, sync::Arc};
@ -226,7 +226,7 @@ pub struct MyExecutorBuilder {
impl<Node> ExecutorBuilder<Node> for MyExecutorBuilder
where
Node: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec>>,
Node: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec, Primitives = EthPrimitives>>,
{
type EVM = MyEvmConfig;
type Executor = BasicBlockExecutorProvider<EthExecutionStrategyFactory<Self::EVM>>;