Separate evmc gasCosts and nim-evm gasCosts (#2454)

This is part of preparations before converting GasInt to uint64
This commit is contained in:
andri lim 2024-07-05 07:00:03 +07:00 committed by GitHub
parent 7d78fd97d5
commit 23c00ce88c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 187 additions and 181 deletions

View File

@ -25,3 +25,10 @@ export
op_codes, op_codes,
memory, memory,
stack stack
when defined(evmc_enabled):
import
./interpreter/evmc_gas_costs
export
evmc_gas_costs

View File

@ -0,0 +1,101 @@
# Nimbus
# Copyright (c) 2018-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
{.push raises: [].}
import
../../common/evmforks,
evmc/evmc
type
# The gas cost specification for storage instructions.
StorageCostSpec = object
netCost : bool # Is this net gas cost metering schedule?
warmAccess: int16 # Storage warm access cost, YP: G_{warmaccess}
sset : int16 # Storage addition cost, YP: G_{sset}
reset : int16 # Storage modification cost, YP: G_{sreset}
clear : int16 # Storage deletion refund, YP: R_{sclear}
StorageStoreCost* = object
gasCost* : int16
gasRefund*: int16
SstoreCosts* = array[evmc_storage_status, StorageStoreCost]
const
# From EIP-2929
ColdSloadCost = 2100
WarmStorageReadCost = 100
# Table of gas cost specification for storage instructions per EVM revision.
func storageCostSpec(): array[EVMFork, StorageCostSpec] {.compileTime.} =
# Legacy cost schedule.
const revs = [
FkFrontier, FkHomestead, FkTangerine,
FkSpurious, FkByzantium, FkPetersburg]
for rev in revs:
result[rev] = StorageCostSpec(
netCost: false, warmAccess: 200, sset: 20000, reset: 5000, clear: 15000)
# Net cost schedule.
result[FkConstantinople] = StorageCostSpec(
netCost: true, warmAccess: 200, sset: 20000, reset: 5000, clear: 15000)
result[FkIstanbul] = StorageCostSpec(
netCost: true, warmAccess: 800, sset: 20000, reset: 5000, clear: 15000)
result[FkBerlin] = StorageCostSpec(
netCost: true, warmAccess: WarmStorageReadCost, sset: 20000,
reset: 5000 - ColdSloadCost, clear: 15000)
result[FkLondon] = StorageCostSpec(
netCost: true, warmAccess: WarmStorageReadCost, sset: 20000,
reset: 5000 - ColdSloadCost, clear: 4800)
result[FkParis] = result[FkLondon]
result[FkShanghai] = result[FkLondon]
result[FkCancun] = result[FkLondon]
proc legacySStoreCost(e: var SstoreCosts,
c: StorageCostSpec) {.compileTime.} =
e[EVMC_STORAGE_ADDED] = StorageStoreCost(gasCost: c.sset , gasRefund: 0)
e[EVMC_STORAGE_DELETED] = StorageStoreCost(gasCost: c.reset, gasRefund: c.clear)
e[EVMC_STORAGE_MODIFIED] = StorageStoreCost(gasCost: c.reset, gasRefund: 0)
e[EVMC_STORAGE_ASSIGNED] = e[EVMC_STORAGE_MODIFIED]
e[EVMC_STORAGE_DELETED_ADDED] = e[EVMC_STORAGE_ADDED]
e[EVMC_STORAGE_MODIFIED_DELETED] = e[EVMC_STORAGE_DELETED]
e[EVMC_STORAGE_DELETED_RESTORED] = e[EVMC_STORAGE_ADDED]
e[EVMC_STORAGE_ADDED_DELETED] = e[EVMC_STORAGE_DELETED]
e[EVMC_STORAGE_MODIFIED_RESTORED] = e[EVMC_STORAGE_MODIFIED]
proc netSStoreCost(e: var SstoreCosts,
c: StorageCostSpec) {.compileTime.} =
e[EVMC_STORAGE_ASSIGNED] = StorageStoreCost(gasCost: c.warmAccess, gasRefund: 0)
e[EVMC_STORAGE_ADDED] = StorageStoreCost(gasCost: c.sset , gasRefund: 0)
e[EVMC_STORAGE_DELETED] = StorageStoreCost(gasCost: c.reset , gasRefund: c.clear)
e[EVMC_STORAGE_MODIFIED] = StorageStoreCost(gasCost: c.reset , gasRefund: 0)
e[EVMC_STORAGE_DELETED_ADDED] = StorageStoreCost(gasCost: c.warmAccess, gasRefund: -c.clear)
e[EVMC_STORAGE_MODIFIED_DELETED] = StorageStoreCost(gasCost: c.warmAccess, gasRefund: c.clear)
e[EVMC_STORAGE_DELETED_RESTORED] = StorageStoreCost(gasCost: c.warmAccess,
gasRefund: c.reset - c.warmAccess - c.clear)
e[EVMC_STORAGE_ADDED_DELETED] = StorageStoreCost(gasCost: c.warmAccess,
gasRefund: c.sset - c.warmAccess)
e[EVMC_STORAGE_MODIFIED_RESTORED] = StorageStoreCost(gasCost: c.warmAccess,
gasRefund: c.reset - c.warmAccess)
proc storageStoreCost(): array[EVMFork, SstoreCosts] {.compileTime.} =
const tbl = storageCostSpec()
for rev in EVMFork:
let c = tbl[rev]
if not c.netCost: # legacy
legacySStoreCost(result[rev], c)
else: # net cost
netSStoreCost(result[rev], c)
const
ForkToSstoreCost* = storageStoreCost()

View File

@ -11,9 +11,6 @@ import
./op_codes, ../../common/evmforks, ./op_codes, ../../common/evmforks,
../evm_errors ../evm_errors
when defined(evmc_enabled):
import evmc/evmc
# Gas Fee Schedule # Gas Fee Schedule
# Yellow Paper Appendix G - https://ethereum.github.io/yellowpaper/paper.pdf # Yellow Paper Appendix G - https://ethereum.github.io/yellowpaper/paper.pdf
type type
@ -70,8 +67,6 @@ type
case kind*: Op case kind*: Op
of Sstore: of Sstore:
when defined(evmc_enabled):
s_status*: evmc_storage_status
s_currentValue*: UInt256 s_currentValue*: UInt256
s_originalValue*: UInt256 s_originalValue*: UInt256
of Call, CallCode, DelegateCall, StaticCall: of Call, CallCode, DelegateCall, StaticCall:
@ -136,87 +131,6 @@ const
ACCESS_LIST_STORAGE_KEY_COST* = 1900.GasInt ACCESS_LIST_STORAGE_KEY_COST* = 1900.GasInt
ACCESS_LIST_ADDRESS_COST* = 2400.GasInt ACCESS_LIST_ADDRESS_COST* = 2400.GasInt
when defined(evmc_enabled):
type
# The gas cost specification for storage instructions.
StorageCostSpec = object
netCost : bool # Is this net gas cost metering schedule?
warmAccess: int16 # Storage warm access cost, YP: G_{warmaccess}
sset : int16 # Storage addition cost, YP: G_{sset}
reset : int16 # Storage modification cost, YP: G_{sreset}
clear : int16 # Storage deletion refund, YP: R_{sclear}
StorageStoreCost* = object
gasCost* : int16
gasRefund*: int16
# Table of gas cost specification for storage instructions per EVM revision.
func storageCostSpec(): array[EVMFork, StorageCostSpec] {.compileTime.} =
# Legacy cost schedule.
const revs = [
FkFrontier, FkHomestead, FkTangerine,
FkSpurious, FkByzantium, FkPetersburg]
for rev in revs:
result[rev] = StorageCostSpec(
netCost: false, warmAccess: 200, sset: 20000, reset: 5000, clear: 15000)
# Net cost schedule.
result[FkConstantinople] = StorageCostSpec(
netCost: true, warmAccess: 200, sset: 20000, reset: 5000, clear: 15000)
result[FkIstanbul] = StorageCostSpec(
netCost: true, warmAccess: 800, sset: 20000, reset: 5000, clear: 15000)
result[FkBerlin] = StorageCostSpec(
netCost: true, warmAccess: WarmStorageReadCost, sset: 20000,
reset: 5000 - ColdSloadCost, clear: 15000)
result[FkLondon] = StorageCostSpec(
netCost: true, warmAccess: WarmStorageReadCost, sset: 20000,
reset: 5000 - ColdSloadCost, clear: 4800)
result[FkParis] = result[FkLondon]
result[FkShanghai] = result[FkLondon]
result[FkCancun] = result[FkLondon]
proc legacySStoreCost(e: var array[evmc_storage_status, StorageStoreCost],
c: StorageCostSpec) {.compileTime.} =
e[EVMC_STORAGE_ADDED] = StorageStoreCost(gasCost: c.sset , gasRefund: 0)
e[EVMC_STORAGE_DELETED] = StorageStoreCost(gasCost: c.reset, gasRefund: c.clear)
e[EVMC_STORAGE_MODIFIED] = StorageStoreCost(gasCost: c.reset, gasRefund: 0)
e[EVMC_STORAGE_ASSIGNED] = e[EVMC_STORAGE_MODIFIED]
e[EVMC_STORAGE_DELETED_ADDED] = e[EVMC_STORAGE_ADDED]
e[EVMC_STORAGE_MODIFIED_DELETED] = e[EVMC_STORAGE_DELETED]
e[EVMC_STORAGE_DELETED_RESTORED] = e[EVMC_STORAGE_ADDED]
e[EVMC_STORAGE_ADDED_DELETED] = e[EVMC_STORAGE_DELETED]
e[EVMC_STORAGE_MODIFIED_RESTORED] = e[EVMC_STORAGE_MODIFIED]
proc netSStoreCost(e: var array[evmc_storage_status, StorageStoreCost],
c: StorageCostSpec) {.compileTime.} =
e[EVMC_STORAGE_ASSIGNED] = StorageStoreCost(gasCost: c.warmAccess, gasRefund: 0)
e[EVMC_STORAGE_ADDED] = StorageStoreCost(gasCost: c.sset , gasRefund: 0)
e[EVMC_STORAGE_DELETED] = StorageStoreCost(gasCost: c.reset , gasRefund: c.clear)
e[EVMC_STORAGE_MODIFIED] = StorageStoreCost(gasCost: c.reset , gasRefund: 0)
e[EVMC_STORAGE_DELETED_ADDED] = StorageStoreCost(gasCost: c.warmAccess, gasRefund: -c.clear)
e[EVMC_STORAGE_MODIFIED_DELETED] = StorageStoreCost(gasCost: c.warmAccess, gasRefund: c.clear)
e[EVMC_STORAGE_DELETED_RESTORED] = StorageStoreCost(gasCost: c.warmAccess,
gasRefund: c.reset - c.warmAccess - c.clear)
e[EVMC_STORAGE_ADDED_DELETED] = StorageStoreCost(gasCost: c.warmAccess,
gasRefund: c.sset - c.warmAccess)
e[EVMC_STORAGE_MODIFIED_RESTORED] = StorageStoreCost(gasCost: c.warmAccess,
gasRefund: c.reset - c.warmAccess)
proc storageStoreCost(): array[EVMFork, array[evmc_storage_status, StorageStoreCost]] {.compileTime.} =
const tbl = storageCostSpec()
for rev in EVMFork:
let c = tbl[rev]
if not c.netCost: # legacy
legacySStoreCost(result[rev], c)
else: # net cost
netSStoreCost(result[rev], c)
const
SstoreCost* = storageStoreCost()
template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) = template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
## Generate the gas cost for each forks and store them in a const ## Generate the gas cost for each forks and store them in a const
@ -318,14 +232,6 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
func `prefix gasSstore`(value: UInt256, gasParams: GasParams): EvmResult[GasResult] {.nimcall.} = func `prefix gasSstore`(value: UInt256, gasParams: GasParams): EvmResult[GasResult] {.nimcall.} =
## Value is word to save ## Value is word to save
var res: GasResult var res: GasResult
when defined(evmc_enabled):
const c = SstoreCost[fork]
let sc = c[gasParams.s_status]
res.gasCost = GasInt sc.gasCost
# refund is used in host_services.setStorage
# res.gasRefund = sc.gasRefund
ok(res)
else:
when fork >= FkBerlin: when fork >= FkBerlin:
# EIP2929 # EIP2929
const const

View File

@ -21,6 +21,7 @@ import
../../memory, ../../memory,
../../stack, ../../stack,
../../types, ../../types,
../gas_meter,
../gas_costs, ../gas_costs,
../op_codes, ../op_codes,
../utils/utils_numeric, ../utils/utils_numeric,
@ -31,9 +32,11 @@ import
when not defined(evmc_enabled): when not defined(evmc_enabled):
import import
../gas_meter,
../../state, ../../state,
../../../db/ledger ../../../db/ledger
else:
import
../evmc_gas_costs
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Private helpers # Private helpers
@ -43,10 +46,12 @@ when evmc_enabled:
proc sstoreEvmc(c: Computation, slot, newValue: UInt256, coldAccess = 0.GasInt): EvmResultVoid = proc sstoreEvmc(c: Computation, slot, newValue: UInt256, coldAccess = 0.GasInt): EvmResultVoid =
let let
status = c.host.setStorage(c.msg.contractAddress, slot, newValue) status = c.host.setStorage(c.msg.contractAddress, slot, newValue)
gasParam = GasParams(kind: Op.Sstore, s_status: status) res = ForkToSstoreCost[c.fork][status]
res = ? c.gasCosts[Sstore].c_handler(newValue, gasParam)
gasCost = res.gasCost + coldAccess gasCost = res.gasCost + coldAccess
if res.gasRefund != 0:
c.gasMeter.refundGas(res.gasRefund)
c.opcodeGastCost(Sstore, gasCost, "SSTORE") c.opcodeGastCost(Sstore, gasCost, "SSTORE")
else: else:

View File

@ -125,7 +125,7 @@ proc accountExists(host: TransactionHost, address: HostAddress): bool {.show.} =
proc getStorage(host: TransactionHost, address: HostAddress, key: HostKey): HostValue {.show.} = proc getStorage(host: TransactionHost, address: HostAddress, key: HostKey): HostValue {.show.} =
host.vmState.readOnlyStateDB.getStorage(address, key) host.vmState.readOnlyStateDB.getStorage(address, key)
proc setStorageStatus(host: TransactionHost, address: HostAddress, proc setStorage(host: TransactionHost, address: HostAddress,
key: HostKey, newVal: HostValue): EvmcStorageStatus {.show.} = key: HostKey, newVal: HostValue): EvmcStorageStatus {.show.} =
let let
db = host.vmState.readOnlyStateDB db = host.vmState.readOnlyStateDB
@ -173,19 +173,6 @@ proc setStorageStatus(host: TransactionHost, address: HostAddress,
else: else:
return EVMC_STORAGE_ASSIGNED return EVMC_STORAGE_ASSIGNED
proc setStorage(host: TransactionHost, address: HostAddress,
key: HostKey, newVal: HostValue): EvmcStorageStatus {.show.} =
let
status = setStorageStatus(host, address, key, newVal)
fork = host.vmState.fork
refund = SstoreCost[fork][status].gasRefund
if refund != 0:
# TODO: Refund depends on `Computation` at the moment.
host.computation.gasMeter.refundGas(refund)
status
proc getBalance(host: TransactionHost, address: HostAddress): HostBalance {.show.} = proc getBalance(host: TransactionHost, address: HostAddress): HostBalance {.show.} =
host.vmState.readOnlyStateDB.getBalance(address) host.vmState.readOnlyStateDB.getBalance(address)