Implement address/sha3 opcodes, start using nim-keccak-tiny

This commit is contained in:
Alexander Ivanov 2018-01-29 19:40:22 +02:00
parent fba1052b4c
commit 5ad14f59b2
15 changed files with 463 additions and 129 deletions

View File

@ -7,4 +7,5 @@ description = "An Ethereum 2.0 Sharding Client for Resource-Restricted Devices
license = "Apache License 2.0"
skipDirs = @["tests"]
requires "nim >= 0.17.0"
requires "nim >= 0.17.0", "https://github.com/status-im/nim-keccak-tiny.git >= 0.1.0"

12
src/account.nim Normal file
View File

@ -0,0 +1,12 @@
import
constants, errors, bigints
type
Account* = ref object
nonce*: Int256
balance*: Int256
#storageRoot*:
#codeHash*:
proc newAccount*(nonce: Int256 = 0.i256, balance: Int256 = 0.i256): Account =
Account(nonce: nonce, balance: balance)

View File

@ -89,14 +89,12 @@ method prepareChildMessage*(
gas: Int256,
to: cstring,
value: Int256,
data: cstring,
data: seq[byte],
code: cstring,
options: MessageOptions = newMessageOptions()): Message =
# ? kwargs.setdefault('sender', self.msg.storage_address)
var childOptions = options
childOptions.depth = c.msg.depth + 1.int256
childOptions.depth = c.msg.depth + 1.i256
result = newMessage(
gas,
c.msg.gasPrice,
@ -107,7 +105,6 @@ method prepareChildMessage*(
code,
childOptions)
#
method extendMemory*(c: var BaseComputation, startPosition: Int256, size: Int256) =
# Memory Management
#
@ -150,7 +147,7 @@ macro generateChildBaseComputation*(t: typed, vmState: typed, childMsg: typed):
if childMsg.isCreate:
var child = `name`(`vmState`, `childMsg`)
c = child.applyCreateMessage()
else:
else:
var child = `name`(`vmState`, `childMsg`)
c = child.applyMessage()
c
@ -201,7 +198,7 @@ method getLogEntries*(c: BaseComputation): seq[(cstring, seq[Int256], cstring)]
result = @[]
else:
result = @[]
method getGasRefund*(c: BaseComputation): Int256 =
if c.isError:
result = 0.int256

View File

@ -14,13 +14,13 @@ template i256*(i: int): Int256 =
i.int256
# TODO
# We'll have a fast fixed int256, for now this works
# We'll have a fast fixed i256, for now this works
proc `==`*(a: Int256, b: int): bool =
a == b.int256
a == b.i256
proc `!=`*(a: Int256, b: int): bool =
a != b.int256
a != b.i256
proc `^`*(base: int; exp: int): Int256 =
let base = base.initBigInt
@ -33,26 +33,26 @@ proc `^`*(base: int; exp: int): Int256 =
proc `^`*(left: Int256, right: int): Int256 =
var value = right.initBigInt
result = 1.initBigInt
var m = right.int256
while value > 0.int256:
var m = right.i256
while value > 0.i256:
result = result * m
value -= 1.int256
value -= 1.i256
proc `>`*(a: Int256, b: int): bool =
a > b.int256
a > b.i256
proc `<`*(a: Int256, b: int): bool =
a < b.int256
a < b.i256
proc `mod`*(a: Int256, b: int): Int256 =
a mod b.int256
a mod b.i256
proc `div`*(a: Int256, b: int): Int256 =
a div b.int256
a div b.i256
proc log256*(a: Int256): Int256 =
# TODO
2.int256
2.i256
proc setXLen[T](s: var seq[T]; newlen: Natural) =
if s.isNil:
@ -75,7 +75,7 @@ mapOp(`or`)
mapOp(`xor`)
proc `abs`*(a: Int256): Int256 =
if a >= 0.int256: a else: -a
if a >= 0.i256: a else: -a
proc `getInt`*(a: Int256): int =
a.limbs[0].int
@ -94,89 +94,91 @@ let
ZERO_HASH32* = repeat(cstring"\x00", 20)
STACKDEPTHLIMIT* = 1024
GAS_NULL* = 0.int256
GAS_ZERO* = 0.int256
GAS_BASE* = 2.int256
GAS_VERY_LOW* = 3.int256
GAS_LOW* = 5.int256
GAS_MID* = 8.int256
GAS_HIGH* = 10.int256
GAS_EXT_CODE* = 20.int256
GAS_BALANCE* = 20.int256
GAS_SLOAD* = 50.int256
GAS_JUMP_DEST* = 1.int256
GAS_SSET* = 20_000.int256
GAS_SRESET* = 5000.int256
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
REFUNDS_CLEAR* = 15_000.int256
REFUNDS_CLEAR* = 15_000.i256
GAS_SELF_DESTRUCT* = 0.int256
GAS_SELF_DESTRUCT_NEW_ACCOUNT* = 25_000.int256
GAS_CREATE* = 32_000.int256
GAS_CALL* = 40.int256
GASCALLVALUE = 9_000.int256
GAS_CALL_STIPEND* = 2_300.int256
GAS_NEW_ACCOUNT* = 25_000.int256
GAS_SELF_DESTRUCT* = 0.i256
GAS_SELF_DESTRUCT_NEW_ACCOUNT* = 25_000.i256
GAS_CREATE* = 32_000.i256
GAS_CALL* = 40.i256
GASCALLVALUE = 9_000.i256
GAS_CALL_STIPEND* = 2_300.i256
GAS_NEW_ACCOUNT* = 25_000.i256
GAS_EXP* = 10.int256
GAS_EXP_BYTE* = 10.int256
GAS_MEMORY* = 3.int256
GAS_TX_CREATE* = 32_000.int256
GAS_TX_DATA_ZERO* = 4.int256
GAS_TX_DATA_NON_ZERO* = 68.int256
GAS_TX* = 21_000.int256
GAS_LOG* = 375.int256
GAS_LOG_DATA* = 8.int256
GAS_LOG_TOPIC* = 375.int256
GAS_SHA3* = 30.int256
GAS_SHA3_WORD* = 6.int256
GAS_COPY* = 3.int256
GAS_BLOCK_HASH* = 20.int256
GAS_CODE_DEPOSIT* = 200.int256
GAS_MEMORY_QUADRATIC_DENOMINATOR* = 512.int256
GAS_SHA256* = 60.int256
GAS_SHA256WORD* = 12.int256
GAS_RIP_EMD160* = 600.int256
GAS_RIP_EMD160WORD* = 120.int256
GAS_IDENTITY* = 15.int256
GAS_COST_BALANCE* = 400.i256
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_IDENTITY_WORD* = 3
GAS_ECRECOVER* = 3_000.int256
GAS_ECADD* = 500.int256
GAS_ECMUL* = 40_000.int256
GAS_ECPAIRING_BASE* = 100_000.int256
GAS_ECPAIRING_PER_POINT* = 80_000.int256
GAS_LIMIT_EMA_DENOMINATOR* = 1_024.int256
GAS_LIMIT_ADJUSTMENT_FACTOR* = 1_024.int256
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
GAS_LIMIT_USAGE_ADJUSTMENT_NUMERATOR* = 3.int256
GAS_LIMIT_USAGE_ADJUSTMENT_DENOMINATOR* = 2.int256
GAS_LIMIT_USAGE_ADJUSTMENT_NUMERATOR* = 3.i256
GAS_LIMIT_USAGE_ADJUSTMENT_DENOMINATOR* = 2.i256
DIFFICULTY_ADJUSTMENT_DENOMINATOR* = 2_048.int256
DIFFICULTY_MINIMUM* = 131_072.int256
DIFFICULTY_ADJUSTMENT_DENOMINATOR* = 2_048.i256
DIFFICULTY_MINIMUM* = 131_072.i256
BOMB_EXPONENTIAL_PERIOD* = 100_000.int256
BOMB_EXPONENTIAL_FREE_PERIODS* = 2.int256
BOMB_EXPONENTIAL_PERIOD* = 100_000.i256
BOMB_EXPONENTIAL_FREE_PERIODS* = 2.i256
BLOCK_REWARD* = 5.int256 * 2.int256 # denoms.ether
BLOCK_REWARD* = 5.i256 * 2.i256 # denoms.ether
UNCLE_DEPTH_PENALTY_FACTOR* = 8.int256
UNCLE_DEPTH_PENALTY_FACTOR* = 8.i256
MAX_UNCLE_DEPTH* = 6.int256
MAX_UNCLES* = 2.int256
MAX_UNCLE_DEPTH* = 6.i256
MAX_UNCLES* = 2.i256
SECPK1_P*: Int256 = 2 ^ 256 - 2 ^ 32 - 977
SECPK1_N*: Int256 = "115792089237316195423570985008687907852837564279074904382605163141518161494337".initBigInt
SECPK1_A* = 0.int256
SECPK1_B* = 7.int256
SECPK1_Gx* = 0.int256
SECPK1_Gy* = 0.int256
SECPK1_A* = 0.i256
SECPK1_B* = 7.i256
SECPK1_Gx* = 0.i256
SECPK1_Gy* = 0.i256
SECPK1_G* = (SECPK1Gx, SECPK1Gy)
EMPTY_UNCLE_HASH* = cstring"\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.int256
GENESIS_DIFFICULTY* = 131_072.int256
GENESIS_GAS_LIMIT* = 3_141_592.int256
GENESIS_BLOCK_NUMBER* = 0.i256
GENESIS_DIFFICULTY* = 131_072.i256
GENESIS_GAS_LIMIT* = 3_141_592.i256
GENESIS_PARENT_HASH* = ZERO_HASH32
GENESIS_COINBASE* = ZERO_ADDRESS
GENESIS_NONCE* = cstring"\x00\x00\x00\x00\x00\x00\x00B"
@ -186,7 +188,7 @@ let
EMPTYSHA3 = cstring"\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p"
BLANK_ROOT_HASH* = cstring"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.int256
GAS_MOD_EXP_QUADRATIC_DENOMINATOR* = 20.i256
MAX_PREV_HEADER_DEPTH* = 256.int256
MAX_PREV_HEADER_DEPTH* = 256.i256

43
src/db/state_db.nim Normal file
View File

@ -0,0 +1,43 @@
import
strformat, tables,
../constants, ../errors, ../validation, ../account, ../logging, bigints
type
AccountStateDB* = ref object
db*: Table[cstring, Int256]
proc newAccountStateDB*(db: Table[cstring, Int256], readOnly: bool = false): AccountStateDB =
result = AccountStateDB(db: db)
proc logger*(db: AccountStateDB): Logger =
logging.getLogger("db.State")
proc getAccount(db: AccountStateDB, address: cstring): Account =
# let rlpAccount = db.trie[address]
# if not rlpAccount.isNil:
# account = rlp.decode[Account](rlpAccount)
# account.mutable = true
# else:
# account = newAccount()
result = newAccount() # TODO
proc setAccount(db: AccountStateDB, address: cstring, account: Account) =
# db.trie[address] = rlp.encode[Account](account)
discard # TODO
# public
proc getBalance*(db: AccountStateDB, address: cstring): Int256 =
validateCanonicalAddress(address, title="Storage Address")
let account = db.getAccount(address)
account.balance
proc setBalance*(db: var AccountStateDB, address: cstring, balance: Int256) =
validateCanonicalAddress(address, title="Storage Address")
let account = db.getAccount(address)
account.balance = balance
db.setAccount(address, account)
proc deltaBalance*(db: var AccountStateDB, address: cstring, delta: Int256) =
db.setBalance(address, db.getBalance(address) + delta)

View File

@ -18,22 +18,22 @@ quasiBoolean(orOp, `or`, nonzero=true) # Bitwise Or
quasiBoolean(xorOp, `xor`, nonzero=true) # Bitwise XOr
# proc iszero*(computation: var BaseComputation) =
# var value = computation.stack.popInt()
proc iszero*(computation: var BaseComputation) =
var value = computation.stack.popInt()
# var res = if value == 0: 1.Int256 else: 0.Int256
# pushRes()
var res = if value == 0: 1.i256 else: 0.i256
pushRes()
# proc notOp*(computation: var BaseComputation) =
# var value = computation.stack.popInt()
proc notOp*(computation: var BaseComputation) =
var value = computation.stack.popInt()
# var res = constants.UINT_256_MAX - value
# pushRes()
var res = constants.UINT_256_MAX - value
pushRes()
# proc byteOp*(computation: var BaseComputation) =
# # Bitwise And
# var (position, value) = computation.stack.popInt(2)
proc byteOp*(computation: var BaseComputation) =
# Bitwise And
var (position, value) = computation.stack.popInt(2)
# var res = if position >= 32.Int256: 0.Int256 else: (value div (256.Int256 ^ (31.Int256 - position))) mod 256
# pushRes()
var res = if position >= 32.i256: 0.i256 else: (value div (256.i256.pow(31.i256 - position))) mod 256
pushRes()

158
src/logic/context.nim Normal file
View File

@ -0,0 +1,158 @@
import
../constants, ../utils_numeric, ../computation, ../vm_state, ../account, ../db/state_db, ../validation,
.. / vm / [stack, message], .. / utils / [address, padding, bytes]
proc balance*(computation: var BaseComputation) =
let address = forceBytesToAddress(computation.stack.popBinary)
var balance: Int256
# TODO computation.vmState.stateDB(read_only=True):
# balance = db.getBalance(address)
# computation.stack.push(balance)
proc origin*(computation: var BaseComputation) =
computation.stack.push(computation.msg.origin)
proc address*(computation: var BaseComputation) =
computation.stack.push(computation.msg.storageAddress)
proc caller*(computation: var BaseComputation) =
computation.stack.push(computation.msg.sender)
proc callValue*(computation: var BaseComputation) =
computation.stack.push(computation.msg.value)
proc callDataLoad*(computation: var BaseComputation) =
# Load call data into memory
let startPosition = computation.stack.popInt.getInt
let value = computation.msg.data[startPosition ..< startPosition + 32].toCString
let paddedValue = padRight(value, 32, cstring"\x00")
let normalizedValue = paddedValue.lStrip(0.char)
computation.stack.push(normalizedValue)
proc callDataSize*(computation: var BaseComputation) =
let size = computation.msg.data.len
computation.stack.push(size)
# def calldatacopy(computation):
# (
# mem_start_position,
# calldata_start_position,
# size,
# ) = computation.stack.pop(num_items=3, type_hint=constants.UINT256)
# computation.extend_memory(mem_start_position, size)
# word_count = ceil32(size) // 32
# copy_gas_cost = word_count * constants.GAS_COPY
# computation.gas_meter.consume_gas(copy_gas_cost, reason="CALLDATACOPY fee")
# value = computation.msg.data[calldata_start_position: calldata_start_position + size]
# padded_value = pad_right(value, size, b'\x00')
# computation.memory.write(mem_start_position, size, padded_value)
# def codesize(computation):
# size = len(computation.code)
# computation.stack.push(size)
# def codecopy(computation):
# (
# mem_start_position,
# code_start_position,
# size,
# ) = computation.stack.pop(num_items=3, type_hint=constants.UINT256)
# computation.extend_memory(mem_start_position, size)
# word_count = ceil32(size) // 32
# copy_gas_cost = constants.GAS_COPY * word_count
# computation.gas_meter.consume_gas(
# copy_gas_cost,
# reason="CODECOPY: word gas cost",
# )
# with computation.code.seek(code_start_position):
# code_bytes = computation.code.read(size)
# padded_code_bytes = pad_right(code_bytes, size, b'\x00')
# computation.memory.write(mem_start_position, size, padded_code_bytes)
# def gasprice(computation):
# computation.stack.push(computation.msg.gas_price)
# def extcodesize(computation):
# account = force_bytes_to_address(computation.stack.pop(type_hint=constants.BYTES))
# with computation.vm_state.state_db(read_only=True) as state_db:
# code_size = len(state_db.get_code(account))
# computation.stack.push(code_size)
# def extcodecopy(computation):
# account = force_bytes_to_address(computation.stack.pop(type_hint=constants.BYTES))
# (
# mem_start_position,
# code_start_position,
# size,
# ) = computation.stack.pop(num_items=3, type_hint=constants.UINT256)
# computation.extend_memory(mem_start_position, size)
# word_count = ceil32(size) // 32
# copy_gas_cost = constants.GAS_COPY * word_count
# computation.gas_meter.consume_gas(
# copy_gas_cost,
# reason='EXTCODECOPY: word gas cost',
# )
# with computation.vm_state.state_db(read_only=True) as state_db:
# code = state_db.get_code(account)
# code_bytes = code[code_start_position:code_start_position + size]
# padded_code_bytes = pad_right(code_bytes, size, b'\x00')
# computation.memory.write(mem_start_position, size, padded_code_bytes)
# def returndatasize(computation):
# size = len(computation.return_data)
# computation.stack.push(size)
# def returndatacopy(computation):
# (
# mem_start_position,
# returndata_start_position,
# size,
# ) = computation.stack.pop(num_items=3, type_hint=constants.UINT256)
# if returndata_start_position + size > len(computation.return_data):
# raise OutOfBoundsRead(
# "Return data length is not sufficient to satisfy request. Asked "
# "for data from index {0} to {1}. Return data is {2} bytes in "
# "length.".format(
# returndata_start_position,
# returndata_start_position + size,
# len(computation.return_data),
# )
# )
# computation.extend_memory(mem_start_position, size)
# word_count = ceil32(size) // 32
# copy_gas_cost = word_count * constants.GAS_COPY
# computation.gas_meter.consume_gas(copy_gas_cost, reason="RETURNDATACOPY fee")
# value = computation.return_data[returndata_start_position: returndata_start_position + size]
# computation.memory.write(mem_start_position, size, value)

12
src/logic/sha3.nim Normal file
View File

@ -0,0 +1,12 @@
import
../constants, ../utils_numeric, .. / utils / [keccak, bytes], .. / vm / [stack, memory, gas_meter], ../computation, helpers, bigints
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 gasCost = constants.GAS_SHA3_WORD * wordCount
computation.gasMeter.consumeGas(gasCost, reason="SHA3: word gas cost")
var res = keccak(cstring"")
pushRes()

View File

@ -2,29 +2,49 @@ import
strformat, strutils, tables, macros,
constants, bigints, errors, logging, vm_state,
vm / [gas_meter, stack, code_stream, memory, message, value, gas_costs], db / chain, computation, opcode, opcode_values, utils / [header, address],
logic / [arithmetic, comparison]
logic / [arithmetic, comparison, sha3, context]
var opcodes = initOpcodes:
# arithmetic
Op.Add: GAS_VERY_LOW add
Op.Mul: GAS_LOW mul
Op.Sub: GAS_VERY_LOW sub
Op.Div: GAS_LOW divide
Op.SDiv: GAS_LOW sdiv
Op.Mod: GAS_LOW modulo
Op.SMod: GAS_LOW smod
Op.AddMod: GAS_MID addmod
Op.MulMod: GAS_MID mulmod
Op.Exp: expGasCost arithmetic.exp
Op.SignExtend: GAS_LOW signextend
Op.Add: GAS_VERY_LOW add
Op.Mul: GAS_LOW mul
Op.Sub: GAS_VERY_LOW sub
Op.Div: GAS_LOW divide
Op.SDiv: GAS_LOW sdiv
Op.Mod: GAS_LOW modulo
Op.SMod: GAS_LOW smod
Op.AddMod: GAS_MID addmod
Op.MulMod: GAS_MID mulmod
Op.Exp: expGasCost arithmetic.exp
Op.SignExtend: GAS_LOW signextend
# comparison
Op.Lt: GAS_VERY_LOW lt
Op.Gt: GAS_VERY_LOW gt
Op.SLt: GAS_VERY_LOW slt
Op.SGt: GAS_VERY_LOW sgt
Op.Eq: GAS_VERY_LOW eq
Op.Lt: GAS_VERY_LOW lt
Op.Gt: GAS_VERY_LOW gt
Op.SLt: GAS_VERY_LOW slt
Op.SGt: GAS_VERY_LOW sgt
Op.Eq: GAS_VERY_LOW eq
Op.IsZero: GAS_VERY_LOW iszero
Op.And: GAS_VERY_LOW andOp
Op.Or: GAS_VERY_LOW orOp
Op.Xor: GAS_VERY_LOW xorOp
Op.Not: GAS_VERY_LOW notOp
Op.Byte: GAS_VERY_LOW byteOp
# sha3
Op.SHA3: GAS_SHA3 sha3op
# context
Op.Address: GAS_BASE context.address
Op.Balance: GAS_COST_BALANCE balance
Op.Origin: GAS_BASE origin
Op.Caller: GAS_BASE caller
Op.CallValue: GAS_BASE callValue
Op.CallDataLoad: GAS_VERY_LOW callDataLoad
Op.CallDataSize: GAS_BASE callDataSize
var mem = newMemory(pow(1024.int256, 2))
@ -32,6 +52,7 @@ var to = toCanonicalAddress(cstring"0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6")
var sender = toCanonicalAddress(cstring"0xcd1722f3947def4cf144679da39c4c32bdc35681")
var code = cstring""
var data: seq[byte] = @[]
var msg = newMessage(
25.int256,
@ -39,7 +60,7 @@ var msg = newMessage(
to,
sender,
0.int256,
cstring"",
data,
code,
MessageOptions(depth: 1.int256))

View File

@ -1,6 +1,6 @@
import strformat, strutils, encodings
import strformat, strutils, encodings, keccak, padding
proc toText(c: cstring): string =
proc toText*(c: cstring): string =
($c).convert(destEncoding="iso-8859-1")
proc toCanonicalAddress*(address: string): string =
@ -8,9 +8,19 @@ proc toCanonicalAddress*(address: string): string =
address
# address.toNormalizedAddress.decodeHex
proc toCanonicalAddress*(address: cstring): string =
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:

11
src/utils/bytes.nim Normal file
View File

@ -0,0 +1,11 @@
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

10
src/utils/keccak.nim Normal file
View File

@ -0,0 +1,10 @@
import
keccak_tiny, strutils
template keccak*(value: string): cstring =
cstring($keccak_256(value))
template keccak*(value: cstring): cstring =
($value).keccak

View File

@ -15,6 +15,16 @@ proc pad(value: cstring, size: int, with: cstring, left: bool): cstring =
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
template padLeft*(value: cstring, size: int, with: cstring): cstring =
pad(value, size, with, true)
@ -34,3 +44,47 @@ template pad32*(value: cstring): cstring =
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)

View File

@ -1,11 +1,11 @@
import
sequtils, bigints,
../constants, ../errors, ../logging, ../validation, ../utils_numeric
../constants, ../errors, ../logging, ../validation, ../utils_numeric, ../utils/bytes
type
Memory* = ref object
logger*: Logger
bytes*: seq[byte]
bytes*: seq[byte]
proc newMemory*: Memory =
new(result)
@ -28,8 +28,11 @@ proc newMemory*(size: Int256): Memory =
result = newMemory()
result.extend(0.int256, size)
proc read*(self: var Memory; startPosition: Int256; size: Int256): cstring =
return cstring""
proc read*(memory: var Memory, startPosition: Int256, size: Int256): seq[byte] =
result = memory.bytes[startPosition.getInt ..< (startPosition + size).getInt]
proc write*(self: var Memory, startPosition: Int256, size: Int256, value: cstring) =
proc write*(memory: var Memory, startPosition: Int256, size: Int256, value: seq[byte]) =
echo value
template write*(memory: var Memory, startPosition: Int256, size: Int256, value: cstring) =
memory.write(startPosition, size, value.toBytes)

View File

@ -22,7 +22,7 @@ type
to*: cstring
sender*: cstring
value*: Int256
data*: cstring
data*: seq[byte]
code*: cstring
internalOrigin: cstring
internalCodeAddress: cstring
@ -71,7 +71,7 @@ proc newMessage*(
to: cstring,
sender: cstring,
value: Int256,
data: cstring,
data: seq[byte],
code: cstring,
options: MessageOptions = newMessageOptions()): Message =