Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LFVM: move addressInAccessList to getAccessCost #730

Merged
merged 8 commits into from
Sep 16, 2024
36 changes: 7 additions & 29 deletions go/interpreter/lfvm/gas.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ func getBerlinGasPriceInternal(op OpCode) tosca.Gas {
case BALANCE:
gp = 100
case CALL:
gp = 100
gp = 0
case CALLCODE:
gp = 100
gp = 0
case STATICCALL:
gp = 100
gp = 0
case DELEGATECALL:
gp = 100
gp = 0
case SELFDESTRUCT:
gp = 5000
}
Expand Down Expand Up @@ -223,11 +223,11 @@ func getStaticGasPriceInternal(op OpCode) tosca.Gas {
case CREATE2:
return 32000
case CALL:
return 700 // Should be 100 according to evm.code
return 700
case CALLCODE:
return 700
case STATICCALL:
return 700 // Should be 100 according to evm.code
return 700
case RETURN:
return 0
case STOP:
Expand All @@ -237,7 +237,7 @@ func getStaticGasPriceInternal(op OpCode) tosca.Gas {
case INVALID:
return 0
case DELEGATECALL:
return 700 // Should be 100 according to evm.code
return 700
case SELFDESTRUCT:
return 0 // should be 5000 according to evm.code
}
Expand Down Expand Up @@ -343,28 +343,6 @@ 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())
// Check slot presence in the access list
//lint:ignore SA1019 deprecated functions to be migrated in #616
warmAccess = c.context.IsAddressInAccessList(addr)
// 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
}
}
}
return warmAccess, coldCost, nil
}

func gasSelfdestruct(c *context) tosca.Gas {
gas := SelfdestructGasEIP150
var address = tosca.Address(c.stack.peekN(0).Bytes20())
Expand Down
25 changes: 13 additions & 12 deletions go/interpreter/lfvm/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -1082,11 +1082,16 @@ func neededMemorySize(c *context, offset, size *uint256.Int) (uint64, error) {
return offset.Uint64() + size.Uint64(), nil
}

func genericCall(c *context, kind tosca.CallKind) {
warmAccess, coldCost, err := addressInAccessList(c)
facuMH marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return
func getAccessCost(accessStatus tosca.AccessStatus) tosca.Gas {
// EIP-2929 says that cold access cost is 2600 and warm is 100.
// (https://eips.ethereum.org/EIPS/eip-2929)
if accessStatus == tosca.ColdAccess {
return tosca.Gas(2600)
}
return tosca.Gas(100)
}

LuisPH3 marked this conversation as resolved.
Show resolved Hide resolved
func genericCall(c *context, kind tosca.CallKind) {
stack := c.stack
value := uint256.NewInt(0)

Expand Down Expand Up @@ -1119,6 +1124,10 @@ func genericCall(c *context, kind tosca.CallKind) {
}

baseGas := c.memory.getExpansionCosts(needed_memory_size)
// from berlin onwards access cost changes depending on warm/cold access.
if c.isAtLeast(tosca.R09_Berlin) {
LuisPH3 marked this conversation as resolved.
Show resolved Hide resolved
baseGas += getAccessCost(c.context.AccessAccount(toAddr))
}
checkGas := func(cost tosca.Gas) bool {
return 0 <= cost && cost <= c.gas
}
Expand Down Expand Up @@ -1148,14 +1157,6 @@ func genericCall(c *context, kind tosca.CallKind) {
}

cost := callGas(c.gas, baseGas, provided_gas)
if !warmAccess {
// 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
}
if !c.useGas(baseGas + cost) {
return
}
Expand Down
76 changes: 76 additions & 0 deletions go/interpreter/lfvm/instructions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -882,3 +882,79 @@ func TestExpansionCostOverflow(t *testing.T) {
}
}
}

func TestGetAccessCost_RespondsWithProperGasPrice(t *testing.T) {
if want, got := tosca.Gas(100), getAccessCost(tosca.WarmAccess); want != got {
t.Errorf("unexpected gas cost, wanted %d, got %d", want, got)
}
if want, got := tosca.Gas(2600), getAccessCost(tosca.ColdAccess); want != got {
t.Errorf("unexpected gas cost, wanted %d, got %d", want, got)
}
}

func TestCall_ChargesNothingForColdAccessBeforeBerlin(t *testing.T) {
facuMH marked this conversation as resolved.
Show resolved Hide resolved

ctrl := gomock.NewController(t)
runContext := tosca.NewMockRunContext(ctrl)
runContext.EXPECT().Call(tosca.Call, gomock.Any()).Return(tosca.CallResult{}, nil)
ctxt := context{
params: tosca.Parameters{
BlockParameters: tosca.BlockParameters{
Revision: tosca.R07_Istanbul,
},
},
stack: NewStack(),
memory: NewMemory(),
context: runContext,
gas: 0,
}

ctxt.stack.stackPointer = 8

genericCall(&ctxt, tosca.Call)

if ctxt.gas != 0 {
t.Errorf("unexpected gas cost, wanted 0, got %v", ctxt.gas)
}
if ctxt.status != statusRunning {
t.Errorf("unexpected status, wanted RUNNING, got %v", ctxt.status)
}
}

func TestCall_ChargesForAccessAfterBerlin(t *testing.T) {

for _, accessStatus := range []tosca.AccessStatus{tosca.WarmAccess, tosca.ColdAccess} {

ctrl := gomock.NewController(t)
runContext := tosca.NewMockRunContext(ctrl)
runContext.EXPECT().AccessAccount(gomock.Any()).Return(accessStatus)
runContext.EXPECT().Call(tosca.Call, gomock.Any()).Return(tosca.CallResult{}, nil)
delta := tosca.Gas(1)
ctxt := context{
params: tosca.Parameters{
BlockParameters: tosca.BlockParameters{
Revision: tosca.R09_Berlin,
},
},
stack: NewStack(),
memory: NewMemory(),
context: runContext,
gas: 2600 + delta,
}
ctxt.stack.stackPointer = 8

genericCall(&ctxt, tosca.Call)

want := tosca.Gas(delta)
if accessStatus == tosca.WarmAccess {
want = 2500 + delta
}
if ctxt.gas != want {
t.Errorf("unexpected gas cost, wanted %v, got %v", want, ctxt.gas)
}

if ctxt.status != statusRunning {
t.Errorf("unexpected status, wanted RUNNING, got %v", ctxt.status)
}
}
}
Loading