mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-16 04:56:36 +00:00
core/state, core/vm: Nyota contract create init simplification (#30409)
Implementation of [this EIP-4762 update](https://github.com/ethereum/EIPs/pull/8867). --------- Signed-off-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Co-authored-by: Tanishq Jasoria <jasoriatanishq@gmail.com>
This commit is contained in:
parent
c0b5d428a9
commit
9be2e010c1
4 changed files with 41 additions and 16 deletions
|
|
@ -117,11 +117,23 @@ func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address)
|
||||||
return gas
|
return gas
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContractCreateCPreheck charges access costs before
|
||||||
|
// a contract creation is initiated. It is just reads, because the
|
||||||
|
// address collision is done before the transfer, and so no write
|
||||||
|
// are guaranteed to happen at this point.
|
||||||
|
func (ae *AccessEvents) ContractCreatePreCheckGas(addr common.Address) uint64 {
|
||||||
|
var gas uint64
|
||||||
|
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, false)
|
||||||
|
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, false)
|
||||||
|
return gas
|
||||||
|
}
|
||||||
|
|
||||||
// ContractCreateInitGas returns the access gas costs for the initialization of
|
// ContractCreateInitGas returns the access gas costs for the initialization of
|
||||||
// a contract creation.
|
// a contract creation.
|
||||||
func (ae *AccessEvents) ContractCreateInitGas(addr common.Address, createSendsValue bool) uint64 {
|
func (ae *AccessEvents) ContractCreateInitGas(addr common.Address) uint64 {
|
||||||
var gas uint64
|
var gas uint64
|
||||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, true)
|
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, true)
|
||||||
|
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, true)
|
||||||
return gas
|
return gas
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,13 +100,13 @@ func TestContractCreateInitGas(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check cold read cost, without a value
|
// Check cold read cost, without a value
|
||||||
gas := ae.ContractCreateInitGas(testAddr, false)
|
gas := ae.ContractCreateInitGas(testAddr)
|
||||||
if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + params.WitnessChunkWriteCost + params.WitnessChunkReadCost; gas != want {
|
if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + 2*params.WitnessChunkWriteCost + 2*params.WitnessChunkReadCost; gas != want {
|
||||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check warm read cost
|
// Check warm read cost
|
||||||
gas = ae.ContractCreateInitGas(testAddr, false)
|
gas = ae.ContractCreateInitGas(testAddr)
|
||||||
if gas != 0 {
|
if gas != 0 {
|
||||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -306,6 +306,8 @@ const (
|
||||||
GasChangeWitnessContractCreation GasChangeReason = 16
|
GasChangeWitnessContractCreation GasChangeReason = 16
|
||||||
// GasChangeWitnessCodeChunk is the amount charged for touching one or more contract code chunks
|
// GasChangeWitnessCodeChunk is the amount charged for touching one or more contract code chunks
|
||||||
GasChangeWitnessCodeChunk GasChangeReason = 17
|
GasChangeWitnessCodeChunk GasChangeReason = 17
|
||||||
|
// GasChangeWitnessContractCollisionCheck the amount charged for checking a contract collision
|
||||||
|
GasChangeWitnessContractCollisionCheck GasChangeReason = 17
|
||||||
|
|
||||||
// GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as
|
// GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as
|
||||||
// it will be "manually" tracked by a direct emit of the gas change event.
|
// it will be "manually" tracked by a direct emit of the gas change event.
|
||||||
|
|
|
||||||
|
|
@ -448,6 +448,18 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||||
}
|
}
|
||||||
evm.StateDB.SetNonce(caller.Address(), nonce+1)
|
evm.StateDB.SetNonce(caller.Address(), nonce+1)
|
||||||
|
|
||||||
|
// Charge the contract creation init gas in verkle mode
|
||||||
|
if evm.chainRules.IsEIP4762 {
|
||||||
|
statelessGas := evm.AccessEvents.ContractCreatePreCheckGas(address)
|
||||||
|
if statelessGas > gas {
|
||||||
|
return nil, common.Address{}, 0, ErrOutOfGas
|
||||||
|
}
|
||||||
|
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||||
|
evm.Config.Tracer.OnGasChange(gas, gas-statelessGas, tracing.GasChangeWitnessContractCollisionCheck)
|
||||||
|
}
|
||||||
|
gas = gas - statelessGas
|
||||||
|
}
|
||||||
|
|
||||||
// We add this to the access list _before_ taking a snapshot. Even if the
|
// We add this to the access list _before_ taking a snapshot. Even if the
|
||||||
// creation fails, the access-list change should not be rolled back.
|
// creation fails, the access-list change should not be rolled back.
|
||||||
if evm.chainRules.IsEIP2929 {
|
if evm.chainRules.IsEIP2929 {
|
||||||
|
|
@ -484,6 +496,17 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
|
||||||
if evm.chainRules.IsEIP158 {
|
if evm.chainRules.IsEIP158 {
|
||||||
evm.StateDB.SetNonce(address, 1)
|
evm.StateDB.SetNonce(address, 1)
|
||||||
}
|
}
|
||||||
|
// Charge the contract creation init gas in verkle mode
|
||||||
|
if evm.chainRules.IsEIP4762 {
|
||||||
|
statelessGas := evm.AccessEvents.ContractCreateInitGas(address)
|
||||||
|
if statelessGas > gas {
|
||||||
|
return nil, common.Address{}, 0, ErrOutOfGas
|
||||||
|
}
|
||||||
|
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||||
|
evm.Config.Tracer.OnGasChange(gas, gas-statelessGas, tracing.GasChangeWitnessContractInit)
|
||||||
|
}
|
||||||
|
gas = gas - statelessGas
|
||||||
|
}
|
||||||
evm.Context.Transfer(evm.StateDB, caller.Address(), address, value)
|
evm.Context.Transfer(evm.StateDB, caller.Address(), address, value)
|
||||||
|
|
||||||
// Initialise a new contract and set the code that is to be used by the EVM.
|
// 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,
|
||||||
// initNewContract runs a new contract's creation code, performs checks on the
|
// initNewContract runs a new contract's creation code, performs checks on the
|
||||||
// resulting code that is to be deployed, and consumes necessary gas.
|
// resulting code that is to be deployed, and consumes necessary gas.
|
||||||
func (evm *EVM) initNewContract(contract *Contract, address common.Address, value *uint256.Int) ([]byte, error) {
|
func (evm *EVM) initNewContract(contract *Contract, address common.Address, value *uint256.Int) ([]byte, error) {
|
||||||
// Charge the contract creation init gas in verkle mode
|
|
||||||
if evm.chainRules.IsEIP4762 {
|
|
||||||
if !contract.UseGas(evm.AccessEvents.ContractCreateInitGas(address, value.Sign() != 0), evm.Config.Tracer, tracing.GasChangeWitnessContractInit) {
|
|
||||||
return nil, ErrOutOfGas
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret, err := evm.interpreter.Run(contract, nil, false)
|
ret, err := evm.interpreter.Run(contract, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ret, err
|
return ret, err
|
||||||
|
|
@ -533,11 +549,6 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address, valu
|
||||||
return ret, ErrCodeStoreOutOfGas
|
return ret, ErrCodeStoreOutOfGas
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Contract creation completed, touch the missing fields in the contract
|
|
||||||
if !contract.UseGas(evm.AccessEvents.AddAccount(address, true), evm.Config.Tracer, tracing.GasChangeWitnessContractCreation) {
|
|
||||||
return ret, ErrCodeStoreOutOfGas
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ret) > 0 && !contract.UseGas(evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true), evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) {
|
if len(ret) > 0 && !contract.UseGas(evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true), evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) {
|
||||||
return ret, ErrCodeStoreOutOfGas
|
return ret, ErrCodeStoreOutOfGas
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue