Delete utilities: address, padding, bytes (#68)

* Delete utilities: address, padding, bytes

* Remove bigEndianToInt

* Fix C compiler error: member reference base type 'char' is not a structure or union

* fix todo comment
This commit is contained in:
Mamy Ratsimbazafy 2018-07-06 17:08:31 +02:00 committed by GitHub
parent 4b5eada322
commit 4dd75aee84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 70 additions and 424 deletions

View File

@ -1,6 +1,6 @@
import
math, strutils, utils/padding, eth_common
math, strutils, eth_common
proc default(t: typedesc): t = discard
@ -8,8 +8,6 @@ proc default(t: typedesc): t = discard
const
UINT_256_MAX*: UInt256 = high(UInt256)
INT_256_MAX_AS_UINT256* = high(Uint256) shr 1
NULLBYTE* = "\x00"
EMPTYWORD* = repeat(NULLBYTE, 32)
UINT160CEILING*: UInt256 = 2.u256.pow(160)
ZERO_ADDRESS* = default(EthAddress)
CREATE_CONTRACT_ADDRESS* = ZERO_ADDRESS

View File

@ -1,153 +0,0 @@
# Nimbus
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import strformat, strutils, encodings, keccak, padding
proc toText*(c: cstring): string =
($c).convert(destEncoding="iso-8859-1")
proc toCanonicalAddress*(address: string): string =
# TODO
address
# address.toNormalizedAddress.decodeHex
template toCanonicalAddress*(address: cstring): string =
address.toText.toCanonicalAddress
proc forceBytesToAddress*(address: string): string =
padLeft(address[^20..^1], 20, "\x00")
template forceBytesToAddress*(address: cstring): string =
address.toText.forceBytesToAddress
proc generateContractAddress*(address: string, nonce: string): string =
""
# keccak(rlp.encode(@[address, nonce]))[^20..^1]
# proc isNormalizedAddress*(value: string): bool =
# # Returns whether the provided value is an address in it's normalized form
# if not value.isAddress:
# false
# else:
# value == value.toNormalizedAddress
# proc toNormalizedAddress*(address: string): string =
# # Converts an address to it's normalized hexidecimal representation
# if address.isHexAddress:
# address.normalizeHexAddress
# elif address.isBinaryAddress:
# address.normalizeBinaryAddress
# elif address.is32byteaddress:
# address.normalize32byteAddress
# else:
# raise newException(ValueError, &"Unknown address format {address}")
# proc toNormalizedAddress*(address: cstring): string =
# toNormalizedAddress(address.toText)
# proc isAddress*(value: string): bool
# # Checks if the given string is an address in any of the known formats
# if value.isChecksumFormattedAddress:
# value.isChecksumAddress
# elif value.isHexAddress:
# true
# elif value.isBinaryAddress:
# true
# elif value.is32byteAddress:
# true
# else:
# false
# proc toCanonicalAddress*(address: cstring): string =
# address.toText.toNormalizedAddress.decodeHex
# proc toCanonicalAddress*(address: string): string =
# address.toNormalizedAddress.decodeHex
# proc isHexAddress(value: string): cstring =
# # Checks if the given string is an address in hexidecimal encoded form
# if value.len notin {42, 40}:
# false
# else:
# value.isHex:
# proc isBinaryAddress(value: string): bool =
# # Checks if the given string is an address in raw bytes form
# value.len == 20
# proc is32byteAddress(value: string): bool =
# # Checks if the given string is an address in hexidecimal encoded form padded to 32 bytes
# let valueAsHex = ""
# if value.len == 32:
# valueAsHex = value.encodeHex
# elif value.len in {66, 64}:
# valueAsHex = value.add0xprefix
# else:
# return false
# if valueAsHex.isPrefixed("0x000000000000000000000000"):
# try:
# return valueAsHex.parseHexInt > 0
# except ValueError:
# false
# else:
# return false
# proc normalizeHexAddress(address: string): string =
# # Returns a hexidecimal address in its normalized hexidecimal representation
# address.toLowerAscii.add0xPrefix
# proc normalizeBinaryAddress(address: string): string =
# # Returns a raw binary address in its normalized hexidecimal representation
# address.encodeHex.normalizeHexAddress
# proc normalize32byteAddress(address: string): string =
# if address.len == 32:
# address[^20..^1].normalizeBinaryAddress
# elif address.len in {66, 64}:
# address[^40..^1].normalizeHexAddress
# else:
# raise newException(ValueError, "Invalid address(must be 32 byte value)")
# proc isCanonicalAddress(value: string): bool =
# if not value.isAddress
# false
# else:
# value == value.toCanonicalAddress
# proc isSameAddress(left: string, right: string): bool =
# # Checks if both addresses are same or not
# if not left.isAddress or not right.isAddress:
# raise newException(ValueError, "Both values must be valid addresses")
# else:
# left.toNormalizedAddress == right.toNormalizedAddress
# proc toChecksumAddress*(address: string): string =
# # Makes a checksum address
# let normAddress = address.toNormalizedAddress
# let addressHash = normAddress.remove0xPrefix.keccak.encodeHex
# var s = ""
# for z in 2 ..< 42:
# s.add(if addressHash[z].parseHexInt > 7: normAddress[z].toUpperAscii() else: normAddress[z])
# result = s.join("").add0xPrefix
# proc toChecksumAddress*(address: cstring): string =
# address.toText.toChecksumAddress
# proc isChecksumAddress(value: string): bool =
# if not value.isHexAddress:
# false
# else:
# value == value.toChecksumAddress
# proc isChecksumFormattedAddress*(value: string): bool =
# if not value.isHexAddress:
# false
# else:
# let r = value.remove0xPrefix
# r != r.toLowerAscii and r != r.toUpperAscii

View File

@ -1,26 +0,0 @@
# Nimbus
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import strutils, sequtils
# proc toBytes*(value: cstring): seq[byte] =
# result = newSeq[byte](value.len)
# for z, c in value:
# result[z] = c.byte
# # result = toSeq(value)
# proc toCString*(value: seq[byte]): cstring =
# var res = ""
# for c in value:
# res.add(c.char)
# cstring(res) # TODO: faster
proc toString*(value: seq[byte]): string =
"0x" & value.mapIt(it.int.toHex(2)).join("").toLowerAscii
proc toBytes*(value: string): seq[byte] =
result = value.mapIt(it.byte)

View File

@ -1,156 +0,0 @@
# Nimbus
# Copyright (c) 2018 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import strformat, strutils
proc repeat*(b: cstring, count: int): cstring =
# TODO
result = cstring(repeat($b, count))
proc pad(value: cstring, size: int, with: cstring, left: bool): cstring =
let padAmount = size - value.len
if padAmount > 0:
let fill = repeat(($with), padAmount)
if left:
result = cstring(&"{fill}{value}")
else:
result = cstring(&"{value}{fill}")
else:
result = value
proc pad(value: string, size: int, with: string, left: bool): string =
let padAmount = size - value.len
if padAmount > 0:
let fill = repeat(with, padAmount)
if left:
result = &"{fill}{value}"
else:
result = &"{value}{fill}"
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)
template padRight*(value: cstring, size: int, with: cstring): cstring =
pad(value, size, with, false)
template zpadRight*(value: cstring, size: int): cstring =
padRight(value, size, with=cstring"\x00")
template zpadLeft*(value: cstring, size: int): cstring =
padLeft(value, size, with=cstring"\x00")
template pad32*(value: cstring): cstring =
zpadLeft(value, size=32)
template pad32r*(value: cstring): cstring =
zpadRight(value, size=32)
template padLeft*(value: string, size: int, with: string): string =
pad(value, size, with, true)
template padRight*(value: string, size: int, with: string): string =
pad(value, size, with, false)
template zpadRight*(value: string, size: int): string =
padRight(value, size, with="\x00")
template zpadLeft*(value: string, size: int): string =
padLeft(value, size, with="\x00")
template pad32*(value: string): string =
zpadLeft(value, size=32)
template pad32r*(value: string): string =
zpadRight(value, size=32)
proc lStrip*(value: cstring, c: char): cstring =
var z = 0
while z < value.len and value[z] == c:
z += 1
if z == 0:
result = value
elif z == value.len:
result = cstring""
else:
result = cstring(($value)[z..^1])
proc rStrip*(value: cstring, c: char): cstring =
var z = value.len - 1
while z >= 0 and value[z] == c:
z -= 1
if z == value.len - 1:
result = value
elif z == -1:
result = cstring""
else:
result = cstring(($value)[0..z])
proc strip*(value: cstring, c: char): cstring =
result = value.lStrip(c).rStrip(c)
proc lStrip*(value: string, c: char): string =
value.strip(chars={c}, trailing=false)
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]

View File

@ -7,7 +7,7 @@
import
strformat, strutils, sequtils, macros, terminal, math, tables,
eth_common, byteutils,
eth_common,
../constants, ../errors, ../validation, ../vm_state, ../logging, ../vm_types,
./interpreter/[opcode_values, gas_meter, gas_costs, vm_forks],
./code_stream, ./memory, ./message, ./stack
@ -23,7 +23,7 @@ proc newBaseComputation*(vmState: BaseVMState, blockNumber: UInt256, message: Me
result.accountsToDelete = initTable[EthAddress, EthAddress]()
result.logEntries = @[]
result.code = newCodeStreamFromUnescaped(message.code) # TODO: what is the best repr
result.rawOutput = "0x"
# result.rawOutput = "0x"
result.gasCosts = blockNumber.toFork.forkToSchedule
proc logger*(computation: BaseComputation): Logger =
@ -45,13 +45,17 @@ proc shouldBurnGas*(c: BaseComputation): bool =
proc shouldEraseReturnData*(c: BaseComputation): bool =
c.isError and c.error.erasesReturnData
func bytesToHex(x: openarray[byte]): string {.inline.} =
## TODO: use seq[byte] for raw data and delete this proc
foldl(x, a & b.int.toHex(2).toLowerAscii, "0x")
proc prepareChildMessage*(
c: var BaseComputation,
gas: GasInt,
to: EthAddress,
value: UInt256,
data: seq[byte],
code: string,
code: seq[byte],
options: MessageOptions = newMessageOptions()): Message =
var childOptions = options
@ -63,17 +67,22 @@ proc prepareChildMessage*(
to,
value,
data,
code,
code.bytesToHex, # TODO: use seq[byte] for Message as well
childOptions)
proc output*(c: BaseComputation): string =
func output*(c: BaseComputation): seq[byte] =
if c.shouldEraseReturnData:
""
@[]
else:
c.rawOutput
proc `output=`*(c: var BaseComputation, value: string) =
c.rawOutput = value
func `output=`*(c: var BaseComputation, value: openarray[byte]) =
c.rawOutput = @value
proc outputHex*(c: BaseComputation): string =
if c.shouldEraseReturnData:
return "0x"
c.rawOutput.bytesToHex
proc registerAccountForDeletion*(c: var BaseComputation, beneficiary: EthAddress) =
validateCanonicalAddress(beneficiary, title="self destruct beneficiary address")
@ -84,7 +93,7 @@ proc registerAccountForDeletion*(c: var BaseComputation, beneficiary: EthAddress
"registered for deletion multiple times")
c.accountsToDelete[c.msg.storageAddress] = beneficiary
proc addLogEntry*(c: var BaseComputation, account: EthAddress, topics: seq[UInt256], data: string) =
proc addLogEntry*(c: var BaseComputation, account: EthAddress, topics: seq[UInt256], data: seq[byte]) =
validateCanonicalAddress(account, title="log entry address")
c.logEntries.add((account, topics, data))

View File

@ -9,8 +9,6 @@ import
./interpreter/[opcode_values, gas_meter],
./interpreter/vm_forks
from ./interpreter/utils/utils_numeric import bigEndianToInt
import # Used in vm_types. Beware of recursive dependencies
./code_stream, ./computation, ./stack, ./message, interpreter_dispatch
@ -18,7 +16,5 @@ export
opcode_values, gas_meter,
vm_forks
export utils_numeric.bigEndianToInt
export
code_stream, computation, stack, message, interpreter_dispatch

View File

@ -12,8 +12,7 @@ import
./gas_meter, ./gas_costs, ./opcode_values, ./vm_forks,
../memory, ../message, ../stack, ../code_stream, ../computation,
../../vm_state, ../../errors, ../../constants, ../../vm_types, ../../logging,
../../db/[db_chain, state_db],
../../utils/[bytes, padding, address] # TODO remove those dependencies
../../db/[db_chain, state_db]
# ##################################
# Syntactic sugar
@ -266,15 +265,7 @@ op callDataCopy, inline = false, memStartPos, copyStartPos, size:
computation.gasCosts[CallDataCopy].m_handler(memPos, copyPos, len),
reason="CallDataCopy fee")
computation.memory.extend(memPos, len)
# If the data does not take 32 bytes, pad with zeros
let lim = min(computation.msg.data.len, copyPos + len)
let padding = copyPos + len - lim
# Note: when extending, extended memory is zero-ed, we only need to offset with padding value
# Also memory.write handles the case where copyPos+padding is out of bounds
computation.memory.write(memPos):
computation.msg.data.toOpenArray(copyPos+padding, copyPos+lim)
computation.memory.writePaddedResult(computation.code.bytes, memPos, copyPos, len)
op codesize, inline = true:
## 0x38, Get size of code running in current environment.
@ -548,7 +539,7 @@ op create, inline = false, value, startPosition, size:
to = CREATE_CONTRACT_ADDRESS,
value = value,
data = @[],
code = callData.toString,
code = callData,
options = MessageOptions(createAddress: contractAddress)
)
@ -709,7 +700,7 @@ template genCall(callName: untyped): untyped =
# computation.vmState.db(readOnly = true):
# let code = if codeAddress != ZERO_ADDRESS: db.getCode(codeAddress)
# else: db.getCode(to)
let code = "0x" # This is a stub hack, newCodeStreamFromUnescaped expects length 2 at least
let code: seq[byte] = @[]
var childMsg = prepareChildMessage(
computation,
@ -740,7 +731,7 @@ template genCall(callName: untyped): untyped =
let actualOutputSize = min(memOutLen, childComputation.output.len)
computation.memory.write(
memOutPos,
childComputation.output.toBytes[0 ..< actualOutputSize])
childComputation.output.toOpenArray(0, actualOutputSize))
if not childComputation.shouldBurnGas:
computation.gasMeter.returnGas(childComputation.gasMeter.gasRemaining)
@ -759,8 +750,7 @@ op returnOp, inline = false, startPos, size:
)
computation.memory.extend(pos, len)
let output = computation.memory.read(pos, len)
computation.output = output.toString
computation.output = computation.memory.read(pos, len)
op revert, inline = false, startPos, size:
## 0xf0, Halt execution reverting state changes but returning data and remaining gas.
@ -772,8 +762,7 @@ op revert, inline = false, startPos, size:
)
computation.memory.extend(pos, len)
let output = computation.memory.read(pos, len).toString
computation.output = output
computation.output = computation.memory.read(pos, len)
op selfDestruct, inline = false:
## 0xff Halt execution and register account for later deletion.

View File

@ -142,7 +142,7 @@ proc logImpl(topicCount: int): NimNode =
`computation`.gasCosts[`OpName`].m_handler(`computation`.memory.len, `memPos`, `len`),
reason="Memory expansion, Log topic and data gas cost")
`computation`.memory.extend(`memPos`, `len`)
let logData = `computation`.memory.read(`memPos`, `len`).toString
let logData = `computation`.memory.read(`memPos`, `len`)
addLogEntry(
`computation`,
account = `computation`.msg.storageAddress,

View File

@ -8,25 +8,19 @@
import
strformat, strutils, sequtils, endians, macros,
eth_common/eth_types, rlp,
../../../constants, ../../../utils/padding
../../../constants
# some methods based on py-evm utils/numeric
proc bigEndianToInt*(value: openarray[byte]): UInt256 =
if value.len == 32:
readUintBE[256](value)
else:
readUintBE[256](padLeft(@value, 32, 0.byte))
proc log256*(value: UInt256): Natural {.inline.}=
func log256*(value: UInt256): Natural {.inline.}=
(255 - value.countLeadingZeroBits) shr 3 # div 8
proc unsignedToPseudoSigned*(value: UInt256): UInt256 {.inline.}=
func unsignedToPseudoSigned*(value: UInt256): UInt256 {.inline.}=
result = value
if value > INT_256_MAX_AS_UINT256:
result -= INT_256_MAX_AS_UINT256
proc pseudoSignedToUnsigned*(value: UInt256): UInt256 {.inline.}=
func pseudoSignedToUnsigned*(value: UInt256): UInt256 {.inline.}=
result = value
if value > INT_256_MAX_AS_UINT256:
result += INT_256_MAX_AS_UINT256

View File

@ -8,7 +8,7 @@
import
sequtils,
eth_common/eth_types,
../constants, ../errors, ../logging, ../validation, ../utils/bytes,
../constants, ../errors, ../logging, ../validation,
./interpreter/utils/utils_numeric
type
@ -57,10 +57,3 @@ proc write*(memory: var Memory, startPos: Natural, value: openarray[byte]) =
for z, b in value:
memory.bytes[z + startPos] = b
template write*(memory: var Memory, startPos: Natural, size: Natural, value: cstring) =
memory.write(startPos, value.toBytes)
# TODO ~ O(n^3):
# - there is a string allocation with $ (?)
# - then a conversion to seq (= new allocation) with toBytes
# - then writing to memory

View File

@ -44,39 +44,30 @@ proc newMessage*(
code: string,
options: MessageOptions = newMessageOptions()): Message =
if to != CREATE_CONTRACT_ADDRESS:
validateCanonicalAddress(to, title="Message.to")
validateCanonicalAddress(sender, title="Message.sender")
validateGte(options.depth, minimum=0, title="Message.depth")
new(result)
result.gas = gas
result.gasPrice = gasPrice
if to != CREATE_CONTRACT_ADDRESS:
validateCanonicalAddress(to, title="Message.to")
result.to = to
validateCanonicalAddress(sender, title="Message.sender")
result.sender = sender
result.value = value
result.data = data
result.depth = options.depth
result.storageAddress = options.createAddress
result.codeAddress = options.codeAddress
result.shouldTransferValue = options.shouldTransferValue
result.isStatic = options.isStatic
result.code = code
if options.origin != ZERO_ADDRESS:
result.internalOrigin = options.origin
else:
result.internalOrigin = sender
validateGte(options.depth, minimum=0, title="Message.depth")
result.depth = options.depth
result.code = code
result.storageAddress = options.createAddress
result.codeAddress = options.codeAddress
result.shouldTransferValue = options.shouldTransferValue
result.isStatic = options.isStatic
proc origin*(message: Message): EthAddress =
if message.internalOrigin != ZERO_ADDRESS:
message.internalOrigin

View File

@ -7,7 +7,7 @@
import
strformat, strutils, sequtils, macros, rlp, eth_common, nimcrypto,
../errors, ../validation, ./interpreter/utils/utils_numeric, ../constants, ../logging, .. / utils / bytes
../errors, ../validation, ./interpreter/utils/utils_numeric, ../constants, ../logging
type
Stack* = ref object of RootObj
@ -25,8 +25,8 @@ proc len*(stack: Stack): int {.inline.} =
proc toStackElement(v: UInt256, elem: var StackElement) {.inline.} = elem = v
proc toStackElement(v: uint | int | GasInt, elem: var StackElement) {.inline.} = elem = v.u256
proc toStackElement(v: EthAddress, elem: var StackElement) {.inline.} = elem = bigEndianToInt(v)
proc toStackElement(v: MDigest, elem: var StackElement) {.inline.} = elem = readUintBE[256](v.data)
proc toStackElement(v: EthAddress, elem: var StackElement) {.inline.} = elem.initFromBytesBE(v)
proc toStackElement(v: MDigest, elem: var StackElement) {.inline.} = elem.initFromBytesBE(v.data, allowPadding = false)
proc fromStackElement(elem: StackElement, v: var UInt256) {.inline.} = v = elem
proc fromStackElement(elem: StackElement, v: var EthAddress) {.inline.} = v[0 .. ^1] = elem.toByteArrayBE().toOpenArray(12, 31)
@ -35,7 +35,7 @@ proc fromStackElement(elem: StackElement, v: var Hash256) {.inline.} = v.data =
proc toStackElement(v: openarray[byte], elem: var StackElement) {.inline.} =
# TODO: This needs to go
validateStackItem(v) # This is necessary to pass stack tests
elem = bigEndianToInt(v)
elem.initFromBytesBE(v)
proc pushAux[T](stack: var Stack, value: T) =
ensureStackLimit()

View File

@ -23,10 +23,10 @@ type
gasMeter*: GasMeter
code*: CodeStream
children*: seq[BaseComputation]
rawOutput*: string
rawOutput*: seq[byte]
returnData*: seq[byte]
error*: Error
logEntries*: seq[(EthAddress, seq[UInt256], string)]
logEntries*: seq[(EthAddress, seq[UInt256], seq[byte])]
shouldEraseReturnData*: bool
accountsToDelete*: Table[EthAddress, EthAddress]
opcodes*: Table[Op, proc(computation: var BaseComputation){.nimcall.}]
@ -72,7 +72,7 @@ type
sender*: EthAddress
value*: UInt256
data*: seq[byte]
code*: string
code*: string # TODO: seq[byte] is probably a better representation
internalOrigin*: EthAddress
internalCodeAddress*: EthAddress
depth*: int

View File

@ -8,7 +8,6 @@
import
os, macros, json, strformat, strutils, parseutils, ospaths, tables,
byteutils, eth_common, eth_keys, ranges/typedranges,
../nimbus/utils/[address, padding],
../nimbus/[vm_state, constants],
../nimbus/db/[db_chain, state_db],
../nimbus/transaction
@ -31,7 +30,13 @@ proc validTest*(folder: string, name: string): bool =
#result = name == "exp2.json"
macro jsonTest*(s: static[string], handler: untyped): untyped =
let testStatusIMPL = ident("testStatusIMPL")
let
testStatusIMPL = ident("testStatusIMPL")
# workaround for strformat in quote do: https://github.com/nim-lang/Nim/issues/8220
symbol = newIdentNode"symbol"
final = newIdentNode"final"
name = newIdentNode"name"
formatted = newStrLitNode"{symbol[final]} {name:<64}{$final}{'\n'}"
result = quote:
var z = 0
var filenames: seq[(string, string, string)] = @[]
@ -57,7 +62,7 @@ macro jsonTest*(s: static[string], handler: untyped): untyped =
status.sort do (a: (string, OrderedTable[string, Status]),
b: (string, OrderedTable[string, Status])) -> int: cmp(a[0], b[0])
let symbol: array[Status, string] = ["+", "-", " "]
let `symbol`: array[Status, string] = ["+", "-", " "]
var raw = ""
raw.add(`s` & "\n")
raw.add("===\n")
@ -70,9 +75,9 @@ macro jsonTest*(s: static[string], handler: untyped): untyped =
var okCount = 0
var failCount = 0
var skipCount = 0
for name, final in sortedStatuses:
raw.add(symbol[final] & " " & name.padRight(64, " ") & $final & "\n")
case final:
for `name`, `final` in sortedStatuses:
raw.add(&`formatted`)
case `final`:
of Status.OK: okCount += 1
of Status.Fail: failCount += 1
of Status.Skip: skipCount += 1

View File

@ -8,7 +8,7 @@
import
unittest,
eth_common/eth_types,
../nimbus/[constants, errors, vm/interpreter, utils/bytes]
../nimbus/[constants, errors, vm/interpreter]
template testPush(value: untyped, expected: untyped): untyped =
@ -21,6 +21,12 @@ template testFailPush(value: untyped): untyped =
expect(ValidationError):
stack.push(value)
func toBytes(s: string): seq[byte] =
cast[seq[byte]](s)
func bigEndianToInt*(value: openarray[byte]): UInt256 =
result.initFromBytesBE(value)
suite "stack":
test "push only valid":
testPush(0'u, 0.u256)

View File

@ -12,7 +12,7 @@ import
./test_helpers,
../nimbus/[constants, errors, logging],
../nimbus/[vm_state, vm_types],
../nimbus/utils/[header, padding],
../nimbus/utils/header,
../nimbus/vm/interpreter,
../nimbus/db/[db_chain, state_db, backends/memory_backend]
@ -94,7 +94,7 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
fail()
let expectedOutput = fixture{"out"}.getStr
check(computation.output == expectedOutput)
check(computation.outputHex == expectedOutput)
let gasMeter = computation.gasMeter
let expectedGasRemaining = fixture{"gas"}.getHexadecimalInt