Skip to content
Open
Show file tree
Hide file tree
Changes from all 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",
})

// 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() {
w.pendingWorkBlock.Store(0)
continue
}

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 `\
// If block is already full, abort
if gp := w.current.gasPool; gp != nil && gp.Gas() < params.TxGas {
continue
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{}{}

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