Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions core/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ var (
// have enough funds for transfer(topmost call only).
ErrInsufficientFundsForTransfer = errors.New("insufficient funds for transfer")

// ErrMaxInitCodeSizeExceeded is returned if creation transaction provides the init code bigger
// than init code size limit.
ErrMaxInitCodeSizeExceeded = errors.New("max initcode size exceeded")

// ErrInsufficientFunds is returned if the total cost of executing a transaction
// is higher than the balance of the user's account.
ErrInsufficientFunds = errors.New("insufficient funds for gas * price + value")
Expand Down
6 changes: 4 additions & 2 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -431,8 +431,10 @@ func (st *StateTransition) TransitionDb(owner common.Address) (*ExecutionResult,
}

// Check whether the init code size has been exceeded.
if rules.IsEIP1559 && contractCreation && len(msg.Data) > params.MaxInitCodeSize {
return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(msg.Data), params.MaxInitCodeSize)
if contractCreation {
if err := vm.CheckMaxInitCodeSize(&rules, uint64(len(msg.Data))); err != nil {
return nil, err
}
}

// Execute the preparatory steps for state transition which includes:
Expand Down
7 changes: 5 additions & 2 deletions core/txpool/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/params"
)
Expand Down Expand Up @@ -65,8 +66,10 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
return fmt.Errorf("%w: type %d rejected, pool not yet in Prague", core.ErrTxTypeNotSupported, tx.Type())
}
// Check whether the init code size has been exceeded
if rules.IsEIP1559 && 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 tx.To() == nil {
if err := vm.CheckMaxInitCodeSize(&rules, uint64(len(tx.Data()))); err != nil {
return err
}
}
// Transactions can't be negative. This may never happen using RLP decoded
// transactions but may occur for transactions created using the RPC.
Expand Down
31 changes: 31 additions & 0 deletions core/vm/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,43 @@
package vm

import (
"fmt"
"math"

"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/params"
"github.com/holiman/uint256"
)

// CheckMaxInitCodeSize checks the size of contract initcode against the protocol-defined limit.
func CheckMaxInitCodeSize(rules *params.Rules, size uint64) error {
if rules.IsOsaka {
if size > params.MaxInitCodeSizeOsaka {
return fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, size, params.MaxInitCodeSizeOsaka)
}
} else if rules.IsEIP1559 {
if size > params.MaxInitCodeSize {
return fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, size, params.MaxInitCodeSize)
}
}
Comment thread
gzliudan marked this conversation as resolved.

return nil
}

// CheckMaxCodeSize checks the size of contract code against the protocol-defined limit.
func CheckMaxCodeSize(rules *params.Rules, size uint64) error {
if rules.IsOsaka {
if size > params.MaxCodeSizeOsaka {
return fmt.Errorf("%w: code size %v limit %v", ErrMaxCodeSizeExceeded, size, params.MaxCodeSizeOsaka)
}
} else if rules.IsEIP158 {
if size > params.MaxCodeSize {
return fmt.Errorf("%w: code size %v limit %v", ErrMaxCodeSizeExceeded, size, params.MaxCodeSize)
}
Comment on lines +43 to +52

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CheckMaxCodeSize now returns a wrapped error with additional context ("%w: code size ..."). This changes the error string from exactly "max code size exceeded" to something with a suffix, which breaks consumers doing string-equality mappings (e.g. eth/tracers/native/call_flat.go maps only the exact string "max code size exceeded"). Either keep the original error message stable for ErrMaxCodeSizeExceeded (and attach details another way), or update the string-based mapping logic to handle the new message format (e.g., prefix match).

Copilot uses AI. Check for mistakes.
}
return nil
}

// calcMemSize64 calculates the required memory size, and returns
// the size and whether the result overflowed uint64
func calcMemSize64(off, l *uint256.Int) (uint64, bool) {
Expand Down
4 changes: 2 additions & 2 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -535,8 +535,8 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]b
}

// Check whether the max code size has been exceeded, assign err if the case.
if evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize {
return ret, ErrMaxCodeSizeExceeded
if err := CheckMaxCodeSize(&evm.chainRules, uint64(len(ret))); err != nil {
return ret, err
}

// Reject code starting with 0xEF if EIP-3541 is enabled.
Expand Down
16 changes: 7 additions & 9 deletions core/vm/gas_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@ package vm

import (
"errors"
"fmt"

"github.com/XinFinOrg/XDPoSChain/params"

"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/common/math"
"github.com/XinFinOrg/XDPoSChain/params"
)

// memoryGasCost calculates the quadratic gas for memory expansion. It does so
Expand Down Expand Up @@ -318,10 +316,10 @@ func gasCreateEip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
if overflow {
return 0, ErrGasUintOverflow
}
if size > params.MaxInitCodeSize {
return 0, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size)
if err := CheckMaxInitCodeSize(&evm.chainRules, size); err != nil {
return 0, err
}
Comment thread
gzliudan marked this conversation as resolved.
// Since size <= params.MaxInitCodeSize, these multiplication cannot overflow
// Since size <= the protocol-defined maximum initcode size limit, these multiplication cannot overflow
moreGas := params.InitCodeWordGas * ((size + 31) / 32)
if gas, overflow = math.SafeAdd(gas, moreGas); overflow {
return 0, ErrGasUintOverflow
Expand All @@ -338,10 +336,10 @@ func gasCreate2Eip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory,
if overflow {
return 0, ErrGasUintOverflow
}
if size > params.MaxInitCodeSize {
return 0, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size)
if err := CheckMaxInitCodeSize(&evm.chainRules, size); err != nil {
return 0, err
}
// Since size <= params.MaxInitCodeSize, these multiplication cannot overflow
// Since size <= the protocol-defined maximum initcode size limit, these multiplication cannot overflow
moreGas := (params.InitCodeWordGas + params.Keccak256WordGas) * ((size + 31) / 32)
if gas, overflow = math.SafeAdd(gas, moreGas); overflow {
return 0, ErrGasUintOverflow
Expand Down
16 changes: 9 additions & 7 deletions core/vm/gas_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,21 +123,21 @@ var createGasTests = []struct {
{"0x61C00060006000f0" + "600052" + "60206000F3", true, 44309, 44309},
// create2(0, 0, 0xc001, 0) without 3860
{"0x600061C00160006000f5" + "600052" + "60206000F3", false, 50471, 50471},
// create2(0, 0, 0xc001, 0) (too large), with 3860
{"0x600061C00160006000f5" + "600052" + "60206000F3", true, 32012, 100000},
// create2(0, 0, 0x10001, 0) (too large), with 3860
{"0x60006201000160006000f5" + "600052" + "60206000F3", true, 32012, 100000},
// create2(0, 0, 0xc000, 0)
// This case is trying to deploy code at (within) the limit
{"0x600061C00060006000f5" + "600052" + "60206000F3", true, 53528, 53528},
// create2(0, 0, 0xc001, 0)
// This case is trying to deploy code exceeding the limit
{"0x600061C00160006000f5" + "600052" + "60206000F3", true, 32024, 100000}}
// create2(0, 0, 0x10001, 0)
// This case is trying to deploy code exceeding Osaka limit
{"0x60006201000160006000f5" + "600052" + "60206000F3", true, 32024, 100000}}

func TestCreateGas(t *testing.T) {
for i, tt := range createGasTests {
var gasUsed = uint64(0)
doCheck := func(testGas int) bool {
address := common.BytesToAddress([]byte("contract"))
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()))
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
statedb.CreateAccount(address)
statedb.SetCode(address, hexutil.MustDecode(tt.code))
statedb.Finalise(true)
Expand All @@ -147,11 +147,13 @@ func TestCreateGas(t *testing.T) {
BlockNumber: big.NewInt(0),
}
config := Config{}
chainConfig := params.AllEthashProtocolChanges
if tt.eip3860 {
config.ExtraEips = []int{3860}
chainConfig = params.MergedTestChainConfig
}

evm := NewEVM(vmctx, statedb, nil, params.AllEthashProtocolChanges, config)
evm := NewEVM(vmctx, statedb, nil, chainConfig, config)
var startGas = uint64(testGas)
ret, gas, err := evm.Call(common.Address{}, address, nil, startGas, new(uint256.Int))
if err != nil {
Expand Down
18 changes: 12 additions & 6 deletions eth/tracers/native/call_flat.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,12 +368,18 @@ func convertErrorToParity(call *flatCallFrame) {

if parityError, ok := parityErrorMapping[call.Error]; ok {
call.Error = parityError
} else {
for gethError, parityError := range parityErrorMappingStartingWith {
if strings.HasPrefix(call.Error, gethError) {
call.Error = parityError
break
}
return
}
if i := strings.IndexByte(call.Error, ':'); i > 0 {
if parityError, ok := parityErrorMapping[call.Error[:i]]; ok {
call.Error = parityError
return
}
}
for gethError, parityError := range parityErrorMappingStartingWith {
if strings.HasPrefix(call.Error, gethError) {
call.Error = parityError
return
}
}
}
Expand Down
58 changes: 58 additions & 0 deletions eth/tracers/native/call_flat_error_mapping_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2024 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 <http://www.gnu.org/licenses/>.

package native

import "testing"

func TestConvertErrorToParity(t *testing.T) {
tests := []struct {
name string
in string
want string
}{
{
name: "exact map key",
in: "max code size exceeded",
want: "Out of gas",
},
{
name: "wrapped map key",
in: "max code size exceeded: code size 24577 limit 24576",
want: "Out of gas",
},
{
name: "existing prefix rule",
in: "out of gas: not enough gas for reentrancy sentry",
want: "Out of gas",
},
{
name: "unknown error unchanged",
in: "some unknown error",
want: "some unknown error",
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
frame := &flatCallFrame{Error: tc.in}
convertErrorToParity(frame)
if frame.Error != tc.want {
t.Fatalf("unexpected mapped error, got=%q want=%q", frame.Error, tc.want)
}
})
}
}
2 changes: 1 addition & 1 deletion internal/ethapi/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func txValidationError(err error) *invalidTxError {
return &invalidTxError{Message: err.Error(), Code: errCodeIntrinsicGas}
case errors.Is(err, core.ErrInsufficientFundsForTransfer):
return &invalidTxError{Message: err.Error(), Code: errCodeInsufficientFunds}
case errors.Is(err, core.ErrMaxInitCodeSizeExceeded):
case errors.Is(err, vm.ErrMaxInitCodeSizeExceeded):
return &invalidTxError{Message: err.Error(), Code: errCodeMaxInitCodeSizeExceeded}
}
return &invalidTxError{
Expand Down
6 changes: 4 additions & 2 deletions params/protocol_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,10 @@ const (

InitialBaseFee = 12500000000 // Initial base fee for EIP-1559 blocks.

MaxCodeSize = 24576 // Maximum bytecode to permit for a contract
MaxInitCodeSize = 2 * MaxCodeSize // Maximum initcode to permit in a creation transaction and create instructions
MaxCodeSize = 24576 // Maximum bytecode to permit for a contract
MaxInitCodeSize = 2 * MaxCodeSize // Maximum initcode to permit in a creation transaction and create instructions
MaxCodeSizeOsaka = 32768 // Maximum bytecode to permit for a contract post Osaka
MaxInitCodeSizeOsaka = 2 * MaxCodeSizeOsaka // Maximum initcode to permit in a creation transaction and create instructions post Osaka

// Precompiled contract gas prices

Expand Down
Loading