Skip to content

Commit 56b9322

Browse files
core: implement EIP-8037, state creation gas cost increase
Co-authored-by: MariusVanDerWijden <m.vanderwijden@live.de>
1 parent 0fc5059 commit 56b9322

File tree

12 files changed

+253
-38
lines changed

12 files changed

+253
-38
lines changed

cmd/evm/internal/t8ntool/transaction.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ func Transaction(ctx *cli.Context) error {
133133
}
134134
// Check intrinsic gas
135135
rules := chainConfig.Rules(common.Big0, true, 0)
136-
gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai)
136+
gasCostPerStateByte := core.CostPerStateByte(&types.Header{}, chainConfig)
137+
gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, rules, gasCostPerStateByte)
137138
if err != nil {
138139
r.Error = err
139140
results = append(results, r)

core/bench_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
8989
data := make([]byte, nbytes)
9090
return func(i int, gen *BlockGen) {
9191
toaddr := common.Address{}
92-
gas, _ := IntrinsicGas(data, nil, nil, false, false, false, false)
92+
gasCostPerStateByte := CostPerStateByte(gen.header, gen.cm.config)
93+
gas, _ := IntrinsicGas(data, nil, nil, false, params.Rules{}, gasCostPerStateByte)
9394
signer := gen.Signer()
9495
gasPrice := big.NewInt(0)
9596
if gen.header.BaseFee != nil {

core/bintrie_witness_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,12 @@ var (
6363
func TestProcessVerkle(t *testing.T) {
6464
var (
6565
code = common.FromHex(`6060604052600a8060106000396000f360606040526008565b00`)
66-
intrinsicContractCreationGas, _ = IntrinsicGas(code, nil, nil, true, true, true, true)
66+
intrinsicContractCreationGas, _ = IntrinsicGas(code, nil, nil, true, params.Rules{IsHomestead: true, IsIstanbul: true, IsShanghai: true}, 0)
6767
// A contract creation that calls EXTCODECOPY in the constructor. Used to ensure that the witness
6868
// will not contain that copied data.
6969
// Source: https://gist.github.com/gballet/a23db1e1cb4ed105616b5920feb75985
7070
codeWithExtCodeCopy = common.FromHex(`0x60806040526040516100109061017b565b604051809103906000f08015801561002c573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561007857600080fd5b5060008067ffffffffffffffff8111156100955761009461024a565b5b6040519080825280601f01601f1916602001820160405280156100c75781602001600182028036833780820191505090505b50905060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506020600083833c81610101906101e3565b60405161010d90610187565b61011791906101a3565b604051809103906000f080158015610133573d6000803e3d6000fd5b50600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505061029b565b60d58061046783390190565b6102068061053c83390190565b61019d816101d9565b82525050565b60006020820190506101b86000830184610194565b92915050565b6000819050602082019050919050565b600081519050919050565b6000819050919050565b60006101ee826101ce565b826101f8846101be565b905061020381610279565b925060208210156102435761023e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8360200360080261028e565b831692505b5050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600061028582516101d9565b80915050919050565b600082821b905092915050565b6101bd806102aa6000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f566852414610030575b600080fd5b61003861004e565b6040516100459190610146565b60405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166381ca91d36040518163ffffffff1660e01b815260040160206040518083038186803b1580156100b857600080fd5b505afa1580156100cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100f0919061010a565b905090565b60008151905061010481610170565b92915050565b6000602082840312156101205761011f61016b565b5b600061012e848285016100f5565b91505092915050565b61014081610161565b82525050565b600060208201905061015b6000830184610137565b92915050565b6000819050919050565b600080fd5b61017981610161565b811461018457600080fd5b5056fea2646970667358221220a6a0e11af79f176f9c421b7b12f441356b25f6489b83d38cc828a701720b41f164736f6c63430008070033608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063ab5ed15014602d575b600080fd5b60336047565b604051603e9190605d565b60405180910390f35b60006001905090565b6057816076565b82525050565b6000602082019050607060008301846050565b92915050565b600081905091905056fea26469706673582212203a14eb0d5cd07c277d3e24912f110ddda3e553245a99afc4eeefb2fbae5327aa64736f6c63430008070033608060405234801561001057600080fd5b5060405161020638038061020683398181016040528101906100329190610063565b60018160001c6100429190610090565b60008190555050610145565b60008151905061005d8161012e565b92915050565b60006020828403121561007957610078610129565b5b60006100878482850161004e565b91505092915050565b600061009b826100f0565b91506100a6836100f0565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156100db576100da6100fa565b5b828201905092915050565b6000819050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600080fd5b610137816100e6565b811461014257600080fd5b50565b60b3806101536000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806381ca91d314602d575b600080fd5b60336047565b604051603e9190605a565b60405180910390f35b60005481565b6054816073565b82525050565b6000602082019050606d6000830184604d565b92915050565b600081905091905056fea26469706673582212209bff7098a2f526de1ad499866f27d6d0d6f17b74a413036d6063ca6a0998ca4264736f6c63430008070033`)
71-
intrinsicCodeWithExtCodeCopyGas, _ = IntrinsicGas(codeWithExtCodeCopy, nil, nil, true, true, true, true)
71+
intrinsicCodeWithExtCodeCopyGas, _ = IntrinsicGas(codeWithExtCodeCopy, nil, nil, true, params.Rules{IsHomestead: true, IsIstanbul: true, IsShanghai: true}, 0)
7272
signer = types.LatestSigner(testVerkleChainConfig)
7373
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
7474
bcdb = rawdb.NewMemoryDatabase() // Database for the blockchain
@@ -199,7 +199,7 @@ func TestProcessParentBlockHash(t *testing.T) {
199199
if isVerkle {
200200
chainConfig = testVerkleChainConfig
201201
}
202-
vmContext := NewEVMBlockContext(header, nil, new(common.Address))
202+
vmContext := NewEVMBlockContext(header, &BlockChain{chainConfig: chainConfig}, new(common.Address))
203203
evm := vm.NewEVM(vmContext, statedb, chainConfig, vm.Config{})
204204
ProcessParentBlockHash(header.ParentHash, evm)
205205
}

core/evm.go

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,23 +64,34 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
6464
random = &header.MixDigest
6565
}
6666
if header.SlotNumber != nil {
67+
6768
slotNum = *header.SlotNumber
6869
}
6970

7071
return vm.BlockContext{
71-
CanTransfer: CanTransfer,
72-
Transfer: Transfer,
73-
GetHash: GetHashFn(header, chain),
74-
Coinbase: beneficiary,
75-
BlockNumber: new(big.Int).Set(header.Number),
76-
Time: header.Time,
77-
Difficulty: new(big.Int).Set(header.Difficulty),
78-
BaseFee: baseFee,
79-
BlobBaseFee: blobBaseFee,
80-
GasLimit: header.GasLimit,
81-
Random: random,
82-
SlotNum: slotNum,
72+
CanTransfer: CanTransfer,
73+
Transfer: Transfer,
74+
GetHash: GetHashFn(header, chain),
75+
Coinbase: beneficiary,
76+
BlockNumber: new(big.Int).Set(header.Number),
77+
Time: header.Time,
78+
Difficulty: new(big.Int).Set(header.Difficulty),
79+
BaseFee: baseFee,
80+
BlobBaseFee: blobBaseFee,
81+
GasLimit: header.GasLimit,
82+
Random: random,
83+
SlotNum: slotNum,
84+
CostPerGasByte: CostPerStateByte(header, chain.Config()),
85+
}
86+
}
87+
88+
// CostPerStateByte computes the cost per one byte of state creation
89+
// after EIP-8037
90+
func CostPerStateByte(header *types.Header, config *params.ChainConfig) uint64 {
91+
if config.IsAmsterdam(header.Number, header.Time) {
92+
return ((header.GasLimit / 2) * 7200 * 365) / params.TargetStateGrowthPerYear
8393
}
94+
return 0
8495
}
8596

8697
// NewEVMTxContext creates a new transaction context for a single transaction.

core/state_transition.go

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,17 @@ func (result *ExecutionResult) Revert() []byte {
6767
}
6868

6969
// IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
70-
func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.SetCodeAuthorization, isContractCreation, isHomestead, isEIP2028, isEIP3860 bool) (uint64, error) {
70+
// costPerStateByte needs to be set post-Amsterdam.
71+
func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.SetCodeAuthorization, isContractCreation bool, rules params.Rules, costPerStateByte uint64) (uint64, error) {
7172
// Set the starting gas for the raw transaction
7273
var gas uint64
73-
if isContractCreation && isHomestead {
74-
gas = params.TxGasContractCreation
74+
if isContractCreation && rules.IsHomestead {
75+
if rules.IsAmsterdam {
76+
// TODO fix EIP-8037
77+
gas = params.AccountCreationSize * costPerStateByte
78+
} else {
79+
gas = params.TxGasContractCreation
80+
}
7581
} else {
7682
gas = params.TxGas
7783
}
@@ -84,7 +90,7 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set
8490

8591
// Make sure we don't exceed uint64 for all data combinations
8692
nonZeroGas := params.TxDataNonZeroGasFrontier
87-
if isEIP2028 {
93+
if rules.IsIstanbul {
8894
nonZeroGas = params.TxDataNonZeroGasEIP2028
8995
}
9096
if (math.MaxUint64-gas)/nonZeroGas < nz {
@@ -97,7 +103,7 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set
97103
}
98104
gas += z * params.TxDataZeroGas
99105

100-
if isContractCreation && isEIP3860 {
106+
if isContractCreation && rules.IsShanghai {
101107
lenWords := toWordSize(dataLen)
102108
if (math.MaxUint64-gas)/params.InitCodeWordGas < lenWords {
103109
return 0, ErrGasUintOverflow
@@ -110,7 +116,11 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set
110116
gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas
111117
}
112118
if authList != nil {
113-
gas += uint64(len(authList)) * params.CallNewAccountGas
119+
if rules.IsAmsterdam {
120+
gas += uint64(len(authList)) * costPerStateByte
121+
} else {
122+
gas += uint64(len(authList)) * params.CallNewAccountGas
123+
}
114124
}
115125
return gas, nil
116126
}
@@ -447,7 +457,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
447457
)
448458

449459
// Check clauses 4-5, subtract intrinsic gas if everything is correct
450-
gas, err := IntrinsicGas(msg.Data, msg.AccessList, msg.SetCodeAuthorizations, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai)
460+
gas, err := IntrinsicGas(msg.Data, msg.AccessList, msg.SetCodeAuthorizations, contractCreation, rules, st.evm.Context.CostPerGasByte)
451461
if err != nil {
452462
return nil, err
453463
}
@@ -512,7 +522,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
512522
if msg.SetCodeAuthorizations != nil {
513523
for _, auth := range msg.SetCodeAuthorizations {
514524
// Note errors are ignored, we simply skip invalid authorizations here.
515-
st.applyAuthorization(&auth)
525+
st.applyAuthorization(rules, &auth)
516526
}
517527
}
518528

@@ -626,7 +636,7 @@ func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorizatio
626636
}
627637

628638
// applyAuthorization applies an EIP-7702 code delegation to the state.
629-
func (st *stateTransition) applyAuthorization(auth *types.SetCodeAuthorization) error {
639+
func (st *stateTransition) applyAuthorization(rules params.Rules, auth *types.SetCodeAuthorization) error {
630640
authority, err := st.validateAuthorization(auth)
631641
if err != nil {
632642
return err
@@ -635,7 +645,13 @@ func (st *stateTransition) applyAuthorization(auth *types.SetCodeAuthorization)
635645
// If the account already exists in state, refund the new account cost
636646
// charged in the intrinsic calculation.
637647
if st.state.Exist(authority) {
638-
st.state.AddRefund(params.CallNewAccountGas - params.TxAuthTupleGas)
648+
if rules.IsAmsterdam {
649+
newAccountCost := params.AccountCreationSize * st.evm.Context.CostPerGasByte
650+
perAuthBasCost := params.AuthorizationCreationSize * st.evm.Context.CostPerGasByte
651+
st.state.AddRefund(newAccountCost - perAuthBasCost)
652+
} else {
653+
st.state.AddRefund(params.CallNewAccountGas - params.TxAuthTupleGas)
654+
}
639655
}
640656

641657
prevDelegation, isDelegated := types.ParseDelegation(st.state.GetCode(authority))

core/txpool/validation.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,23 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
125125
}
126126
// Ensure the transaction has more gas than the bare minimum needed to cover
127127
// the transaction metadata
128-
intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, true, rules.IsIstanbul, rules.IsShanghai)
128+
gasCostPerStateByte := core.CostPerStateByte(head, opts.Config)
129+
intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, rules, gasCostPerStateByte)
129130
if err != nil {
130131
return err
131132
}
133+
if gasCostPerStateByte != 0 {
134+
// We require transactions to pay for 110% of intrinsic gas in order to
135+
// prevent situations where a change in gas limit invalidates a lot
136+
// of transactions in the txpool
137+
if tx.Gas() < (intrGas*10)/9 {
138+
return fmt.Errorf("%w: gas %v, minimum needed %v", core.ErrIntrinsicGas, tx.Gas(), intrGas)
139+
}
140+
}
132141
if tx.Gas() < intrGas {
133142
return fmt.Errorf("%w: gas %v, minimum needed %v", core.ErrIntrinsicGas, tx.Gas(), intrGas)
134143
}
144+
135145
// Ensure the transaction can cover floor data gas.
136146
if rules.IsPrague {
137147
floorDataGas, err := core.FloorDataGas(tx.Data())

core/vm/eips.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ var activators = map[int]func(*JumpTable){
4444
7939: enable7939,
4545
8024: enable8024,
4646
7843: enable7843,
47+
8037: enable8037,
4748
}
4849

4950
// EnableEIP enables the given EIP on the config.
@@ -596,3 +597,10 @@ func enable7843(jt *JumpTable) {
596597
maxStack: maxStack(0, 1),
597598
}
598599
}
600+
func enable8037(jt *JumpTable) {
601+
jt[CREATE].dynamicGas = gasCreateEip8037
602+
jt[CREATE2].dynamicGas = gasCreate2Eip8037
603+
jt[CALL].dynamicGas = gasCall8037
604+
jt[SELFDESTRUCT].dynamicGas = gasSelfdestruct8037
605+
jt[SSTORE].dynamicGas = gasSStore8037
606+
}

core/vm/evm.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,16 @@ type BlockContext struct {
5858
GetHash GetHashFunc
5959

6060
// Block information
61-
Coinbase common.Address // Provides information for COINBASE
62-
GasLimit uint64 // Provides information for GASLIMIT
63-
BlockNumber *big.Int // Provides information for NUMBER
64-
Time uint64 // Provides information for TIME
65-
Difficulty *big.Int // Provides information for DIFFICULTY
66-
BaseFee *big.Int // Provides information for BASEFEE (0 if vm runs with NoBaseFee flag and 0 gas price)
67-
BlobBaseFee *big.Int // Provides information for BLOBBASEFEE (0 if vm runs with NoBaseFee flag and 0 blob gas price)
68-
Random *common.Hash // Provides information for PREVRANDAO
69-
SlotNum uint64 // Provides information for SLOTNUM
61+
Coinbase common.Address // Provides information for COINBASE
62+
GasLimit uint64 // Provides information for GASLIMIT
63+
BlockNumber *big.Int // Provides information for NUMBER
64+
Time uint64 // Provides information for TIME
65+
Difficulty *big.Int // Provides information for DIFFICULTY
66+
BaseFee *big.Int // Provides information for BASEFEE (0 if vm runs with NoBaseFee flag and 0 gas price)
67+
BlobBaseFee *big.Int // Provides information for BLOBBASEFEE (0 if vm runs with NoBaseFee flag and 0 blob gas price)
68+
Random *common.Hash // Provides information for PREVRANDAO
69+
SlotNum uint64 // Provides information for SLOTNUM
70+
CostPerGasByte uint64 // EIP-8037
7071
}
7172

7273
// TxContext provides the EVM with information about a transaction.
@@ -617,6 +618,9 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]b
617618

618619
if !evm.chainRules.IsEIP4762 {
619620
createDataGas := uint64(len(ret)) * params.CreateDataGas
621+
if evm.chainRules.IsAmsterdam {
622+
createDataGas = uint64(len(ret)) * evm.Context.CostPerGasByte
623+
}
620624
if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
621625
return ret, ErrCodeStoreOutOfGas
622626
}

0 commit comments

Comments
 (0)