Saner EVM gasCosts (#2457)
This is also a part of preparations before converting GasInt to uint64
This commit is contained in:
parent
23c00ce88c
commit
6fe7411ac0
|
@ -340,9 +340,8 @@ proc writeContract*(c: Computation) =
|
|||
# transaction too, before self-destruction wipes the account at the end.
|
||||
|
||||
let
|
||||
gasParams = GasParams(kind: Create, cr_memLength: len)
|
||||
res = c.gasCosts[Create].cr_handler(0.u256, gasParams)
|
||||
codeCost = res.gasCost
|
||||
gasParams = GasParamsCr(memLength: len)
|
||||
codeCost = c.gasCosts[Create].cr_handler(0.u256, gasParams)
|
||||
|
||||
if codeCost <= c.gasMeter.gasRemaining:
|
||||
c.gasMeter.consumeGas(codeCost,
|
||||
|
|
|
@ -65,25 +65,22 @@ type
|
|||
# - σ: an account address
|
||||
# - μ: a value popped from the stack or its size.
|
||||
|
||||
case kind*: Op
|
||||
of Sstore:
|
||||
s_currentValue*: UInt256
|
||||
s_originalValue*: UInt256
|
||||
of Call, CallCode, DelegateCall, StaticCall:
|
||||
c_isNewAccount*: bool
|
||||
c_gasBalance*: GasInt
|
||||
c_contractGas*: UInt256
|
||||
c_currentMemSize*: GasNatural
|
||||
c_memOffset*: GasNatural
|
||||
c_memLength*: GasNatural
|
||||
of Create:
|
||||
cr_currentMemSize*: GasNatural
|
||||
cr_memOffset*: GasNatural
|
||||
cr_memLength*: GasNatural
|
||||
of SelfDestruct:
|
||||
sd_condition*: bool
|
||||
else:
|
||||
discard
|
||||
kind*: Op
|
||||
isNewAccount*: bool
|
||||
gasBalance*: GasInt
|
||||
contractGas*: UInt256
|
||||
currentMemSize*: GasNatural
|
||||
memOffset*: GasNatural
|
||||
memLength*: GasNatural
|
||||
|
||||
GasParamsSs* = object
|
||||
currentValue*: UInt256
|
||||
originalValue*: UInt256
|
||||
|
||||
GasParamsCr* = object
|
||||
currentMemSize*: GasNatural
|
||||
memOffset*: GasNatural
|
||||
memLength*: GasNatural
|
||||
|
||||
GasCostKind* = enum
|
||||
GckInvalidOp,
|
||||
|
@ -91,10 +88,14 @@ type
|
|||
GckDynamic,
|
||||
GckMemExpansion,
|
||||
GckCreate,
|
||||
GckComplex,
|
||||
GckLater
|
||||
GckCall,
|
||||
GckLater,
|
||||
GckSuicide,
|
||||
GckSstore
|
||||
|
||||
GasResult = tuple[gasCost, gasRefund: GasInt]
|
||||
# gasRefund of sstore can be a negative number
|
||||
SStoreGasResult = tuple[gasCost: GasInt, gasRefund: int64]
|
||||
CallGasResult = tuple[gasCost, childGasLimit: GasInt]
|
||||
|
||||
GasCost = object
|
||||
case kind*: GasCostKind
|
||||
|
@ -109,15 +110,21 @@ type
|
|||
m_handler*: proc(currentMemSize, memOffset, memLength: GasNatural): GasInt
|
||||
{.nimcall, gcsafe, raises: [].}
|
||||
of GckCreate:
|
||||
cr_handler*: proc(value: UInt256, gasParams: GasParams): GasResult
|
||||
cr_handler*: proc(value: UInt256, params: GasParamsCr): GasInt
|
||||
{.nimcall, gcsafe, raises: [].}
|
||||
of GckComplex:
|
||||
c_handler*: proc(value: UInt256, gasParams: GasParams): EvmResult[GasResult]
|
||||
of GckCall:
|
||||
c_handler*: proc(value: UInt256, params: GasParams): EvmResult[CallGasResult]
|
||||
{.nimcall, gcsafe, raises: [].}
|
||||
# We use gasCost/gasRefund for:
|
||||
# - Properly log and order cost and refund (for Sstore especially)
|
||||
# - Allow to use unsigned integer in the future
|
||||
# - CALL instruction requires passing the child message gas (Ccallgas in yellow paper)
|
||||
of GckSuicide:
|
||||
sc_handler*: proc(condition: bool): GasInt
|
||||
{.nimcall, gcsafe, raises: [].}
|
||||
of GckSstore:
|
||||
ss_handler*: proc(value: UInt256, params: GasParamsSs): SStoreGasResult
|
||||
{.nimcall, gcsafe, raises: [].}
|
||||
|
||||
GasCosts* = array[Op, GasCost]
|
||||
|
||||
|
@ -198,16 +205,13 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
|
|||
if not value.isZero:
|
||||
result += static(FeeSchedule[GasExpByte]) * (1 + log256(value))
|
||||
|
||||
func `prefix gasCreate`(value: UInt256, gasParams: GasParams): GasResult {.nimcall.} =
|
||||
func `prefix gasCreate`(value: UInt256, params: GasParamsCr): GasInt {.nimcall.} =
|
||||
if value.isZero:
|
||||
result.gasCost = static(FeeSchedule[GasCodeDeposit]) * gasParams.cr_memLength
|
||||
result = static(FeeSchedule[GasCodeDeposit]) * params.memLength
|
||||
else:
|
||||
result.gasCost = static(FeeSchedule[GasCreate]) +
|
||||
(static(FeeSchedule[GasInitcodeWord]) * gasParams.cr_memLength.wordCount) +
|
||||
`prefix gasMemoryExpansion`(
|
||||
gasParams.cr_currentMemSize,
|
||||
gasParams.cr_memOffset,
|
||||
gasParams.cr_memLength)
|
||||
result = static(FeeSchedule[GasCreate]) +
|
||||
(static(FeeSchedule[GasInitcodeWord]) * params.memLength.wordCount) +
|
||||
`prefix gasMemoryExpansion`(params.currentMemSize, params.memOffset, params.memLength)
|
||||
|
||||
func `prefix gasSha3`(currentMemSize, memOffset, memLength: GasNatural): GasInt {.nimcall.} =
|
||||
|
||||
|
@ -229,9 +233,9 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
|
|||
result = static(FeeSchedule[GasVeryLow])
|
||||
result += `prefix gasMemoryExpansion`(currentMemSize, memOffset, memLength)
|
||||
|
||||
func `prefix gasSstore`(value: UInt256, gasParams: GasParams): EvmResult[GasResult] {.nimcall.} =
|
||||
func `prefix gasSstore`(value: UInt256, params: GasParamsSs): SStoreGasResult {.nimcall.} =
|
||||
## Value is word to save
|
||||
var res: GasResult
|
||||
var res: SStoreGasResult
|
||||
when fork >= FkBerlin:
|
||||
# EIP2929
|
||||
const
|
||||
|
@ -252,13 +256,13 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
|
|||
ClearRefund {.used.} = FeeSchedule[RefundsClear]# clearing an originally existing storage slot
|
||||
|
||||
when fork < FkConstantinople or fork == FkPetersburg:
|
||||
let isStorageEmpty = gasParams.s_currentValue.isZero
|
||||
let isStorageEmpty = params.currentValue.isZero
|
||||
|
||||
# Gas cost - literal translation of Yellow Paper
|
||||
res.gasCost = if value.isZero.not and isStorageEmpty:
|
||||
InitGas
|
||||
else:
|
||||
CleanGas
|
||||
InitGas
|
||||
else:
|
||||
CleanGas
|
||||
|
||||
# Refund
|
||||
if value.isZero and not isStorageEmpty:
|
||||
|
@ -279,35 +283,35 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
|
|||
# 2.2.2.2. Otherwise, add SSTORE_CLEAN_REFUND gas to refund counter.
|
||||
|
||||
# Gas sentry honoured, do the actual gas calculation based on the stored value
|
||||
if gasParams.s_currentValue == value: # noop (1)
|
||||
if params.currentValue == value: # noop (1)
|
||||
res.gasCost = NoopGas
|
||||
return ok(res)
|
||||
return res
|
||||
|
||||
if gasParams.s_originalValue == gasParams.s_currentValue:
|
||||
if gasParams.s_originalValue.isZero: # create slot (2.1.1)
|
||||
if params.originalValue == params.currentValue:
|
||||
if params.originalValue.isZero: # create slot (2.1.1)
|
||||
res.gasCost = InitGas
|
||||
return ok(res)
|
||||
return res
|
||||
|
||||
if value.isZero: # delete slot (2.1.2b)
|
||||
res.gasRefund = ClearRefund
|
||||
|
||||
res.gasCost = CleanGas # write existing slot (2.1.2)
|
||||
return ok(res)
|
||||
return res
|
||||
|
||||
if not gasParams.s_originalValue.isZero:
|
||||
if gasParams.s_currentValue.isZero: # recreate slot (2.2.1.1)
|
||||
if not params.originalValue.isZero:
|
||||
if params.currentValue.isZero: # recreate slot (2.2.1.1)
|
||||
res.gasRefund -= ClearRefund
|
||||
if value.isZero: # delete slot (2.2.1.2)
|
||||
res.gasRefund += ClearRefund
|
||||
|
||||
if gasParams.s_originalValue == value:
|
||||
if gasParams.s_originalValue.isZero: # reset to original inexistent slot (2.2.2.1)
|
||||
if params.originalValue == value:
|
||||
if params.originalValue.isZero: # reset to original inexistent slot (2.2.2.1)
|
||||
res.gasRefund += InitRefund
|
||||
else: # reset to original existing slot (2.2.2.2)
|
||||
res.gasRefund += CleanRefund
|
||||
|
||||
res.gasCost = DirtyGas # dirty update (2.2)
|
||||
ok(res)
|
||||
res
|
||||
|
||||
func `prefix gasLog0`(currentMemSize, memOffset, memLength: GasNatural): GasInt {.nimcall.} =
|
||||
result = `prefix gasMemoryExpansion`(currentMemSize, memOffset, memLength)
|
||||
|
@ -343,7 +347,7 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
|
|||
static(FeeSchedule[GasLogData]) * memLength +
|
||||
static(4 * FeeSchedule[GasLogTopic])
|
||||
|
||||
func `prefix gasCall`(value: UInt256, gasParams: GasParams): EvmResult[GasResult] {.nimcall.} =
|
||||
func `prefix gasCall`(value: UInt256, params: GasParams): EvmResult[CallGasResult] {.nimcall.} =
|
||||
|
||||
# From the Yellow Paper, going through the equation from bottom to top
|
||||
# https://ethereum.github.io/yellowpaper/paper.pdf#appendix.H
|
||||
|
@ -365,87 +369,73 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
|
|||
# The discussion for the draft EIP-5, which proposes to change the CALL opcode also goes over
|
||||
# the current implementation - https://github.com/ethereum/EIPs/issues/8
|
||||
|
||||
# Both gasCost and childGasLimit can go below zero
|
||||
# but that is an OOG condition. Leaving this function
|
||||
# both of them are positive integers.
|
||||
|
||||
# First we have to take into account the costs of memory expansion:
|
||||
# Note there is a "bug" in the Ethereum Yellow Paper
|
||||
# - https://github.com/ethereum/yellowpaper/issues/325
|
||||
# μg already includes memory expansion costs but it is not
|
||||
# plainly explained n the CALL opcode details
|
||||
|
||||
# i.e. Cmem(μ′i) − Cmem(μi)
|
||||
# Yellow Paper: μ′i ≡ M(M(μi,μs[3],μs[4]),μs[5],μs[6])
|
||||
# M is the memory expansion function
|
||||
# μ′i is passed through gasParams.memRequested
|
||||
# TODO:
|
||||
# - Py-EVM has costs for both input and output memory expansion
|
||||
# https://github.com/ethereum/py-evm/blob/eed0bfe4499b394ee58113408e487e7d35ab88d6/evm/vm/logic/call.py#L56-L57
|
||||
# - Parity only for the largest expansion
|
||||
# https://github.com/paritytech/parity/blob/af1088ef61323f171915555023d8e993aaaed755/ethcore/evm/src/interpreter/gasometer.rs#L192-L195
|
||||
# - Go-Ethereum only has one cost
|
||||
# https://github.com/ethereum/go-ethereum/blob/13af27641829f61d1e6b383e37aab6caae22f2c1/core/vm/gas_table.go#L334
|
||||
# ⚠⚠ Py-EVM seems wrong if memory is needed for both in and out.
|
||||
var res: GasResult
|
||||
res.gasCost = `prefix gasMemoryExpansion`(
|
||||
gasParams.c_currentMemSize,
|
||||
gasParams.c_memOffset,
|
||||
gasParams.c_memLength
|
||||
)
|
||||
var gasCost: int64 = `prefix gasMemoryExpansion`(
|
||||
params.currentMemSize,
|
||||
params.memOffset,
|
||||
params.memLength)
|
||||
var childGasLimit: int64
|
||||
|
||||
# Cnew_account
|
||||
if gasParams.c_isNewAccount and gasParams.kind == Call:
|
||||
if params.isNewAccount and params.kind == Call:
|
||||
when fork < FkSpurious:
|
||||
# Pre-EIP161 all account creation calls consumed 25000 gas.
|
||||
res.gasCost += static(FeeSchedule[GasNewAccount])
|
||||
gasCost += static(FeeSchedule[GasNewAccount])
|
||||
else:
|
||||
# Afterwards, only those transfering value:
|
||||
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-158.md
|
||||
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md
|
||||
if not value.isZero:
|
||||
res.gasCost += static(FeeSchedule[GasNewAccount])
|
||||
gasCost += static(FeeSchedule[GasNewAccount])
|
||||
|
||||
# Cxfer
|
||||
if not value.isZero and gasParams.kind in {Call, CallCode}:
|
||||
res.gasCost += static(FeeSchedule[GasCallValue])
|
||||
if not value.isZero and params.kind in {Call, CallCode}:
|
||||
gasCost += static(FeeSchedule[GasCallValue])
|
||||
|
||||
# Cextra
|
||||
res.gasCost += static(FeeSchedule[GasCall])
|
||||
gasCost += static(FeeSchedule[GasCall])
|
||||
|
||||
# Cgascap
|
||||
when fork >= FkTangerine:
|
||||
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md
|
||||
let gas = `prefix all_but_one_64th`(gasParams.c_gasBalance - res.gasCost)
|
||||
if gasParams.c_contractGas > high(GasInt).u256 or
|
||||
gas < gasParams.c_contractGas.truncate(GasInt):
|
||||
res.gasRefund = gas
|
||||
let gas = `prefix all_but_one_64th`(params.gasBalance - gasCost)
|
||||
if params.contractGas > high(int64).u256 or
|
||||
gas < params.contractGas.truncate(int64):
|
||||
childGasLimit = gas
|
||||
else:
|
||||
res.gasRefund = gasParams.c_contractGas.truncate(GasInt)
|
||||
childGasLimit = params.contractGas.truncate(int64)
|
||||
else:
|
||||
if gasParams.c_contractGas > high(GasInt).u256:
|
||||
if params.contractGas > high(int64).u256:
|
||||
return err(gasErr(GasIntOverflow))
|
||||
res.gasRefund = gasParams.c_contractGas.truncate(GasInt)
|
||||
childGasLimit = params.contractGas.truncate(int64)
|
||||
|
||||
if res.gasRefund > 0: # skip check if gasRefund is negative
|
||||
if res.gasCost.u256 + res.gasRefund.u256 > high(GasInt).u256:
|
||||
if childGasLimit > 0: # skip check if childGasLimit is negative
|
||||
if gasCost.u256 + childGasLimit.u256 > high(int64).u256:
|
||||
return err(gasErr(GasIntOverflow))
|
||||
|
||||
res.gasCost += res.gasRefund
|
||||
gasCost += childGasLimit
|
||||
|
||||
# Ccallgas - Gas sent to the child message
|
||||
if not value.isZero and gasParams.kind in {Call, CallCode}:
|
||||
res.gasRefund += static(FeeSchedule[GasCallStipend])
|
||||
if not value.isZero and params.kind in {Call, CallCode}:
|
||||
childGasLimit += static(FeeSchedule[GasCallStipend])
|
||||
|
||||
ok(res)
|
||||
if gasCost <= 0 and childGasLimit <= 0:
|
||||
return err(opErr(OutOfGas))
|
||||
|
||||
# at this point gasCost and childGasLimit is always > 0
|
||||
ok( (gasCost, childGasLimit) )
|
||||
|
||||
func `prefix gasHalt`(currentMemSize, memOffset, memLength: GasNatural): GasInt {.nimcall.} =
|
||||
`prefix gasMemoryExpansion`(currentMemSize, memOffset, memLength)
|
||||
|
||||
func `prefix gasSelfDestruct`(value: UInt256, gasParams: GasParams): EvmResult[GasResult] {.nimcall.} =
|
||||
var res: GasResult
|
||||
res.gasCost += static(FeeSchedule[GasSelfDestruct])
|
||||
func `prefix gasSelfDestruct`(condition: bool): GasInt {.nimcall.} =
|
||||
result += static(FeeSchedule[GasSelfDestruct])
|
||||
when fork >= FkTangerine:
|
||||
if gasParams.sd_condition:
|
||||
res.gasCost += static(FeeSchedule[GasNewAccount])
|
||||
ok(res)
|
||||
if condition:
|
||||
result += static(FeeSchedule[GasNewAccount])
|
||||
|
||||
func `prefix gasCreate2`(currentMemSize, memOffset, memLength: GasNatural): GasInt {.nimcall.} =
|
||||
result = static(FeeSchedule[GasSha3Word]) * (memLength).wordCount
|
||||
|
@ -475,14 +465,22 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
|
|||
{.nimcall, gcsafe, raises: [].}): GasCost =
|
||||
GasCost(kind: GckMemExpansion, m_handler: handler)
|
||||
|
||||
func complex(handler: proc(value: UInt256, gasParams: GasParams): EvmResult[GasResult]
|
||||
func handleCall(handler: proc(value: UInt256, gasParams: GasParams): EvmResult[CallGasResult]
|
||||
{.nimcall, gcsafe, raises: [].}): GasCost =
|
||||
GasCost(kind: GckComplex, c_handler: handler)
|
||||
GasCost(kind: GckCall, c_handler: handler)
|
||||
|
||||
func handleCreate(handler: proc(value: UInt256, gasParams: GasParams): GasResult
|
||||
func handleCreate(handler: proc(value: UInt256, gasParams: GasParamsCr): GasInt
|
||||
{.nimcall, gcsafe, raises: [].}): GasCost =
|
||||
GasCost(kind: GckCreate, cr_handler: handler)
|
||||
|
||||
func handleSuicide(handler: proc(condition: bool): GasInt
|
||||
{.nimcall, gcsafe, raises: [].}): GasCost =
|
||||
GasCost(kind: GckSuicide, sc_handler: handler)
|
||||
|
||||
func handleSstore(handler: proc(value: UInt256, gasParams: GasParamsSs): SStoreGasResult
|
||||
{.nimcall, gcsafe, raises: [].}): GasCost =
|
||||
GasCost(kind: GckSstore, ss_handler: handler)
|
||||
|
||||
# Returned value
|
||||
fill_enum_table_holes(Op, GasCost(kind: GckInvalidOp)):
|
||||
[
|
||||
|
@ -556,7 +554,7 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
|
|||
Mstore: memExpansion `prefix gasLoadStore`,
|
||||
Mstore8: memExpansion `prefix gasLoadStore`,
|
||||
Sload: fixedOrLater GasSload,
|
||||
Sstore: complex `prefix gasSstore`,
|
||||
Sstore: handleSstore `prefix gasSstore`,
|
||||
Jump: fixed GasMid,
|
||||
JumpI: fixed GasHigh,
|
||||
Pc: fixed GasBase,
|
||||
|
@ -651,15 +649,15 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
|
|||
|
||||
# f0s: System operations
|
||||
Create: handleCreate `prefix gasCreate`,
|
||||
Call: complex `prefix gasCall`,
|
||||
CallCode: complex `prefix gasCall`,
|
||||
Call: handleCall `prefix gasCall`,
|
||||
CallCode: handleCall `prefix gasCall`,
|
||||
Return: memExpansion `prefix gasHalt`,
|
||||
DelegateCall: complex `prefix gasCall`,
|
||||
DelegateCall: handleCall `prefix gasCall`,
|
||||
Create2: memExpansion `prefix gasCreate2`,
|
||||
StaticCall: complex `prefix gasCall`,
|
||||
StaticCall: handleCall `prefix gasCall`,
|
||||
Revert: memExpansion `prefix gasHalt`,
|
||||
Invalid: fixed GasZero,
|
||||
SelfDestruct: complex `prefix gasSelfDestruct`
|
||||
SelfDestruct: handleSuicide `prefix gasSelfDestruct`
|
||||
]
|
||||
|
||||
# Generate the fork-specific gas costs tables
|
||||
|
|
|
@ -210,22 +210,22 @@ proc callOp(k: var VmCtx): EvmResultVoid =
|
|||
|
||||
let
|
||||
p = ? cpt.callParams
|
||||
res = ? cpt.gasCosts[Call].c_handler(
|
||||
|
||||
var
|
||||
(gasCost, childGasLimit) = ? cpt.gasCosts[Call].c_handler(
|
||||
p.value,
|
||||
GasParams(
|
||||
kind: Call,
|
||||
c_isNewAccount: not cpt.accountExists(p.contractAddress),
|
||||
c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929,
|
||||
c_contractGas: p.gas,
|
||||
c_currentMemSize: cpt.memory.len,
|
||||
c_memOffset: p.memOffset,
|
||||
c_memLength: p.memLength))
|
||||
|
||||
var (gasCost, childGasLimit) = res
|
||||
kind: Call,
|
||||
isNewAccount: not cpt.accountExists(p.contractAddress),
|
||||
gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929,
|
||||
contractGas: p.gas,
|
||||
currentMemSize: cpt.memory.len,
|
||||
memOffset: p.memOffset,
|
||||
memLength: p.memLength))
|
||||
|
||||
# at this point gasCost is always > 0
|
||||
gasCost += p.gasCallEIP2929
|
||||
if gasCost >= 0:
|
||||
? cpt.opcodeGastCost(Call, gasCost, reason = $Call)
|
||||
? cpt.opcodeGastCost(Call, gasCost, reason = $Call)
|
||||
|
||||
cpt.returnData.setLen(0)
|
||||
|
||||
|
@ -237,9 +237,6 @@ proc callOp(k: var VmCtx): EvmResultVoid =
|
|||
cpt.gasMeter.returnGas(childGasLimit)
|
||||
return ok()
|
||||
|
||||
if gasCost < 0 and childGasLimit <= 0:
|
||||
return err(opErr(OutOfGas))
|
||||
|
||||
cpt.memory.extend(p.memInPos, p.memInLen)
|
||||
cpt.memory.extend(p.memOutPos, p.memOutLen)
|
||||
|
||||
|
@ -288,21 +285,22 @@ proc callCodeOp(k: var VmCtx): EvmResultVoid =
|
|||
let
|
||||
cpt = k.cpt
|
||||
p = ? cpt.callCodeParams
|
||||
res = ? cpt.gasCosts[CallCode].c_handler(
|
||||
|
||||
var
|
||||
(gasCost, childGasLimit) = ? cpt.gasCosts[CallCode].c_handler(
|
||||
p.value,
|
||||
GasParams(
|
||||
kind: CallCode,
|
||||
c_isNewAccount: not cpt.accountExists(p.contractAddress),
|
||||
c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929,
|
||||
c_contractGas: p.gas,
|
||||
c_currentMemSize: cpt.memory.len,
|
||||
c_memOffset: p.memOffset,
|
||||
c_memLength: p.memLength))
|
||||
kind: CallCode,
|
||||
isNewAccount: not cpt.accountExists(p.contractAddress),
|
||||
gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929,
|
||||
contractGas: p.gas,
|
||||
currentMemSize: cpt.memory.len,
|
||||
memOffset: p.memOffset,
|
||||
memLength: p.memLength))
|
||||
|
||||
var (gasCost, childGasLimit) = res
|
||||
# at this point gasCost is always > 0
|
||||
gasCost += p.gasCallEIP2929
|
||||
if gasCost >= 0:
|
||||
? cpt.opcodeGastCost(CallCode, gasCost, reason = $CallCode)
|
||||
? cpt.opcodeGastCost(CallCode, gasCost, reason = $CallCode)
|
||||
|
||||
cpt.returnData.setLen(0)
|
||||
|
||||
|
@ -314,9 +312,6 @@ proc callCodeOp(k: var VmCtx): EvmResultVoid =
|
|||
cpt.gasMeter.returnGas(childGasLimit)
|
||||
return ok()
|
||||
|
||||
if gasCost < 0 and childGasLimit <= 0:
|
||||
return err(opErr(OutOfGas))
|
||||
|
||||
cpt.memory.extend(p.memInPos, p.memInLen)
|
||||
cpt.memory.extend(p.memOutPos, p.memOutLen)
|
||||
|
||||
|
@ -366,21 +361,22 @@ proc delegateCallOp(k: var VmCtx): EvmResultVoid =
|
|||
let
|
||||
cpt = k.cpt
|
||||
p = ? cpt.delegateCallParams
|
||||
res = ? cpt.gasCosts[DelegateCall].c_handler(
|
||||
|
||||
var
|
||||
(gasCost, childGasLimit) = ? cpt.gasCosts[DelegateCall].c_handler(
|
||||
p.value,
|
||||
GasParams(
|
||||
kind: DelegateCall,
|
||||
c_isNewAccount: not cpt.accountExists(p.contractAddress),
|
||||
c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929,
|
||||
c_contractGas: p.gas,
|
||||
c_currentMemSize: cpt.memory.len,
|
||||
c_memOffset: p.memOffset,
|
||||
c_memLength: p.memLength))
|
||||
kind: DelegateCall,
|
||||
isNewAccount: not cpt.accountExists(p.contractAddress),
|
||||
gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929,
|
||||
contractGas: p.gas,
|
||||
currentMemSize: cpt.memory.len,
|
||||
memOffset: p.memOffset,
|
||||
memLength: p.memLength))
|
||||
|
||||
var (gasCost, childGasLimit) = res
|
||||
# at this point gasCost is always > 0
|
||||
gasCost += p.gasCallEIP2929
|
||||
if gasCost >= 0:
|
||||
? cpt.opcodeGastCost(DelegateCall, gasCost, reason = $DelegateCall)
|
||||
? cpt.opcodeGastCost(DelegateCall, gasCost, reason = $DelegateCall)
|
||||
|
||||
cpt.returnData.setLen(0)
|
||||
if cpt.msg.depth >= MaxCallDepth:
|
||||
|
@ -391,9 +387,6 @@ proc delegateCallOp(k: var VmCtx): EvmResultVoid =
|
|||
cpt.gasMeter.returnGas(childGasLimit)
|
||||
return ok()
|
||||
|
||||
if gasCost < 0 and childGasLimit <= 0:
|
||||
return err(opErr(OutOfGas))
|
||||
|
||||
cpt.memory.extend(p.memInPos, p.memInLen)
|
||||
cpt.memory.extend(p.memOutPos, p.memOutLen)
|
||||
|
||||
|
@ -438,21 +431,22 @@ proc staticCallOp(k: var VmCtx): EvmResultVoid =
|
|||
let
|
||||
cpt = k.cpt
|
||||
p = ? cpt.staticCallParams
|
||||
res = ? cpt.gasCosts[StaticCall].c_handler(
|
||||
|
||||
var
|
||||
(gasCost, childGasLimit) = ? cpt.gasCosts[StaticCall].c_handler(
|
||||
p.value,
|
||||
GasParams(
|
||||
kind: StaticCall,
|
||||
c_isNewAccount: not cpt.accountExists(p.contractAddress),
|
||||
c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929,
|
||||
c_contractGas: p.gas,
|
||||
c_currentMemSize: cpt.memory.len,
|
||||
c_memOffset: p.memOffset,
|
||||
c_memLength: p.memLength))
|
||||
kind: StaticCall,
|
||||
isNewAccount: not cpt.accountExists(p.contractAddress),
|
||||
gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929,
|
||||
contractGas: p.gas,
|
||||
currentMemSize: cpt.memory.len,
|
||||
memOffset: p.memOffset,
|
||||
memLength: p.memLength))
|
||||
|
||||
var (gasCost, childGasLimit) = res
|
||||
# at this point gasCost is always > 0
|
||||
gasCost += p.gasCallEIP2929
|
||||
if gasCost >= 0:
|
||||
? cpt.opcodeGastCost(StaticCall, gasCost, reason = $StaticCall)
|
||||
? cpt.opcodeGastCost(StaticCall, gasCost, reason = $StaticCall)
|
||||
|
||||
cpt.returnData.setLen(0)
|
||||
|
||||
|
@ -464,9 +458,6 @@ proc staticCallOp(k: var VmCtx): EvmResultVoid =
|
|||
cpt.gasMeter.returnGas(childGasLimit)
|
||||
return ok()
|
||||
|
||||
if gasCost < 0 and childGasLimit <= 0:
|
||||
return err(opErr(OutOfGas))
|
||||
|
||||
cpt.memory.extend(p.memInPos, p.memInLen)
|
||||
cpt.memory.extend(p.memOutPos, p.memOutLen)
|
||||
|
||||
|
|
|
@ -101,15 +101,14 @@ proc createOp(k: var VmCtx): EvmResultVoid =
|
|||
return err(opErr(InvalidInitCode))
|
||||
|
||||
let
|
||||
gasParams = GasParams(
|
||||
kind: Create,
|
||||
cr_currentMemSize: cpt.memory.len,
|
||||
cr_memOffset: memPos,
|
||||
cr_memLength: memLen)
|
||||
res = cpt.gasCosts[Create].cr_handler(1.u256, gasParams)
|
||||
gasParams = GasParamsCr(
|
||||
currentMemSize: cpt.memory.len,
|
||||
memOffset: memPos,
|
||||
memLength: memLen)
|
||||
gasCost = cpt.gasCosts[Create].cr_handler(1.u256, gasParams)
|
||||
|
||||
? cpt.opcodeGastCost(Create,
|
||||
res.gasCost, reason = "CREATE: GasCreate + memLen * memory expansion")
|
||||
gasCost, reason = "CREATE: GasCreate + memLen * memory expansion")
|
||||
cpt.memory.extend(memPos, memLen)
|
||||
cpt.returnData.setLen(0)
|
||||
|
||||
|
@ -182,14 +181,13 @@ proc create2Op(k: var VmCtx): EvmResultVoid =
|
|||
return err(opErr(InvalidInitCode))
|
||||
|
||||
let
|
||||
gasParams = GasParams(
|
||||
kind: Create,
|
||||
cr_currentMemSize: cpt.memory.len,
|
||||
cr_memOffset: memPos,
|
||||
cr_memLength: memLen)
|
||||
res = cpt.gasCosts[Create].cr_handler(1.u256, gasParams)
|
||||
gasParams = GasParamsCr(
|
||||
currentMemSize: cpt.memory.len,
|
||||
memOffset: memPos,
|
||||
memLength: memLen)
|
||||
|
||||
let gasCost = res.gasCost + cpt.gasCosts[Create2].m_handler(0, 0, memLen)
|
||||
var gasCost = cpt.gasCosts[Create].cr_handler(1.u256, gasParams)
|
||||
gasCost = gasCost + cpt.gasCosts[Create2].m_handler(0, 0, memLen)
|
||||
|
||||
? cpt.opcodeGastCost(Create2,
|
||||
gasCost, reason = "CREATE2: GasCreate + memLen * memory expansion")
|
||||
|
|
|
@ -58,11 +58,10 @@ else:
|
|||
proc sstoreImpl(c: Computation, slot, newValue: UInt256): EvmResultVoid =
|
||||
let
|
||||
currentValue = c.getStorage(slot)
|
||||
gasParam = GasParams(
|
||||
kind: Op.Sstore,
|
||||
s_currentValue: currentValue)
|
||||
gasParam = GasParamsSs(
|
||||
currentValue: currentValue)
|
||||
|
||||
res = ? c.gasCosts[Sstore].c_handler(newValue, gasParam)
|
||||
res = c.gasCosts[Sstore].ss_handler(newValue, gasParam)
|
||||
|
||||
? c.opcodeGastCost(Sstore, res.gasCost, "SSTORE")
|
||||
if res.gasRefund > 0:
|
||||
|
@ -78,12 +77,11 @@ else:
|
|||
stateDB = c.vmState.readOnlyStateDB
|
||||
currentValue = c.getStorage(slot)
|
||||
|
||||
gasParam = GasParams(
|
||||
kind: Op.Sstore,
|
||||
s_currentValue: currentValue,
|
||||
s_originalValue: stateDB.getCommittedStorage(c.msg.contractAddress, slot))
|
||||
gasParam = GasParamsSs(
|
||||
currentValue: currentValue,
|
||||
originalValue: stateDB.getCommittedStorage(c.msg.contractAddress, slot))
|
||||
|
||||
res = ? c.gasCosts[Sstore].c_handler(newValue, gasParam)
|
||||
res = c.gasCosts[Sstore].ss_handler(newValue, gasParam)
|
||||
|
||||
? c.opcodeGastCost(Sstore, res.gasCost + coldAccess, "SSTORE")
|
||||
|
||||
|
|
|
@ -86,17 +86,15 @@ proc selfDestructOp(k: var VmCtx): EvmResultVoid =
|
|||
|
||||
proc selfDestructEIP150Op(k: var VmCtx): EvmResultVoid =
|
||||
## selfDestructEip150 (auto generated comment)
|
||||
let cpt = k.cpt
|
||||
let beneficiary = ? cpt.stack.popAddress()
|
||||
block:
|
||||
let gasParams = GasParams(
|
||||
kind: SelfDestruct,
|
||||
sd_condition: not cpt.accountExists(beneficiary))
|
||||
let
|
||||
cpt = k.cpt
|
||||
beneficiary = ? cpt.stack.popAddress()
|
||||
condition = not cpt.accountExists(beneficiary)
|
||||
gasCost = cpt.gasCosts[SelfDestruct].sc_handler(condition)
|
||||
|
||||
let res = ? cpt.gasCosts[SelfDestruct].c_handler(0.u256, gasParams)
|
||||
? cpt.opcodeGastCost(SelfDestruct,
|
||||
res.gasCost, reason = "SELFDESTRUCT EIP150")
|
||||
cpt.selfDestruct(beneficiary)
|
||||
? cpt.opcodeGastCost(SelfDestruct,
|
||||
gasCost, reason = "SELFDESTRUCT EIP150")
|
||||
cpt.selfDestruct(beneficiary)
|
||||
ok()
|
||||
|
||||
proc selfDestructEIP161Op(k: var VmCtx): EvmResultVoid =
|
||||
|
@ -104,20 +102,16 @@ proc selfDestructEIP161Op(k: var VmCtx): EvmResultVoid =
|
|||
let cpt = k.cpt
|
||||
? checkInStaticContext(cpt)
|
||||
|
||||
let beneficiary = ? cpt.stack.popAddress()
|
||||
block:
|
||||
let
|
||||
isDead = not cpt.accountExists(beneficiary)
|
||||
balance = cpt.getBalance(cpt.msg.contractAddress)
|
||||
let
|
||||
beneficiary = ? cpt.stack.popAddress()
|
||||
isDead = not cpt.accountExists(beneficiary)
|
||||
balance = cpt.getBalance(cpt.msg.contractAddress)
|
||||
condition = isDead and not balance.isZero
|
||||
gasCost = cpt.gasCosts[SelfDestruct].sc_handler(condition)
|
||||
|
||||
let gasParams = GasParams(
|
||||
kind: SelfDestruct,
|
||||
sd_condition: isDead and not balance.isZero)
|
||||
|
||||
let res = ? cpt.gasCosts[SelfDestruct].c_handler(0.u256, gasParams)
|
||||
? cpt.opcodeGastCost(SelfDestruct,
|
||||
res.gasCost, reason = "SELFDESTRUCT EIP161")
|
||||
cpt.selfDestruct(beneficiary)
|
||||
? cpt.opcodeGastCost(SelfDestruct,
|
||||
gasCost, reason = "SELFDESTRUCT EIP161")
|
||||
cpt.selfDestruct(beneficiary)
|
||||
ok()
|
||||
|
||||
proc selfDestructEIP2929Op(k: var VmCtx): EvmResultVoid =
|
||||
|
@ -125,32 +119,27 @@ proc selfDestructEIP2929Op(k: var VmCtx): EvmResultVoid =
|
|||
let cpt = k.cpt
|
||||
? checkInStaticContext(cpt)
|
||||
|
||||
let beneficiary = ? cpt.stack.popAddress()
|
||||
block:
|
||||
let
|
||||
isDead = not cpt.accountExists(beneficiary)
|
||||
balance = cpt.getBalance(cpt.msg.contractAddress)
|
||||
let
|
||||
beneficiary = ? cpt.stack.popAddress()
|
||||
isDead = not cpt.accountExists(beneficiary)
|
||||
balance = cpt.getBalance(cpt.msg.contractAddress)
|
||||
condition = isDead and not balance.isZero
|
||||
|
||||
let
|
||||
gasParams = GasParams(
|
||||
kind: SelfDestruct,
|
||||
sd_condition: isDead and not balance.isZero)
|
||||
res = ? cpt.gasCosts[SelfDestruct].c_handler(0.u256, gasParams)
|
||||
var
|
||||
gasCost = cpt.gasCosts[SelfDestruct].sc_handler(condition)
|
||||
|
||||
var gasCost = res.gasCost
|
||||
|
||||
when evmc_enabled:
|
||||
if cpt.host.accessAccount(beneficiary) == EVMC_ACCESS_COLD:
|
||||
when evmc_enabled:
|
||||
if cpt.host.accessAccount(beneficiary) == EVMC_ACCESS_COLD:
|
||||
gasCost = gasCost + ColdAccountAccessCost
|
||||
else:
|
||||
cpt.vmState.mutateStateDB:
|
||||
if not db.inAccessList(beneficiary):
|
||||
db.accessList(beneficiary)
|
||||
gasCost = gasCost + ColdAccountAccessCost
|
||||
else:
|
||||
cpt.vmState.mutateStateDB:
|
||||
if not db.inAccessList(beneficiary):
|
||||
db.accessList(beneficiary)
|
||||
gasCost = gasCost + ColdAccountAccessCost
|
||||
|
||||
? cpt.opcodeGastCost(SelfDestruct,
|
||||
gasCost, reason = "SELFDESTRUCT EIP2929")
|
||||
cpt.selfDestruct(beneficiary)
|
||||
? cpt.opcodeGastCost(SelfDestruct,
|
||||
gasCost, reason = "SELFDESTRUCT EIP2929")
|
||||
cpt.selfDestruct(beneficiary)
|
||||
ok()
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue