mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-30 03:01:58 -04:00
fix: always handle payload building for opstack (#11629)
This commit is contained in:
@@ -46,6 +46,11 @@ pub trait EthChainSpec: Send + Sync + Unpin + Debug {
|
||||
|
||||
/// The bootnodes for the chain, if any.
|
||||
fn bootnodes(&self) -> Option<Vec<NodeRecord>>;
|
||||
|
||||
/// Returns `true` if this chain contains Optimism configuration.
|
||||
fn is_optimism(&self) -> bool {
|
||||
self.chain().is_optimism()
|
||||
}
|
||||
}
|
||||
|
||||
impl EthChainSpec for ChainSpec {
|
||||
@@ -92,4 +97,8 @@ impl EthChainSpec for ChainSpec {
|
||||
fn bootnodes(&self) -> Option<Vec<NodeRecord>> {
|
||||
self.bootnodes()
|
||||
}
|
||||
|
||||
fn is_optimism(&self) -> bool {
|
||||
Self::is_optimism(self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ reth-prune.workspace = true
|
||||
reth-stages-api.workspace = true
|
||||
reth-tasks.workspace = true
|
||||
reth-node-types.workspace = true
|
||||
reth-chainspec.workspace = true
|
||||
|
||||
# async
|
||||
futures.workspace = true
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use futures::{Stream, StreamExt};
|
||||
use pin_project::pin_project;
|
||||
use reth_beacon_consensus::{BeaconConsensusEngineEvent, BeaconEngineMessage, EngineNodeTypes};
|
||||
use reth_chainspec::EthChainSpec;
|
||||
use reth_consensus::Consensus;
|
||||
use reth_engine_tree::{
|
||||
backfill::PipelineSync,
|
||||
download::BasicBlockDownloader,
|
||||
engine::{EngineApiRequest, EngineApiRequestHandler, EngineHandler},
|
||||
engine::{EngineApiKind, EngineApiRequest, EngineApiRequestHandler, EngineHandler},
|
||||
persistence::PersistenceHandle,
|
||||
tree::{EngineApiTreeHandler, InvalidBlockHook, TreeConfig},
|
||||
};
|
||||
@@ -79,6 +80,9 @@ where
|
||||
invalid_block_hook: Box<dyn InvalidBlockHook>,
|
||||
sync_metrics_tx: MetricEventsSender,
|
||||
) -> Self {
|
||||
let engine_kind =
|
||||
if chain_spec.is_optimism() { EngineApiKind::OpStack } else { EngineApiKind::Ethereum };
|
||||
|
||||
let downloader = BasicBlockDownloader::new(client, consensus.clone());
|
||||
|
||||
let persistence_handle =
|
||||
@@ -97,6 +101,7 @@ where
|
||||
canonical_in_memory_state,
|
||||
tree_config,
|
||||
invalid_block_hook,
|
||||
engine_kind,
|
||||
);
|
||||
|
||||
let engine_handler = EngineApiRequestHandler::new(to_tree_tx, from_tree);
|
||||
|
||||
@@ -212,15 +212,28 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// The type for specifying the kind of engine api
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
/// The type for specifying the kind of engine api.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub enum EngineApiKind {
|
||||
/// The chain contains Ethereum configuration.
|
||||
#[default]
|
||||
Ethereum,
|
||||
/// The chain contains Optimism configuration.
|
||||
OpStack,
|
||||
}
|
||||
|
||||
impl EngineApiKind {
|
||||
/// Returns true if this is the ethereum variant
|
||||
pub const fn is_ethereum(&self) -> bool {
|
||||
matches!(self, Self::Ethereum)
|
||||
}
|
||||
|
||||
/// Returns true if this is the ethereum variant
|
||||
pub const fn is_opstack(&self) -> bool {
|
||||
matches!(self, Self::OpStack)
|
||||
}
|
||||
}
|
||||
|
||||
/// The request variants that the engine API handler can receive.
|
||||
#[derive(Debug)]
|
||||
pub enum EngineApiRequest<T: EngineTypes> {
|
||||
|
||||
@@ -66,7 +66,10 @@ pub mod config;
|
||||
mod invalid_block_hook;
|
||||
mod metrics;
|
||||
mod persistence_state;
|
||||
use crate::{engine::EngineApiRequest, tree::metrics::EngineApiMetrics};
|
||||
use crate::{
|
||||
engine::{EngineApiKind, EngineApiRequest},
|
||||
tree::metrics::EngineApiMetrics,
|
||||
};
|
||||
pub use config::TreeConfig;
|
||||
pub use invalid_block_hook::{InvalidBlockHooks, NoopInvalidBlockHook};
|
||||
pub use persistence_state::PersistenceState;
|
||||
@@ -498,6 +501,8 @@ pub struct EngineApiTreeHandler<P, E, T: EngineTypes, Spec> {
|
||||
metrics: EngineApiMetrics,
|
||||
/// An invalid block hook.
|
||||
invalid_block_hook: Box<dyn InvalidBlockHook>,
|
||||
/// The engine API variant of this handler
|
||||
engine_kind: EngineApiKind,
|
||||
}
|
||||
|
||||
impl<P: Debug, E: Debug, T: EngineTypes + Debug, Spec: Debug> std::fmt::Debug
|
||||
@@ -519,6 +524,7 @@ impl<P: Debug, E: Debug, T: EngineTypes + Debug, Spec: Debug> std::fmt::Debug
|
||||
.field("config", &self.config)
|
||||
.field("metrics", &self.metrics)
|
||||
.field("invalid_block_hook", &format!("{:p}", self.invalid_block_hook))
|
||||
.field("engine_kind", &self.engine_kind)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -545,6 +551,7 @@ where
|
||||
persistence_state: PersistenceState,
|
||||
payload_builder: PayloadBuilderHandle<T>,
|
||||
config: TreeConfig,
|
||||
engine_kind: EngineApiKind,
|
||||
) -> Self {
|
||||
let (incoming_tx, incoming) = std::sync::mpsc::channel();
|
||||
|
||||
@@ -565,6 +572,7 @@ where
|
||||
metrics: Default::default(),
|
||||
incoming_tx,
|
||||
invalid_block_hook: Box::new(NoopInvalidBlockHook),
|
||||
engine_kind,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -589,6 +597,7 @@ where
|
||||
canonical_in_memory_state: CanonicalInMemoryState,
|
||||
config: TreeConfig,
|
||||
invalid_block_hook: Box<dyn InvalidBlockHook>,
|
||||
kind: EngineApiKind,
|
||||
) -> (Sender<FromEngine<EngineApiRequest<T>>>, UnboundedReceiver<EngineApiEvent>) {
|
||||
let best_block_number = provider.best_block_number().unwrap_or(0);
|
||||
let header = provider.sealed_header(best_block_number).ok().flatten().unwrap_or_default();
|
||||
@@ -618,6 +627,7 @@ where
|
||||
persistence_state,
|
||||
payload_builder,
|
||||
config,
|
||||
kind,
|
||||
);
|
||||
task.set_invalid_block_hook(invalid_block_hook);
|
||||
let incoming = task.incoming_tx.clone();
|
||||
@@ -1041,8 +1051,15 @@ where
|
||||
if let Ok(Some(canonical_header)) = self.find_canonical_header(state.head_block_hash) {
|
||||
debug!(target: "engine::tree", head = canonical_header.number, "fcu head block is already canonical");
|
||||
|
||||
// TODO(mattsse): for optimism we'd need to trigger a build job as well because on
|
||||
// Optimism, the proposers are allowed to reorg their own chain at will.
|
||||
// For OpStack the proposers are allowed to reorg their own chain at will, so we need to
|
||||
// always trigger a new payload job if requested.
|
||||
if self.engine_kind.is_opstack() {
|
||||
if let Some(attr) = attrs {
|
||||
debug!(target: "engine::tree", head = canonical_header.number, "handling payload attributes for canonical head");
|
||||
let updated = self.process_payload_attributes(attr, &canonical_header, state);
|
||||
return Ok(TreeOutcome::new(updated))
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Client software MAY skip an update of the forkchoice state and MUST NOT begin a
|
||||
// payload build process if `forkchoiceState.headBlockHash` references a `VALID`
|
||||
@@ -2680,6 +2697,7 @@ mod tests {
|
||||
PersistenceState::default(),
|
||||
payload_builder,
|
||||
TreeConfig::default(),
|
||||
EngineApiKind::Ethereum,
|
||||
);
|
||||
|
||||
let block_builder = TestBlockBuilder::default().with_chain_spec((*chain_spec).clone());
|
||||
|
||||
@@ -93,6 +93,10 @@ impl EthChainSpec for OpChainSpec {
|
||||
fn bootnodes(&self) -> Option<Vec<NodeRecord>> {
|
||||
self.inner.bootnodes()
|
||||
}
|
||||
|
||||
fn is_optimism(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Hardforks for OpChainSpec {
|
||||
|
||||
Reference in New Issue
Block a user