Gas & Memory ops refactoring - uses native integer instead of uint256 fixes #35 and #39 (#40)

* Gas refactoring - uses int64

* Use primitive int in test_vm_json
This commit is contained in:
Mamy Ratsimbazafy 2018-05-25 12:25:19 +02:00 committed by GitHub
parent c77b7cd035
commit cb49352b6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 263 additions and 244 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -55,4 +55,4 @@ proc pc*(computation) =
proc gas*(computation) =
let gasRemaining = gasMeter.gasRemaining
stack.push(gasRemaining)
stack.push(gasRemaining.u256)

View File

@ -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`,

View File

@ -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) =

View File

@ -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("")

View File

@ -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})")

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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}")

View File

@ -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)

View File

@ -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,

View File

@ -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)

View File

@ -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])

View File

@ -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

View File

@ -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)