mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-02-09 22:45:57 -05:00
feat: make payload builder generic over attributes type (#5948)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
@@ -54,6 +54,8 @@ reth-prune.workspace = true
|
||||
reth-snapshot = { workspace = true, features = ["clap"] }
|
||||
reth-trie.workspace = true
|
||||
reth-nippy-jar.workspace = true
|
||||
reth-node-api.workspace = true
|
||||
reth-node-builder.workspace = true
|
||||
|
||||
# crypto
|
||||
alloy-rlp.workspace = true
|
||||
|
||||
@@ -18,6 +18,7 @@ use clap::{
|
||||
};
|
||||
use futures::TryFutureExt;
|
||||
use reth_network_api::{NetworkInfo, Peers};
|
||||
use reth_node_api::EngineTypes;
|
||||
use reth_provider::{
|
||||
AccountReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, ChangeSetReader,
|
||||
EvmEnvProvider, HeaderProvider, StateProviderFactory,
|
||||
@@ -224,7 +225,7 @@ impl RpcServerArgs {
|
||||
/// Returns the handles for the launched regular RPC server(s) (if any) and the server handle
|
||||
/// for the auth server that handles the `engine_` API that's accessed by the consensus
|
||||
/// layer.
|
||||
pub async fn start_servers<Reth, Engine, Conf>(
|
||||
pub async fn start_servers<Reth, Engine, Conf, EngineT: EngineTypes>(
|
||||
&self,
|
||||
components: &Reth,
|
||||
engine_api: Engine,
|
||||
@@ -233,7 +234,7 @@ impl RpcServerArgs {
|
||||
) -> eyre::Result<RethRpcServerHandles>
|
||||
where
|
||||
Reth: RethNodeComponents,
|
||||
Engine: EngineApiServer,
|
||||
Engine: EngineApiServer<EngineT>,
|
||||
Conf: RethNodeCommandConfig,
|
||||
{
|
||||
let auth_config = self.auth_server_config(jwt_secret)?;
|
||||
@@ -322,13 +323,13 @@ impl RpcServerArgs {
|
||||
}
|
||||
|
||||
/// Create Engine API server.
|
||||
pub async fn start_auth_server<Provider, Pool, Network, Tasks>(
|
||||
pub async fn start_auth_server<Provider, Pool, Network, Tasks, EngineT>(
|
||||
&self,
|
||||
provider: Provider,
|
||||
pool: Pool,
|
||||
network: Network,
|
||||
executor: Tasks,
|
||||
engine_api: EngineApi<Provider>,
|
||||
engine_api: EngineApi<Provider, EngineT>,
|
||||
jwt_secret: JwtSecret,
|
||||
) -> Result<AuthServerHandle, RpcError>
|
||||
where
|
||||
@@ -343,6 +344,7 @@ impl RpcServerArgs {
|
||||
Pool: TransactionPool + Clone + 'static,
|
||||
Network: NetworkInfo + Peers + Clone + 'static,
|
||||
Tasks: TaskSpawner + Clone + 'static,
|
||||
EngineT: EngineTypes + 'static,
|
||||
{
|
||||
let socket_address = SocketAddr::new(self.auth_addr, self.auth_port);
|
||||
|
||||
|
||||
@@ -59,6 +59,11 @@ use reth_interfaces::{
|
||||
};
|
||||
use reth_network::{NetworkBuilder, NetworkConfig, NetworkEvents, NetworkHandle, NetworkManager};
|
||||
use reth_network_api::{NetworkInfo, PeersInfo};
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
use reth_node_builder::EthEngineTypes;
|
||||
#[cfg(feature = "optimism")]
|
||||
use reth_node_builder::OptimismEngineTypes;
|
||||
use reth_payload_builder::PayloadBuilderHandle;
|
||||
use reth_primitives::{
|
||||
constants::eip4844::{LoadKzgSettingsError, MAINNET_KZG_TRUSTED_SETUP},
|
||||
kzg::KzgSettings,
|
||||
@@ -1109,8 +1114,24 @@ impl<DB: Database + DatabaseMetrics + DatabaseMetadata + 'static> NodeBuilderWit
|
||||
ext.on_components_initialized(&components)?;
|
||||
|
||||
debug!(target: "reth::cli", "Spawning payload builder service");
|
||||
let payload_builder =
|
||||
ext.spawn_payload_builder_service(&self.config.builder, &components)?;
|
||||
|
||||
// TODO: stateful node builder should handle this in with_payload_builder
|
||||
// Optimism's payload builder is implemented on the OptimismPayloadBuilder type.
|
||||
#[cfg(feature = "optimism")]
|
||||
let payload_builder = reth_optimism_payload_builder::OptimismPayloadBuilder::default()
|
||||
.set_compute_pending_block(self.config.builder.compute_pending_block);
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
let payload_builder: PayloadBuilderHandle<OptimismEngineTypes> =
|
||||
ext.spawn_payload_builder_service(&self.config.builder, &components, payload_builder)?;
|
||||
|
||||
// The default payload builder is implemented on the unit type.
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
let payload_builder = reth_ethereum_payload_builder::EthereumPayloadBuilder::default();
|
||||
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
let payload_builder: PayloadBuilderHandle<EthEngineTypes> =
|
||||
ext.spawn_payload_builder_service(&self.config.builder, &components, payload_builder)?;
|
||||
|
||||
let (consensus_engine_tx, mut consensus_engine_rx) = unbounded_channel();
|
||||
if let Some(store_path) = self.config.debug.engine_api_store.clone() {
|
||||
@@ -1279,7 +1300,7 @@ impl<DB: Database + DatabaseMetrics + DatabaseMetadata + 'static> NodeBuilderWit
|
||||
#[cfg(feature = "optimism")]
|
||||
if self.config.chain.is_optimism() && !self.config.rollup.enable_genesis_walkback {
|
||||
let client = rpc_server_handles.auth.http_client();
|
||||
reth_rpc_api::EngineApiClient::fork_choice_updated_v2(
|
||||
reth_rpc_api::EngineApiClient::<OptimismEngineTypes>::fork_choice_updated_v2(
|
||||
&client,
|
||||
reth_rpc_types::engine::ForkchoiceState {
|
||||
head_block_hash: head.hash,
|
||||
|
||||
@@ -5,7 +5,10 @@ use crate::cli::{
|
||||
config::{PayloadBuilderConfig, RethNetworkConfig, RethRpcConfig},
|
||||
};
|
||||
use clap::Args;
|
||||
use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig};
|
||||
use reth_basic_payload_builder::{
|
||||
BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig, PayloadBuilder,
|
||||
};
|
||||
use reth_node_api::EngineTypes;
|
||||
use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService};
|
||||
use reth_provider::CanonStateSubscriptions;
|
||||
use reth_tasks::TaskSpawner;
|
||||
@@ -125,14 +128,22 @@ pub trait RethNodeCommandConfig: fmt::Debug {
|
||||
///
|
||||
/// By default this spawns a [BasicPayloadJobGenerator] with the default configuration
|
||||
/// [BasicPayloadJobGeneratorConfig].
|
||||
fn spawn_payload_builder_service<Conf, Reth>(
|
||||
fn spawn_payload_builder_service<Conf, Reth, Builder, Engine>(
|
||||
&mut self,
|
||||
conf: &Conf,
|
||||
components: &Reth,
|
||||
) -> eyre::Result<PayloadBuilderHandle>
|
||||
payload_builder: Builder,
|
||||
) -> eyre::Result<PayloadBuilderHandle<Engine>>
|
||||
where
|
||||
Conf: PayloadBuilderConfig,
|
||||
Reth: RethNodeComponents,
|
||||
Engine: EngineTypes + 'static,
|
||||
Builder: PayloadBuilder<
|
||||
Reth::Pool,
|
||||
Reth::Provider,
|
||||
Attributes = Engine::PayloadBuilderAttributes,
|
||||
> + Unpin
|
||||
+ 'static,
|
||||
{
|
||||
let payload_job_config = BasicPayloadJobGeneratorConfig::default()
|
||||
.interval(conf.interval())
|
||||
@@ -145,15 +156,6 @@ pub trait RethNodeCommandConfig: fmt::Debug {
|
||||
#[cfg(feature = "optimism")]
|
||||
let payload_job_config = payload_job_config.extradata(Default::default());
|
||||
|
||||
// The default payload builder is implemented on the unit type.
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
let payload_builder = reth_ethereum_payload_builder::EthereumPayloadBuilder::default();
|
||||
|
||||
// Optimism's payload builder is implemented on the OptimismPayloadBuilder type.
|
||||
#[cfg(feature = "optimism")]
|
||||
let payload_builder = reth_optimism_payload_builder::OptimismPayloadBuilder::default()
|
||||
.set_compute_pending_block(conf.compute_pending_block());
|
||||
|
||||
let payload_generator = BasicPayloadJobGenerator::with_builder(
|
||||
components.provider(),
|
||||
components.pool(),
|
||||
@@ -315,18 +317,26 @@ impl<T: RethNodeCommandConfig> RethNodeCommandConfig for NoArgs<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn_payload_builder_service<Conf, Reth>(
|
||||
fn spawn_payload_builder_service<Conf, Reth, Builder, Engine>(
|
||||
&mut self,
|
||||
conf: &Conf,
|
||||
components: &Reth,
|
||||
) -> eyre::Result<PayloadBuilderHandle>
|
||||
payload_builder: Builder,
|
||||
) -> eyre::Result<PayloadBuilderHandle<Engine>>
|
||||
where
|
||||
Conf: PayloadBuilderConfig,
|
||||
Reth: RethNodeComponents,
|
||||
Engine: EngineTypes + 'static,
|
||||
Builder: PayloadBuilder<
|
||||
Reth::Pool,
|
||||
Reth::Provider,
|
||||
Attributes = Engine::PayloadBuilderAttributes,
|
||||
> + Unpin
|
||||
+ 'static,
|
||||
{
|
||||
self.inner_mut()
|
||||
.ok_or_else(|| eyre::eyre!("config value must be set"))?
|
||||
.spawn_payload_builder_service(conf, components)
|
||||
.spawn_payload_builder_service(conf, components, payload_builder)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,10 @@ use reth_blockchain_tree::{
|
||||
};
|
||||
use reth_db::{init_db, DatabaseEnv};
|
||||
use reth_interfaces::{consensus::Consensus, RethResult};
|
||||
use reth_payload_builder::{database::CachedReads, PayloadBuilderAttributes};
|
||||
use reth_node_api::PayloadBuilderAttributes;
|
||||
use reth_payload_builder::database::CachedReads;
|
||||
#[cfg(feature = "optimism")]
|
||||
use reth_payload_builder::OptimismPayloadBuilderAttributes;
|
||||
use reth_primitives::{
|
||||
constants::eip4844::{LoadKzgSettingsError, MAINNET_KZG_TRUSTED_SETUP},
|
||||
fs,
|
||||
@@ -34,6 +37,8 @@ use reth_provider::{
|
||||
ProviderFactory, StageCheckpointReader, StateProviderFactory,
|
||||
};
|
||||
use reth_revm::EvmProcessorFactory;
|
||||
#[cfg(feature = "optimism")]
|
||||
use reth_rpc_types::engine::OptimismPayloadAttributes;
|
||||
use reth_rpc_types::engine::{BlobsBundleV1, PayloadAttributes};
|
||||
use reth_transaction_pool::{
|
||||
blobstore::InMemoryBlobStore, BlobStore, EthPooledTransaction, PoolConfig, TransactionOrigin,
|
||||
@@ -42,6 +47,9 @@ use reth_transaction_pool::{
|
||||
use std::{path::PathBuf, str::FromStr, sync::Arc};
|
||||
use tracing::*;
|
||||
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
use reth_payload_builder::EthPayloadBuilderAttributes;
|
||||
|
||||
/// `reth debug build-block` command
|
||||
/// This debug routine requires that the node is positioned at the block before the target.
|
||||
/// The script will then parse the block and attempt to build a similar one.
|
||||
@@ -235,16 +243,31 @@ impl Command {
|
||||
suggested_fee_recipient: self.suggested_fee_recipient,
|
||||
// TODO: add support for withdrawals
|
||||
withdrawals: None,
|
||||
#[cfg(feature = "optimism")]
|
||||
optimism_payload_attributes: reth_rpc_types::engine::OptimismPayloadAttributes::default(
|
||||
),
|
||||
};
|
||||
#[cfg(feature = "optimism")]
|
||||
let payload_config = PayloadConfig::new(
|
||||
Arc::clone(&best_block),
|
||||
Bytes::default(),
|
||||
PayloadBuilderAttributes::try_new(best_block.hash, payload_attrs)?,
|
||||
OptimismPayloadBuilderAttributes::try_new(
|
||||
best_block.hash,
|
||||
OptimismPayloadAttributes {
|
||||
payload_attributes: payload_attrs,
|
||||
transactions: None,
|
||||
no_tx_pool: None,
|
||||
gas_limit: None,
|
||||
},
|
||||
)?,
|
||||
self.chain.clone(),
|
||||
);
|
||||
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
let payload_config = PayloadConfig::new(
|
||||
Arc::clone(&best_block),
|
||||
Bytes::default(),
|
||||
EthPayloadBuilderAttributes::try_new(best_block.hash, payload_attrs)?,
|
||||
self.chain.clone(),
|
||||
);
|
||||
|
||||
let args = BuildArguments::new(
|
||||
blockchain_db.clone(),
|
||||
transaction_pool,
|
||||
|
||||
@@ -21,7 +21,12 @@ use reth_db::{init_db, DatabaseEnv};
|
||||
use reth_interfaces::consensus::Consensus;
|
||||
use reth_network::NetworkHandle;
|
||||
use reth_network_api::NetworkInfo;
|
||||
use reth_payload_builder::PayloadBuilderService;
|
||||
use reth_node_api::EngineTypes;
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
use reth_node_builder::EthEngineTypes;
|
||||
#[cfg(feature = "optimism")]
|
||||
use reth_node_builder::OptimismEngineTypes;
|
||||
use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService};
|
||||
use reth_primitives::{
|
||||
fs::{self},
|
||||
ChainSpec,
|
||||
@@ -29,7 +34,7 @@ use reth_primitives::{
|
||||
use reth_provider::{providers::BlockchainProvider, CanonStateSubscriptions, ProviderFactory};
|
||||
use reth_revm::EvmProcessorFactory;
|
||||
use reth_rpc_types::{
|
||||
engine::{CancunPayloadFields, ForkchoiceState, PayloadAttributes},
|
||||
engine::{CancunPayloadFields, ForkchoiceState},
|
||||
ExecutionPayload,
|
||||
};
|
||||
use reth_stages::Pipeline;
|
||||
@@ -175,8 +180,17 @@ impl Command {
|
||||
self.chain.clone(),
|
||||
payload_builder,
|
||||
);
|
||||
let (payload_service, payload_builder) =
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
let (payload_service, payload_builder): (
|
||||
_,
|
||||
PayloadBuilderHandle<OptimismEngineTypes>,
|
||||
) = PayloadBuilderService::new(payload_generator, blockchain_db.canonical_state_stream());
|
||||
|
||||
#[cfg(not(feature = "optimism"))]
|
||||
let (payload_service, payload_builder): (_, PayloadBuilderHandle<EthEngineTypes>) =
|
||||
PayloadBuilderService::new(payload_generator, blockchain_db.canonical_state_stream());
|
||||
|
||||
ctx.task_executor.spawn_critical("payload builder service", Box::pin(payload_service));
|
||||
|
||||
// Configure the consensus engine
|
||||
@@ -245,8 +259,8 @@ impl Command {
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
enum StoredEngineApiMessage {
|
||||
ForkchoiceUpdated { state: ForkchoiceState, payload_attrs: Option<PayloadAttributes> },
|
||||
enum StoredEngineApiMessage<Attributes> {
|
||||
ForkchoiceUpdated { state: ForkchoiceState, payload_attrs: Option<Attributes> },
|
||||
NewPayload { payload: ExecutionPayload, cancun_fields: Option<CancunPayloadFields> },
|
||||
}
|
||||
|
||||
@@ -260,7 +274,14 @@ impl EngineApiStore {
|
||||
Self { path }
|
||||
}
|
||||
|
||||
fn on_message(&self, msg: &BeaconEngineMessage, received_at: SystemTime) -> eyre::Result<()> {
|
||||
fn on_message<Engine>(
|
||||
&self,
|
||||
msg: &BeaconEngineMessage<Engine>,
|
||||
received_at: SystemTime,
|
||||
) -> eyre::Result<()>
|
||||
where
|
||||
Engine: EngineTypes,
|
||||
{
|
||||
fs::create_dir_all(&self.path)?; // ensure that store path had been created
|
||||
let timestamp = received_at.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_millis();
|
||||
match msg {
|
||||
@@ -278,10 +299,12 @@ impl EngineApiStore {
|
||||
let filename = format!("{}-new_payload-{}.json", timestamp, payload.block_hash());
|
||||
fs::write(
|
||||
self.path.join(filename),
|
||||
serde_json::to_vec(&StoredEngineApiMessage::NewPayload {
|
||||
payload: payload.clone(),
|
||||
cancun_fields: cancun_fields.clone(),
|
||||
})?,
|
||||
serde_json::to_vec(
|
||||
&StoredEngineApiMessage::<Engine::PayloadAttributes>::NewPayload {
|
||||
payload: payload.clone(),
|
||||
cancun_fields: cancun_fields.clone(),
|
||||
},
|
||||
)?,
|
||||
)?;
|
||||
}
|
||||
// noop
|
||||
@@ -310,11 +333,14 @@ impl EngineApiStore {
|
||||
Ok(filenames_by_ts.into_iter().flat_map(|(_, paths)| paths))
|
||||
}
|
||||
|
||||
pub(crate) async fn intercept(
|
||||
pub(crate) async fn intercept<Engine>(
|
||||
self,
|
||||
mut rx: UnboundedReceiver<BeaconEngineMessage>,
|
||||
to_engine: UnboundedSender<BeaconEngineMessage>,
|
||||
) {
|
||||
mut rx: UnboundedReceiver<BeaconEngineMessage<Engine>>,
|
||||
to_engine: UnboundedSender<BeaconEngineMessage<Engine>>,
|
||||
) where
|
||||
Engine: EngineTypes,
|
||||
BeaconEngineMessage<Engine>: std::fmt::Debug,
|
||||
{
|
||||
loop {
|
||||
let Some(msg) = rx.recv().await else { break };
|
||||
if let Err(error) = self.on_message(&msg, SystemTime::now()) {
|
||||
|
||||
Reference in New Issue
Block a user