mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-11 21:04:11 +00:00
* Gas refactoring - uses int64 * Use primitive int in test_vm_json
This commit is contained in:
parent
c77b7cd035
commit
cb49352b6a
@ -6,7 +6,7 @@
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
strformat, strutils, sequtils, tables, macros, stint, terminal,
|
||||
strformat, strutils, sequtils, tables, macros, stint, terminal, math,
|
||||
constants, errors, utils/hexadecimal, utils_numeric, validation, vm_state, logging, opcode_values, types,
|
||||
vm / [code_stream, gas_meter, memory, message, stack],
|
||||
|
||||
@ -15,7 +15,7 @@ import
|
||||
vm/forks/f20150730_frontier/frontier_vm_state,
|
||||
vm/forks/f20161018_tangerine_whistle/tangerine_vm_state
|
||||
|
||||
proc memoryGasCost*(sizeInBytes: UInt256): UInt256 =
|
||||
proc memoryGasCost*(sizeInBytes: Natural): GasInt =
|
||||
let
|
||||
sizeInWords = ceil32(sizeInBytes) div 32
|
||||
linearCost = sizeInWords * GAS_MEMORY
|
||||
@ -86,7 +86,7 @@ method shouldEraseReturnData*(c: BaseComputation): bool =
|
||||
|
||||
method prepareChildMessage*(
|
||||
c: var BaseComputation,
|
||||
gas: UInt256,
|
||||
gas: GasInt,
|
||||
to: string,
|
||||
value: UInt256,
|
||||
data: seq[byte],
|
||||
@ -105,13 +105,10 @@ method prepareChildMessage*(
|
||||
code,
|
||||
childOptions)
|
||||
|
||||
method extendMemory*(c: var BaseComputation, startPosition: UInt256, size: UInt256) =
|
||||
method extendMemory*(c: var BaseComputation, startPosition: Natural, size: Natural) =
|
||||
# Memory Management
|
||||
#
|
||||
# validate_uint256(start_position, title="Memory start position")
|
||||
# validate_uint256(size, title="Memory size")
|
||||
|
||||
let beforeSize = ceil32(len(c.memory).u256)
|
||||
let beforeSize = ceil32(len(c.memory))
|
||||
let afterSize = ceil32(startPosition + size)
|
||||
|
||||
let beforeCost = memoryGasCost(beforeSize)
|
||||
@ -201,21 +198,21 @@ method getLogEntries*(c: BaseComputation): seq[(string, seq[UInt256], string)] =
|
||||
else:
|
||||
result = @[]
|
||||
|
||||
method getGasRefund*(c: BaseComputation): UInt256 =
|
||||
method getGasRefund*(c: BaseComputation): GasInt =
|
||||
if c.isError:
|
||||
result = 0.u256
|
||||
result = 0
|
||||
else:
|
||||
result = c.gasMeter.gasRefunded + c.children.mapIt(it.getGasRefund()).foldl(a + b, 0.u256)
|
||||
result = c.gasMeter.gasRefunded + c.children.mapIt(it.getGasRefund()).foldl(a + b, 0'i64)
|
||||
|
||||
method getGasUsed*(c: BaseComputation): UInt256 =
|
||||
method getGasUsed*(c: BaseComputation): GasInt =
|
||||
if c.shouldBurnGas:
|
||||
result = c.msg.gas
|
||||
else:
|
||||
result = max(0.u256, c.msg.gas - c.gasMeter.gasRemaining)
|
||||
result = max(0, c.msg.gas - c.gasMeter.gasRemaining)
|
||||
|
||||
method getGasRemaining*(c: BaseComputation): UInt256 =
|
||||
method getGasRemaining*(c: BaseComputation): GasInt =
|
||||
if c.shouldBurnGas:
|
||||
result = 0.u256
|
||||
result = 0
|
||||
else:
|
||||
result = c.gasMeter.gasRemaining
|
||||
|
||||
|
@ -46,13 +46,13 @@ proc `==`*(a: UInt256, b: int): bool =
|
||||
proc `!=`*(a: UInt256, b: int): bool =
|
||||
a != b.u256
|
||||
|
||||
proc `^`*(base: int; exp: int): UInt256 =
|
||||
let base = base.u256
|
||||
var ex = exp
|
||||
result = 1.u256
|
||||
while ex > 0:
|
||||
result = result * base
|
||||
dec(ex)
|
||||
# proc `^`*(base: int; exp: int): UInt256 =
|
||||
# let base = base.u256
|
||||
# var ex = exp
|
||||
# result = 1.u256
|
||||
# while ex > 0:
|
||||
# result = result * base
|
||||
# dec(ex)
|
||||
|
||||
proc `^`*(left: Int256, right: int): Int256 =
|
||||
var value = right.i256
|
||||
@ -123,7 +123,7 @@ let
|
||||
INT_256_MAX_AS_UINT256* = cast[Uint256](high(Int256))
|
||||
NULLBYTE* = "\x00"
|
||||
EMPTYWORD* = repeat(NULLBYTE, 32)
|
||||
UINT160CEILING*: UInt256 = 2 ^ 160
|
||||
UINT160CEILING*: UInt256 = 2.u256 ^ 160
|
||||
CREATE_CONTRACT_ADDRESS* = ""
|
||||
ZERO_ADDRESS* = repeat("\x00", 20)
|
||||
ZERO_HASH32* = repeat("\x00", 20)
|
||||
@ -147,34 +147,34 @@ let
|
||||
# GAS_SLOAD_COST* = 20.u256
|
||||
# GAS_SELF_DESTRUCT_COST* = 0.u256
|
||||
# GAS_IN_HANDLER* = 0.u256 # to be calculated in handler
|
||||
REFUND_SCLEAR* = 15_000.u256
|
||||
REFUND_SCLEAR* = 15_000
|
||||
|
||||
# GAS_SELF_DESTRUCT* = 0.u256
|
||||
# GAS_SELF_DESTRUCT_NEW_ACCOUNT* = 25_000.u256
|
||||
GAS_CREATE* = 32_000.u256
|
||||
# GAS_CALL* = 40.u256
|
||||
GAS_CALL_VALUE* = 9_000.u256
|
||||
GAS_CALL_STIPEND* = 2_300.u256
|
||||
GAS_NEW_ACCOUNT* = 25_000.u256
|
||||
GAS_CALL_VALUE* = 9_000
|
||||
GAS_CALL_STIPEND* = 2_300
|
||||
GAS_NEW_ACCOUNT* = 25_000
|
||||
|
||||
# GAS_COST_BALANCE* = 400.u256 # TODO: this is post-eip150, see also GAS_BALANCE
|
||||
|
||||
# GAS_EXP* = 10.u256
|
||||
# GAS_EXP_BYTE* = 10.u256
|
||||
GAS_MEMORY* = 3.u256
|
||||
GAS_MEMORY* = 3
|
||||
GAS_TX_CREATE* = 32_000.u256
|
||||
GAS_TX_DATA_ZERO* = 4.u256
|
||||
GAS_TX_DATA_NON_ZERO* = 68.u256
|
||||
GAS_TX* = 21_000.u256
|
||||
GAS_LOG* = 375.u256
|
||||
GAS_LOG_DATA* = 8.u256
|
||||
GAS_LOG_TOPIC* = 375.u256
|
||||
GAS_LOG_DATA* = 8
|
||||
GAS_LOG_TOPIC* = 375
|
||||
# GAS_SHA3* = 30.u256
|
||||
GAS_SHA3_WORD* = 6.u256
|
||||
GAS_COPY* = 3.u256
|
||||
GAS_SHA3_WORD* = 6
|
||||
GAS_COPY* = 3
|
||||
GAS_BLOCK_HASH* = 20.u256
|
||||
GAS_CODE_DEPOSIT* = 200.u256
|
||||
GAS_MEMORY_QUADRATIC_DENOMINATOR* = 512.u256
|
||||
GAS_MEMORY_QUADRATIC_DENOMINATOR* = 512
|
||||
GAS_SHA256* = 60.u256
|
||||
GAS_SHA256WORD* = 12.u256
|
||||
GAS_RIP_EMD160* = 600.u256
|
||||
@ -188,7 +188,7 @@ let
|
||||
GAS_ECPAIRING_PER_POINT* = 80_000.u256
|
||||
GAS_LIMIT_EMA_DENOMINATOR* = 1_024.u256
|
||||
GAS_LIMIT_ADJUSTMENT_FACTOR* = 1_024.u256
|
||||
GAS_LIMIT_MAXIMUM*: UInt256 = 2 ^ 63 - 1.u256
|
||||
GAS_LIMIT_MAXIMUM* = high(int64)
|
||||
GAS_LIMIT_USAGE_ADJUSTMENT_NUMERATOR* = 3.u256
|
||||
GAS_LIMIT_USAGE_ADJUSTMENT_DENOMINATOR* = 2.u256
|
||||
|
||||
@ -206,7 +206,7 @@ let
|
||||
MAX_UNCLE_DEPTH* = 6.u256
|
||||
MAX_UNCLES* = 2.u256
|
||||
|
||||
SECPK1_P*: UInt256 = 2 ^ 256 - 2 ^ 32 - 977.u256
|
||||
SECPK1_P*: UInt256 = 2.u256 ^ 256 - 2.u256 ^ 32 - 977.u256
|
||||
SECPK1_N*: UInt256 = "115792089237316195423570985008687907852837564279074904382605163141518161494337".u256
|
||||
SECPK1_A* = 0.u256
|
||||
SECPK1_B* = 7.u256
|
||||
|
@ -92,7 +92,7 @@ proc exp*(computation: var BaseComputation) =
|
||||
|
||||
var gasCost = computation.gasCosts[GasExp]
|
||||
if not exponent.isZero:
|
||||
gasCost += gasCost * (one(Uint256) + log256(exponent))
|
||||
gasCost += gasCost * (1 + log256(exponent))
|
||||
computation.gasMeter.consumeGas(gasCost, reason="EXP: exponent bytes")
|
||||
|
||||
let res = if base.isZero: 0.u256 # 0^0 is 0 in py-evm
|
||||
|
@ -39,13 +39,13 @@ type
|
||||
using
|
||||
computation: var BaseComputation
|
||||
|
||||
method msgExtraGas*(call: BaseCall, computation; gas: UInt256, to: string, value: UInt256): UInt256 {.base.} =
|
||||
method msgExtraGas*(call: BaseCall, computation; gas: GasInt, to: string, value: UInt256): GasInt {.base.} =
|
||||
raise newException(NotImplementedError, "Must be implemented by subclasses")
|
||||
|
||||
method msgGas*(call: BaseCall, computation; gas: UInt256, to: string, value: UInt256): (UInt256, UInt256) {.base.} =
|
||||
method msgGas*(call: BaseCall, computation; gas: GasInt, to: string, value: UInt256): (GasInt, GasInt) {.base.} =
|
||||
let extraGas = call.msgExtraGas(computation, gas, to, value)
|
||||
let totalFee = gas + extraGas
|
||||
let childMsgGas = gas + (if value != 0: GAS_CALL_STIPEND else: 0.u256)
|
||||
let childMsgGas = gas + (if value != 0: GAS_CALL_STIPEND else: 0)
|
||||
(childMsgGas, totalFee)
|
||||
|
||||
method callParams*(call: BaseCall, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) {.base.} =
|
||||
@ -60,11 +60,13 @@ method runLogic*(call: BaseCall, computation) =
|
||||
shouldTransferValue,
|
||||
isStatic) = call.callParams(computation)
|
||||
|
||||
computation.extendMemory(memoryInputStartPosition, memoryInputSize)
|
||||
computation.extendMemory(memoryOutputStartPosition, memoryOutputSize)
|
||||
let (memInPos, memInLen, memOutPos, memOutLen) = (memoryInputStartPosition.toInt, memoryInputSize.toInt, memoryOutputStartPosition.toInt, memoryOutputSize.toInt)
|
||||
|
||||
let callData = computation.memory.read(memoryInputStartPosition, memoryInputSize)
|
||||
let (childMsgGas, childMsgGasFee) = call.msgGas(computation, gas, to, value)
|
||||
computation.extendMemory(memInPos, memInLen)
|
||||
computation.extendMemory(memOutPos, memOutLen)
|
||||
|
||||
let callData = computation.memory.read(memInPos, memInLen)
|
||||
let (childMsgGas, childMsgGasFee) = call.msgGas(computation, gas.toInt, to, value)
|
||||
computation.gasMeter.consumeGas(childMsgGasFee, reason = $call.kind)
|
||||
|
||||
# TODO: Pre-call checks
|
||||
@ -116,22 +118,22 @@ method runLogic*(call: BaseCall, computation) =
|
||||
else:
|
||||
computation.stack.push(1.u256)
|
||||
if not childComputation.shouldEraseReturnData:
|
||||
let actualOutputSize = min(memoryOutputSize, childComputation.output.len.u256)
|
||||
let actualOutputSize = min(memOutLen, childComputation.output.len)
|
||||
computation.memory.write(
|
||||
memoryOutputStartPosition,
|
||||
memOutPos,
|
||||
actualOutputSize,
|
||||
childComputation.output.toBytes[0 ..< actualOutputSize.toInt])
|
||||
childComputation.output.toBytes[0 ..< actualOutputSize])
|
||||
if not childComputation.shouldBurnGas:
|
||||
computation.gasMeter.returnGas(childComputation.gasMeter.gasRemaining)
|
||||
|
||||
method msgExtraGas(call: Call, computation; gas: UInt256, to: string, value: UInt256): UInt256 =
|
||||
method msgExtraGas(call: Call, computation; gas: GasInt, to: string, value: UInt256): GasInt =
|
||||
# TODO: db
|
||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||
# let accountExists = db.accountExists(to)
|
||||
let accountExists = false
|
||||
|
||||
let transferGasFee = if value != 0: GAS_CALL_VALUE else: 0.u256
|
||||
let createGasFee = if not accountExists: GAS_NEW_ACCOUNT else: 0.u256
|
||||
let transferGasFee = if value != 0: GAS_CALL_VALUE else: 0
|
||||
let createGasFee = if not accountExists: GAS_NEW_ACCOUNT else: 0
|
||||
transferGasFee + createGasFee
|
||||
|
||||
method callParams(call: CallCode, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
@ -154,8 +156,8 @@ method callParams(call: CallCode, computation): (UInt256, UInt256, string, strin
|
||||
true, # should_transfer_value,
|
||||
computation.msg.isStatic)
|
||||
|
||||
method msgExtraGas(call: CallCode, computation; gas: UInt256, to: string, value: UInt256): UInt256 =
|
||||
if value != 0: GAS_CALL_VALUE else: 0.u256
|
||||
method msgExtraGas(call: CallCode, computation; gas: GasInt, to: string, value: UInt256): GasInt =
|
||||
if value != 0: GAS_CALL_VALUE else: 0
|
||||
|
||||
method callParams(call: Call, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
let gas = computation.stack.popInt()
|
||||
@ -180,11 +182,11 @@ method callParams(call: Call, computation): (UInt256, UInt256, string, string, s
|
||||
true, # should_transfer_value,
|
||||
computation.msg.isStatic)
|
||||
|
||||
method msgGas(call: DelegateCall, computation; gas: UInt256, to: string, value: UInt256): (UInt256, UInt256) =
|
||||
method msgGas(call: DelegateCall, computation; gas: GasInt, to: string, value: UInt256): (GasInt, GasInt) =
|
||||
(gas, gas)
|
||||
|
||||
method msgExtraGas(call: DelegateCall, computation; gas: UInt256, to: string, value: UInt256): UInt256 =
|
||||
0.u256
|
||||
method msgExtraGas(call: DelegateCall, computation; gas: GasInt, to: string, value: UInt256): GasInt =
|
||||
0
|
||||
|
||||
method callParams(call: DelegateCall, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
let gas = computation.stack.popInt()
|
||||
@ -209,30 +211,30 @@ method callParams(call: DelegateCall, computation): (UInt256, UInt256, string, s
|
||||
false, # should_transfer_value,
|
||||
computation.msg.isStatic)
|
||||
|
||||
proc maxChildGasEIP150*(gas: UInt256): UInt256 =
|
||||
proc maxChildGasEIP150*(gas: GasInt): GasInt =
|
||||
gas - gas div 64
|
||||
|
||||
proc computeEIP150MsgGas(computation; gas: UInt256, extraGas: UInt256, value: UInt256, name: string, callStipend: UInt256): (UInt256, UInt256) =
|
||||
proc computeEIP150MsgGas(computation; gas, extraGas: GasInt, value: UInt256, name: string, callStipend: GasInt): (GasInt, GasInt) =
|
||||
if computation.gasMeter.gasRemaining < extraGas:
|
||||
raise newException(OutOfGas, &"Out of gas: Needed {extraGas} - Remaining {computation.gasMeter.gasRemaining} - Reason: {name}")
|
||||
let gas = min(gas, maxChildGasEIP150(computation.gasMeter.gasRemaining - extraGas))
|
||||
let totalFee = gas + extraGas
|
||||
let childMsgGas = gas + (if value != 0: callStipend else: 0.u256)
|
||||
let childMsgGas = gas + (if value != 0: callStipend else: 0)
|
||||
(childMsgGas, totalFee)
|
||||
|
||||
method msgGas(call: CallEIP150, computation; gas: UInt256, to: string, value: UInt256): (UInt256, UInt256) =
|
||||
method msgGas(call: CallEIP150, computation; gas: GasInt, to: string, value: UInt256): (GasInt, GasInt) =
|
||||
let extraGas = call.msgExtraGas(computation, gas, to, value)
|
||||
computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, GAS_CALL_STIPEND)
|
||||
|
||||
method msgGas(call: CallCodeEIP150, computation; gas: UInt256, to: string, value: UInt256): (UInt256, UInt256) =
|
||||
method msgGas(call: CallCodeEIP150, computation; gas: GasInt, to: string, value: UInt256): (GasInt, GasInt) =
|
||||
let extraGas = call.msgExtraGas(computation, gas, to, value)
|
||||
computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, GAS_CALL_STIPEND)
|
||||
|
||||
method msgGas(call: DelegateCallEIP150, computation; gas: UInt256, to: string, value: UInt256): (UInt256, UInt256) =
|
||||
method msgGas(call: DelegateCallEIP150, computation; gas: GasInt, to: string, value: UInt256): (GasInt, GasInt) =
|
||||
let extraGas = call.msgExtraGas(computation, gas, to, value)
|
||||
computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, 0.u256)
|
||||
computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, 0)
|
||||
|
||||
proc msgExtraGas*(call: CallEIP161, computation; gas: UInt256, to: string, value: UInt256): UInt256 =
|
||||
proc msgExtraGas*(call: CallEIP161, computation; gas: GasInt, to: string, value: UInt256): GasInt =
|
||||
# TODO: with
|
||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||
# account_is_dead = (
|
||||
@ -240,8 +242,8 @@ proc msgExtraGas*(call: CallEIP161, computation; gas: UInt256, to: string, value
|
||||
# state_db.account_is_empty(to))
|
||||
let accountIsDead = true
|
||||
|
||||
let transferGasFee = if value != 0: GAS_CALL_VALUE else: 0.u256
|
||||
let createGasFee = if accountIsDead and value != 0: GAS_NEW_ACCOUNT else: 0.u256
|
||||
let transferGasFee = if value != 0: GAS_CALL_VALUE else: 0
|
||||
let createGasFee = if accountIsDead and value != 0: GAS_NEW_ACCOUNT else: 0
|
||||
transferGasFee + createGasFee
|
||||
|
||||
|
||||
|
@ -47,14 +47,15 @@ proc callDataCopy*(computation: var BaseComputation) =
|
||||
let (memStartPosition,
|
||||
calldataStartPosition,
|
||||
size) = computation.stack.popInt(3)
|
||||
computation.extendMemory(memStartPosition, size)
|
||||
let (memPos, callPos, len) = (memStartPosition.toInt, calldataStartPosition.toInt, size.toInt)
|
||||
computation.extendMemory(memPos, len)
|
||||
|
||||
let wordCount = ceil32(size) div 32
|
||||
let wordCount = ceil32(len) div 32
|
||||
let copyGasCost = wordCount * constants.GAS_COPY
|
||||
computation.gasMeter.consumeGas(copyGasCost, reason="CALLDATACOPY fee")
|
||||
let value = computation.msg.data[calldataStartPosition.toInt ..< (calldataStartPosition + size).toInt]
|
||||
let paddedValue = padRight(value, size.toInt, 0.byte)
|
||||
computation.memory.write(memStartPosition, size, paddedValue)
|
||||
let value = computation.msg.data[callPos ..< callPos + len]
|
||||
let paddedValue = padRight(value, len, 0.byte)
|
||||
computation.memory.write(memPos, len, paddedValue)
|
||||
|
||||
|
||||
proc codesize*(computation: var BaseComputation) =
|
||||
@ -66,8 +67,10 @@ proc codecopy*(computation: var BaseComputation) =
|
||||
let (memStartPosition,
|
||||
codeStartPosition,
|
||||
size) = computation.stack.popInt(3)
|
||||
computation.extendMemory(memStartPosition, size)
|
||||
let wordCount = ceil32(size) div 32
|
||||
let (memPos, codePos, len) = (memStartPosition.toInt, codeStartPosition.toInt, size.toInt)
|
||||
computation.extendMemory(memPos, len)
|
||||
|
||||
let wordCount = ceil32(len) div 32
|
||||
let copyGasCost = constants.GAS_COPY * wordCount
|
||||
|
||||
computation.gasMeter.consumeGas(copyGasCost, reason="CODECOPY: word gas cost")
|
||||
@ -79,7 +82,7 @@ proc codecopy*(computation: var BaseComputation) =
|
||||
|
||||
|
||||
proc gasprice*(computation: var BaseComputation) =
|
||||
computation.stack.push(computation.msg.gasPrice)
|
||||
computation.stack.push(computation.msg.gasPrice.u256)
|
||||
|
||||
|
||||
proc extCodeSize*(computation: var BaseComputation) =
|
||||
@ -93,8 +96,9 @@ proc extCodeSize*(computation: var BaseComputation) =
|
||||
proc extCodeCopy*(computation: var BaseComputation) =
|
||||
let account = forceBytesToAddress(computation.stack.popString)
|
||||
let (memStartPosition, codeStartPosition, size) = computation.stack.popInt(3)
|
||||
computation.extendMemory(memStartPosition, size)
|
||||
let wordCount = ceil32(size) div 32
|
||||
let (memPos, codePos, len) = (memStartPosition.toInt, codeStartPosition.toInt, size.toInt)
|
||||
computation.extendMemory(memPos, len)
|
||||
let wordCount = ceil32(len) div 32
|
||||
let copyGasCost = constants.GAS_COPY * wordCount
|
||||
|
||||
computation.gasMeter.consumeGas(copyGasCost, reason="EXTCODECOPY: word gas cost")
|
||||
@ -112,15 +116,16 @@ proc returnDataSize*(computation: var BaseComputation) =
|
||||
|
||||
proc returnDataCopy*(computation: var BaseComputation) =
|
||||
let (memStartPosition, returnDataStartPosition, size) = computation.stack.popInt(3)
|
||||
if returnDataStartPosition + size > computation.returnData.len:
|
||||
let (memPos, returnPos, len) = (memStartPosition.toInt, returnDataStartPosition.toInt, size.toInt)
|
||||
if returnPos + len > computation.returnData.len:
|
||||
raise newException(OutOfBoundsRead,
|
||||
"Return data length is not sufficient to satisfy request. Asked \n" &
|
||||
&"for data from index {returnDataStartPosition} to {returnDataStartPosition + size}. Return data is {computation.returnData.len} in \n" &
|
||||
"length")
|
||||
|
||||
computation.extendMemory(memStartPosition, size)
|
||||
let wordCount = ceil32(size) div 32
|
||||
computation.extendMemory(memPos, len)
|
||||
let wordCount = ceil32(len) div 32
|
||||
let copyGasCost = wordCount * constants.GAS_COPY
|
||||
computation.gasMeter.consumeGas(copyGasCost, reason="RETURNDATACOPY fee")
|
||||
let value = ($computation.returnData)[returnDataStartPosition.toInt ..< (returnDataStartPosition + size).toInt]
|
||||
computation.memory.write(memStartPosition, size, value)
|
||||
let value = ($computation.returnData)[returnPos ..< returnPos + len]
|
||||
computation.memory.write(memPos, len, value)
|
||||
|
@ -55,4 +55,4 @@ proc pc*(computation) =
|
||||
|
||||
proc gas*(computation) =
|
||||
let gasRemaining = gasMeter.gasRemaining
|
||||
stack.push(gasRemaining)
|
||||
stack.push(gasRemaining.u256)
|
||||
|
@ -17,18 +17,19 @@ using
|
||||
|
||||
macro logXX(topicCount: static[int]): untyped =
|
||||
if topicCount < 0 or topicCount > 4:
|
||||
error(&"Invalid log topic size {topicCount} Must be 0, 1, 2, 3, or 4")
|
||||
error(&"Invalid log topic len {topicCount} Must be 0, 1, 2, 3, or 4")
|
||||
return
|
||||
|
||||
let name = ident(&"log{topicCount}")
|
||||
let computation = ident("computation")
|
||||
let topics = ident("topics")
|
||||
let topicsTuple = ident("topicsTuple")
|
||||
let size = ident("size")
|
||||
let memStartPosition = ident("memStartPosition")
|
||||
let len = ident("len")
|
||||
let memPos = ident("memPos")
|
||||
result = quote:
|
||||
proc `name`*(`computation`: var BaseComputation) =
|
||||
let (`memStartPosition`, `size`) = `computation`.stack.popInt(2)
|
||||
let (memStartPosition, size) = `computation`.stack.popInt(2)
|
||||
let (`memPos`, `len`) = (memStartPosition.toInt, size.toInt)
|
||||
var `topics`: seq[UInt256]
|
||||
|
||||
var topicCode: NimNode
|
||||
@ -50,12 +51,12 @@ macro logXX(topicCount: static[int]): untyped =
|
||||
result.body.add(topicCode)
|
||||
|
||||
let logicCode = quote:
|
||||
let dataGasCost = constants.GAS_LOG_DATA * `size`
|
||||
let topicGasCost = constants.GAS_LOG_TOPIC * `topicCount`.u256
|
||||
let dataGasCost = constants.GAS_LOG_DATA * `len`
|
||||
let topicGasCost = constants.GAS_LOG_TOPIC * `topicCount`
|
||||
let totalGasCost = dataGasCost + topicGasCost
|
||||
`computation`.gasMeter.consumeGas(totalGasCost, reason="Log topic and data gas cost")
|
||||
`computation`.extendMemory(`memStartPosition`, `size`)
|
||||
let logData = `computation`.memory.read(`memStartPosition`, `size`).toString
|
||||
`computation`.extendMemory(`memPos`, `len`)
|
||||
let logData = `computation`.memory.read(`memPos`, `len`).toString
|
||||
`computation`.addLogEntry(
|
||||
account=`computation`.msg.storageAddress,
|
||||
topics=`topics`,
|
||||
|
@ -6,7 +6,8 @@
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
../constants, ../computation, ../types, .. / vm / [stack, memory], .. / utils / [padding, bytes]
|
||||
../constants, ../computation, ../types, .. / vm / [stack, memory], .. / utils / [padding, bytes],
|
||||
stint
|
||||
|
||||
|
||||
{.this: computation.}
|
||||
@ -16,14 +17,14 @@ using
|
||||
computation: var BaseComputation
|
||||
|
||||
proc mstoreX(computation; x: int) =
|
||||
let start = stack.popInt()
|
||||
let start = stack.popInt().toInt
|
||||
let value = stack.popBinary()
|
||||
|
||||
let paddedValue = padLeft(value, x, 0.byte)
|
||||
let normalizedValue = paddedValue[^x .. ^1]
|
||||
|
||||
extendMemory(start, x.u256)
|
||||
memory.write(start, 32.u256, normalizedValue)
|
||||
extendMemory(start, x)
|
||||
memory.write(start, 32, normalizedValue)
|
||||
|
||||
# TODO template handler
|
||||
|
||||
@ -34,11 +35,11 @@ proc mstore8*(computation) =
|
||||
mstoreX(1)
|
||||
|
||||
proc mload*(computation) =
|
||||
let start = stack.popInt()
|
||||
let start = stack.popInt().toInt
|
||||
|
||||
extendMemory(start, 32.u256)
|
||||
extendMemory(start, 32)
|
||||
|
||||
let value = memory.read(start, 32.u256)
|
||||
let value = memory.read(start, 32)
|
||||
stack.push(value)
|
||||
|
||||
proc msize*(computation) =
|
||||
|
@ -10,9 +10,10 @@ import
|
||||
|
||||
proc sha3op*(computation: var BaseComputation) =
|
||||
let (startPosition, size) = computation.stack.popInt(2)
|
||||
computation.extendMemory(startPosition, size)
|
||||
let sha3Bytes = computation.memory.read(startPosition, size)
|
||||
let wordCount = sha3Bytes.len.u256.ceil32 div 32
|
||||
let (pos, len) = (startPosition.toInt, size.toInt)
|
||||
computation.extendMemory(pos, len)
|
||||
let sha3Bytes = computation.memory.read(pos, len)
|
||||
let wordCount = sha3Bytes.len.ceil32 div 32 # TODO, can't we just shr instead of rounding + div
|
||||
let gasCost = constants.GAS_SHA3_WORD * wordCount
|
||||
computation.gasMeter.consumeGas(gasCost, reason="SHA3: word gas cost")
|
||||
var res = keccak("")
|
||||
|
@ -29,7 +29,7 @@ proc sstore*(computation) =
|
||||
let isCurrentlyEmpty = not existing # currentValue == 0
|
||||
let isGoingToBeEmpty = value == 0
|
||||
|
||||
let gasRefund = if isCurrentlyEmpty or not isGoingToBeEmpty: 0.u256 else: REFUND_SCLEAR
|
||||
let gasRefund = if isCurrentlyEmpty or not isGoingToBeEmpty: 0 else: REFUND_SCLEAR
|
||||
let gasCost = if isCurrentlyEmpty and not isGoingToBeEmpty: GAS_SSET else: GAS_SRESET
|
||||
|
||||
computation.gasMeter.consumeGas(computation.gasCosts[gasCost], &"SSTORE: {computation.msg.storageAddress}[slot] -> {value} ({currentValue})")
|
||||
|
@ -24,13 +24,14 @@ type
|
||||
|
||||
CreateByzantium* = ref object of CreateEIP150 # TODO: Refactoring - put that in VM forks
|
||||
|
||||
method maxChildGasModifier(create: Create, gas: UInt256): UInt256 {.base.} =
|
||||
method maxChildGasModifier(create: Create, gas: GasInt): GasInt {.base.} =
|
||||
gas
|
||||
|
||||
method runLogic*(create: Create, computation) =
|
||||
computation.gasMeter.consumeGas(computation.gasCosts[create.gasCost(computation)], reason = $create.kind) # TODO: Refactoring create gas costs
|
||||
let (value, startPosition, size) = computation.stack.popInt(3)
|
||||
computation.extendMemory(startPosition, size)
|
||||
let (pos, len) = (startPosition.toInt, size.toInt)
|
||||
computation.extendMemory(pos, len)
|
||||
|
||||
# TODO: with
|
||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||
@ -42,7 +43,7 @@ method runLogic*(create: Create, computation) =
|
||||
# computation.stack.push(0)
|
||||
# return
|
||||
|
||||
let callData = computation.memory.read(startPosition, size)
|
||||
let callData = computation.memory.read(pos, len)
|
||||
let createMsgGas = create.maxChildGasModifier(computation.gasMeter.gasRemaining)
|
||||
computation.gasMeter.consumeGas(createMsgGas, reason="CREATE")
|
||||
|
||||
@ -82,7 +83,7 @@ method runLogic*(create: Create, computation) =
|
||||
computation.stack.push(contractAddress)
|
||||
computation.gasMeter.returnGas(childComputation.gasMeter.gasRemaining)
|
||||
|
||||
method maxChildGasModifier(create: CreateEIP150, gas: UInt256): UInt256 =
|
||||
method maxChildGasModifier(create: CreateEIP150, gas: GasInt): GasInt =
|
||||
maxChildGasEIP150(gas)
|
||||
|
||||
method runLogic*(create: CreateByzantium, computation) =
|
||||
@ -142,15 +143,17 @@ proc selfdestruct(computation; beneficiary: string) =
|
||||
|
||||
proc returnOp*(computation) =
|
||||
let (startPosition, size) = stack.popInt(2)
|
||||
computation.extendMemory(startPosition, size)
|
||||
let output = memory.read(startPosition, size)
|
||||
let (pos, len) = (startPosition.toInt, size.toInt)
|
||||
computation.extendMemory(pos, len)
|
||||
let output = memory.read(pos, len)
|
||||
computation.output = output.toString
|
||||
raise newException(Halt, "RETURN")
|
||||
|
||||
proc revert*(computation) =
|
||||
let (startPosition, size) = stack.popInt(2)
|
||||
computation.extendMemory(startPosition, size)
|
||||
let output = memory.read(startPosition, size).toString
|
||||
let (pos, len) = (startPosition.toInt, size.toInt)
|
||||
computation.extendMemory(pos, len)
|
||||
let output = memory.read(pos, len).toString
|
||||
computation.output = output
|
||||
raise newException(Revert, $output)
|
||||
|
||||
|
@ -9,7 +9,8 @@ import
|
||||
tables,
|
||||
constants, vm_state,
|
||||
opcode_values, stint,
|
||||
vm / [code_stream, gas_meter, memory, message, stack]
|
||||
vm / [code_stream, memory, stack],
|
||||
./logging
|
||||
|
||||
type
|
||||
BaseComputation* = ref object of RootObj
|
||||
@ -49,6 +50,16 @@ type
|
||||
gasCostKind*: GasCostKind
|
||||
runLogic*: proc(computation: var BaseComputation)
|
||||
|
||||
GasInt* = int64
|
||||
## Type alias used for gas computation
|
||||
# For reference - https://github.com/status-im/nimbus/issues/35#issuecomment-391726518
|
||||
|
||||
GasMeter* = ref object
|
||||
logger*: Logger
|
||||
gasRefunded*: GasInt
|
||||
startGas*: GasInt
|
||||
gasRemaining*: GasInt
|
||||
|
||||
GasCostKind* = enum
|
||||
GasZero
|
||||
GasBase
|
||||
@ -71,4 +82,42 @@ type
|
||||
GasExp
|
||||
GasSHA3
|
||||
|
||||
GasCosts* = array[GasCostKind, UInt256]
|
||||
GasCosts* = array[GasCostKind, GasInt]
|
||||
|
||||
Message* = ref object
|
||||
# A message for VM computation
|
||||
|
||||
# depth = None
|
||||
|
||||
# code = None
|
||||
# codeAddress = None
|
||||
|
||||
# createAddress = None
|
||||
|
||||
# shouldTransferValue = None
|
||||
# isStatic = None
|
||||
|
||||
# logger = logging.getLogger("evm.vm.message.Message")
|
||||
|
||||
gas*: GasInt
|
||||
gasPrice*: GasInt
|
||||
to*: string
|
||||
sender*: string
|
||||
value*: UInt256
|
||||
data*: seq[byte]
|
||||
code*: string
|
||||
internalOrigin*: string
|
||||
internalCodeAddress*: string
|
||||
depth*: int
|
||||
internalStorageAddress*: string
|
||||
shouldTransferValue*: bool
|
||||
isStatic*: bool
|
||||
isCreate*: bool
|
||||
|
||||
MessageOptions* = ref object
|
||||
origin*: string
|
||||
depth*: int
|
||||
createAddress*: string
|
||||
codeAddress*: string
|
||||
shouldTransferValue*: bool
|
||||
isStatic*: bool
|
||||
|
@ -36,8 +36,8 @@ proc bigEndianToInt*(value: Bytes): UInt256 =
|
||||
# proc bitLength*(value: UInt256): int =
|
||||
# 255 - value.countLeadingZeroBits
|
||||
|
||||
proc log256*(value: UInt256): UInt256 =
|
||||
((255 - value.countLeadingZeroBits) div 8).u256
|
||||
proc log256*(value: UInt256): Natural =
|
||||
(255 - value.countLeadingZeroBits) div 8 # Compilers optimize to `shr 3`
|
||||
|
||||
# proc ceil8*(value: int): int =
|
||||
# let remainder = value mod 8
|
||||
@ -68,12 +68,12 @@ proc pseudoSignedToUnsigned*(value: UInt256): UInt256 =
|
||||
macro ceilXX(ceiling: static[int]): untyped =
|
||||
var name = ident(&"ceil{ceiling}")
|
||||
result = quote:
|
||||
proc `name`*(value: UInt256): UInt256 =
|
||||
var remainder = value mod `ceiling`.u256
|
||||
proc `name`*(value: Natural): Natural =
|
||||
var remainder = value mod `ceiling`
|
||||
if remainder == 0:
|
||||
return value
|
||||
else:
|
||||
return value + `ceiling`.u256 - remainder
|
||||
return value + `ceiling` - remainder
|
||||
|
||||
|
||||
ceilXX(32)
|
||||
|
@ -10,36 +10,36 @@ import
|
||||
|
||||
# TODO: Make that computation at compile-time.
|
||||
# Go-Ethereum uses pure uint64 for gas computation
|
||||
let BaseGasCosts*: GasCosts = [
|
||||
GasZero: 0.u256,
|
||||
GasBase: 2.u256,
|
||||
GasVeryLow: 3.u256,
|
||||
GasLow: 5.u256,
|
||||
GasMid: 8.u256,
|
||||
GasHigh: 10.u256,
|
||||
GasSload: 50.u256, # Changed to 200 in Tangerine (EIP150)
|
||||
GasJumpDest: 1.u256,
|
||||
GasSset: 20_000.u256,
|
||||
GasSreset: 5_000.u256,
|
||||
GasExtCode: 20.u256,
|
||||
GasCoinbase: 20.u256,
|
||||
GasSelfDestruct: 0.u256, # Changed to 5000 in Tangerine (EIP150)
|
||||
GasInHandler: 0.u256, # to be calculated in handler
|
||||
GasRefundSclear: 15000.u256,
|
||||
const BaseGasCosts*: GasCosts = [
|
||||
GasZero: 0'i64,
|
||||
GasBase: 2,
|
||||
GasVeryLow: 3,
|
||||
GasLow: 5,
|
||||
GasMid: 8,
|
||||
GasHigh: 10,
|
||||
GasSload: 50, # Changed to 200 in Tangerine (EIP150)
|
||||
GasJumpDest: 1,
|
||||
GasSset: 20_000,
|
||||
GasSreset: 5_000,
|
||||
GasExtCode: 20,
|
||||
GasCoinbase: 20,
|
||||
GasSelfDestruct: 0, # Changed to 5000 in Tangerine (EIP150)
|
||||
GasInHandler: 0, # to be calculated in handler
|
||||
GasRefundSclear: 15000,
|
||||
|
||||
GasBalance: 20.u256, # Changed to 400 in Tangerine (EIP150)
|
||||
GasCall: 40.u256, # Changed to 700 in Tangerine (EIP150)
|
||||
GasExp: 10.u256,
|
||||
GasSHA3: 30.u256
|
||||
GasBalance: 20, # Changed to 400 in Tangerine (EIP150)
|
||||
GasCall: 40, # Changed to 700 in Tangerine (EIP150)
|
||||
GasExp: 10,
|
||||
GasSHA3: 30
|
||||
]
|
||||
|
||||
proc tangerineGasCosts(baseCosts: GasCosts): GasCosts =
|
||||
|
||||
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md
|
||||
result = baseCosts
|
||||
result[GasSload] = 200.u256
|
||||
result[GasSelfDestruct] = 5000.u256
|
||||
result[GasBalance] = 400.u256
|
||||
result[GasCall] = 40.u256
|
||||
result[GasSload] = 200
|
||||
result[GasSelfDestruct] = 5000
|
||||
result[GasBalance] = 400
|
||||
result[GasCall] = 40
|
||||
|
||||
let TangerineGasCosts* = BaseGasCosts.tangerineGasCosts
|
||||
const TangerineGasCosts* = BaseGasCosts.tangerineGasCosts
|
||||
|
@ -7,25 +7,20 @@
|
||||
|
||||
import
|
||||
strformat,
|
||||
../logging, ../errors, ../constants, stint
|
||||
../logging, ../errors, ../types
|
||||
|
||||
type
|
||||
GasMeter* = ref object
|
||||
logger*: Logger
|
||||
gasRefunded*: UInt256
|
||||
startGas*: UInt256
|
||||
gasRemaining*: UInt256
|
||||
|
||||
proc newGasMeter*(startGas: UInt256): GasMeter =
|
||||
proc newGasMeter*(startGas: GasInt): GasMeter =
|
||||
new(result)
|
||||
result.startGas = startGas
|
||||
result.gasRemaining = result.startGas
|
||||
result.gasRefunded = 0.u256
|
||||
result.gasRefunded = 0
|
||||
result.logger = logging.getLogger("gas")
|
||||
|
||||
proc consumeGas*(gasMeter: var GasMeter; amount: UInt256; reason: string) =
|
||||
proc consumeGas*(gasMeter: var GasMeter; amount: GasInt; reason: string) =
|
||||
#if amount < 0.u256:
|
||||
# raise newException(ValidationError, "Gas consumption amount must be positive")
|
||||
# Alternatively: use a range type `range[0'i64 .. high(int64)]`
|
||||
# https://github.com/status-im/nimbus/issues/35#issuecomment-391726518
|
||||
if amount > gasMeter.gasRemaining:
|
||||
raise newException(OutOfGas,
|
||||
&"Out of gas: Needed {amount} - Remaining {gasMeter.gasRemaining} - Reason: {reason}")
|
||||
@ -33,16 +28,20 @@ proc consumeGas*(gasMeter: var GasMeter; amount: UInt256; reason: string) =
|
||||
gasMeter.logger.trace(
|
||||
&"GAS CONSUMPTION: {gasMeter.gasRemaining + amount} - {amount} -> {gasMeter.gasRemaining} ({reason})")
|
||||
|
||||
proc returnGas*(gasMeter: var GasMeter; amount: UInt256) =
|
||||
proc returnGas*(gasMeter: var GasMeter; amount: GasInt) =
|
||||
#if amount < 0.int256:
|
||||
# raise newException(ValidationError, "Gas return amount must be positive")
|
||||
# Alternatively: use a range type `range[0'i64 .. high(int64)]`
|
||||
# https://github.com/status-im/nimbus/issues/35#issuecomment-391726518
|
||||
gasMeter.gasRemaining += amount
|
||||
gasMeter.logger.trace(
|
||||
&"GAS RETURNED: {gasMeter.gasRemaining - amount} + {amount} -> {gasMeter.gasRemaining}")
|
||||
|
||||
proc refundGas*(gasMeter: var GasMeter; amount: UInt256) =
|
||||
proc refundGas*(gasMeter: var GasMeter; amount: GasInt) =
|
||||
#if amount < 0.int256:
|
||||
# raise newException(ValidationError, "Gas refund amount must be positive")
|
||||
# Alternatively: use a range type `range[0'i64 .. high(int64)]`
|
||||
# https://github.com/status-im/nimbus/issues/35#issuecomment-391726518
|
||||
gasMeter.gasRefunded += amount
|
||||
gasMeter.logger.trace(
|
||||
&"GAS REFUND: {gasMeter.gasRemaining - amount} + {amount} -> {gasMeter.gasRefunded}")
|
||||
|
@ -24,39 +24,39 @@ proc len*(memory: Memory): int =
|
||||
|
||||
|
||||
# TODO: why is the size passed as a UInt256?
|
||||
proc extend*(memory: var Memory; startPosition: UInt256; size: UInt256) =
|
||||
proc extend*(memory: var Memory; startPosition: Natural; size: Natural) =
|
||||
if size == 0:
|
||||
return
|
||||
var newSize = ceil32(startPosition + size)
|
||||
if newSize <= len(memory).u256:
|
||||
if newSize <= len(memory):
|
||||
return
|
||||
var sizeToExtend = newSize - len(memory).u256
|
||||
memory.bytes = memory.bytes.concat(repeat(0.byte, sizeToExtend.toInt))
|
||||
var sizeToExtend = newSize - len(memory)
|
||||
memory.bytes = memory.bytes.concat(repeat(0.byte, sizeToExtend))
|
||||
|
||||
proc newMemory*(size: UInt256): Memory =
|
||||
proc newMemory*(size: Natural): Memory =
|
||||
result = newMemory()
|
||||
result.extend(0.u256, size)
|
||||
result.extend(0, size)
|
||||
|
||||
# TODO: why is the size passed as a UInt256?
|
||||
proc read*(memory: var Memory, startPosition: UInt256, size: UInt256): seq[byte] =
|
||||
result = memory.bytes[startPosition.toInt ..< (startPosition + size).toInt]
|
||||
proc read*(memory: var Memory, startPosition: Natural, size: Natural): seq[byte] =
|
||||
result = memory.bytes[startPosition ..< (startPosition + size)]
|
||||
|
||||
# TODO: why is the size passed as a UInt256?
|
||||
proc write*(memory: var Memory, startPosition: UInt256, size: UInt256, value: seq[byte]) =
|
||||
proc write*(memory: var Memory, startPosition: Natural, size: Natural, value: seq[byte]) =
|
||||
if size == 0:
|
||||
return
|
||||
#echo size
|
||||
#echo startPosition
|
||||
#validateGte(startPosition, 0)
|
||||
#validateGte(size, 0)
|
||||
validateLength(value, size.toInt)
|
||||
validateLength(value, size)
|
||||
validateLte(startPosition + size, memory.len)
|
||||
let index = memory.len
|
||||
if memory.len.u256 < startPosition + size:
|
||||
memory.bytes = memory.bytes.concat(repeat(0.byte, memory.len - (startPosition + size).toInt)) # TODO: better logarithmic scaling?
|
||||
if memory.len < startPosition + size:
|
||||
memory.bytes = memory.bytes.concat(repeat(0.byte, memory.len - (startPosition + size))) # TODO: better logarithmic scaling?
|
||||
|
||||
for z, b in value:
|
||||
memory.bytes[z + startPosition.toInt] = b
|
||||
memory.bytes[z + startPosition] = b
|
||||
|
||||
template write*(memory: var Memory, startPosition: UInt256, size: UInt256, value: cstring) =
|
||||
template write*(memory: var Memory, startPosition: Natural, size: Natural, value: cstring) =
|
||||
memory.write(startPosition, size, value.toBytes)
|
||||
|
@ -6,46 +6,7 @@
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
../logging, ../constants, ../validation, stint
|
||||
|
||||
type
|
||||
Message* = ref object
|
||||
# A message for VM computation
|
||||
|
||||
# depth = None
|
||||
|
||||
# code = None
|
||||
# codeAddress = None
|
||||
|
||||
# createAddress = None
|
||||
|
||||
# shouldTransferValue = None
|
||||
# isStatic = None
|
||||
|
||||
# logger = logging.getLogger("evm.vm.message.Message")
|
||||
|
||||
gas*: UInt256
|
||||
gasPrice*: UInt256
|
||||
to*: string
|
||||
sender*: string
|
||||
value*: UInt256
|
||||
data*: seq[byte]
|
||||
code*: string
|
||||
internalOrigin: string
|
||||
internalCodeAddress: string
|
||||
depth*: int
|
||||
internalStorageAddress: string
|
||||
shouldTransferValue*: bool
|
||||
isStatic*: bool
|
||||
isCreate*: bool
|
||||
|
||||
MessageOptions* = ref object
|
||||
origin*: string
|
||||
depth*: int
|
||||
createAddress*: string
|
||||
codeAddress*: string
|
||||
shouldTransferValue*: bool
|
||||
isStatic*: bool
|
||||
../logging, ../constants, ../validation, stint, ../types
|
||||
|
||||
proc `origin=`*(message: var Message, value: string) =
|
||||
message.internalOrigin = value
|
||||
@ -73,8 +34,8 @@ proc newMessageOptions*(
|
||||
isStatic: isStatic)
|
||||
|
||||
proc newMessage*(
|
||||
gas: UInt256,
|
||||
gasPrice: UInt256,
|
||||
gas: GasInt,
|
||||
gasPrice: GasInt,
|
||||
to: string,
|
||||
sender: string,
|
||||
value: UInt256,
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
import unittest, macros, strformat, strutils, sequtils,
|
||||
stint,
|
||||
../src/[constants, opcode_values, errors, logging, vm/gas_meter]
|
||||
../src/[constants, opcode_values, errors, logging, types, vm/gas_meter]
|
||||
|
||||
# TODO: quicktest
|
||||
# PS: parametrize can be easily immitated, but still quicktests would be even more useful
|
||||
@ -15,7 +15,7 @@ import unittest, macros, strformat, strutils, sequtils,
|
||||
disableLogging()
|
||||
|
||||
proc gasMeters: seq[GasMeter] =
|
||||
@[newGasMeter(10.u256), newGasMeter(100.u256), newGasMeter(999.u256)]
|
||||
@[newGasMeter(10), newGasMeter(100), newGasMeter(999)]
|
||||
|
||||
macro all(element: untyped, handler: untyped): untyped =
|
||||
let name = ident(&"{element.repr}s")
|
||||
@ -84,15 +84,15 @@ suite "gasMeter":
|
||||
all(gasMeter):
|
||||
check(gasMeter.gasRemaining == gasMeter.startGas)
|
||||
expect(OutOfGas):
|
||||
gasMeter.consumeGas(gasMeter.startGas + 1.u256, "")
|
||||
gasMeter.consumeGas(gasMeter.startGas + 1, "")
|
||||
|
||||
test "return refund works correctly":
|
||||
all(gasMeter):
|
||||
check(gasMeter.gasRemaining == gasMeter.startGas)
|
||||
check(gasMeter.gasRefunded == 0)
|
||||
gasMeter.consumeGas(5.u256, "")
|
||||
check(gasMeter.gasRemaining == gasMeter.startGas - 5.u256)
|
||||
gasMeter.returnGas(5.u256)
|
||||
gasMeter.consumeGas(5, "")
|
||||
check(gasMeter.gasRemaining == gasMeter.startGas - 5)
|
||||
gasMeter.returnGas(5)
|
||||
check(gasMeter.gasRemaining == gasMeter.startGas)
|
||||
gasMeter.refundGas(5.u256)
|
||||
check(gasMeter.gasRefunded == 5.u256)
|
||||
gasMeter.refundGas(5)
|
||||
check(gasMeter.gasRefunded == 5)
|
||||
|
@ -11,17 +11,17 @@ import unittest, macros, strformat, strutils, sequtils,
|
||||
|
||||
proc memory32: Memory =
|
||||
result = newMemory()
|
||||
result.extend(0.u256, 32.u256)
|
||||
result.extend(0, 32)
|
||||
|
||||
proc memory128: Memory =
|
||||
result = newMemory()
|
||||
result.extend(0.u256, 128.u256)
|
||||
result.extend(0, 128)
|
||||
|
||||
suite "memory":
|
||||
test "write":
|
||||
var mem = memory32()
|
||||
# Test that write creates 32byte string == value padded with zeros
|
||||
mem.write(startPosition = 0.u256, size = 4.u256, value = @[1.byte, 0.byte, 1.byte, 0.byte])
|
||||
mem.write(startPosition = 0, size = 4, value = @[1.byte, 0.byte, 1.byte, 0.byte])
|
||||
check(mem.bytes == @[1.byte, 0.byte, 1.byte, 0.byte].concat(repeat(0.byte, 28)))
|
||||
|
||||
# test "write rejects invalid position":
|
||||
@ -47,28 +47,28 @@ suite "memory":
|
||||
test "write rejects invalid value":
|
||||
expect(ValidationError):
|
||||
var mem = memory32()
|
||||
mem.write(startPosition = 0.u256, size = 4.u256, value = @[1.byte, 0.byte])
|
||||
mem.write(startPosition = 0, size = 4, value = @[1.byte, 0.byte])
|
||||
|
||||
test "write rejects valyes beyond memory size":
|
||||
expect(ValidationError):
|
||||
var mem = memory128()
|
||||
mem.write(startPosition = 128.u256, size = 4.u256, value = @[1.byte, 0.byte, 1.byte, 0.byte])
|
||||
mem.write(startPosition = 128, size = 4, value = @[1.byte, 0.byte, 1.byte, 0.byte])
|
||||
|
||||
test "extends appropriately extends memory":
|
||||
var mem = newMemory()
|
||||
# Test extends to 32 byte array: 0 < (start_position + size) <= 32
|
||||
mem.extend(startPosition = 0.u256, size = 10.u256)
|
||||
mem.extend(startPosition = 0, size = 10)
|
||||
check(mem.bytes == repeat(0.byte, 32))
|
||||
# Test will extend past length if params require: 32 < (start_position + size) <= 64
|
||||
mem.extend(startPosition = 28.u256, size = 32.u256)
|
||||
mem.extend(startPosition = 28, size = 32)
|
||||
check(mem.bytes == repeat(0.byte, 64))
|
||||
# Test won't extend past length unless params require: 32 < (start_position + size) <= 64
|
||||
mem.extend(startPosition = 48.u256, size = 10.u256)
|
||||
mem.extend(startPosition = 48, size = 10)
|
||||
check(mem.bytes == repeat(0.byte, 64))
|
||||
|
||||
test "read returns correct bytes":
|
||||
var mem = memory32()
|
||||
mem.write(startPosition = 5.u256, size = 4.u256, value = @[1.byte, 0.byte, 1.byte, 0.byte])
|
||||
check(mem.read(startPosition = 5.u256, size = 4.u256) == @[1.byte, 0.byte, 1.byte, 0.byte])
|
||||
check(mem.read(startPosition = 6.u256, size = 4.u256) == @[0.byte, 1.byte, 0.byte, 0.byte])
|
||||
check(mem.read(startPosition = 1.u256, size = 3.u256) == @[0.byte, 0.byte, 0.byte])
|
||||
mem.write(startPosition = 5, size = 4, value = @[1.byte, 0.byte, 1.byte, 0.byte])
|
||||
check(mem.read(startPosition = 5, size = 4) == @[1.byte, 0.byte, 1.byte, 0.byte])
|
||||
check(mem.read(startPosition = 6, size = 4) == @[0.byte, 1.byte, 0.byte, 0.byte])
|
||||
check(mem.read(startPosition = 1, size = 3) == @[0.byte, 0.byte, 0.byte])
|
||||
|
@ -16,7 +16,7 @@ import
|
||||
test_helpers
|
||||
|
||||
|
||||
proc testCode(code: string, initialGas: UInt256, blockNum: UInt256): BaseComputation =
|
||||
proc testCode(code: string, initialGas: GasInt, blockNum: UInt256): BaseComputation =
|
||||
let header = BlockHeader(blockNumber: blockNum)
|
||||
var vm = newNimbusVM(header, newBaseChainDB(newMemoryDB()))
|
||||
# coinbase: "",
|
||||
@ -32,7 +32,7 @@ proc testCode(code: string, initialGas: UInt256, blockNum: UInt256): BaseComputa
|
||||
data = @[],
|
||||
code=code,
|
||||
gas=initial_gas,
|
||||
gasPrice=1.u256) # What is this used for?
|
||||
gasPrice=1) # What is this used for?
|
||||
# gasPrice=fixture{"exec"}{"gasPrice"}.getHexadecimalInt.u256,
|
||||
#options=newMessageOptions(origin=fixture{"exec"}{"origin"}.getStr))
|
||||
|
||||
@ -53,10 +53,10 @@ suite "opcodes":
|
||||
test "add":
|
||||
var c = testCode(
|
||||
"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01",
|
||||
100_000.u256,
|
||||
100_000,
|
||||
0.u256
|
||||
)
|
||||
check(c.gasMeter.gasRemaining == 99_991.u256)
|
||||
check(c.gasMeter.gasRemaining == 99_991)
|
||||
check(c.stack.peek == "115792089237316195423570985008687907853269984665640564039457584007913129639934".u256)
|
||||
# let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||
# let code = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01600055".from_hex().unwrap();
|
||||
@ -80,33 +80,33 @@ suite "opcodes":
|
||||
block: # Using Balance (0x31)
|
||||
var c = testCode(
|
||||
"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff31",
|
||||
100_000.u256,
|
||||
100_000,
|
||||
0.u256
|
||||
)
|
||||
check: c.gasMeter.gasRemaining == 100000.u256 - 3.u256 - 20.u256 # Starting gas - push32 (verylow) - balance
|
||||
check: c.gasMeter.gasRemaining == 100000 - 3 - 20 # Starting gas - push32 (verylow) - balance
|
||||
|
||||
block: # Using SLOAD (0x54)
|
||||
var c = testCode(
|
||||
"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff54",
|
||||
100_000.u256,
|
||||
100_000,
|
||||
0.u256
|
||||
)
|
||||
check: c.gasMeter.gasRemaining == 100000.u256 - 3.u256 - 50.u256 # Starting gas - push32 (verylow) - SLOAD
|
||||
check: c.gasMeter.gasRemaining == 100000 - 3 - 50 # Starting gas - push32 (verylow) - SLOAD
|
||||
|
||||
|
||||
test "Tangerine VM computation - post-EIP150 gas cost properly applied":
|
||||
block: # Using Balance (0x31)
|
||||
var c = testCode(
|
||||
"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff31",
|
||||
100_000.u256,
|
||||
100_000,
|
||||
2_463_000.u256 # Tangerine block
|
||||
)
|
||||
check: c.gasMeter.gasRemaining == 100000.u256 - 3.u256 - 400.u256 # Starting gas - push32 (verylow) - balance
|
||||
check: c.gasMeter.gasRemaining == 100000 - 3 - 400 # Starting gas - push32 (verylow) - balance
|
||||
|
||||
block: # Using SLOAD (0x54)
|
||||
var c = testCode(
|
||||
"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff54",
|
||||
100_000.u256,
|
||||
100_000,
|
||||
2_463_000.u256
|
||||
)
|
||||
check: c.gasMeter.gasRemaining == 100000.u256 - 3.u256 - 200.u256 # Starting gas - push32 (verylow) - SLOAD
|
||||
check: c.gasMeter.gasRemaining == 100000 - 3 - 200 # Starting gas - push32 (verylow) - SLOAD
|
||||
|
@ -45,8 +45,8 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
||||
value=fixture{"exec"}{"value"}.getHexadecimalInt.u256,
|
||||
data=fixture{"exec"}{"data"}.getStr.mapIt(it.byte),
|
||||
code=code,
|
||||
gas=fixture{"exec"}{"gas"}.getHexadecimalInt.u256,
|
||||
gasPrice=fixture{"exec"}{"gasPrice"}.getHexadecimalInt.u256,
|
||||
gas=fixture{"exec"}{"gas"}.getHexadecimalInt,
|
||||
gasPrice=fixture{"exec"}{"gasPrice"}.getHexadecimalInt,
|
||||
options=newMessageOptions(origin=fixture{"exec"}{"origin"}.getStr))
|
||||
|
||||
#echo fixture{"exec"}
|
||||
@ -81,7 +81,7 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
||||
check(computation.output == expectedOutput)
|
||||
let gasMeter = computation.gasMeter
|
||||
|
||||
let expectedGasRemaining = fixture{"gas"}.getHexadecimalInt.u256
|
||||
let expectedGasRemaining = fixture{"gas"}.getHexadecimalInt
|
||||
let actualGasRemaining = gasMeter.gasRemaining
|
||||
checkpoint(&"{actualGasRemaining} {expectedGasRemaining}")
|
||||
check(actualGasRemaining == expectedGasRemaining or
|
||||
@ -100,7 +100,7 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
||||
var (childComputation, createdCall) = child
|
||||
let toAddress = createdCall{"destination"}.getStr
|
||||
let data = createdCall{"data"}.getStr.mapIt(it.byte)
|
||||
let gasLimit = createdCall{"gasLimit"}.getHexadecimalInt.u256
|
||||
let gasLimit = createdCall{"gasLimit"}.getHexadecimalInt
|
||||
let value = createdCall{"value"}.getHexadecimalInt.u256
|
||||
|
||||
check(childComputation.msg.to == toAddress)
|
||||
|
Loading…
x
Reference in New Issue
Block a user