Skip to content

Commit

Permalink
Governable block gas limit (#522)
Browse files Browse the repository at this point in the history
  • Loading branch information
mrsmkl authored and Asa Oines committed Nov 7, 2019
1 parent 7ae61e4 commit 8d79a06
Show file tree
Hide file tree
Showing 15 changed files with 84 additions and 74 deletions.
3 changes: 3 additions & 0 deletions build/ci.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,9 @@ func buildFlags(env build.Environment) (flags []string) {
}
if runtime.GOOS == "darwin" {
ld = append(ld, "-s")
} else {
ld = append(ld, "-extldflags")
ld = append(ld, "-pthread")
}

if len(ld) > 0 {
Expand Down
50 changes: 21 additions & 29 deletions cmd/puppeth/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,8 @@ type alethGenesisSpec struct {
EIP158ForkBlock hexutil.Uint64 `json:"EIP158ForkBlock"`
ByzantiumForkBlock hexutil.Uint64 `json:"byzantiumForkBlock"`
ConstantinopleForkBlock hexutil.Uint64 `json:"constantinopleForkBlock"`
MinGasLimit hexutil.Uint64 `json:"minGasLimit"`
MaxGasLimit hexutil.Uint64 `json:"maxGasLimit"`
TieBreakingGas bool `json:"tieBreakingGas"`
GasLimitBoundDivisor math2.HexOrDecimal64 `json:"gasLimitBoundDivisor"`
MinimumDifficulty *hexutil.Big `json:"minimumDifficulty"`
DifficultyBoundDivisor *math2.HexOrDecimal256 `json:"difficultyBoundDivisor"`
DurationLimit *math2.HexOrDecimal256 `json:"durationLimit"`
Expand Down Expand Up @@ -124,11 +122,9 @@ func newAlethGenesisSpec(network string, genesis *core.Genesis) (*alethGenesisSp
spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64())
spec.Params.ChainID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64())
spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize)
spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit)
spec.Params.MaxGasLimit = (hexutil.Uint64)(math.MaxInt64)
spec.Params.MinimumDifficulty = (*hexutil.Big)(params.MinimumDifficulty)
spec.Params.DifficultyBoundDivisor = (*math2.HexOrDecimal256)(params.DifficultyBoundDivisor)
spec.Params.GasLimitBoundDivisor = (math2.HexOrDecimal64)(params.GasLimitBoundDivisor)
spec.Params.DurationLimit = (*math2.HexOrDecimal256)(params.DurationLimit)
spec.Params.BlockReward = (*hexutil.Big)(ethash.FrontierBlockReward)

Expand Down Expand Up @@ -223,29 +219,27 @@ type parityChainSpec struct {
} `json:"engine"`

Params struct {
AccountStartNonce hexutil.Uint64 `json:"accountStartNonce"`
MaximumExtraDataSize hexutil.Uint64 `json:"maximumExtraDataSize"`
MinGasLimit hexutil.Uint64 `json:"minGasLimit"`
GasLimitBoundDivisor math2.HexOrDecimal64 `json:"gasLimitBoundDivisor"`
NetworkID hexutil.Uint64 `json:"networkID"`
ChainID hexutil.Uint64 `json:"chainID"`
MaxCodeSize hexutil.Uint64 `json:"maxCodeSize"`
MaxCodeSizeTransition hexutil.Uint64 `json:"maxCodeSizeTransition"`
EIP98Transition hexutil.Uint64 `json:"eip98Transition"`
EIP150Transition hexutil.Uint64 `json:"eip150Transition"`
EIP160Transition hexutil.Uint64 `json:"eip160Transition"`
EIP161abcTransition hexutil.Uint64 `json:"eip161abcTransition"`
EIP161dTransition hexutil.Uint64 `json:"eip161dTransition"`
EIP155Transition hexutil.Uint64 `json:"eip155Transition"`
EIP140Transition hexutil.Uint64 `json:"eip140Transition"`
EIP211Transition hexutil.Uint64 `json:"eip211Transition"`
EIP214Transition hexutil.Uint64 `json:"eip214Transition"`
EIP658Transition hexutil.Uint64 `json:"eip658Transition"`
EIP145Transition hexutil.Uint64 `json:"eip145Transition"`
EIP1014Transition hexutil.Uint64 `json:"eip1014Transition"`
EIP1052Transition hexutil.Uint64 `json:"eip1052Transition"`
EIP1283Transition hexutil.Uint64 `json:"eip1283Transition"`
EIP1283DisableTransition hexutil.Uint64 `json:"eip1283DisableTransition"`
AccountStartNonce hexutil.Uint64 `json:"accountStartNonce"`
MaximumExtraDataSize hexutil.Uint64 `json:"maximumExtraDataSize"`
NetworkID hexutil.Uint64 `json:"networkID"`
ChainID hexutil.Uint64 `json:"chainID"`
MaxCodeSize hexutil.Uint64 `json:"maxCodeSize"`
MaxCodeSizeTransition hexutil.Uint64 `json:"maxCodeSizeTransition"`
EIP98Transition hexutil.Uint64 `json:"eip98Transition"`
EIP150Transition hexutil.Uint64 `json:"eip150Transition"`
EIP160Transition hexutil.Uint64 `json:"eip160Transition"`
EIP161abcTransition hexutil.Uint64 `json:"eip161abcTransition"`
EIP161dTransition hexutil.Uint64 `json:"eip161dTransition"`
EIP155Transition hexutil.Uint64 `json:"eip155Transition"`
EIP140Transition hexutil.Uint64 `json:"eip140Transition"`
EIP211Transition hexutil.Uint64 `json:"eip211Transition"`
EIP214Transition hexutil.Uint64 `json:"eip214Transition"`
EIP658Transition hexutil.Uint64 `json:"eip658Transition"`
EIP145Transition hexutil.Uint64 `json:"eip145Transition"`
EIP1014Transition hexutil.Uint64 `json:"eip1014Transition"`
EIP1052Transition hexutil.Uint64 `json:"eip1052Transition"`
EIP1283Transition hexutil.Uint64 `json:"eip1283Transition"`
EIP1283DisableTransition hexutil.Uint64 `json:"eip1283DisableTransition"`
} `json:"params"`

Genesis struct {
Expand Down Expand Up @@ -354,8 +348,6 @@ func newParityChainSpec(network string, genesis *core.Genesis, bootnodes []strin
}

spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize)
spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit)
spec.Params.GasLimitBoundDivisor = (math2.HexOrDecimal64)(params.GasLimitBoundDivisor)
spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64())
spec.Params.ChainID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64())
spec.Params.MaxCodeSize = params.MaxCodeSize
Expand Down
4 changes: 0 additions & 4 deletions consensus/ethash/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,11 +284,7 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *
if diff < 0 {
diff *= -1
}
limit := parent.GasLimit / params.GasLimitBoundDivisor

if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit {
return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit)
}
// Verify that the block number is parent's +1
if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 {
return consensus.ErrInvalidNumber
Expand Down
4 changes: 2 additions & 2 deletions consensus/istanbul/backend/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ func newBlockChain(n int, isFullChain bool) (*core.BlockChain, *Backend) {
func createRandomDataDir() string {
rand.Seed(time.Now().UnixNano())
for {
dirName := "geth_ibft_" + strconv.Itoa(rand.Int()%1000)
dirName := "geth_ibft_" + strconv.Itoa(rand.Int()%1000000)
dataDir := filepath.Join("/tmp", dirName)
err := os.Mkdir(dataDir, 0700)
if os.IsExist(err) {
Expand Down Expand Up @@ -270,7 +270,7 @@ func makeHeader(parent *types.Block, config *istanbul.Config) *types.Header {
header := &types.Header{
ParentHash: parent.Hash(),
Number: parent.Number().Add(parent.Number(), common.Big1),
GasLimit: core.CalcGasLimit(parent, parent.GasLimit(), parent.GasLimit()),
GasLimit: core.CalcGasLimit(parent, nil),
GasUsed: 0,
Extra: parent.Extra(),
Time: new(big.Int).Add(parent.Time(), new(big.Int).SetUint64(config.BlockPeriod)),
Expand Down
2 changes: 1 addition & 1 deletion consensus/istanbul/core/testbackend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ func (t *testSystem) NewBackend(id uint64) *testSystemBackend {
func createRandomDataDir() string {
rand.Seed(time.Now().UnixNano())
for {
dirName := "geth_ibft_" + strconv.Itoa(rand.Int()%1000)
dirName := "geth_ibft_" + strconv.Itoa(rand.Int()%1000000)
dataDir := filepath.Join("/tmp", dirName)
err := os.Mkdir(dataDir, 0700)
if os.IsExist(err) {
Expand Down
32 changes: 32 additions & 0 deletions contract_comm/blockchain_parameters/blockchain_parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,20 @@ const (
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "blockGasLimit",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "intrinsicGasForAlternativeGasCurrency",
Expand Down Expand Up @@ -146,3 +160,21 @@ func SpawnCheck() {
}
}()
}

func GetBlockGasLimit(header *types.Header, state vm.StateDB) (uint64, error) {
var gasLimit *big.Int
_, err := contract_comm.MakeStaticCall(
params.BlockchainParametersRegistryId,
blockchainParametersABI,
"blockGasLimit",
[]interface{}{},
&gasLimit,
params.MaxGasForReadBlockchainParameter,
header,
state,
)
if err != nil {
return params.DefaultGasLimit, err
}
return gasLimit.Uint64(), nil
}
2 changes: 1 addition & 1 deletion core/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
from := 0
return func(i int, gen *BlockGen) {
block := gen.PrevBlock(i - 1)
gas := CalcGasLimit(block, block.GasLimit(), block.GasLimit())
gas := CalcGasLimit(block, nil)
for {
gas -= params.TxGas
if gas < params.TxGas {
Expand Down
39 changes: 11 additions & 28 deletions core/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import (
"fmt"

"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/contract_comm/blockchain_parameters"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
)

Expand Down Expand Up @@ -105,35 +107,16 @@ func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *stat
// to keep the baseline gas above the provided floor, and increase it towards the
// ceil if the blocks are full. If the ceil is exceeded, it will always decrease
// the gas allowance.
func CalcGasLimit(parent *types.Block, gasFloor, gasCeil uint64) uint64 {
// contrib = (parentGasUsed * 3 / 2) / 1024
contrib := (parent.GasUsed() + parent.GasUsed()/2) / params.GasLimitBoundDivisor
func CalcGasLimit(parent *types.Block, statedb *state.StateDB) uint64 {
header := parent.Header()

// decay = parentGasLimit / 1024 -1
decay := parent.GasLimit()/params.GasLimitBoundDivisor - 1
limit, err := blockchain_parameters.GetBlockGasLimit(header, statedb)

/*
strategy: gasLimit of block-to-mine is set based on parent's
gasUsed value. if parentGasUsed > parentGasLimit * (2/3) then we
increase it, otherwise lower it (or leave it unchanged if it's right
at that usage) the amount increased/decreased depends on how far away
from parentGasLimit * (2/3) parentGasUsed is.
*/
limit := parent.GasLimit() - decay + contrib
if limit < params.MinGasLimit {
limit = params.MinGasLimit
if err == nil {
return limit
}
// If we're outside our allowed gas range, we try to hone towards them
if limit < gasFloor {
limit = parent.GasLimit() + decay
if limit > gasFloor {
limit = gasFloor
}
} else if limit > gasCeil {
limit = parent.GasLimit() - decay
if limit < gasCeil {
limit = gasCeil
}
}
return limit

log.Warn("Cannot read block gas limit", "err", err)

return params.DefaultGasLimit
}
2 changes: 1 addition & 1 deletion core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S
Difficulty: parent.Difficulty(),
UncleHash: parent.UncleHash(),
}),
GasLimit: CalcGasLimit(parent, parent.GasLimit(), parent.GasLimit()),
GasLimit: CalcGasLimit(parent, state),
Number: new(big.Int).Add(parent.Number(), common.Big1),
Time: time,
}
Expand Down
2 changes: 1 addition & 1 deletion core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
Root: root,
}
if g.GasLimit == 0 {
head.GasLimit = params.GenesisGasLimit
head.GasLimit = params.DefaultGasLimit
}
if g.Difficulty == nil {
head.Difficulty = params.GenesisDifficulty
Expand Down
2 changes: 1 addition & 1 deletion core/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestDefaultGenesisBlock(t *testing.T) {

func TestSetupGenesis(t *testing.T) {
var (
customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50")
customghash = common.HexToHash("0x603e4119abc46d60fb1d5116bd810c207e6639053517f0632c9cebad854ee0c0")
customg = Genesis{
Config: &params.ChainConfig{HomesteadBlock: big.NewInt(3)},
Alloc: GenesisAlloc{
Expand Down
2 changes: 1 addition & 1 deletion eth/fetcher/fetcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ var (
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
testAddress = crypto.PubkeyToAddress(testKey.PublicKey)
genesis = core.GenesisBlockForTesting(testdb, testAddress, big.NewInt(1000000000))
unknownBlock = types.NewBlock(&types.Header{GasLimit: params.GenesisGasLimit}, nil, nil, nil, nil)
unknownBlock = types.NewBlock(&types.Header{GasLimit: params.DefaultGasLimit}, nil, nil, nil, nil)
)

// makeChain creates a chain of n blocks starting at and including parent.
Expand Down
8 changes: 7 additions & 1 deletion miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -909,10 +909,16 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64)
}

num := parent.Number()
limit := uint64(0)
if w.current != nil {
limit = core.CalcGasLimit(parent, w.current.state)
} else {
limit = core.CalcGasLimit(parent, nil)
}
header := &types.Header{
ParentHash: parent.Hash(),
Number: num.Add(num, common.Big1),
GasLimit: core.CalcGasLimit(parent, w.gasFloor, w.gasCeil),
GasLimit: limit,
Extra: w.extra,
Time: big.NewInt(timestamp),
}
Expand Down
2 changes: 1 addition & 1 deletion miner/worker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consens
if shouldAddPendingTxs {
backend.txPool.AddLocals(pendingTxs)
}
w := newWorker(chainConfig, engine, backend, new(event.TypeMux), time.Second, params.GenesisGasLimit, params.GenesisGasLimit, nil, testVerificationService, &backend.db)
w := newWorker(chainConfig, engine, backend, new(event.TypeMux), time.Second, params.DefaultGasLimit, params.DefaultGasLimit, nil, testVerificationService, &backend.db)
w.setEtherbase(testBankAddress)
return w, backend
}
Expand Down
4 changes: 1 addition & 3 deletions params/protocol_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ import (
)

const (
GasLimitBoundDivisor uint64 = 1024 // The bound divisor of the gas limit, used in update calculations.
MinGasLimit uint64 = 5000 // Minimum the gas limit may ever be.
GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block.
DefaultGasLimit uint64 = 20000000 // Gas limit of the blocks before BlockchainParams contract is loaded.

MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis.
ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction.
Expand Down

0 comments on commit 8d79a06

Please sign in to comment.