Skip to content

Commit 9be2e01

Browse files
core/state, core/vm: Nyota contract create init simplification (#30409)
Implementation of [this EIP-4762 update](ethereum/EIPs#8867). --------- Signed-off-by: Guillaume Ballet <[email protected]> Co-authored-by: Tanishq Jasoria <[email protected]>
1 parent c0b5d42 commit 9be2e01

File tree

4 files changed

+41
-16
lines changed

4 files changed

+41
-16
lines changed

core/state/access_events.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,23 @@ func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address)
117117
return gas
118118
}
119119

120+
// ContractCreateCPreheck charges access costs before
121+
// a contract creation is initiated. It is just reads, because the
122+
// address collision is done before the transfer, and so no write
123+
// are guaranteed to happen at this point.
124+
func (ae *AccessEvents) ContractCreatePreCheckGas(addr common.Address) uint64 {
125+
var gas uint64
126+
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, false)
127+
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, false)
128+
return gas
129+
}
130+
120131
// ContractCreateInitGas returns the access gas costs for the initialization of
121132
// a contract creation.
122-
func (ae *AccessEvents) ContractCreateInitGas(addr common.Address, createSendsValue bool) uint64 {
133+
func (ae *AccessEvents) ContractCreateInitGas(addr common.Address) uint64 {
123134
var gas uint64
124135
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, true)
136+
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, true)
125137
return gas
126138
}
127139

core/state/access_events_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,13 @@ func TestContractCreateInitGas(t *testing.T) {
100100
}
101101

102102
// Check cold read cost, without a value
103-
gas := ae.ContractCreateInitGas(testAddr, false)
104-
if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + params.WitnessChunkWriteCost + params.WitnessChunkReadCost; gas != want {
103+
gas := ae.ContractCreateInitGas(testAddr)
104+
if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + 2*params.WitnessChunkWriteCost + 2*params.WitnessChunkReadCost; gas != want {
105105
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
106106
}
107107

108108
// Check warm read cost
109-
gas = ae.ContractCreateInitGas(testAddr, false)
109+
gas = ae.ContractCreateInitGas(testAddr)
110110
if gas != 0 {
111111
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
112112
}

core/tracing/hooks.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ const (
306306
GasChangeWitnessContractCreation GasChangeReason = 16
307307
// GasChangeWitnessCodeChunk is the amount charged for touching one or more contract code chunks
308308
GasChangeWitnessCodeChunk GasChangeReason = 17
309+
// GasChangeWitnessContractCollisionCheck the amount charged for checking a contract collision
310+
GasChangeWitnessContractCollisionCheck GasChangeReason = 17
309311

310312
// GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as
311313
// it will be "manually" tracked by a direct emit of the gas change event.

core/vm/evm.go

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,18 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
448448
}
449449
evm.StateDB.SetNonce(caller.Address(), nonce+1)
450450

451+
// Charge the contract creation init gas in verkle mode
452+
if evm.chainRules.IsEIP4762 {
453+
statelessGas := evm.AccessEvents.ContractCreatePreCheckGas(address)
454+
if statelessGas > gas {
455+
return nil, common.Address{}, 0, ErrOutOfGas
456+
}
457+
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
458+
evm.Config.Tracer.OnGasChange(gas, gas-statelessGas, tracing.GasChangeWitnessContractCollisionCheck)
459+
}
460+
gas = gas - statelessGas
461+
}
462+
451463
// We add this to the access list _before_ taking a snapshot. Even if the
452464
// creation fails, the access-list change should not be rolled back.
453465
if evm.chainRules.IsEIP2929 {
@@ -484,6 +496,17 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
484496
if evm.chainRules.IsEIP158 {
485497
evm.StateDB.SetNonce(address, 1)
486498
}
499+
// Charge the contract creation init gas in verkle mode
500+
if evm.chainRules.IsEIP4762 {
501+
statelessGas := evm.AccessEvents.ContractCreateInitGas(address)
502+
if statelessGas > gas {
503+
return nil, common.Address{}, 0, ErrOutOfGas
504+
}
505+
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
506+
evm.Config.Tracer.OnGasChange(gas, gas-statelessGas, tracing.GasChangeWitnessContractInit)
507+
}
508+
gas = gas - statelessGas
509+
}
487510
evm.Context.Transfer(evm.StateDB, caller.Address(), address, value)
488511

489512
// Initialise a new contract and set the code that is to be used by the EVM.
@@ -505,13 +528,6 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
505528
// initNewContract runs a new contract's creation code, performs checks on the
506529
// resulting code that is to be deployed, and consumes necessary gas.
507530
func (evm *EVM) initNewContract(contract *Contract, address common.Address, value *uint256.Int) ([]byte, error) {
508-
// Charge the contract creation init gas in verkle mode
509-
if evm.chainRules.IsEIP4762 {
510-
if !contract.UseGas(evm.AccessEvents.ContractCreateInitGas(address, value.Sign() != 0), evm.Config.Tracer, tracing.GasChangeWitnessContractInit) {
511-
return nil, ErrOutOfGas
512-
}
513-
}
514-
515531
ret, err := evm.interpreter.Run(contract, nil, false)
516532
if err != nil {
517533
return ret, err
@@ -533,11 +549,6 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address, valu
533549
return ret, ErrCodeStoreOutOfGas
534550
}
535551
} else {
536-
// Contract creation completed, touch the missing fields in the contract
537-
if !contract.UseGas(evm.AccessEvents.AddAccount(address, true), evm.Config.Tracer, tracing.GasChangeWitnessContractCreation) {
538-
return ret, ErrCodeStoreOutOfGas
539-
}
540-
541552
if len(ret) > 0 && !contract.UseGas(evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true), evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) {
542553
return ret, ErrCodeStoreOutOfGas
543554
}

0 commit comments

Comments
 (0)