From c553b1e86d8200effda90fff5711870fb25642d1 Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Wed, 11 Dec 2024 22:26:25 +0100 Subject: [PATCH] feat(builder): ethereum builder config (#13315) --- .../src/commands/debug_cmd/build_block.rs | 3 +- .../src/commands/debug_cmd/replay_engine.rs | 2 + crates/ethereum/node/Cargo.toml | 2 +- crates/ethereum/node/src/node.rs | 25 ++++++++++-- crates/ethereum/payload/src/config.rs | 22 +++++++++++ crates/ethereum/payload/src/lib.rs | 38 +++++++++++++------ crates/node/core/src/args/payload_builder.rs | 8 ++-- crates/node/core/src/version.rs | 13 +++++-- crates/optimism/payload/src/builder.rs | 10 ++--- crates/payload/basic/src/lib.rs | 23 ++--------- crates/payload/basic/src/stack.rs | 6 +-- examples/custom-engine-types/src/main.rs | 25 ++++++++---- .../custom-payload-builder/src/generator.rs | 3 +- examples/custom-payload-builder/src/main.rs | 9 +++-- 14 files changed, 120 insertions(+), 69 deletions(-) create mode 100644 crates/ethereum/payload/src/config.rs diff --git a/bin/reth/src/commands/debug_cmd/build_block.rs b/bin/reth/src/commands/debug_cmd/build_block.rs index 41a9d9f4f570..6aafa7e604c6 100644 --- a/bin/reth/src/commands/debug_cmd/build_block.rs +++ b/bin/reth/src/commands/debug_cmd/build_block.rs @@ -22,6 +22,7 @@ use reth_cli_commands::common::{AccessRights, CliNodeTypes, Environment, Environ use reth_cli_runner::CliContext; use reth_consensus::{Consensus, FullConsensus}; use reth_errors::RethResult; +use reth_ethereum_payload_builder::EthereumBuilderConfig; use reth_evm::execute::{BlockExecutorProvider, Executor}; use reth_execution_types::ExecutionOutcome; use reth_fs_util as fs; @@ -228,7 +229,6 @@ impl> Command { }; let payload_config = PayloadConfig::new( Arc::new(SealedHeader::new(best_block.header().clone(), best_block.hash())), - Bytes::default(), reth_payload_builder::EthPayloadBuilderAttributes::try_new( best_block.hash(), payload_attrs, @@ -247,6 +247,7 @@ impl> Command { let payload_builder = reth_ethereum_payload_builder::EthereumPayloadBuilder::new( EthEvmConfig::new(provider_factory.chain_spec()), + EthereumBuilderConfig::new(Default::default()), ); match payload_builder.try_build(args)? { diff --git a/bin/reth/src/commands/debug_cmd/replay_engine.rs b/bin/reth/src/commands/debug_cmd/replay_engine.rs index 4b98fc85d0b2..bd734f449a36 100644 --- a/bin/reth/src/commands/debug_cmd/replay_engine.rs +++ b/bin/reth/src/commands/debug_cmd/replay_engine.rs @@ -15,6 +15,7 @@ use reth_config::Config; use reth_consensus::FullConsensus; use reth_db::DatabaseEnv; use reth_engine_util::engine_store::{EngineMessageStore, StoredEngineApiMessage}; +use reth_ethereum_payload_builder::EthereumBuilderConfig; use reth_fs_util as fs; use reth_network::{BlockDownloaderProvider, NetworkHandle}; use reth_network_api::NetworkInfo; @@ -123,6 +124,7 @@ impl> Command { // Set up payload builder let payload_builder = reth_ethereum_payload_builder::EthereumPayloadBuilder::new( EthEvmConfig::new(provider_factory.chain_spec()), + EthereumBuilderConfig::new(Default::default()), ); let payload_generator = BasicPayloadJobGenerator::with_builder( diff --git a/crates/ethereum/node/Cargo.toml b/crates/ethereum/node/Cargo.toml index f5fe1dac234c..633705384a8b 100644 --- a/crates/ethereum/node/Cargo.toml +++ b/crates/ethereum/node/Cargo.toml @@ -27,6 +27,7 @@ reth-consensus.workspace = true reth-beacon-consensus.workspace = true reth-rpc.workspace = true reth-node-api.workspace = true +reth-node-core.workspace = true reth-chainspec.workspace = true reth-primitives.workspace = true reth-revm = { workspace = true, features = ["std"] } @@ -43,7 +44,6 @@ reth-chainspec.workspace = true reth-db.workspace = true reth-exex.workspace = true reth-node-api.workspace = true -reth-node-core.workspace = true reth-payload-primitives.workspace = true reth-e2e-test-utils.workspace = true reth-rpc-eth-api.workspace = true diff --git a/crates/ethereum/node/src/node.rs b/crates/ethereum/node/src/node.rs index 4d87be68f5dc..7b1ce7d899a4 100644 --- a/crates/ethereum/node/src/node.rs +++ b/crates/ethereum/node/src/node.rs @@ -8,6 +8,7 @@ use reth_chainspec::ChainSpec; use reth_ethereum_engine_primitives::{ EthBuiltPayload, EthPayloadAttributes, EthPayloadBuilderAttributes, }; +use reth_ethereum_payload_builder::EthereumBuilderConfig; use reth_evm::execute::BasicBlockExecutorProvider; use reth_evm_ethereum::execute::EthExecutionStrategyFactory; use reth_network::{EthNetworkPrimitives, NetworkHandle, PeersInfo}; @@ -23,6 +24,7 @@ use reth_node_builder::{ rpc::{EngineValidatorBuilder, RpcAddOns}, BuilderContext, Node, NodeAdapter, NodeComponentsBuilder, PayloadBuilderConfig, PayloadTypes, }; +use reth_node_core::version::default_extra_data_bytes; use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService}; use reth_primitives::{EthPrimitives, PooledTransactionsElement}; use reth_provider::{CanonStateSubscriptions, EthStorage}; @@ -228,9 +230,24 @@ where } /// A basic ethereum payload service. -#[derive(Debug, Default, Clone)] -#[non_exhaustive] -pub struct EthereumPayloadBuilder; +#[derive(Clone, Debug)] +pub struct EthereumPayloadBuilder { + /// Payload builder configuration. + config: EthereumBuilderConfig, +} + +impl Default for EthereumPayloadBuilder { + fn default() -> Self { + Self { config: EthereumBuilderConfig::new(default_extra_data_bytes()) } + } +} + +impl EthereumPayloadBuilder { + /// Create new ethereum payload builder. + pub const fn new(config: EthereumBuilderConfig) -> Self { + Self { config } + } +} impl EthereumPayloadBuilder { /// A helper method initializing [`PayloadBuilderService`] with the given EVM config. @@ -254,7 +271,7 @@ impl EthereumPayloadBuilder { >, { let payload_builder = - reth_ethereum_payload_builder::EthereumPayloadBuilder::new(evm_config); + reth_ethereum_payload_builder::EthereumPayloadBuilder::new(evm_config, self.config); let conf = ctx.payload_builder_config(); let payload_job_config = BasicPayloadJobGeneratorConfig::default() diff --git a/crates/ethereum/payload/src/config.rs b/crates/ethereum/payload/src/config.rs new file mode 100644 index 000000000000..deacce62f70b --- /dev/null +++ b/crates/ethereum/payload/src/config.rs @@ -0,0 +1,22 @@ +use alloy_primitives::Bytes; + +/// Settings for the Ethereum builder. +#[derive(PartialEq, Eq, Clone, Debug)] +pub struct EthereumBuilderConfig { + /// Block extra data. + pub extra_data: Bytes, +} + +impl EthereumBuilderConfig { + /// Create new payload builder config. + pub const fn new(extra_data: Bytes) -> Self { + Self { extra_data } + } +} + +impl EthereumBuilderConfig { + /// Returns owned extra data bytes for the block. + pub fn extra_data(&self) -> Bytes { + self.extra_data.clone() + } +} diff --git a/crates/ethereum/payload/src/lib.rs b/crates/ethereum/payload/src/lib.rs index 296ba6c2baf5..575b12659c76 100644 --- a/crates/ethereum/payload/src/lib.rs +++ b/crates/ethereum/payload/src/lib.rs @@ -50,21 +50,26 @@ use revm::{ use std::sync::Arc; use tracing::{debug, trace, warn}; +mod config; +pub use config::*; + type BestTransactionsIter = Box< dyn BestTransactions::Transaction>>>, >; /// Ethereum payload builder -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct EthereumPayloadBuilder { /// The type responsible for creating the evm. evm_config: EvmConfig, + /// Payload builder configuration. + builder_config: EthereumBuilderConfig, } impl EthereumPayloadBuilder { /// `EthereumPayloadBuilder` constructor. - pub const fn new(evm_config: EvmConfig) -> Self { - Self { evm_config } + pub const fn new(evm_config: EvmConfig, builder_config: EthereumBuilderConfig) -> Self { + Self { evm_config, builder_config } } } @@ -107,9 +112,14 @@ where .map_err(PayloadBuilderError::other)?; let pool = args.pool.clone(); - default_ethereum_payload(self.evm_config.clone(), args, cfg_env, block_env, |attributes| { - pool.best_transactions_with_attributes(attributes) - }) + default_ethereum_payload( + self.evm_config.clone(), + self.builder_config.clone(), + args, + cfg_env, + block_env, + |attributes| pool.best_transactions_with_attributes(attributes), + ) } fn build_empty_payload( @@ -133,9 +143,14 @@ where let pool = args.pool.clone(); - default_ethereum_payload(self.evm_config.clone(), args, cfg_env, block_env, |attributes| { - pool.best_transactions_with_attributes(attributes) - })? + default_ethereum_payload( + self.evm_config.clone(), + self.builder_config.clone(), + args, + cfg_env, + block_env, + |attributes| pool.best_transactions_with_attributes(attributes), + )? .into_payload() .ok_or_else(|| PayloadBuilderError::MissingPayload) } @@ -149,6 +164,7 @@ where #[inline] pub fn default_ethereum_payload( evm_config: EvmConfig, + builder_config: EthereumBuilderConfig, args: BuildArguments, initialized_cfg: CfgEnvWithHandlerCfg, initialized_block_env: BlockEnv, @@ -167,7 +183,7 @@ where let state = StateProviderDatabase::new(state_provider); let mut db = State::builder().with_database(cached_reads.as_db_mut(state)).with_bundle_update().build(); - let PayloadConfig { parent_header, extra_data, attributes } = config; + let PayloadConfig { parent_header, attributes } = config; debug!(target: "payload_builder", id=%attributes.id, parent_header = ?parent_header.hash(), parent_number = parent_header.number, "building new payload"); let mut cumulative_gas_used = 0; @@ -470,7 +486,7 @@ where gas_limit: block_gas_limit, difficulty: U256::ZERO, gas_used: cumulative_gas_used, - extra_data, + extra_data: builder_config.extra_data, parent_beacon_block_root: attributes.parent_beacon_block_root, blob_gas_used: blob_gas_used.map(Into::into), excess_blob_gas: excess_blob_gas.map(Into::into), diff --git a/crates/node/core/src/args/payload_builder.rs b/crates/node/core/src/args/payload_builder.rs index cd7ba7dccfb5..2bce2e8e700c 100644 --- a/crates/node/core/src/args/payload_builder.rs +++ b/crates/node/core/src/args/payload_builder.rs @@ -1,4 +1,4 @@ -use crate::{cli::config::PayloadBuilderConfig, version::default_extradata}; +use crate::{cli::config::PayloadBuilderConfig, version::default_extra_data}; use alloy_consensus::constants::MAXIMUM_EXTRA_DATA_SIZE; use alloy_eips::{eip1559::ETHEREUM_BLOCK_GAS_LIMIT, merge::SLOT_DURATION}; use clap::{ @@ -13,7 +13,7 @@ use std::{borrow::Cow, ffi::OsStr, time::Duration}; #[command(next_help_heading = "Builder")] pub struct PayloadBuilderArgs { /// Block extra data set by the payload builder. - #[arg(long = "builder.extradata", value_parser = ExtradataValueParser::default(), default_value_t = default_extradata())] + #[arg(long = "builder.extradata", value_parser = ExtradataValueParser::default(), default_value_t = default_extra_data())] pub extradata: String, /// Target gas ceiling for built blocks. @@ -40,7 +40,7 @@ pub struct PayloadBuilderArgs { impl Default for PayloadBuilderArgs { fn default() -> Self { Self { - extradata: default_extradata(), + extradata: default_extra_data(), max_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT, interval: Duration::from_secs(1), deadline: SLOT_DURATION, @@ -130,7 +130,7 @@ mod tests { #[test] fn test_default_extradata() { - let extradata = default_extradata(); + let extradata = default_extra_data(); let args = CommandParser::::parse_from([ "reth", "--builder.extradata", diff --git a/crates/node/core/src/version.rs b/crates/node/core/src/version.rs index 4bf2dc56f39b..ae729e7f2f04 100644 --- a/crates/node/core/src/version.rs +++ b/crates/node/core/src/version.rs @@ -1,4 +1,5 @@ //! Version information for reth. +use alloy_primitives::Bytes; use alloy_rpc_types_engine::ClientCode; use reth_db::ClientVersion; @@ -114,7 +115,7 @@ pub(crate) const P2P_CLIENT_VERSION: &str = const_format::concatcp!( env!("VERGEN_CARGO_TARGET_TRIPLE") ); -/// The default extradata used for payload building. +/// The default extra data used for payload building. /// /// - The latest version from Cargo.toml /// - The OS identifier @@ -124,10 +125,16 @@ pub(crate) const P2P_CLIENT_VERSION: &str = const_format::concatcp!( /// ```text /// reth/v{major}.{minor}.{patch}/{OS} /// ``` -pub fn default_extradata() -> String { +pub fn default_extra_data() -> String { format!("reth/v{}/{}", env!("CARGO_PKG_VERSION"), std::env::consts::OS) } +/// The default extra data in bytes. +/// See [`default_extra_data`]. +pub fn default_extra_data_bytes() -> Bytes { + Bytes::from(default_extra_data().as_bytes().to_vec()) +} + /// The default client version accessing the database. pub fn default_client_version() -> ClientVersion { ClientVersion { @@ -143,7 +150,7 @@ mod tests { #[test] fn assert_extradata_less_32bytes() { - let extradata = default_extradata(); + let extradata = default_extra_data(); assert!(extradata.len() <= 32, "extradata must be less than 32 bytes: {extradata}") } } diff --git a/crates/optimism/payload/src/builder.rs b/crates/optimism/payload/src/builder.rs index 27778da8f429..790da228cef3 100644 --- a/crates/optimism/payload/src/builder.rs +++ b/crates/optimism/payload/src/builder.rs @@ -195,11 +195,7 @@ where let (initialized_cfg, initialized_block_env) = self.cfg_and_block_env(&attributes, &parent).map_err(PayloadBuilderError::other)?; - let config = PayloadConfig { - parent_header: Arc::new(parent), - attributes, - extra_data: Default::default(), - }; + let config = PayloadConfig { parent_header: Arc::new(parent), attributes }; let ctx = OpPayloadBuilderCtx { evm_config: self.evm_config.clone(), chain_spec: client.chain_spec(), @@ -621,7 +617,7 @@ impl OpPayloadBuilderCtx { /// Returns the extra data for the block. /// - /// After holocene this extracts the extradata from the paylpad + /// After holocene this extracts the extra data from the payload pub fn extra_data(&self) -> Result { if self.is_holocene_active() { self.attributes() @@ -632,7 +628,7 @@ impl OpPayloadBuilderCtx { ) .map_err(PayloadBuilderError::other) } else { - Ok(self.config.extra_data.clone()) + Ok(Default::default()) } } diff --git a/crates/payload/basic/src/lib.rs b/crates/payload/basic/src/lib.rs index 8e9c06865d03..189b8a8c2f82 100644 --- a/crates/payload/basic/src/lib.rs +++ b/crates/payload/basic/src/lib.rs @@ -163,11 +163,7 @@ where .ok_or_else(|| PayloadBuilderError::MissingParentHeader(attributes.parent()))? }; - let config = PayloadConfig::new( - Arc::new(parent_header.clone()), - self.config.extradata.clone(), - attributes, - ); + let config = PayloadConfig::new(Arc::new(parent_header.clone()), attributes); let until = self.job_deadline(config.attributes.timestamp()); let deadline = Box::pin(tokio::time::sleep_until(until)); @@ -713,30 +709,17 @@ impl Drop for Cancelled { pub struct PayloadConfig { /// The parent header. pub parent_header: Arc, - /// Block extra data. - pub extra_data: Bytes, /// Requested attributes for the payload. pub attributes: Attributes, } -impl PayloadConfig { - /// Returns an owned instance of the [`PayloadConfig`]'s `extra_data` bytes. - pub fn extra_data(&self) -> Bytes { - self.extra_data.clone() - } -} - impl PayloadConfig where Attributes: PayloadBuilderAttributes, { /// Create new payload config. - pub const fn new( - parent_header: Arc, - extra_data: Bytes, - attributes: Attributes, - ) -> Self { - Self { parent_header, extra_data, attributes } + pub const fn new(parent_header: Arc, attributes: Attributes) -> Self { + Self { parent_header, attributes } } /// Returns the payload id. diff --git a/crates/payload/basic/src/stack.rs b/crates/payload/basic/src/stack.rs index 45a3f3b42448..77314d443912 100644 --- a/crates/payload/basic/src/stack.rs +++ b/crates/payload/basic/src/stack.rs @@ -204,7 +204,6 @@ where cached_reads: args.cached_reads.clone(), config: PayloadConfig { parent_header: args.config.parent_header.clone(), - extra_data: args.config.extra_data.clone(), attributes: left_attr.clone(), }, cancel: args.cancel.clone(), @@ -226,7 +225,6 @@ where cached_reads: args.cached_reads.clone(), config: PayloadConfig { parent_header: args.config.parent_header.clone(), - extra_data: args.config.extra_data.clone(), attributes: right_attr.clone(), }, cancel: args.cancel.clone(), @@ -252,16 +250,14 @@ where match config.attributes { Either::Left(left_attr) => { let left_config = PayloadConfig { - attributes: left_attr, parent_header: config.parent_header.clone(), - extra_data: config.extra_data.clone(), + attributes: left_attr, }; self.left.build_empty_payload(client, left_config).map(Either::Left) } Either::Right(right_attr) => { let right_config = PayloadConfig { parent_header: config.parent_header.clone(), - extra_data: config.extra_data.clone(), attributes: right_attr, }; self.right.build_empty_payload(client, right_config).map(Either::Right) diff --git a/examples/custom-engine-types/src/main.rs b/examples/custom-engine-types/src/main.rs index f30956d8f5cf..8437cf8d3c4d 100644 --- a/examples/custom-engine-types/src/main.rs +++ b/examples/custom-engine-types/src/main.rs @@ -46,12 +46,14 @@ use reth::{ }, tasks::TaskManager, transaction_pool::{PoolTransaction, TransactionPool}, + version::default_extra_data_bytes, }; use reth_basic_payload_builder::{ BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig, BuildArguments, BuildOutcome, PayloadBuilder, PayloadConfig, }; use reth_chainspec::{Chain, ChainSpec, ChainSpecProvider}; +use reth_ethereum_payload_builder::EthereumBuilderConfig; use reth_node_api::{ payload::{EngineApiMessageVersion, EngineObjectValidationError, PayloadOrAttributes}, validate_version_specific_fields, AddOnsContext, EngineTypes, EngineValidator, @@ -398,20 +400,21 @@ where args: BuildArguments, ) -> Result, PayloadBuilderError> { let BuildArguments { client, pool, cached_reads, config, cancel, best_payload } = args; - let PayloadConfig { parent_header, extra_data, attributes } = config; + let PayloadConfig { parent_header, attributes } = config; let chain_spec = client.chain_spec(); // This reuses the default EthereumPayloadBuilder to build the payload // but any custom logic can be implemented here - reth_ethereum_payload_builder::EthereumPayloadBuilder::new(EthEvmConfig::new( - chain_spec.clone(), - )) + reth_ethereum_payload_builder::EthereumPayloadBuilder::new( + EthEvmConfig::new(chain_spec.clone()), + EthereumBuilderConfig::new(default_extra_data_bytes()), + ) .try_build(BuildArguments { client, pool, cached_reads, - config: PayloadConfig { parent_header, extra_data, attributes: attributes.0 }, + config: PayloadConfig { parent_header, attributes: attributes.0 }, cancel, best_payload, }) @@ -422,10 +425,16 @@ where client: &Client, config: PayloadConfig, ) -> Result { - let PayloadConfig { parent_header, extra_data, attributes } = config; + let PayloadConfig { parent_header, attributes } = config; let chain_spec = client.chain_spec(); - >::build_empty_payload(&reth_ethereum_payload_builder::EthereumPayloadBuilder::new(EthEvmConfig::new(chain_spec.clone())),client, - PayloadConfig { parent_header, extra_data, attributes: attributes.0}) + >::build_empty_payload( + &reth_ethereum_payload_builder::EthereumPayloadBuilder::new( + EthEvmConfig::new(chain_spec.clone()), + EthereumBuilderConfig::new(default_extra_data_bytes()) + ), + client, + PayloadConfig { parent_header, attributes: attributes.0} + ) } } diff --git a/examples/custom-payload-builder/src/generator.rs b/examples/custom-payload-builder/src/generator.rs index da48a0754f9c..6620170fe897 100644 --- a/examples/custom-payload-builder/src/generator.rs +++ b/examples/custom-payload-builder/src/generator.rs @@ -1,6 +1,5 @@ use crate::job::EmptyBlockPayloadJob; use alloy_eips::BlockNumberOrTag; -use alloy_primitives::Bytes; use reth::{ providers::{BlockReaderIdExt, BlockSource, StateProviderFactory}, tasks::TaskSpawner, @@ -85,7 +84,7 @@ where let hash = parent_block.hash(); let header = SealedHeader::new(parent_block.header().clone(), hash); - let config = PayloadConfig::new(Arc::new(header), Bytes::default(), attributes); + let config = PayloadConfig::new(Arc::new(header), attributes); Ok(EmptyBlockPayloadJob { client: self.client.clone(), _pool: self.pool.clone(), diff --git a/examples/custom-payload-builder/src/main.rs b/examples/custom-payload-builder/src/main.rs index d7c42e341b59..6ae920378294 100644 --- a/examples/custom-payload-builder/src/main.rs +++ b/examples/custom-payload-builder/src/main.rs @@ -18,9 +18,11 @@ use reth::{ payload::PayloadBuilderHandle, providers::CanonStateSubscriptions, transaction_pool::{PoolTransaction, TransactionPool}, + version::default_extra_data_bytes, }; use reth_basic_payload_builder::BasicPayloadJobGeneratorConfig; use reth_chainspec::ChainSpec; +use reth_ethereum_payload_builder::EthereumBuilderConfig; use reth_node_api::NodeTypesWithEngine; use reth_node_ethereum::{node::EthereumAddOns, EthEngineTypes, EthEvmConfig, EthereumNode}; use reth_payload_builder::PayloadBuilderService; @@ -65,9 +67,10 @@ where pool, ctx.task_executor().clone(), payload_job_config, - reth_ethereum_payload_builder::EthereumPayloadBuilder::new(EthEvmConfig::new( - ctx.chain_spec(), - )), + reth_ethereum_payload_builder::EthereumPayloadBuilder::new( + EthEvmConfig::new(ctx.chain_spec()), + EthereumBuilderConfig::new(default_extra_data_bytes()), + ), ); let (payload_service, payload_builder) =