Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/cli/default_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ devfakeauthor = false
base-fee-change-denominator = 0
prefetch = false
prefetch-gaslimit-percent = 100
disable-pending-block = false

[jsonrpc]
ipcdisable = false
Expand Down
15 changes: 8 additions & 7 deletions docs/cli/example_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,14 @@ bp-rpc-endpoints = [ ] # Comma separated rpc endpoints of all block producers
lifetime = "3h0m0s" # Maximum amount of time non-executable transaction are queued

[miner]
mine = false # Enable mining
etherbase = "" # Public address for block mining rewards
extradata = "" # Block extra data set by the miner (default = client version)
gaslimit = 50000000 # Target gas ceiling for mined blocks (used when dynamic gas limit is disabled)
gasprice = "25000000000" # Minimum gas price for mining a transaction. Regardless the value set, it will be enforced to 25000000000 for all networks
recommit = "2m5s" # The time interval for miner to re-create mining work
commitinterrupt = true # Interrupt the current mining work when time is exceeded and create partial blocks
mine = false # Enable mining
etherbase = "" # Public address for block mining rewards
extradata = "" # Block extra data set by the miner (default = client version)
gaslimit = 50000000 # Target gas ceiling for mined blocks (used when dynamic gas limit is disabled)
gasprice = "25000000000" # Minimum gas price for mining a transaction. Regardless the value set, it will be enforced to 25000000000 for all networks
recommit = "2m5s" # The time interval for miner to re-create mining work
commitinterrupt = true # Interrupt the current mining work when time is exceeded and create partial blocks
disable-pending-block = false # Disable the pending block creation loop on non block producer nodes. When set, 'pending' block will be unavailable for RPC queries.
# Dynamic gas limit configuration
enableDynamicGasLimit = false # Enable dynamic gas limit adjustment based on base fee
gasLimitMin = 50000000 # Minimum gas limit when dynamic gas limit is enabled
Expand Down
2 changes: 2 additions & 0 deletions docs/cli/server.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@ The ```bor server``` command runs the Bor client.

- ```miner.blocktime```: The block time defined by the miner. Needs to be larger or equal to the consensus block time. If not set (default = 0), the miner will use the consensus block time. (default: 0s)

- ```miner.disable-pending-block```: Disable the pending block creation loop on non block producer nodes. When set, 'pending' block will be unavailable for RPC queries. (default: false)

- ```miner.enableDynamicGasLimit```: Enable dynamic gas limit adjustment based on base fee (default: false)

- ```miner.enableDynamicTargetGas```: Enable dynamic EIP-1559 target gas percentage adjustment based on base fee (post-Lisovo, mutually exclusive with enableDynamicGasLimit) (default: false)
Expand Down
8 changes: 7 additions & 1 deletion internal/cli/server/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,11 @@ type SealerConfig struct {

// PrefetchGasLimitPercent is the gas limit percentage for prefetching (e.g., 100 = 100%, 110 = 110%)
PrefetchGasLimitPercent uint64 `hcl:"prefetch-gaslimit-percent,optional" toml:"prefetch-gaslimit-percent,optional"`

// DisablePendingBlock disables the pending block creation loop on non block producer nodes. When
// set, 'pending' block will be unavailable for RPC queries. This won't apply for block producer
// nodes.
DisablePendingBlock bool `hcl:"disable-pending-block,optional" toml:"disable-pending-block,optional"`
}

type JsonRPCConfig struct {
Expand Down Expand Up @@ -866,7 +871,6 @@ func DefaultConfig() *Config {
StateScheme: "path",
Snapshot: true,
BorLogs: false,

TxPool: &TxPoolConfig{
Locals: []string{},
NoLocals: false,
Expand Down Expand Up @@ -906,6 +910,7 @@ func DefaultConfig() *Config {
PrefetchGasLimitPercent: 100,
TargetGasPercentage: 0, // Initialize to 0, will be set from CLI or remain 0 (meaning use default)
BaseFeeChangeDenominator: 0, // Initialize to 0, will be set from CLI or remain 0 (meaning use default)
DisablePendingBlock: false,
},
Gpo: &GpoConfig{
Blocks: 20,
Expand Down Expand Up @@ -1277,6 +1282,7 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*
n.Miner.BlockTime = c.Sealer.BlockTime
n.Miner.EnablePrefetch = c.Sealer.EnablePrefetch
n.Miner.PrefetchGasLimitPercent = c.Sealer.PrefetchGasLimitPercent
n.Miner.DisablePendingBlock = c.Sealer.DisablePendingBlock

// Validate prefetch gas limit percentage
if c.Sealer.EnablePrefetch && c.Sealer.PrefetchGasLimitPercent > 150 {
Expand Down
7 changes: 7 additions & 0 deletions internal/cli/server/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,13 @@ func (c *Command) Flags(config *Config) *flagset.Flagset {
Default: c.cliConfig.Sealer.TargetGasMaxPercentage,
Group: "Sealer",
})
f.BoolFlag(&flagset.BoolFlag{
Name: "miner.disable-pending-block",
Usage: "Disable the pending block creation loop on non block producer nodes. When set, 'pending' block will be unavailable for RPC queries.",
Value: &c.cliConfig.Sealer.DisablePendingBlock,
Default: c.cliConfig.Sealer.DisablePendingBlock,
Group: "Sealer",
Comment thread
manav2401 marked this conversation as resolved.
})

// ethstats
f.StringFlag(&flagset.StringFlag{
Expand Down
4 changes: 4 additions & 0 deletions miner/miner.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ type Config struct {
PendingFeeRecipient common.Address `toml:"-"` // Address for pending block rewards.
EnablePrefetch bool // Enable transaction prefetching from pool during block building
PrefetchGasLimitPercent uint64 // Gas limit percentage for prefetching (e.g., 100 = 100%, 110 = 110%)

DisablePendingBlock bool // Disable the pending block creation loop on non block producer nodes
}

// DefaultConfig contains default settings for miner.
Expand All @@ -89,6 +91,8 @@ var DefaultConfig = Config{
Recommit: 2 * time.Second,
EnablePrefetch: true,
PrefetchGasLimitPercent: 100, // 100% of header gas limit

DisablePendingBlock: false,
}

// Miner is the main object which takes care of submitting new work to consensus
Expand Down
10 changes: 9 additions & 1 deletion miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,14 @@
for {
select {
case req := <-w.newWorkCh:
// When DisablePendingBlock is set and the worker is not actively producing
// blocks (non-validator), skip commitWork entirely — its only purpose in
// that case is to maintain the pending block snapshot for RPC.
if w.config.DisablePendingBlock && !w.IsRunning() {
Comment thread
manav2401 marked this conversation as resolved.
Comment thread
manav2401 marked this conversation as resolved.
w.pendingWorkBlock.Store(0)
continue
Comment thread
manav2401 marked this conversation as resolved.
}

if w.chainConfig.ChainID.Cmp(params.BorMainnetChainConfig.ChainID) == 0 || w.chainConfig.ChainID.Cmp(params.MumbaiChainConfig.ChainID) == 0 || w.chainConfig.ChainID.Cmp(params.AmoyChainConfig.ChainID) == 0 {
if w.eth.PeerCount() > 0 || devFakeAuthor {
//nolint:contextcheck
Expand All @@ -849,10 +857,10 @@
// Apply transactions to the pending state if we're not sealing
//
// Note all transactions received may not be continuous with transactions
// already included in the current sealing block. These transactions will
// be automatically eliminated.
// nolint : nestif
if !w.IsRunning() && w.current != nil {
if !w.IsRunning() && !w.config.DisablePendingBlock && w.current != nil {

Check warning on line 863 in miner/worker.go

View check run for this annotation

Claude / Claude Code Review

DisablePendingBlock bypassed by Clique dev-mode else branch in txsCh handler

The `DisablePendingBlock` flag is bypassed in the `txsCh` handler's `else` branch: when `DisablePendingBlock=true` and `\!IsRunning()`, the guard at line 863 evaluates to false, causing fall-through into the else branch which contains an unguarded Clique Period=0 dev-mode path that calls `commitWork` unconditionally. On a non-running Clique dev-mode (Period=0) node with `DisablePendingBlock=true`, every incoming transaction event will still trigger pending snapshot creation. The fix is to add `\
Comment thread
manav2401 marked this conversation as resolved.
// If block is already full, abort
if gp := w.current.gasPool; gp != nil && gp.Gas() < params.TxGas {
continue
Comment thread
manav2401 marked this conversation as resolved.
Expand Down
42 changes: 42 additions & 0 deletions miner/worker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2967,3 +2967,45 @@ func TestDelayFlagOffByOne(t *testing.T) {
require.True(t, buggyDelayFlag(), "bug: last tx skipped, DAG hint incorrectly embedded")
require.False(t, fixedDelayFlag(), "fix: last tx detected, DAG hint suppressed")
}

// TestDisablePendingBlock validates if setting `DisablePendingBlock` affects the
// creation of pending block or not.
func TestDisablePendingBlock(t *testing.T) {
t.Parallel()

t.Run("pending block is nil when flag is enabled", func(t *testing.T) {
t.Parallel()

config := DefaultTestConfig()
config.DisablePendingBlock = true

w, _, cleanup := newTestWorker(t, config, ethashChainConfig, ethash.NewFaker(), rawdb.NewMemoryDatabase(), false, 0)
defer cleanup()

// Trigger the pending block build (non-validator path: worker is not started/running).
w.startCh <- struct{}{}

Comment thread
manav2401 marked this conversation as resolved.
require.Never(t, func() bool {
block, receipts, stateDB := w.pending()
return block != nil || receipts != nil || stateDB != nil
}, 500*time.Millisecond, 100*time.Millisecond, "pending block, receipts and state should be nil when DisablePendingBlock is true")
})

t.Run("pending block is created when flag is disabled", func(t *testing.T) {
t.Parallel()

config := DefaultTestConfig()
config.DisablePendingBlock = false

w, _, cleanup := newTestWorker(t, config, ethashChainConfig, ethash.NewFaker(), rawdb.NewMemoryDatabase(), false, 0)
defer cleanup()

// Trigger the pending block build (non-validator path: worker is not started/running).
w.startCh <- struct{}{}

require.Eventually(t, func() bool {
block, receipts, stateDB := w.pending()
return block != nil && receipts != nil && stateDB != nil
}, 2*time.Second, 100*time.Millisecond, "pending block, receipts and state should not be nil when DisablePendingBlock is false")
})
}
Loading