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],
|
2019-04-15 04:10:40 +00:00
|
|
|
|
./opcode_values, ./vm_forks, ../../errors
|
2018-05-24 10:01:59 +00:00
|
|
|
|
|
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:
|
|
|
|
|
s_isStorageEmpty*: bool
|
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
|
2018-06-13 17:33:47 +00:00
|
|
|
|
c_currentMemSize*: Natural
|
|
|
|
|
c_memOffset*: Natural
|
|
|
|
|
c_memLength*: Natural
|
2019-03-15 15:15:40 +00:00
|
|
|
|
of Create:
|
|
|
|
|
cr_currentMemSize*: Natural
|
|
|
|
|
cr_memOffset*: Natural
|
|
|
|
|
cr_memLength*: Natural
|
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-04-25 22:18:51 +00:00
|
|
|
|
m_handler*: proc(currentMemSize, memOffset, memLength: Natural): 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]
|
|
|
|
|
|
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 ##############################
|
|
|
|
|
|
2018-06-13 17:33:47 +00:00
|
|
|
|
func `prefix gasMemoryExpansion`(currentMemSize, memOffset, memLength: Natural): 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
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
# Note: The all-but-one-64th calculation should occur after the memory expansion fee is taken
|
|
|
|
|
# https://github.com/ethereum/yellowpaper/pull/442
|
|
|
|
|
|
|
|
|
|
result = gas - (gas shr 6)
|
|
|
|
|
|
|
|
|
|
# ############### 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
|
|
|
|
|
2018-06-13 17:33:47 +00:00
|
|
|
|
func `prefix gasSha3`(currentMemSize, memOffset, memLength: Natural): 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
|
|
|
|
|
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
|
|
|
|
func `prefix gasCopy`(currentMemSize, memOffset, memLength: Natural): 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
|
|
|
|
|
2018-07-24 00:00:06 +00:00
|
|
|
|
func `prefix gasExtCodeCopy`(currentMemSize, memOffset, memLength: Natural): GasInt {.nimcall.} =
|
|
|
|
|
result = static(FeeSchedule[GasExtCode]) +
|
|
|
|
|
static(FeeSchedule[GasCopy]) * memLength.wordCount
|
|
|
|
|
result += `prefix gasMemoryExpansion`(currentMemSize, memOffset, memLength)
|
2018-06-12 15:33:47 +00:00
|
|
|
|
|
2018-06-13 17:33:47 +00:00
|
|
|
|
func `prefix gasLoadStore`(currentMemSize, memOffset, memLength: Natural): 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
|
|
|
|
|
|
|
|
|
|
# workaround for static evaluation not working for if expression
|
|
|
|
|
const
|
|
|
|
|
gSet = FeeSchedule[GasSset]
|
|
|
|
|
gSreset = FeeSchedule[GasSreset]
|
|
|
|
|
|
|
|
|
|
# Gas cost - literal translation of Yellow Paper
|
2019-02-06 07:46:09 +00:00
|
|
|
|
result.gasCost = if value.isZero.not and gasParams.s_isStorageEmpty:
|
|
|
|
|
gSet
|
|
|
|
|
else:
|
|
|
|
|
gSreset
|
2018-06-12 15:33:47 +00:00
|
|
|
|
|
|
|
|
|
# Refund
|
2018-06-13 14:05:52 +00:00
|
|
|
|
if value.isZero and not gasParams.s_isStorageEmpty:
|
2018-06-12 15:33:47 +00:00
|
|
|
|
result.gasRefund = static(FeeSchedule[RefundSclear])
|
|
|
|
|
|
2018-06-13 17:33:47 +00:00
|
|
|
|
func `prefix gasLog0`(currentMemSize, memOffset, memLength: Natural): GasInt {.nimcall.} =
|
|
|
|
|
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
|
|
|
|
|
2018-06-13 17:33:47 +00:00
|
|
|
|
func `prefix gasLog1`(currentMemSize, memOffset, memLength: Natural): GasInt {.nimcall.} =
|
|
|
|
|
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])
|
|
|
|
|
|
2018-06-13 17:33:47 +00:00
|
|
|
|
func `prefix gasLog2`(currentMemSize, memOffset, memLength: Natural): GasInt {.nimcall.} =
|
|
|
|
|
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])
|
|
|
|
|
|
2018-06-13 17:33:47 +00:00
|
|
|
|
func `prefix gasLog3`(currentMemSize, memOffset, memLength: Natural): GasInt {.nimcall.} =
|
|
|
|
|
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])
|
|
|
|
|
|
2018-06-13 17:33:47 +00:00
|
|
|
|
func `prefix gasLog4`(currentMemSize, memOffset, memLength: Natural): GasInt {.nimcall.} =
|
|
|
|
|
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])
|
|
|
|
|
|
2018-06-13 17:33:47 +00:00
|
|
|
|
func `prefix gasHalt`(currentMemSize, memOffset, memLength: Natural): GasInt {.nimcall.} =
|
|
|
|
|
`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-05-07 03:23:27 +00:00
|
|
|
|
func `prefix gasCreate2`(currentMemSize, memOffset, memLength: Natural): 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
|
|
|
|
|
let `ResultGasCostsName`*{.inject.}: GasCosts = block:
|
|
|
|
|
# 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-04-25 22:18:51 +00:00
|
|
|
|
func memExpansion(handler: proc(currentMemSize, memOffset, memLength: Natural): 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,
|
|
|
|
|
|
|
|
|
|
# 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,
|
|
|
|
|
|
|
|
|
|
# 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
|
2018-09-18 15:28:40 +00:00
|
|
|
|
func homesteadGasFees(previous_fees: GasFeeSchedule): GasFeeSchedule =
|
|
|
|
|
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.md
|
|
|
|
|
result = previous_fees
|
|
|
|
|
result[GasTXCreate] = 32000
|
|
|
|
|
|
2018-06-12 15:33:47 +00:00
|
|
|
|
func tangerineGasFees(previous_fees: GasFeeSchedule): GasFeeSchedule =
|
2018-05-24 10:01:59 +00:00
|
|
|
|
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md
|
2018-06-12 15:33:47 +00:00
|
|
|
|
result = previous_fees
|
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
|
|
|
|
|
2018-06-12 15:33:47 +00:00
|
|
|
|
func spuriousGasFees(previous_fees: GasFeeSchedule): GasFeeSchedule =
|
|
|
|
|
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-160.md
|
|
|
|
|
result = previous_fees
|
|
|
|
|
result[GasExpByte] = 50
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
2018-11-28 19:02:21 +00:00
|
|
|
|
gasFees*: array[Fork, GasFeeSchedule] = [
|
|
|
|
|
FkFrontier: BaseGasFees,
|
|
|
|
|
FkThawing: BaseGasFees,
|
|
|
|
|
FkHomestead: HomesteadGasFees,
|
|
|
|
|
FkDao: HomesteadGasFees,
|
|
|
|
|
FkTangerine: TangerineGasFees,
|
|
|
|
|
FkSpurious: SpuriousGasFees,
|
2019-04-30 05:23:51 +00:00
|
|
|
|
FkByzantium: SpuriousGasFees,
|
|
|
|
|
FkConstantinople: SpuriousGasFees
|
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)
|
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
|
2019-04-17 02:46:33 +00:00
|
|
|
|
else:
|
|
|
|
|
SpuriousGasCosts
|
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
|
|
|
|
|
GasECMul* = 40000
|
|
|
|
|
GasECPairingBase* = 100000
|
|
|
|
|
GasECPairingPerPoint* = 80000
|
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
|
2019-04-24 14:31:05 +00:00
|
|
|
|
GasQuadDivisor* = 20
|