mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-02-24 01:38:33 +00:00
Pass more tests, use UInt256 more often
82 / 189 arithmetic 55 / 62 logic 77 / 78 stack Most errors are the same sstore gascost bug, also next work on flow and memory
This commit is contained in:
parent
aa1970013d
commit
99921f38cb
@ -10,7 +10,7 @@ skipDirs = @["tests"]
|
||||
requires "nim >= 0.17.0",
|
||||
"https://github.com/status-im/nim-keccak-tiny.git >= 0.1.0",
|
||||
"https://github.com/status-im/nim-rlp.git >= 1.0.0",
|
||||
"https://github.com/status-im/nim-ttmath >= 0.2.0"
|
||||
"https://github.com/status-im/nim-ttmath >= 0.5.0"
|
||||
|
||||
|
||||
|
||||
|
@ -3,12 +3,12 @@ import
|
||||
|
||||
type
|
||||
Account* = ref object
|
||||
nonce*: Int256
|
||||
balance*: Int256
|
||||
nonce*: UInt256
|
||||
balance*: UInt256
|
||||
storageRoot*: string
|
||||
codeHash*: string
|
||||
|
||||
rlpFields Account, nonce, balance
|
||||
|
||||
proc newAccount*(nonce: Int256 = 0.i256, balance: Int256 = 0.i256): Account =
|
||||
proc newAccount*(nonce: UInt256 = 0.u256, balance: UInt256 = 0.u256): Account =
|
||||
Account(nonce: nonce, balance: balance)
|
||||
|
@ -8,4 +8,4 @@ type
|
||||
Block* = ref object of RootObj
|
||||
header*: Header
|
||||
uncles*: CountableList[Header]
|
||||
blockNumber*: Int256
|
||||
blockNumber*: UInt256
|
||||
|
@ -1,9 +1,9 @@
|
||||
import
|
||||
strformat, strutils, sequtils, tables, macros, ttmath,
|
||||
strformat, strutils, sequtils, tables, macros, ttmath, terminal,
|
||||
constants, errors, utils/hexadecimal, utils_numeric, validation, vm_state, logging, opcode_values,
|
||||
vm / [code_stream, gas_meter, memory, message, stack]
|
||||
|
||||
proc memoryGasCost*(sizeInBytes: Int256): Int256 =
|
||||
proc memoryGasCost*(sizeInBytes: UInt256): UInt256 =
|
||||
var
|
||||
sizeInWords = ceil32(sizeInBytes) div 32
|
||||
linearCost = sizeInWords * GAS_MEMORY
|
||||
@ -26,7 +26,7 @@ type
|
||||
rawOutput*: string
|
||||
returnData*: string
|
||||
error*: Error
|
||||
logEntries*: seq[(string, seq[Int256], string)]
|
||||
logEntries*: seq[(string, seq[UInt256], string)]
|
||||
shouldEraseReturnData*: bool
|
||||
accountsToDelete*: Table[string, string]
|
||||
opcodes*: Table[Op, Opcode] # TODO array[Op, Opcode]
|
||||
@ -40,9 +40,9 @@ type
|
||||
Opcode* = ref object of RootObj
|
||||
case kind*: Op
|
||||
of VARIABLE_GAS_COST_OPS:
|
||||
gasCostHandler*: proc(computation: var BaseComputation): Int256
|
||||
gasCostHandler*: proc(computation: var BaseComputation): UInt256
|
||||
else:
|
||||
gasCostConstant*: Int256
|
||||
gasCostConstant*: UInt256
|
||||
runLogic*: proc(computation: var BaseComputation)
|
||||
|
||||
proc newBaseComputation*(vmState: BaseVMState, message: Message): BaseComputation =
|
||||
@ -87,9 +87,9 @@ method shouldEraseReturnData*(c: BaseComputation): bool =
|
||||
|
||||
method prepareChildMessage*(
|
||||
c: var BaseComputation,
|
||||
gas: Int256,
|
||||
gas: UInt256,
|
||||
to: string,
|
||||
value: Int256,
|
||||
value: UInt256,
|
||||
data: seq[byte],
|
||||
code: string,
|
||||
options: MessageOptions = newMessageOptions()): Message =
|
||||
@ -106,13 +106,13 @@ method prepareChildMessage*(
|
||||
code,
|
||||
childOptions)
|
||||
|
||||
method extendMemory*(c: var BaseComputation, startPosition: Int256, size: Int256) =
|
||||
method extendMemory*(c: var BaseComputation, startPosition: UInt256, size: UInt256) =
|
||||
# Memory Management
|
||||
#
|
||||
# validate_uint256(start_position, title="Memory start position")
|
||||
# validate_uint256(size, title="Memory size")
|
||||
|
||||
let beforeSize = ceil32(len(c.memory).int256)
|
||||
let beforeSize = ceil32(len(c.memory).u256)
|
||||
let afterSize = ceil32(startPosition + size)
|
||||
|
||||
let beforeCost = memoryGasCost(beforeSize)
|
||||
@ -182,7 +182,7 @@ method registerAccountForDeletion*(c: var BaseComputation, beneficiary: string)
|
||||
"registered for deletion multiple times")
|
||||
c.accountsToDelete[c.msg.storageAddress] = beneficiary
|
||||
|
||||
method addLogEntry*(c: var BaseComputation, account: string, topics: seq[Int256], data: string) =
|
||||
method addLogEntry*(c: var BaseComputation, account: string, topics: seq[UInt256], data: string) =
|
||||
validateCanonicalAddress(account, title="log entry address")
|
||||
c.logEntries.add((account, topics, data))
|
||||
|
||||
@ -193,28 +193,28 @@ method getAccountsForDeletion*(c: BaseComputation): seq[(string, string)] =
|
||||
else:
|
||||
result = @[]
|
||||
|
||||
method getLogEntries*(c: BaseComputation): seq[(string, seq[Int256], string)] =
|
||||
method getLogEntries*(c: BaseComputation): seq[(string, seq[UInt256], string)] =
|
||||
# TODO
|
||||
if c.isError:
|
||||
result = @[]
|
||||
else:
|
||||
result = @[]
|
||||
|
||||
method getGasRefund*(c: BaseComputation): Int256 =
|
||||
method getGasRefund*(c: BaseComputation): UInt256 =
|
||||
if c.isError:
|
||||
result = 0.int256
|
||||
result = 0.u256
|
||||
else:
|
||||
result = c.gasMeter.gasRefunded + c.children.mapIt(it.getGasRefund()).foldl(a + b, 0.int256)
|
||||
result = c.gasMeter.gasRefunded + c.children.mapIt(it.getGasRefund()).foldl(a + b, 0.u256)
|
||||
|
||||
method getGasUsed*(c: BaseComputation): Int256 =
|
||||
method getGasUsed*(c: BaseComputation): UInt256 =
|
||||
if c.shouldBurnGas:
|
||||
result = c.msg.gas
|
||||
else:
|
||||
result = max(0.int256, c.msg.gas - c.gasMeter.gasRemaining)
|
||||
result = max(0.u256, c.msg.gas - c.gasMeter.gasRemaining)
|
||||
|
||||
method getGasRemaining*(c: BaseComputation): Int256 =
|
||||
method getGasRemaining*(c: BaseComputation): UInt256 =
|
||||
if c.shouldBurnGas:
|
||||
result = 0.int256
|
||||
result = 0.u256
|
||||
else:
|
||||
result = c.gasMeter.gasRemaining
|
||||
|
||||
@ -295,6 +295,7 @@ macro applyComputation*(t: typed, vmState: untyped, message: untyped): untyped =
|
||||
opcode.run(c)
|
||||
except Halt:
|
||||
break
|
||||
c.logger.log($c.stack & "\n\n", fgGreen)
|
||||
return c
|
||||
inComputation(c):
|
||||
res = handler()
|
||||
|
@ -1,10 +1,14 @@
|
||||
|
||||
import
|
||||
ttmath, math, strutils, tables, utils/padding
|
||||
ttmath, math, strutils, tables, utils/padding, rlp
|
||||
|
||||
# rlpFields UInt256, table
|
||||
|
||||
type
|
||||
TypeHint* {.pure.} = enum UInt256, Bytes, Any
|
||||
|
||||
Bytes* = seq[byte]
|
||||
|
||||
# Int256* = BigInt #distinct int # TODO
|
||||
|
||||
proc int256*(i: int): Int256 =
|
||||
@ -16,6 +20,12 @@ proc int256*(i: int): Int256 =
|
||||
template i256*(i: Int256): Int256 =
|
||||
i
|
||||
|
||||
template u256*(i: int): UInt256 =
|
||||
i.uint.u256
|
||||
|
||||
template u256*(i: UInt256): UInt256 =
|
||||
i
|
||||
|
||||
template getInt*(i: int): int =
|
||||
i
|
||||
|
||||
@ -28,10 +38,16 @@ proc `==`*(a: Int256, b: int): bool =
|
||||
proc `!=`*(a: Int256, b: int): bool =
|
||||
a != b.i256
|
||||
|
||||
proc `^`*(base: int; exp: int): Int256 =
|
||||
let base = base.i256
|
||||
proc `==`*(a: UInt256, b: int): bool =
|
||||
a == b.u256
|
||||
|
||||
proc `!=`*(a: UInt256, b: int): bool =
|
||||
a != b.u256
|
||||
|
||||
proc `^`*(base: int; exp: int): UInt256 =
|
||||
let base = base.u256
|
||||
var ex = exp
|
||||
result = 1.i256
|
||||
result = 1.u256
|
||||
while ex > 0:
|
||||
result *= base
|
||||
dec(ex)
|
||||
@ -44,22 +60,47 @@ proc `^`*(left: Int256, right: int): Int256 =
|
||||
result = result * m
|
||||
value -= 1.i256
|
||||
|
||||
proc `^`*(left: UInt256, right: int): UInt256 =
|
||||
var value = right.u256
|
||||
result = 1.u256
|
||||
var m = right.u256
|
||||
while value > 0.u256:
|
||||
result = result * m
|
||||
value -= 1.u256
|
||||
|
||||
|
||||
proc `>`*(a: Int256, b: int): bool =
|
||||
a > b.i256
|
||||
|
||||
proc `<`*(a: Int256, b: int): bool =
|
||||
a < b.i256
|
||||
|
||||
proc `>`*(a: UInt256, b: int): bool =
|
||||
a > b.u256
|
||||
|
||||
proc `<`*(a: UInt256, b: int): bool =
|
||||
a < b.u256
|
||||
|
||||
proc `mod`*(a: Int256, b: int): Int256 =
|
||||
a mod b.i256
|
||||
|
||||
proc `div`*(a: Int256, b: int): Int256 =
|
||||
a div b.i256
|
||||
|
||||
proc `mod`*(a: UInt256, b: int): UInt256 =
|
||||
a mod b.u256
|
||||
|
||||
proc `div`*(a: UInt256, b: int): UInt256 =
|
||||
a div b.u256
|
||||
|
||||
proc log256*(a: Int256): Int256 =
|
||||
# TODO
|
||||
2.i256
|
||||
|
||||
proc log256*(a: UInt256): UInt256 =
|
||||
# TODO
|
||||
2.u256
|
||||
|
||||
proc setXLen[T](s: var seq[T]; newlen: Natural) =
|
||||
if s.isNil:
|
||||
s = newSeq[T](newlen)
|
||||
@ -69,13 +110,11 @@ proc setXLen[T](s: var seq[T]; newlen: Natural) =
|
||||
template mapOp(op: untyped): untyped =
|
||||
proc `op`*(left: Int256, right: int): Int256 =
|
||||
result = left.i256
|
||||
result = `op`(result, right.i256) # for now we dont have so many bits
|
||||
# var maxRight = right.i256
|
||||
# var l = max(left.limbs.len, right.limbs.len)
|
||||
# result.limbs.setXLen(l)
|
||||
# maxRight.limbs.setXLen(l)
|
||||
# for z in 0 ..< l:
|
||||
# result.limbs[z] = `op`(result.limbs[z], maxRight.limbs[z])
|
||||
result = `op`(result, right.i256)
|
||||
|
||||
proc `op`*(left: UInt256, right: int): UInt256 =
|
||||
result = left.u256
|
||||
result = `op`(result, right.u256)
|
||||
|
||||
mapOp(`and`)
|
||||
mapOp(`or`)
|
||||
@ -84,109 +123,115 @@ mapOp(`xor`)
|
||||
proc `abs`*(a: Int256): Int256 =
|
||||
if a >= 0.i256: a else: -a
|
||||
|
||||
# constants
|
||||
|
||||
let
|
||||
UINT_256_MAX*: Int256 = 2 ^ 256 - 1.i256
|
||||
UINT_256_CEILING*: Int256 = 2 ^ 256
|
||||
UINT_255_MAX*: Int256 = 2 ^ (256 - 1) - 1.i256
|
||||
UINT_255_CEILING*: Int256 = 2 ^ (256 - 1)
|
||||
UINT_256_MAX*: UInt256 = 2 ^ 256 - 1.u256
|
||||
UINT_256_CEILING*: UInt256 = 2 ^ 256
|
||||
UINT_255_MAX*: UInt256 = 2 ^ (255 - 1) - 1.u256
|
||||
UINT_255_CEILING*: UInt256 = 2 ^ 255
|
||||
UINT_256_CEILING_INT*: Int256 = 2.i256 ^ 256
|
||||
UINT_255_MAX_INT*: Int256 = 2.i256 ^ (255 - 1) - 1.i256
|
||||
UINT_256_MAX_INT*: Int256 = 2.i256 ^ 256 - 1.i256
|
||||
UINT_255_CEILING_INT*: Int256 = 2.i256 ^ 255
|
||||
|
||||
NULLBYTE* = "\x00"
|
||||
EMPTYWORD* = repeat(NULLBYTE, 32)
|
||||
UINT160CEILING*: Int256 = 2 ^ 160
|
||||
UINT160CEILING*: UInt256 = 2 ^ 160
|
||||
CREATE_CONTRACT_ADDRESS* = ""
|
||||
ZERO_ADDRESS* = repeat("\x00", 20)
|
||||
ZERO_HASH32* = repeat("\x00", 20)
|
||||
STACK_DEPTH_LIMIT* = 1024
|
||||
|
||||
GAS_NULL* = 0.i256
|
||||
GAS_ZERO* = 0.i256
|
||||
GAS_BASE* = 2.i256
|
||||
GAS_VERY_LOW* = 3.i256
|
||||
GAS_LOW* = 5.i256
|
||||
GAS_MID* = 8.i256
|
||||
GAS_HIGH* = 10.i256
|
||||
GAS_EXT_CODE* = 20.i256
|
||||
GAS_BALANCE* = 20.i256
|
||||
GAS_SLOAD* = 50.i256
|
||||
GAS_JUMP_DEST* = 1.i256
|
||||
GAS_SSET* = 20_000.i256
|
||||
GAS_SRESET* = 5000.i256
|
||||
GAS_EXT_CODE_COST* = 700.i256
|
||||
GAS_COINBASE* = 20.i256
|
||||
GAS_SLOAD_COST* = 20.i256
|
||||
GAS_SELF_DESTRUCT_COST* = 5_000.i256
|
||||
GAS_IN_HANDLER* = 0.i256 # to be calculated in handler
|
||||
REFUNDS_CLEAR* = 15_000.i256
|
||||
GAS_NULL* = 0.u256
|
||||
GAS_ZERO* = 0.u256
|
||||
GAS_BASE* = 2.u256
|
||||
GAS_VERY_LOW* = 3.u256
|
||||
GAS_LOW* = 5.u256
|
||||
GAS_MID* = 8.u256
|
||||
GAS_HIGH* = 10.u256
|
||||
GAS_EXT_CODE* = 20.u256
|
||||
GAS_BALANCE* = 20.u256
|
||||
GAS_SLOAD* = 50.u256
|
||||
GAS_JUMP_DEST* = 1.u256
|
||||
GAS_SSET* = 20_000.u256
|
||||
GAS_SRESET* = 5_000.u256
|
||||
GAS_EXT_CODE_COST* = 700.u256
|
||||
GAS_COINBASE* = 20.u256
|
||||
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
|
||||
|
||||
GAS_SELF_DESTRUCT* = 0.i256
|
||||
GAS_SELF_DESTRUCT_NEW_ACCOUNT* = 25_000.i256
|
||||
GAS_CREATE* = 32_000.i256
|
||||
GAS_CALL* = 40.i256
|
||||
GAS_CALL_VALUE* = 9_000.i256
|
||||
GAS_CALL_STIPEND* = 2_300.i256
|
||||
GAS_NEW_ACCOUNT* = 25_000.i256
|
||||
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_COST_BALANCE* = 400.i256
|
||||
GAS_COST_BALANCE* = 400.u256
|
||||
|
||||
GAS_EXP* = 10.i256
|
||||
GAS_EXP_BYTE* = 10.i256
|
||||
GAS_MEMORY* = 3.i256
|
||||
GAS_TX_CREATE* = 32_000.i256
|
||||
GAS_TX_DATA_ZERO* = 4.i256
|
||||
GAS_TX_DATA_NON_ZERO* = 68.i256
|
||||
GAS_TX* = 21_000.i256
|
||||
GAS_LOG* = 375.i256
|
||||
GAS_LOG_DATA* = 8.i256
|
||||
GAS_LOG_TOPIC* = 375.i256
|
||||
GAS_SHA3* = 30.i256
|
||||
GAS_SHA3_WORD* = 6.i256
|
||||
GAS_COPY* = 3.i256
|
||||
GAS_BLOCK_HASH* = 20.i256
|
||||
GAS_CODE_DEPOSIT* = 200.i256
|
||||
GAS_MEMORY_QUADRATIC_DENOMINATOR* = 512.i256
|
||||
GAS_SHA256* = 60.i256
|
||||
GAS_SHA256WORD* = 12.i256
|
||||
GAS_RIP_EMD160* = 600.i256
|
||||
GAS_RIP_EMD160WORD* = 120.i256
|
||||
GAS_IDENTITY* = 15.i256
|
||||
GAS_EXP* = 10.u256
|
||||
GAS_EXP_BYTE* = 10.u256
|
||||
GAS_MEMORY* = 3.u256
|
||||
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_SHA3* = 30.u256
|
||||
GAS_SHA3_WORD* = 6.u256
|
||||
GAS_COPY* = 3.u256
|
||||
GAS_BLOCK_HASH* = 20.u256
|
||||
GAS_CODE_DEPOSIT* = 200.u256
|
||||
GAS_MEMORY_QUADRATIC_DENOMINATOR* = 512.u256
|
||||
GAS_SHA256* = 60.u256
|
||||
GAS_SHA256WORD* = 12.u256
|
||||
GAS_RIP_EMD160* = 600.u256
|
||||
GAS_RIP_EMD160WORD* = 120.u256
|
||||
GAS_IDENTITY* = 15.u256
|
||||
GAS_IDENTITY_WORD* = 3
|
||||
GAS_ECRECOVER* = 3_000.i256
|
||||
GAS_ECADD* = 500.i256
|
||||
GAS_ECMUL* = 40_000.i256
|
||||
GAS_ECPAIRING_BASE* = 100_000.i256
|
||||
GAS_ECPAIRING_PER_POINT* = 80_000.i256
|
||||
GAS_LIMIT_EMA_DENOMINATOR* = 1_024.i256
|
||||
GAS_LIMIT_ADJUSTMENT_FACTOR* = 1_024.i256
|
||||
GAS_LIMIT_MAXIMUM*: Int256 = 2 ^ 63 - 1.i256
|
||||
GAS_LIMIT_USAGE_ADJUSTMENT_NUMERATOR* = 3.i256
|
||||
GAS_LIMIT_USAGE_ADJUSTMENT_DENOMINATOR* = 2.i256
|
||||
GAS_ECRECOVER* = 3_000.u256
|
||||
GAS_ECADD* = 500.u256
|
||||
GAS_ECMUL* = 40_000.u256
|
||||
GAS_ECPAIRING_BASE* = 100_000.u256
|
||||
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_USAGE_ADJUSTMENT_NUMERATOR* = 3.u256
|
||||
GAS_LIMIT_USAGE_ADJUSTMENT_DENOMINATOR* = 2.u256
|
||||
|
||||
DIFFICULTY_ADJUSTMENT_DENOMINATOR* = 2_048.i256
|
||||
DIFFICULTY_MINIMUM* = 131_072.i256
|
||||
DIFFICULTY_ADJUSTMENT_DENOMINATOR* = 2_048.u256
|
||||
DIFFICULTY_MINIMUM* = 131_072.u256
|
||||
|
||||
BOMB_EXPONENTIAL_PERIOD* = 100_000.i256
|
||||
BOMB_EXPONENTIAL_FREE_PERIODS* = 2.i256
|
||||
BOMB_EXPONENTIAL_PERIOD* = 100_000.u256
|
||||
BOMB_EXPONENTIAL_FREE_PERIODS* = 2.u256
|
||||
|
||||
BLOCK_REWARD* = 5.i256 * 2.i256 # denoms.ether
|
||||
BLOCK_REWARD* = 5.u256 * 2.u256 # denoms.ether
|
||||
|
||||
UNCLE_DEPTH_PENALTY_FACTOR* = 8.i256
|
||||
UNCLE_DEPTH_PENALTY_FACTOR* = 8.u256
|
||||
|
||||
MAX_UNCLE_DEPTH* = 6.i256
|
||||
MAX_UNCLES* = 2.i256
|
||||
MAX_UNCLE_DEPTH* = 6.u256
|
||||
MAX_UNCLES* = 2.u256
|
||||
|
||||
SECPK1_P*: Int256 = 2 ^ 256 - 2 ^ 32 - 977.i256
|
||||
SECPK1_N*: Int256 = "115792089237316195423570985008687907852837564279074904382605163141518161494337".i256
|
||||
SECPK1_A* = 0.i256
|
||||
SECPK1_B* = 7.i256
|
||||
SECPK1_Gx* = 0.i256
|
||||
SECPK1_Gy* = 0.i256
|
||||
SECPK1_P*: UInt256 = 2 ^ 256 - 2 ^ 32 - 977.u256
|
||||
SECPK1_N*: UInt256 = "115792089237316195423570985008687907852837564279074904382605163141518161494337".u256
|
||||
SECPK1_A* = 0.u256
|
||||
SECPK1_B* = 7.u256
|
||||
SECPK1_Gx* = 0.u256
|
||||
SECPK1_Gy* = 0.u256
|
||||
SECPK1_G* = (SECPK1Gx, SECPK1Gy)
|
||||
|
||||
EMPTY_UNCLE_HASH* = "\x1d\xccM\xe8\xde\xc7]z\xab\x85\xb5g\xb6\xcc\xd4\x1a\xd3\x12E\x1b\x94\x8at\x13\xf0\xa1B\xfd@\xd4\x93G"
|
||||
|
||||
GENESIS_BLOCK_NUMBER* = 0.i256
|
||||
GENESIS_DIFFICULTY* = 131_072.i256
|
||||
GENESIS_GAS_LIMIT* = 3_141_592.i256
|
||||
GENESIS_BLOCK_NUMBER* = 0.u256
|
||||
GENESIS_DIFFICULTY* = 131_072.u256
|
||||
GENESIS_GAS_LIMIT* = 3_141_592.u256
|
||||
GENESIS_PARENT_HASH* = ZERO_HASH32
|
||||
GENESIS_COINBASE* = ZERO_ADDRESS
|
||||
GENESIS_NONCE* = "\x00\x00\x00\x00\x00\x00\x00B"
|
||||
@ -196,7 +241,7 @@ let
|
||||
EMPTYSHA3 = "\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p"
|
||||
BLANK_ROOT_HASH* = "V\xe8\x1f\x17\x1b\xccU\xa6\xff\x83E\xe6\x92\xc0\xf8n[H\xe0\x1b\x99l\xad\xc0\x01b/\xb5\xe3c\xb4!"
|
||||
|
||||
GAS_MOD_EXP_QUADRATIC_DENOMINATOR* = 20.i256
|
||||
GAS_MOD_EXP_QUADRATIC_DENOMINATOR* = 20.u256
|
||||
|
||||
MAX_PREV_HEADER_DEPTH* = 256.i256
|
||||
MAX_PREV_HEADER_DEPTH* = 256.u256
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
import
|
||||
strformat, tables,
|
||||
../constants, ../errors, ../validation, ../account, ../logging, ../utils/keccak, ttmath
|
||||
../constants, ../errors, ../validation, ../account, ../logging, ../utils_numeric, .. / utils / [padding, bytes, keccak], ttmath, rlp
|
||||
|
||||
type
|
||||
AccountStateDB* = ref object
|
||||
db*: Table[string, string]
|
||||
db*: Table[string, UInt256]
|
||||
rootHash*: string # TODO trie
|
||||
|
||||
proc newAccountStateDB*(db: Table[string, string], readOnly: bool = false): AccountStateDB =
|
||||
result = AccountStateDB(db: db)
|
||||
result = AccountStateDB(db: initTable[string, UInt256]())
|
||||
|
||||
proc logger*(db: AccountStateDB): Logger =
|
||||
logging.getLogger("db.State")
|
||||
@ -32,68 +32,72 @@ proc getCodeHash*(db: AccountStateDB, address: string): string =
|
||||
let account = db.getAccount(address)
|
||||
result = account.codeHash
|
||||
|
||||
proc getBalance*(db: AccountStateDB, address: string): Int256 =
|
||||
proc getBalance*(db: AccountStateDB, address: string): UInt256 =
|
||||
validateCanonicalAddress(address, title="Storage Address")
|
||||
let account = db.getAccount(address)
|
||||
account.balance
|
||||
|
||||
proc setBalance*(db: var AccountStateDB, address: string, balance: Int256) =
|
||||
proc setBalance*(db: var AccountStateDB, address: string, balance: UInt256) =
|
||||
validateCanonicalAddress(address, title="Storage Address")
|
||||
let account = db.getAccount(address)
|
||||
account.balance = balance
|
||||
db.setAccount(address, account)
|
||||
|
||||
proc deltaBalance*(db: var AccountStateDB, address: string, delta: Int256) =
|
||||
proc deltaBalance*(db: var AccountStateDB, address: string, delta: UInt256) =
|
||||
db.setBalance(address, db.getBalance(address) + delta)
|
||||
|
||||
|
||||
proc setStorage*(db: var AccountStateDB, address: string, slot: Int256, value: Int256) =
|
||||
validateGte(value, 0, title="Storage Value")
|
||||
validateGte(slot, 0, title="Storage Slot")
|
||||
proc setStorage*(db: var AccountStateDB, address: string, slot: UInt256, value: UInt256) =
|
||||
#validateGte(value, 0, title="Storage Value")
|
||||
#validateGte(slot, 0, title="Storage Slot")
|
||||
validateCanonicalAddress(address, title="Storage Address")
|
||||
|
||||
let account = db.getAccount(address)
|
||||
|
||||
# TODO
|
||||
# let account = db.getAccount(address)
|
||||
# var storage = HashTrie(HexaryTrie(self.db, account.storageRoot))
|
||||
|
||||
# let slotAsKey = pad32(intToBigEndian(slot))
|
||||
|
||||
# if value:
|
||||
# let encodedValue = rlp.encode(value)
|
||||
# storage[slotAsKey] = encodedValue
|
||||
# else:
|
||||
# del storage[slotAsKey]
|
||||
|
||||
let slotAsKey = slot.intToBigEndian.pad32.toString
|
||||
var storage = db.db
|
||||
# TODO fix
|
||||
#if value > 0:
|
||||
# let encodedValue = rlp.encode(value)
|
||||
# storage[slotAsKey] = encodedValue
|
||||
#else:
|
||||
# storage.del(slotAsKey)
|
||||
storage[slotAsKey] = value
|
||||
# account.storageRoot = storage.rootHash
|
||||
# db.setAccount(address, account)
|
||||
|
||||
proc getStorage*(db: var AccountStateDB, address: string, slot: Int256): Int256 =
|
||||
proc getStorage*(db: var AccountStateDB, address: string, slot: UInt256): UInt256 =
|
||||
validateCanonicalAddress(address, title="Storage Address")
|
||||
validateGte(slot, 0, title="Storage Slot")
|
||||
0.i256
|
||||
#validateGte(slot, 0, title="Storage Slot")
|
||||
|
||||
# TODO
|
||||
# make it more correct
|
||||
# for now, we just use a table
|
||||
|
||||
# let account = db.GetAccount(address)
|
||||
# var storage = HashTrie(HexaryTrie(self.db, account.storageRoot))
|
||||
|
||||
# let slotAsKey = pad32(intToBigEndian(slot))
|
||||
let slotAsKey = slot.intToBigEndian.pad32.toString
|
||||
var storage = db.db
|
||||
if storage.hasKey(slotAsKey):
|
||||
result = storage[slotAsKey]
|
||||
#let encodedValue = storage[slotAsKey]
|
||||
#result = rlp.decode(encodedValue)
|
||||
else:
|
||||
result = 0.u256
|
||||
|
||||
# if slotAsKey in storage:
|
||||
# let encodedValue = storage[slotAsKey]
|
||||
# return rlp.decode(encodedValue)
|
||||
# else:
|
||||
# return 0.i256
|
||||
|
||||
proc setNonce*(db: var AccountStateDB, address: string, nonce: Int256) =
|
||||
proc setNonce*(db: var AccountStateDB, address: string, nonce: UInt256) =
|
||||
validateCanonicalAddress(address, title="Storage Address")
|
||||
validateGte(nonce, 0, title="Nonce")
|
||||
#validateGte(nonce, 0, title="Nonce")
|
||||
|
||||
var account = db.getAccount(address)
|
||||
account.nonce = nonce
|
||||
|
||||
db.setAccount(address, account)
|
||||
|
||||
proc getNonce*(db: AccountStateDB, address: string): Int256 =
|
||||
proc getNonce*(db: AccountStateDB, address: string): UInt256 =
|
||||
validateCanonicalAddress(address, title="Storage Address")
|
||||
|
||||
let account = db.getAccount(address)
|
||||
@ -105,15 +109,15 @@ proc setCode*(db: var AccountStateDB, address: string, code: string) =
|
||||
var account = db.getAccount(address)
|
||||
|
||||
account.codeHash = keccak(code)
|
||||
db.db[account.codeHash] = code
|
||||
#db.db[account.codeHash] = code
|
||||
db.setAccount(address, account)
|
||||
|
||||
proc getCode*(db: var AccountStateDB, address: string): string =
|
||||
let codeHash = db.getCodeHash(address)
|
||||
if db.db.hasKey(codeHash):
|
||||
result = db.db[codeHash]
|
||||
else:
|
||||
result = ""
|
||||
#if db.db.hasKey(codeHash):
|
||||
# result = db.db[codeHash]
|
||||
#else:
|
||||
result = ""
|
||||
|
||||
# proc rootHash*(db: AccountStateDB): string =
|
||||
# TODO return self.Trie.rootHash
|
||||
|
@ -1,14 +1,14 @@
|
||||
import strformat
|
||||
import strformat, terminal
|
||||
|
||||
type
|
||||
Logger* = object
|
||||
name*: string
|
||||
|
||||
var DEBUG = true
|
||||
var DEBUG* = false
|
||||
|
||||
proc log*(l: Logger, msg: string) =
|
||||
proc log*(l: Logger, msg: string, color: ForegroundColor = fgBlack) =
|
||||
if DEBUG:
|
||||
echo &"#{l.name}: {msg}"
|
||||
styledWriteLine(stdout, color, &"#{l.name}: {msg}", resetStyle)
|
||||
|
||||
proc debug*(l: Logger, msg: string) =
|
||||
if DEBUG:
|
||||
@ -16,7 +16,7 @@ proc debug*(l: Logger, msg: string) =
|
||||
|
||||
proc trace*(l: Logger, msg: string) =
|
||||
if DEBUG:
|
||||
l.log(msg)
|
||||
l.log(msg, fgBlue)
|
||||
|
||||
proc getLogger*(name: string): Logger =
|
||||
result = Logger(name: name)
|
||||
|
@ -7,21 +7,22 @@ proc add*(computation: var BaseComputation) =
|
||||
# Addition
|
||||
var (left, right) = computation.stack.popInt(2)
|
||||
|
||||
var res = (left + right) and constants.UINT_256_MAX
|
||||
var res = (left + right) and UINT_256_MAX
|
||||
pushRes()
|
||||
|
||||
proc addmod*(computation: var BaseComputation) =
|
||||
# Modulo Addition
|
||||
var (left, right, arg) = computation.stack.popInt(3)
|
||||
|
||||
var res = if arg == 0: 0.int256 else: (left + right) mod arg
|
||||
var res = if arg == 0: 0.u256 else: (left + right) mod arg
|
||||
echo left + right, " ", arg
|
||||
pushRes()
|
||||
|
||||
proc sub*(computation: var BaseComputation) =
|
||||
# Subtraction
|
||||
var (left, right) = computation.stack.popInt(2)
|
||||
|
||||
var res = (left - right) and constants.UINT_256_MAX
|
||||
var res = (left - right) and UINT_256_MAX
|
||||
pushRes()
|
||||
|
||||
|
||||
@ -29,50 +30,50 @@ proc modulo*(computation: var BaseComputation) =
|
||||
# Modulo
|
||||
var (value, arg) = computation.stack.popInt(2)
|
||||
|
||||
var res = if arg == 0: 0.int256 else: value mod arg
|
||||
var res = if arg == 0: 0.u256 else: value mod arg
|
||||
pushRes()
|
||||
|
||||
proc smod*(computation: var BaseComputation) =
|
||||
# Signed Modulo
|
||||
var (value, arg) = computation.stack.popInt(2)
|
||||
value = unsignedToSigned(value)
|
||||
arg = unsignedToSigned(value)
|
||||
let signedValue = unsignedToSigned(value)
|
||||
let signedArg = unsignedToSigned(arg)
|
||||
|
||||
var posOrNeg = if value < 0: -1.int256 else: 1.int256
|
||||
var res = if arg == 0: 0.int256 else: ((value.abs mod arg.abs) * posOrNeg) and constants.UINT_256_MAX
|
||||
res = signedToUnsigned(res)
|
||||
var posOrNeg = if signedValue < 0: -1.i256 else: 1.i256
|
||||
var signedRes = if signedArg == 0: 0.i256 else: ((signedValue.abs mod signedArg.abs) * posOrNeg) and UINT_256_MAX_INT
|
||||
var res = signedToUnsigned(signedRes)
|
||||
pushRes()
|
||||
|
||||
proc mul*(computation: var BaseComputation) =
|
||||
# Multiplication
|
||||
var (left, right) = computation.stack.popInt(2)
|
||||
|
||||
var res = (left * right) and constants.UINT_256_MAX
|
||||
var res = (left * right) and UINT_256_MAX
|
||||
pushRes()
|
||||
|
||||
proc mulmod*(computation: var BaseComputation) =
|
||||
# Modulo Multiplication
|
||||
var (left, right, arg) = computation.stack.popInt(3)
|
||||
|
||||
var res = if arg == 0: 0.int256 else: (left * right) mod arg
|
||||
var res = if arg == 0: 0.u256 else: (left * right) mod arg
|
||||
pushRes()
|
||||
|
||||
proc divide*(computation: var BaseComputation) =
|
||||
# Division
|
||||
var (numerator, denominator) = computation.stack.popInt(2)
|
||||
|
||||
var res = if denominator == 0: 0.int256 else: (numerator div denominator) and constants.UINT_256_MAX
|
||||
var res = if denominator == 0: 0.u256 else: (numerator div denominator) and UINT_256_MAX
|
||||
pushRes()
|
||||
|
||||
proc sdiv*(computation: var BaseComputation) =
|
||||
# Signed Division
|
||||
var (numerator, denominator) = computation.stack.popInt(2)
|
||||
numerator = unsignedToSigned(numerator)
|
||||
denominator = unsignedToSigned(denominator)
|
||||
let signedNumerator = unsignedToSigned(numerator)
|
||||
let signedDenominator = unsignedToSigned(denominator)
|
||||
|
||||
var posOrNeg = if numerator * denominator < 0: -1.int256 else: 1.int256
|
||||
var res = if denominator == 0: 0.int256 else: (posOrNeg * (numerator.abs div denominator.abs))
|
||||
res = unsignedToSigned(res)
|
||||
var posOrNeg = if signedNumerator * signedDenominator < 0: -1.i256 else: 1.i256
|
||||
var signedRes = if signedDenominator == 0: 0.i256 else: (posOrNeg * (signedNumerator.abs div signedDenominator.abs))
|
||||
var res = signedToUnsigned(signedRes)
|
||||
pushRes()
|
||||
|
||||
# no curry
|
||||
@ -80,9 +81,9 @@ proc exp*(computation: var BaseComputation) =
|
||||
# Exponentiation
|
||||
var (base, exponent) = computation.stack.popInt(2)
|
||||
|
||||
var bitSize = 0.int256 # TODO exponent.bitLength()
|
||||
var bitSize = 0.u256 # TODO exponent.bitLength()
|
||||
var byteSize = ceil8(bitSize) div 8
|
||||
var res = if base == 0: 0.int256 else: (base ^ exponent.getInt) mod constants.UINT_256_CEILING
|
||||
var res = if base == 0: 0.u256 else: (base ^ exponent.getUInt.int) mod UINT_256_CEILING
|
||||
# computation.gasMeter.consumeGas(
|
||||
# gasPerByte * byteSize,
|
||||
# reason="EXP: exponent bytes"
|
||||
@ -93,11 +94,11 @@ proc signextend*(computation: var BaseComputation) =
|
||||
# Signed Extend
|
||||
var (bits, value) = computation.stack.popInt(2)
|
||||
|
||||
var res: Int256
|
||||
if bits <= 31.int256:
|
||||
var testBit = bits.getInt * 8 + 7
|
||||
var signBit = (1.int256 shl testBit)
|
||||
res = if value != 0 and signBit != 0: value or (constants.UINT_256_CEILING - signBit) else: value and (signBit - 1.int256)
|
||||
var res: UInt256
|
||||
if bits <= 31.u256:
|
||||
var testBit = bits.getUInt.int * 8 + 7
|
||||
var signBit = (1 shl testBit)
|
||||
res = if value != 0 and signBit != 0: value or (UINT_256_CEILING - signBit.u256) else: value and (signBit.u256 - 1.u256)
|
||||
else:
|
||||
res = value
|
||||
pushRes()
|
||||
|
@ -16,7 +16,7 @@ proc coinbase*(computation) =
|
||||
stack.push(vmState.coinbase)
|
||||
|
||||
proc timestamp*(computation) =
|
||||
stack.push(vmState.timestamp)
|
||||
stack.push(vmState.timestamp.u256)
|
||||
|
||||
proc number*(computation) =
|
||||
stack.push(vmState.blockNumber)
|
||||
|
@ -30,16 +30,16 @@ type
|
||||
using
|
||||
computation: var BaseComputation
|
||||
|
||||
method msgExtraGas*(call: BaseCall, computation; gas: Int256, to: string, value: Int256): Int256 {.base.} =
|
||||
method msgExtraGas*(call: BaseCall, computation; gas: UInt256, to: string, value: UInt256): UInt256 {.base.} =
|
||||
raise newException(NotImplementedError, "Must be implemented by subclasses")
|
||||
|
||||
method msgGas*(call: BaseCall, computation; gas: Int256, to: string, value: Int256): (Int256, Int256) {.base.} =
|
||||
method msgGas*(call: BaseCall, computation; gas: UInt256, to: string, value: UInt256): (UInt256, UInt256) {.base.} =
|
||||
let extraGas = call.msgExtraGas(computation, gas, to, value)
|
||||
let totalFee = gas + extraGas
|
||||
let childMsgGas = gas + (if value != 0: GAS_CALL_STIPEND else: 0.i256)
|
||||
let childMsgGas = gas + (if value != 0: GAS_CALL_STIPEND else: 0.u256)
|
||||
(childMsgGas, totalFee)
|
||||
|
||||
method callParams*(call: BaseCall, computation): (Int256, Int256, string, string, string, Int256, Int256, Int256, Int256, bool, bool) {.base.} =
|
||||
method callParams*(call: BaseCall, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) {.base.} =
|
||||
raise newException(NotImplementedError, "Must be implemented subclasses")
|
||||
|
||||
method runLogic*(call: BaseCall, computation) =
|
||||
@ -61,7 +61,7 @@ method runLogic*(call: BaseCall, computation) =
|
||||
# TODO: Pre-call checks
|
||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||
# sender_balance = state_db.get_balance(computation.msg.storage_address)
|
||||
let senderBalance = 0.i256
|
||||
let senderBalance = 0.u256
|
||||
|
||||
let insufficientFunds = shouldTransferValue and senderBalance < value
|
||||
let stackTooDeep = computation.msg.depth + 1 > constants.STACK_DEPTH_LIMIT
|
||||
@ -78,7 +78,7 @@ method runLogic*(call: BaseCall, computation) =
|
||||
|
||||
call.logger.debug(&"{call.kind} failure: {errMessage}")
|
||||
computation.gasMeter.returnGas(childMsgGas)
|
||||
computation.stack.push(0.i256)
|
||||
computation.stack.push(0.u256)
|
||||
else:
|
||||
# TODO: with
|
||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||
@ -103,31 +103,31 @@ method runLogic*(call: BaseCall, computation) =
|
||||
# TODO
|
||||
var childComputation: BaseComputation
|
||||
if childComputation.isError:
|
||||
computation.stack.push(0.i256)
|
||||
computation.stack.push(0.u256)
|
||||
else:
|
||||
computation.stack.push(1.i256)
|
||||
computation.stack.push(1.u256)
|
||||
if not childComputation.shouldEraseReturnData:
|
||||
let actualOutputSize = min(memoryOutputSize, childComputation.output.len.i256)
|
||||
let actualOutputSize = min(memoryOutputSize, childComputation.output.len.u256)
|
||||
computation.memory.write(
|
||||
memoryOutputStartPosition,
|
||||
actualOutputSize,
|
||||
childComputation.output.toBytes[0 ..< actualOutputSize.getInt])
|
||||
childComputation.output.toBytes[0 ..< actualOutputSize.getUInt.int])
|
||||
if not childComputation.shouldBurnGas:
|
||||
computation.gasMeter.returnGas(childComputation.gasMeter.gasRemaining)
|
||||
|
||||
method msgExtraGas(call: Call, computation; gas: Int256, to: string, value: Int256): Int256 =
|
||||
method msgExtraGas(call: Call, computation; gas: UInt256, to: string, value: UInt256): UInt256 =
|
||||
# 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.i256
|
||||
let createGasFee = if not accountExists: GAS_NEW_ACCOUNT else: 0.i256
|
||||
let transferGasFee = if value != 0: GAS_CALL_VALUE else: 0.u256
|
||||
let createGasFee = if not accountExists: GAS_NEW_ACCOUNT else: 0.u256
|
||||
transferGasFee + createGasFee
|
||||
|
||||
method callParams(call: CallCode, computation): (Int256, Int256, string, string, string, Int256, Int256, Int256, Int256, bool, bool) =
|
||||
method callParams(call: CallCode, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
let gas = computation.stack.popInt()
|
||||
let to = forceBytesToAddress(computation.stack.popBinary)
|
||||
let to = forceBytesToAddress(computation.stack.popString)
|
||||
|
||||
let (value,
|
||||
memoryInputStartPosition, memoryInputSize,
|
||||
@ -145,12 +145,12 @@ method callParams(call: CallCode, computation): (Int256, Int256, string, string,
|
||||
true, # should_transfer_value,
|
||||
computation.msg.isStatic)
|
||||
|
||||
method msgExtraGas(call: CallCode, computation; gas: Int256, to: string, value: Int256): Int256 =
|
||||
if value != 0: GAS_CALL_VALUE else: 0.i256
|
||||
method msgExtraGas(call: CallCode, computation; gas: UInt256, to: string, value: UInt256): UInt256 =
|
||||
if value != 0: GAS_CALL_VALUE else: 0.u256
|
||||
|
||||
method callParams(call: Call, computation): (Int256, Int256, string, string, string, Int256, Int256, Int256, Int256, bool, bool) =
|
||||
method callParams(call: Call, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
let gas = computation.stack.popInt()
|
||||
let codeAddress = forceBytesToAddress(computation.stack.popBinary)
|
||||
let codeAddress = forceBytesToAddress(computation.stack.popString)
|
||||
|
||||
let (value,
|
||||
memoryInputStartPosition, memoryInputSize,
|
||||
@ -171,15 +171,15 @@ method callParams(call: Call, computation): (Int256, Int256, string, string, str
|
||||
true, # should_transfer_value,
|
||||
computation.msg.isStatic)
|
||||
|
||||
method msgGas(call: DelegateCall, computation; gas: Int256, to: string, value: Int256): (Int256, Int256) =
|
||||
method msgGas(call: DelegateCall, computation; gas: UInt256, to: string, value: UInt256): (UInt256, UInt256) =
|
||||
(gas, gas)
|
||||
|
||||
method msgExtraGas(call: DelegateCall, computation; gas: Int256, to: string, value: Int256): Int256 =
|
||||
0.i256
|
||||
method msgExtraGas(call: DelegateCall, computation; gas: UInt256, to: string, value: UInt256): UInt256 =
|
||||
0.u256
|
||||
|
||||
method callParams(call: DelegateCall, computation): (Int256, Int256, string, string, string, Int256, Int256, Int256, Int256, bool, bool) =
|
||||
method callParams(call: DelegateCall, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
let gas = computation.stack.popInt()
|
||||
let codeAddress = forceBytesToAddress(computation.stack.popBinary)
|
||||
let codeAddress = forceBytesToAddress(computation.stack.popString)
|
||||
|
||||
let (memoryInputStartPosition, memoryInputSize,
|
||||
memoryOutputStartPosition, memoryOutputSize) = computation.stack.popInt(4)
|
||||
@ -200,30 +200,30 @@ method callParams(call: DelegateCall, computation): (Int256, Int256, string, str
|
||||
false, # should_transfer_value,
|
||||
computation.msg.isStatic)
|
||||
|
||||
proc maxChildGasEIP150*(gas: Int256): Int256 =
|
||||
proc maxChildGasEIP150*(gas: UInt256): UInt256 =
|
||||
gas - gas div 64
|
||||
|
||||
proc computeEIP150MsgGas(computation; gas: Int256, extraGas: Int256, value: Int256, name: string, callStipend: Int256): (Int256, Int256) =
|
||||
proc computeEIP150MsgGas(computation; gas: UInt256, extraGas: UInt256, value: UInt256, name: string, callStipend: UInt256): (UInt256, UInt256) =
|
||||
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.i256)
|
||||
let childMsgGas = gas + (if value != 0: callStipend else: 0.u256)
|
||||
(childMsgGas, totalFee)
|
||||
|
||||
method msgGas(call: CallEIP150, computation; gas: Int256, to: string, value: Int256): (Int256, Int256) =
|
||||
method msgGas(call: CallEIP150, computation; gas: UInt256, to: string, value: UInt256): (UInt256, UInt256) =
|
||||
let extraGas = call.msgExtraGas(computation, gas, to, value)
|
||||
computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, GAS_CALL_STIPEND)
|
||||
|
||||
method msgGas(call: CallCodeEIP150, computation; gas: Int256, to: string, value: Int256): (Int256, Int256) =
|
||||
method msgGas(call: CallCodeEIP150, computation; gas: UInt256, to: string, value: UInt256): (UInt256, UInt256) =
|
||||
let extraGas = call.msgExtraGas(computation, gas, to, value)
|
||||
computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, GAS_CALL_STIPEND)
|
||||
|
||||
method msgGas(call: DelegateCallEIP150, computation; gas: Int256, to: string, value: Int256): (Int256, Int256) =
|
||||
method msgGas(call: DelegateCallEIP150, computation; gas: UInt256, to: string, value: UInt256): (UInt256, UInt256) =
|
||||
let extraGas = call.msgExtraGas(computation, gas, to, value)
|
||||
computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, 0.i256)
|
||||
computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, 0.u256)
|
||||
|
||||
proc msgExtraGas*(call: CallEIP161, computation; gas: Int256, to: string, value: Int256): Int256 =
|
||||
proc msgExtraGas*(call: CallEIP161, computation; gas: UInt256, to: string, value: UInt256): UInt256 =
|
||||
# TODO: with
|
||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||
# account_is_dead = (
|
||||
@ -231,20 +231,20 @@ proc msgExtraGas*(call: CallEIP161, computation; gas: Int256, to: string, value:
|
||||
# state_db.account_is_empty(to))
|
||||
let accountIsDead = true
|
||||
|
||||
let transferGasFee = if value != 0: GAS_CALL_VALUE else: 0.i256
|
||||
let createGasFee = if accountIsDead and value != 0: GAS_NEW_ACCOUNT else: 0.i256
|
||||
let transferGasFee = if value != 0: GAS_CALL_VALUE else: 0.u256
|
||||
let createGasFee = if accountIsDead and value != 0: GAS_NEW_ACCOUNT else: 0.u256
|
||||
transferGasFee + createGasFee
|
||||
|
||||
|
||||
method callParams(call: StaticCall, computation): (Int256, Int256, string, string, string, Int256, Int256, Int256, Int256, bool, bool) =
|
||||
method callParams(call: StaticCall, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
let gas = computation.stack.popInt()
|
||||
let to = forceBytesToAddress(computation.stack.popBinary)
|
||||
let to = forceBytesToAddress(computation.stack.popString)
|
||||
|
||||
let (memoryInputStartPosition, memoryInputSize,
|
||||
memoryOutputStartPosition, memoryOutputSize) = computation.stack.popInt(4)
|
||||
|
||||
result = (gas,
|
||||
0.i256, # value
|
||||
0.u256, # value
|
||||
to,
|
||||
nil, # sender
|
||||
nil, # codeAddress
|
||||
@ -256,7 +256,7 @@ method callParams(call: StaticCall, computation): (Int256, Int256, string, strin
|
||||
true) # is_static
|
||||
|
||||
|
||||
method callParams(call: CallByzantium, computation): (Int256, Int256, string, string, string, Int256, Int256, Int256, Int256, bool, bool) =
|
||||
method callParams(call: CallByzantium, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
result = procCall callParams(call, computation)
|
||||
if computation.msg.isStatic and result[1] != 0:
|
||||
raise newException(WriteProtection, "Cannot modify state while inside of a STATICCALL context")
|
||||
|
@ -21,7 +21,7 @@ quasiBoolean(xorOp, `xor`, nonzero=true) # Bitwise XOr
|
||||
proc iszero*(computation: var BaseComputation) =
|
||||
var value = computation.stack.popInt()
|
||||
|
||||
var res = if value == 0: 1.i256 else: 0.i256
|
||||
var res = if value == 0: 1.u256 else: 0.u256
|
||||
pushRes()
|
||||
|
||||
proc notOp*(computation: var BaseComputation) =
|
||||
@ -34,6 +34,6 @@ proc byteOp*(computation: var BaseComputation) =
|
||||
# Bitwise And
|
||||
var (position, value) = computation.stack.popInt(2)
|
||||
|
||||
var res = if position >= 32.i256: 0.i256 else: (value div (256.i256.pow(31 - position.getInt))) mod 256
|
||||
var res = if position >= 32.u256: 0.u256 else: (value div (256.u256.pow(31'u - position.getUInt))) mod 256
|
||||
pushRes()
|
||||
|
||||
|
@ -4,7 +4,7 @@ import
|
||||
.. / vm / [stack, message, gas_meter, memory, code_stream], .. / utils / [address, padding, bytes], ttmath
|
||||
|
||||
proc balance*(computation: var BaseComputation) =
|
||||
let address = forceBytesToAddress(computation.stack.popBinary)
|
||||
let address = forceBytesToAddress(computation.stack.popString)
|
||||
var balance: Int256
|
||||
# TODO computation.vmState.stateDB(read_only=True):
|
||||
# balance = db.getBalance(address)
|
||||
@ -25,15 +25,15 @@ proc callValue*(computation: var BaseComputation) =
|
||||
|
||||
proc callDataLoad*(computation: var BaseComputation) =
|
||||
# Load call data into memory
|
||||
let startPosition = computation.stack.popInt.getInt
|
||||
let value = computation.msg.data[startPosition ..< startPosition + 32].toString
|
||||
let paddedValue = padRight(value, 32, "\x00")
|
||||
let normalizedValue = paddedValue.lStrip(0.char)
|
||||
let startPosition = computation.stack.popInt.getUInt.int
|
||||
let value = computation.msg.data[startPosition ..< startPosition + 32]
|
||||
let paddedValue = padRight(value, 32, 0.byte)
|
||||
let normalizedValue = paddedValue.lStrip(0.byte)
|
||||
computation.stack.push(normalizedValue)
|
||||
|
||||
|
||||
proc callDataSize*(computation: var BaseComputation) =
|
||||
let size = computation.msg.data.len
|
||||
let size = computation.msg.data.len.u256
|
||||
computation.stack.push(size)
|
||||
|
||||
proc callDataCopy*(computation: var BaseComputation) =
|
||||
@ -45,13 +45,13 @@ proc callDataCopy*(computation: var BaseComputation) =
|
||||
let wordCount = ceil32(size) div 32
|
||||
let copyGasCost = wordCount * constants.GAS_COPY
|
||||
computation.gasMeter.consumeGas(copyGasCost, reason="CALLDATACOPY fee")
|
||||
let value = computation.msg.data[calldataStartPosition.getInt ..< (calldataStartPosition + size).getInt].toString
|
||||
let paddedValue = padRight(value, size.getInt, "\x00")
|
||||
let value = computation.msg.data[calldataStartPosition.getUInt.int ..< (calldataStartPosition + size).getUInt.int]
|
||||
let paddedValue = padRight(value, size.getUInt.int, 0.byte)
|
||||
computation.memory.write(memStartPosition, size, paddedValue)
|
||||
|
||||
|
||||
proc codesize*(computation: var BaseComputation) =
|
||||
let size = computation.code.len.i256
|
||||
let size = computation.code.len.u256
|
||||
computation.stack.push(size)
|
||||
|
||||
|
||||
@ -76,7 +76,7 @@ proc gasprice*(computation: var BaseComputation) =
|
||||
|
||||
|
||||
proc extCodeSize*(computation: var BaseComputation) =
|
||||
let account = forceBytesToAddress(computation.stack.popBinary)
|
||||
let account = forceBytesToAddress(computation.stack.popString)
|
||||
# TODO
|
||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||
# code_size = len(state_db.get_code(account))
|
||||
@ -84,7 +84,7 @@ proc extCodeSize*(computation: var BaseComputation) =
|
||||
# computation.stack.push(code_size)
|
||||
|
||||
proc extCodeCopy*(computation: var BaseComputation) =
|
||||
let account = forceBytesToAddress(computation.stack.popBinary)
|
||||
let account = forceBytesToAddress(computation.stack.popString)
|
||||
let (memStartPosition, codeStartPosition, size) = computation.stack.popInt(3)
|
||||
computation.extendMemory(memStartPosition, size)
|
||||
let wordCount = ceil32(size) div 32
|
||||
@ -100,7 +100,7 @@ proc extCodeCopy*(computation: var BaseComputation) =
|
||||
# computation.memory.write(mem_start_position, size, padded_code_bytes)
|
||||
|
||||
proc returnDataSize*(computation: var BaseComputation) =
|
||||
let size = computation.returnData.len
|
||||
let size = computation.returnData.len.u256
|
||||
computation.stack.push(size)
|
||||
|
||||
proc returnDataCopy*(computation: var BaseComputation) =
|
||||
@ -115,5 +115,5 @@ proc returnDataCopy*(computation: var BaseComputation) =
|
||||
let wordCount = ceil32(size) div 32
|
||||
let copyGasCost = wordCount * constants.GAS_COPY
|
||||
computation.gasMeter.consumeGas(copyGasCost, reason="RETURNDATACOPY fee")
|
||||
let value = ($computation.returnData)[returnDataStartPosition.getInt ..< (returnDataStartPosition + size).getInt]
|
||||
let value = ($computation.returnData)[returnDataStartPosition.getUInt.int ..< (returnDataStartPosition + size).getUInt.int]
|
||||
computation.memory.write(memStartPosition, size, value)
|
||||
|
@ -14,7 +14,7 @@ proc stop*(computation) =
|
||||
|
||||
|
||||
proc jump*(computation) =
|
||||
let jumpDest = stack.popInt.getInt
|
||||
let jumpDest = stack.popInt.getUInt.int
|
||||
|
||||
code.pc = jumpDest
|
||||
|
||||
@ -30,21 +30,21 @@ proc jumpi*(computation) =
|
||||
let (jumpDest, checkValue) = stack.popInt(2)
|
||||
|
||||
if checkValue > 0:
|
||||
code.pc = jumpDest.getInt
|
||||
code.pc = jumpDest.getUInt.int
|
||||
|
||||
let nextOpcode = code.peek()
|
||||
|
||||
if nextOpcode != JUMPDEST:
|
||||
raise newException(InvalidJumpDestination, "Invalid Jump Destination")
|
||||
|
||||
if not code.isValidOpcode(jumpDest.getInt):
|
||||
if not code.isValidOpcode(jumpDest.getUInt.int):
|
||||
raise newException(InvalidInstruction, "Jump resulted in invalid instruction")
|
||||
|
||||
proc jumpdest*(computation) =
|
||||
discard
|
||||
|
||||
proc pc*(computation) =
|
||||
let pc = max(code.pc - 1, 0)
|
||||
let pc = max(code.pc - 1, 0).u256
|
||||
stack.push(pc)
|
||||
|
||||
proc gas*(computation) =
|
||||
|
@ -10,25 +10,26 @@ macro quasiBoolean*(name: untyped, op: untyped, signed: untyped = nil, nonzero:
|
||||
var signedNode = newEmptyNode()
|
||||
var finishSignedNode = newEmptyNode()
|
||||
let resNode = ident("res")
|
||||
let leftNode = ident("left")
|
||||
let rightNode = ident("right")
|
||||
var leftNode = ident("left")
|
||||
var rightNode = ident("right")
|
||||
var actualLeftNode = leftNode
|
||||
var actualRightNode = rightNode
|
||||
if not signed.isNil:
|
||||
actualLeftNode = ident("leftSigned")
|
||||
actualRightNode = ident("rightSigned")
|
||||
signedNode = quote:
|
||||
`leftNode` = unsignedToSigned(`leftNode`)
|
||||
`rightNode` = unsignedToSigned(`rightNode`)
|
||||
finishSignedNode = quote:
|
||||
`resNode` = signedToUnsigned(`resNode`)
|
||||
let `actualLeftNode` = unsignedToSigned(`leftNode`)
|
||||
let `actualRightNode` = unsignedToSigned(`rightNode`)
|
||||
var test = if nonzero.isNil:
|
||||
quote:
|
||||
`op`(`leftNode`, `rightNode`)
|
||||
`op`(`actualLeftNode`, `actualRightNode`)
|
||||
else:
|
||||
quote:
|
||||
`op`(`leftNode`, `rightNode`) != 0
|
||||
`op`(`actualLeftNode`, `actualRightNode`) != 0
|
||||
result = quote:
|
||||
proc `name`*(computation: var BaseComputation) =
|
||||
var (`leftNode`, `rightNode`) = computation.stack.popInt(2)
|
||||
`signedNode`
|
||||
|
||||
var `resNode` = if `test`: 1.int256 else: 0.int256
|
||||
`finishSignedNode`
|
||||
var `resNode` = if `test`: 1.u256 else: 0.u256
|
||||
computation.stack.push(`resNode`)
|
||||
|
@ -22,7 +22,7 @@ macro logXX(topicCount: static[int]): untyped =
|
||||
result = quote:
|
||||
proc `name`*(`computation`: var BaseComputation) =
|
||||
let (`memStartPosition`, `size`) = `computation`.stack.popInt(2)
|
||||
var `topics`: seq[Int256]
|
||||
var `topics`: seq[UInt256]
|
||||
|
||||
var topicCode: NimNode
|
||||
if topicCount == 0:
|
||||
@ -44,7 +44,7 @@ macro logXX(topicCount: static[int]): untyped =
|
||||
|
||||
let logicCode = quote:
|
||||
let dataGasCost = constants.GAS_LOG_DATA * `size`
|
||||
let topicGasCost = constants.GAS_LOG_TOPIC * `topicCount`.i256
|
||||
let topicGasCost = constants.GAS_LOG_TOPIC * `topicCount`.u256
|
||||
let totalGasCost = dataGasCost + topicGasCost
|
||||
`computation`.gasMeter.consumeGas(totalGasCost, reason="Log topic and data gas cost")
|
||||
`computation`.extendMemory(`memStartPosition`, `size`)
|
||||
|
@ -12,11 +12,11 @@ proc mstoreX(computation; x: int) =
|
||||
let start = stack.popInt()
|
||||
let value = stack.popBinary()
|
||||
|
||||
let paddedValue = padLeft(value, x, "\x00")
|
||||
let normalizedValue = ($paddedValue)[^x .. ^1]
|
||||
|
||||
extendMemory(start, x.int256)
|
||||
memory.write(start, 32.int256, normalizedValue)
|
||||
let paddedValue = padLeft(value, x, 0.byte)
|
||||
let normalizedValue = paddedValue[^x .. ^1]
|
||||
|
||||
extendMemory(start, x.u256)
|
||||
memory.write(start, 32.u256, normalizedValue)
|
||||
|
||||
# TODO template handler
|
||||
|
||||
@ -29,10 +29,10 @@ proc mstore8*(computation) =
|
||||
proc mload*(computation) =
|
||||
let start = stack.popInt()
|
||||
|
||||
extendMemory(start, 32.int256)
|
||||
extendMemory(start, 32.u256)
|
||||
|
||||
let value = memory.read(start, 32.int256).toString
|
||||
let value = memory.read(start, 32.u256)
|
||||
stack.push(value)
|
||||
|
||||
proc msize*(computation) =
|
||||
stack.push(memory.len)
|
||||
stack.push(memory.len.u256)
|
||||
|
@ -5,7 +5,7 @@ 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.i256.ceil32 div 32
|
||||
let wordCount = sha3Bytes.len.u256.ceil32 div 32
|
||||
let gasCost = constants.GAS_SHA3_WORD * wordCount
|
||||
computation.gasMeter.consumeGas(gasCost, reason="SHA3: word gas cost")
|
||||
var res = keccak("")
|
||||
|
@ -1,5 +1,5 @@
|
||||
import
|
||||
strformat, macros,
|
||||
strformat, macros, sequtils,
|
||||
../constants, ../errors, ../computation, .. / vm / [stack, code_stream], .. / utils / [padding, bytes], ttmath
|
||||
|
||||
{.this: computation.}
|
||||
@ -9,7 +9,7 @@ using
|
||||
computation: var BaseComputation
|
||||
|
||||
proc pop*(computation) =
|
||||
discard stack.pop()
|
||||
discard stack.popInt()
|
||||
|
||||
macro pushXX(size: static[int]): untyped =
|
||||
let computation = ident("computation")
|
||||
@ -17,12 +17,12 @@ macro pushXX(size: static[int]): untyped =
|
||||
let name = ident(&"push{size}")
|
||||
result = quote:
|
||||
proc `name`*(`computation`: var BaseComputation) =
|
||||
let `value` = `computation`.code.read(`size`).toString
|
||||
let stripped = `value`.strip(0.char)
|
||||
let `value` = `computation`.code.read(`size`)
|
||||
let stripped = `value`.toString.strip(0.char)
|
||||
if stripped.len == 0:
|
||||
`computation`.stack.push(0.i256)
|
||||
`computation`.stack.push(0.u256)
|
||||
else:
|
||||
let paddedValue = `value`.padRight(`size`, "\x00")
|
||||
let paddedValue = `value`.padRight(`size`, 0.byte)
|
||||
`computation`.stack.push(paddedValue)
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import
|
||||
../constants, ../errors, ../computation, .. / db / state_db, .. / vm / [stack, gas_meter, message], strformat
|
||||
../constants, ../errors, ../computation, ../vm_state, .. / db / [db_chain, state_db], .. / vm / [stack, gas_meter, message], strformat, ttmath, utils / header
|
||||
|
||||
{.this: computation.}
|
||||
{.experimental.}
|
||||
@ -9,52 +9,26 @@ using
|
||||
|
||||
proc sstore*(computation) =
|
||||
let (slot, value) = stack.popInt(2)
|
||||
#if value != 0: #and slot == 0:
|
||||
computation.gasMeter.consumeGas(GAS_SSET, &"SSTORE: {computation.msg.storageAddress}[slot] -> {value} (TODO)")
|
||||
#else:
|
||||
#computation.gasMeter.consumeGas(GAS_SRESET, &"SSTORE: {computation.msg.storageAddress}[slot] -> {value} (TODO)")
|
||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||
# current_value = state_db.get_storage(
|
||||
# address=computation.msg.storage_address,
|
||||
# slot=slot,
|
||||
# )
|
||||
|
||||
# let isCurrentlyEmpty = not bool(current_value)
|
||||
# let isGoingToBeEmpty = not bool(value)
|
||||
var currentValue = 0.u256
|
||||
|
||||
# if is_currently_empty:
|
||||
# gas_refund = 0
|
||||
# elif is_going_to_be_empty:
|
||||
# gas_refund = constants.REFUND_SCLEAR
|
||||
# else:
|
||||
# gas_refund = 0
|
||||
computation.vmState.db(readOnly=false):
|
||||
currentValue = db.getStorage(computation.msg.storageAddress, slot)
|
||||
|
||||
# if is_currently_empty and is_going_to_be_empty:
|
||||
# gas_cost = constants.GAS_SRESET
|
||||
# elif is_currently_empty:
|
||||
# gas_cost = constants.GAS_SSET
|
||||
# elif is_going_to_be_empty:
|
||||
# gas_cost = constants.GAS_SRESET
|
||||
# else:
|
||||
# gas_cost = constants.GAS_SRESET
|
||||
let isCurrentlyEmpty = currentValue == 0
|
||||
let isGoingToBeEmpty = value == 0
|
||||
|
||||
# computation.gas_meter.consume_gas(gas_cost, reason="SSTORE: {0}[{1}] -> {2} ({3})".format(
|
||||
# encode_hex(computation.msg.storage_address),
|
||||
# slot,
|
||||
# value,
|
||||
# current_value,
|
||||
# ))
|
||||
let gasRefund = if isCurrentlyEmpty or not isGoingToBeEmpty: 0.u256 else: REFUND_SCLEAR
|
||||
|
||||
# if gas_refund:
|
||||
# computation.gas_meter.refund_gas(gas_refund)
|
||||
let gasCost = if isCurrentlyEmpty and not isGoingToBeEmpty: GAS_SSET else: GAS_SRESET
|
||||
|
||||
# with computation.vm_state.state_db() as state_db:
|
||||
# state_db.set_storage(
|
||||
# address=computation.msg.storage_address,
|
||||
# slot=slot,
|
||||
# value=value,
|
||||
# )
|
||||
computation.gasMeter.consumeGas(gasCost, &"SSTORE: {computation.msg.storageAddress}[slot] -> {value} ({currentValue})")
|
||||
|
||||
if gasRefund > 0:
|
||||
computation.gasMeter.refundGas(gasRefund)
|
||||
|
||||
computation.vmState.db(readOnly=false):
|
||||
db.setStorage(computation.msg.storageAddress, slot, value)
|
||||
|
||||
proc sload*(computation) =
|
||||
let slot = stack.popInt()
|
||||
|
@ -17,7 +17,7 @@ type
|
||||
|
||||
CreateByzantium* = ref object of CreateEIP150
|
||||
|
||||
method maxChildGasModifier(create: Create, gas: Int256): Int256 {.base.} =
|
||||
method maxChildGasModifier(create: Create, gas: UInt256): UInt256 {.base.} =
|
||||
gas
|
||||
|
||||
method runLogic*(create: Create, computation) =
|
||||
@ -55,7 +55,7 @@ method runLogic*(create: Create, computation) =
|
||||
|
||||
if isCollision:
|
||||
computation.vmState.logger.debug(&"Address collision while creating contract: {contractAddress.encodeHex}")
|
||||
computation.stack.push(0.i256)
|
||||
computation.stack.push(0.u256)
|
||||
return
|
||||
|
||||
let childMsg = computation.prepareChildMessage(
|
||||
@ -70,12 +70,12 @@ method runLogic*(create: Create, computation) =
|
||||
var childComputation: BaseComputation
|
||||
|
||||
if childComputation.isError:
|
||||
computation.stack.push(0.i256)
|
||||
computation.stack.push(0.u256)
|
||||
else:
|
||||
computation.stack.push(contractAddress)
|
||||
computation.gasMeter.returnGas(childComputation.gasMeter.gasRemaining)
|
||||
|
||||
method maxChildGasModifier(create: CreateEIP150, gas: Int256): Int256 =
|
||||
method maxChildGasModifier(create: CreateEIP150, gas: UInt256): UInt256 =
|
||||
maxChildGasEIP150(gas)
|
||||
|
||||
method runLogic*(create: CreateByzantium, computation) =
|
||||
@ -84,7 +84,7 @@ method runLogic*(create: CreateByzantium, computation) =
|
||||
procCall runLogic(create, computation)
|
||||
|
||||
proc selfdestructEIP150(computation) =
|
||||
let beneficiary = forceBytesToAddress(stack.popBinary)
|
||||
let beneficiary = forceBytesToAddress(stack.popString)
|
||||
# TODO: with
|
||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||
# if not state_db.account_exists(beneficiary):
|
||||
@ -95,7 +95,7 @@ proc selfdestructEIP150(computation) =
|
||||
# _selfdestruct(computation, beneficiary)
|
||||
|
||||
proc selfdestructEIP161(computation) =
|
||||
let beneficiary = forceBytesToAddress(stack.popBinary)
|
||||
let beneficiary = forceBytesToAddress(stack.popString)
|
||||
# TODO: with
|
||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||
# is_dead = (
|
||||
@ -136,8 +136,8 @@ proc selfdestruct(computation; beneficiary: string) =
|
||||
proc returnOp*(computation) =
|
||||
let (startPosition, size) = stack.popInt(2)
|
||||
computation.extendMemory(startPosition, size)
|
||||
let output = memory.read(startPosition, size).toString
|
||||
computation.output = output
|
||||
let output = memory.read(startPosition, size)
|
||||
computation.output = output.toString
|
||||
raise newException(Halt, "RETURN")
|
||||
|
||||
proc revert*(computation) =
|
||||
@ -148,7 +148,7 @@ proc revert*(computation) =
|
||||
raise newException(Revert, $output)
|
||||
|
||||
proc selfdestruct*(computation) =
|
||||
let beneficiary = forceBytesToAddress(stack.popBinary)
|
||||
let beneficiary = forceBytesToAddress(stack.popString)
|
||||
selfdestruct(computation, beneficiary)
|
||||
raise newException(Halt, "SELFDESTRUCT")
|
||||
|
||||
|
@ -10,16 +10,16 @@ template run*(opcode: Opcode, computation: var BaseComputation) =
|
||||
method logger*(opcode: Opcode): Logger =
|
||||
logging.getLogger(&"vm.opcode.{opcode.kind}")
|
||||
|
||||
method gasCost*(opcode: Opcode, computation: var BaseComputation): Int256 =
|
||||
method gasCost*(opcode: Opcode, computation: var BaseComputation): UInt256 =
|
||||
if opcode.kind in VARIABLE_GAS_COST_OPS:
|
||||
opcode.gasCostHandler(computation)
|
||||
else:
|
||||
opcode.gasCostConstant
|
||||
|
||||
template newOpcode*(kind: Op, gasCost: Int256, logic: proc(computation: var BaseComputation)): Opcode =
|
||||
template newOpcode*(kind: Op, gasCost: UInt256, logic: proc(computation: var BaseComputation)): Opcode =
|
||||
Opcode(kind: kind, gasCostConstant: gasCost, runLogic: logic)
|
||||
|
||||
template newOpcode*(kind: Op, gasHandler: proc(computation: var BaseComputation): Int256, logic: proc(computation: var BaseComputation)): Opcode =
|
||||
template newOpcode*(kind: Op, gasHandler: proc(computation: var BaseComputation): UInt256, logic: proc(computation: var BaseComputation)): Opcode =
|
||||
Opcode(kind: kind, gasCostHandler: gasHandler, runLogic: logic)
|
||||
|
||||
method `$`*(opcode: Opcode): string =
|
||||
|
@ -97,7 +97,7 @@ var OPCODE_TABLE* = initOpcodes:
|
||||
|
||||
|
||||
# system
|
||||
Op.Return: 0.i256 returnOp
|
||||
Op.Return: 0.u256 returnOp
|
||||
Op.SelfDestruct: GAS_SELF_DESTRUCT_COST selfdestruct
|
||||
|
||||
|
||||
|
@ -4,16 +4,16 @@ import
|
||||
type
|
||||
BaseTransaction* = ref object
|
||||
nonce*: Int256
|
||||
gasPrice*: Int256
|
||||
gas*: Int256
|
||||
gasPrice*: UInt256
|
||||
gas*: UInt256
|
||||
to*: string
|
||||
value*: Int256
|
||||
value*: UInt256
|
||||
data*: string
|
||||
v*: Int256
|
||||
r*: Int256
|
||||
s*: Int256
|
||||
|
||||
proc intrinsicGas*(t: BaseTransaction): Int256 =
|
||||
proc intrinsicGas*(t: BaseTransaction): UInt256 =
|
||||
# Compute the baseline gas cost for this transaction. This is the amount
|
||||
# of gas needed to send this transaction (but that is not actually used
|
||||
# for computation)
|
||||
|
@ -13,7 +13,9 @@ import strutils, sequtils
|
||||
# cstring(res) # TODO: faster
|
||||
|
||||
proc toString*(value: seq[byte]): string =
|
||||
value.mapIt(it.char).join("")
|
||||
"0x" & value.mapIt(it.int.toHex(2)).join("").toLowerAscii
|
||||
|
||||
proc toBytes*(value: string): seq[byte] =
|
||||
result = value.mapIt(it.byte)
|
||||
|
||||
|
||||
|
@ -3,11 +3,11 @@ import ../constants, ttmath, strformat
|
||||
type
|
||||
Header* = ref object
|
||||
timestamp*: int
|
||||
difficulty*: Int256
|
||||
blockNumber*: Int256
|
||||
difficulty*: UInt256
|
||||
blockNumber*: UInt256
|
||||
hash*: string
|
||||
coinbase*: string
|
||||
gasLimit*: Int256
|
||||
gasLimit*: UInt256
|
||||
stateRoot*: string
|
||||
|
||||
# TODO
|
||||
@ -52,14 +52,14 @@ proc generateHeaderFromParentHeader*(
|
||||
|
||||
# return header
|
||||
|
||||
proc computeGasLimit*(header: Header, gasLimitFloor: Int256): Int256 =
|
||||
proc computeGasLimit*(header: Header, gasLimitFloor: UInt256): UInt256 =
|
||||
# TODO
|
||||
gasLimitFloor
|
||||
|
||||
proc gasUsed*(header: Header): Int256 =
|
||||
proc gasUsed*(header: Header): UInt256 =
|
||||
# TODO
|
||||
0.int256
|
||||
0.u256
|
||||
|
||||
proc gasLimit*(header: Header): Int256 =
|
||||
proc gasLimit*(header: Header): UInt256 =
|
||||
# TODO
|
||||
0.int256
|
||||
0.u256
|
||||
|
@ -26,6 +26,17 @@ proc pad(value: string, size: int, with: string, left: bool): string =
|
||||
else:
|
||||
result = value
|
||||
|
||||
proc pad[T](value: seq[T], size: int, element: T, left: bool): seq[T] =
|
||||
let padAmount = size - value.len
|
||||
if padAmount > 0:
|
||||
let fill = repeat(element, padAmount)
|
||||
if left:
|
||||
result = fill.concat(value)
|
||||
else:
|
||||
result = value.concat(fill)
|
||||
else:
|
||||
result = value
|
||||
|
||||
template padLeft*(value: cstring, size: int, with: cstring): cstring =
|
||||
pad(value, size, with, true)
|
||||
|
||||
@ -94,3 +105,45 @@ proc lStrip*(value: string, c: char): string =
|
||||
|
||||
proc rStip*(value: string, c: char): string =
|
||||
value.strip(chars={c}, leading=false)
|
||||
|
||||
|
||||
template padLeft*[T](value: seq[T], size: int, element: T): seq[T] =
|
||||
pad(value, size, element, true)
|
||||
|
||||
template padRight*[T](value: seq[T], size: int, element: T): seq[T] =
|
||||
pad(value, size, element, false)
|
||||
|
||||
template zpadRight*[T](value: seq[T], size: int): seq[T] =
|
||||
padRight(value, size, 0.byte)
|
||||
|
||||
template zpadLeft*[T](value: seq[T], size: int): seq[T] =
|
||||
padLeft(value, size, 0.byte)
|
||||
|
||||
template pad32*[T](value: seq[T]): seq[T] =
|
||||
zpadLeft(value, 32)
|
||||
|
||||
template pad32r*[T](value: seq[T]): seq[T] =
|
||||
zpadRight(value, 32)
|
||||
|
||||
proc lStrip*[T](value: seq[T], element: T): seq[T] =
|
||||
var z = 0
|
||||
while z < value.len and value[z] == element:
|
||||
z += 1
|
||||
if z == 0:
|
||||
result = value
|
||||
elif z == value.len:
|
||||
result = @[]
|
||||
else:
|
||||
result = value[z..^1]
|
||||
|
||||
proc rStrip*[T](value: seq[T], element: T): seq[T] =
|
||||
var z = value.len - 1
|
||||
while z >= 0 and value[z] == element:
|
||||
z -= 1
|
||||
if z == value.len - 1:
|
||||
result = value
|
||||
elif z == -1:
|
||||
result = @[]
|
||||
else:
|
||||
result = value[0..z]
|
||||
|
||||
|
@ -1,32 +1,48 @@
|
||||
import ttmath, constants, strformat, macros
|
||||
import ttmath, constants, strformat, sequtils, endians, macros, utils / padding
|
||||
|
||||
proc intToBigEndian*(value: Int256): string =
|
||||
result = ""
|
||||
# TODO improve
|
||||
|
||||
proc bigEndianToInt*(value: string): Int256 =
|
||||
result = 0.int256
|
||||
proc intToBigEndian*(value: UInt256): Bytes =
|
||||
result = repeat(0.byte, 32)
|
||||
for z in 0 ..< 4:
|
||||
var temp = value.table[z]
|
||||
bigEndian64(result[24 - z * 8].addr, temp.addr)
|
||||
|
||||
proc bigEndianToInt*(value: Bytes): UInt256 =
|
||||
var bytes = value.padLeft(32, 0.byte)
|
||||
result = 0.u256
|
||||
for z in 0 ..< 4:
|
||||
var temp = 0.uint
|
||||
bigEndian64(temp.addr, bytes[24 - z * 8].addr)
|
||||
result.table[z] = temp
|
||||
|
||||
proc unsignedToSigned*(value: Int256): Int256 =
|
||||
if value <= UINT_255_MAX:
|
||||
return value
|
||||
else:
|
||||
return value - UINT_256_CEILING
|
||||
#echo intToBigEndian("32482610168005790164680892356840817100452003984372336767666156211029086934369".u256)
|
||||
|
||||
proc signedToUnsigned*(value: Int256): Int256 =
|
||||
if value < 0:
|
||||
return value + UINT_256_CEILING
|
||||
else:
|
||||
return value
|
||||
proc unsignedToSigned*(value: UInt256): Int256 =
|
||||
0.i256
|
||||
# TODO
|
||||
# if value <= UINT_255_MAX_INT:
|
||||
# return value
|
||||
# else:
|
||||
# return value - UINT_256_CEILING_INT
|
||||
|
||||
proc signedToUnsigned*(value: Int256): UInt256 =
|
||||
0.u256
|
||||
# TODO
|
||||
# if value < 0:
|
||||
# return value + UINT_256_CEILING_INT
|
||||
# else:
|
||||
# return value
|
||||
|
||||
macro ceilXX(ceiling: static[int]): untyped =
|
||||
var name = ident(&"ceil{ceiling}")
|
||||
result = quote:
|
||||
proc `name`*(value: Int256): Int256 =
|
||||
var remainder = value mod `ceiling`.int256
|
||||
proc `name`*(value: UInt256): UInt256 =
|
||||
var remainder = value mod `ceiling`.u256
|
||||
if remainder == 0:
|
||||
return value
|
||||
else:
|
||||
return value + `ceiling`.int256 - remainder
|
||||
return value + `ceiling`.u256 - remainder
|
||||
|
||||
|
||||
ceilXX(32)
|
||||
|
@ -26,13 +26,13 @@ proc validateLength*[T](values: seq[T], size: int) =
|
||||
raise newException(ValidationError,
|
||||
&"seq expected {size} len, got {values.len}")
|
||||
|
||||
proc validateLte*(value: Int256 | int, maximum: int, title: string = "Value") =
|
||||
if value.i256 > maximum.i256:
|
||||
proc validateLte*(value: UInt256 | int, maximum: int, title: string = "Value") =
|
||||
if value.u256 > maximum.u256:
|
||||
raise newException(ValidationError,
|
||||
&"{title} {value} is not less or equal to {maximum}")
|
||||
|
||||
proc validateLt*(value: Int256 | int, maximum: int, title: string = "Value") =
|
||||
if value.i256 >= maximum.i256:
|
||||
proc validateLt*(value: UInt256 | int, maximum: int, title: string = "Value") =
|
||||
if value.u256 >= maximum.u256:
|
||||
raise newException(ValidationError,
|
||||
&"{title} {value} is not less than {maximum}")
|
||||
|
||||
@ -40,3 +40,8 @@ proc validateStackItem*(value: string) =
|
||||
if value.len > 32:
|
||||
raise newException(ValidationError,
|
||||
&"Invalid stack item: expected 32 bytes, got {value.len}: value is {value}")
|
||||
|
||||
proc validateStackItem*(value: string | seq[byte]) =
|
||||
if value.len > 32:
|
||||
raise newException(ValidationError,
|
||||
&"Invalid stack item: expected 32 bytes, got {value.len}: value is {value}")
|
||||
|
@ -4,7 +4,7 @@ import
|
||||
|
||||
type
|
||||
CodeStream* = ref object
|
||||
bytes: seq[byte]
|
||||
bytes*: seq[byte]
|
||||
depthProcessed: int
|
||||
invalidPositions: HashSet[int]
|
||||
pc*: int
|
||||
|
@ -4,7 +4,7 @@ import
|
||||
|
||||
proc validateFrontierTransaction*(vmState: BaseVmState, transaction: BaseTransaction) =
|
||||
let gasCost = transaction.gas * transaction.gasPrice
|
||||
var senderBalance: Int256
|
||||
var senderBalance: UInt256
|
||||
# inDB(vmState.stateDB(readOnly=true):
|
||||
# senderBalance = db.getBalance(transaction.sender)
|
||||
senderBalance = gasCost # TODO
|
||||
|
@ -9,14 +9,14 @@ type
|
||||
method name*(vm: FrontierVM): string =
|
||||
"FrontierVM"
|
||||
|
||||
method getBlockReward(vm: FrontierVM): Int256 =
|
||||
method getBlockReward(vm: FrontierVM): UInt256 =
|
||||
BLOCK_REWARD
|
||||
|
||||
method getUncleReward(vm: FrontierVM, blockNumber: Int256, uncle: Block): Int256 =
|
||||
method getUncleReward(vm: FrontierVM, blockNumber: UInt256, uncle: Block): UInt256 =
|
||||
BLOCK_REWARD * (UNCLE_DEPTH_PENALTY_FACTOR + uncle.blockNumber - blockNumber) div UNCLE_DEPTH_PENALTY_FACTOR
|
||||
|
||||
|
||||
method getNephewReward(vm: FrontierVM): Int256 =
|
||||
method getNephewReward(vm: FrontierVM): UInt256 =
|
||||
vm.getBlockReward() div 32
|
||||
|
||||
proc newFrontierVM*(header: Header, chainDB: BaseChainDB): FrontierVM =
|
||||
|
@ -2,7 +2,7 @@ import
|
||||
strformat, ttmath,
|
||||
../constants, ../opcode, ../computation, stack
|
||||
|
||||
proc expGasCost*(computation: var BaseComputation): Int256 =
|
||||
proc expGasCost*(computation: var BaseComputation): UInt256 =
|
||||
let arg = computation.stack.getInt(0)
|
||||
result = if arg == 0: 10.i256 else: (10.i256 + 10.i256 * (1.i256 + arg.log256))
|
||||
result = if arg == 0: 10.u256 else: (10.u256 + 10.u256 * (1.u256 + arg.log256))
|
||||
|
||||
|
@ -5,20 +5,20 @@ import
|
||||
type
|
||||
GasMeter* = ref object
|
||||
logger*: Logger
|
||||
gasRefunded*: Int256
|
||||
startGas*: Int256
|
||||
gasRemaining*: Int256
|
||||
gasRefunded*: UInt256
|
||||
startGas*: UInt256
|
||||
gasRemaining*: UInt256
|
||||
|
||||
proc newGasMeter*(startGas: Int256): GasMeter =
|
||||
proc newGasMeter*(startGas: UInt256): GasMeter =
|
||||
new(result)
|
||||
result.startGas = startGas
|
||||
result.gasRemaining = result.startGas
|
||||
result.gasRefunded = 0.int256
|
||||
result.gasRefunded = 0.u256
|
||||
result.logger = logging.getLogger("gas")
|
||||
|
||||
proc consumeGas*(gasMeter: var GasMeter; amount: Int256; reason: string) =
|
||||
if amount < 0.int256:
|
||||
raise newException(ValidationError, "Gas consumption amount must be positive")
|
||||
proc consumeGas*(gasMeter: var GasMeter; amount: UInt256; reason: string) =
|
||||
#if amount < 0.u256:
|
||||
# raise newException(ValidationError, "Gas consumption amount must be positive")
|
||||
if amount > gasMeter.gasRemaining:
|
||||
raise newException(OutOfGas,
|
||||
&"Out of gas: Needed {amount} - Remaining {gasMeter.gasRemaining} - Reason: {reason}")
|
||||
@ -26,16 +26,16 @@ proc consumeGas*(gasMeter: var GasMeter; amount: Int256; reason: string) =
|
||||
gasMeter.logger.trace(
|
||||
&"GAS CONSUMPTION: {gasMeter.gasRemaining + amount} - {amount} -> {gasMeter.gasRemaining} ({reason})")
|
||||
|
||||
proc returnGas*(gasMeter: var GasMeter; amount: Int256) =
|
||||
if amount < 0.int256:
|
||||
raise newException(ValidationError, "Gas return amount must be positive")
|
||||
proc returnGas*(gasMeter: var GasMeter; amount: UInt256) =
|
||||
#if amount < 0.int256:
|
||||
# raise newException(ValidationError, "Gas return amount must be positive")
|
||||
gasMeter.gasRemaining += amount
|
||||
gasMeter.logger.trace(
|
||||
&"GAS RETURNED: {gasMeter.gasRemaining - amount} + {amount} -> {gasMeter.gasRemaining}")
|
||||
|
||||
proc refundGas*(gasMeter: var GasMeter; amount: Int256) =
|
||||
if amount < 0.int256:
|
||||
raise newException(ValidationError, "Gas refund amount must be positive")
|
||||
proc refundGas*(gasMeter: var GasMeter; amount: UInt256) =
|
||||
#if amount < 0.int256:
|
||||
# raise newException(ValidationError, "Gas refund amount must be positive")
|
||||
gasMeter.gasRefunded += amount
|
||||
gasMeter.logger.trace(
|
||||
&"GAS REFUND: {gasMeter.gasRemaining - amount} + {amount} -> {gasMeter.gasRefunded}")
|
||||
|
@ -15,37 +15,37 @@ proc newMemory*: Memory =
|
||||
proc len*(memory: Memory): int =
|
||||
result = memory.bytes.len
|
||||
|
||||
proc extend*(memory: var Memory; startPosition: Int256; size: Int256) =
|
||||
proc extend*(memory: var Memory; startPosition: UInt256; size: UInt256) =
|
||||
if size == 0:
|
||||
return
|
||||
var newSize = ceil32(startPosition + size)
|
||||
if newSize <= len(memory).int256:
|
||||
if newSize <= len(memory).u256:
|
||||
return
|
||||
var sizeToExtend = newSize - len(memory).int256
|
||||
memory.bytes = memory.bytes.concat(repeat(0.byte, sizeToExtend.getInt))
|
||||
var sizeToExtend = newSize - len(memory).u256
|
||||
memory.bytes = memory.bytes.concat(repeat(0.byte, sizeToExtend.getUInt.int))
|
||||
|
||||
proc newMemory*(size: Int256): Memory =
|
||||
proc newMemory*(size: UInt256): Memory =
|
||||
result = newMemory()
|
||||
result.extend(0.int256, size)
|
||||
result.extend(0.u256, size)
|
||||
|
||||
proc read*(memory: var Memory, startPosition: Int256, size: Int256): seq[byte] =
|
||||
result = memory.bytes[startPosition.getInt ..< (startPosition + size).getInt]
|
||||
proc read*(memory: var Memory, startPosition: UInt256, size: UInt256): seq[byte] =
|
||||
result = memory.bytes[startPosition.getUInt.int ..< (startPosition + size).getUInt.int]
|
||||
|
||||
proc write*(memory: var Memory, startPosition: Int256, size: Int256, value: seq[byte]) =
|
||||
proc write*(memory: var Memory, startPosition: UInt256, size: UInt256, value: seq[byte]) =
|
||||
if size == 0:
|
||||
return
|
||||
#echo size
|
||||
#echo startPosition
|
||||
validateGte(startPosition, 0)
|
||||
validateGte(size, 0)
|
||||
validateLength(value, size.getInt)
|
||||
#validateGte(startPosition, 0)
|
||||
#validateGte(size, 0)
|
||||
validateLength(value, size.getUInt.int)
|
||||
validateLte(startPosition + size, memory.len)
|
||||
let index = memory.len
|
||||
if memory.len.i256 < startPosition + size:
|
||||
memory.bytes = memory.bytes.concat(repeat(0.byte, memory.len - (startPosition + size).getInt)) # TODO: better logarithmic scaling?
|
||||
if memory.len.u256 < startPosition + size:
|
||||
memory.bytes = memory.bytes.concat(repeat(0.byte, memory.len - (startPosition + size).getUInt.int)) # TODO: better logarithmic scaling?
|
||||
|
||||
for z, b in value:
|
||||
memory.bytes[z + startPosition.getInt] = b
|
||||
memory.bytes[z + startPosition.getUInt.int] = b
|
||||
|
||||
template write*(memory: var Memory, startPosition: Int256, size: Int256, value: cstring) =
|
||||
template write*(memory: var Memory, startPosition: UInt256, size: UInt256, value: cstring) =
|
||||
memory.write(startPosition, size, value.toBytes)
|
||||
|
@ -17,11 +17,11 @@ type
|
||||
|
||||
# logger = logging.getLogger("evm.vm.message.Message")
|
||||
|
||||
gas*: Int256
|
||||
gasPrice*: Int256
|
||||
gas*: UInt256
|
||||
gasPrice*: UInt256
|
||||
to*: string
|
||||
sender*: string
|
||||
value*: Int256
|
||||
value*: UInt256
|
||||
data*: seq[byte]
|
||||
code*: string
|
||||
internalOrigin: string
|
||||
@ -66,11 +66,11 @@ proc newMessageOptions*(
|
||||
isStatic: isStatic)
|
||||
|
||||
proc newMessage*(
|
||||
gas: Int256,
|
||||
gasPrice: Int256,
|
||||
gas: UInt256,
|
||||
gasPrice: UInt256,
|
||||
to: string,
|
||||
sender: string,
|
||||
value: Int256,
|
||||
value: UInt256,
|
||||
data: seq[byte],
|
||||
code: string,
|
||||
options: MessageOptions = newMessageOptions()): Message =
|
||||
|
159
src/vm/stack.nim
159
src/vm/stack.nim
@ -1,13 +1,12 @@
|
||||
import
|
||||
strformat, strutils, sequtils, macros,
|
||||
value, ../errors, ../validation, ../utils_numeric, ../constants, ttmath, ../logging
|
||||
value, ../errors, ../validation, ../utils_numeric, ../constants, ttmath, ../logging, .. / utils / bytes
|
||||
|
||||
type
|
||||
|
||||
Stack* = ref object of RootObj
|
||||
## VM Stack
|
||||
logger*: Logger
|
||||
values*: seq[Value]
|
||||
values*: seq[UInt256]
|
||||
|
||||
template ensureStackLimit: untyped =
|
||||
if len(stack.values) > 1023:
|
||||
@ -16,86 +15,80 @@ template ensureStackLimit: untyped =
|
||||
proc len*(stack: Stack): int =
|
||||
len(stack.values)
|
||||
|
||||
proc push*(stack: var Stack; value: Value) =
|
||||
## Push an item onto the stack
|
||||
template toType(i: UInt256, _: typedesc[UInt256]): UInt256 =
|
||||
i
|
||||
|
||||
template toType(i: UInt256, _: typedesc[string]): string =
|
||||
i.intToBigEndian.toString
|
||||
|
||||
template toType(i: UInt256, _: typedesc[Bytes]): Bytes =
|
||||
i.intToBigEndian
|
||||
|
||||
template toType(b: string, _: typedesc[UInt256]): UInt256 =
|
||||
b.toBytes.bigEndianToInt
|
||||
|
||||
template toType(b: string, _: typedesc[string]): string =
|
||||
b
|
||||
|
||||
template toType(b: string, _: typedesc[Bytes]): Bytes =
|
||||
b.toBytes
|
||||
|
||||
template toType(b: Bytes, _: typedesc[UInt256]): UInt256 =
|
||||
b.bigEndianToInt
|
||||
|
||||
template toType(b: Bytes, _: typedesc[string]): string =
|
||||
b.toString
|
||||
|
||||
template toType(b: Bytes, _: typedesc[Bytes]): Bytes =
|
||||
b
|
||||
|
||||
proc push*(stack: var Stack, value: uint) =
|
||||
## Push an integer onto the stack
|
||||
ensureStackLimit()
|
||||
|
||||
stack.values.add(value.u256)
|
||||
|
||||
proc push*(stack: var Stack, value: UInt256) =
|
||||
## Push an integer onto the stack
|
||||
ensureStackLimit()
|
||||
if value.kind == VInt:
|
||||
validateGte(value.i, 0)
|
||||
else:
|
||||
validateStackItem(value.b)
|
||||
|
||||
stack.values.add(value)
|
||||
|
||||
proc push*(stack: var Stack; value: int) =
|
||||
## Push an integer onto the stack
|
||||
ensureStackLimit()
|
||||
validateGte(value, 0)
|
||||
|
||||
stack.values.add(Value(kind: VInt, i: value.int256))
|
||||
|
||||
proc push*(stack: var Stack; value: Int256) =
|
||||
## Push an integer onto the stack
|
||||
ensureStackLimit()
|
||||
validateGte(value, 0)
|
||||
|
||||
stack.values.add(Value(kind: VInt, i: value))
|
||||
|
||||
proc push*(stack: var Stack; value: string) =
|
||||
proc push*(stack: var Stack, value: string) =
|
||||
## Push a binary onto the stack
|
||||
ensureStackLimit()
|
||||
validateStackItem(value)
|
||||
|
||||
stack.values.add(Value(kind: VBinary, b: value))
|
||||
stack.values.add(value.toType(UInt256))
|
||||
|
||||
proc internalPop(stack: var Stack; numItems: int): seq[Value] =
|
||||
proc push*(stack: var Stack, value: Bytes) =
|
||||
ensureStackLimit()
|
||||
validateStackItem(value)
|
||||
|
||||
stack.values.add(value.toType(UInt256))
|
||||
|
||||
proc internalPop(stack: var Stack, numItems: int): seq[UInt256] =
|
||||
if len(stack) < numItems:
|
||||
result = @[]
|
||||
else:
|
||||
result = stack.values[^numItems .. ^1]
|
||||
stack.values = stack.values[0 ..< ^numItems]
|
||||
|
||||
template toType(i: Int256, _: typedesc[Int256]): Int256 =
|
||||
i
|
||||
|
||||
template toType(i: Int256, _: typedesc[string]): string =
|
||||
intToBigEndian(i)
|
||||
|
||||
template toType(b: string, _: typedesc[Int256]): Int256 =
|
||||
bigEndianToInt(b)
|
||||
|
||||
template toType(b: string, _: typedesc[string]): string =
|
||||
b
|
||||
|
||||
proc internalPop(stack: var Stack; numItems: int, T: typedesc): seq[T] =
|
||||
proc internalPop(stack: var Stack, numItems: int, T: typedesc): seq[T] =
|
||||
result = @[]
|
||||
if len(stack) < numItems:
|
||||
return
|
||||
|
||||
for z in 0 ..< numItems:
|
||||
var value = stack.values.pop()
|
||||
case value.kind:
|
||||
of VInt:
|
||||
result.add(toType(value.i, T))
|
||||
of VBinary:
|
||||
result.add(toType(value.b, T))
|
||||
result.add(toType(value, T))
|
||||
|
||||
template ensurePop(elements: untyped, a: untyped): untyped =
|
||||
if len(`elements`) < `a`:
|
||||
raise newException(InsufficientStack, "No stack items")
|
||||
|
||||
proc pop*(stack: var Stack): Value =
|
||||
## Pop an item off the stack
|
||||
var elements = stack.internalPop(1)
|
||||
ensurePop(elements, 1)
|
||||
result = elements[0]
|
||||
|
||||
proc pop*(stack: var Stack; numItems: int): seq[Value] =
|
||||
## Pop many items off the stack
|
||||
result = stack.internalPop(numItems)
|
||||
ensurePop(result, numItems)
|
||||
|
||||
proc popInt*(stack: var Stack): Int256 =
|
||||
var elements = stack.internalPop(1, Int256)
|
||||
proc popInt*(stack: var Stack): UInt256 =
|
||||
var elements = stack.internalPop(1, UInt256)
|
||||
ensurePop(elements, 1)
|
||||
result = elements[0]
|
||||
|
||||
@ -114,11 +107,7 @@ macro internalPopTuple(numItems: static[int]): untyped =
|
||||
var zNode = newLit(z)
|
||||
var element = quote:
|
||||
var value = `stackNode`.values.pop()
|
||||
case value.kind:
|
||||
of VInt:
|
||||
`resultNode`[`zNode`] = toType(value.i, `t`)
|
||||
of VBinary:
|
||||
`resultNode`[`zNode`] = toType(value.b, `t`)
|
||||
`resultNode`[`zNode`] = toType(value, `t`)
|
||||
result[^1].add(element)
|
||||
|
||||
# define pop<T> for tuples
|
||||
@ -129,26 +118,31 @@ internalPopTuple(5)
|
||||
internalPopTuple(6)
|
||||
internalPopTuple(7)
|
||||
|
||||
macro popInt*(stack: typed; numItems: static[int]): untyped =
|
||||
macro popInt*(stack: typed, numItems: static[int]): untyped =
|
||||
var resultNode = ident("result")
|
||||
if numItems >= 8:
|
||||
result = quote:
|
||||
`stack`.internalPop(`numItems`, Int256)
|
||||
`stack`.internalPop(`numItems`, UInt256)
|
||||
else:
|
||||
var name = ident(&"internalPopTuple{numItems}")
|
||||
result = quote:
|
||||
`name`(`stack`, Int256)
|
||||
`name`(`stack`, UInt256)
|
||||
|
||||
# proc popInt*(stack: var Stack, numItems: int): seq[Int256] =
|
||||
# result = stack.internalPop(numItems, Int256)
|
||||
# ensurePop(result, numItems)
|
||||
proc popBinary*(stack: var Stack): Bytes =
|
||||
var elements = stack.internalPop(1, Bytes)
|
||||
ensurePop(elements, 1)
|
||||
result = elements[0]
|
||||
|
||||
proc popBinary*(stack: var Stack): string =
|
||||
proc popBinary*(stack: var Stack, numItems: int): seq[Bytes] =
|
||||
result = stack.internalPop(numItems, Bytes)
|
||||
ensurePop(result, numItems)
|
||||
|
||||
proc popString*(stack: var Stack): string =
|
||||
var elements = stack.internalPop(1, string)
|
||||
ensurePop(elements, 1)
|
||||
result = elements[0]
|
||||
|
||||
proc popBinary*(stack: var Stack; numItems: int): seq[string] =
|
||||
proc popString*(stack: var Stack, numItems: int): seq[string] =
|
||||
result = stack.internalPop(numItems, string)
|
||||
ensurePop(result, numItems)
|
||||
|
||||
@ -157,7 +151,7 @@ proc newStack*(): Stack =
|
||||
result.logger = logging.getLogger("stack.Stack")
|
||||
result.values = @[]
|
||||
|
||||
proc swap*(stack: var Stack; position: int) =
|
||||
proc swap*(stack: var Stack, position: int) =
|
||||
## Perform a SWAP operation on the stack
|
||||
var idx = position + 1
|
||||
if idx < len(stack) + 1:
|
||||
@ -166,7 +160,7 @@ proc swap*(stack: var Stack; position: int) =
|
||||
raise newException(InsufficientStack,
|
||||
&"Insufficient stack items for SWAP{position}")
|
||||
|
||||
proc dup*(stack: var Stack; position: int | Int256) =
|
||||
proc dup*(stack: var Stack, position: int | UInt256) =
|
||||
## Perform a DUP operation on the stack
|
||||
if (position != 0 and position.getInt < stack.len + 1) or (position == 0 and position.getInt < stack.len):
|
||||
stack.push(stack.values[^position.getInt])
|
||||
@ -175,21 +169,14 @@ proc dup*(stack: var Stack; position: int | Int256) =
|
||||
&"Insufficient stack items for DUP{position}")
|
||||
|
||||
|
||||
proc getInt*(stack: Stack, position: int): Int256 =
|
||||
let element = stack.values[position]
|
||||
case element.kind:
|
||||
of VInt:
|
||||
result = element.i
|
||||
else:
|
||||
raise newException(TypeError, "Expected int")
|
||||
proc getInt*(stack: Stack, position: int): UInt256 =
|
||||
stack.values[position]
|
||||
|
||||
proc getBinary*(stack: Stack, position: int): string =
|
||||
let element = stack.values[position]
|
||||
case element.kind:
|
||||
of VBinary:
|
||||
result = element.b
|
||||
else:
|
||||
raise newException(TypeError, "Expected binary")
|
||||
proc getBinary*(stack: Stack, position: int): Bytes =
|
||||
stack.values[position].toType(Bytes)
|
||||
|
||||
proc getString*(stack: Stack, position: int): string =
|
||||
stack.values[position].toType(string)
|
||||
|
||||
proc `$`*(stack: Stack): string =
|
||||
let values = stack.values.mapIt(&" {$it}").join("\n")
|
||||
|
@ -1,5 +1,5 @@
|
||||
import
|
||||
strformat, strutils,
|
||||
strformat, strutils, sequtils,
|
||||
../constants, ttmath
|
||||
|
||||
type
|
||||
@ -10,7 +10,7 @@ type
|
||||
of VInt:
|
||||
i*: Int256
|
||||
of VBinary:
|
||||
b*: string
|
||||
b*: seq[byte]
|
||||
|
||||
proc `$`*(value: Value): string =
|
||||
case value.kind:
|
||||
@ -26,6 +26,9 @@ proc vint*(i: Int256): Value =
|
||||
Value(kind: VInt, i: i)
|
||||
|
||||
proc vbinary*(b: string): Value =
|
||||
Value(kind: VBinary, b: b.mapIt(it.byte))
|
||||
|
||||
proc vbinary*(b: seq[byte]): Value =
|
||||
Value(kind: VBinary, b: b)
|
||||
|
||||
proc `==`*(a: Value, b: Value): bool =
|
||||
|
@ -47,22 +47,22 @@ method coinbase*(vmState: BaseVMState): string =
|
||||
method timestamp*(vmState: BaseVMState): int =
|
||||
vmState.blockHeader.timestamp
|
||||
|
||||
method blockNumber*(vmState: BaseVMState): Int256 =
|
||||
method blockNumber*(vmState: BaseVMState): UInt256 =
|
||||
vmState.blockHeader.blockNumber
|
||||
|
||||
method difficulty*(vmState: BaseVMState): Int256 =
|
||||
method difficulty*(vmState: BaseVMState): UInt256 =
|
||||
vmState.blockHeader.difficulty
|
||||
|
||||
method gasLimit*(vmState: BaseVMState): Int256 =
|
||||
method gasLimit*(vmState: BaseVMState): UInt256 =
|
||||
vmState.blockHeader.gasLimit
|
||||
|
||||
method getAncestorHash*(vmState: BaseVMState, blockNumber: Int256): string =
|
||||
var ancestorDepth = vmState.blockHeader.blockNumber - blockNumber - 1.int256
|
||||
method getAncestorHash*(vmState: BaseVMState, blockNumber: UInt256): string =
|
||||
var ancestorDepth = vmState.blockHeader.blockNumber - blockNumber - 1.u256
|
||||
if ancestorDepth >= constants.MAX_PREV_HEADER_DEPTH or
|
||||
ancestorDepth < 0 or
|
||||
ancestorDepth >= vmState.prevHeaders.len.int256:
|
||||
ancestorDepth >= vmState.prevHeaders.len.u256:
|
||||
return ""
|
||||
var header = vmState.prevHeaders[ancestorDepth.getInt]
|
||||
var header = vmState.prevHeaders[ancestorDepth.getUInt.int]
|
||||
result = header.hash
|
||||
|
||||
macro db*(vmState: untyped, readOnly: untyped, handler: untyped): untyped =
|
||||
@ -72,7 +72,6 @@ macro db*(vmState: untyped, readOnly: untyped, handler: untyped): untyped =
|
||||
let db = ident("db")
|
||||
result = quote:
|
||||
block:
|
||||
echo `vmState`
|
||||
var `db` = `vmState`.chaindb.getStateDB(`vmState`.blockHeader.stateRoot, `readOnly`)
|
||||
`handler`
|
||||
if `readOnly`:
|
||||
|
@ -6,7 +6,7 @@ import unittest, macros, strformat, strutils, sequtils, constants, opcode_values
|
||||
disableLogging()
|
||||
|
||||
proc gasMeters: seq[GasMeter] =
|
||||
@[newGasMeter(10.i256), newGasMeter(100.i256), newGasMeter(999.i256)]
|
||||
@[newGasMeter(10.u256), newGasMeter(100.u256), newGasMeter(999.u256)]
|
||||
|
||||
macro all(element: untyped, handler: untyped): untyped =
|
||||
let name = ident(&"{element.repr}s")
|
||||
@ -47,20 +47,21 @@ macro all(element: untyped, handler: untyped): untyped =
|
||||
|
||||
|
||||
suite "gasMeter":
|
||||
test "consume rejects negative":
|
||||
all(gasMeter):
|
||||
expect(ValidationError):
|
||||
gasMeter.consumeGas(-1.i256, "independent")
|
||||
# types
|
||||
# test "consume rejects negative":
|
||||
# all(gasMeter):
|
||||
# expect(ValidationError):
|
||||
# gasMeter.consumeGas(-1.i256, "independent")
|
||||
|
||||
test "return rejects negative":
|
||||
all(gasMeter):
|
||||
expect(ValidationError):
|
||||
gasMeter.returnGas(-1.i256)
|
||||
# test "return rejects negative":
|
||||
# all(gasMeter):
|
||||
# expect(ValidationError):
|
||||
# gasMeter.returnGas(-1.i256)
|
||||
|
||||
test "refund rejects negative":
|
||||
all(gasMeter):
|
||||
expect(ValidationError):
|
||||
gasMeter.returnGas(-1.i256)
|
||||
# test "refund rejects negative":
|
||||
# all(gasMeter):
|
||||
# expect(ValidationError):
|
||||
# gasMeter.returnGas(-1.i256)
|
||||
|
||||
# TODO: -0/+0
|
||||
test "consume spends":
|
||||
@ -74,15 +75,15 @@ suite "gasMeter":
|
||||
all(gasMeter):
|
||||
check(gasMeter.gasRemaining == gasMeter.startGas)
|
||||
expect(OutOfGas):
|
||||
gasMeter.consumeGas(gasMeter.startGas + 1.i256, "")
|
||||
gasMeter.consumeGas(gasMeter.startGas + 1.u256, "")
|
||||
|
||||
test "return refund works correctly":
|
||||
all(gasMeter):
|
||||
check(gasMeter.gasRemaining == gasMeter.startGas)
|
||||
check(gasMeter.gasRefunded == 0)
|
||||
gasMeter.consumeGas(5.i256, "")
|
||||
check(gasMeter.gasRemaining == gasMeter.startGas - 5.i256)
|
||||
gasMeter.returnGas(5.i256)
|
||||
gasMeter.consumeGas(5.u256, "")
|
||||
check(gasMeter.gasRemaining == gasMeter.startGas - 5.u256)
|
||||
gasMeter.returnGas(5.u256)
|
||||
check(gasMeter.gasRemaining == gasMeter.startGas)
|
||||
gasMeter.refundGas(5.i256)
|
||||
check(gasMeter.gasRefunded == 5.i256)
|
||||
gasMeter.refundGas(5.u256)
|
||||
check(gasMeter.gasRefunded == 5.u256)
|
||||
|
@ -1,59 +1,6 @@
|
||||
import
|
||||
os, macros, json, strformat, strutils, ttmath, utils / [hexadecimal, address], chain, vm_state, constants, db / [db_chain, state_db], vm / forks / frontier / vm, parseutils
|
||||
os, macros, json, strformat, strutils, ttmath, utils / [hexadecimal, address], chain, vm_state, constants, db / [db_chain, state_db], vm / forks / frontier / vm, parseutils, ospaths
|
||||
|
||||
# TODO
|
||||
# This block is a child of the genesis defined in the chain fixture above and contains a single tx
|
||||
# that transfers 10 wei from 0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b to
|
||||
# 0x095e7baea6a6c7c4c2dfeb977efac326af552d87.
|
||||
# var validBlockRlp = decodeHex(
|
||||
# "0xf90260f901f9a07285abd5b24742f184ad676e31f6054663b3529bc35ea2fcad8a3e0f642a46f7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0964e6c9995e7e3757e934391b4f16b50c20409ee4eb9abd4c4617cb805449b9aa053d5b71a8fbb9590de82d69dfa4ac31923b0c8afce0d30d0d8d1e931f25030dca0bc37d79753ad738a6dac4921e57392f145d8887476de3f783dfa7edae9283e52b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd8825208845754132380a0194605bacef646779359318c7b5899559a5bf4074bbe2cfb7e1b83b1504182dd88e0205813b22e5a9cf861f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba0f3266921c93d600c43f6fa4724b7abae079b35b9e95df592f95f9f3445e94c88a012f977552ebdb7a492cf35f3106df16ccb4576ebad4113056ee1f52cbe4978c1c0") # noqa: E501
|
||||
#
|
||||
# type
|
||||
# PrivateKey = object # TODO
|
||||
# publicKey*: cstring
|
||||
#
|
||||
# proc testChain*: Chain =
|
||||
# # Return a Chain object containing just the genesis block.
|
||||
# #
|
||||
# # This Chain does not perform any validation when importing new blocks.
|
||||
# #
|
||||
# # The Chain's state includes one funded account and a private key for it, which can be found in
|
||||
# # the funded_address and private_keys variables in the chain itself.
|
||||
# # Disable block validation so that we don't need to construct finalized blocks.
|
||||
#
|
||||
# var klass = configureChain(
|
||||
# "TestChainWithoutBlockValidation",
|
||||
# constants.GENESIS_BLOCK_NUMBER,
|
||||
# FrontierVM,
|
||||
# importBlock=false,
|
||||
# validateBlock=false)
|
||||
#
|
||||
# var privateKey = PrivateKey(publicKey: cstring"0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8") # TODO
|
||||
# var fundedAddress = privateKey.publicKey.toCanonicalAddress()
|
||||
# var initialBalance = 100_000_000
|
||||
# var genesisParams = GenesisParams(
|
||||
# blockNumber: constants.GENESIS_BLOCK_NUMBER,
|
||||
# difficulty: constants.GENESIS_DIFFICULTY,
|
||||
# gasLimit: constants.GENESIS_GAS_LIMIT,
|
||||
# parentHash: constants.GENESIS_PARENT_HASH,
|
||||
# coinbase: constants.GENESIS_COINBASE,
|
||||
# nonce: constants.GENESIS_NONCE,
|
||||
# mixHash: constants.GENESIS_MIX_HASH,
|
||||
# extraData: constants.GENESIS_EXTRA_DATA,
|
||||
# timestamp: 1501851927,
|
||||
# stateRoot: decodeHex("0x9d354f9b5ba851a35eced279ef377111387197581429cfcc7f744ef89a30b5d4"))
|
||||
#
|
||||
# var genesisState = GenesisState(
|
||||
# fundedAddress: FundedAddress(
|
||||
# balance: initialBalance,
|
||||
# nonce: 0,
|
||||
# code: cstring""))
|
||||
#
|
||||
# result = klass.fromGenesis(newBaseChainDB(getDbBackend()), genesisParams, genesisState)
|
||||
# result.fundedAddress = fundedAddress
|
||||
# result.fundedAddressInitialBalance = initialBalance
|
||||
# result.fundedAddressPrivateKey = privateKey
|
||||
#
|
||||
proc generateTest(filename: string, handler: NimNode): NimNode =
|
||||
echo filename
|
||||
let testStatusIMPL = ident("testStatusIMPL")
|
||||
@ -63,23 +10,24 @@ proc generateTest(filename: string, handler: NimNode): NimNode =
|
||||
|
||||
macro jsonTest*(s: static[string], handler: untyped): untyped =
|
||||
result = nnkStmtList.newTree()
|
||||
echo &"tests/fixtures/{s}"
|
||||
#echo &"tests/fixtures/{s}"
|
||||
var z = 0
|
||||
for filename in walkDirRec(&"tests/fixtures/{s}"):
|
||||
if "mul" in filename:
|
||||
if z >= 4:
|
||||
break
|
||||
for filename in walkDirRec("tests" / "fixtures" / s):
|
||||
var (folder, name) = filename.splitPath()
|
||||
#if "Arithmetic" in folder: #
|
||||
if name.startswith("swap"):
|
||||
echo name
|
||||
result.add(generateTest(filename, handler))
|
||||
z += 1
|
||||
|
||||
proc setupStateDB*(desiredState: JsonNode, stateDB: var AccountStateDB) =
|
||||
for account, accountData in desiredState:
|
||||
for slot, value in accountData{"storage"}:
|
||||
stateDB.setStorage(account, slot.parseInt.i256, value.getInt.i256)
|
||||
stateDB.setStorage(account, slot.parseInt.u256, value.getInt.u256)
|
||||
|
||||
let nonce = accountData{"nonce"}.getInt.i256
|
||||
let nonce = accountData{"nonce"}.getInt.u256
|
||||
let code = accountData{"code"}.getStr
|
||||
let balance = accountData{"balance"}.getInt.i256
|
||||
let balance = accountData{"balance"}.getInt.u256
|
||||
|
||||
stateDB.setNonce(account, nonce)
|
||||
stateDB.setCode(account, code)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import
|
||||
unittest, strformat, strutils, sequtils, tables, ttmath, json,
|
||||
test_helpers, constants, errors, logging,
|
||||
chain, vm_state, computation, opcode, opcode_table, utils / header, vm / [gas_meter, message, code_stream], vm / forks / frontier / vm, db / [db_chain, state_db], db / backends / memory_backend
|
||||
chain, vm_state, computation, opcode, opcode_table, utils / header, vm / [gas_meter, message, code_stream, stack], vm / forks / frontier / vm, db / [db_chain, state_db], db / backends / memory_backend
|
||||
|
||||
|
||||
proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus)
|
||||
@ -17,9 +17,9 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
||||
var vm = newFrontierVM(Header(), newBaseChainDB(newMemoryDB()))
|
||||
let header = Header(
|
||||
coinbase: fixture{"env"}{"currentCoinbase"}.getStr,
|
||||
difficulty: fixture{"env"}{"currentDifficulty"}.getHexadecimalInt.i256,
|
||||
blockNumber: fixture{"env"}{"currentNumber"}.getHexadecimalInt.i256,
|
||||
gasLimit: fixture{"env"}{"currentGasLimit"}.getHexadecimalInt.i256,
|
||||
difficulty: fixture{"env"}{"currentDifficulty"}.getHexadecimalInt.u256,
|
||||
blockNumber: fixture{"env"}{"currentNumber"}.getHexadecimalInt.u256,
|
||||
gasLimit: fixture{"env"}{"currentGasLimit"}.getHexadecimalInt.u256,
|
||||
timestamp: fixture{"env"}{"currentTimestamp"}.getHexadecimalInt)
|
||||
|
||||
var code = ""
|
||||
@ -31,18 +31,19 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
||||
let message = newMessage(
|
||||
to=fixture{"exec"}{"address"}.getStr,
|
||||
sender=fixture{"exec"}{"caller"}.getStr,
|
||||
value=fixture{"exec"}{"value"}.getHexadecimalInt.i256,
|
||||
value=fixture{"exec"}{"value"}.getHexadecimalInt.u256,
|
||||
data=fixture{"exec"}{"data"}.getStr.mapIt(it.byte),
|
||||
code=code,
|
||||
gas=fixture{"exec"}{"gas"}.getHexadecimalInt.i256,
|
||||
gasPrice=fixture{"exec"}{"gasPrice"}.getHexadecimalInt.i256,
|
||||
gas=fixture{"exec"}{"gas"}.getHexadecimalInt.u256,
|
||||
gasPrice=fixture{"exec"}{"gasPrice"}.getHexadecimalInt.u256,
|
||||
options=newMessageOptions(origin=fixture{"exec"}{"origin"}.getStr))
|
||||
|
||||
echo fixture{"exec"}
|
||||
#echo fixture{"exec"}
|
||||
var c = newCodeStreamFromUnescaped(code)
|
||||
var opcodes = c.decompile
|
||||
for opcode in opcodes:
|
||||
echo opcode[0], " ", opcode[1], " ", opcode[2]
|
||||
if DEBUG:
|
||||
for opcode in opcodes:
|
||||
echo opcode[0], " ", opcode[1], " ", opcode[2]
|
||||
|
||||
var computation = newBaseComputation(vm.state, message)
|
||||
computation.accountsToDelete = initTable[string, string]()
|
||||
@ -69,10 +70,10 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
||||
check(computation.output == expectedOutput)
|
||||
let gasMeter = computation.gasMeter
|
||||
|
||||
let expectedGasRemaining = fixture{"gas"}.getHexadecimalInt.i256
|
||||
let expectedGasRemaining = fixture{"gas"}.getHexadecimalInt.u256
|
||||
let actualGasRemaining = gasMeter.gasRemaining
|
||||
let gasDelta = actualGasRemaining - expectedGasRemaining
|
||||
check(gasDelta == 0)
|
||||
#let gasDelta = actualGasRemaining - expectedGasRemaining
|
||||
check(actualGasRemaining == expectedGasRemaining)
|
||||
|
||||
let callCreatesJson = fixture{"callcreates"}
|
||||
var callCreates: seq[JsonNode] = @[]
|
||||
@ -85,8 +86,8 @@ 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.i256
|
||||
let value = createdCall{"value"}.getHexadecimalInt.i256
|
||||
let gasLimit = createdCall{"gasLimit"}.getHexadecimalInt.u256
|
||||
let value = createdCall{"value"}.getHexadecimalInt.u256
|
||||
|
||||
check(childComputation.msg.to == toAddress)
|
||||
check(data == childComputation.msg.data or childComputation.msg.code.len > 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user