Skip to content

Commit

Permalink
rerwork addressInAccessList into calculateAccessCost
Browse files Browse the repository at this point in the history
  • Loading branch information
facuMH committed Sep 6, 2024
1 parent 4184cb3 commit 7cfbdf6
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 98 deletions.
21 changes: 6 additions & 15 deletions go/interpreter/lfvm/gas.go
Original file line number Diff line number Diff line change
Expand Up @@ -457,26 +457,17 @@ func gasEip2929AccountCheck(c *context, address tosca.Address) error {
return nil
}

func addressInAccessList(c *context) (warmAccess bool, coldCost tosca.Gas, err error) {
warmAccess = true
if c.isAtLeast(tosca.R09_Berlin) {
addr := tosca.Address(c.stack.peekN(1).Bytes20())
func calculateAccessCost(address tosca.Address, revision tosca.Revision, runContext tosca.RunContext) (isWarm bool, accessCost tosca.Gas) {
isWarm = true
if revision >= tosca.R09_Berlin {
// Check slot presence in the access list
//lint:ignore SA1019 deprecated functions to be migrated in #616
warmAccess = c.context.IsAddressInAccessList(addr)
isWarm = runContext.IsAddressInAccessList(address)
// The WarmStorageReadCostEIP2929 (100) is already deducted in the form of a constant cost, so
// the cost to charge for cold access, if any, is Cold - Warm
coldCost = ColdAccountAccessCostEIP2929 - WarmStorageReadCostEIP2929
if !warmAccess {
c.context.AccessAccount(addr)
// Charge the remaining difference here already, to correctly calculate available
// gas for call
if !c.useGas(coldCost) {
return false, 0, errOutOfGas
}
}
accessCost = ColdAccountAccessCostEIP2929 - WarmStorageReadCostEIP2929
}
return warmAccess, coldCost, nil
return isWarm, accessCost
}

func gasSelfdestruct(c *context) tosca.Gas {
Expand Down
100 changes: 24 additions & 76 deletions go/interpreter/lfvm/gas_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
package lfvm

import (
"errors"
"testing"

"github.com/Fantom-foundation/Tosca/go/tosca"
Expand Down Expand Up @@ -62,66 +61,44 @@ func TestGas_CallGasCalculation(t *testing.T) {
}
}

func TestGas_AddressInAccessList(t *testing.T) {
func TestGas_calculateAccessCost(t *testing.T) {

tests := map[string]struct {
setup func(*context)
accessStatus bool
coldCost tosca.Gas
revision tosca.Revision
warmAccess bool
coldCost tosca.Gas
}{
"istanbul": {
setup: func(c *context) {
c.params.Revision = tosca.R07_Istanbul
},
accessStatus: true,
revision: tosca.R07_Istanbul,
warmAccess: true,
},
"berlin_warm": {
setup: func(c *context) {
c.params.Revision = tosca.R09_Berlin
c.context.(*tosca.MockRunContext).EXPECT().IsAddressInAccessList(gomock.Any()).Return(true)
c.stack.push(uint256.NewInt(1))
c.stack.push(uint256.NewInt(2))
},
accessStatus: true,
coldCost: ColdAccountAccessCostEIP2929 - WarmStorageReadCostEIP2929,
revision: tosca.R09_Berlin,
warmAccess: true,
coldCost: ColdAccountAccessCostEIP2929 - WarmStorageReadCostEIP2929,
},
"berlin_cold_enough_gas": {
setup: func(c *context) {
c.params.Revision = tosca.R09_Berlin
c.context.(*tosca.MockRunContext).EXPECT().IsAddressInAccessList(gomock.Any()).Return(false)
c.context.(*tosca.MockRunContext).EXPECT().AccessAccount(gomock.Any()).Return(tosca.ColdAccess)
c.stack.push(uint256.NewInt(1))
c.stack.push(uint256.NewInt(2))
c.gas = ColdAccountAccessCostEIP2929 - WarmStorageReadCostEIP2929
},
accessStatus: false,
coldCost: ColdAccountAccessCostEIP2929 - WarmStorageReadCostEIP2929,
revision: tosca.R09_Berlin,
warmAccess: false,
coldCost: ColdAccountAccessCostEIP2929 - WarmStorageReadCostEIP2929,
},
}

for name, test := range tests {
t.Run(name, func(t *testing.T) {
ctrl := gomock.NewController(t)
runContext := tosca.NewMockRunContext(ctrl)

ctxt := context{
status: statusRunning,
params: tosca.Parameters{},
context: runContext,
stack: NewStack(),
memory: NewMemory(),
gas: 1 << 20,
}
test.setup(&ctxt)

warmGot, coldCostGot, errGot := addressInAccessList(&ctxt)

if errGot != nil {
t.Errorf("unexpected error, wanted %v, got %v", nil, errGot)
}

if warmGot != test.accessStatus {
t.Errorf("unexpected warm access status, wanted %v, got %v", test.accessStatus, warmGot)
mockRunContext := tosca.NewMockRunContext(ctrl)
mockRunContext.EXPECT().IsAddressInAccessList(gomock.Any()).Return(test.warmAccess).AnyTimes()
mockRunContext.EXPECT().AccessAccount(gomock.Any()).Return(tosca.ColdAccess).AnyTimes()

warmGot, coldCostGot := calculateAccessCost(
tosca.Address{1},
test.revision,
mockRunContext,
)

if warmGot != test.warmAccess {
t.Errorf("unexpected warm access status, wanted %v, got %v", test.warmAccess, warmGot)
}

if coldCostGot != test.coldCost {
Expand All @@ -131,32 +108,3 @@ func TestGas_AddressInAccessList(t *testing.T) {
})
}
}

func TestGas_AddressInAccessListReportsOutOfGas(t *testing.T) {

ctrl := gomock.NewController(t)
runContext := tosca.NewMockRunContext(ctrl)
ctxt := context{
status: statusRunning,
params: tosca.Parameters{
BlockParameters: tosca.BlockParameters{
Revision: tosca.R09_Berlin,
},
},
context: runContext,
stack: NewStack(),
memory: NewMemory(),
gas: ColdAccountAccessCostEIP2929 - WarmStorageReadCostEIP2929 - 1,
}

ctxt.context.(*tosca.MockRunContext).EXPECT().IsAddressInAccessList(gomock.Any()).Return(false)
ctxt.context.(*tosca.MockRunContext).EXPECT().AccessAccount(gomock.Any()).Return(tosca.ColdAccess)
ctxt.stack.push(uint256.NewInt(1))
ctxt.stack.push(uint256.NewInt(2))

_, _, errGot := addressInAccessList(&ctxt)
if !errors.Is(errGot, errOutOfGas) {
t.Errorf("unexpected error, wanted %v, got %v", errOutOfGas, errGot)
}

}
20 changes: 13 additions & 7 deletions go/interpreter/lfvm/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -1044,10 +1044,7 @@ func neededMemorySize(c *context, offset, size *uint256.Int) (uint64, error) {
}

func genericCall(c *context, kind tosca.CallKind) {
warmAccess, coldCost, err := addressInAccessList(c)
if err != nil {
return
}

stack := c.stack
value := uint256.NewInt(0)

Expand Down Expand Up @@ -1079,6 +1076,15 @@ func genericCall(c *context, kind tosca.CallKind) {
needed_memory_size = ret_memory_size
}

isWarm, accessCost := calculateAccessCost(toAddr, c.params.Revision, c.context)
if !isWarm {
c.context.AccessAccount(toAddr)
if !c.useGas(accessCost) {
c.status = statusOutOfGas
return
}
}

baseGas := c.memory.ExpansionCosts(needed_memory_size)
checkGas := func(cost tosca.Gas) bool {
return 0 <= cost && cost <= c.gas
Expand Down Expand Up @@ -1109,13 +1115,13 @@ func genericCall(c *context, kind tosca.CallKind) {
}

cost := callGas(c.gas, baseGas, provided_gas)
if !warmAccess {
if !isWarm {
// In case of a cold access, we temporarily add the cold charge back, and also
// add it to the returned gas. By adding it to the return, it will be charged
// outside of this function, as part of the dynamic gas, and that will make it
// also become correctly reported to tracers.
c.gas += coldCost
baseGas += coldCost
c.gas += accessCost
baseGas += accessCost
}
if !c.useGas(baseGas + cost) {
return
Expand Down

0 comments on commit 7cfbdf6

Please sign in to comment.