2018-05-24 10:01:59 +00:00
# Nimbus
# Copyright (c) 2018 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.
import
2019-02-05 19:15:50 +00:00
math , eth / common / eth_types ,
Refactor interpreter dispatch (#65)
* move forks constants, rename errors
* Move vm/utils to vm/interpreter/utils
* initial opcodes refactoring
* Add refactored Comparison & Bitwise Logic Operations
* Add sha3 and address, simplify macro, support pop 0
* balance, origin, caller, callValue
* fix gas copy opcodes gas costs, add callDataLoad/Size/Copy, CodeSize/Copy and gas price opcode
* Update with 30s, 40s, 50s opcodes + impl of balance + stack improvement
* add push, dup, swap, log, create and call operations
* finish opcode implementation
* Add the new dispatching logic
* Pass the opcode test
* Make test_vm_json compile
* halt execution without exceptions for Return, Revert, selfdestruct (fix #62)
* Properly catch and recover from EVM exceptions (stack underflow ...)
* Fix byte op
* Fix jump regressions
* Update for latest devel, don't import old dispatch code as quasiBoolean macro is broken by latest devel
* Fix sha3 regression on empty memory slice and until end of range slice
* Fix padding / range error on expXY_success (gas computation left)
* update logging procs
* Add tracing - expXY_success is not a regression, sload stub was accidentally passing the test
* Reuse the same stub as OO implementation
* Delete previous opcode implementation
* Delete object oriented fork code
* Delete exceptions that were used as control flows
* delete base.nim :fire:, yet another OO remnants
* Delete opcode table
* Enable omputed gotos and compile-time gas fees
* Revert const gasCosts -> generates SIGSEGV
* inline push, swap and dup opcodes
* loggers are now template again, why does this pass new tests?
* Trigger CI rebuild after rocksdb fix https://github.com/status-im/nim-rocksdb/pull/5
* Address review comment on "push" + VMTests in debug mode (not release)
* Address review comment: don't tag fork by default, make opcode impl grepable
* Static compilation fixes after rebasing
* fix the initialization of the VM database
* add a missing import
* Deactivate balance and sload test following #59
* Reactivate stack check (deactivated in #59, necessary to pass tests)
* Merge remaining opcodes implementation from #59
* Merge callDataLoad and codeCopy fixes, todo simplify see #67
2018-07-06 07:52:31 +00:00
. / utils / [ macros_gen_opcodes , utils_numeric ] ,
2021-06-01 11:04:47 +00:00
. / opcode_values , .. / .. / forks , .. / .. / errors
2018-05-24 10:01:59 +00:00
2020-01-17 14:49:22 +00:00
when defined ( evmc_enabled ) :
import evmc / evmc
2018-06-12 15:33:47 +00:00
# Gas Fee Schedule
# Yellow Paper Appendix G - https://ethereum.github.io/yellowpaper/paper.pdf
type
2018-11-28 19:02:21 +00:00
GasFeeKind * = enum
2018-06-12 15:33:47 +00:00
GasZero , # Nothing paid for operations of the set Wzero.
GasBase , # Amount of gas to pay for operations of the set Wbase.
GasVeryLow , # Amount of gas to pay for operations of the set Wverylow.
GasLow , # Amount of gas to pay for operations of the set Wlow.
GasMid , # Amount of gas to pay for operations of the set Wmid.
GasHigh , # Amount of gas to pay for operations of the set Whigh.
GasExtCode , # Amount of gas to pay for operations of the set Wextcode.
GasBalance , # Amount of gas to pay for a BALANCE operation.
GasSload , # Paid for a SLOAD operation.
GasJumpDest , # Paid for a JUMPDEST operation.
GasSset , # Paid for an SSTORE operation when the storage value is set to non-zero from zero.
GasSreset , # Paid for an SSTORE operation when the storage value’ s zeroness remains unchanged or is set to zero.
RefundSclear , # Refund given (added into refund counter) when the storage value is set to zero from non-zero.
RefundSelfDestruct , # Refund given (added into refund counter) for self-destructing an account.
GasSelfDestruct , # Amount of gas to pay for a SELFDESTRUCT operation.
GasCreate , # Paid for a CREATE operation.
GasCodeDeposit , # Paid per byte for a CREATE operation to succeed in placing code into state.
GasCall , # Paid for a CALL operation.
GasCallValue , # Paid for a non-zero value transfer as part of the CALL operation.
GasCallStipend , # A stipend for the called contract subtracted from Gcallvalue for a non-zero value transfer.
GasNewAccount , # Paid for a CALL or SELFDESTRUCT operation which creates an account.
GasExp , # Partial payment for an EXP operation.
GasExpByte , # Partial payment when multiplied by ⌈log256(exponent)⌉ for the EXP operation.
GasMemory , # Paid for every additional word when expanding memory.
GasTXCreate , # Paid by all contract-creating transactions after the Homestead transition.
GasTXDataZero , # Paid for every zero byte of data or code for a transaction.
GasTXDataNonZero , # Paid for every non-zero byte of data or code for a transaction.
GasTransaction , # Paid for every transaction.
GasLog , # Partial payment for a LOG operation.
GasLogData , # Paid for each byte in a LOG operation’ s data.
GasLogTopic , # Paid for each topic of a LOG operation.
GasSha3 , # Paid for each SHA3 operation.
GasSha3Word , # Paid for each word (rounded up) for input data to a SHA3 operation.
GasCopy , # Partial payment for COPY operations, multiplied by words copied, rounded up.
2019-04-30 05:23:51 +00:00
GasBlockhash , # Payment for BLOCKHASH operation.
GasExtCodeHash # Payment for contract's code hashing
2018-06-12 15:33:47 +00:00
GasFeeSchedule = array [ GasFeeKind , GasInt ]
GasParams * = object
# Yellow Paper, Appendix H - https://ethereum.github.io/yellowpaper/paper.pdf
# GasCost is a function of (σ , μ):
# - σ is the full system state
# - μ is the machine state
# In practice, we often require the following from
# - σ : an account address
# - μ: a value popped from the stack or its size.
case kind * : Op
of Sstore :
2020-01-17 14:49:22 +00:00
when defined ( evmc_enabled ) :
s_status * : evmc_storage_status
2020-01-18 00:32:39 +00:00
s_currentValue * : Uint256
s_originalValue * : Uint256
2019-03-18 10:24:25 +00:00
of Call , CallCode , DelegateCall , StaticCall :
2018-06-12 15:33:47 +00:00
c_isNewAccount * : bool
c_gasBalance * : GasInt
2019-04-15 04:10:40 +00:00
c_contractGas * : Uint256
2019-10-26 01:24:43 +00:00
c_currentMemSize * : GasNatural
c_memOffset * : GasNatural
c_memLength * : GasNatural
2019-03-15 15:15:40 +00:00
of Create :
2019-10-26 01:24:43 +00:00
cr_currentMemSize * : GasNatural
cr_memOffset * : GasNatural
cr_memLength * : GasNatural
2019-04-07 04:29:09 +00:00
of SelfDestruct :
sd_condition * : bool
2018-06-12 15:33:47 +00:00
else :
discard
GasCostKind * = enum
GckInvalidOp ,
GckFixed ,
GckDynamic ,
GckMemExpansion ,
GckComplex
GasResult = tuple [ gasCost , gasRefund : GasInt ]
GasCost = object
case kind * : GasCostKind
of GckInvalidOp :
discard
of GckFixed :
cost * : GasInt
of GckDynamic :
2019-04-25 22:18:51 +00:00
d_handler * : proc ( value : Uint256 ) : GasInt {. nimcall , gcsafe . }
2018-06-12 15:33:47 +00:00
of GckMemExpansion :
2019-10-26 01:24:43 +00:00
m_handler * : proc ( currentMemSize , memOffset , memLength : GasNatural ) : GasInt {. nimcall , gcsafe . }
2018-06-12 15:33:47 +00:00
of GckComplex :
2019-04-25 22:18:51 +00:00
c_handler * : proc ( value : Uint256 , gasParams : GasParams ) : GasResult {. nimcall , gcsafe . }
2018-06-12 15:33:47 +00:00
# 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)
GasCosts * = array [ Op , GasCost ]
2020-12-11 10:51:17 +00:00
const
ColdSloadCost * = 2100
ColdAccountAccessCost * = 2600
WarmStorageReadCost * = 100
2018-11-28 19:02:21 +00:00
template gasCosts ( fork : Fork , prefix , ResultGasCostsName : untyped ) =
2018-06-12 15:33:47 +00:00
## Generate the gas cost for each forks and store them in a const
## named `ResultGasCostsName`
2018-11-28 19:02:21 +00:00
const FeeSchedule = gasFees [ fork ]
2018-06-12 15:33:47 +00:00
# ############### Helper functions ##############################
2019-10-26 01:24:43 +00:00
func ` prefix gasMemoryExpansion ` ( currentMemSize , memOffset , memLength : GasNatural ) : GasInt {. inline . } =
2018-06-12 15:33:47 +00:00
# Input: size (in bytes)
# Yellow Paper:
# Memory expansion cost
# = Cmem(μ′ i) − Cmem(μi)
# μi is memory size before opcode execution
# μ'i is the memory size after opcode execution
# Cmem(a) ≡ Gmemory · a + a² / 512
2018-07-23 21:00:49 +00:00
#
# Except when memLength = 0, where per eq (297),
# M(currentMemSize, f, l) = currentMemSize
2018-07-25 01:37:56 +00:00
let
2019-02-06 07:46:09 +00:00
prevWords : int64 = currentMemSize . wordCount
newWords : int64 = ( memOffset + memLength ) . wordCount
2018-07-25 01:37:56 +00:00
2019-02-06 07:46:09 +00:00
if memLength = = 0 or newWords < = prevWords :
2018-07-23 21:00:49 +00:00
# Special subcase of memory-expansion cost
# currentMemSize - currentMemSize = 0
# "Referencing a zero length range ... does not require memory to be extended
# to the beginning of the range."
2018-07-25 01:37:56 +00:00
#
# Also, don't credit EVM code for allocating memory
# then accessing lots of low memory. memoryGasCost,
# via go-ethereum, checks for this as special case.
2018-07-23 21:00:49 +00:00
return 0
2018-06-12 15:33:47 +00:00
let
2019-02-06 07:46:09 +00:00
prevCost = prevWords * static ( FeeSchedule [ GasMemory ] ) +
( prevWords ^ 2 ) shr 9 # div 512
newCost = newWords * static ( FeeSchedule [ GasMemory ] ) +
( newWords ^ 2 ) shr 9 # div 512
2018-06-12 15:33:47 +00:00
# TODO: add logging
2019-02-06 07:46:09 +00:00
result = max ( newCost - prevCost , 0 )
2018-06-12 15:33:47 +00:00
2019-11-13 14:49:39 +00:00
when fork > = FkTangerine :
func ` prefix all_but_one_64th ` ( gas : GasInt ) : GasInt {. inline . } =
## Computes all but 1/64th
## L(n) ≡ n − ⌊n/64⌋ - (floored(n/64))
# Introduced in EIP-150 - https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md
2018-06-12 15:33:47 +00:00
2019-11-13 14:49:39 +00:00
# Note: The all-but-one-64th calculation should occur after the memory expansion fee is taken
# https://github.com/ethereum/yellowpaper/pull/442
2018-06-12 15:33:47 +00:00
2019-11-13 14:49:39 +00:00
result = gas - ( gas shr 6 )
2018-06-12 15:33:47 +00:00
# ############### Opcode gas functions ##############################
func ` prefix gasExp ` ( value : Uint256 ) : GasInt {. nimcall . } =
## Value is the exponent
result = static FeeSchedule [ GasExp ]
if not value . isZero :
result + = static ( FeeSchedule [ GasExpByte ] ) * ( 1 + log256 ( value ) )
2019-03-15 15:15:40 +00:00
func ` prefix gasCreate ` ( value : Uint256 , gasParams : GasParams ) : GasResult {. nimcall . } =
if value . isZero :
result . gasCost = static ( FeeSchedule [ GasCodeDeposit ] ) * gasParams . cr_memLength
else :
result . gasCost = static ( FeeSchedule [ GasCreate ] ) +
` prefix gasMemoryExpansion ` (
gasParams . cr_currentMemSize ,
gasParams . cr_memOffset ,
gasParams . cr_memLength )
2018-09-14 16:59:21 +00:00
2019-10-26 01:24:43 +00:00
func ` prefix gasSha3 ` ( currentMemSize , memOffset , memLength : GasNatural ) : GasInt {. nimcall . } =
2018-06-12 15:33:47 +00:00
2018-06-13 17:33:47 +00:00
result = ` prefix gasMemoryExpansion ` ( currentMemSize , memOffset , memLength )
2018-06-12 15:33:47 +00:00
result + = static ( FeeSchedule [ GasSha3 ] ) +
2018-06-13 17:33:47 +00:00
static ( FeeSchedule [ GasSha3Word ] ) * ( memLength ) . wordCount
2018-06-12 15:33:47 +00:00
2019-10-26 01:24:43 +00:00
func ` prefix gasCopy ` ( currentMemSize , memOffset , memLength : GasNatural ) : GasInt {. nimcall . } =
2018-06-12 15:33:47 +00:00
result = static ( FeeSchedule [ GasVeryLow ] ) +
Refactor interpreter dispatch (#65)
* move forks constants, rename errors
* Move vm/utils to vm/interpreter/utils
* initial opcodes refactoring
* Add refactored Comparison & Bitwise Logic Operations
* Add sha3 and address, simplify macro, support pop 0
* balance, origin, caller, callValue
* fix gas copy opcodes gas costs, add callDataLoad/Size/Copy, CodeSize/Copy and gas price opcode
* Update with 30s, 40s, 50s opcodes + impl of balance + stack improvement
* add push, dup, swap, log, create and call operations
* finish opcode implementation
* Add the new dispatching logic
* Pass the opcode test
* Make test_vm_json compile
* halt execution without exceptions for Return, Revert, selfdestruct (fix #62)
* Properly catch and recover from EVM exceptions (stack underflow ...)
* Fix byte op
* Fix jump regressions
* Update for latest devel, don't import old dispatch code as quasiBoolean macro is broken by latest devel
* Fix sha3 regression on empty memory slice and until end of range slice
* Fix padding / range error on expXY_success (gas computation left)
* update logging procs
* Add tracing - expXY_success is not a regression, sload stub was accidentally passing the test
* Reuse the same stub as OO implementation
* Delete previous opcode implementation
* Delete object oriented fork code
* Delete exceptions that were used as control flows
* delete base.nim :fire:, yet another OO remnants
* Delete opcode table
* Enable omputed gotos and compile-time gas fees
* Revert const gasCosts -> generates SIGSEGV
* inline push, swap and dup opcodes
* loggers are now template again, why does this pass new tests?
* Trigger CI rebuild after rocksdb fix https://github.com/status-im/nim-rocksdb/pull/5
* Address review comment on "push" + VMTests in debug mode (not release)
* Address review comment: don't tag fork by default, make opcode impl grepable
* Static compilation fixes after rebasing
* fix the initialization of the VM database
* add a missing import
* Deactivate balance and sload test following #59
* Reactivate stack check (deactivated in #59, necessary to pass tests)
* Merge remaining opcodes implementation from #59
* Merge callDataLoad and codeCopy fixes, todo simplify see #67
2018-07-06 07:52:31 +00:00
static ( FeeSchedule [ GasCopy ] ) * memLength . wordCount
result + = ` prefix gasMemoryExpansion ` ( currentMemSize , memOffset , memLength )
2018-06-12 15:33:47 +00:00
2019-10-26 01:24:43 +00:00
func ` prefix gasExtCodeCopy ` ( currentMemSize , memOffset , memLength : GasNatural ) : GasInt {. nimcall . } =
2018-07-24 00:00:06 +00:00
result = static ( FeeSchedule [ GasExtCode ] ) +
static ( FeeSchedule [ GasCopy ] ) * memLength . wordCount
result + = ` prefix gasMemoryExpansion ` ( currentMemSize , memOffset , memLength )
2018-06-12 15:33:47 +00:00
2019-10-26 01:24:43 +00:00
func ` prefix gasLoadStore ` ( currentMemSize , memOffset , memLength : GasNatural ) : GasInt {. nimcall . } =
2018-06-12 15:33:47 +00:00
result = static ( FeeSchedule [ GasVeryLow ] )
2018-06-13 17:33:47 +00:00
result + = ` prefix gasMemoryExpansion ` ( currentMemSize , memOffset , memLength )
2018-06-12 15:33:47 +00:00
func ` prefix gasSstore ` ( value : Uint256 , gasParams : Gasparams ) : GasResult {. nimcall . } =
## Value is word to save
2020-12-11 10:51:17 +00:00
when fork > = FkBerlin :
# EIP2929
const
SLOAD_GAS = WarmStorageReadCost
SSTORE_RESET_GAS = 5000 - ColdSloadCost
else :
const
SLOAD_GAS = FeeSchedule [ GasSload ]
SSTORE_RESET_GAS = FeeSchedule [ GasSreset ]
2020-07-21 13:13:58 +00:00
const
2020-12-11 10:51:17 +00:00
NoopGas = SLOAD_GAS # if the value doesn't change.
DirtyGas = SLOAD_GAS # if a dirty value is changed.
2020-07-21 13:13:58 +00:00
InitGas = FeeSchedule [ GasSset ] # from clean zero to non-zero
2020-12-11 10:51:17 +00:00
InitRefund = FeeSchedule [ GasSset ] - SLOAD_GAS # resetting to the original zero value
CleanGas = SSTORE_RESET_GAS # from clean non-zero to something else
CleanRefund = SSTORE_RESET_GAS - SLOAD_GAS # resetting to the original non-zero value
2020-07-21 13:13:58 +00:00
ClearRefund = FeeSchedule [ RefundsClear ] # clearing an originally existing storage slot
2018-06-12 15:33:47 +00:00
2020-01-17 14:49:22 +00:00
when defined ( evmc_enabled ) :
2019-11-12 12:49:46 +00:00
const
2020-07-21 13:13:58 +00:00
sstoreDirty = when fork < FkConstantinople or fork = = FkPetersburg : CleanGas
else : DirtyGas
2020-01-17 14:49:22 +00:00
case gasParams . s_status
2020-07-21 13:13:58 +00:00
of EVMC_STORAGE_ADDED : result . gasCost = InitGas
of EVMC_STORAGE_MODIFIED : result . gasCost = CleanGas
2020-01-18 00:32:39 +00:00
of EVMC_STORAGE_DELETED :
2020-07-21 13:13:58 +00:00
result . gasCost = CleanGas
result . gasRefund + = ClearRefund
2020-01-18 00:32:39 +00:00
of EVMC_STORAGE_UNCHANGED : result . gasCost = sstoreDirty
of EVMC_STORAGE_MODIFIED_AGAIN :
result . gasCost = sstoreDirty
if not gasParams . s_originalValue . isZero :
if gasParams . s_currentValue . isZero :
2020-07-21 13:13:58 +00:00
result . gasRefund - = ClearRefund
2020-01-18 00:32:39 +00:00
if value . isZero :
2020-07-21 13:13:58 +00:00
result . gasRefund + = ClearRefund
2020-01-18 00:32:39 +00:00
if gasParams . s_originalValue = = value :
if gasParams . s_originalValue . isZero :
2020-07-21 13:13:58 +00:00
result . gasRefund + = InitRefund
2020-01-18 00:32:39 +00:00
else :
2020-07-21 13:13:58 +00:00
result . gasRefund + = CleanRefund
2019-11-12 12:49:46 +00:00
else :
2020-03-04 09:32:30 +00:00
when fork < FkConstantinople or fork = = FkPetersburg :
2020-07-21 13:13:58 +00:00
let isStorageEmpty = gasParams . s_currentValue . isZero
2020-01-17 14:49:22 +00:00
# Gas cost - literal translation of Yellow Paper
2020-07-21 13:13:58 +00:00
result . gasCost = if value . isZero . not and isStorageEmpty :
InitGas
2020-01-17 14:49:22 +00:00
else :
2020-07-21 13:13:58 +00:00
CleanGas
2020-01-17 14:49:22 +00:00
# Refund
2020-07-21 13:13:58 +00:00
if value . isZero and not isStorageEmpty :
result . gasRefund = ClearRefund
2020-01-17 14:49:22 +00:00
else :
# 0. If *gasleft* is less than or equal to 2300, fail the current call.
# 1. If current value equals new value (this is a no-op), SSTORE_NOOP_GAS gas is deducted.
# 2. If current value does not equal new value:
# 2.1. If original value equals current value (this storage slot has not been changed by the current execution context):
# 2.1.1. If original value is 0, SSTORE_INIT_GAS gas is deducted.
# 2.1.2. Otherwise, SSTORE_CLEAN_GAS gas is deducted. If new value is 0, add SSTORE_CLEAR_REFUND to refund counter.
# 2.2. If original value does not equal current value (this storage slot is dirty), SSTORE_DIRTY_GAS gas is deducted. Apply both of the following clauses:
# 2.2.1. If original value is not 0:
# 2.2.1.1. If current value is 0 (also means that new value is not 0), subtract SSTORE_CLEAR_REFUND gas from refund counter. We can prove that refund counter will never go below 0.
# 2.2.1.2. If new value is 0 (also means that current value is not 0), add SSTORE_CLEAR_REFUND gas to refund counter.
# 2.2.2. If original value equals new value (this storage slot is reset):
# 2.2.2.1. If original value is 0, add SSTORE_INIT_REFUND 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
if gasParams . s_currentValue = = value : # noop (1)
2020-07-21 13:13:58 +00:00
result . gasCost = NoopGas
2019-11-12 13:24:52 +00:00
return
2020-01-17 14:49:22 +00:00
if gasParams . s_originalValue = = gasParams . s_currentValue :
if gasParams . s_originalValue . isZero : # create slot (2.1.1)
2020-07-21 13:13:58 +00:00
result . gasCost = InitGas
2020-01-17 14:49:22 +00:00
return
if value . isZero : # delete slot (2.1.2b)
2020-07-21 13:13:58 +00:00
result . gasRefund = ClearRefund
2019-11-12 13:24:52 +00:00
2020-07-21 13:13:58 +00:00
result . gasCost = CleanGas # write existing slot (2.1.2)
2020-01-17 14:49:22 +00:00
return
2019-11-12 13:24:52 +00:00
2020-01-17 14:49:22 +00:00
if not gasParams . s_originalValue . isZero :
if gasParams . s_currentValue . isZero : # recreate slot (2.2.1.1)
2020-07-21 13:13:58 +00:00
result . gasRefund - = ClearRefund
2020-01-17 14:49:22 +00:00
if value . isZero : # delete slot (2.2.1.2)
2020-07-21 13:13:58 +00:00
result . gasRefund + = ClearRefund
2019-11-12 13:24:52 +00:00
2020-01-17 14:49:22 +00:00
if gasParams . s_originalValue = = value :
if gasParams . s_originalValue . isZero : # reset to original inexistent slot (2.2.2.1)
2020-07-21 13:13:58 +00:00
result . gasRefund + = InitRefund
2020-01-17 14:49:22 +00:00
else : # reset to original existing slot (2.2.2.2)
2020-07-21 13:13:58 +00:00
result . gasRefund + = CleanRefund
2019-11-12 13:24:52 +00:00
2020-07-21 13:13:58 +00:00
result . gasCost = DirtyGas # dirty update (2.2)
2018-06-12 15:33:47 +00:00
2019-10-26 01:24:43 +00:00
func ` prefix gasLog0 ` ( currentMemSize , memOffset , memLength : GasNatural ) : GasInt {. nimcall . } =
2018-06-13 17:33:47 +00:00
result = ` prefix gasMemoryExpansion ` ( currentMemSize , memOffset , memLength )
2018-06-12 15:33:47 +00:00
result + = static ( FeeSchedule [ GasLog ] ) +
2018-06-13 17:33:47 +00:00
static ( FeeSchedule [ GasLogData ] ) * memLength
2018-06-12 15:33:47 +00:00
2019-10-26 01:24:43 +00:00
func ` prefix gasLog1 ` ( currentMemSize , memOffset , memLength : GasNatural ) : GasInt {. nimcall . } =
2018-06-13 17:33:47 +00:00
result = ` prefix gasMemoryExpansion ` ( currentMemSize , memOffset , memLength )
2018-06-12 15:33:47 +00:00
result + = static ( FeeSchedule [ GasLog ] ) +
2018-06-13 17:33:47 +00:00
static ( FeeSchedule [ GasLogData ] ) * memLength +
2018-06-12 15:33:47 +00:00
static ( FeeSchedule [ GasLogTopic ] )
2019-10-26 01:24:43 +00:00
func ` prefix gasLog2 ` ( currentMemSize , memOffset , memLength : GasNatural ) : GasInt {. nimcall . } =
2018-06-13 17:33:47 +00:00
result = ` prefix gasMemoryExpansion ` ( currentMemSize , memOffset , memLength )
2018-06-12 15:33:47 +00:00
result + = static ( FeeSchedule [ GasLog ] ) +
2018-06-13 17:33:47 +00:00
static ( FeeSchedule [ GasLogData ] ) * memLength +
2018-06-12 15:33:47 +00:00
static ( 2 * FeeSchedule [ GasLogTopic ] )
2019-10-26 01:24:43 +00:00
func ` prefix gasLog3 ` ( currentMemSize , memOffset , memLength : GasNatural ) : GasInt {. nimcall . } =
2018-06-13 17:33:47 +00:00
result = ` prefix gasMemoryExpansion ` ( currentMemSize , memOffset , memLength )
2018-06-12 15:33:47 +00:00
2018-08-02 22:57:28 +00:00
result + = static ( FeeSchedule [ GasLog ] ) +
2018-06-13 17:33:47 +00:00
static ( FeeSchedule [ GasLogData ] ) * memLength +
2018-06-12 15:33:47 +00:00
static ( 3 * FeeSchedule [ GasLogTopic ] )
2019-10-26 01:24:43 +00:00
func ` prefix gasLog4 ` ( currentMemSize , memOffset , memLength : GasNatural ) : GasInt {. nimcall . } =
2018-06-13 17:33:47 +00:00
result = ` prefix gasMemoryExpansion ` ( currentMemSize , memOffset , memLength )
2018-06-12 15:33:47 +00:00
2018-08-02 22:57:28 +00:00
result + = static ( FeeSchedule [ GasLog ] ) +
2018-06-13 17:33:47 +00:00
static ( FeeSchedule [ GasLogData ] ) * memLength +
2018-06-12 15:33:47 +00:00
static ( 4 * FeeSchedule [ GasLogTopic ] )
func ` prefix gasCall ` ( value : Uint256 , gasParams : Gasparams ) : GasResult {. nimcall . } =
# From the Yellow Paper, going through the equation from bottom to top
# https://ethereum.github.io/yellowpaper/paper.pdf#appendix.H
#
# More readable info on the subtleties wiki page: https://github.com/ethereum/wiki/wiki/Subtleties#other-operations
# CALL has a multi-part gas cost:
#
# - 700 base
# - 9000 additional if the value is nonzero
# - 25000 additional if the destination account does not yet exist
#
# The child message of a nonzero-value CALL operation (NOT the top-level message arising from a transaction!)
# gains an additional 2300 gas on top of the gas supplied by the calling account;
# this stipend can be considered to be paid out of the 9000 mandatory additional fee for nonzero-value calls.
# This ensures that a call recipient will always have enough gas to log that it received funds.
#
# EIP150 goes over computation: https://github.com/ethereum/eips/issues/150
#
# 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
# 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.
result . gasCost = ` prefix gasMemoryExpansion ` (
2018-06-13 17:33:47 +00:00
gasParams . c_currentMemSize ,
gasParams . c_memOffset ,
gasParams . c_memLength
2018-06-12 15:33:47 +00:00
)
2018-11-28 19:02:21 +00:00
# Cnew_account
2019-03-18 10:24:25 +00:00
if gasParams . c_isNewAccount and gasParams . kind = = Call :
2019-04-07 03:58:43 +00:00
when fork < FkSpurious :
2018-11-28 19:02:21 +00:00
# Pre-EIP161 all account creation calls consumed 25000 gas.
result . 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 :
result . gasCost + = static ( FeeSchedule [ GasNewAccount ] )
2018-06-12 15:33:47 +00:00
# Cxfer
2019-03-18 10:24:25 +00:00
if not value . isZero and gasParams . kind in { Call , CallCode } :
2018-06-12 15:33:47 +00:00
result . gasCost + = static ( FeeSchedule [ GasCallValue ] )
# Cextra
result . gasCost + = static ( FeeSchedule [ GasCall ] )
# Cgascap
2019-04-07 03:58:43 +00:00
when fork > = FkTangerine :
2018-11-28 19:02:21 +00:00
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md
2019-04-15 04:10:40 +00:00
let gas = ` prefix all_but_one_64th ` ( gasParams . c_gasBalance - result . gasCost )
if gasParams . c_contractGas > high ( GasInt ) . u256 or
gas < gasParams . c_contractGas . truncate ( GasInt ) :
result . gasRefund = gas
else :
result . gasRefund = gasParams . c_contractGas . truncate ( GasInt )
2019-02-06 07:46:09 +00:00
else :
2019-04-15 04:10:40 +00:00
if gasParams . c_contractGas > high ( GasInt ) . u256 :
raise newException ( TypeError , " GasInt Overflow ( " & $ gasParams . kind & " ) " & $ gasParams . c_contractGas )
result . gasRefund = gasParams . c_contractGas . truncate ( GasInt )
2019-02-15 03:26:27 +00:00
result . gasCost + = result . gasRefund
2018-06-12 15:33:47 +00:00
# Ccallgas - Gas sent to the child message
2019-03-18 10:24:25 +00:00
if not value . isZero and gasParams . kind in { Call , CallCode } :
2018-06-12 15:33:47 +00:00
result . gasRefund + = static ( FeeSchedule [ GasCallStipend ] )
2019-10-26 01:24:43 +00:00
func ` prefix gasHalt ` ( currentMemSize , memOffset , memLength : GasNatural ) : GasInt {. nimcall . } =
2018-06-13 17:33:47 +00:00
` prefix gasMemoryExpansion ` ( currentMemSize , memOffset , memLength )
2018-06-12 15:33:47 +00:00
func ` prefix gasSelfDestruct ` ( value : Uint256 , gasParams : Gasparams ) : GasResult {. nimcall . } =
2019-04-07 04:29:09 +00:00
result . gasCost + = static ( FeeSchedule [ GasSelfDestruct ] )
when fork > = FkTangerine :
if gasParams . sd_condition :
result . gasCost + = static ( FeeSchedule [ GasNewAccount ] )
2018-06-12 15:33:47 +00:00
2019-10-26 01:24:43 +00:00
func ` prefix gasCreate2 ` ( currentMemSize , memOffset , memLength : GasNatural ) : GasInt {. nimcall . } =
2019-05-08 11:41:25 +00:00
result = static ( FeeSchedule [ GasSha3Word ] ) * ( memLength ) . wordCount
2019-05-07 03:23:27 +00:00
2018-06-12 15:33:47 +00:00
# ###################################################################################################
# TODO - change this `let` into `const` - pending: https://github.com/nim-lang/Nim/issues/8015
2019-10-16 13:00:23 +00:00
let ` ResultGasCostsName ` * {. inject , compileTime . } : GasCosts = block :
2018-06-12 15:33:47 +00:00
# We use a block expression to avoid name redefinition conflicts
# with "fixed" and "dynamic"
# Syntactic sugar
func fixed ( gasFeeKind : static [ GasFeeKind ] ) : GasCost =
GasCost ( kind : GckFixed , cost : static ( FeeSchedule [ gasFeeKind ] ) )
2019-04-25 22:18:51 +00:00
func dynamic ( handler : proc ( value : Uint256 ) : GasInt {. nimcall , gcsafe . } ) : GasCost =
2018-06-12 15:33:47 +00:00
GasCost ( kind : GckDynamic , d_handler : handler )
2019-10-26 01:24:43 +00:00
func memExpansion ( handler : proc ( currentMemSize , memOffset , memLength : GasNatural ) : GasInt {. nimcall , gcsafe . } ) : GasCost =
2018-06-12 15:33:47 +00:00
GasCost ( kind : GckMemExpansion , m_handler : handler )
2019-04-25 22:18:51 +00:00
func complex ( handler : proc ( value : Uint256 , gasParams : GasParams ) : GasResult {. nimcall , gcsafe . } ) : GasCost =
2018-06-12 15:33:47 +00:00
GasCost ( kind : GckComplex , c_handler : handler )
# Returned value
fill_enum_table_holes ( Op , GasCost ( kind : GckInvalidOp ) ) :
[
# 0s: Stop and Arithmetic Operations
Stop : fixed GasZero ,
Add : fixed GasVeryLow ,
Mul : fixed GasLow ,
Sub : fixed GasVeryLow ,
Div : fixed GasLow ,
Sdiv : fixed GasLow ,
Mod : fixed GasLow ,
Smod : fixed GasLow ,
Addmod : fixed GasMid ,
Mulmod : fixed GasMid ,
Exp : dynamic ` prefix gasExp ` ,
SignExtend : fixed GasLow ,
# 10s: Comparison & Bitwise Logic Operations
Lt : fixed GasVeryLow ,
Gt : fixed GasVeryLow ,
Slt : fixed GasVeryLow ,
Sgt : fixed GasVeryLow ,
Eq : fixed GasVeryLow ,
IsZero : fixed GasVeryLow ,
And : fixed GasVeryLow ,
Or : fixed GasVeryLow ,
Xor : fixed GasVeryLow ,
Not : fixed GasVeryLow ,
Byte : fixed GasVeryLow ,
2019-05-07 04:13:09 +00:00
Shl : fixed GasVeryLow ,
Shr : fixed GasVeryLow ,
2019-04-30 05:23:51 +00:00
Sar : fixed GasVeryLow ,
2018-06-12 15:33:47 +00:00
# 20s: SHA3
Sha3 : memExpansion ` prefix gasSha3 ` ,
# 30s: Environmental Information
Address : fixed GasBase ,
Balance : fixed GasBalance ,
Origin : fixed GasBase ,
Caller : fixed GasBase ,
CallValue : fixed GasBase ,
CallDataLoad : fixed GasVeryLow ,
CallDataSize : fixed GasBase ,
Refactor interpreter dispatch (#65)
* move forks constants, rename errors
* Move vm/utils to vm/interpreter/utils
* initial opcodes refactoring
* Add refactored Comparison & Bitwise Logic Operations
* Add sha3 and address, simplify macro, support pop 0
* balance, origin, caller, callValue
* fix gas copy opcodes gas costs, add callDataLoad/Size/Copy, CodeSize/Copy and gas price opcode
* Update with 30s, 40s, 50s opcodes + impl of balance + stack improvement
* add push, dup, swap, log, create and call operations
* finish opcode implementation
* Add the new dispatching logic
* Pass the opcode test
* Make test_vm_json compile
* halt execution without exceptions for Return, Revert, selfdestruct (fix #62)
* Properly catch and recover from EVM exceptions (stack underflow ...)
* Fix byte op
* Fix jump regressions
* Update for latest devel, don't import old dispatch code as quasiBoolean macro is broken by latest devel
* Fix sha3 regression on empty memory slice and until end of range slice
* Fix padding / range error on expXY_success (gas computation left)
* update logging procs
* Add tracing - expXY_success is not a regression, sload stub was accidentally passing the test
* Reuse the same stub as OO implementation
* Delete previous opcode implementation
* Delete object oriented fork code
* Delete exceptions that were used as control flows
* delete base.nim :fire:, yet another OO remnants
* Delete opcode table
* Enable omputed gotos and compile-time gas fees
* Revert const gasCosts -> generates SIGSEGV
* inline push, swap and dup opcodes
* loggers are now template again, why does this pass new tests?
* Trigger CI rebuild after rocksdb fix https://github.com/status-im/nim-rocksdb/pull/5
* Address review comment on "push" + VMTests in debug mode (not release)
* Address review comment: don't tag fork by default, make opcode impl grepable
* Static compilation fixes after rebasing
* fix the initialization of the VM database
* add a missing import
* Deactivate balance and sload test following #59
* Reactivate stack check (deactivated in #59, necessary to pass tests)
* Merge remaining opcodes implementation from #59
* Merge callDataLoad and codeCopy fixes, todo simplify see #67
2018-07-06 07:52:31 +00:00
CallDataCopy : memExpansion ` prefix gasCopy ` ,
2018-06-12 15:33:47 +00:00
CodeSize : fixed GasBase ,
Refactor interpreter dispatch (#65)
* move forks constants, rename errors
* Move vm/utils to vm/interpreter/utils
* initial opcodes refactoring
* Add refactored Comparison & Bitwise Logic Operations
* Add sha3 and address, simplify macro, support pop 0
* balance, origin, caller, callValue
* fix gas copy opcodes gas costs, add callDataLoad/Size/Copy, CodeSize/Copy and gas price opcode
* Update with 30s, 40s, 50s opcodes + impl of balance + stack improvement
* add push, dup, swap, log, create and call operations
* finish opcode implementation
* Add the new dispatching logic
* Pass the opcode test
* Make test_vm_json compile
* halt execution without exceptions for Return, Revert, selfdestruct (fix #62)
* Properly catch and recover from EVM exceptions (stack underflow ...)
* Fix byte op
* Fix jump regressions
* Update for latest devel, don't import old dispatch code as quasiBoolean macro is broken by latest devel
* Fix sha3 regression on empty memory slice and until end of range slice
* Fix padding / range error on expXY_success (gas computation left)
* update logging procs
* Add tracing - expXY_success is not a regression, sload stub was accidentally passing the test
* Reuse the same stub as OO implementation
* Delete previous opcode implementation
* Delete object oriented fork code
* Delete exceptions that were used as control flows
* delete base.nim :fire:, yet another OO remnants
* Delete opcode table
* Enable omputed gotos and compile-time gas fees
* Revert const gasCosts -> generates SIGSEGV
* inline push, swap and dup opcodes
* loggers are now template again, why does this pass new tests?
* Trigger CI rebuild after rocksdb fix https://github.com/status-im/nim-rocksdb/pull/5
* Address review comment on "push" + VMTests in debug mode (not release)
* Address review comment: don't tag fork by default, make opcode impl grepable
* Static compilation fixes after rebasing
* fix the initialization of the VM database
* add a missing import
* Deactivate balance and sload test following #59
* Reactivate stack check (deactivated in #59, necessary to pass tests)
* Merge remaining opcodes implementation from #59
* Merge callDataLoad and codeCopy fixes, todo simplify see #67
2018-07-06 07:52:31 +00:00
CodeCopy : memExpansion ` prefix gasCopy ` ,
2018-06-12 15:33:47 +00:00
GasPrice : fixed GasBase ,
ExtCodeSize : fixed GasExtcode ,
2018-07-24 00:00:06 +00:00
ExtCodeCopy : memExpansion ` prefix gasExtCodeCopy ` ,
2018-06-12 15:33:47 +00:00
ReturnDataSize : fixed GasBase ,
Refactor interpreter dispatch (#65)
* move forks constants, rename errors
* Move vm/utils to vm/interpreter/utils
* initial opcodes refactoring
* Add refactored Comparison & Bitwise Logic Operations
* Add sha3 and address, simplify macro, support pop 0
* balance, origin, caller, callValue
* fix gas copy opcodes gas costs, add callDataLoad/Size/Copy, CodeSize/Copy and gas price opcode
* Update with 30s, 40s, 50s opcodes + impl of balance + stack improvement
* add push, dup, swap, log, create and call operations
* finish opcode implementation
* Add the new dispatching logic
* Pass the opcode test
* Make test_vm_json compile
* halt execution without exceptions for Return, Revert, selfdestruct (fix #62)
* Properly catch and recover from EVM exceptions (stack underflow ...)
* Fix byte op
* Fix jump regressions
* Update for latest devel, don't import old dispatch code as quasiBoolean macro is broken by latest devel
* Fix sha3 regression on empty memory slice and until end of range slice
* Fix padding / range error on expXY_success (gas computation left)
* update logging procs
* Add tracing - expXY_success is not a regression, sload stub was accidentally passing the test
* Reuse the same stub as OO implementation
* Delete previous opcode implementation
* Delete object oriented fork code
* Delete exceptions that were used as control flows
* delete base.nim :fire:, yet another OO remnants
* Delete opcode table
* Enable omputed gotos and compile-time gas fees
* Revert const gasCosts -> generates SIGSEGV
* inline push, swap and dup opcodes
* loggers are now template again, why does this pass new tests?
* Trigger CI rebuild after rocksdb fix https://github.com/status-im/nim-rocksdb/pull/5
* Address review comment on "push" + VMTests in debug mode (not release)
* Address review comment: don't tag fork by default, make opcode impl grepable
* Static compilation fixes after rebasing
* fix the initialization of the VM database
* add a missing import
* Deactivate balance and sload test following #59
* Reactivate stack check (deactivated in #59, necessary to pass tests)
* Merge remaining opcodes implementation from #59
* Merge callDataLoad and codeCopy fixes, todo simplify see #67
2018-07-06 07:52:31 +00:00
ReturnDataCopy : memExpansion ` prefix gasCopy ` ,
2019-04-30 05:23:51 +00:00
ExtCodeHash : fixed GasExtCodeHash ,
2018-06-12 15:33:47 +00:00
# 40s: Block Information
Blockhash : fixed GasBlockhash ,
Coinbase : fixed GasBase ,
Timestamp : fixed GasBase ,
Number : fixed GasBase ,
Difficulty : fixed GasBase ,
GasLimit : fixed GasBase ,
2021-05-15 06:37:40 +00:00
ChainIdOp : fixed GasBase ,
2019-11-12 12:21:33 +00:00
SelfBalance : fixed GasLow ,
2018-06-12 15:33:47 +00:00
# 50s: Stack, Memory, Storage and Flow Operations
Pop : fixed GasBase ,
Mload : memExpansion ` prefix gasLoadStore ` ,
Mstore : memExpansion ` prefix gasLoadStore ` ,
Mstore8 : memExpansion ` prefix gasLoadStore ` ,
Sload : fixed GasSload ,
Sstore : complex ` prefix gasSstore ` ,
Jump : fixed GasMid ,
JumpI : fixed GasHigh ,
Pc : fixed GasBase ,
Msize : fixed GasBase ,
Gas : fixed GasBase ,
JumpDest : fixed GasJumpDest ,
2020-11-25 09:43:34 +00:00
BeginSub : fixed GasBase ,
ReturnSub : fixed GasLow ,
JumpSub : fixed GasHigh ,
2018-06-12 15:33:47 +00:00
# 60s & 70s: Push Operations
Push1 : fixed GasVeryLow ,
Push2 : fixed GasVeryLow ,
Push3 : fixed GasVeryLow ,
Push4 : fixed GasVeryLow ,
Push5 : fixed GasVeryLow ,
Push6 : fixed GasVeryLow ,
Push7 : fixed GasVeryLow ,
Push8 : fixed GasVeryLow ,
Push9 : fixed GasVeryLow ,
Push10 : fixed GasVeryLow ,
Push11 : fixed GasVeryLow ,
Push12 : fixed GasVeryLow ,
Push13 : fixed GasVeryLow ,
Push14 : fixed GasVeryLow ,
Push15 : fixed GasVeryLow ,
Push16 : fixed GasVeryLow ,
Push17 : fixed GasVeryLow ,
Push18 : fixed GasVeryLow ,
Push19 : fixed GasVeryLow ,
Push20 : fixed GasVeryLow ,
Push21 : fixed GasVeryLow ,
Push22 : fixed GasVeryLow ,
Push23 : fixed GasVeryLow ,
Push24 : fixed GasVeryLow ,
Push25 : fixed GasVeryLow ,
Push26 : fixed GasVeryLow ,
Push27 : fixed GasVeryLow ,
Push28 : fixed GasVeryLow ,
Push29 : fixed GasVeryLow ,
Push30 : fixed GasVeryLow ,
Push31 : fixed GasVeryLow ,
Push32 : fixed GasVeryLow ,
# 80s: Duplication Operations
Dup1 : fixed GasVeryLow ,
Dup2 : fixed GasVeryLow ,
Dup3 : fixed GasVeryLow ,
Dup4 : fixed GasVeryLow ,
Dup5 : fixed GasVeryLow ,
Dup6 : fixed GasVeryLow ,
Dup7 : fixed GasVeryLow ,
Dup8 : fixed GasVeryLow ,
Dup9 : fixed GasVeryLow ,
Dup10 : fixed GasVeryLow ,
Dup11 : fixed GasVeryLow ,
Dup12 : fixed GasVeryLow ,
Dup13 : fixed GasVeryLow ,
Dup14 : fixed GasVeryLow ,
Dup15 : fixed GasVeryLow ,
Dup16 : fixed GasVeryLow ,
# 90s: Exchange Operations
Swap1 : fixed GasVeryLow ,
Swap2 : fixed GasVeryLow ,
Swap3 : fixed GasVeryLow ,
Swap4 : fixed GasVeryLow ,
Swap5 : fixed GasVeryLow ,
Swap6 : fixed GasVeryLow ,
Swap7 : fixed GasVeryLow ,
Swap8 : fixed GasVeryLow ,
Swap9 : fixed GasVeryLow ,
Swap10 : fixed GasVeryLow ,
Swap11 : fixed GasVeryLow ,
Swap12 : fixed GasVeryLow ,
Swap13 : fixed GasVeryLow ,
Swap14 : fixed GasVeryLow ,
Swap15 : fixed GasVeryLow ,
Swap16 : fixed GasVeryLow ,
# a0s: Logging Operations
Log0 : memExpansion ` prefix gasLog0 ` ,
Log1 : memExpansion ` prefix gasLog1 ` ,
Log2 : memExpansion ` prefix gasLog2 ` ,
Log3 : memExpansion ` prefix gasLog3 ` ,
Log4 : memExpansion ` prefix gasLog4 ` ,
# f0s: System operations
2019-03-15 15:15:40 +00:00
Create : complex ` prefix gasCreate ` ,
2018-06-12 15:33:47 +00:00
Call : complex ` prefix gasCall ` ,
CallCode : complex ` prefix gasCall ` ,
Return : memExpansion ` prefix gasHalt ` ,
DelegateCall : complex ` prefix gasCall ` ,
2019-05-07 03:23:27 +00:00
Create2 : memExpansion ` prefix gasCreate2 ` ,
2018-06-12 15:33:47 +00:00
StaticCall : complex ` prefix gasCall ` ,
2019-04-07 05:34:43 +00:00
Revert : memExpansion ` prefix gasHalt ` ,
2018-06-12 15:33:47 +00:00
Invalid : fixed GasZero ,
SelfDestruct : complex ` prefix gasSelfDestruct `
]
# Generate the fork-specific gas costs tables
const
BaseGasFees : GasFeeSchedule = [
2018-09-07 19:44:17 +00:00
# Fee Schedule for the initial Ethereum forks
2018-06-12 15:33:47 +00:00
GasZero : 0 'i64 ,
GasBase : 2 ,
GasVeryLow : 3 ,
GasLow : 5 ,
GasMid : 8 ,
GasHigh : 10 ,
GasExtCode : 20 , # Changed to 700 in Tangerine (EIP150)
GasBalance : 20 , # Changed to 400 in Tangerine (EIP150)
GasSload : 50 , # Changed to 200 in Tangerine (EIP150)
GasJumpDest : 1 ,
GasSset : 20_000 ,
GasSreset : 5_000 ,
RefundSclear : 15_000 ,
RefundSelfDestruct : 24_000 ,
GasSelfDestruct : 0 , # Changed to 5000 in Tangerine (EIP150)
GasCreate : 32000 ,
GasCodeDeposit : 200 ,
GasCall : 40 , # Changed to 700 in Tangerine (EIP150)
GasCallValue : 9000 ,
GasCallStipend : 2300 ,
GasNewAccount : 25_000 ,
GasExp : 10 ,
GasExpByte : 10 , # Changed to 50 in Spurious Dragon (EIP160)
GasMemory : 3 ,
2018-09-18 15:28:40 +00:00
GasTXCreate : 0 , # Changed to 32000 in Homestead (EIP2)
2018-06-12 15:33:47 +00:00
GasTXDataZero : 4 ,
GasTXDataNonZero : 68 ,
GasTransaction : 21000 ,
GasLog : 375 ,
GasLogData : 8 ,
GasLogTopic : 375 ,
GasSha3 : 30 ,
GasSha3Word : 6 ,
GasCopy : 3 ,
2019-04-30 05:23:51 +00:00
GasBlockhash : 20 ,
GasExtCodeHash : 400
2018-06-12 15:33:47 +00:00
]
# Create the schedule for each forks
2019-11-14 15:27:24 +00:00
func homesteadGasFees ( previousFees : GasFeeSchedule ) : GasFeeSchedule =
2018-09-18 15:28:40 +00:00
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.md
2019-11-14 15:27:24 +00:00
result = previousFees
2018-09-18 15:28:40 +00:00
result [ GasTXCreate ] = 32000
2019-11-14 15:27:24 +00:00
func tangerineGasFees ( previousFees : GasFeeSchedule ) : GasFeeSchedule =
2018-05-24 10:01:59 +00:00
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md
2019-11-14 15:27:24 +00:00
result = previousFees
2019-04-07 03:58:43 +00:00
result [ GasExtCode ] = 700
2018-05-25 10:25:19 +00:00
result [ GasSload ] = 200
result [ GasSelfDestruct ] = 5000
result [ GasBalance ] = 400
2019-04-07 03:58:43 +00:00
result [ GasCall ] = 700
2018-05-24 10:01:59 +00:00
2019-11-14 15:27:24 +00:00
func spuriousGasFees ( previousFees : GasFeeSchedule ) : GasFeeSchedule =
2018-06-12 15:33:47 +00:00
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-160.md
2019-11-14 15:27:24 +00:00
result = previousFees
2018-06-12 15:33:47 +00:00
result [ GasExpByte ] = 50
2019-11-14 15:27:24 +00:00
func istanbulGasFees ( previousFees : GasFeeSchedule ) : GasFeeSchedule =
2019-11-11 05:12:58 +00:00
# https://eips.ethereum.org/EIPS/eip-1884
2019-11-14 15:27:24 +00:00
result = previousFees
2019-11-11 05:12:58 +00:00
result [ GasSload ] = 800
result [ GasExtCodeHash ] = 700
result [ GasBalance ] = 700
2019-11-11 05:20:46 +00:00
result [ GasTXDataNonZero ] = 16
2019-11-12 12:49:46 +00:00
2021-01-13 11:17:38 +00:00
func berlinGasFees ( previousFees : GasFeeSchedule ) : GasFeeSchedule =
# https://eips.ethereum.org/EIPS/eip-2929
result = previousFees
2021-01-14 10:20:42 +00:00
# SLOAD gasCost become fully dynamic, see sloadEIP2929
result [ GasSLoad ] = 0
2021-01-13 11:17:38 +00:00
result [ GasCall ] = WarmStorageReadCost
2018-06-12 15:33:47 +00:00
const
2018-09-18 15:28:40 +00:00
HomesteadGasFees = BaseGasFees . homesteadGasFees
TangerineGasFees = HomesteadGasFees . tangerineGasFees
2018-06-12 15:33:47 +00:00
SpuriousGasFees = TangerineGasFees . spuriousGasFees
2019-11-11 05:12:58 +00:00
IstanbulGasFees = SpuriousGasFees . istanbulGasFees
2021-01-13 11:17:38 +00:00
BerlinGasFees = IstanbulGasFees . berlinGasFees
2018-06-12 15:33:47 +00:00
2018-11-28 19:02:21 +00:00
gasFees * : array [ Fork , GasFeeSchedule ] = [
FkFrontier : BaseGasFees ,
FkHomestead : HomesteadGasFees ,
FkTangerine : TangerineGasFees ,
FkSpurious : SpuriousGasFees ,
2019-04-30 05:23:51 +00:00
FkByzantium : SpuriousGasFees ,
2019-11-11 04:20:16 +00:00
FkConstantinople : SpuriousGasFees ,
2020-03-04 09:32:30 +00:00
FkPetersburg : SpuriousGasFees ,
2020-11-19 04:59:53 +00:00
FkIstanbul : IstanbulGasFees ,
2021-01-13 11:17:38 +00:00
FkBerlin : BerlinGasFees
2018-11-28 19:02:21 +00:00
]
gasCosts ( FkFrontier , base , BaseGasCosts )
gasCosts ( FkHomestead , homestead , HomesteadGasCosts )
gasCosts ( FkTangerine , tangerine , TangerineGasCosts )
2019-04-17 02:46:33 +00:00
gasCosts ( FkSpurious , spurious , SpuriousGasCosts )
2020-03-04 09:32:30 +00:00
gasCosts ( FkConstantinople , constantinople , ConstantinopleGasCosts )
2019-11-14 15:27:24 +00:00
gasCosts ( FkIstanbul , istanbul , IstanbulGasCosts )
2020-12-11 10:51:17 +00:00
gasCosts ( FkBerlin , berlin , BerlinGasCosts )
Refactor interpreter dispatch (#65)
* move forks constants, rename errors
* Move vm/utils to vm/interpreter/utils
* initial opcodes refactoring
* Add refactored Comparison & Bitwise Logic Operations
* Add sha3 and address, simplify macro, support pop 0
* balance, origin, caller, callValue
* fix gas copy opcodes gas costs, add callDataLoad/Size/Copy, CodeSize/Copy and gas price opcode
* Update with 30s, 40s, 50s opcodes + impl of balance + stack improvement
* add push, dup, swap, log, create and call operations
* finish opcode implementation
* Add the new dispatching logic
* Pass the opcode test
* Make test_vm_json compile
* halt execution without exceptions for Return, Revert, selfdestruct (fix #62)
* Properly catch and recover from EVM exceptions (stack underflow ...)
* Fix byte op
* Fix jump regressions
* Update for latest devel, don't import old dispatch code as quasiBoolean macro is broken by latest devel
* Fix sha3 regression on empty memory slice and until end of range slice
* Fix padding / range error on expXY_success (gas computation left)
* update logging procs
* Add tracing - expXY_success is not a regression, sload stub was accidentally passing the test
* Reuse the same stub as OO implementation
* Delete previous opcode implementation
* Delete object oriented fork code
* Delete exceptions that were used as control flows
* delete base.nim :fire:, yet another OO remnants
* Delete opcode table
* Enable omputed gotos and compile-time gas fees
* Revert const gasCosts -> generates SIGSEGV
* inline push, swap and dup opcodes
* loggers are now template again, why does this pass new tests?
* Trigger CI rebuild after rocksdb fix https://github.com/status-im/nim-rocksdb/pull/5
* Address review comment on "push" + VMTests in debug mode (not release)
* Address review comment: don't tag fork by default, make opcode impl grepable
* Static compilation fixes after rebasing
* fix the initialization of the VM database
* add a missing import
* Deactivate balance and sload test following #59
* Reactivate stack check (deactivated in #59, necessary to pass tests)
* Merge remaining opcodes implementation from #59
* Merge callDataLoad and codeCopy fixes, todo simplify see #67
2018-07-06 07:52:31 +00:00
proc forkToSchedule * ( fork : Fork ) : GasCosts =
2018-09-18 15:28:40 +00:00
if fork < FkHomestead :
Refactor interpreter dispatch (#65)
* move forks constants, rename errors
* Move vm/utils to vm/interpreter/utils
* initial opcodes refactoring
* Add refactored Comparison & Bitwise Logic Operations
* Add sha3 and address, simplify macro, support pop 0
* balance, origin, caller, callValue
* fix gas copy opcodes gas costs, add callDataLoad/Size/Copy, CodeSize/Copy and gas price opcode
* Update with 30s, 40s, 50s opcodes + impl of balance + stack improvement
* add push, dup, swap, log, create and call operations
* finish opcode implementation
* Add the new dispatching logic
* Pass the opcode test
* Make test_vm_json compile
* halt execution without exceptions for Return, Revert, selfdestruct (fix #62)
* Properly catch and recover from EVM exceptions (stack underflow ...)
* Fix byte op
* Fix jump regressions
* Update for latest devel, don't import old dispatch code as quasiBoolean macro is broken by latest devel
* Fix sha3 regression on empty memory slice and until end of range slice
* Fix padding / range error on expXY_success (gas computation left)
* update logging procs
* Add tracing - expXY_success is not a regression, sload stub was accidentally passing the test
* Reuse the same stub as OO implementation
* Delete previous opcode implementation
* Delete object oriented fork code
* Delete exceptions that were used as control flows
* delete base.nim :fire:, yet another OO remnants
* Delete opcode table
* Enable omputed gotos and compile-time gas fees
* Revert const gasCosts -> generates SIGSEGV
* inline push, swap and dup opcodes
* loggers are now template again, why does this pass new tests?
* Trigger CI rebuild after rocksdb fix https://github.com/status-im/nim-rocksdb/pull/5
* Address review comment on "push" + VMTests in debug mode (not release)
* Address review comment: don't tag fork by default, make opcode impl grepable
* Static compilation fixes after rebasing
* fix the initialization of the VM database
* add a missing import
* Deactivate balance and sload test following #59
* Reactivate stack check (deactivated in #59, necessary to pass tests)
* Merge remaining opcodes implementation from #59
* Merge callDataLoad and codeCopy fixes, todo simplify see #67
2018-07-06 07:52:31 +00:00
BaseGasCosts
2018-09-18 15:28:40 +00:00
elif fork < FkTangerine :
HomesteadGasCosts
2019-04-17 02:46:33 +00:00
elif fork < FkSpurious :
Refactor interpreter dispatch (#65)
* move forks constants, rename errors
* Move vm/utils to vm/interpreter/utils
* initial opcodes refactoring
* Add refactored Comparison & Bitwise Logic Operations
* Add sha3 and address, simplify macro, support pop 0
* balance, origin, caller, callValue
* fix gas copy opcodes gas costs, add callDataLoad/Size/Copy, CodeSize/Copy and gas price opcode
* Update with 30s, 40s, 50s opcodes + impl of balance + stack improvement
* add push, dup, swap, log, create and call operations
* finish opcode implementation
* Add the new dispatching logic
* Pass the opcode test
* Make test_vm_json compile
* halt execution without exceptions for Return, Revert, selfdestruct (fix #62)
* Properly catch and recover from EVM exceptions (stack underflow ...)
* Fix byte op
* Fix jump regressions
* Update for latest devel, don't import old dispatch code as quasiBoolean macro is broken by latest devel
* Fix sha3 regression on empty memory slice and until end of range slice
* Fix padding / range error on expXY_success (gas computation left)
* update logging procs
* Add tracing - expXY_success is not a regression, sload stub was accidentally passing the test
* Reuse the same stub as OO implementation
* Delete previous opcode implementation
* Delete object oriented fork code
* Delete exceptions that were used as control flows
* delete base.nim :fire:, yet another OO remnants
* Delete opcode table
* Enable omputed gotos and compile-time gas fees
* Revert const gasCosts -> generates SIGSEGV
* inline push, swap and dup opcodes
* loggers are now template again, why does this pass new tests?
* Trigger CI rebuild after rocksdb fix https://github.com/status-im/nim-rocksdb/pull/5
* Address review comment on "push" + VMTests in debug mode (not release)
* Address review comment: don't tag fork by default, make opcode impl grepable
* Static compilation fixes after rebasing
* fix the initialization of the VM database
* add a missing import
* Deactivate balance and sload test following #59
* Reactivate stack check (deactivated in #59, necessary to pass tests)
* Merge remaining opcodes implementation from #59
* Merge callDataLoad and codeCopy fixes, todo simplify see #67
2018-07-06 07:52:31 +00:00
TangerineGasCosts
2020-03-04 09:32:30 +00:00
elif fork = = FkConstantinople :
ConstantinopleGasCosts # with EIP-1283
2019-11-14 15:27:24 +00:00
elif fork < FkIstanbul :
2019-04-17 02:46:33 +00:00
SpuriousGasCosts
2020-12-11 10:51:17 +00:00
elif fork < FkBerlin :
2019-11-14 15:27:24 +00:00
IstanbulGasCosts
2020-12-11 10:51:17 +00:00
else :
BerlinGasCosts
2018-10-03 15:39:34 +00:00
const
## Precompile costs
2018-10-03 16:59:41 +00:00
GasSHA256 * = 60
GasSHA256Word * = 12
GasRIPEMD160 * = 600
GasRIPEMD160Word * = 120
GasIdentity * = 15
GasIdentityWord * = 3
GasECRecover * = 3000
GasECAdd * = 500
2019-11-11 04:33:56 +00:00
GasECAddIstanbul * = 150
2018-10-03 16:59:41 +00:00
GasECMul * = 40000
2019-11-11 04:33:56 +00:00
GasECMulIstanbul * = 6000
2018-10-03 16:59:41 +00:00
GasECPairingBase * = 100000
2019-11-11 04:33:56 +00:00
GasECPairingBaseIstanbul * = 45000
2018-10-03 16:59:41 +00:00
GasECPairingPerPoint * = 80000
2019-11-11 04:33:56 +00:00
GasECPairingPerPointIstanbul * = 34000
2018-10-05 15:26:20 +00:00
# The Yellow Paper is special casing the GasQuadDivisor.
# It is defined in Appendix G with the other GasFeeKind constants
# instead of Appendix E for precompiled contracts
2020-11-27 14:42:17 +00:00
GasQuadDivisor * = 20
GasQuadDivisorEIP2565 * = 3
# EIP2537 BLS12 381
Bls12381G1AddGas * = 600
Bls12381G1MulGas * = 12000
Bls12381G2AddGas * = 4500
Bls12381G2MulGas * = 55000
Bls12381PairingBaseGas * = 115000
Bls12381PairingPerPairGas * = 23000
Bls12381MapG1Gas * = 5500
Bls12381MapG2Gas * = 110000