Skip to content

Commit

Permalink
core/{state, vm}: Nyota contract create init simplification
Browse files Browse the repository at this point in the history
Co-authored-by: Tanishq Jasoria <[email protected]>
  • Loading branch information
gballet and tanishqjasoria committed Sep 6, 2024
1 parent 88c8459 commit 3ba2a4d
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 15 deletions.
14 changes: 13 additions & 1 deletion core/state/access_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,23 @@ func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address)
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 (aw *AccessEvents) ContractCreatePreCheckGas(addr common.Address) uint64 {
var gas uint64
gas += aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, false)
gas += aw.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, false)
return gas
}

// ContractCreateInitGas returns the access gas costs for the initialization of
// a contract creation.
func (ae *AccessEvents) ContractCreateInitGas(addr common.Address, createSendsValue bool) uint64 {
func (ae *AccessEvents) ContractCreateInitGas(addr common.Address) uint64 {
var gas uint64
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BasicDataLeafKey, true)
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeHashLeafKey, true)
return gas
}

Expand Down
4 changes: 2 additions & 2 deletions core/state/access_events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,13 @@ func TestContractCreateInitGas(t *testing.T) {
}

// 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 {
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
}

// Check warm read cost
gas = ae.ContractCreateInitGas(testAddr, false)
gas = ae.ContractCreateInitGas(testAddr)
if gas != 0 {
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
}
Expand Down
28 changes: 16 additions & 12 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,14 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
}
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
}
}

// 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.
if evm.chainRules.IsEIP2929 {
Expand Down Expand Up @@ -484,6 +492,14 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
if evm.chainRules.IsEIP158 {
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
}
gas = gas - statelessGas
}
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.
Expand All @@ -505,13 +521,6 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
// initNewContract runs a new contract's creation code, performs checks on the
// 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) {
// 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)
if err != nil {
return ret, err
Expand All @@ -533,11 +542,6 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address, valu
return ret, ErrCodeStoreOutOfGas
}
} 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) {
return ret, ErrCodeStoreOutOfGas
}
Expand Down

0 comments on commit 3ba2a4d

Please sign in to comment.