chore: remove auto-seal consensus (#12385)

This commit is contained in:
Arsenii Kulikov
2024-11-08 01:29:49 +04:00
committed by GitHub
parent 29da7d744a
commit d19032fca1
18 changed files with 11 additions and 1388 deletions

View File

@ -11,7 +11,6 @@ exclude_crates=(
# The following are not working yet, but known to be fixable
reth-exex-types # https://github.com/paradigmxyz/reth/issues/9946
# The following require investigation if they can be fixed
reth-auto-seal-consensus
reth-basic-payload-builder
reth-beacon-consensus
reth-bench

34
Cargo.lock generated
View File

@ -6385,37 +6385,6 @@ dependencies = [
"tracing",
]
[[package]]
name = "reth-auto-seal-consensus"
version = "1.1.1"
dependencies = [
"alloy-eips",
"alloy-primitives",
"alloy-rpc-types-engine",
"futures-util",
"reth-beacon-consensus",
"reth-chainspec",
"reth-consensus",
"reth-engine-primitives",
"reth-evm",
"reth-execution-errors",
"reth-execution-types",
"reth-network-p2p",
"reth-network-peers",
"reth-optimism-consensus",
"reth-primitives",
"reth-provider",
"reth-revm",
"reth-stages-api",
"reth-tokio-util",
"reth-transaction-pool",
"reth-trie",
"revm-primitives",
"tokio",
"tokio-stream",
"tracing",
]
[[package]]
name = "reth-basic-payload-builder"
version = "1.1.1"
@ -7924,7 +7893,6 @@ dependencies = [
"futures",
"jsonrpsee",
"rayon",
"reth-auto-seal-consensus",
"reth-beacon-consensus",
"reth-blockchain-tree",
"reth-chain-state",
@ -8043,7 +8011,6 @@ dependencies = [
"futures",
"rand 0.8.5",
"reth",
"reth-auto-seal-consensus",
"reth-basic-payload-builder",
"reth-beacon-consensus",
"reth-chainspec",
@ -8266,7 +8233,6 @@ dependencies = [
"op-alloy-rpc-types-engine",
"parking_lot",
"reth",
"reth-auto-seal-consensus",
"reth-basic-payload-builder",
"reth-beacon-consensus",
"reth-chainspec",

View File

@ -20,7 +20,6 @@ members = [
"crates/cli/runner/",
"crates/cli/util/",
"crates/config/",
"crates/consensus/auto-seal/",
"crates/consensus/beacon/",
"crates/consensus/common/",
"crates/consensus/consensus/",
@ -299,7 +298,6 @@ overflow-checks = true
# reth
op-reth = { path = "crates/optimism/bin" }
reth = { path = "bin/reth" }
reth-auto-seal-consensus = { path = "crates/consensus/auto-seal" }
reth-basic-payload-builder = { path = "crates/payload/basic" }
reth-beacon-consensus = { path = "crates/consensus/beacon" }
reth-bench = { path = "bin/reth-bench" }

View File

@ -1,57 +0,0 @@
[package]
name = "reth-auto-seal-consensus"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
description = "A consensus impl for local testing purposes"
[lints]
workspace = true
[dependencies]
# reth
reth-chainspec.workspace = true
reth-beacon-consensus.workspace = true
reth-primitives.workspace = true
reth-execution-errors.workspace = true
reth-execution-types.workspace = true
reth-network-p2p.workspace = true
reth-provider.workspace = true
reth-stages-api.workspace = true
reth-revm.workspace = true
reth-transaction-pool.workspace = true
reth-evm.workspace = true
reth-engine-primitives.workspace = true
reth-consensus.workspace = true
reth-network-peers.workspace = true
reth-tokio-util.workspace = true
reth-trie.workspace = true
# ethereum
alloy-eips.workspace = true
alloy-primitives.workspace = true
revm-primitives.workspace = true
alloy-rpc-types-engine.workspace = true
# optimism
reth-optimism-consensus = { workspace = true, optional = true }
# async
futures-util.workspace = true
tokio = { workspace = true, features = ["sync", "time"] }
tokio-stream.workspace = true
tracing.workspace = true
[features]
optimism = [
"reth-provider/optimism",
"reth-optimism-consensus",
"reth-beacon-consensus/optimism",
"reth-execution-types/optimism",
"reth-optimism-consensus?/optimism",
"reth-primitives/optimism",
"revm-primitives/optimism"
]

View File

@ -1,132 +0,0 @@
//! This includes download client implementations for auto sealing miners.
use crate::Storage;
use alloy_eips::BlockHashOrNumber;
use alloy_primitives::B256;
use reth_network_p2p::{
bodies::client::{BodiesClient, BodiesFut},
download::DownloadClient,
headers::client::{HeadersClient, HeadersDirection, HeadersFut, HeadersRequest},
priority::Priority,
};
use reth_network_peers::{PeerId, WithPeerId};
use reth_primitives::{BlockBody, Header};
use std::fmt::Debug;
use tracing::{trace, warn};
/// A download client that polls the miner for transactions and assembles blocks to be returned in
/// the download process.
///
/// When polled, the miner will assemble blocks when miners produce ready transactions and store the
/// blocks in memory.
#[derive(Debug, Clone)]
pub struct AutoSealClient {
storage: Storage,
}
impl AutoSealClient {
pub(crate) const fn new(storage: Storage) -> Self {
Self { storage }
}
async fn fetch_headers(&self, request: HeadersRequest) -> Vec<Header> {
trace!(target: "consensus::auto", ?request, "received headers request");
let storage = self.storage.read().await;
let HeadersRequest { start, limit, direction } = request;
let mut headers = Vec::new();
let mut block: BlockHashOrNumber = match start {
BlockHashOrNumber::Hash(start) => start.into(),
BlockHashOrNumber::Number(num) => {
if let Some(hash) = storage.block_hash(num) {
hash.into()
} else {
warn!(target: "consensus::auto", num, "no matching block found");
return headers
}
}
};
for _ in 0..limit {
// fetch from storage
if let Some(header) = storage.header_by_hash_or_number(block) {
match direction {
HeadersDirection::Falling => block = header.parent_hash.into(),
HeadersDirection::Rising => {
let next = header.number + 1;
block = next.into()
}
}
headers.push(header);
} else {
break
}
}
trace!(target: "consensus::auto", ?headers, "returning headers");
headers
}
async fn fetch_bodies(&self, hashes: Vec<B256>) -> Vec<BlockBody> {
trace!(target: "consensus::auto", ?hashes, "received bodies request");
let storage = self.storage.read().await;
let mut bodies = Vec::new();
for hash in hashes {
if let Some(body) = storage.bodies.get(&hash).cloned() {
bodies.push(body);
} else {
break
}
}
trace!(target: "consensus::auto", ?bodies, "returning bodies");
bodies
}
}
impl HeadersClient for AutoSealClient {
type Output = HeadersFut;
fn get_headers_with_priority(
&self,
request: HeadersRequest,
_priority: Priority,
) -> Self::Output {
let this = self.clone();
Box::pin(async move {
let headers = this.fetch_headers(request).await;
Ok(WithPeerId::new(PeerId::random(), headers))
})
}
}
impl BodiesClient for AutoSealClient {
type Output = BodiesFut;
fn get_block_bodies_with_priority(
&self,
hashes: Vec<B256>,
_priority: Priority,
) -> Self::Output {
let this = self.clone();
Box::pin(async move {
let bodies = this.fetch_bodies(hashes).await;
Ok(WithPeerId::new(PeerId::random(), bodies))
})
}
}
impl DownloadClient for AutoSealClient {
fn report_bad_message(&self, _peer_id: PeerId) {
warn!("Reported a bad message on a miner, we should never produce bad blocks");
// noop
}
fn num_connected_peers(&self) -> usize {
// no such thing as connected peers when we are mining ourselves
1
}
}

View File

@ -1,690 +0,0 @@
//! A [Consensus] implementation for local testing purposes
//! that automatically seals blocks.
//!
//! The Mining task polls a [`MiningMode`], and will return a list of transactions that are ready to
//! be mined.
//!
//! These downloaders poll the miner, assemble the block, and return transactions that are ready to
//! be mined.
#![doc(
html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
)]
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
use alloy_eips::{eip1898::BlockHashOrNumber, eip7685::Requests};
use alloy_primitives::{BlockHash, BlockNumber, Bloom, B256, U256};
use reth_beacon_consensus::BeaconEngineMessage;
use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_consensus::{Consensus, ConsensusError, PostExecutionInput};
use reth_engine_primitives::EngineTypes;
use reth_execution_errors::{
BlockExecutionError, BlockValidationError, InternalBlockExecutionError,
};
use reth_execution_types::ExecutionOutcome;
use reth_primitives::{
proofs, Block, BlockBody, BlockWithSenders, Header, SealedBlock, SealedHeader,
TransactionSigned, Withdrawals,
};
use reth_provider::{BlockReaderIdExt, StateProviderFactory, StateRootProvider};
use reth_revm::database::StateProviderDatabase;
use reth_transaction_pool::TransactionPool;
use reth_trie::HashedPostState;
use revm_primitives::calc_excess_blob_gas;
use std::{
collections::HashMap,
fmt::Debug,
sync::Arc,
time::{SystemTime, UNIX_EPOCH},
};
use tokio::sync::{mpsc::UnboundedSender, RwLock, RwLockReadGuard, RwLockWriteGuard};
use tracing::trace;
mod client;
mod mode;
mod task;
pub use crate::client::AutoSealClient;
pub use mode::{FixedBlockTimeMiner, MiningMode, ReadyTransactionMiner};
use reth_evm::execute::{BlockExecutorProvider, Executor};
pub use task::MiningTask;
/// A consensus implementation intended for local development and testing purposes.
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct AutoSealConsensus<ChainSpec> {
/// Configuration
chain_spec: Arc<ChainSpec>,
}
impl<ChainSpec> AutoSealConsensus<ChainSpec> {
/// Create a new instance of [`AutoSealConsensus`]
pub const fn new(chain_spec: Arc<ChainSpec>) -> Self {
Self { chain_spec }
}
}
impl<ChainSpec: Send + Sync + Debug> Consensus for AutoSealConsensus<ChainSpec> {
fn validate_header(&self, _header: &SealedHeader) -> Result<(), ConsensusError> {
Ok(())
}
fn validate_header_against_parent(
&self,
_header: &SealedHeader,
_parent: &SealedHeader,
) -> Result<(), ConsensusError> {
Ok(())
}
fn validate_header_with_total_difficulty(
&self,
_header: &Header,
_total_difficulty: U256,
) -> Result<(), ConsensusError> {
Ok(())
}
fn validate_block_pre_execution(&self, _block: &SealedBlock) -> Result<(), ConsensusError> {
Ok(())
}
fn validate_block_post_execution(
&self,
_block: &BlockWithSenders,
_input: PostExecutionInput<'_>,
) -> Result<(), ConsensusError> {
Ok(())
}
}
/// Builder type for configuring the setup
#[derive(Debug)]
pub struct AutoSealBuilder<Client, Pool, Engine: EngineTypes, EvmConfig, ChainSpec> {
client: Client,
consensus: AutoSealConsensus<ChainSpec>,
pool: Pool,
mode: MiningMode,
storage: Storage,
to_engine: UnboundedSender<BeaconEngineMessage<Engine>>,
evm_config: EvmConfig,
}
// === impl AutoSealBuilder ===
impl<Client, Pool, Engine, EvmConfig, ChainSpec>
AutoSealBuilder<Client, Pool, Engine, EvmConfig, ChainSpec>
where
Client: BlockReaderIdExt,
Pool: TransactionPool,
Engine: EngineTypes,
ChainSpec: EthChainSpec,
{
/// Creates a new builder instance to configure all parts.
pub fn new(
chain_spec: Arc<ChainSpec>,
client: Client,
pool: Pool,
to_engine: UnboundedSender<BeaconEngineMessage<Engine>>,
mode: MiningMode,
evm_config: EvmConfig,
) -> Self {
let latest_header = client.latest_header().ok().flatten().unwrap_or_else(|| {
SealedHeader::new(chain_spec.genesis_header().clone(), chain_spec.genesis_hash())
});
Self {
storage: Storage::new(latest_header),
client,
consensus: AutoSealConsensus::new(chain_spec),
pool,
mode,
to_engine,
evm_config,
}
}
/// Sets the [`MiningMode`] it operates in, default is [`MiningMode::Auto`]
pub fn mode(mut self, mode: MiningMode) -> Self {
self.mode = mode;
self
}
/// Consumes the type and returns all components
#[track_caller]
pub fn build(
self,
) -> (
AutoSealConsensus<ChainSpec>,
AutoSealClient,
MiningTask<Client, Pool, EvmConfig, Engine, ChainSpec>,
) {
let Self { client, consensus, pool, mode, storage, to_engine, evm_config } = self;
let auto_client = AutoSealClient::new(storage.clone());
let task = MiningTask::new(
Arc::clone(&consensus.chain_spec),
mode,
to_engine,
storage,
client,
pool,
evm_config,
);
(consensus, auto_client, task)
}
}
/// In memory storage
#[derive(Debug, Clone, Default)]
pub(crate) struct Storage {
inner: Arc<RwLock<StorageInner>>,
}
// == impl Storage ===
impl Storage {
/// Initializes the [Storage] with the given best block. This should be initialized with the
/// highest block in the chain, if there is a chain already stored on-disk.
fn new(best_block: SealedHeader) -> Self {
let (header, best_hash) = best_block.split();
let mut storage = StorageInner {
best_hash,
total_difficulty: header.difficulty,
best_block: header.number,
..Default::default()
};
storage.headers.insert(header.number, header);
storage.bodies.insert(best_hash, BlockBody::default());
Self { inner: Arc::new(RwLock::new(storage)) }
}
/// Returns the write lock of the storage
pub(crate) async fn write(&self) -> RwLockWriteGuard<'_, StorageInner> {
self.inner.write().await
}
/// Returns the read lock of the storage
pub(crate) async fn read(&self) -> RwLockReadGuard<'_, StorageInner> {
self.inner.read().await
}
}
/// In-memory storage for the chain the auto seal engine is building.
#[derive(Default, Debug)]
pub(crate) struct StorageInner {
/// Headers buffered for download.
pub(crate) headers: HashMap<BlockNumber, Header>,
/// A mapping between block hash and number.
pub(crate) hash_to_number: HashMap<BlockHash, BlockNumber>,
/// Bodies buffered for download.
pub(crate) bodies: HashMap<BlockHash, BlockBody>,
/// Tracks best block
pub(crate) best_block: u64,
/// Tracks hash of best block
pub(crate) best_hash: B256,
/// The total difficulty of the chain until this block
pub(crate) total_difficulty: U256,
}
// === impl StorageInner ===
impl StorageInner {
/// Returns the block hash for the given block number if it exists.
pub(crate) fn block_hash(&self, num: u64) -> Option<BlockHash> {
self.hash_to_number.iter().find_map(|(k, v)| num.eq(v).then_some(*k))
}
/// Returns the matching header if it exists.
pub(crate) fn header_by_hash_or_number(
&self,
hash_or_num: BlockHashOrNumber,
) -> Option<Header> {
let num = match hash_or_num {
BlockHashOrNumber::Hash(hash) => self.hash_to_number.get(&hash).copied()?,
BlockHashOrNumber::Number(num) => num,
};
self.headers.get(&num).cloned()
}
/// Inserts a new header+body pair
pub(crate) fn insert_new_block(&mut self, mut header: Header, body: BlockBody) {
header.number = self.best_block + 1;
header.parent_hash = self.best_hash;
self.best_hash = header.hash_slow();
self.best_block = header.number;
self.total_difficulty += header.difficulty;
trace!(target: "consensus::auto", num=self.best_block, hash=?self.best_hash, "inserting new block");
self.headers.insert(header.number, header);
self.bodies.insert(self.best_hash, body);
self.hash_to_number.insert(self.best_hash, self.best_block);
}
/// Fills in pre-execution header fields based on the current best block and given
/// transactions.
pub(crate) fn build_header_template<ChainSpec>(
&self,
timestamp: u64,
transactions: &[TransactionSigned],
ommers: &[Header],
withdrawals: Option<&Withdrawals>,
requests: Option<&Requests>,
chain_spec: &ChainSpec,
) -> Header
where
ChainSpec: EthChainSpec + EthereumHardforks,
{
// check previous block for base fee
let base_fee_per_gas = self.headers.get(&self.best_block).and_then(|parent| {
parent.next_block_base_fee(chain_spec.base_fee_params_at_timestamp(timestamp))
});
let blob_gas_used = chain_spec.is_cancun_active_at_timestamp(timestamp).then(|| {
transactions
.iter()
.filter_map(|tx| tx.transaction.as_eip4844())
.map(|blob_tx| blob_tx.blob_gas())
.sum::<u64>()
});
let mut header = Header {
parent_hash: self.best_hash,
ommers_hash: proofs::calculate_ommers_root(ommers),
transactions_root: proofs::calculate_transaction_root(transactions),
withdrawals_root: withdrawals.map(|w| proofs::calculate_withdrawals_root(w)),
difficulty: U256::from(2),
number: self.best_block + 1,
gas_limit: chain_spec.max_gas_limit(),
timestamp,
base_fee_per_gas,
blob_gas_used,
requests_hash: requests.map(|r| r.requests_hash()),
..Default::default()
};
if chain_spec.is_cancun_active_at_timestamp(timestamp) {
let parent = self.headers.get(&self.best_block);
header.parent_beacon_block_root =
parent.and_then(|parent| parent.parent_beacon_block_root);
header.blob_gas_used = Some(0);
let (parent_excess_blob_gas, parent_blob_gas_used) = match parent {
Some(parent) if chain_spec.is_cancun_active_at_timestamp(parent.timestamp) => (
parent.excess_blob_gas.unwrap_or_default(),
parent.blob_gas_used.unwrap_or_default(),
),
_ => (0, 0),
};
header.excess_blob_gas =
Some(calc_excess_blob_gas(parent_excess_blob_gas, parent_blob_gas_used))
}
header
}
/// Builds and executes a new block with the given transactions, on the provided executor.
///
/// This returns the header of the executed block, as well as the poststate from execution.
#[allow(clippy::too_many_arguments)]
pub(crate) fn build_and_execute<Provider, Executor, ChainSpec>(
&mut self,
transactions: Vec<TransactionSigned>,
ommers: Vec<Header>,
provider: &Provider,
chain_spec: Arc<ChainSpec>,
executor: &Executor,
) -> Result<(SealedHeader, ExecutionOutcome), BlockExecutionError>
where
Executor: BlockExecutorProvider,
Provider: StateProviderFactory,
ChainSpec: EthChainSpec + EthereumHardforks,
{
let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_secs();
// if shanghai is active, include empty withdrawals
let withdrawals =
chain_spec.is_shanghai_active_at_timestamp(timestamp).then_some(Withdrawals::default());
// if prague is active, include empty requests
let requests =
chain_spec.is_prague_active_at_timestamp(timestamp).then_some(Requests::default());
let header = self.build_header_template(
timestamp,
&transactions,
&ommers,
withdrawals.as_ref(),
requests.as_ref(),
&chain_spec,
);
let block = Block {
header,
body: BlockBody {
transactions,
ommers: ommers.clone(),
withdrawals: withdrawals.clone(),
},
}
.with_recovered_senders()
.ok_or(BlockExecutionError::Validation(BlockValidationError::SenderRecoveryError))?;
trace!(target: "consensus::auto", transactions=?&block.body, "executing transactions");
let mut db = StateProviderDatabase::new(
provider.latest().map_err(InternalBlockExecutionError::LatestBlock)?,
);
// execute the block
let block_execution_output =
executor.executor(&mut db).execute((&block, U256::ZERO).into())?;
let gas_used = block_execution_output.gas_used;
let execution_outcome = ExecutionOutcome::from((block_execution_output, block.number));
let hashed_state = HashedPostState::from_bundle_state(&execution_outcome.state().state);
// todo(onbjerg): we should not pass requests around as this is building a block, which
// means we need to extract the requests from the execution output and compute the requests
// root here
let Block { mut header, body, .. } = block.block;
let body = BlockBody { transactions: body.transactions, ommers, withdrawals };
trace!(target: "consensus::auto", ?execution_outcome, ?header, ?body, "executed block, calculating state root and completing header");
// now we need to update certain header fields with the results of the execution
header.state_root = db.state_root(hashed_state)?;
header.gas_used = gas_used;
let receipts = execution_outcome.receipts_by_block(header.number);
// update logs bloom
let receipts_with_bloom =
receipts.iter().map(|r| r.as_ref().unwrap().bloom_slow()).collect::<Vec<Bloom>>();
header.logs_bloom = receipts_with_bloom.iter().fold(Bloom::ZERO, |bloom, r| bloom | *r);
// update receipts root
header.receipts_root = {
#[cfg(feature = "optimism")]
let receipts_root = execution_outcome
.generic_receipts_root_slow(header.number, |receipts| {
reth_optimism_consensus::calculate_receipt_root_no_memo_optimism(
receipts,
&chain_spec,
header.timestamp,
)
})
.expect("Receipts is present");
#[cfg(not(feature = "optimism"))]
let receipts_root =
execution_outcome.receipts_root_slow(header.number).expect("Receipts is present");
receipts_root
};
trace!(target: "consensus::auto", root=?header.state_root, ?body, "calculated root");
// finally insert into storage
self.insert_new_block(header.clone(), body);
// set new header with hash that should have been updated by insert_new_block
let new_header = SealedHeader::new(header, self.best_hash);
Ok((new_header, execution_outcome))
}
}
#[cfg(test)]
mod tests {
use super::*;
use reth_chainspec::{ChainHardforks, ChainSpec, EthereumHardfork, ForkCondition};
use reth_primitives::Transaction;
#[test]
fn test_block_hash() {
let mut storage = StorageInner::default();
// Define two block hashes and their corresponding block numbers.
let block_hash_1: BlockHash = B256::random();
let block_number_1: BlockNumber = 1;
let block_hash_2: BlockHash = B256::random();
let block_number_2: BlockNumber = 2;
// Insert the block number and hash pairs into the `hash_to_number` map.
storage.hash_to_number.insert(block_hash_1, block_number_1);
storage.hash_to_number.insert(block_hash_2, block_number_2);
// Verify that `block_hash` returns the correct block hash for the given block number.
assert_eq!(storage.block_hash(block_number_1), Some(block_hash_1));
assert_eq!(storage.block_hash(block_number_2), Some(block_hash_2));
// Test that `block_hash` returns `None` for a non-existent block number.
let block_number_3: BlockNumber = 3;
assert_eq!(storage.block_hash(block_number_3), None);
}
#[test]
fn test_header_by_hash_or_number() {
let mut storage = StorageInner::default();
// Define block numbers, headers, and hashes.
let block_number_1: u64 = 1;
let block_number_2: u64 = 2;
let header_1 = Header { number: block_number_1, ..Default::default() };
let header_2 = Header { number: block_number_2, ..Default::default() };
let block_hash_1: BlockHash = B256::random();
let block_hash_2: BlockHash = B256::random();
// Insert headers and hash-to-number mappings.
storage.headers.insert(block_number_1, header_1.clone());
storage.headers.insert(block_number_2, header_2.clone());
storage.hash_to_number.insert(block_hash_1, block_number_1);
storage.hash_to_number.insert(block_hash_2, block_number_2);
// Test header retrieval by block number.
assert_eq!(
storage.header_by_hash_or_number(BlockHashOrNumber::Number(block_number_1)),
Some(header_1.clone())
);
assert_eq!(
storage.header_by_hash_or_number(BlockHashOrNumber::Number(block_number_2)),
Some(header_2.clone())
);
// Test header retrieval by block hash.
assert_eq!(
storage.header_by_hash_or_number(BlockHashOrNumber::Hash(block_hash_1)),
Some(header_1)
);
assert_eq!(
storage.header_by_hash_or_number(BlockHashOrNumber::Hash(block_hash_2)),
Some(header_2)
);
// Test non-existent block number and hash.
assert_eq!(storage.header_by_hash_or_number(BlockHashOrNumber::Number(999)), None);
let non_existent_hash: BlockHash = B256::random();
assert_eq!(
storage.header_by_hash_or_number(BlockHashOrNumber::Hash(non_existent_hash)),
None
);
}
#[test]
fn test_insert_new_block() {
let mut storage = StorageInner::default();
// Define headers and block bodies.
let header_1 = Header { difficulty: U256::from(100), ..Default::default() };
let body_1 = BlockBody::default();
let header_2 = Header { difficulty: U256::from(200), ..Default::default() };
let body_2 = BlockBody::default();
// Insert the first block.
storage.insert_new_block(header_1.clone(), body_1.clone());
let best_block_1 = storage.best_block;
let best_hash_1 = storage.best_hash;
// Verify the block was inserted correctly.
assert_eq!(
storage.headers.get(&best_block_1),
Some(&Header { number: 1, ..header_1.clone() })
);
assert_eq!(storage.bodies.get(&best_hash_1), Some(&body_1));
assert_eq!(storage.hash_to_number.get(&best_hash_1), Some(&best_block_1));
// Insert the second block.
storage.insert_new_block(header_2.clone(), body_2.clone());
let best_block_2 = storage.best_block;
let best_hash_2 = storage.best_hash;
// Verify the second block was inserted correctly.
assert_eq!(
storage.headers.get(&best_block_2),
Some(&Header {
number: 2,
parent_hash: Header { number: 1, ..header_1 }.hash_slow(),
..header_2
})
);
assert_eq!(storage.bodies.get(&best_hash_2), Some(&body_2));
assert_eq!(storage.hash_to_number.get(&best_hash_2), Some(&best_block_2));
// Check that the total difficulty was updated.
assert_eq!(storage.total_difficulty, header_1.difficulty + header_2.difficulty);
}
#[test]
fn test_build_basic_header_template() {
let mut storage = StorageInner::default();
let chain_spec = ChainSpec::default();
let best_block_number = 1;
let best_block_hash = B256::random();
let timestamp = 1_600_000_000;
// Set up best block information
storage.best_block = best_block_number;
storage.best_hash = best_block_hash;
// Build header template
let header = storage.build_header_template(
timestamp,
&[], // no transactions
&[], // no ommers
None, // no withdrawals
None, // no requests
&chain_spec,
);
// Verify basic fields
assert_eq!(header.parent_hash, best_block_hash);
assert_eq!(header.number, best_block_number + 1);
assert_eq!(header.timestamp, timestamp);
assert_eq!(header.gas_limit, chain_spec.max_gas_limit);
}
#[test]
fn test_ommers_and_transactions_roots() {
let storage = StorageInner::default();
let chain_spec = ChainSpec::default();
let timestamp = 1_600_000_000;
// Setup ommers and transactions
let ommers = vec![Header::default()];
let transactions = vec![TransactionSigned::default()];
// Build header template
let header = storage.build_header_template(
timestamp,
&transactions,
&ommers,
None, // no withdrawals
None, // no requests
&chain_spec,
);
// Verify ommers and transactions roots
assert_eq!(header.ommers_hash, proofs::calculate_ommers_root(&ommers));
assert_eq!(header.transactions_root, proofs::calculate_transaction_root(&transactions));
}
// Test base fee calculation from the parent block
#[test]
fn test_base_fee_calculation() {
let mut storage = StorageInner::default();
let chain_spec = ChainSpec::default();
let timestamp = 1_600_000_000;
// Set up the parent header with base fee
let base_fee = Some(100);
let parent_header = Header { base_fee_per_gas: base_fee, ..Default::default() };
storage.headers.insert(storage.best_block, parent_header);
// Build header template
let header = storage.build_header_template(
timestamp,
&[], // no transactions
&[], // no ommers
None, // no withdrawals
None, // no requests
&chain_spec,
);
// Verify base fee is correctly propagated
assert_eq!(header.base_fee_per_gas, base_fee);
}
// Test blob gas and excess blob gas calculation when Cancun is active
#[test]
fn test_blob_gas_calculation_cancun() {
let storage = StorageInner::default();
let chain_spec = ChainSpec {
hardforks: ChainHardforks::new(vec![(
EthereumHardfork::Cancun.boxed(),
ForkCondition::Timestamp(25),
)]),
..Default::default()
};
let timestamp = 26;
// Set up a transaction with blob gas
let blob_tx = TransactionSigned {
transaction: Transaction::Eip4844(Default::default()),
..Default::default()
};
let transactions = vec![blob_tx];
// Build header template
let header = storage.build_header_template(
timestamp,
&transactions,
&[], // no ommers
None, // no withdrawals
None, // no requests
&chain_spec,
);
// Verify that the header has the correct fields including blob gas
assert_eq!(
header,
Header {
parent_hash: B256::ZERO,
ommers_hash: proofs::calculate_ommers_root(&[]),
transactions_root: proofs::calculate_transaction_root(&transactions),
withdrawals_root: None,
difficulty: U256::from(2),
number: 1,
gas_limit: chain_spec.max_gas_limit,
timestamp,
base_fee_per_gas: None,
blob_gas_used: Some(0),
requests_hash: None,
excess_blob_gas: Some(0),
..Default::default()
}
);
}
}

View File

@ -1,166 +0,0 @@
//! The mode the auto seal miner is operating in.
use alloy_primitives::TxHash;
use futures_util::{stream::Fuse, StreamExt};
use reth_transaction_pool::{TransactionPool, ValidPoolTransaction};
use std::{
fmt,
pin::Pin,
sync::Arc,
task::{Context, Poll},
time::Duration,
};
use tokio::{sync::mpsc::Receiver, time::Interval};
use tokio_stream::{wrappers::ReceiverStream, Stream};
/// Mode of operations for the `Miner`
#[derive(Debug)]
pub enum MiningMode {
/// A miner that does nothing
None,
/// A miner that listens for new transactions that are ready.
///
/// Either one transaction will be mined per block, or any number of transactions will be
/// allowed
Auto(ReadyTransactionMiner),
/// A miner that constructs a new block every `interval` tick
FixedBlockTime(FixedBlockTimeMiner),
}
// === impl MiningMode ===
impl MiningMode {
/// Creates a new instant mining mode that listens for new transactions and tries to build
/// non-empty blocks as soon as transactions arrive.
pub fn instant(max_transactions: usize, listener: Receiver<TxHash>) -> Self {
Self::Auto(ReadyTransactionMiner {
max_transactions,
has_pending_txs: None,
rx: ReceiverStream::new(listener).fuse(),
})
}
/// Creates a new interval miner that builds a block ever `duration`.
pub fn interval(duration: Duration) -> Self {
Self::FixedBlockTime(FixedBlockTimeMiner::new(duration))
}
/// polls the Pool and returns those transactions that should be put in a block, if any.
pub(crate) fn poll<Pool>(
&mut self,
pool: &Pool,
cx: &mut Context<'_>,
) -> Poll<Vec<Arc<ValidPoolTransaction<<Pool as TransactionPool>::Transaction>>>>
where
Pool: TransactionPool,
{
match self {
Self::None => Poll::Pending,
Self::Auto(miner) => miner.poll(pool, cx),
Self::FixedBlockTime(miner) => miner.poll(pool, cx),
}
}
}
impl fmt::Display for MiningMode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let kind = match self {
Self::None => "None",
Self::Auto(_) => "Auto",
Self::FixedBlockTime(_) => "FixedBlockTime",
};
write!(f, "{kind}")
}
}
/// A miner that's supposed to create a new block every `interval`, mining all transactions that are
/// ready at that time.
///
/// The default blocktime is set to 6 seconds
#[derive(Debug)]
pub struct FixedBlockTimeMiner {
/// The interval this fixed block time miner operates with
interval: Interval,
}
// === impl FixedBlockTimeMiner ===
impl FixedBlockTimeMiner {
/// Creates a new instance with an interval of `duration`
pub(crate) fn new(duration: Duration) -> Self {
let start = tokio::time::Instant::now() + duration;
Self { interval: tokio::time::interval_at(start, duration) }
}
fn poll<Pool>(
&mut self,
pool: &Pool,
cx: &mut Context<'_>,
) -> Poll<Vec<Arc<ValidPoolTransaction<<Pool as TransactionPool>::Transaction>>>>
where
Pool: TransactionPool,
{
if self.interval.poll_tick(cx).is_ready() {
// drain the pool
return Poll::Ready(pool.best_transactions().collect())
}
Poll::Pending
}
}
impl Default for FixedBlockTimeMiner {
fn default() -> Self {
Self::new(Duration::from_secs(6))
}
}
/// A miner that Listens for new ready transactions
pub struct ReadyTransactionMiner {
/// how many transactions to mine per block
max_transactions: usize,
/// stores whether there are pending transactions (if known)
has_pending_txs: Option<bool>,
/// Receives hashes of transactions that are ready
rx: Fuse<ReceiverStream<TxHash>>,
}
// === impl ReadyTransactionMiner ===
impl ReadyTransactionMiner {
fn poll<Pool>(
&mut self,
pool: &Pool,
cx: &mut Context<'_>,
) -> Poll<Vec<Arc<ValidPoolTransaction<<Pool as TransactionPool>::Transaction>>>>
where
Pool: TransactionPool,
{
// drain the notification stream
while let Poll::Ready(Some(_hash)) = Pin::new(&mut self.rx).poll_next(cx) {
self.has_pending_txs = Some(true);
}
if self.has_pending_txs == Some(false) {
return Poll::Pending
}
let transactions = pool.best_transactions().take(self.max_transactions).collect::<Vec<_>>();
// there are pending transactions if we didn't drain the pool
self.has_pending_txs = Some(transactions.len() >= self.max_transactions);
if transactions.is_empty() {
return Poll::Pending
}
Poll::Ready(transactions)
}
}
impl fmt::Debug for ReadyTransactionMiner {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReadyTransactionMiner")
.field("max_transactions", &self.max_transactions)
.finish_non_exhaustive()
}
}

View File

@ -1,221 +0,0 @@
use crate::{mode::MiningMode, Storage};
use alloy_rpc_types_engine::ForkchoiceState;
use futures_util::{future::BoxFuture, FutureExt};
use reth_beacon_consensus::{BeaconEngineMessage, ForkchoiceStatus};
use reth_chainspec::{EthChainSpec, EthereumHardforks};
use reth_engine_primitives::{EngineApiMessageVersion, EngineTypes};
use reth_evm::execute::BlockExecutorProvider;
use reth_provider::{CanonChainTracker, StateProviderFactory};
use reth_stages_api::PipelineEvent;
use reth_tokio_util::EventStream;
use reth_transaction_pool::{TransactionPool, ValidPoolTransaction};
use std::{
collections::VecDeque,
future::Future,
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
use tokio::sync::{mpsc::UnboundedSender, oneshot};
use tracing::{debug, error, warn};
/// A Future that listens for new ready transactions and puts new blocks into storage
pub struct MiningTask<Client, Pool: TransactionPool, Executor, Engine: EngineTypes, ChainSpec> {
/// The configured chain spec
chain_spec: Arc<ChainSpec>,
/// The client used to interact with the state
client: Client,
/// The active miner
miner: MiningMode,
/// Single active future that inserts a new block into `storage`
insert_task: Option<BoxFuture<'static, Option<EventStream<PipelineEvent>>>>,
/// Shared storage to insert new blocks
storage: Storage,
/// Pool where transactions are stored
pool: Pool,
/// backlog of sets of transactions ready to be mined
queued: VecDeque<Vec<Arc<ValidPoolTransaction<<Pool as TransactionPool>::Transaction>>>>,
// TODO: ideally this would just be a sender of hashes
to_engine: UnboundedSender<BeaconEngineMessage<Engine>>,
/// The pipeline events to listen on
pipe_line_events: Option<EventStream<PipelineEvent>>,
/// The type used for block execution
block_executor: Executor,
}
// === impl MiningTask ===
impl<Executor, Client, Pool: TransactionPool, Engine: EngineTypes, ChainSpec>
MiningTask<Client, Pool, Executor, Engine, ChainSpec>
{
/// Creates a new instance of the task
#[allow(clippy::too_many_arguments)]
pub(crate) fn new(
chain_spec: Arc<ChainSpec>,
miner: MiningMode,
to_engine: UnboundedSender<BeaconEngineMessage<Engine>>,
storage: Storage,
client: Client,
pool: Pool,
block_executor: Executor,
) -> Self {
Self {
chain_spec,
client,
miner,
insert_task: None,
storage,
pool,
to_engine,
queued: Default::default(),
pipe_line_events: None,
block_executor,
}
}
/// Sets the pipeline events to listen on.
pub fn set_pipeline_events(&mut self, events: EventStream<PipelineEvent>) {
self.pipe_line_events = Some(events);
}
}
impl<Executor, Client, Pool, Engine, ChainSpec> Future
for MiningTask<Client, Pool, Executor, Engine, ChainSpec>
where
Client: StateProviderFactory + CanonChainTracker + Clone + Unpin + 'static,
Pool: TransactionPool + Unpin + 'static,
Engine: EngineTypes,
Executor: BlockExecutorProvider,
ChainSpec: EthChainSpec + EthereumHardforks + 'static,
{
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
// this drives block production and
loop {
if let Poll::Ready(transactions) = this.miner.poll(&this.pool, cx) {
// miner returned a set of transaction that we feed to the producer
this.queued.push_back(transactions);
}
if this.insert_task.is_none() {
if this.queued.is_empty() {
// nothing to insert
break
}
// ready to queue in new insert task
let storage = this.storage.clone();
let transactions = this.queued.pop_front().expect("not empty");
let to_engine = this.to_engine.clone();
let client = this.client.clone();
let chain_spec = Arc::clone(&this.chain_spec);
let events = this.pipe_line_events.take();
let executor = this.block_executor.clone();
// Create the mining future that creates a block, notifies the engine that drives
// the pipeline
this.insert_task = Some(Box::pin(async move {
let mut storage = storage.write().await;
let transactions: Vec<_> = transactions
.into_iter()
.map(|tx| {
let recovered = tx.to_recovered_transaction();
recovered.into_signed()
})
.collect();
let ommers = vec![];
match storage.build_and_execute(
transactions.clone(),
ommers.clone(),
&client,
chain_spec,
&executor,
) {
Ok((new_header, _bundle_state)) => {
let state = ForkchoiceState {
head_block_hash: new_header.hash(),
finalized_block_hash: new_header.hash(),
safe_block_hash: new_header.hash(),
};
drop(storage);
// TODO: make this a future
// await the fcu call rx for SYNCING, then wait for a VALID response
loop {
// send the new update to the engine, this will trigger the engine
// to download and execute the block we just inserted
let (tx, rx) = oneshot::channel();
let _ = to_engine.send(BeaconEngineMessage::ForkchoiceUpdated {
state,
payload_attrs: None,
tx,
version: EngineApiMessageVersion::default(),
});
debug!(target: "consensus::auto", ?state, "Sent fork choice update");
match rx.await.unwrap() {
Ok(fcu_response) => {
match fcu_response.forkchoice_status() {
ForkchoiceStatus::Valid => break,
ForkchoiceStatus::Invalid => {
error!(target: "consensus::auto", ?fcu_response, "Forkchoice update returned invalid response");
return None
}
ForkchoiceStatus::Syncing => {
debug!(target: "consensus::auto", ?fcu_response, "Forkchoice update returned SYNCING, waiting for VALID");
// wait for the next fork choice update
continue
}
}
}
Err(err) => {
error!(target: "consensus::auto", %err, "Autoseal fork choice update failed");
return None
}
}
}
// update canon chain for rpc
client.set_canonical_head(new_header.clone());
client.set_safe(new_header.clone());
client.set_finalized(new_header.clone());
}
Err(err) => {
warn!(target: "consensus::auto", %err, "failed to execute block")
}
}
events
}));
}
if let Some(mut fut) = this.insert_task.take() {
match fut.poll_unpin(cx) {
Poll::Ready(events) => {
this.pipe_line_events = events;
}
Poll::Pending => {
this.insert_task = Some(fut);
break
}
}
}
}
Poll::Pending
}
}
impl<Client, Pool: TransactionPool, EvmConfig: std::fmt::Debug, Engine: EngineTypes, ChainSpec>
std::fmt::Debug for MiningTask<Client, Pool, EvmConfig, Engine, ChainSpec>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MiningTask").finish_non_exhaustive()
}
}

View File

@ -24,7 +24,6 @@ reth-network.workspace = true
reth-evm.workspace = true
reth-evm-ethereum.workspace = true
reth-consensus.workspace = true
reth-auto-seal-consensus.workspace = true
reth-beacon-consensus.workspace = true
reth-rpc.workspace = true
reth-node-api.workspace = true

View File

@ -2,7 +2,6 @@
use std::sync::Arc;
use reth_auto_seal_consensus::AutoSealConsensus;
use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig};
use reth_beacon_consensus::EthBeaconConsensus;
use reth_chainspec::ChainSpec;
@ -335,13 +334,9 @@ where
type Consensus = Arc<dyn reth_consensus::Consensus>;
async fn build_consensus(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Consensus> {
if ctx.is_dev() {
Ok(Arc::new(AutoSealConsensus::new(ctx.chain_spec())))
} else {
Ok(Arc::new(EthBeaconConsensus::new(ctx.chain_spec())))
}
}
}
/// Builder for [`EthereumEngineValidator`].
#[derive(Debug, Default, Clone)]

View File

@ -1,12 +1,10 @@
use std::sync::Arc;
use crate::utils::eth_payload_attributes;
use alloy_genesis::Genesis;
use alloy_primitives::{b256, hex};
use futures::StreamExt;
use reth::{args::DevArgs, rpc::api::eth::helpers::EthTransactions};
use reth_chainspec::ChainSpec;
use reth_e2e_test_utils::setup;
use reth_node_api::FullNodeComponents;
use reth_node_builder::{
rpc::RethRpcAddOns, EngineNodeLauncher, FullNode, NodeBuilder, NodeConfig, NodeHandle,
@ -17,16 +15,6 @@ use reth_tasks::TaskManager;
#[tokio::test]
async fn can_run_dev_node() -> eyre::Result<()> {
reth_tracing::init_test_tracing();
let (mut nodes, _tasks, _) =
setup::<EthereumNode>(1, custom_chain(), true, eth_payload_attributes).await?;
assert_chain_advances(nodes.pop().unwrap().inner).await;
Ok(())
}
#[tokio::test]
async fn can_run_dev_node_new_engine() -> eyre::Result<()> {
reth_tracing::init_test_tracing();
let tasks = TaskManager::current();
let exec = tasks.executor();

View File

@ -13,7 +13,6 @@ workspace = true
[dependencies]
## reth
reth-auto-seal-consensus.workspace = true
reth-beacon-consensus.workspace = true
reth-blockchain-tree.workspace = true
reth-chain-state.workspace = true

View File

@ -5,7 +5,6 @@ use std::{sync::Arc, thread::available_parallelism};
use alloy_primitives::{BlockNumber, B256};
use eyre::{Context, OptionExt};
use rayon::ThreadPoolBuilder;
use reth_auto_seal_consensus::MiningMode;
use reth_beacon_consensus::EthBeaconConsensus;
use reth_blockchain_tree::{
BlockchainTree, BlockchainTreeConfig, ShareableBlockchainTree, TreeExternals,
@ -16,6 +15,7 @@ use reth_consensus::Consensus;
use reth_db_api::database::Database;
use reth_db_common::init::{init_genesis, InitDatabaseError};
use reth_downloaders::{bodies::noop::NoopBodiesDownloader, headers::noop::NoopHeaderDownloader};
use reth_engine_local::MiningMode;
use reth_engine_tree::tree::{InvalidBlockHook, InvalidBlockHooks, NoopInvalidBlockHook};
use reth_evm::noop::NoopBlockExecutorProvider;
use reth_fs_util as fs;
@ -52,8 +52,9 @@ use reth_stages::{sets::DefaultStages, MetricEvent, PipelineBuilder, PipelineTar
use reth_static_file::StaticFileProducer;
use reth_tasks::TaskExecutor;
use reth_tracing::tracing::{debug, error, info, warn};
use reth_transaction_pool::TransactionPool;
use tokio::sync::{
mpsc::{unbounded_channel, Receiver, UnboundedSender},
mpsc::{unbounded_channel, UnboundedSender},
oneshot, watch,
};
@ -386,13 +387,11 @@ impl<R, ChainSpec: EthChainSpec> LaunchContextWith<Attached<WithConfigs<ChainSpe
}
/// Returns the [`MiningMode`] intended for --dev mode.
pub fn dev_mining_mode(&self, pending_transactions_listener: Receiver<B256>) -> MiningMode {
pub fn dev_mining_mode(&self, pool: impl TransactionPool) -> MiningMode {
if let Some(interval) = self.node_config().dev.block_time {
MiningMode::interval(interval)
} else if let Some(max_transactions) = self.node_config().dev.block_max_transactions {
MiningMode::instant(max_transactions, pending_transactions_listener)
} else {
MiningMode::instant(1, pending_transactions_listener)
MiningMode::instant(pool)
}
}
}

View File

@ -8,7 +8,7 @@ use reth_beacon_consensus::{
use reth_blockchain_tree::BlockchainTreeConfig;
use reth_chainspec::EthChainSpec;
use reth_consensus_debug_client::{DebugConsensusClient, EtherscanBlockProvider};
use reth_engine_local::{LocalEngineService, LocalPayloadAttributesBuilder, MiningMode};
use reth_engine_local::{LocalEngineService, LocalPayloadAttributesBuilder};
use reth_engine_service::service::{ChainEvent, EngineService};
use reth_engine_tree::{
engine::{EngineApiRequest, EngineRequestHandler},
@ -208,11 +208,6 @@ where
info!(target: "reth::cli", prune_config=?ctx.prune_config().unwrap_or_default(), "Pruner initialized");
let mut engine_service = if ctx.is_dev() {
let mining_mode = if let Some(block_time) = ctx.node_config().dev.block_time {
MiningMode::interval(block_time)
} else {
MiningMode::instant(ctx.components().pool().clone())
};
let eth_service = LocalEngineService::new(
ctx.consensus(),
ctx.components().block_executor().clone(),
@ -225,7 +220,7 @@ where
ctx.sync_metrics_tx(),
consensus_engine_tx.clone(),
Box::pin(consensus_engine_stream),
mining_mode,
ctx.dev_mining_mode(ctx.components().pool()),
LocalPayloadAttributesBuilder::new(ctx.chain_spec()),
);

View File

@ -11,7 +11,6 @@ pub use exex::ExExLauncher;
use std::{future::Future, sync::Arc};
use alloy_primitives::utils::format_ether;
use futures::{future::Either, stream, stream_select, StreamExt};
use reth_beacon_consensus::{
hooks::{EngineHooks, PruneHook, StaticFileHook},
@ -33,7 +32,6 @@ use reth_provider::providers::BlockchainProvider;
use reth_rpc::eth::RpcNodeCore;
use reth_tasks::TaskExecutor;
use reth_tracing::tracing::{debug, info};
use reth_transaction_pool::TransactionPool;
use tokio::sync::{mpsc::unbounded_channel, oneshot};
use tokio_stream::wrappers::UnboundedReceiverStream;
@ -210,47 +208,7 @@ where
let pipeline_exex_handle =
exex_manager_handle.clone().unwrap_or_else(ExExManagerHandle::empty);
let (pipeline, client) = if ctx.is_dev() {
info!(target: "reth::cli", "Starting Reth in dev mode");
for (idx, (address, alloc)) in ctx.chain_spec().genesis().alloc.iter().enumerate() {
info!(target: "reth::cli", "Allocated Genesis Account: {:02}. {} ({} ETH)", idx, address.to_string(), format_ether(alloc.balance));
}
// install auto-seal
let mining_mode =
ctx.dev_mining_mode(ctx.components().pool().pending_transactions_listener());
info!(target: "reth::cli", mode=%mining_mode, "configuring dev mining mode");
let (_, client, mut task) = reth_auto_seal_consensus::AutoSealBuilder::new(
ctx.chain_spec(),
ctx.blockchain_db().clone(),
ctx.components().pool().clone(),
consensus_engine_tx.clone(),
mining_mode,
ctx.components().block_executor().clone(),
)
.build();
let pipeline = crate::setup::build_networked_pipeline(
&ctx.toml_config().stages,
client.clone(),
ctx.consensus(),
ctx.provider_factory().clone(),
ctx.task_executor(),
ctx.sync_metrics_tx(),
ctx.prune_config(),
max_block,
static_file_producer,
ctx.components().block_executor().clone(),
pipeline_exex_handle,
)?;
let pipeline_events = pipeline.events();
task.set_pipeline_events(pipeline_events);
debug!(target: "reth::cli", "Spawning auto mine task");
ctx.task_executor().spawn(Box::pin(task));
(pipeline, Either::Left(client))
eyre::bail!("Dev mode is not supported for legacy engine")
} else {
let pipeline = crate::setup::build_networked_pipeline(
&ctx.toml_config().stages,
@ -266,7 +224,7 @@ where
pipeline_exex_handle,
)?;
(pipeline, Either::Right(network_client.clone()))
(pipeline, network_client.clone())
};
let pipeline_events = pipeline.events();

View File

@ -16,7 +16,6 @@ reth-chainspec.workspace = true
reth-engine-local.workspace = true
reth-primitives.workspace = true
reth-payload-builder.workspace = true
reth-auto-seal-consensus.workspace = true
reth-basic-payload-builder.workspace = true
reth-consensus.workspace = true
reth-node-api.workspace = true
@ -76,7 +75,6 @@ optimism = [
"reth-optimism-payload-builder/optimism",
"reth-beacon-consensus/optimism",
"revm/optimism",
"reth-auto-seal-consensus/optimism",
"reth-optimism-rpc/optimism",
"reth-engine-local/optimism",
"reth-optimism-consensus/optimism",

View File

@ -467,13 +467,9 @@ where
type Consensus = Arc<dyn reth_consensus::Consensus>;
async fn build_consensus(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Consensus> {
if ctx.is_dev() {
Ok(Arc::new(reth_auto_seal_consensus::AutoSealConsensus::new(ctx.chain_spec())))
} else {
Ok(Arc::new(OpBeaconConsensus::new(ctx.chain_spec())))
}
}
}
/// Builder for [`OpEngineValidator`].
#[derive(Debug, Default, Clone)]

View File

@ -82,7 +82,6 @@ The networking component mainly lives in [`net/network`](../../crates/net/networ
Different consensus mechanisms.
- [`consensus/common`](../../crates/consensus/common): Common consensus functions and traits (e.g. fee calculation)
- [`consensus/auto-seal`](../../crates/consensus/auto-seal): A consensus mechanism that auto-seals blocks for local development (also commonly known as "auto-mine")
- [`consensus/beacon`](../../crates/consensus/beacon): Consensus mechanism that handles messages from a beacon node ("eth2")
### Execution