diff --git a/cmd/ronin/main.go b/cmd/ronin/main.go index ec4a20ee8e..be9015894e 100644 --- a/cmd/ronin/main.go +++ b/cmd/ronin/main.go @@ -136,6 +136,7 @@ var ( utils.MinerRecommitIntervalFlag, utils.MinerNoVerifyFlag, utils.MinerBlockProduceLeftoverFlag, + utils.MinerBlockSizeReserveFlag, utils.NATFlag, utils.NoDiscoverFlag, utils.DiscoveryV5Flag, diff --git a/cmd/ronin/usage.go b/cmd/ronin/usage.go index 149fb278b3..00eac30eb1 100644 --- a/cmd/ronin/usage.go +++ b/cmd/ronin/usage.go @@ -195,6 +195,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{ utils.MinerRecommitIntervalFlag, utils.MinerNoVerifyFlag, utils.MinerBlockProduceLeftoverFlag, + utils.MinerBlockSizeReserveFlag, }, }, { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 25c0607634..e851706dda 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -490,6 +490,11 @@ var ( Usage: "The interval block with transactions needs committing before empty block is produced", Value: ethconfig.Defaults.Miner.BlockProduceLeftOver, } + MinerBlockSizeReserveFlag = cli.Uint64Flag{ + Name: "miner.blocksizereserve", + Usage: "Reserved block size when committing transactions to block", + Value: ethconfig.Defaults.Miner.BlockSizeReserve, + } // Account settings UnlockedAccountFlag = cli.StringFlag{ Name: "unlock", @@ -1474,6 +1479,7 @@ func setMiner(ctx *cli.Context, cfg *miner.Config) { if ctx.GlobalIsSet(MinerBlockProduceLeftoverFlag.Name) { cfg.BlockProduceLeftOver = ctx.GlobalDuration(MinerBlockProduceLeftoverFlag.Name) } + cfg.BlockSizeReserve = ctx.GlobalUint64(MinerBlockSizeReserveFlag.Name) if ctx.GlobalIsSet(LegacyMinerGasTargetFlag.Name) { log.Warn("The generic --miner.gastarget flag is deprecated and will be removed in the future!") } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index dd28275c2c..70b7c7462d 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -90,6 +90,7 @@ var Defaults = Config{ GasPrice: big.NewInt(params.GWei), Recommit: 3 * time.Second, BlockProduceLeftOver: 200 * time.Millisecond, + BlockSizeReserve: 500000, }, TxPool: core.DefaultTxPoolConfig, RPCGasCap: 50000000, diff --git a/genesis/mainnet.json b/genesis/mainnet.json index ad8cb0b652..13ffb4ae01 100644 --- a/genesis/mainnet.json +++ b/genesis/mainnet.json @@ -25,7 +25,8 @@ "stakingContract": "0x545edb750eB8769C868429BE9586F5857A768758" }, "puffyBlock": 0, - "bubaBlock": 0 + "bubaBlock": 0, + "olekBlock": 24935500 }, "alloc": { "0x0000000000000000000000000000000000000011": { diff --git a/miner/miner.go b/miner/miner.go index a232c07ca2..8ab1dfa49e 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -54,6 +54,7 @@ type Config struct { Recommit time.Duration // The time interval for miner to re-create mining work. Noverify bool // Disable remote mining solution verification(only useful in ethash). BlockProduceLeftOver time.Duration + BlockSizeReserve uint64 } // Miner creates blocks and searches for proof-of-work values. @@ -227,6 +228,10 @@ func (miner *Miner) SetBlockProducerLeftover(interval time.Duration) { miner.worker.setBlockProducerLeftover(interval) } +func (miner *Miner) SetBlockSizeReserve(size uint64) { + miner.worker.setBlockSizeReserve(size) +} + // EnablePreseal turns on the preseal mining feature. It's enabled by default. // Note this function shouldn't be exposed to API, it's unnecessary for users // (miners) to actually know the underlying detail. It's only for outside project diff --git a/miner/worker.go b/miner/worker.go index 0a9ab96f4c..c0602fa4e4 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -81,18 +81,23 @@ const ( // recentMinedCacheLimit is the maximum blocks stored in recentMinedBlocks for avoiding // double sign a block recentMinedCacheLimit = 20 + + // maxBlockSize is the maximum size of block, this is used to abort transaction commit + // to block when the estimated block size is larger than this threshold + maxBlockSize = 10 * 1024 * 1024 // 10MB ) // environment is the worker's current environment and holds all of the current state information. type environment struct { signer types.Signer - state *state.StateDB // apply state changes here - ancestors mapset.Set // ancestor set (used for checking uncle parent validity) - family mapset.Set // family set (used for checking uncle invalidity) - uncles mapset.Set // uncle set - tcount int // tx count in cycle - gasPool *core.GasPool // available gas used to pack transactions + state *state.StateDB // apply state changes here + ancestors mapset.Set // ancestor set (used for checking uncle parent validity) + family mapset.Set // family set (used for checking uncle invalidity) + uncles mapset.Set // uncle set + tcount int // tx count in cycle + gasPool *core.GasPool // available gas used to pack transactions + estimatedBlockSize uint64 header *types.Header txs []*types.Transaction @@ -309,6 +314,12 @@ func (w *worker) setBlockProducerLeftover(interval time.Duration) { w.config.BlockProduceLeftOver = interval } +func (w *worker) setBlockSizeReserve(size uint64) { + w.mu.Lock() + defer w.mu.Unlock() + w.config.BlockSizeReserve = size +} + // disablePreseal disables pre-sealing mining feature func (w *worker) disablePreseal() { atomic.StoreUint32(&w.noempty, 1) @@ -755,12 +766,13 @@ func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error { state.StartPrefetcher("miner") env := &environment{ - signer: types.MakeSigner(w.chainConfig, header.Number), - state: state, - ancestors: mapset.NewSet(), - family: mapset.NewSet(), - uncles: mapset.NewSet(), - header: header, + signer: types.MakeSigner(w.chainConfig, header.Number), + state: state, + ancestors: mapset.NewSet(), + family: mapset.NewSet(), + uncles: mapset.NewSet(), + header: header, + estimatedBlockSize: 0, } // when 08 is processed ancestors contain 07 (quick block) for _, ancestor := range w.chain.GetBlocksFromHash(parent.Hash(), 7) { @@ -928,6 +940,12 @@ Loop: log.Trace("Not enough gas for further transactions", "have", w.current.gasPool, "want", params.TxGas) break } + + if w.current.estimatedBlockSize+w.config.BlockSizeReserve > maxBlockSize { + log.Debug("Estimated block size is too big", "estimated size", w.current.estimatedBlockSize) + break + } + // Retrieve the next transaction and abort if all done tx := txs.Peek() if tx == nil { @@ -970,6 +988,7 @@ Loop: // Everything ok, collect the logs and shift in the next transaction from the same account coalescedLogs = append(coalescedLogs, logs...) w.current.tcount++ + w.current.estimatedBlockSize += uint64(tx.Size()) txs.Shift() case errors.Is(err, core.ErrTxTypeNotSupported):