mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-12 21:34:33 +00:00
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.
|
# transaction too, before self-destruction wipes the account at the end.
|
||||||
|
|
||||||
let
|
let
|
||||||
gasParams = GasParams(kind: Create, cr_memLength: len)
|
gasParams = GasParamsCr(memLength: len)
|
||||||
res = c.gasCosts[Create].cr_handler(0.u256, gasParams)
|
codeCost = c.gasCosts[Create].cr_handler(0.u256, gasParams)
|
||||||
codeCost = res.gasCost
|
|
||||||
|
|
||||||
if codeCost <= c.gasMeter.gasRemaining:
|
if codeCost <= c.gasMeter.gasRemaining:
|
||||||
c.gasMeter.consumeGas(codeCost,
|
c.gasMeter.consumeGas(codeCost,
|
||||||
|
@ -65,25 +65,22 @@ type
|
|||||||
# - σ: an account address
|
# - σ: an account address
|
||||||
# - μ: a value popped from the stack or its size.
|
# - μ: a value popped from the stack or its size.
|
||||||
|
|
||||||
case kind*: Op
|
kind*: Op
|
||||||
of Sstore:
|
isNewAccount*: bool
|
||||||
s_currentValue*: UInt256
|
gasBalance*: GasInt
|
||||||
s_originalValue*: UInt256
|
contractGas*: UInt256
|
||||||
of Call, CallCode, DelegateCall, StaticCall:
|
currentMemSize*: GasNatural
|
||||||
c_isNewAccount*: bool
|
memOffset*: GasNatural
|
||||||
c_gasBalance*: GasInt
|
memLength*: GasNatural
|
||||||
c_contractGas*: UInt256
|
|
||||||
c_currentMemSize*: GasNatural
|
GasParamsSs* = object
|
||||||
c_memOffset*: GasNatural
|
currentValue*: UInt256
|
||||||
c_memLength*: GasNatural
|
originalValue*: UInt256
|
||||||
of Create:
|
|
||||||
cr_currentMemSize*: GasNatural
|
GasParamsCr* = object
|
||||||
cr_memOffset*: GasNatural
|
currentMemSize*: GasNatural
|
||||||
cr_memLength*: GasNatural
|
memOffset*: GasNatural
|
||||||
of SelfDestruct:
|
memLength*: GasNatural
|
||||||
sd_condition*: bool
|
|
||||||
else:
|
|
||||||
discard
|
|
||||||
|
|
||||||
GasCostKind* = enum
|
GasCostKind* = enum
|
||||||
GckInvalidOp,
|
GckInvalidOp,
|
||||||
@ -91,10 +88,14 @@ type
|
|||||||
GckDynamic,
|
GckDynamic,
|
||||||
GckMemExpansion,
|
GckMemExpansion,
|
||||||
GckCreate,
|
GckCreate,
|
||||||
GckComplex,
|
GckCall,
|
||||||
GckLater
|
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
|
GasCost = object
|
||||||
case kind*: GasCostKind
|
case kind*: GasCostKind
|
||||||
@ -109,15 +110,21 @@ type
|
|||||||
m_handler*: proc(currentMemSize, memOffset, memLength: GasNatural): GasInt
|
m_handler*: proc(currentMemSize, memOffset, memLength: GasNatural): GasInt
|
||||||
{.nimcall, gcsafe, raises: [].}
|
{.nimcall, gcsafe, raises: [].}
|
||||||
of GckCreate:
|
of GckCreate:
|
||||||
cr_handler*: proc(value: UInt256, gasParams: GasParams): GasResult
|
cr_handler*: proc(value: UInt256, params: GasParamsCr): GasInt
|
||||||
{.nimcall, gcsafe, raises: [].}
|
{.nimcall, gcsafe, raises: [].}
|
||||||
of GckComplex:
|
of GckCall:
|
||||||
c_handler*: proc(value: UInt256, gasParams: GasParams): EvmResult[GasResult]
|
c_handler*: proc(value: UInt256, params: GasParams): EvmResult[CallGasResult]
|
||||||
{.nimcall, gcsafe, raises: [].}
|
{.nimcall, gcsafe, raises: [].}
|
||||||
# We use gasCost/gasRefund for:
|
# We use gasCost/gasRefund for:
|
||||||
# - Properly log and order cost and refund (for Sstore especially)
|
# - Properly log and order cost and refund (for Sstore especially)
|
||||||
# - Allow to use unsigned integer in the future
|
# - Allow to use unsigned integer in the future
|
||||||
# - CALL instruction requires passing the child message gas (Ccallgas in yellow paper)
|
# - 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]
|
GasCosts* = array[Op, GasCost]
|
||||||
|
|
||||||
@ -198,16 +205,13 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
|
|||||||
if not value.isZero:
|
if not value.isZero:
|
||||||
result += static(FeeSchedule[GasExpByte]) * (1 + log256(value))
|
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:
|
if value.isZero:
|
||||||
result.gasCost = static(FeeSchedule[GasCodeDeposit]) * gasParams.cr_memLength
|
result = static(FeeSchedule[GasCodeDeposit]) * params.memLength
|
||||||
else:
|
else:
|
||||||
result.gasCost = static(FeeSchedule[GasCreate]) +
|
result = static(FeeSchedule[GasCreate]) +
|
||||||
(static(FeeSchedule[GasInitcodeWord]) * gasParams.cr_memLength.wordCount) +
|
(static(FeeSchedule[GasInitcodeWord]) * params.memLength.wordCount) +
|
||||||
`prefix gasMemoryExpansion`(
|
`prefix gasMemoryExpansion`(params.currentMemSize, params.memOffset, params.memLength)
|
||||||
gasParams.cr_currentMemSize,
|
|
||||||
gasParams.cr_memOffset,
|
|
||||||
gasParams.cr_memLength)
|
|
||||||
|
|
||||||
func `prefix gasSha3`(currentMemSize, memOffset, memLength: GasNatural): GasInt {.nimcall.} =
|
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 = static(FeeSchedule[GasVeryLow])
|
||||||
result += `prefix gasMemoryExpansion`(currentMemSize, memOffset, memLength)
|
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
|
## Value is word to save
|
||||||
var res: GasResult
|
var res: SStoreGasResult
|
||||||
when fork >= FkBerlin:
|
when fork >= FkBerlin:
|
||||||
# EIP2929
|
# EIP2929
|
||||||
const
|
const
|
||||||
@ -252,13 +256,13 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
|
|||||||
ClearRefund {.used.} = FeeSchedule[RefundsClear]# clearing an originally existing storage slot
|
ClearRefund {.used.} = FeeSchedule[RefundsClear]# clearing an originally existing storage slot
|
||||||
|
|
||||||
when fork < FkConstantinople or fork == FkPetersburg:
|
when fork < FkConstantinople or fork == FkPetersburg:
|
||||||
let isStorageEmpty = gasParams.s_currentValue.isZero
|
let isStorageEmpty = params.currentValue.isZero
|
||||||
|
|
||||||
# Gas cost - literal translation of Yellow Paper
|
# Gas cost - literal translation of Yellow Paper
|
||||||
res.gasCost = if value.isZero.not and isStorageEmpty:
|
res.gasCost = if value.isZero.not and isStorageEmpty:
|
||||||
InitGas
|
InitGas
|
||||||
else:
|
else:
|
||||||
CleanGas
|
CleanGas
|
||||||
|
|
||||||
# Refund
|
# Refund
|
||||||
if value.isZero and not isStorageEmpty:
|
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.
|
# 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
|
# 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
|
res.gasCost = NoopGas
|
||||||
return ok(res)
|
return res
|
||||||
|
|
||||||
if gasParams.s_originalValue == gasParams.s_currentValue:
|
if params.originalValue == params.currentValue:
|
||||||
if gasParams.s_originalValue.isZero: # create slot (2.1.1)
|
if params.originalValue.isZero: # create slot (2.1.1)
|
||||||
res.gasCost = InitGas
|
res.gasCost = InitGas
|
||||||
return ok(res)
|
return res
|
||||||
|
|
||||||
if value.isZero: # delete slot (2.1.2b)
|
if value.isZero: # delete slot (2.1.2b)
|
||||||
res.gasRefund = ClearRefund
|
res.gasRefund = ClearRefund
|
||||||
|
|
||||||
res.gasCost = CleanGas # write existing slot (2.1.2)
|
res.gasCost = CleanGas # write existing slot (2.1.2)
|
||||||
return ok(res)
|
return res
|
||||||
|
|
||||||
if not gasParams.s_originalValue.isZero:
|
if not params.originalValue.isZero:
|
||||||
if gasParams.s_currentValue.isZero: # recreate slot (2.2.1.1)
|
if params.currentValue.isZero: # recreate slot (2.2.1.1)
|
||||||
res.gasRefund -= ClearRefund
|
res.gasRefund -= ClearRefund
|
||||||
if value.isZero: # delete slot (2.2.1.2)
|
if value.isZero: # delete slot (2.2.1.2)
|
||||||
res.gasRefund += ClearRefund
|
res.gasRefund += ClearRefund
|
||||||
|
|
||||||
if gasParams.s_originalValue == value:
|
if params.originalValue == value:
|
||||||
if gasParams.s_originalValue.isZero: # reset to original inexistent slot (2.2.2.1)
|
if params.originalValue.isZero: # reset to original inexistent slot (2.2.2.1)
|
||||||
res.gasRefund += InitRefund
|
res.gasRefund += InitRefund
|
||||||
else: # reset to original existing slot (2.2.2.2)
|
else: # reset to original existing slot (2.2.2.2)
|
||||||
res.gasRefund += CleanRefund
|
res.gasRefund += CleanRefund
|
||||||
|
|
||||||
res.gasCost = DirtyGas # dirty update (2.2)
|
res.gasCost = DirtyGas # dirty update (2.2)
|
||||||
ok(res)
|
res
|
||||||
|
|
||||||
func `prefix gasLog0`(currentMemSize, memOffset, memLength: GasNatural): GasInt {.nimcall.} =
|
func `prefix gasLog0`(currentMemSize, memOffset, memLength: GasNatural): GasInt {.nimcall.} =
|
||||||
result = `prefix gasMemoryExpansion`(currentMemSize, memOffset, memLength)
|
result = `prefix gasMemoryExpansion`(currentMemSize, memOffset, memLength)
|
||||||
@ -343,7 +347,7 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
|
|||||||
static(FeeSchedule[GasLogData]) * memLength +
|
static(FeeSchedule[GasLogData]) * memLength +
|
||||||
static(4 * FeeSchedule[GasLogTopic])
|
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
|
# From the Yellow Paper, going through the equation from bottom to top
|
||||||
# https://ethereum.github.io/yellowpaper/paper.pdf#appendix.H
|
# 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 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
|
# 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:
|
var gasCost: int64 = `prefix gasMemoryExpansion`(
|
||||||
# Note there is a "bug" in the Ethereum Yellow Paper
|
params.currentMemSize,
|
||||||
# - https://github.com/ethereum/yellowpaper/issues/325
|
params.memOffset,
|
||||||
# μg already includes memory expansion costs but it is not
|
params.memLength)
|
||||||
# plainly explained n the CALL opcode details
|
var childGasLimit: int64
|
||||||
|
|
||||||
# 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
|
|
||||||
)
|
|
||||||
|
|
||||||
# Cnew_account
|
# Cnew_account
|
||||||
if gasParams.c_isNewAccount and gasParams.kind == Call:
|
if params.isNewAccount and params.kind == Call:
|
||||||
when fork < FkSpurious:
|
when fork < FkSpurious:
|
||||||
# Pre-EIP161 all account creation calls consumed 25000 gas.
|
# Pre-EIP161 all account creation calls consumed 25000 gas.
|
||||||
res.gasCost += static(FeeSchedule[GasNewAccount])
|
gasCost += static(FeeSchedule[GasNewAccount])
|
||||||
else:
|
else:
|
||||||
# Afterwards, only those transfering value:
|
# 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-158.md
|
||||||
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md
|
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md
|
||||||
if not value.isZero:
|
if not value.isZero:
|
||||||
res.gasCost += static(FeeSchedule[GasNewAccount])
|
gasCost += static(FeeSchedule[GasNewAccount])
|
||||||
|
|
||||||
# Cxfer
|
# Cxfer
|
||||||
if not value.isZero and gasParams.kind in {Call, CallCode}:
|
if not value.isZero and params.kind in {Call, CallCode}:
|
||||||
res.gasCost += static(FeeSchedule[GasCallValue])
|
gasCost += static(FeeSchedule[GasCallValue])
|
||||||
|
|
||||||
# Cextra
|
# Cextra
|
||||||
res.gasCost += static(FeeSchedule[GasCall])
|
gasCost += static(FeeSchedule[GasCall])
|
||||||
|
|
||||||
# Cgascap
|
# Cgascap
|
||||||
when fork >= FkTangerine:
|
when fork >= FkTangerine:
|
||||||
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md
|
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md
|
||||||
let gas = `prefix all_but_one_64th`(gasParams.c_gasBalance - res.gasCost)
|
let gas = `prefix all_but_one_64th`(params.gasBalance - gasCost)
|
||||||
if gasParams.c_contractGas > high(GasInt).u256 or
|
if params.contractGas > high(int64).u256 or
|
||||||
gas < gasParams.c_contractGas.truncate(GasInt):
|
gas < params.contractGas.truncate(int64):
|
||||||
res.gasRefund = gas
|
childGasLimit = gas
|
||||||
else:
|
else:
|
||||||
res.gasRefund = gasParams.c_contractGas.truncate(GasInt)
|
childGasLimit = params.contractGas.truncate(int64)
|
||||||
else:
|
else:
|
||||||
if gasParams.c_contractGas > high(GasInt).u256:
|
if params.contractGas > high(int64).u256:
|
||||||
return err(gasErr(GasIntOverflow))
|
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 childGasLimit > 0: # skip check if childGasLimit is negative
|
||||||
if res.gasCost.u256 + res.gasRefund.u256 > high(GasInt).u256:
|
if gasCost.u256 + childGasLimit.u256 > high(int64).u256:
|
||||||
return err(gasErr(GasIntOverflow))
|
return err(gasErr(GasIntOverflow))
|
||||||
|
|
||||||
res.gasCost += res.gasRefund
|
gasCost += childGasLimit
|
||||||
|
|
||||||
# Ccallgas - Gas sent to the child message
|
# Ccallgas - Gas sent to the child message
|
||||||
if not value.isZero and gasParams.kind in {Call, CallCode}:
|
if not value.isZero and params.kind in {Call, CallCode}:
|
||||||
res.gasRefund += static(FeeSchedule[GasCallStipend])
|
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.} =
|
func `prefix gasHalt`(currentMemSize, memOffset, memLength: GasNatural): GasInt {.nimcall.} =
|
||||||
`prefix gasMemoryExpansion`(currentMemSize, memOffset, memLength)
|
`prefix gasMemoryExpansion`(currentMemSize, memOffset, memLength)
|
||||||
|
|
||||||
func `prefix gasSelfDestruct`(value: UInt256, gasParams: GasParams): EvmResult[GasResult] {.nimcall.} =
|
func `prefix gasSelfDestruct`(condition: bool): GasInt {.nimcall.} =
|
||||||
var res: GasResult
|
result += static(FeeSchedule[GasSelfDestruct])
|
||||||
res.gasCost += static(FeeSchedule[GasSelfDestruct])
|
|
||||||
when fork >= FkTangerine:
|
when fork >= FkTangerine:
|
||||||
if gasParams.sd_condition:
|
if condition:
|
||||||
res.gasCost += static(FeeSchedule[GasNewAccount])
|
result += static(FeeSchedule[GasNewAccount])
|
||||||
ok(res)
|
|
||||||
|
|
||||||
func `prefix gasCreate2`(currentMemSize, memOffset, memLength: GasNatural): GasInt {.nimcall.} =
|
func `prefix gasCreate2`(currentMemSize, memOffset, memLength: GasNatural): GasInt {.nimcall.} =
|
||||||
result = static(FeeSchedule[GasSha3Word]) * (memLength).wordCount
|
result = static(FeeSchedule[GasSha3Word]) * (memLength).wordCount
|
||||||
@ -475,14 +465,22 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
|
|||||||
{.nimcall, gcsafe, raises: [].}): GasCost =
|
{.nimcall, gcsafe, raises: [].}): GasCost =
|
||||||
GasCost(kind: GckMemExpansion, m_handler: handler)
|
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 =
|
{.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 =
|
{.nimcall, gcsafe, raises: [].}): GasCost =
|
||||||
GasCost(kind: GckCreate, cr_handler: handler)
|
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
|
# Returned value
|
||||||
fill_enum_table_holes(Op, GasCost(kind: GckInvalidOp)):
|
fill_enum_table_holes(Op, GasCost(kind: GckInvalidOp)):
|
||||||
[
|
[
|
||||||
@ -556,7 +554,7 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
|
|||||||
Mstore: memExpansion `prefix gasLoadStore`,
|
Mstore: memExpansion `prefix gasLoadStore`,
|
||||||
Mstore8: memExpansion `prefix gasLoadStore`,
|
Mstore8: memExpansion `prefix gasLoadStore`,
|
||||||
Sload: fixedOrLater GasSload,
|
Sload: fixedOrLater GasSload,
|
||||||
Sstore: complex `prefix gasSstore`,
|
Sstore: handleSstore `prefix gasSstore`,
|
||||||
Jump: fixed GasMid,
|
Jump: fixed GasMid,
|
||||||
JumpI: fixed GasHigh,
|
JumpI: fixed GasHigh,
|
||||||
Pc: fixed GasBase,
|
Pc: fixed GasBase,
|
||||||
@ -651,15 +649,15 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) =
|
|||||||
|
|
||||||
# f0s: System operations
|
# f0s: System operations
|
||||||
Create: handleCreate `prefix gasCreate`,
|
Create: handleCreate `prefix gasCreate`,
|
||||||
Call: complex `prefix gasCall`,
|
Call: handleCall `prefix gasCall`,
|
||||||
CallCode: complex `prefix gasCall`,
|
CallCode: handleCall `prefix gasCall`,
|
||||||
Return: memExpansion `prefix gasHalt`,
|
Return: memExpansion `prefix gasHalt`,
|
||||||
DelegateCall: complex `prefix gasCall`,
|
DelegateCall: handleCall `prefix gasCall`,
|
||||||
Create2: memExpansion `prefix gasCreate2`,
|
Create2: memExpansion `prefix gasCreate2`,
|
||||||
StaticCall: complex `prefix gasCall`,
|
StaticCall: handleCall `prefix gasCall`,
|
||||||
Revert: memExpansion `prefix gasHalt`,
|
Revert: memExpansion `prefix gasHalt`,
|
||||||
Invalid: fixed GasZero,
|
Invalid: fixed GasZero,
|
||||||
SelfDestruct: complex `prefix gasSelfDestruct`
|
SelfDestruct: handleSuicide `prefix gasSelfDestruct`
|
||||||
]
|
]
|
||||||
|
|
||||||
# Generate the fork-specific gas costs tables
|
# Generate the fork-specific gas costs tables
|
||||||
|
@ -210,22 +210,22 @@ proc callOp(k: var VmCtx): EvmResultVoid =
|
|||||||
|
|
||||||
let
|
let
|
||||||
p = ? cpt.callParams
|
p = ? cpt.callParams
|
||||||
res = ? cpt.gasCosts[Call].c_handler(
|
|
||||||
|
var
|
||||||
|
(gasCost, childGasLimit) = ? cpt.gasCosts[Call].c_handler(
|
||||||
p.value,
|
p.value,
|
||||||
GasParams(
|
GasParams(
|
||||||
kind: Call,
|
kind: Call,
|
||||||
c_isNewAccount: not cpt.accountExists(p.contractAddress),
|
isNewAccount: not cpt.accountExists(p.contractAddress),
|
||||||
c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929,
|
gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929,
|
||||||
c_contractGas: p.gas,
|
contractGas: p.gas,
|
||||||
c_currentMemSize: cpt.memory.len,
|
currentMemSize: cpt.memory.len,
|
||||||
c_memOffset: p.memOffset,
|
memOffset: p.memOffset,
|
||||||
c_memLength: p.memLength))
|
memLength: p.memLength))
|
||||||
|
|
||||||
var (gasCost, childGasLimit) = res
|
|
||||||
|
|
||||||
|
# at this point gasCost is always > 0
|
||||||
gasCost += p.gasCallEIP2929
|
gasCost += p.gasCallEIP2929
|
||||||
if gasCost >= 0:
|
? cpt.opcodeGastCost(Call, gasCost, reason = $Call)
|
||||||
? cpt.opcodeGastCost(Call, gasCost, reason = $Call)
|
|
||||||
|
|
||||||
cpt.returnData.setLen(0)
|
cpt.returnData.setLen(0)
|
||||||
|
|
||||||
@ -237,9 +237,6 @@ proc callOp(k: var VmCtx): EvmResultVoid =
|
|||||||
cpt.gasMeter.returnGas(childGasLimit)
|
cpt.gasMeter.returnGas(childGasLimit)
|
||||||
return ok()
|
return ok()
|
||||||
|
|
||||||
if gasCost < 0 and childGasLimit <= 0:
|
|
||||||
return err(opErr(OutOfGas))
|
|
||||||
|
|
||||||
cpt.memory.extend(p.memInPos, p.memInLen)
|
cpt.memory.extend(p.memInPos, p.memInLen)
|
||||||
cpt.memory.extend(p.memOutPos, p.memOutLen)
|
cpt.memory.extend(p.memOutPos, p.memOutLen)
|
||||||
|
|
||||||
@ -288,21 +285,22 @@ proc callCodeOp(k: var VmCtx): EvmResultVoid =
|
|||||||
let
|
let
|
||||||
cpt = k.cpt
|
cpt = k.cpt
|
||||||
p = ? cpt.callCodeParams
|
p = ? cpt.callCodeParams
|
||||||
res = ? cpt.gasCosts[CallCode].c_handler(
|
|
||||||
|
var
|
||||||
|
(gasCost, childGasLimit) = ? cpt.gasCosts[CallCode].c_handler(
|
||||||
p.value,
|
p.value,
|
||||||
GasParams(
|
GasParams(
|
||||||
kind: CallCode,
|
kind: CallCode,
|
||||||
c_isNewAccount: not cpt.accountExists(p.contractAddress),
|
isNewAccount: not cpt.accountExists(p.contractAddress),
|
||||||
c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929,
|
gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929,
|
||||||
c_contractGas: p.gas,
|
contractGas: p.gas,
|
||||||
c_currentMemSize: cpt.memory.len,
|
currentMemSize: cpt.memory.len,
|
||||||
c_memOffset: p.memOffset,
|
memOffset: p.memOffset,
|
||||||
c_memLength: p.memLength))
|
memLength: p.memLength))
|
||||||
|
|
||||||
var (gasCost, childGasLimit) = res
|
# at this point gasCost is always > 0
|
||||||
gasCost += p.gasCallEIP2929
|
gasCost += p.gasCallEIP2929
|
||||||
if gasCost >= 0:
|
? cpt.opcodeGastCost(CallCode, gasCost, reason = $CallCode)
|
||||||
? cpt.opcodeGastCost(CallCode, gasCost, reason = $CallCode)
|
|
||||||
|
|
||||||
cpt.returnData.setLen(0)
|
cpt.returnData.setLen(0)
|
||||||
|
|
||||||
@ -314,9 +312,6 @@ proc callCodeOp(k: var VmCtx): EvmResultVoid =
|
|||||||
cpt.gasMeter.returnGas(childGasLimit)
|
cpt.gasMeter.returnGas(childGasLimit)
|
||||||
return ok()
|
return ok()
|
||||||
|
|
||||||
if gasCost < 0 and childGasLimit <= 0:
|
|
||||||
return err(opErr(OutOfGas))
|
|
||||||
|
|
||||||
cpt.memory.extend(p.memInPos, p.memInLen)
|
cpt.memory.extend(p.memInPos, p.memInLen)
|
||||||
cpt.memory.extend(p.memOutPos, p.memOutLen)
|
cpt.memory.extend(p.memOutPos, p.memOutLen)
|
||||||
|
|
||||||
@ -366,21 +361,22 @@ proc delegateCallOp(k: var VmCtx): EvmResultVoid =
|
|||||||
let
|
let
|
||||||
cpt = k.cpt
|
cpt = k.cpt
|
||||||
p = ? cpt.delegateCallParams
|
p = ? cpt.delegateCallParams
|
||||||
res = ? cpt.gasCosts[DelegateCall].c_handler(
|
|
||||||
|
var
|
||||||
|
(gasCost, childGasLimit) = ? cpt.gasCosts[DelegateCall].c_handler(
|
||||||
p.value,
|
p.value,
|
||||||
GasParams(
|
GasParams(
|
||||||
kind: DelegateCall,
|
kind: DelegateCall,
|
||||||
c_isNewAccount: not cpt.accountExists(p.contractAddress),
|
isNewAccount: not cpt.accountExists(p.contractAddress),
|
||||||
c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929,
|
gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929,
|
||||||
c_contractGas: p.gas,
|
contractGas: p.gas,
|
||||||
c_currentMemSize: cpt.memory.len,
|
currentMemSize: cpt.memory.len,
|
||||||
c_memOffset: p.memOffset,
|
memOffset: p.memOffset,
|
||||||
c_memLength: p.memLength))
|
memLength: p.memLength))
|
||||||
|
|
||||||
var (gasCost, childGasLimit) = res
|
# at this point gasCost is always > 0
|
||||||
gasCost += p.gasCallEIP2929
|
gasCost += p.gasCallEIP2929
|
||||||
if gasCost >= 0:
|
? cpt.opcodeGastCost(DelegateCall, gasCost, reason = $DelegateCall)
|
||||||
? cpt.opcodeGastCost(DelegateCall, gasCost, reason = $DelegateCall)
|
|
||||||
|
|
||||||
cpt.returnData.setLen(0)
|
cpt.returnData.setLen(0)
|
||||||
if cpt.msg.depth >= MaxCallDepth:
|
if cpt.msg.depth >= MaxCallDepth:
|
||||||
@ -391,9 +387,6 @@ proc delegateCallOp(k: var VmCtx): EvmResultVoid =
|
|||||||
cpt.gasMeter.returnGas(childGasLimit)
|
cpt.gasMeter.returnGas(childGasLimit)
|
||||||
return ok()
|
return ok()
|
||||||
|
|
||||||
if gasCost < 0 and childGasLimit <= 0:
|
|
||||||
return err(opErr(OutOfGas))
|
|
||||||
|
|
||||||
cpt.memory.extend(p.memInPos, p.memInLen)
|
cpt.memory.extend(p.memInPos, p.memInLen)
|
||||||
cpt.memory.extend(p.memOutPos, p.memOutLen)
|
cpt.memory.extend(p.memOutPos, p.memOutLen)
|
||||||
|
|
||||||
@ -438,21 +431,22 @@ proc staticCallOp(k: var VmCtx): EvmResultVoid =
|
|||||||
let
|
let
|
||||||
cpt = k.cpt
|
cpt = k.cpt
|
||||||
p = ? cpt.staticCallParams
|
p = ? cpt.staticCallParams
|
||||||
res = ? cpt.gasCosts[StaticCall].c_handler(
|
|
||||||
|
var
|
||||||
|
(gasCost, childGasLimit) = ? cpt.gasCosts[StaticCall].c_handler(
|
||||||
p.value,
|
p.value,
|
||||||
GasParams(
|
GasParams(
|
||||||
kind: StaticCall,
|
kind: StaticCall,
|
||||||
c_isNewAccount: not cpt.accountExists(p.contractAddress),
|
isNewAccount: not cpt.accountExists(p.contractAddress),
|
||||||
c_gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929,
|
gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929,
|
||||||
c_contractGas: p.gas,
|
contractGas: p.gas,
|
||||||
c_currentMemSize: cpt.memory.len,
|
currentMemSize: cpt.memory.len,
|
||||||
c_memOffset: p.memOffset,
|
memOffset: p.memOffset,
|
||||||
c_memLength: p.memLength))
|
memLength: p.memLength))
|
||||||
|
|
||||||
var (gasCost, childGasLimit) = res
|
# at this point gasCost is always > 0
|
||||||
gasCost += p.gasCallEIP2929
|
gasCost += p.gasCallEIP2929
|
||||||
if gasCost >= 0:
|
? cpt.opcodeGastCost(StaticCall, gasCost, reason = $StaticCall)
|
||||||
? cpt.opcodeGastCost(StaticCall, gasCost, reason = $StaticCall)
|
|
||||||
|
|
||||||
cpt.returnData.setLen(0)
|
cpt.returnData.setLen(0)
|
||||||
|
|
||||||
@ -464,9 +458,6 @@ proc staticCallOp(k: var VmCtx): EvmResultVoid =
|
|||||||
cpt.gasMeter.returnGas(childGasLimit)
|
cpt.gasMeter.returnGas(childGasLimit)
|
||||||
return ok()
|
return ok()
|
||||||
|
|
||||||
if gasCost < 0 and childGasLimit <= 0:
|
|
||||||
return err(opErr(OutOfGas))
|
|
||||||
|
|
||||||
cpt.memory.extend(p.memInPos, p.memInLen)
|
cpt.memory.extend(p.memInPos, p.memInLen)
|
||||||
cpt.memory.extend(p.memOutPos, p.memOutLen)
|
cpt.memory.extend(p.memOutPos, p.memOutLen)
|
||||||
|
|
||||||
|
@ -101,15 +101,14 @@ proc createOp(k: var VmCtx): EvmResultVoid =
|
|||||||
return err(opErr(InvalidInitCode))
|
return err(opErr(InvalidInitCode))
|
||||||
|
|
||||||
let
|
let
|
||||||
gasParams = GasParams(
|
gasParams = GasParamsCr(
|
||||||
kind: Create,
|
currentMemSize: cpt.memory.len,
|
||||||
cr_currentMemSize: cpt.memory.len,
|
memOffset: memPos,
|
||||||
cr_memOffset: memPos,
|
memLength: memLen)
|
||||||
cr_memLength: memLen)
|
gasCost = cpt.gasCosts[Create].cr_handler(1.u256, gasParams)
|
||||||
res = cpt.gasCosts[Create].cr_handler(1.u256, gasParams)
|
|
||||||
|
|
||||||
? cpt.opcodeGastCost(Create,
|
? cpt.opcodeGastCost(Create,
|
||||||
res.gasCost, reason = "CREATE: GasCreate + memLen * memory expansion")
|
gasCost, reason = "CREATE: GasCreate + memLen * memory expansion")
|
||||||
cpt.memory.extend(memPos, memLen)
|
cpt.memory.extend(memPos, memLen)
|
||||||
cpt.returnData.setLen(0)
|
cpt.returnData.setLen(0)
|
||||||
|
|
||||||
@ -182,14 +181,13 @@ proc create2Op(k: var VmCtx): EvmResultVoid =
|
|||||||
return err(opErr(InvalidInitCode))
|
return err(opErr(InvalidInitCode))
|
||||||
|
|
||||||
let
|
let
|
||||||
gasParams = GasParams(
|
gasParams = GasParamsCr(
|
||||||
kind: Create,
|
currentMemSize: cpt.memory.len,
|
||||||
cr_currentMemSize: cpt.memory.len,
|
memOffset: memPos,
|
||||||
cr_memOffset: memPos,
|
memLength: memLen)
|
||||||
cr_memLength: memLen)
|
|
||||||
res = cpt.gasCosts[Create].cr_handler(1.u256, gasParams)
|
|
||||||
|
|
||||||
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,
|
? cpt.opcodeGastCost(Create2,
|
||||||
gasCost, reason = "CREATE2: GasCreate + memLen * memory expansion")
|
gasCost, reason = "CREATE2: GasCreate + memLen * memory expansion")
|
||||||
|
@ -58,11 +58,10 @@ else:
|
|||||||
proc sstoreImpl(c: Computation, slot, newValue: UInt256): EvmResultVoid =
|
proc sstoreImpl(c: Computation, slot, newValue: UInt256): EvmResultVoid =
|
||||||
let
|
let
|
||||||
currentValue = c.getStorage(slot)
|
currentValue = c.getStorage(slot)
|
||||||
gasParam = GasParams(
|
gasParam = GasParamsSs(
|
||||||
kind: Op.Sstore,
|
currentValue: currentValue)
|
||||||
s_currentValue: currentValue)
|
|
||||||
|
|
||||||
res = ? c.gasCosts[Sstore].c_handler(newValue, gasParam)
|
res = c.gasCosts[Sstore].ss_handler(newValue, gasParam)
|
||||||
|
|
||||||
? c.opcodeGastCost(Sstore, res.gasCost, "SSTORE")
|
? c.opcodeGastCost(Sstore, res.gasCost, "SSTORE")
|
||||||
if res.gasRefund > 0:
|
if res.gasRefund > 0:
|
||||||
@ -78,12 +77,11 @@ else:
|
|||||||
stateDB = c.vmState.readOnlyStateDB
|
stateDB = c.vmState.readOnlyStateDB
|
||||||
currentValue = c.getStorage(slot)
|
currentValue = c.getStorage(slot)
|
||||||
|
|
||||||
gasParam = GasParams(
|
gasParam = GasParamsSs(
|
||||||
kind: Op.Sstore,
|
currentValue: currentValue,
|
||||||
s_currentValue: currentValue,
|
originalValue: stateDB.getCommittedStorage(c.msg.contractAddress, slot))
|
||||||
s_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")
|
? c.opcodeGastCost(Sstore, res.gasCost + coldAccess, "SSTORE")
|
||||||
|
|
||||||
|
@ -86,17 +86,15 @@ proc selfDestructOp(k: var VmCtx): EvmResultVoid =
|
|||||||
|
|
||||||
proc selfDestructEIP150Op(k: var VmCtx): EvmResultVoid =
|
proc selfDestructEIP150Op(k: var VmCtx): EvmResultVoid =
|
||||||
## selfDestructEip150 (auto generated comment)
|
## selfDestructEip150 (auto generated comment)
|
||||||
let cpt = k.cpt
|
let
|
||||||
let beneficiary = ? cpt.stack.popAddress()
|
cpt = k.cpt
|
||||||
block:
|
beneficiary = ? cpt.stack.popAddress()
|
||||||
let gasParams = GasParams(
|
condition = not cpt.accountExists(beneficiary)
|
||||||
kind: SelfDestruct,
|
gasCost = cpt.gasCosts[SelfDestruct].sc_handler(condition)
|
||||||
sd_condition: not cpt.accountExists(beneficiary))
|
|
||||||
|
|
||||||
let res = ? cpt.gasCosts[SelfDestruct].c_handler(0.u256, gasParams)
|
? cpt.opcodeGastCost(SelfDestruct,
|
||||||
? cpt.opcodeGastCost(SelfDestruct,
|
gasCost, reason = "SELFDESTRUCT EIP150")
|
||||||
res.gasCost, reason = "SELFDESTRUCT EIP150")
|
cpt.selfDestruct(beneficiary)
|
||||||
cpt.selfDestruct(beneficiary)
|
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
proc selfDestructEIP161Op(k: var VmCtx): EvmResultVoid =
|
proc selfDestructEIP161Op(k: var VmCtx): EvmResultVoid =
|
||||||
@ -104,20 +102,16 @@ proc selfDestructEIP161Op(k: var VmCtx): EvmResultVoid =
|
|||||||
let cpt = k.cpt
|
let cpt = k.cpt
|
||||||
? checkInStaticContext(cpt)
|
? checkInStaticContext(cpt)
|
||||||
|
|
||||||
let beneficiary = ? cpt.stack.popAddress()
|
let
|
||||||
block:
|
beneficiary = ? cpt.stack.popAddress()
|
||||||
let
|
isDead = not cpt.accountExists(beneficiary)
|
||||||
isDead = not cpt.accountExists(beneficiary)
|
balance = cpt.getBalance(cpt.msg.contractAddress)
|
||||||
balance = cpt.getBalance(cpt.msg.contractAddress)
|
condition = isDead and not balance.isZero
|
||||||
|
gasCost = cpt.gasCosts[SelfDestruct].sc_handler(condition)
|
||||||
|
|
||||||
let gasParams = GasParams(
|
? cpt.opcodeGastCost(SelfDestruct,
|
||||||
kind: SelfDestruct,
|
gasCost, reason = "SELFDESTRUCT EIP161")
|
||||||
sd_condition: isDead and not balance.isZero)
|
cpt.selfDestruct(beneficiary)
|
||||||
|
|
||||||
let res = ? cpt.gasCosts[SelfDestruct].c_handler(0.u256, gasParams)
|
|
||||||
? cpt.opcodeGastCost(SelfDestruct,
|
|
||||||
res.gasCost, reason = "SELFDESTRUCT EIP161")
|
|
||||||
cpt.selfDestruct(beneficiary)
|
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
proc selfDestructEIP2929Op(k: var VmCtx): EvmResultVoid =
|
proc selfDestructEIP2929Op(k: var VmCtx): EvmResultVoid =
|
||||||
@ -125,32 +119,27 @@ proc selfDestructEIP2929Op(k: var VmCtx): EvmResultVoid =
|
|||||||
let cpt = k.cpt
|
let cpt = k.cpt
|
||||||
? checkInStaticContext(cpt)
|
? checkInStaticContext(cpt)
|
||||||
|
|
||||||
let beneficiary = ? cpt.stack.popAddress()
|
let
|
||||||
block:
|
beneficiary = ? cpt.stack.popAddress()
|
||||||
let
|
isDead = not cpt.accountExists(beneficiary)
|
||||||
isDead = not cpt.accountExists(beneficiary)
|
balance = cpt.getBalance(cpt.msg.contractAddress)
|
||||||
balance = cpt.getBalance(cpt.msg.contractAddress)
|
condition = isDead and not balance.isZero
|
||||||
|
|
||||||
let
|
var
|
||||||
gasParams = GasParams(
|
gasCost = cpt.gasCosts[SelfDestruct].sc_handler(condition)
|
||||||
kind: SelfDestruct,
|
|
||||||
sd_condition: isDead and not balance.isZero)
|
|
||||||
res = ? cpt.gasCosts[SelfDestruct].c_handler(0.u256, gasParams)
|
|
||||||
|
|
||||||
var gasCost = res.gasCost
|
when evmc_enabled:
|
||||||
|
if cpt.host.accessAccount(beneficiary) == EVMC_ACCESS_COLD:
|
||||||
when evmc_enabled:
|
gasCost = gasCost + ColdAccountAccessCost
|
||||||
if cpt.host.accessAccount(beneficiary) == EVMC_ACCESS_COLD:
|
else:
|
||||||
|
cpt.vmState.mutateStateDB:
|
||||||
|
if not db.inAccessList(beneficiary):
|
||||||
|
db.accessList(beneficiary)
|
||||||
gasCost = gasCost + ColdAccountAccessCost
|
gasCost = gasCost + ColdAccountAccessCost
|
||||||
else:
|
|
||||||
cpt.vmState.mutateStateDB:
|
|
||||||
if not db.inAccessList(beneficiary):
|
|
||||||
db.accessList(beneficiary)
|
|
||||||
gasCost = gasCost + ColdAccountAccessCost
|
|
||||||
|
|
||||||
? cpt.opcodeGastCost(SelfDestruct,
|
? cpt.opcodeGastCost(SelfDestruct,
|
||||||
gasCost, reason = "SELFDESTRUCT EIP2929")
|
gasCost, reason = "SELFDESTRUCT EIP2929")
|
||||||
cpt.selfDestruct(beneficiary)
|
cpt.selfDestruct(beneficiary)
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user