From e9577729f84dcf737c6ee2b999b55ccf34f360da Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Thu, 12 Dec 2024 17:29:33 +0100 Subject: [PATCH] fix(builder): desired block gas limit (#13351) --- Cargo.lock | 2 +- book/cli/reth/node.md | 4 +-- crates/ethereum/consensus/src/lib.rs | 8 ++--- crates/ethereum/evm/src/lib.rs | 2 +- crates/ethereum/node/Cargo.toml | 3 +- crates/ethereum/node/src/node.rs | 31 +++++-------------- crates/ethereum/payload/Cargo.toml | 1 + crates/ethereum/payload/src/config.rs | 27 +++++++++++++++- crates/ethereum/payload/src/lib.rs | 1 + crates/evm/src/lib.rs | 2 ++ crates/node/core/src/args/payload_builder.rs | 14 ++++----- crates/node/core/src/args/txpool.rs | 6 ++-- crates/node/core/src/cli/config.rs | 4 +-- crates/optimism/evm/src/lib.rs | 2 +- crates/optimism/payload/src/builder.rs | 1 + crates/primitives-traits/src/constants/mod.rs | 3 ++ .../rpc-eth-api/src/helpers/pending_block.rs | 1 + crates/rpc/rpc/Cargo.toml | 1 - crates/rpc/rpc/src/validation.rs | 3 +- 19 files changed, 66 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 21278d66f..151421261 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7626,6 +7626,7 @@ dependencies = [ "reth-payload-builder-primitives", "reth-payload-primitives", "reth-primitives", + "reth-primitives-traits", "reth-revm", "reth-storage-api", "reth-transaction-pool", @@ -8962,7 +8963,6 @@ dependencies = [ "reth-consensus-common", "reth-engine-primitives", "reth-errors", - "reth-ethereum-consensus", "reth-evm", "reth-evm-ethereum", "reth-network-api", diff --git a/book/cli/reth/node.md b/book/cli/reth/node.md index cf05ae66e..685426ed6 100644 --- a/book/cli/reth/node.md +++ b/book/cli/reth/node.md @@ -458,7 +458,7 @@ TxPool: [default: 7] - --txpool.gas-limit + --txpool.gas-limit The default enforced gas limit for transactions entering the pool [default: 30000000] @@ -514,7 +514,7 @@ Builder: [default: reth//] --builder.gaslimit - Target gas ceiling for built blocks + Target gas limit for built blocks [default: 30000000] diff --git a/crates/ethereum/consensus/src/lib.rs b/crates/ethereum/consensus/src/lib.rs index 2eef91886..35c36daa9 100644 --- a/crates/ethereum/consensus/src/lib.rs +++ b/crates/ethereum/consensus/src/lib.rs @@ -22,12 +22,12 @@ use reth_consensus_common::validation::{ validate_header_base_fee, validate_header_extradata, validate_header_gas, }; use reth_primitives::{BlockWithSenders, NodePrimitives, Receipt, SealedBlock, SealedHeader}; -use reth_primitives_traits::{constants::MINIMUM_GAS_LIMIT, BlockBody}; +use reth_primitives_traits::{ + constants::{GAS_LIMIT_BOUND_DIVISOR, MINIMUM_GAS_LIMIT}, + BlockBody, +}; use std::{fmt::Debug, sync::Arc, time::SystemTime}; -/// The bound divisor of the gas limit, used in update calculations. -pub const GAS_LIMIT_BOUND_DIVISOR: u64 = 1024; - mod validation; pub use validation::validate_block_post_execution; diff --git a/crates/ethereum/evm/src/lib.rs b/crates/ethereum/evm/src/lib.rs index 509b61cb2..3e0533440 100644 --- a/crates/ethereum/evm/src/lib.rs +++ b/crates/ethereum/evm/src/lib.rs @@ -154,7 +154,7 @@ impl ConfigureEvmEnv for EthEvmConfig { self.chain_spec.base_fee_params_at_timestamp(attributes.timestamp), ); - let mut gas_limit = U256::from(parent.gas_limit); + let mut gas_limit = U256::from(attributes.gas_limit); // If we are on the London fork boundary, we need to multiply the parent's gas limit by the // elasticity multiplier to get the new gas limit. diff --git a/crates/ethereum/node/Cargo.toml b/crates/ethereum/node/Cargo.toml index 633705384..0e7f60581 100644 --- a/crates/ethereum/node/Cargo.toml +++ b/crates/ethereum/node/Cargo.toml @@ -27,7 +27,6 @@ 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 +42,7 @@ eyre.workspace = true 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 7b1ce7d89..51b5abbe4 100644 --- a/crates/ethereum/node/src/node.rs +++ b/crates/ethereum/node/src/node.rs @@ -1,7 +1,5 @@ //! Ethereum Node types config. -use std::sync::Arc; - use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig}; use reth_beacon_consensus::EthBeaconConsensus; use reth_chainspec::ChainSpec; @@ -24,7 +22,6 @@ 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}; @@ -35,6 +32,7 @@ use reth_transaction_pool::{ TransactionValidationTaskExecutor, }; use reth_trie_db::MerklePatriciaTrie; +use std::sync::Arc; use crate::{EthEngineTypes, EthEvmConfig}; @@ -230,24 +228,9 @@ where } /// A basic ethereum payload service. -#[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 } - } -} +#[derive(Clone, Default, Debug)] +#[non_exhaustive] +pub struct EthereumPayloadBuilder; impl EthereumPayloadBuilder { /// A helper method initializing [`PayloadBuilderService`] with the given EVM config. @@ -270,9 +253,11 @@ impl EthereumPayloadBuilder { PayloadBuilderAttributes = EthPayloadBuilderAttributes, >, { - let payload_builder = - reth_ethereum_payload_builder::EthereumPayloadBuilder::new(evm_config, self.config); let conf = ctx.payload_builder_config(); + let payload_builder = reth_ethereum_payload_builder::EthereumPayloadBuilder::new( + evm_config, + EthereumBuilderConfig::new(conf.extradata_bytes()).with_gas_limit(conf.gas_limit()), + ); let payload_job_config = BasicPayloadJobGeneratorConfig::default() .interval(conf.interval()) diff --git a/crates/ethereum/payload/Cargo.toml b/crates/ethereum/payload/Cargo.toml index bec0b094c..dd4a5f948 100644 --- a/crates/ethereum/payload/Cargo.toml +++ b/crates/ethereum/payload/Cargo.toml @@ -14,6 +14,7 @@ workspace = true [dependencies] # reth reth-primitives.workspace = true +reth-primitives-traits.workspace = true reth-revm.workspace = true reth-transaction-pool.workspace = true reth-payload-builder.workspace = true diff --git a/crates/ethereum/payload/src/config.rs b/crates/ethereum/payload/src/config.rs index deacce62f..0e625d557 100644 --- a/crates/ethereum/payload/src/config.rs +++ b/crates/ethereum/payload/src/config.rs @@ -1,16 +1,26 @@ +use alloy_eips::eip1559::ETHEREUM_BLOCK_GAS_LIMIT; use alloy_primitives::Bytes; +use reth_primitives_traits::constants::GAS_LIMIT_BOUND_DIVISOR; /// Settings for the Ethereum builder. #[derive(PartialEq, Eq, Clone, Debug)] pub struct EthereumBuilderConfig { /// Block extra data. pub extra_data: Bytes, + /// Desired gas limit. + pub desired_gas_limit: u64, } impl EthereumBuilderConfig { /// Create new payload builder config. pub const fn new(extra_data: Bytes) -> Self { - Self { extra_data } + Self { extra_data, desired_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT } + } + + /// Set desired gas limit. + pub const fn with_gas_limit(mut self, desired_gas_limit: u64) -> Self { + self.desired_gas_limit = desired_gas_limit; + self } } @@ -19,4 +29,19 @@ impl EthereumBuilderConfig { pub fn extra_data(&self) -> Bytes { self.extra_data.clone() } + + /// Returns the gas limit for the next block based + /// on parent and desired gas limits. + pub fn gas_limit(&self, parent_gas_limit: u64) -> u64 { + calculate_block_gas_limit(parent_gas_limit, self.desired_gas_limit) + } +} + +/// Calculate the gas limit for the next block based on parent and desired gas limits. +/// Ref: +pub fn calculate_block_gas_limit(parent_gas_limit: u64, desired_gas_limit: u64) -> u64 { + let delta = (parent_gas_limit / GAS_LIMIT_BOUND_DIVISOR).saturating_sub(1); + let min_gas_limit = parent_gas_limit - delta; + let max_gas_limit = parent_gas_limit + delta; + desired_gas_limit.clamp(min_gas_limit, max_gas_limit) } diff --git a/crates/ethereum/payload/src/lib.rs b/crates/ethereum/payload/src/lib.rs index 757b75018..bc8f05cbf 100644 --- a/crates/ethereum/payload/src/lib.rs +++ b/crates/ethereum/payload/src/lib.rs @@ -88,6 +88,7 @@ where timestamp: config.attributes.timestamp(), suggested_fee_recipient: config.attributes.suggested_fee_recipient(), prev_randao: config.attributes.prev_randao(), + gas_limit: self.builder_config.gas_limit(parent.gas_limit), }; self.evm_config.next_cfg_and_block_env(parent, next_attributes) } diff --git a/crates/evm/src/lib.rs b/crates/evm/src/lib.rs index 29f6d7c65..ce3f02fe1 100644 --- a/crates/evm/src/lib.rs +++ b/crates/evm/src/lib.rs @@ -231,6 +231,8 @@ pub struct NextBlockEnvAttributes { pub suggested_fee_recipient: Address, /// The randomness value for the next block. pub prev_randao: B256, + /// Block gas limit. + pub gas_limit: u64, } /// Function hook that allows to modify a transaction environment. diff --git a/crates/node/core/src/args/payload_builder.rs b/crates/node/core/src/args/payload_builder.rs index 2bce2e8e7..c5ef0d7f3 100644 --- a/crates/node/core/src/args/payload_builder.rs +++ b/crates/node/core/src/args/payload_builder.rs @@ -16,9 +16,9 @@ pub struct PayloadBuilderArgs { #[arg(long = "builder.extradata", value_parser = ExtradataValueParser::default(), default_value_t = default_extra_data())] pub extradata: String, - /// Target gas ceiling for built blocks. - #[arg(long = "builder.gaslimit", default_value = "30000000", value_name = "GAS_LIMIT")] - pub max_gas_limit: u64, + /// Target gas limit for built blocks. + #[arg(long = "builder.gaslimit", default_value_t = ETHEREUM_BLOCK_GAS_LIMIT, value_name = "GAS_LIMIT")] + pub gas_limit: u64, /// The interval at which the job should build a new payload after the last. /// @@ -41,7 +41,7 @@ impl Default for PayloadBuilderArgs { fn default() -> Self { Self { extradata: default_extra_data(), - max_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT, + gas_limit: ETHEREUM_BLOCK_GAS_LIMIT, interval: Duration::from_secs(1), deadline: SLOT_DURATION, max_payload_tasks: 3, @@ -62,8 +62,8 @@ impl PayloadBuilderConfig for PayloadBuilderArgs { self.deadline } - fn max_gas_limit(&self) -> u64 { - self.max_gas_limit + fn gas_limit(&self) -> u64 { + self.gas_limit } fn max_payload_tasks(&self) -> usize { @@ -129,7 +129,7 @@ mod tests { } #[test] - fn test_default_extradata() { + fn test_default_extra_data() { let extradata = default_extra_data(); let args = CommandParser::::parse_from([ "reth", diff --git a/crates/node/core/src/args/txpool.rs b/crates/node/core/src/args/txpool.rs index a8ea1d9cd..2b69d6317 100644 --- a/crates/node/core/src/args/txpool.rs +++ b/crates/node/core/src/args/txpool.rs @@ -52,7 +52,7 @@ pub struct TxPoolArgs { /// The default enforced gas limit for transactions entering the pool #[arg(long = "txpool.gas-limit", default_value_t = ETHEREUM_BLOCK_GAS_LIMIT)] - pub gas_limit: u64, + pub enforced_gas_limit: u64, /// Price bump percentage to replace an already existing blob transaction #[arg(long = "blobpool.pricebump", default_value_t = REPLACE_BLOB_PRICE_BUMP)] @@ -105,7 +105,7 @@ impl Default for TxPoolArgs { max_account_slots: TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER, price_bump: DEFAULT_PRICE_BUMP, minimal_protocol_basefee: MIN_PROTOCOL_BASE_FEE, - gas_limit: ETHEREUM_BLOCK_GAS_LIMIT, + enforced_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT, blob_transaction_price_bump: REPLACE_BLOB_PRICE_BUMP, max_tx_input_bytes: DEFAULT_MAX_TX_INPUT_BYTES, max_cached_entries: DEFAULT_MAX_CACHED_BLOBS, @@ -151,7 +151,7 @@ impl RethTransactionPoolConfig for TxPoolArgs { replace_blob_tx_price_bump: self.blob_transaction_price_bump, }, minimal_protocol_basefee: self.minimal_protocol_basefee, - gas_limit: self.gas_limit, + gas_limit: self.enforced_gas_limit, pending_tx_listener_buffer_size: self.pending_tx_listener_buffer_size, new_tx_listener_buffer_size: self.new_tx_listener_buffer_size, max_new_pending_txs_notifications: self.max_new_pending_txs_notifications, diff --git a/crates/node/core/src/cli/config.rs b/crates/node/core/src/cli/config.rs index 27325632d..e3b542c0b 100644 --- a/crates/node/core/src/cli/config.rs +++ b/crates/node/core/src/cli/config.rs @@ -24,8 +24,8 @@ pub trait PayloadBuilderConfig { /// The deadline for when the payload builder job should resolve. fn deadline(&self) -> Duration; - /// Target gas ceiling for built blocks. - fn max_gas_limit(&self) -> u64; + /// Target gas limit for built blocks. + fn gas_limit(&self) -> u64; /// Maximum number of tasks to spawn for building a payload. fn max_payload_tasks(&self) -> usize; diff --git a/crates/optimism/evm/src/lib.rs b/crates/optimism/evm/src/lib.rs index 7424379f5..740eb92e6 100644 --- a/crates/optimism/evm/src/lib.rs +++ b/crates/optimism/evm/src/lib.rs @@ -157,7 +157,7 @@ impl ConfigureEvmEnv for OpEvmConfig { timestamp: U256::from(attributes.timestamp), difficulty: U256::ZERO, prevrandao: Some(attributes.prev_randao), - gas_limit: U256::from(parent.gas_limit), + gas_limit: U256::from(attributes.gas_limit), // calculate basefee based on parent block's gas usage basefee: self.chain_spec.next_block_base_fee(parent, attributes.timestamp)?, // calculate excess gas based on parent block's blob gas usage diff --git a/crates/optimism/payload/src/builder.rs b/crates/optimism/payload/src/builder.rs index 790da228c..0af6832f6 100644 --- a/crates/optimism/payload/src/builder.rs +++ b/crates/optimism/payload/src/builder.rs @@ -175,6 +175,7 @@ where timestamp: attributes.timestamp(), suggested_fee_recipient: attributes.suggested_fee_recipient(), prev_randao: attributes.prev_randao(), + gas_limit: attributes.gas_limit.unwrap_or(parent.gas_limit), }; self.evm_config.next_cfg_and_block_env(parent, next_attributes) } diff --git a/crates/primitives-traits/src/constants/mod.rs b/crates/primitives-traits/src/constants/mod.rs index e927ed3a7..9af3feb9d 100644 --- a/crates/primitives-traits/src/constants/mod.rs +++ b/crates/primitives-traits/src/constants/mod.rs @@ -10,6 +10,9 @@ pub const RETH_CLIENT_VERSION: &str = concat!("reth/v", env!("CARGO_PKG_VERSION" /// Minimum gas limit allowed for transactions. pub const MINIMUM_GAS_LIMIT: u64 = 5000; +/// The bound divisor of the gas limit, used in update calculations. +pub const GAS_LIMIT_BOUND_DIVISOR: u64 = 1024; + /// The number of blocks to unwind during a reorg that already became a part of canonical chain. /// /// In reality, the node can end up in this particular situation very rarely. It would happen only diff --git a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs index af05eeaef..ff07fbdee 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/pending_block.rs @@ -116,6 +116,7 @@ pub trait LoadPendingBlock: timestamp: latest.timestamp() + 12, suggested_fee_recipient: latest.beneficiary(), prev_randao: B256::random(), + gas_limit: latest.gas_limit(), }, ) .map_err(RethError::other) diff --git a/crates/rpc/rpc/Cargo.toml b/crates/rpc/rpc/Cargo.toml index 14519860e..70cef2fcb 100644 --- a/crates/rpc/rpc/Cargo.toml +++ b/crates/rpc/rpc/Cargo.toml @@ -20,7 +20,6 @@ reth-rpc-api.workspace = true reth-rpc-eth-api.workspace = true reth-engine-primitives.workspace = true reth-errors.workspace = true -reth-ethereum-consensus.workspace = true reth-provider.workspace = true reth-transaction-pool.workspace = true reth-network-api.workspace = true diff --git a/crates/rpc/rpc/src/validation.rs b/crates/rpc/rpc/src/validation.rs index a7042126c..eb77e7a93 100644 --- a/crates/rpc/rpc/src/validation.rs +++ b/crates/rpc/rpc/src/validation.rs @@ -16,10 +16,9 @@ use reth_chainspec::{ChainSpecProvider, EthereumHardforks}; use reth_consensus::{Consensus, FullConsensus, PostExecutionInput}; use reth_engine_primitives::PayloadValidator; use reth_errors::{BlockExecutionError, ConsensusError, ProviderError}; -use reth_ethereum_consensus::GAS_LIMIT_BOUND_DIVISOR; use reth_evm::execute::{BlockExecutorProvider, Executor}; use reth_primitives::{GotExpected, NodePrimitives, SealedBlockWithSenders, SealedHeader}; -use reth_primitives_traits::{Block as _, BlockBody}; +use reth_primitives_traits::{constants::GAS_LIMIT_BOUND_DIVISOR, Block as _, BlockBody}; use reth_provider::{ BlockExecutionInput, BlockExecutionOutput, BlockReaderIdExt, StateProviderFactory, };