Skip to content

Commit 6661828

Browse files
committed
core: Make creation transaction invalid if initcode size above limit
1 parent b6b7fd4 commit 6661828

File tree

4 files changed

+71
-0
lines changed

4 files changed

+71
-0
lines changed

cmd/evm/internal/t8ntool/transaction.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ func Transaction(ctx *cli.Context) error {
178178
case new(big.Int).Mul(tx.GasFeeCap(), new(big.Int).SetUint64(tx.Gas())).BitLen() > 256:
179179
r.Error = errors.New("gas * maxFeePerGas exceeds 256 bits")
180180
}
181+
// Check whether the init code size has been exceeded.
182+
if eip3860 && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize {
183+
r.Error = errors.New("init code size limit exceeded")
184+
}
181185
results = append(results, r)
182186
}
183187
out, err := json.MarshalIndent(results, "", " ")

core/error.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ var (
6363
// have enough funds for transfer(topmost call only).
6464
ErrInsufficientFundsForTransfer = errors.New("insufficient funds for transfer")
6565

66+
// ErrMaxInitCodeSizeExceeded is returned if creation transaction provides the init code bigger
67+
// than init code size limit.
68+
ErrMaxInitCodeSizeExceeded = errors.New("max initcode size exceeded")
69+
6670
// ErrInsufficientFunds is returned if the total cost of executing a transaction
6771
// is higher than the balance of the user's account.
6872
ErrInsufficientFunds = errors.New("insufficient funds for gas * price + value")

core/state_processor_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,17 @@ func TestStateProcessorErrors(t *testing.T) {
7575
}), signer, key1)
7676
return tx
7777
}
78+
var mkDynamicCreationTx = func(nonce uint64, gasLimit uint64, gasTipCap, gasFeeCap *big.Int, data []byte) *types.Transaction {
79+
tx, _ := types.SignTx(types.NewTx(&types.DynamicFeeTx{
80+
Nonce: nonce,
81+
GasTipCap: gasTipCap,
82+
GasFeeCap: gasFeeCap,
83+
Gas: gasLimit,
84+
Value: big.NewInt(0),
85+
Data: data,
86+
}), signer, key1)
87+
return tx
88+
}
7889
{ // Tests against a 'recent' chain definition
7990
var (
8091
db = rawdb.NewMemoryDatabase()
@@ -297,6 +308,53 @@ func TestStateProcessorErrors(t *testing.T) {
297308
}
298309
}
299310
}
311+
312+
// ErrMaxInitCodeSizeExceeded, for this we need extra EIP-3860 enabled.
313+
{
314+
var (
315+
db = rawdb.NewMemoryDatabase()
316+
gspec = &Genesis{
317+
Config: config,
318+
Alloc: GenesisAlloc{
319+
common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{
320+
Balance: big.NewInt(1000000000000000000), // 1 ether
321+
Nonce: 0,
322+
},
323+
},
324+
}
325+
genesis = gspec.MustCommit(db)
326+
blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{ExtraEips: []int{3860}}, nil, nil)
327+
tooBigInitCode = [params.MaxInitCodeSize + 1]byte{}
328+
smallInitCode = [320]byte{}
329+
)
330+
defer blockchain.Stop()
331+
for i, tt := range []struct {
332+
txs []*types.Transaction
333+
want string
334+
}{
335+
{ // ErrMaxInitCodeSizeExceeded
336+
txs: []*types.Transaction{
337+
mkDynamicCreationTx(0, 500000, common.Big0, misc.CalcBaseFee(config, genesis.Header()), tooBigInitCode[:]),
338+
},
339+
want: "could not apply tx 0 [0x832b54a6c3359474a9f504b1003b2cc1b6fcaa18e4ef369eb45b5d40dad6378f]: max initcode size exceeded: code size 49153 limit 49152",
340+
},
341+
{ // ErrIntrinsicGas: Not enough gas to cover init code
342+
txs: []*types.Transaction{
343+
mkDynamicCreationTx(0, 54299, common.Big0, misc.CalcBaseFee(config, genesis.Header()), smallInitCode[:]),
344+
},
345+
want: "could not apply tx 0 [0x39b7436cb432d3662a25626474282c5c4c1a213326fd87e4e18a91477bae98b2]: intrinsic gas too low: have 54299, want 54300",
346+
},
347+
} {
348+
block := GenerateBadBlock(genesis, ethash.NewFaker(), tt.txs, gspec.Config)
349+
_, err := blockchain.InsertChain(types.Blocks{block})
350+
if err == nil {
351+
t.Fatal("block imported without errors")
352+
}
353+
if have, want := err.Error(), tt.want; have != want {
354+
t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want)
355+
}
356+
}
357+
}
300358
}
301359

302360
// GenerateBadBlock constructs a "block" which contains the transactions. The transactions are not expected to be

core/state_transition.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,11 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
328328
return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex())
329329
}
330330

331+
// Check whether the init code size has been exceeded.
332+
if eip3860 && contractCreation && len(st.data) > params.MaxInitCodeSize {
333+
return nil, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(st.data), params.MaxInitCodeSize)
334+
}
335+
331336
// Set up the initial access list.
332337
if rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber); rules.IsBerlin {
333338
st.state.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())

0 commit comments

Comments
 (0)