Skip to content

Commit

Permalink
Feat: transition of contract size limit (#1376)
Browse files Browse the repository at this point in the history
* add fix for updating transitions for old config

* field does not exist yet

* added deprecation message

* added ContractSizeLimit field to the transition and some UT for GetMaxCodeSize

* Added some check and unit tests

* lint fix

* resolve conflicts

* updated based on reviews
  • Loading branch information
achraf17 authored Apr 12, 2022
1 parent 9fd8fc2 commit 6665a93
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 10 deletions.
19 changes: 19 additions & 0 deletions params/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
)

// Genesis hashes to enforce below configs on.
Expand Down Expand Up @@ -430,6 +431,7 @@ type Transition struct {
EpochLength uint64 `json:"epochlength,omitempty"` // Number of blocks that should pass before pending validator votes are reset
BlockPeriodSeconds uint64 `json:"blockperiodseconds,omitempty"` // Minimum time between two consecutive IBFT or QBFT blocks’ timestamps in seconds
RequestTimeoutSeconds uint64 `json:"requesttimeoutseconds,omitempty"` // Minimum request timeout for each IBFT or QBFT round in milliseconds
ContractSizeLimit uint64 `json:"contractsizelimit,omitempty"` // Maximum smart contract code size
}

// String implements the fmt.Stringer interface.
Expand Down Expand Up @@ -565,6 +567,7 @@ func (c *ChainConfig) GetMaxCodeSize(num *big.Int) int {
maxCodeSize := MaxCodeSize

if len(c.MaxCodeSizeConfig) > 0 {
log.Warn("WARNING: The attribute config.maxCodeSizeConfig is deprecated and will be removed in the future, please use config.transitions.contractsizelimit on genesis file")
for _, data := range c.MaxCodeSizeConfig {
if data.Block.Cmp(num) > 0 {
break
Expand All @@ -580,6 +583,13 @@ func (c *ChainConfig) GetMaxCodeSize(num *big.Int) int {
maxCodeSize = int(c.MaxCodeSize) * 1024
}
}
if len(c.Transitions) > 0 {
for i := 0; i < len(c.Transitions) && c.Transitions[i].Block.Cmp(num) <= 0; i++ {
if c.Transitions[i].ContractSizeLimit != 0 {
maxCodeSize = int(c.Transitions[i].ContractSizeLimit) * 1024
}
}
}
return maxCodeSize
}

Expand Down Expand Up @@ -623,6 +633,9 @@ func (c *ChainConfig) CheckTransitionsData() error {
if c.Istanbul != nil && c.Istanbul.TestQBFTBlock != nil && (transition.Algorithm == IBFT || transition.Algorithm == QBFT) {
return ErrTestQBFTBlockAndTransitions
}
if len(c.MaxCodeSizeConfig) > 0 && transition.ContractSizeLimit != 0 {
return ErrMaxCodeSizeConfigAndTransitions
}
if transition.Algorithm == QBFT {
isQBFT = true
}
Expand All @@ -635,6 +648,9 @@ func (c *ChainConfig) CheckTransitionsData() error {
if transition.Algorithm == IBFT && isQBFT {
return ErrTransition
}
if transition.ContractSizeLimit != 0 && (transition.ContractSizeLimit < 24 || transition.ContractSizeLimit > 128) {
return ErrContractSizeLimit
}
prevBlock = transition.Block
}
return nil
Expand Down Expand Up @@ -754,6 +770,9 @@ func isTransitionsConfigCompatible(c1, c2 *ChainConfig, head *big.Int) (error, *
if isSameBlock || c1.Transitions[i].EpochLength != c2.Transitions[i].EpochLength {
return ErrTransitionIncompatible("EpochLength"), head, head
}
if isSameBlock || c1.Transitions[i].ContractSizeLimit != c2.Transitions[i].ContractSizeLimit {
return ErrTransitionIncompatible("ContractSizeLimit"), head, head
}
}

return nil, big.NewInt(0), big.NewInt(0)
Expand Down
85 changes: 80 additions & 5 deletions params/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,10 @@ func TestCheckTransitionsData(t *testing.T) {
wantErr error
}
var ibftTransitionsConfig, qbftTransitionsConfig, invalidTransition, invalidBlockOrder []Transition
tranI0 := Transition{big.NewInt(0), IBFT, 30000, 5, 10}
tranQ5 := Transition{big.NewInt(5), QBFT, 30000, 5, 10}
tranI10 := Transition{big.NewInt(10), IBFT, 30000, 5, 10}
tranQ8 := Transition{big.NewInt(8), QBFT, 30000, 5, 10}
tranI0 := Transition{big.NewInt(0), IBFT, 30000, 5, 10, 50}
tranQ5 := Transition{big.NewInt(5), QBFT, 30000, 5, 10, 50}
tranI10 := Transition{big.NewInt(10), IBFT, 30000, 5, 10, 50}
tranQ8 := Transition{big.NewInt(8), QBFT, 30000, 5, 10, 50}

ibftTransitionsConfig = append(ibftTransitionsConfig, tranI0, tranI10)
qbftTransitionsConfig = append(qbftTransitionsConfig, tranQ5, tranQ8)
Expand Down Expand Up @@ -391,7 +391,7 @@ func TestCheckTransitionsData(t *testing.T) {
wantErr: ErrBlockOrder,
},
{
stored: &ChainConfig{Transitions: []Transition{{nil, IBFT, 30000, 5, 10}}},
stored: &ChainConfig{Transitions: []Transition{{nil, IBFT, 30000, 5, 10, 50}}},
wantErr: ErrBlockNumberMissing,
},
{
Expand All @@ -402,6 +402,26 @@ func TestCheckTransitionsData(t *testing.T) {
stored: &ChainConfig{Transitions: []Transition{{Block: big.NewInt(0), Algorithm: ""}}},
wantErr: nil,
},
{
stored: &ChainConfig{MaxCodeSizeConfig: []MaxCodeConfigStruct{{big.NewInt(10), 24}}, Transitions: []Transition{{Block: big.NewInt(0), ContractSizeLimit: 50}}},
wantErr: ErrMaxCodeSizeConfigAndTransitions,
},
{
stored: &ChainConfig{Transitions: []Transition{{Block: big.NewInt(0), ContractSizeLimit: 23}}},
wantErr: ErrContractSizeLimit,
},
{
stored: &ChainConfig{Transitions: []Transition{{Block: big.NewInt(0), ContractSizeLimit: 129}}},
wantErr: ErrContractSizeLimit,
},
{
stored: &ChainConfig{Transitions: []Transition{{Block: big.NewInt(0), ContractSizeLimit: 50}}},
wantErr: nil,
},
{
stored: &ChainConfig{Transitions: []Transition{{Block: big.NewInt(0)}}},
wantErr: nil,
},
}

for _, test := range tests {
Expand All @@ -411,3 +431,58 @@ func TestCheckTransitionsData(t *testing.T) {
}
}
}

func TestGetMaxCodeSize(t *testing.T) {
type test struct {
config *ChainConfig
blockNumber int64
maxCode int
}
config1, config2, config3 := *TestChainConfig, *TestChainConfig, *TestChainConfig
config1.MaxCodeSizeConfig = []MaxCodeConfigStruct{
{big.NewInt(2), 28},
{big.NewInt(4), 32},
}
config1.MaxCodeSize = 34
config2.MaxCodeSize = 36
config2.MaxCodeSizeChangeBlock = big.NewInt(2)
config3.MaxCodeSize = 0
config3.Transitions = []Transition{
{Block: big.NewInt(2), ContractSizeLimit: 50},
{Block: big.NewInt(4), ContractSizeLimit: 54},
}
maxCodeDefault := 32 * 1024
tests := []test{
{MainnetChainConfig, 0, MaxCodeSize},
{RopstenChainConfig, 0, MaxCodeSize},
{RinkebyChainConfig, 0, MaxCodeSize},
{GoerliChainConfig, 0, MaxCodeSize},
{YoloV3ChainConfig, 0, MaxCodeSize},
{AllEthashProtocolChanges, 0, 35 * 1024},
{AllCliqueProtocolChanges, 0, maxCodeDefault},
{TestChainConfig, 0, maxCodeDefault},
{QuorumTestChainConfig, 0, maxCodeDefault},
{QuorumMPSTestChainConfig, 0, maxCodeDefault},
{&config1, 0, MaxCodeSize},
{&config1, 1, MaxCodeSize},
{&config1, 2, 28 * 1024},
{&config1, 3, 28 * 1024},
{&config1, 4, 32 * 1024},
{&config2, 0, MaxCodeSize},
{&config2, 1, MaxCodeSize},
{&config2, 2, 36 * 1024},
{&config2, 3, 36 * 1024},
{&config3, 0, MaxCodeSize},
{&config3, 1, MaxCodeSize},
{&config3, 2, 50 * 1024},
{&config3, 3, 50 * 1024},
{&config3, 4, 54 * 1024},
{&config3, 8, 54 * 1024},
}
for _, test := range tests {
maxCodeSize := test.config.GetMaxCodeSize(big.NewInt(test.blockNumber))
if !reflect.DeepEqual(maxCodeSize, test.maxCode) {
t.Errorf("error mismatch:\nexpected: %v\nreceived: %v\n", test.maxCode, maxCodeSize)
}
}
}
12 changes: 7 additions & 5 deletions params/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import (
)

var (
ErrTransitionAlgorithm = errors.New("transition algorithm is invalid, should be either `ibft` or `qbft`")
ErrBlockNumberMissing = errors.New("block number not given in transitions data")
ErrBlockOrder = errors.New("block order should be ascending")
ErrTransition = errors.New("can't transition from qbft to ibft")
ErrTestQBFTBlockAndTransitions = errors.New("can't use transition algorithm and testQBFTBlock at the same time")
ErrTransitionAlgorithm = errors.New("transition algorithm is invalid, should be either `ibft` or `qbft`")
ErrBlockNumberMissing = errors.New("block number not given in transitions data")
ErrBlockOrder = errors.New("block order should be ascending")
ErrTransition = errors.New("can't transition from qbft to ibft")
ErrTestQBFTBlockAndTransitions = errors.New("can't use transition algorithm and testQBFTBlock at the same time")
ErrMaxCodeSizeConfigAndTransitions = errors.New("can't use transition ContractSizeLimit and MaxCodeSizeConfig at the same time")
ErrContractSizeLimit = errors.New("transition contract code size must be between 24 and 128")
)

func ErrTransitionIncompatible(field string) error {
Expand Down

0 comments on commit 6665a93

Please sign in to comment.