mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-11 21:04:11 +00:00
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:
parent
4b5eada322
commit
4dd75aee84
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
import
|
import
|
||||||
math, strutils, utils/padding, eth_common
|
math, strutils, eth_common
|
||||||
|
|
||||||
proc default(t: typedesc): t = discard
|
proc default(t: typedesc): t = discard
|
||||||
|
|
||||||
@ -8,8 +8,6 @@ proc default(t: typedesc): t = discard
|
|||||||
const
|
const
|
||||||
UINT_256_MAX*: UInt256 = high(UInt256)
|
UINT_256_MAX*: UInt256 = high(UInt256)
|
||||||
INT_256_MAX_AS_UINT256* = high(Uint256) shr 1
|
INT_256_MAX_AS_UINT256* = high(Uint256) shr 1
|
||||||
NULLBYTE* = "\x00"
|
|
||||||
EMPTYWORD* = repeat(NULLBYTE, 32)
|
|
||||||
UINT160CEILING*: UInt256 = 2.u256.pow(160)
|
UINT160CEILING*: UInt256 = 2.u256.pow(160)
|
||||||
ZERO_ADDRESS* = default(EthAddress)
|
ZERO_ADDRESS* = default(EthAddress)
|
||||||
CREATE_CONTRACT_ADDRESS* = ZERO_ADDRESS
|
CREATE_CONTRACT_ADDRESS* = ZERO_ADDRESS
|
||||||
|
@ -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
|
|
@ -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)
|
|
@ -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]
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import
|
import
|
||||||
strformat, strutils, sequtils, macros, terminal, math, tables,
|
strformat, strutils, sequtils, macros, terminal, math, tables,
|
||||||
eth_common, byteutils,
|
eth_common,
|
||||||
../constants, ../errors, ../validation, ../vm_state, ../logging, ../vm_types,
|
../constants, ../errors, ../validation, ../vm_state, ../logging, ../vm_types,
|
||||||
./interpreter/[opcode_values, gas_meter, gas_costs, vm_forks],
|
./interpreter/[opcode_values, gas_meter, gas_costs, vm_forks],
|
||||||
./code_stream, ./memory, ./message, ./stack
|
./code_stream, ./memory, ./message, ./stack
|
||||||
@ -23,7 +23,7 @@ proc newBaseComputation*(vmState: BaseVMState, blockNumber: UInt256, message: Me
|
|||||||
result.accountsToDelete = initTable[EthAddress, EthAddress]()
|
result.accountsToDelete = initTable[EthAddress, EthAddress]()
|
||||||
result.logEntries = @[]
|
result.logEntries = @[]
|
||||||
result.code = newCodeStreamFromUnescaped(message.code) # TODO: what is the best repr
|
result.code = newCodeStreamFromUnescaped(message.code) # TODO: what is the best repr
|
||||||
result.rawOutput = "0x"
|
# result.rawOutput = "0x"
|
||||||
result.gasCosts = blockNumber.toFork.forkToSchedule
|
result.gasCosts = blockNumber.toFork.forkToSchedule
|
||||||
|
|
||||||
proc logger*(computation: BaseComputation): Logger =
|
proc logger*(computation: BaseComputation): Logger =
|
||||||
@ -45,13 +45,17 @@ proc shouldBurnGas*(c: BaseComputation): bool =
|
|||||||
proc shouldEraseReturnData*(c: BaseComputation): bool =
|
proc shouldEraseReturnData*(c: BaseComputation): bool =
|
||||||
c.isError and c.error.erasesReturnData
|
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*(
|
proc prepareChildMessage*(
|
||||||
c: var BaseComputation,
|
c: var BaseComputation,
|
||||||
gas: GasInt,
|
gas: GasInt,
|
||||||
to: EthAddress,
|
to: EthAddress,
|
||||||
value: UInt256,
|
value: UInt256,
|
||||||
data: seq[byte],
|
data: seq[byte],
|
||||||
code: string,
|
code: seq[byte],
|
||||||
options: MessageOptions = newMessageOptions()): Message =
|
options: MessageOptions = newMessageOptions()): Message =
|
||||||
|
|
||||||
var childOptions = options
|
var childOptions = options
|
||||||
@ -63,17 +67,22 @@ proc prepareChildMessage*(
|
|||||||
to,
|
to,
|
||||||
value,
|
value,
|
||||||
data,
|
data,
|
||||||
code,
|
code.bytesToHex, # TODO: use seq[byte] for Message as well
|
||||||
childOptions)
|
childOptions)
|
||||||
|
|
||||||
proc output*(c: BaseComputation): string =
|
func output*(c: BaseComputation): seq[byte] =
|
||||||
if c.shouldEraseReturnData:
|
if c.shouldEraseReturnData:
|
||||||
""
|
@[]
|
||||||
else:
|
else:
|
||||||
c.rawOutput
|
c.rawOutput
|
||||||
|
|
||||||
proc `output=`*(c: var BaseComputation, value: string) =
|
func `output=`*(c: var BaseComputation, value: openarray[byte]) =
|
||||||
c.rawOutput = value
|
c.rawOutput = @value
|
||||||
|
|
||||||
|
proc outputHex*(c: BaseComputation): string =
|
||||||
|
if c.shouldEraseReturnData:
|
||||||
|
return "0x"
|
||||||
|
c.rawOutput.bytesToHex
|
||||||
|
|
||||||
proc registerAccountForDeletion*(c: var BaseComputation, beneficiary: EthAddress) =
|
proc registerAccountForDeletion*(c: var BaseComputation, beneficiary: EthAddress) =
|
||||||
validateCanonicalAddress(beneficiary, title="self destruct beneficiary address")
|
validateCanonicalAddress(beneficiary, title="self destruct beneficiary address")
|
||||||
@ -84,7 +93,7 @@ proc registerAccountForDeletion*(c: var BaseComputation, beneficiary: EthAddress
|
|||||||
"registered for deletion multiple times")
|
"registered for deletion multiple times")
|
||||||
c.accountsToDelete[c.msg.storageAddress] = beneficiary
|
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")
|
validateCanonicalAddress(account, title="log entry address")
|
||||||
c.logEntries.add((account, topics, data))
|
c.logEntries.add((account, topics, data))
|
||||||
|
|
||||||
|
@ -9,8 +9,6 @@ import
|
|||||||
./interpreter/[opcode_values, gas_meter],
|
./interpreter/[opcode_values, gas_meter],
|
||||||
./interpreter/vm_forks
|
./interpreter/vm_forks
|
||||||
|
|
||||||
from ./interpreter/utils/utils_numeric import bigEndianToInt
|
|
||||||
|
|
||||||
import # Used in vm_types. Beware of recursive dependencies
|
import # Used in vm_types. Beware of recursive dependencies
|
||||||
./code_stream, ./computation, ./stack, ./message, interpreter_dispatch
|
./code_stream, ./computation, ./stack, ./message, interpreter_dispatch
|
||||||
|
|
||||||
@ -18,7 +16,5 @@ export
|
|||||||
opcode_values, gas_meter,
|
opcode_values, gas_meter,
|
||||||
vm_forks
|
vm_forks
|
||||||
|
|
||||||
export utils_numeric.bigEndianToInt
|
|
||||||
|
|
||||||
export
|
export
|
||||||
code_stream, computation, stack, message, interpreter_dispatch
|
code_stream, computation, stack, message, interpreter_dispatch
|
||||||
|
@ -12,8 +12,7 @@ import
|
|||||||
./gas_meter, ./gas_costs, ./opcode_values, ./vm_forks,
|
./gas_meter, ./gas_costs, ./opcode_values, ./vm_forks,
|
||||||
../memory, ../message, ../stack, ../code_stream, ../computation,
|
../memory, ../message, ../stack, ../code_stream, ../computation,
|
||||||
../../vm_state, ../../errors, ../../constants, ../../vm_types, ../../logging,
|
../../vm_state, ../../errors, ../../constants, ../../vm_types, ../../logging,
|
||||||
../../db/[db_chain, state_db],
|
../../db/[db_chain, state_db]
|
||||||
../../utils/[bytes, padding, address] # TODO remove those dependencies
|
|
||||||
|
|
||||||
# ##################################
|
# ##################################
|
||||||
# Syntactic sugar
|
# Syntactic sugar
|
||||||
@ -266,15 +265,7 @@ op callDataCopy, inline = false, memStartPos, copyStartPos, size:
|
|||||||
computation.gasCosts[CallDataCopy].m_handler(memPos, copyPos, len),
|
computation.gasCosts[CallDataCopy].m_handler(memPos, copyPos, len),
|
||||||
reason="CallDataCopy fee")
|
reason="CallDataCopy fee")
|
||||||
|
|
||||||
computation.memory.extend(memPos, len)
|
computation.memory.writePaddedResult(computation.code.bytes, memPos, copyPos, 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)
|
|
||||||
|
|
||||||
op codesize, inline = true:
|
op codesize, inline = true:
|
||||||
## 0x38, Get size of code running in current environment.
|
## 0x38, Get size of code running in current environment.
|
||||||
@ -548,7 +539,7 @@ op create, inline = false, value, startPosition, size:
|
|||||||
to = CREATE_CONTRACT_ADDRESS,
|
to = CREATE_CONTRACT_ADDRESS,
|
||||||
value = value,
|
value = value,
|
||||||
data = @[],
|
data = @[],
|
||||||
code = callData.toString,
|
code = callData,
|
||||||
options = MessageOptions(createAddress: contractAddress)
|
options = MessageOptions(createAddress: contractAddress)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -709,7 +700,7 @@ template genCall(callName: untyped): untyped =
|
|||||||
# computation.vmState.db(readOnly = true):
|
# computation.vmState.db(readOnly = true):
|
||||||
# let code = if codeAddress != ZERO_ADDRESS: db.getCode(codeAddress)
|
# let code = if codeAddress != ZERO_ADDRESS: db.getCode(codeAddress)
|
||||||
# else: db.getCode(to)
|
# 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(
|
var childMsg = prepareChildMessage(
|
||||||
computation,
|
computation,
|
||||||
@ -740,7 +731,7 @@ template genCall(callName: untyped): untyped =
|
|||||||
let actualOutputSize = min(memOutLen, childComputation.output.len)
|
let actualOutputSize = min(memOutLen, childComputation.output.len)
|
||||||
computation.memory.write(
|
computation.memory.write(
|
||||||
memOutPos,
|
memOutPos,
|
||||||
childComputation.output.toBytes[0 ..< actualOutputSize])
|
childComputation.output.toOpenArray(0, actualOutputSize))
|
||||||
if not childComputation.shouldBurnGas:
|
if not childComputation.shouldBurnGas:
|
||||||
computation.gasMeter.returnGas(childComputation.gasMeter.gasRemaining)
|
computation.gasMeter.returnGas(childComputation.gasMeter.gasRemaining)
|
||||||
|
|
||||||
@ -759,8 +750,7 @@ op returnOp, inline = false, startPos, size:
|
|||||||
)
|
)
|
||||||
|
|
||||||
computation.memory.extend(pos, len)
|
computation.memory.extend(pos, len)
|
||||||
let output = computation.memory.read(pos, len)
|
computation.output = computation.memory.read(pos, len)
|
||||||
computation.output = output.toString
|
|
||||||
|
|
||||||
op revert, inline = false, startPos, size:
|
op revert, inline = false, startPos, size:
|
||||||
## 0xf0, Halt execution reverting state changes but returning data and remaining gas.
|
## 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)
|
computation.memory.extend(pos, len)
|
||||||
let output = computation.memory.read(pos, len).toString
|
computation.output = computation.memory.read(pos, len)
|
||||||
computation.output = output
|
|
||||||
|
|
||||||
op selfDestruct, inline = false:
|
op selfDestruct, inline = false:
|
||||||
## 0xff Halt execution and register account for later deletion.
|
## 0xff Halt execution and register account for later deletion.
|
||||||
|
@ -142,7 +142,7 @@ proc logImpl(topicCount: int): NimNode =
|
|||||||
`computation`.gasCosts[`OpName`].m_handler(`computation`.memory.len, `memPos`, `len`),
|
`computation`.gasCosts[`OpName`].m_handler(`computation`.memory.len, `memPos`, `len`),
|
||||||
reason="Memory expansion, Log topic and data gas cost")
|
reason="Memory expansion, Log topic and data gas cost")
|
||||||
`computation`.memory.extend(`memPos`, `len`)
|
`computation`.memory.extend(`memPos`, `len`)
|
||||||
let logData = `computation`.memory.read(`memPos`, `len`).toString
|
let logData = `computation`.memory.read(`memPos`, `len`)
|
||||||
addLogEntry(
|
addLogEntry(
|
||||||
`computation`,
|
`computation`,
|
||||||
account = `computation`.msg.storageAddress,
|
account = `computation`.msg.storageAddress,
|
||||||
|
@ -8,25 +8,19 @@
|
|||||||
import
|
import
|
||||||
strformat, strutils, sequtils, endians, macros,
|
strformat, strutils, sequtils, endians, macros,
|
||||||
eth_common/eth_types, rlp,
|
eth_common/eth_types, rlp,
|
||||||
../../../constants, ../../../utils/padding
|
../../../constants
|
||||||
|
|
||||||
# some methods based on py-evm utils/numeric
|
# some methods based on py-evm utils/numeric
|
||||||
|
|
||||||
proc bigEndianToInt*(value: openarray[byte]): UInt256 =
|
func log256*(value: UInt256): Natural {.inline.}=
|
||||||
if value.len == 32:
|
|
||||||
readUintBE[256](value)
|
|
||||||
else:
|
|
||||||
readUintBE[256](padLeft(@value, 32, 0.byte))
|
|
||||||
|
|
||||||
proc log256*(value: UInt256): Natural {.inline.}=
|
|
||||||
(255 - value.countLeadingZeroBits) shr 3 # div 8
|
(255 - value.countLeadingZeroBits) shr 3 # div 8
|
||||||
|
|
||||||
proc unsignedToPseudoSigned*(value: UInt256): UInt256 {.inline.}=
|
func unsignedToPseudoSigned*(value: UInt256): UInt256 {.inline.}=
|
||||||
result = value
|
result = value
|
||||||
if value > INT_256_MAX_AS_UINT256:
|
if value > INT_256_MAX_AS_UINT256:
|
||||||
result -= 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
|
result = value
|
||||||
if value > INT_256_MAX_AS_UINT256:
|
if value > INT_256_MAX_AS_UINT256:
|
||||||
result += INT_256_MAX_AS_UINT256
|
result += INT_256_MAX_AS_UINT256
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
import
|
import
|
||||||
sequtils,
|
sequtils,
|
||||||
eth_common/eth_types,
|
eth_common/eth_types,
|
||||||
../constants, ../errors, ../logging, ../validation, ../utils/bytes,
|
../constants, ../errors, ../logging, ../validation,
|
||||||
./interpreter/utils/utils_numeric
|
./interpreter/utils/utils_numeric
|
||||||
|
|
||||||
type
|
type
|
||||||
@ -57,10 +57,3 @@ proc write*(memory: var Memory, startPos: Natural, value: openarray[byte]) =
|
|||||||
|
|
||||||
for z, b in value:
|
for z, b in value:
|
||||||
memory.bytes[z + startPos] = b
|
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
|
|
||||||
|
@ -44,39 +44,30 @@ proc newMessage*(
|
|||||||
code: string,
|
code: string,
|
||||||
options: MessageOptions = newMessageOptions()): Message =
|
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)
|
new(result)
|
||||||
result.gas = gas
|
result.gas = gas
|
||||||
result.gasPrice = gasPrice
|
result.gasPrice = gasPrice
|
||||||
|
|
||||||
if to != CREATE_CONTRACT_ADDRESS:
|
|
||||||
validateCanonicalAddress(to, title="Message.to")
|
|
||||||
result.to = to
|
result.to = to
|
||||||
|
|
||||||
validateCanonicalAddress(sender, title="Message.sender")
|
|
||||||
result.sender = sender
|
result.sender = sender
|
||||||
|
|
||||||
result.value = value
|
result.value = value
|
||||||
|
|
||||||
result.data = data
|
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:
|
if options.origin != ZERO_ADDRESS:
|
||||||
result.internalOrigin = options.origin
|
result.internalOrigin = options.origin
|
||||||
else:
|
else:
|
||||||
result.internalOrigin = sender
|
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 =
|
proc origin*(message: Message): EthAddress =
|
||||||
if message.internalOrigin != ZERO_ADDRESS:
|
if message.internalOrigin != ZERO_ADDRESS:
|
||||||
message.internalOrigin
|
message.internalOrigin
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
import
|
import
|
||||||
strformat, strutils, sequtils, macros, rlp, eth_common, nimcrypto,
|
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
|
type
|
||||||
Stack* = ref object of RootObj
|
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: UInt256, elem: var StackElement) {.inline.} = elem = v
|
||||||
proc toStackElement(v: uint | int | GasInt, elem: var StackElement) {.inline.} = elem = v.u256
|
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: EthAddress, elem: var StackElement) {.inline.} = elem.initFromBytesBE(v)
|
||||||
proc toStackElement(v: MDigest, elem: var StackElement) {.inline.} = elem = readUintBE[256](v.data)
|
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 UInt256) {.inline.} = v = elem
|
||||||
proc fromStackElement(elem: StackElement, v: var EthAddress) {.inline.} = v[0 .. ^1] = elem.toByteArrayBE().toOpenArray(12, 31)
|
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.} =
|
proc toStackElement(v: openarray[byte], elem: var StackElement) {.inline.} =
|
||||||
# TODO: This needs to go
|
# TODO: This needs to go
|
||||||
validateStackItem(v) # This is necessary to pass stack tests
|
validateStackItem(v) # This is necessary to pass stack tests
|
||||||
elem = bigEndianToInt(v)
|
elem.initFromBytesBE(v)
|
||||||
|
|
||||||
proc pushAux[T](stack: var Stack, value: T) =
|
proc pushAux[T](stack: var Stack, value: T) =
|
||||||
ensureStackLimit()
|
ensureStackLimit()
|
||||||
|
@ -23,10 +23,10 @@ type
|
|||||||
gasMeter*: GasMeter
|
gasMeter*: GasMeter
|
||||||
code*: CodeStream
|
code*: CodeStream
|
||||||
children*: seq[BaseComputation]
|
children*: seq[BaseComputation]
|
||||||
rawOutput*: string
|
rawOutput*: seq[byte]
|
||||||
returnData*: seq[byte]
|
returnData*: seq[byte]
|
||||||
error*: Error
|
error*: Error
|
||||||
logEntries*: seq[(EthAddress, seq[UInt256], string)]
|
logEntries*: seq[(EthAddress, seq[UInt256], seq[byte])]
|
||||||
shouldEraseReturnData*: bool
|
shouldEraseReturnData*: bool
|
||||||
accountsToDelete*: Table[EthAddress, EthAddress]
|
accountsToDelete*: Table[EthAddress, EthAddress]
|
||||||
opcodes*: Table[Op, proc(computation: var BaseComputation){.nimcall.}]
|
opcodes*: Table[Op, proc(computation: var BaseComputation){.nimcall.}]
|
||||||
@ -72,7 +72,7 @@ type
|
|||||||
sender*: EthAddress
|
sender*: EthAddress
|
||||||
value*: UInt256
|
value*: UInt256
|
||||||
data*: seq[byte]
|
data*: seq[byte]
|
||||||
code*: string
|
code*: string # TODO: seq[byte] is probably a better representation
|
||||||
internalOrigin*: EthAddress
|
internalOrigin*: EthAddress
|
||||||
internalCodeAddress*: EthAddress
|
internalCodeAddress*: EthAddress
|
||||||
depth*: int
|
depth*: int
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import
|
import
|
||||||
os, macros, json, strformat, strutils, parseutils, ospaths, tables,
|
os, macros, json, strformat, strutils, parseutils, ospaths, tables,
|
||||||
byteutils, eth_common, eth_keys, ranges/typedranges,
|
byteutils, eth_common, eth_keys, ranges/typedranges,
|
||||||
../nimbus/utils/[address, padding],
|
|
||||||
../nimbus/[vm_state, constants],
|
../nimbus/[vm_state, constants],
|
||||||
../nimbus/db/[db_chain, state_db],
|
../nimbus/db/[db_chain, state_db],
|
||||||
../nimbus/transaction
|
../nimbus/transaction
|
||||||
@ -31,7 +30,13 @@ proc validTest*(folder: string, name: string): bool =
|
|||||||
#result = name == "exp2.json"
|
#result = name == "exp2.json"
|
||||||
|
|
||||||
macro jsonTest*(s: static[string], handler: untyped): untyped =
|
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:
|
result = quote:
|
||||||
var z = 0
|
var z = 0
|
||||||
var filenames: seq[(string, string, string)] = @[]
|
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]),
|
status.sort do (a: (string, OrderedTable[string, Status]),
|
||||||
b: (string, OrderedTable[string, Status])) -> int: cmp(a[0], b[0])
|
b: (string, OrderedTable[string, Status])) -> int: cmp(a[0], b[0])
|
||||||
|
|
||||||
let symbol: array[Status, string] = ["+", "-", " "]
|
let `symbol`: array[Status, string] = ["+", "-", " "]
|
||||||
var raw = ""
|
var raw = ""
|
||||||
raw.add(`s` & "\n")
|
raw.add(`s` & "\n")
|
||||||
raw.add("===\n")
|
raw.add("===\n")
|
||||||
@ -70,9 +75,9 @@ macro jsonTest*(s: static[string], handler: untyped): untyped =
|
|||||||
var okCount = 0
|
var okCount = 0
|
||||||
var failCount = 0
|
var failCount = 0
|
||||||
var skipCount = 0
|
var skipCount = 0
|
||||||
for name, final in sortedStatuses:
|
for `name`, `final` in sortedStatuses:
|
||||||
raw.add(symbol[final] & " " & name.padRight(64, " ") & $final & "\n")
|
raw.add(&`formatted`)
|
||||||
case final:
|
case `final`:
|
||||||
of Status.OK: okCount += 1
|
of Status.OK: okCount += 1
|
||||||
of Status.Fail: failCount += 1
|
of Status.Fail: failCount += 1
|
||||||
of Status.Skip: skipCount += 1
|
of Status.Skip: skipCount += 1
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
import
|
import
|
||||||
unittest,
|
unittest,
|
||||||
eth_common/eth_types,
|
eth_common/eth_types,
|
||||||
../nimbus/[constants, errors, vm/interpreter, utils/bytes]
|
../nimbus/[constants, errors, vm/interpreter]
|
||||||
|
|
||||||
|
|
||||||
template testPush(value: untyped, expected: untyped): untyped =
|
template testPush(value: untyped, expected: untyped): untyped =
|
||||||
@ -21,6 +21,12 @@ template testFailPush(value: untyped): untyped =
|
|||||||
expect(ValidationError):
|
expect(ValidationError):
|
||||||
stack.push(value)
|
stack.push(value)
|
||||||
|
|
||||||
|
func toBytes(s: string): seq[byte] =
|
||||||
|
cast[seq[byte]](s)
|
||||||
|
|
||||||
|
func bigEndianToInt*(value: openarray[byte]): UInt256 =
|
||||||
|
result.initFromBytesBE(value)
|
||||||
|
|
||||||
suite "stack":
|
suite "stack":
|
||||||
test "push only valid":
|
test "push only valid":
|
||||||
testPush(0'u, 0.u256)
|
testPush(0'u, 0.u256)
|
||||||
|
@ -12,7 +12,7 @@ import
|
|||||||
./test_helpers,
|
./test_helpers,
|
||||||
../nimbus/[constants, errors, logging],
|
../nimbus/[constants, errors, logging],
|
||||||
../nimbus/[vm_state, vm_types],
|
../nimbus/[vm_state, vm_types],
|
||||||
../nimbus/utils/[header, padding],
|
../nimbus/utils/header,
|
||||||
../nimbus/vm/interpreter,
|
../nimbus/vm/interpreter,
|
||||||
../nimbus/db/[db_chain, state_db, backends/memory_backend]
|
../nimbus/db/[db_chain, state_db, backends/memory_backend]
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
|||||||
fail()
|
fail()
|
||||||
|
|
||||||
let expectedOutput = fixture{"out"}.getStr
|
let expectedOutput = fixture{"out"}.getStr
|
||||||
check(computation.output == expectedOutput)
|
check(computation.outputHex == expectedOutput)
|
||||||
let gasMeter = computation.gasMeter
|
let gasMeter = computation.gasMeter
|
||||||
|
|
||||||
let expectedGasRemaining = fixture{"gas"}.getHexadecimalInt
|
let expectedGasRemaining = fixture{"gas"}.getHexadecimalInt
|
||||||
|
Loading…
x
Reference in New Issue
Block a user