From d7e8ec61f09d57fa4bae52336b9f7bc549fdd9f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 22 Sep 2016 19:25:57 +0300 Subject: [PATCH] cmd, core, params: dynamic gas ceiling on heavy blocks --- cmd/geth/main.go | 1 + cmd/geth/usage.go | 1 + cmd/utils/flags.go | 9 ++++++++- core/block_validator.go | 11 ++++++++++- core/blockchain.go | 17 +++++++++++++++-- params/miner_strategy.go | 35 +++++++++++++++++++++++++++++++++++ params/protocol_params.go | 5 +---- 7 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 params/miner_strategy.go diff --git a/cmd/geth/main.go b/cmd/geth/main.go index a7b332d0ff..6606fbac6c 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -150,6 +150,7 @@ participating. utils.MiningGPUFlag, utils.AutoDAGFlag, utils.TargetGasLimitFlag, + utils.BlockTimeLimitFlag, utils.NATFlag, utils.NatspecEnabledFlag, utils.NoDiscoverFlag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index dc1788aad2..4bb7936669 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -126,6 +126,7 @@ var AppHelpFlagGroups = []flagGroup{ utils.AutoDAGFlag, utils.EtherbaseFlag, utils.TargetGasLimitFlag, + utils.BlockTimeLimitFlag, utils.GasPriceFlag, utils.ExtraDataFlag, }, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 3ab556a8fc..6ae3f26d44 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -180,9 +180,14 @@ var ( } TargetGasLimitFlag = cli.StringFlag{ Name: "targetgaslimit", - Usage: "Target gas limit sets the artificial target gas floor for the blocks to mine", + Usage: "Sets the artificial target gas floor for the blocks to mine", Value: params.GenesisGasLimit.String(), } + BlockTimeLimitFlag = cli.IntFlag{ + Name: "blocktimelimit", + Usage: "Time limit for processing a block after which to halve the hard gas limit", + Value: 5, + } AutoDAGFlag = cli.BoolFlag{ Name: "autodag", Usage: "Enable automatic DAG pregeneration", @@ -746,6 +751,8 @@ func SetupNetwork(ctx *cli.Context) { core.ExpDiffPeriod = big.NewInt(math.MaxInt64) } params.TargetGasLimit = common.String2Big(ctx.GlobalString(TargetGasLimitFlag.Name)) + params.CurrentGasCeil.Set(params.TargetGasLimit) + params.BlockTimeLimit = time.Duration(ctx.GlobalInt(BlockTimeLimitFlag.Name)) * time.Second } // MustMakeChainConfig reads the chain configuration from the database in ctx.Datadir. diff --git a/core/block_validator.go b/core/block_validator.go index e5bc6178b9..b06cbb3303 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -364,7 +364,6 @@ func CalcGasLimit(parent *types.Block) *big.Int { */ gl := new(big.Int).Sub(parent.GasLimit(), decay) gl = gl.Add(gl, contrib) - gl.Set(common.BigMax(gl, params.MinGasLimit)) // however, if we're now below the target (TargetGasLimit) we increase the // limit as much as we can (parentGasLimit / 1024 -1) @@ -372,5 +371,15 @@ func CalcGasLimit(parent *types.Block) *big.Int { gl.Add(parent.GasLimit(), decay) gl.Set(common.BigMin(gl, params.TargetGasLimit)) } + // If the gas limit performance ceiling is exceeded, mandatorilly decrease + params.CurrentGasCeilLock.Lock() + if gl.Cmp(params.CurrentGasCeil) > 0 { + gl.Sub(parent.GasLimit(), decay) + gl.Set(common.BigMax(gl, params.CurrentGasCeil)) + } + params.CurrentGasCeilLock.Unlock() + + // Make sure we never go below the minimum gas limit + gl.Set(common.BigMax(gl, params.MinGasLimit)) return gl } diff --git a/core/blockchain.go b/core/blockchain.go index 1fbcdfc6f7..179ccc1925 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -38,6 +38,7 @@ import ( "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" @@ -977,12 +978,24 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) { events = append(events, ChainSplitEvent{block, logs}) } stats.processed++ + + // Update the current gas limit (mining only) based on import times + params.CurrentGasCeilLock.Lock() + if time.Since(bstart) > params.BlockTimeLimit { + ceil := new(big.Int).Div(params.CurrentGasCeil, params.CurrentGasCeilCutDiv) + params.CurrentGasCeil.Set(common.BigMax(ceil, params.MinGasLimit)) + } else { + ceil := new(big.Int).Add(params.CurrentGasCeil, new(big.Int).Div(params.CurrentGasCeil, params.CurrentGasCeilIncDiv)) + limit := new(big.Int).Mul(chain[i].GasLimit(), big.NewInt(2)) + params.CurrentGasCeil.Set(common.BigMin(ceil, limit)) + } + glog.V(logger.Debug).Infof("block gas ceiling changed to %v", params.CurrentGasCeil) + params.CurrentGasCeilLock.Unlock() } if (stats.queued > 0 || stats.processed > 0 || stats.ignored > 0) && bool(glog.V(logger.Info)) { - tend := time.Since(tstart) start, end := chain[0], chain[len(chain)-1] - glog.Infof("imported %d block(s) (%d queued %d ignored) including %d txs in %v. #%v [%x / %x]\n", stats.processed, stats.queued, stats.ignored, txcount, tend, end.Number(), start.Hash().Bytes()[:4], end.Hash().Bytes()[:4]) + glog.Infof("imported %d block(s) (%d queued %d ignored) including %d txs in %v. #%v [%x / %x]\n", stats.processed, stats.queued, stats.ignored, txcount, time.Since(tstart), end.Number(), start.Hash().Bytes()[:4], end.Hash().Bytes()[:4]) } go self.postChainEvents(events, coalescedLogs) diff --git a/params/miner_strategy.go b/params/miner_strategy.go new file mode 100644 index 0000000000..c5c1cabfc0 --- /dev/null +++ b/params/miner_strategy.go @@ -0,0 +1,35 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package params + +import ( + "math/big" + "sync" + "time" +) + +var ( + GenesisGasLimit = big.NewInt(4712388) // Gas limit of the Genesis block. + TargetGasLimit = new(big.Int).Set(GenesisGasLimit) // The artificial target + BlockTimeLimit = 5 * time.Second // Block processing time limit to reduce gas after + + // Temp hack to get a dynamic gas limit in palace (clean up!!!) + CurrentGasCeil = new(big.Int).Set(GenesisGasLimit) + CurrentGasCeilCutDiv = big.NewInt(2) + CurrentGasCeilIncDiv = new(big.Int).Set(GasLimitBoundDivisor) + CurrentGasCeilLock sync.Mutex +) diff --git a/params/protocol_params.go b/params/protocol_params.go index 2dfc251b63..c1404cdffc 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -39,10 +39,7 @@ var ( CallStipend = big.NewInt(2300) // Free gas given at beginning of call. EcrecoverGas = big.NewInt(3000) // Sha256WordGas = big.NewInt(12) // - - MinGasLimit = big.NewInt(5000) // Minimum the gas limit may ever be. - GenesisGasLimit = big.NewInt(4712388) // Gas limit of the Genesis block. - TargetGasLimit = new(big.Int).Set(GenesisGasLimit) // The artificial target + MinGasLimit = big.NewInt(5000) // Minimum the gas limit may ever be. Sha3Gas = big.NewInt(30) // Once per SHA3 operation. Sha256Gas = big.NewInt(60) //