Skip to content

Commit 07f2bb1

Browse files
yperbasisclaudetaratorio
authored
Implement EIP-7954: Increase Maximum Contract Size (#19624)
https://eips.ethereum.org/EIPS/eip-7954 --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: taratorio <94537774+taratorio@users.noreply.github.com>
1 parent 5f82720 commit 07f2bb1

9 files changed

Lines changed: 90 additions & 35 deletions

File tree

execution/chain/chain_config.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,10 @@ func (c *Config) IsNapoli(num uint64) bool {
356356
return (c != nil) && (c.Bor != nil) && c.Bor.IsNapoli(num)
357357
}
358358

359+
func (c *Config) IsAhmedabad(num uint64) bool {
360+
return (c != nil) && (c.Bor != nil) && c.Bor.IsAhmedabad(num)
361+
}
362+
359363
// Refer to https://forum.polygon.technology/t/pip-63-bhilai-hardfork
360364
func (c *Config) IsBhilai(num uint64) bool {
361365
return (c != nil) && (c.Bor != nil) && c.Bor.IsBhilai(num)
@@ -727,7 +731,7 @@ type Rules struct {
727731
IsHomestead, IsTangerineWhistle, IsSpuriousDragon bool
728732
IsByzantium, IsConstantinople, IsPetersburg bool
729733
IsIstanbul, IsBerlin, IsLondon, IsShanghai bool
730-
IsCancun, IsNapoli, IsBhilai bool
734+
IsCancun, IsNapoli, IsAhmedabad, IsBhilai bool
731735
IsPrague, IsOsaka, IsAmsterdam bool
732736
IsAura bool
733737
}

execution/protocol/params/protocol.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,9 +136,11 @@ const (
136136
ElasticityMultiplier = 2 // Bounds the maximum gas limit an EIP-1559 block may have.
137137
InitialBaseFee = 1000000000 // Initial base fee for EIP-1559 blocks.
138138

139-
MaxCodeSize = 24576 // Maximum bytecode to permit for a contract
140-
MaxCodeSizePostAhmedabad = 32768 // Maximum bytecode to permit for a contract post Ahmedabad hard fork (bor / polygon pos) (32KB)
141-
MaxInitCodeSize = 2 * MaxCodeSize // Maximum initcode to permit in a creation transaction and create instructions
139+
MaxCodeSize = 24 * 1024 // Maximum bytecode to permit for a contract
140+
MaxCodeSizeAhmedabad = 32 * 1024 // Maximum bytecode to permit for a contract post Ahmedabad hard fork (bor / polygon pos) (32KB)
141+
MaxInitCodeSize = 2 * MaxCodeSize // Maximum initcode to permit in a creation transaction and create instructions
142+
MaxCodeSizeAmsterdam = 32 * 1024 // EIP-7954: Increase Maximum Contract Size
143+
MaxInitCodeSizeAmsterdam = 2 * MaxCodeSizeAmsterdam // EIP-7954: Increase Maximum Contract Size
142144

143145
// Precompiled contract gas prices
144146

execution/protocol/state_transition.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -373,8 +373,10 @@ func (st *StateTransition) ApplyFrame() (*evmtypes.ExecutionResult, error) {
373373
}
374374

375375
// Check whether the init code size has been exceeded.
376-
if isEIP3860 && contractCreation && len(st.data) > params.MaxInitCodeSize {
377-
return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(st.data), params.MaxInitCodeSize)
376+
if contractCreation {
377+
if err := vm.CheckMaxInitCodeSize(uint64(len(st.data)), isEIP3860, rules.IsAmsterdam); err != nil {
378+
return nil, err
379+
}
378380
}
379381

380382
// Execute the preparatory steps for state transition which includes:
@@ -529,8 +531,10 @@ func (st *StateTransition) TransitionDb(refunds bool, gasBailout bool) (result *
529531
}
530532

531533
// Check whether the init code size has been exceeded.
532-
if isEIP3860 && contractCreation && len(st.data) > params.MaxInitCodeSize {
533-
return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(st.data), params.MaxInitCodeSize)
534+
if contractCreation {
535+
if err := vm.CheckMaxInitCodeSize(uint64(len(st.data)), isEIP3860, rules.IsAmsterdam); err != nil {
536+
return nil, err
537+
}
534538
}
535539

536540
// Execute the preparatory steps for state transition which includes:

execution/tests/eest_devnet/block_test.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,6 @@ func TestExecutionSpecBlockchainDevnet(t *testing.T) {
127127
bt.SkipLoad(`^for_amsterdam/amsterdam/eip7954_increase_max_contract_size/test_max_code_size_via_create.json`) // gas limit too high: address 0x1AD9bc24818784172FF393bb6F89F094D4d2Ca29, gas limit 100000000
128128
bt.SkipLoad(`^for_amsterdam/amsterdam/eip7954_increase_max_contract_size/test_max_code_size_with_max_initcode.json`) // gas limit too high: address 0x1AD9bc24818784172FF393bb6F89F094D4d2Ca29, gas limit 100000000
129129
bt.SkipLoad(`^for_amsterdam/amsterdam/eip7954_increase_max_contract_size/test_max_code_size_with_max_initcode_mainnet.json`) // gas used by execution: 102194, in header: 112704
130-
bt.SkipLoad(`^for_amsterdam/amsterdam/eip7954_increase_max_contract_size/test_max_initcode_size.json`) // max initcode size exceeded: code size 65536 limit 49152
131-
bt.SkipLoad(`^for_amsterdam/amsterdam/eip7954_increase_max_contract_size/test_max_initcode_size_gas_metering.json`) // max initcode size exceeded: code size 65536 limit 49152
132130
bt.SkipLoad(`^for_amsterdam/amsterdam/eip7954_increase_max_contract_size/test_max_initcode_size_gas_metering_via_create.json`) // block access list mismatch
133131
bt.SkipLoad(`^for_amsterdam/amsterdam/eip7954_increase_max_contract_size/test_max_initcode_size_via_create.json`) // gas used by execution: 16777216, in header: 676630
134132
bt.SkipLoad(`^for_amsterdam/amsterdam/eip7954_increase_max_contract_size/test_over_max_code_size_mainnet.json`) // gas used by execution: 16777216, in header: 16645728
@@ -445,7 +443,6 @@ func TestExecutionSpecBlockchainDevnet(t *testing.T) {
445443
bt.SkipLoad(`^for_amsterdam/prague/eip7702_set_code_tx/test_valid_tx_invalid_chain_id.json`) // gas used by execution: 72931, in header: 196058
446444
bt.SkipLoad(`^for_amsterdam/shanghai/eip3651_warm_coinbase/`) // gas used by execution: 45846, in header: 37568
447445
bt.SkipLoad(`^for_amsterdam/shanghai/eip3855_push0/`) // gas used by execution: 67973, in header: 75136
448-
bt.SkipLoad(`^for_amsterdam/shanghai/eip3860_initcode/test_contract_creating_tx.json`) // max initcode size exceeded: code size 49153 limit 49152
449446
bt.SkipLoad(`^for_amsterdam/shanghai/eip4895_withdrawals/test_balance_within_block.json`) // gas used by execution: 46076, in header: 37568
450447
bt.SkipLoad(`^for_amsterdam/shanghai/eip4895_withdrawals/test_newly_created_contract.json`) // gas used by execution: 53279, in header: 132662
451448
bt.SkipLoad(`^for_amsterdam/shanghai/eip4895_withdrawals/test_no_evm_execution.json`) // gas used by execution: 86210, in header: 75136

execution/vm/common.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,14 @@
2020
package vm
2121

2222
import (
23+
"fmt"
24+
2325
"github.com/holiman/uint256"
2426

2527
"github.com/erigontech/erigon/common"
2628
"github.com/erigontech/erigon/common/math"
29+
"github.com/erigontech/erigon/execution/chain"
30+
"github.com/erigontech/erigon/execution/protocol/params"
2731
)
2832

2933
// calcMemSize64 calculates the required memory size, and returns
@@ -85,3 +89,41 @@ func ToWordSize(size uint64) uint64 {
8589

8690
return (size + 31) / 32
8791
}
92+
93+
// See EIP-170 & EIP-7954
94+
func CheckMaxCodeSize(size int, rules *chain.Rules) error {
95+
// Gnosis Chain prior to Shanghai didn't have EIP-170 enabled,
96+
// but EIP-3860 (part of Shanghai) requires EIP-170.
97+
if !rules.IsSpuriousDragon || (rules.IsAura && !rules.IsShanghai) {
98+
return nil
99+
}
100+
101+
var maxSize int
102+
if rules.IsAmsterdam {
103+
maxSize = params.MaxCodeSizeAmsterdam
104+
} else if rules.IsAhmedabad {
105+
maxSize = params.MaxCodeSizeAhmedabad
106+
} else {
107+
maxSize = params.MaxCodeSize
108+
}
109+
if size > maxSize {
110+
return fmt.Errorf("%w: size %v limit %v", ErrMaxCodeSizeExceeded, size, maxSize)
111+
}
112+
return nil
113+
}
114+
115+
// See EIP-3860 & EIP-7954
116+
func CheckMaxInitCodeSize(size uint64, eip3860, eip7954 bool) error {
117+
var maxSize uint64
118+
if eip7954 {
119+
maxSize = params.MaxInitCodeSizeAmsterdam
120+
} else if eip3860 {
121+
maxSize = params.MaxInitCodeSize
122+
} else {
123+
return nil
124+
}
125+
if size > maxSize {
126+
return fmt.Errorf("%w: size %v limit %v", ErrMaxInitCodeSizeExceeded, size, maxSize)
127+
}
128+
return nil
129+
}

execution/vm/evm.go

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -469,14 +469,9 @@ func (evm *EVM) create(caller accounts.Address, codeAndHash *codeAndHash, gasRem
469469
ret, gasRemaining, err = evm.Run(contract, gasRemaining, nil, false)
470470

471471
// EIP-170: Contract code size limit
472-
if err == nil && evm.chainRules.IsSpuriousDragon && len(ret) > evm.maxCodeSize() {
473-
// Gnosis Chain prior to Shanghai didn't have EIP-170 enabled,
474-
// but EIP-3860 (part of Shanghai) requires EIP-170.
475-
if !evm.chainRules.IsAura || evm.config.HasEip3860(evm.chainRules) {
476-
err = ErrMaxCodeSizeExceeded
477-
}
472+
if err == nil {
473+
err = CheckMaxCodeSize(len(ret), evm.chainRules)
478474
}
479-
480475
// Reject code starting with 0xEF if EIP-3541 is enabled.
481476
if err == nil && evm.chainRules.IsLondon && len(ret) >= 1 && ret[0] == 0xEF {
482477
err = ErrInvalidCode
@@ -512,13 +507,6 @@ func (evm *EVM) create(caller accounts.Address, codeAndHash *codeAndHash, gasRem
512507
return ret, address, gasRemaining, err
513508
}
514509

515-
func (evm *EVM) maxCodeSize() int {
516-
if evm.chainConfig.Bor != nil && evm.chainConfig.Bor.IsAhmedabad(evm.Context.BlockNumber) {
517-
return params.MaxCodeSizePostAhmedabad
518-
}
519-
return params.MaxCodeSize
520-
}
521-
522510
// Create creates a new contract using code as deployment code.
523511
// DESCRIBED: docs/programmers_guide/guide.md#nonce
524512
func (evm *EVM) Create(caller accounts.Address, code []byte, gasRemaining uint64, endowment uint256.Int, bailout bool) (ret []byte, contractAddr accounts.Address, leftOverGas uint64, err error) {

execution/vm/evmtypes/rules.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ func (bc *BlockContext) Rules(c *chain.Config) *chain.Rules {
4343
IsShanghai: c.IsShanghai(bc.Time) || c.IsAgra(bc.BlockNumber),
4444
IsCancun: c.IsCancun(bc.Time),
4545
IsNapoli: c.IsNapoli(bc.BlockNumber),
46+
IsAhmedabad: c.IsAhmedabad(bc.BlockNumber),
4647
IsBhilai: c.IsBhilai(bc.BlockNumber),
4748
IsPrague: c.IsPrague(bc.Time) || c.IsBhilai(bc.BlockNumber),
4849
IsOsaka: c.IsOsaka(bc.Time),

execution/vm/gas_table.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ func gasCreate2(_ *EVM, callContext *CallContext, availableGas uint64, memorySiz
314314
return gas, nil
315315
}
316316

317-
func gasCreateEip3860(_ *EVM, callContext *CallContext, availableGas uint64, memorySize uint64) (uint64, error) {
317+
func gasCreateEip3860(evm *EVM, callContext *CallContext, availableGas uint64, memorySize uint64) (uint64, error) {
318318
gas, err := memoryGasCost(callContext, memorySize)
319319
if err != nil {
320320
return 0, err
@@ -323,11 +323,11 @@ func gasCreateEip3860(_ *EVM, callContext *CallContext, availableGas uint64, mem
323323
if overflow {
324324
return 0, ErrGasUintOverflow
325325
}
326-
if size > params.MaxInitCodeSize {
327-
return 0, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size)
326+
if err := CheckMaxInitCodeSize(size, evm.ChainRules().IsShanghai, evm.ChainRules().IsAmsterdam); err != nil {
327+
return 0, err
328328
}
329329
numWords := ToWordSize(size)
330-
// Since size <= params.MaxInitCodeSize, this multiplication cannot overflow
330+
// Since size <= params.MaxInitCodeSize(Amsterdam), this multiplication cannot overflow
331331
wordGas := params.InitCodeWordGas * numWords
332332
gas, overflow = math.SafeAdd(gas, wordGas)
333333
if overflow {
@@ -336,7 +336,7 @@ func gasCreateEip3860(_ *EVM, callContext *CallContext, availableGas uint64, mem
336336
return gas, nil
337337
}
338338

339-
func gasCreate2Eip3860(_ *EVM, callContext *CallContext, availableGas uint64, memorySize uint64) (uint64, error) {
339+
func gasCreate2Eip3860(evm *EVM, callContext *CallContext, availableGas uint64, memorySize uint64) (uint64, error) {
340340
gas, err := memoryGasCost(callContext, memorySize)
341341
if err != nil {
342342
return 0, err
@@ -345,11 +345,11 @@ func gasCreate2Eip3860(_ *EVM, callContext *CallContext, availableGas uint64, me
345345
if overflow {
346346
return 0, ErrGasUintOverflow
347347
}
348-
if size > params.MaxInitCodeSize {
349-
return 0, fmt.Errorf("%w: size %d", ErrMaxInitCodeSizeExceeded, size)
348+
if err := CheckMaxInitCodeSize(size, evm.ChainRules().IsShanghai, evm.ChainRules().IsAmsterdam); err != nil {
349+
return 0, err
350350
}
351351
numWords := ToWordSize(size)
352-
// Since size <= params.MaxInitCodeSize, this multiplication cannot overflow
352+
// Since size <= params.MaxInitCodeSize(Amsterdam), this multiplication cannot overflow
353353
wordGas := (params.InitCodeWordGas + params.Keccak256WordGas) * numWords
354354
gas, overflow = math.SafeAdd(gas, wordGas)
355355
if overflow {

txnprovider/txpool/pool.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import (
5050
"github.com/erigontech/erigon/execution/protocol/params"
5151
"github.com/erigontech/erigon/execution/types"
5252
"github.com/erigontech/erigon/execution/types/accounts"
53+
"github.com/erigontech/erigon/execution/vm"
5354
"github.com/erigontech/erigon/node/ethconfig"
5455
"github.com/erigontech/erigon/node/gointerfaces"
5556
"github.com/erigontech/erigon/node/gointerfaces/grpcutil"
@@ -146,6 +147,8 @@ type TxPool struct {
146147
isPostPrague atomic.Bool
147148
osakaTime *uint64
148149
isPostOsaka atomic.Bool
150+
amsterdamTime *uint64
151+
isPostAmsterdam atomic.Bool
149152
feeCalculator FeeCalculator
150153
p2pFetcher *Fetch
151154
p2pSender *Send
@@ -293,6 +296,13 @@ func New(
293296
osakaTimeU64 := chainConfig.OsakaTime.Uint64()
294297
res.osakaTime = &osakaTimeU64
295298
}
299+
if chainConfig.AmsterdamTime != nil {
300+
if !chainConfig.AmsterdamTime.IsUint64() {
301+
return nil, errors.New("amsterdamTime overflow")
302+
}
303+
amsterdamTimeU64 := chainConfig.AmsterdamTime.Uint64()
304+
res.amsterdamTime = &amsterdamTimeU64
305+
}
296306

297307
res.p2pFetcher = NewFetch(ctx, sentryClients, res, stateChangesClient, poolDB, res.chainID, logger, opts...)
298308
res.p2pSender = NewSend(ctx, sentryClients, logger, opts...)
@@ -942,8 +952,11 @@ func toBlobs(_blobs [][]byte) []*goethkzg.Blob {
942952
func (p *TxPool) validateTx(txn *TxnSlot, isLocal bool, stateCache kvcache.CacheView) txpoolcfg.DiscardReason {
943953
isEIP3860 := p.isShanghai() || p.isAgra()
944954
isPrague := p.isPrague() || p.isBhilai()
945-
if isEIP3860 && txn.Creation && txn.DataLen > params.MaxInitCodeSize {
946-
return txpoolcfg.InitCodeTooLarge // EIP-3860
955+
isEIP7954 := p.isAmsterdam()
956+
if txn.Creation {
957+
if err := vm.CheckMaxInitCodeSize(uint64(txn.DataLen), isEIP3860, isEIP7954); err != nil {
958+
return txpoolcfg.InitCodeTooLarge
959+
}
947960
}
948961

949962
if txn.Type == types.AccountAbstractionTxType {
@@ -1248,6 +1261,10 @@ func (p *TxPool) isOsaka() bool {
12481261
return isTimeBasedForkActivated(&p.isPostOsaka, p.osakaTime)
12491262
}
12501263

1264+
func (p *TxPool) isAmsterdam() bool {
1265+
return isTimeBasedForkActivated(&p.isPostAmsterdam, p.amsterdamTime)
1266+
}
1267+
12511268
func (p *TxPool) GetMaxBlobsPerBlock() uint64 {
12521269
now := time.Now().Unix()
12531270
return p.chainConfig.GetMaxBlobsPerBlock(uint64(now))

0 commit comments

Comments
 (0)