Implement address/sha3 opcodes, start using nim-keccak-tiny
This commit is contained in:
parent
fba1052b4c
commit
5ad14f59b2
|
@ -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"
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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()
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,10 @@
|
|||
import
|
||||
keccak_tiny, strutils
|
||||
|
||||
template keccak*(value: string): cstring =
|
||||
cstring($keccak_256(value))
|
||||
|
||||
template keccak*(value: cstring): cstring =
|
||||
($value).keccak
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 =
|
||||
|
||||
|
|
Loading…
Reference in New Issue