From a1f8141d58187fa51ec45b7d867f28466fbe704e Mon Sep 17 00:00:00 2001 From: ganeshvanahalli Date: Thu, 21 Sep 2023 14:17:35 -0500 Subject: [PATCH] Make contract size limit configurable --- core/state_transition.go | 4 ++-- core/txpool/txpool.go | 4 ++-- core/vm/evm.go | 2 +- core/vm/gas_table.go | 8 ++++---- params/config.go | 22 ++++++++++++++++++++++ params/config_test.go | 31 +++++++++++++++++++++++++++++++ 6 files changed, 62 insertions(+), 9 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index a70ce4eb06..5dd8de1542 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -408,8 +408,8 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { } // Check whether the init code size has been exceeded. - if rules.IsShanghai && contractCreation && len(msg.Data) > params.MaxInitCodeSize { - return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(msg.Data), params.MaxInitCodeSize) + if rules.IsShanghai && contractCreation && len(msg.Data) > int(*st.evm.ChainConfig().MaxInitCodeSize) { + return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(msg.Data), int(*st.evm.ChainConfig().MaxInitCodeSize)) } // Execute the preparatory steps for state transition which includes: diff --git a/core/txpool/txpool.go b/core/txpool/txpool.go index 745568d437..a7f6d43518 100644 --- a/core/txpool/txpool.go +++ b/core/txpool/txpool.go @@ -615,8 +615,8 @@ func (pool *TxPool) validateTxBasics(tx *types.Transaction, local bool) error { return ErrOversizedData } // Check whether the init code size has been exceeded. - if pool.shanghai.Load() && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { - return fmt.Errorf("%w: code size %v limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), params.MaxInitCodeSize) + if pool.shanghai.Load() && tx.To() == nil && len(tx.Data()) > int(*pool.chainconfig.MaxInitCodeSize) { + return fmt.Errorf("%w: code size %v limit %v", core.ErrMaxInitCodeSizeExceeded, len(tx.Data()), int(*pool.chainconfig.MaxInitCodeSize)) } // Transactions can't be negative. This may never happen using RLP decoded // transactions but may occur if you create a transaction using the RPC. diff --git a/core/vm/evm.go b/core/vm/evm.go index b604d3389c..dbea4747b1 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -504,7 +504,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, ret, err := evm.interpreter.Run(contract, nil, false) // Check whether the max code size has been exceeded, assign err if the case. - if err == nil && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize { + if err == nil && evm.chainRules.IsEIP158 && len(ret) > int(*evm.chainConfig.MaxCodeSize) { err = ErrMaxCodeSizeExceeded } diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 4f961ef4db..7409d2c6cc 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -308,10 +308,10 @@ func gasCreateEip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m return 0, err } size, overflow := stack.Back(2).Uint64WithOverflow() - if overflow || size > params.MaxInitCodeSize { + if overflow || size > *evm.chainConfig.MaxInitCodeSize { return 0, ErrGasUintOverflow } - // Since size <= params.MaxInitCodeSize, these multiplication cannot overflow + // Since size <= *evm.chainConfig.MaxInitCodeSize, these multiplication cannot overflow moreGas := params.InitCodeWordGas * ((size + 31) / 32) if gas, overflow = math.SafeAdd(gas, moreGas); overflow { return 0, ErrGasUintOverflow @@ -324,10 +324,10 @@ func gasCreate2Eip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, return 0, err } size, overflow := stack.Back(2).Uint64WithOverflow() - if overflow || size > params.MaxInitCodeSize { + if overflow || size > *evm.chainConfig.MaxInitCodeSize { return 0, ErrGasUintOverflow } - // Since size <= params.MaxInitCodeSize, these multiplication cannot overflow + // Since size <= *evm.chainConfig.MaxInitCodeSize, these multiplication cannot overflow moreGas := (params.InitCodeWordGas + params.Keccak256WordGas) * ((size + 31) / 32) if gas, overflow = math.SafeAdd(gas, moreGas); overflow { return 0, ErrGasUintOverflow diff --git a/params/config.go b/params/config.go index a5c518aa8d..527a2fb925 100644 --- a/params/config.go +++ b/params/config.go @@ -17,6 +17,7 @@ package params import ( + "encoding/json" "fmt" "math/big" @@ -307,6 +308,27 @@ type ChainConfig struct { Clique *CliqueConfig `json:"clique,omitempty"` ArbitrumChainParams ArbitrumChainParams `json:"arbitrum,omitempty"` + + MaxCodeSize *uint64 `json:"maxCodeSize,omitempty,"` // Maximum bytecode to permit for a contract + MaxInitCodeSize *uint64 `json:"maxInitCodeSize,omitempty"` // Maximum initcode to permit in a creation transaction and create instructions +} + +// UnmarshalJSON implements the json.Unmarshaler interface by decoding the json +// string values into the config fields +func (c *ChainConfig) UnmarshalJSON(data []byte) error { + type chainConfigJSON ChainConfig + var cfgJSON chainConfigJSON + if err := json.Unmarshal(data, &cfgJSON); err != nil { + return err + } + if cfgJSON.MaxCodeSize == nil { + cfgJSON.MaxCodeSize = newUint64(MaxCodeSize) + } + if cfgJSON.MaxInitCodeSize == nil { + cfgJSON.MaxInitCodeSize = newUint64(MaxInitCodeSize) + } + *c = ChainConfig(cfgJSON) + return nil } // EthashConfig is the consensus engine configs for proof-of-work based sealing. diff --git a/params/config_test.go b/params/config_test.go index 1d03d96739..f2ca219cf2 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -17,6 +17,7 @@ package params import ( + "encoding/json" "math/big" "reflect" "testing" @@ -140,3 +141,33 @@ func TestConfigRules(t *testing.T) { t.Errorf("expected %v to be shanghai", currentArbosVersion) } } + +type marshalUnMarshalTest struct { + input interface{} + want interface{} +} + +var unmarshalChainConfigTests = []marshalUnMarshalTest{ + {input: `{"maxCodeSize": 10, "maxInitCodeSize": 10}`, + want: [2]uint64{10, 10}}, + {input: `{"maxCodeSize": 10}`, + want: [2]uint64{10, MaxInitCodeSize}}, + {input: `{"maxInitCodeSize": 10}`, + want: [2]uint64{MaxCodeSize, 10}}, + {input: `{}`, + want: [2]uint64{MaxCodeSize, MaxInitCodeSize}}, +} + +func TestUnmarshalChainConfig(t *testing.T) { + var c ChainConfig + for _, test := range unmarshalChainConfigTests { + if err := json.Unmarshal([]byte(test.input.(string)), &c); err != nil { + t.Errorf("failed to unmarshal. Error: %q", err) + } + expected := test.want.([2]uint64) + if *c.MaxCodeSize != expected[0] || *c.MaxInitCodeSize != expected[1] { + t.Errorf("failed to unmarshal MaxCodeSize and MaxInitCodeSize correctly. unmarshalled as (%d %d) want (%d %d))", + *c.MaxCodeSize, *c.MaxInitCodeSize, expected[0], expected[1]) + } + } +}