Reorganize VM/interpreter + cleanup (#52)
* Move and cleanup interpreter files - prepare for redesign of VM * fix call comment aobut recursive dependencies * memory: use a template again and avoid (?) a cstring-> string conversion * Fix stack test regression * Fix recursive dependency on logging_ops, test_vm_json compiles but regression :/ * Fix signextend regression * Fix 3 signed test and sha3 test
This commit is contained in:
parent
05275f9773
commit
c26c751f9b
106
nimbus/chain.nim
106
nimbus/chain.nim
|
@ -1,106 +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
|
||||
tables, stint, eth_common, eth_keys,
|
||||
./logging, ./constants, ./errors, ./validation, ./utils/hexadecimal, ./vm/base, ./db/db_chain,
|
||||
./utils/header, ./vm/forks/f20150730_frontier/frontier_vm
|
||||
|
||||
type
|
||||
Chain* = ref object
|
||||
## An Chain is a combination of one or more VM classes. Each VM is associated
|
||||
## with a range of blocks. The Chain class acts as a wrapper around these other
|
||||
## VM classes, delegating operations to the appropriate VM depending on the
|
||||
## current block number.
|
||||
header*: BlockHeader
|
||||
logger*: Logger
|
||||
networkId*: string
|
||||
vmsByRange*: seq[tuple[blockNumber: UInt256, vmk: VMkind]] # TODO: VM should actually be a runtime typedesc(VM)
|
||||
importBlock*: bool
|
||||
validateBlock*: bool
|
||||
db*: BaseChainDB
|
||||
fundedAddress*: EthAddress
|
||||
fundedAddressInitialBalance*: int
|
||||
fundedAddressPrivateKey*: PrivateKey
|
||||
|
||||
GenesisParams* = ref object
|
||||
blockNumber*: BlockNumber
|
||||
difficulty*: UInt256
|
||||
gasLimit*: GasInt
|
||||
parentHash*: Hash256
|
||||
coinbase*: EthAddress
|
||||
nonce*: string
|
||||
mixHash*: Hash256
|
||||
extraData*: string
|
||||
timestamp*: EthTime
|
||||
stateRoot*: Hash256
|
||||
|
||||
FundedAddress* = ref object
|
||||
balance*: Int256
|
||||
nonce*: int
|
||||
code*: string
|
||||
|
||||
|
||||
proc configureChain*(name: string, blockNumber: UInt256, vmk: VMKind, importBlock: bool = true, validateBlock: bool = true): Chain =
|
||||
new(result)
|
||||
result.vmsByRange = @[(blockNumber: blockNumber, vmk: vmk)]
|
||||
result.importBlock = importBlock
|
||||
result.validateBlock = validateBlock
|
||||
|
||||
proc fromGenesis*(
|
||||
chain: Chain,
|
||||
chainDB: BaseChainDB,
|
||||
genesisParams: GenesisParams,
|
||||
genesisState: Table[string, FundedAddress]): Chain =
|
||||
## Initialize the Chain from a genesis state
|
||||
var stateDB = chaindb.getStateDB(BLANK_ROOT_HASH)
|
||||
# TODO
|
||||
# for account, accountData in genesisState:
|
||||
# stateDB.setBalance(account, accountData.balance)
|
||||
# stateDB.setNonce(account, accountData.nonce)
|
||||
# stateDB.setCode(account, accountData.code)
|
||||
|
||||
new(result)
|
||||
result.db = chainDB
|
||||
result.header = BlockHeader()
|
||||
result.logger = logging.getLogger("evm.chain.chain.Chain")
|
||||
result.importBlock = chain.importBlock
|
||||
result.validateBlock = chain.validateBlock
|
||||
result.vmsByRange = chain.vmsByRange
|
||||
# TODO
|
||||
# chainDB.persistBlockToDB(result.getBlock)
|
||||
|
||||
|
||||
proc getVMClassForBlockNumber*(chain: Chain, blockNumber: BlockNumber): VMKind =
|
||||
## Returns the VM class for the given block number
|
||||
# TODO - Refactoring: superseded by newNimbusVM for the time being #https://github.com/status-im/nimbus/pull/37
|
||||
# TODO - Refactoring: redundant with constants.nim `toFork`
|
||||
# TODO should the return value be a typedesc?
|
||||
|
||||
# TODO: validate_block_number
|
||||
for idx in countdown(chain.vmsByRange.high, chain.vmsByRange.low):
|
||||
let (n, vmk) = chain.vmsByRange[idx]
|
||||
if blockNumber >= n:
|
||||
return vmk
|
||||
|
||||
raise newException(ValueError, "VM not found for block #" & $blockNumber) # TODO: VMNotFound exception
|
||||
|
||||
# TODO - Refactoring: superseded by newNimbusVM for the time being #https://github.com/status-im/nimbus/pull/37
|
||||
|
||||
proc getVM*(chain: Chain, header: BlockHeader): VM =
|
||||
## Returns the VM instance for the given block number
|
||||
# TODO - Refactoring: superseded by newNimbusVM for the time being #https://github.com/status-im/nimbus/pull/37
|
||||
# TODO - Refactoring: redundant with constants.nim `toFork`
|
||||
# shadowing input param
|
||||
let vm_class = chain.getVMClassForBlockNumber(header.blockNumber)
|
||||
|
||||
case vm_class:
|
||||
of vmkFrontier: result = newFrontierVM(header, chain.db)
|
||||
else:
|
||||
raise newException(ValueError, "Chain: only FrontierVM is implemented")
|
||||
|
||||
proc getVM*(chain: Chain): VM {.inline.} = getVM(chain, chain.header)
|
|
@ -2,103 +2,6 @@
|
|||
import
|
||||
stint, math, strutils, utils/padding, eth_common
|
||||
|
||||
proc int256*(i: int): Int256 =
|
||||
i.i256
|
||||
|
||||
# template i256*(i: int): Int256 =
|
||||
# i.initBigInt
|
||||
|
||||
template i256*(i: Int256): Int256 =
|
||||
i
|
||||
|
||||
template u256*(i: int): UInt256 =
|
||||
i.uint.u256
|
||||
|
||||
template u256*(i: UInt256): UInt256 =
|
||||
i
|
||||
|
||||
template getInt*(i: int): int =
|
||||
i
|
||||
|
||||
# TODO
|
||||
# We'll have a fast fixed i256, for now this works
|
||||
|
||||
proc `==`*(a: Int256, b: int): bool =
|
||||
a == b.i256
|
||||
|
||||
proc `!=`*(a: Int256, b: int): bool =
|
||||
a != b.i256
|
||||
|
||||
proc `==`*(a: UInt256, b: int): bool =
|
||||
a == b.u256
|
||||
|
||||
proc `!=`*(a: UInt256, b: int): bool =
|
||||
a != b.u256
|
||||
|
||||
# proc `^`*(base: int; exp: int): UInt256 =
|
||||
# let base = base.u256
|
||||
# var ex = exp
|
||||
# result = 1.u256
|
||||
# while ex > 0:
|
||||
# result = result * base
|
||||
# dec(ex)
|
||||
|
||||
proc `^`*(left: Int256, right: int): Int256 =
|
||||
var value = right.i256
|
||||
result = 1.i256
|
||||
var m = right.i256
|
||||
while value > 0.i256:
|
||||
result = result * m
|
||||
value -= 1.i256
|
||||
|
||||
proc `^`*(left: UInt256, right: UInt256): UInt256 =
|
||||
var value = right
|
||||
result = 1.u256
|
||||
var m = right.u256
|
||||
while value > 0.u256:
|
||||
result = result * m
|
||||
value -= 1.u256
|
||||
|
||||
proc `^`*(left: UInt256, right: int): UInt256 =
|
||||
left ^ right.u256
|
||||
|
||||
proc `>`*(a: Int256, b: int): bool =
|
||||
a > b.i256
|
||||
|
||||
proc `<`*(a: Int256, b: int): bool =
|
||||
a < b.i256
|
||||
|
||||
proc `>`*(a: UInt256, b: int): bool =
|
||||
a > b.u256
|
||||
|
||||
proc `<`*(a: UInt256, b: int): bool =
|
||||
a < b.u256
|
||||
|
||||
proc `mod`*(a: Int256, b: int): Int256 =
|
||||
a mod b.i256
|
||||
|
||||
proc `div`*(a: Int256, b: int): Int256 =
|
||||
a div b.i256
|
||||
|
||||
proc `mod`*(a: UInt256, b: int): UInt256 =
|
||||
a mod b.u256
|
||||
|
||||
proc `div`*(a: UInt256, b: int): UInt256 =
|
||||
a div b.u256
|
||||
|
||||
template mapOp(op: untyped): untyped =
|
||||
proc `op`*(left: Int256, right: int): Int256 =
|
||||
result = left.i256
|
||||
result = `op`(result, right.i256)
|
||||
|
||||
proc `op`*(left: UInt256, right: int): UInt256 =
|
||||
result = left.u256
|
||||
result = `op`(result, right.u256)
|
||||
|
||||
mapOp(`and`)
|
||||
mapOp(`or`)
|
||||
mapOp(`xor`)
|
||||
|
||||
proc default(t: typedesc): t = discard
|
||||
|
||||
# constants
|
||||
|
@ -108,7 +11,7 @@ let
|
|||
INT_256_MAX_AS_UINT256* = cast[Uint256](high(Int256))
|
||||
NULLBYTE* = "\x00"
|
||||
EMPTYWORD* = repeat(NULLBYTE, 32)
|
||||
UINT160CEILING*: UInt256 = 2.u256 ^ 160
|
||||
UINT160CEILING*: UInt256 = 2.u256.pow(160)
|
||||
ZERO_ADDRESS* = default(EthAddress)
|
||||
CREATE_CONTRACT_ADDRESS* = ZERO_ADDRESS
|
||||
ZERO_HASH32* = Hash256()
|
||||
|
@ -133,14 +36,6 @@ let
|
|||
MAX_UNCLE_DEPTH* = 6.u256
|
||||
MAX_UNCLES* = 2.u256
|
||||
|
||||
SECPK1_P*: UInt256 = 2.u256 ^ 256 - 2.u256 ^ 32 - 977.u256
|
||||
SECPK1_N*: UInt256 = "115792089237316195423570985008687907852837564279074904382605163141518161494337".u256
|
||||
SECPK1_A* = 0.u256
|
||||
SECPK1_B* = 7.u256
|
||||
SECPK1_Gx* = 0.u256
|
||||
SECPK1_Gy* = 0.u256
|
||||
SECPK1_G* = (SECPK1Gx, SECPK1Gy)
|
||||
|
||||
EMPTY_UNCLE_HASH* = "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347".toDigest
|
||||
|
||||
GENESIS_BLOCK_NUMBER* = 0.u256
|
||||
|
|
|
@ -6,9 +6,8 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
eth_common, tables,
|
||||
../constants, ../errors, ../validation, ../account, ../logging, ../utils_numeric, .. / utils / [padding, bytes, keccak],
|
||||
stint, rlp
|
||||
eth_common, tables, nimcrypto, stint, rlp,
|
||||
../constants, ../errors, ../validation, ../account, ../logging
|
||||
|
||||
type
|
||||
AccountStateDB* = ref object
|
||||
|
@ -64,11 +63,11 @@ proc setStorage*(db: var AccountStateDB, address: EthAddress, slot: UInt256, val
|
|||
# let account = db.getAccount(address)
|
||||
# var storage = HashTrie(HexaryTrie(self.db, account.storageRoot))
|
||||
|
||||
let slotAsKey = slot.intToBigEndian.pad32.toString
|
||||
let slotAsKey = "0x" & slot.dumpHex # Convert to a number to hex big-endian representation including prefix and leading zeros
|
||||
var storage = db.db
|
||||
# TODO fix
|
||||
if value > 0:
|
||||
let encodedValue = rlp.encode value.intToBigEndian
|
||||
let encodedValue = rlp.encode value.toByteArrayBE
|
||||
storage[slotAsKey] = encodedValue
|
||||
else:
|
||||
storage.del(slotAsKey)
|
||||
|
@ -87,13 +86,11 @@ proc getStorage*(db: var AccountStateDB, address: EthAddress, slot: UInt256): (U
|
|||
# let account = db.GetAccount(address)
|
||||
# var storage = HashTrie(HexaryTrie(self.db, account.storageRoot))
|
||||
|
||||
let slotAsKey = slot.intToBigEndian.pad32.toString
|
||||
let slotAsKey = "0x" & slot.dumpHex # Convert to a number to hex big-endian representation including prefix and leading zeros
|
||||
var storage = db.db
|
||||
if storage.hasKey(slotAsKey):
|
||||
#result = storage[slotAsKey]
|
||||
# XXX: `bigEndianToInt` can be refactored to work with a BytesRange/openarray
|
||||
# Then we won't need to call `toSeq` here.
|
||||
result = (storage[slotAsKey].toSeq.bigEndianToInt, true)
|
||||
let byteRange = storage[slotAsKey]
|
||||
result = (readUintBE[256](byteRange.toOpenArray), true)
|
||||
else:
|
||||
result = (0.u256, false)
|
||||
|
||||
|
@ -117,7 +114,7 @@ proc setCode*(db: var AccountStateDB, address: EthAddress, code: string) =
|
|||
|
||||
var account = db.getAccount(address)
|
||||
|
||||
account.codeHash = keccak(code)
|
||||
account.codeHash = keccak256.digest code
|
||||
#db.db[account.codeHash] = code
|
||||
db.setAccount(address, account)
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ type
|
|||
## Error signaling that an account has insufficient funds to transfer the
|
||||
## requested value.
|
||||
|
||||
StackDepthLimit* = object of VMError
|
||||
StackDepthError* = object of VMError
|
||||
## Error signaling that the call stack has exceeded it's maximum allowed depth.
|
||||
|
||||
ContractCreationCollision* = object of VMError
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
# --warning[XDeclaredButNotUsed]:off
|
|
@ -1,34 +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, sequtils, macros,
|
||||
constants, logging, errors, opcode_values, computation, vm/stack, stint,
|
||||
./vm_types
|
||||
|
||||
|
||||
# Super dirty fix for https://github.com/status-im/nimbus/issues/46
|
||||
# Pending https://github.com/status-im/nimbus/issues/36
|
||||
# Disentangle opcode logic
|
||||
from logic.call import runLogic, BaseCall
|
||||
|
||||
|
||||
template run*(opcode: Opcode, computation: var BaseComputation) =
|
||||
# Hook for performing the actual VM execution
|
||||
# opcode.consumeGas(computation)
|
||||
|
||||
if opcode.kind == Op.Call: # Super dirty fix for https://github.com/status-im/nimbus/issues/46
|
||||
# TODO remove this branch
|
||||
runLogic(BaseCall(opcode), computation)
|
||||
elif computation.gasCosts[opcode.kind].kind != GckFixed:
|
||||
opcode.runLogic(computation)
|
||||
else:
|
||||
computation.gasMeter.consumeGas(computation.gasCosts[opcode.kind].cost, reason = $opcode.kind)
|
||||
opcode.runLogic(computation)
|
||||
|
||||
method logger*(opcode: Opcode): Logger =
|
||||
logging.getLogger(&"vm.opcode.{opcode.kind}")
|
|
@ -1,93 +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, tables, macros,
|
||||
constants, stint, errors, logging, vm_state, opcode_table,
|
||||
vm / [gas_meter, stack, code_stream, memory, message, value], db / chain, computation, opcode, opcode_values, utils / [header, address],
|
||||
logic / [arithmetic, comparison, sha3, context, block_ops, stack_ops, duplication, swap, memory_ops, storage, flow, logging_ops, invalid, call, system_ops]
|
||||
|
||||
var mem = newMemory(pow(1024.int256, 2))
|
||||
|
||||
var to = toCanonicalAddress("0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6")
|
||||
var sender = toCanonicalAddress("0xcd1722f3947def4cf144679da39c4c32bdc35681")
|
||||
|
||||
var code = ""
|
||||
var data: seq[byte] = @[]
|
||||
|
||||
var msg = newMessage(
|
||||
25.int256,
|
||||
1.int256,
|
||||
to,
|
||||
sender,
|
||||
0.int256,
|
||||
data,
|
||||
code,
|
||||
MessageOptions(depth: 1))
|
||||
|
||||
var c = BaseComputation(
|
||||
vmState: BaseVMState(
|
||||
prevHeaders: @[],
|
||||
chaindb: BaseChainDB(),
|
||||
blockHeader: BlockHeader(),
|
||||
name: "zero"),
|
||||
msg: msg,
|
||||
memory: mem,
|
||||
stack: newStack(),
|
||||
gasMeter: newGasMeter(msg.gas),
|
||||
code: newCodeStream(code),
|
||||
children: @[],
|
||||
rawOutput: "",
|
||||
returnData: "",
|
||||
error: nil,
|
||||
logEntries: @[],
|
||||
shouldEraseReturnData: false,
|
||||
accountsToDelete: initTable[string, string](),
|
||||
opcodes: OPCODE_TABLE,
|
||||
precompiles: initTable[string, Opcode]())
|
||||
|
||||
# var c2 = c.applyComputation(c.vmState, c.msg)
|
||||
|
||||
macro runOpcodes*(computation: untyped, program: untyped): untyped =
|
||||
# runOpcodes(c):
|
||||
# stack: @[Value..]
|
||||
#
|
||||
# Op
|
||||
# Op
|
||||
#
|
||||
# becomes
|
||||
#
|
||||
# c.stack.push(Value) ..
|
||||
#
|
||||
# c.getOpcodeFn(Op).run(c)
|
||||
# echo c.stack ..
|
||||
var stack = nnkStmtList.newTree()
|
||||
for child in program[0][1][0][1]:
|
||||
let push = quote:
|
||||
`computation`.stack.push(`child`)
|
||||
stack.add(push)
|
||||
|
||||
var ops = nnkStmtList.newTree()
|
||||
for z, op in program:
|
||||
if z > 0:
|
||||
let run = quote:
|
||||
`computation`.getOpcodeFn(`op`).run(`computation`)
|
||||
echo `computation`.stack
|
||||
ops.add(run)
|
||||
|
||||
result = nnkStmtList.newTree(stack, ops)
|
||||
|
||||
# useful for testing simple cases
|
||||
runOpcodes(c):
|
||||
stack: @[2.vint, 2.vint, 2.vint, 2.vint, 2.vint, 2.vint, 4.vint]
|
||||
|
||||
Op.Add
|
||||
Op.Mul
|
||||
Op.Div
|
||||
Op.Sub
|
||||
Op.Mul
|
||||
|
|
@ -24,5 +24,3 @@ proc toString*(value: seq[byte]): string =
|
|||
|
||||
proc toBytes*(value: string): seq[byte] =
|
||||
result = value.mapIt(it.byte)
|
||||
|
||||
|
||||
|
|
|
@ -92,4 +92,8 @@ proc generateHeaderFromParentHeader*(
|
|||
# TODO: data: extraData,
|
||||
)
|
||||
|
||||
import nimcrypto
|
||||
# TODO: required otherwise
|
||||
# eth_common/rlp_serialization.nim(18, 12) template/generic instantiation from here
|
||||
# nimcrypto/hash.nim(46, 6) Error: attempting to call undeclared routine: 'init'
|
||||
proc hash*(b: BlockHeader): Hash256 {.inline.} = rlpHash(b)
|
||||
|
|
|
@ -1,20 +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
|
||||
# eth_utils, rlp, trie, evm.db.backends.memory, evm.db.chain
|
||||
|
||||
# proc makeTrieRootAndNodes*(transactions: auto; trieClass: auto): auto =
|
||||
# var
|
||||
# chaindb = BaseChainDB(MemoryDB())
|
||||
# db = chaindb.db
|
||||
# transactionDb = trieClass(db)
|
||||
# for index, transaction in transactions:
|
||||
# var indexKey = rlp.encode(index)
|
||||
# transactionDb[indexKey] = rlp.encode(transaction)
|
||||
# return (transactionDb.rootHash, transactionDb.db.wrappedDb.kvStore)
|
||||
|
|
@ -6,7 +6,9 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
../logging, ../constants, ../errors, ../transaction, ../vm_types, ../computation, ../block_types, ../vm_state, ../vm_state_transactions, ../db/db_chain, ../utils/header
|
||||
../logging, ../constants, ../errors, ../transaction, ../vm_types,
|
||||
../block_types, ../vm_state, ../vm_state_transactions, ../db/db_chain, ../utils/header,
|
||||
./computation
|
||||
|
||||
type
|
||||
VMkind* = enum
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import
|
||||
strformat, strutils, sequtils, parseutils, sets, macros,
|
||||
../logging, ../constants, ../opcode_values
|
||||
../logging, ../constants, ./interpreter/opcode_values
|
||||
|
||||
type
|
||||
CodeStream* = ref object
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
|
||||
import
|
||||
strformat, strutils, sequtils, macros, stint, terminal, math, eth_common, byteutils, tables,
|
||||
./constants, ./errors, ./utils/hexadecimal, ./utils_numeric, ./validation, ./vm_state, ./logging, ./opcode_values, ./vm_types,
|
||||
./vm/[code_stream, gas_meter, memory, message, stack],
|
||||
../constants, ../errors, ../validation, ../vm_state, ../logging, ../vm_types,
|
||||
./interpreter/[opcode_values,gas_meter, gas_costs],
|
||||
./code_stream, ./memory, ./message, ./stack,
|
||||
|
||||
# TODO further refactoring of gas cost
|
||||
vm/forks/gas_costs,
|
||||
vm/forks/f20150730_frontier/frontier_vm_state,
|
||||
vm/forks/f20161018_tangerine_whistle/tangerine_vm_state
|
||||
./forks/f20150730_frontier/frontier_vm_state,
|
||||
./forks/f20161018_tangerine_whistle/tangerine_vm_state
|
||||
|
||||
method newBaseComputation*(vmState: BaseVMState, message: Message): BaseComputation {.base.}=
|
||||
raise newException(ValueError, "Must be implemented by subclasses")
|
||||
|
@ -239,6 +239,27 @@ method getOpcodeFn*(computation: var BaseComputation, op: Op): Opcode =
|
|||
raise newException(InvalidInstruction,
|
||||
&"Invalid opcode {op}")
|
||||
|
||||
# Super dirty fix for https://github.com/status-im/nimbus/issues/46
|
||||
# Pending https://github.com/status-im/nimbus/issues/36
|
||||
# Disentangle opcode logic
|
||||
from ./interpreter/opcodes_impl/call import runLogic, BaseCall
|
||||
|
||||
template run*(opcode: Opcode, computation: var BaseComputation) =
|
||||
# Hook for performing the actual VM execution
|
||||
# opcode.consumeGas(computation)
|
||||
|
||||
if opcode.kind == Op.Call: # Super dirty fix for https://github.com/status-im/nimbus/issues/46
|
||||
# TODO remove this branch
|
||||
runLogic(BaseCall(opcode), computation)
|
||||
elif computation.gasCosts[opcode.kind].kind != GckFixed:
|
||||
opcode.runLogic(computation)
|
||||
else:
|
||||
computation.gasMeter.consumeGas(computation.gasCosts[opcode.kind].cost, reason = $opcode.kind)
|
||||
opcode.runLogic(computation)
|
||||
|
||||
method logger*(opcode: Opcode): Logger =
|
||||
logging.getLogger(&"vm.opcode.{opcode.kind}")
|
||||
|
||||
macro applyComputation*(t: typed, vmState: untyped, message: untyped): untyped =
|
||||
# Perform the computation that would be triggered by the VM message
|
||||
# c.applyComputation(vmState, message)
|
|
@ -0,0 +1 @@
|
|||
Folder to be deleted
|
|
@ -5,14 +5,20 @@
|
|||
# * 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
|
||||
import
|
||||
./interpreter/[opcode_values, gas_meter, opcode_table],
|
||||
./interpreter/vm_forks
|
||||
|
||||
# proc encodeHex*(value: string): string =
|
||||
# # return "0x" & codecs.decode(codecs.encode(value, "hex"), "utf8")
|
||||
# return value
|
||||
from utils/utils_numeric import bigEndianToInt
|
||||
|
||||
# proc decodeHex*(value: string): string =
|
||||
# # var hexPart = value.rsplit("x", 1)[1]
|
||||
# return value
|
||||
# # return codecs.decode(hexPart, "hex")
|
||||
import # Used in vm_types. Beware of recursive dependencies
|
||||
./code_stream, ./computation, ./stack, ./message
|
||||
|
||||
export
|
||||
opcode_values, gas_meter, opcode_table,
|
||||
vm_forks
|
||||
|
||||
export utils_numeric.bigEndianToInt
|
||||
|
||||
export
|
||||
code_stream, computation, stack, message
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
|
@ -6,10 +6,9 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
stint, eth_common, math,
|
||||
../../utils/macros_gen_opcodes,
|
||||
../../opcode_values,
|
||||
../../utils_numeric
|
||||
stint, math, eth_common, # GasInt
|
||||
../utils/[macros_gen_opcodes, utils_numeric],
|
||||
./opcode_values
|
||||
|
||||
# Gas Fee Schedule
|
||||
# Yellow Paper Appendix G - https://ethereum.github.io/yellowpaper/paper.pdf
|
|
@ -6,8 +6,8 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
strformat,
|
||||
../logging, ../errors, ../vm_types
|
||||
strformat, eth_common, # GasInt
|
||||
../../logging, ../../errors, ../../vm_types
|
||||
|
||||
proc newGasMeter*(startGas: GasInt): GasMeter =
|
||||
new(result)
|
|
@ -6,11 +6,9 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
tables,
|
||||
stint, logging,
|
||||
vm / [gas_meter, stack, code_stream, memory, message], db / db_chain, computation, opcode, opcode_values, utils / [header, address],
|
||||
logic / [arithmetic, comparison, sha3, context, block_ops, stack_ops, duplication, swap, memory_ops, storage, flow, logging_ops, invalid, call, system_ops],
|
||||
./vm_types
|
||||
tables, stint,
|
||||
../../vm_types, ./opcode_values,
|
||||
opcodes_impl/[arithmetic, comparison, sha3, context, block_ops, stack_ops, duplication, swap, memory_ops, storage, flow, logging_ops, invalid, call, system_ops]
|
||||
|
||||
const
|
||||
OpLogic*: Table[Op, proc(computation: var BaseComputation){.nimcall.}] = {
|
|
@ -5,7 +5,7 @@
|
|||
# * 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 ./utils/macros_gen_opcodes
|
||||
import ../utils/macros_gen_opcodes
|
||||
|
||||
fill_enum_holes:
|
||||
type
|
|
@ -6,9 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
../constants, ../utils_numeric, ../computation, ../vm_types,
|
||||
.. / vm / [gas_meter, stack], ../opcode, ../opcode_values,
|
||||
helpers, stint, strutils
|
||||
helpers, stint, strutils, ./impl_std_import
|
||||
|
||||
proc add*(computation: var BaseComputation) =
|
||||
# Addition
|
||||
|
@ -107,7 +105,7 @@ proc signextend*(computation: var BaseComputation) =
|
|||
if bits <= 31.u256:
|
||||
let testBit = bits.toInt * 8 + 7
|
||||
let bitPos = (1 shl testBit)
|
||||
let mask = bitPos - 1
|
||||
let mask = u256(bitPos - 1)
|
||||
if not (value and bitPos).isZero:
|
||||
res = value or (not mask)
|
||||
else:
|
|
@ -6,8 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
times,
|
||||
../constants, ../errors, ../computation, ../vm_state, ../vm_types, .. / vm / [stack], stint
|
||||
times, ./impl_std_import
|
||||
|
||||
{.this: computation.}
|
||||
{.experimental.}
|
|
@ -6,11 +6,15 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
strformat, eth_common,
|
||||
../constants, ../vm_types, ../errors, ../computation, ../opcode_values, ../logging,
|
||||
.. / vm / [stack, memory, gas_meter, message],
|
||||
.. / utils / [address, bytes],
|
||||
stint
|
||||
strformat, eth_common, stint,
|
||||
# ./impl_std_import # Cannot do that due to recursive dependencies
|
||||
# .../vm/interpreter/opcodes_impl/impl_std_import.nim imports .../vm/computation.nim
|
||||
# .../vm/computation.nim imports .../vm/interpreter/opcodes_impl/call.nim
|
||||
# .../vm/interpreter/opcodes_impl/call.nim imports .../vm/interpreter/opcodes_impl/impl_std_import.nim
|
||||
../../../constants, ../../../vm_types, ../../../errors, ../../../logging,
|
||||
../../../utils/bytes,
|
||||
../../computation, ../../stack, ../../memory, ../../message,
|
||||
../opcode_values, ../gas_meter, ../gas_costs
|
||||
|
||||
type
|
||||
# TODO most of these are for gas handling
|
||||
|
@ -68,7 +72,7 @@ method runLogic*(call: BaseCall, computation) =
|
|||
let senderBalance = 0.u256
|
||||
|
||||
let insufficientFunds = shouldTransferValue and senderBalance < value
|
||||
let stackTooDeep = computation.msg.depth + 1 > constants.STACK_DEPTH_LIMIT
|
||||
let stackTooDeep = computation.msg.depth + 1 > STACK_DEPTH_LIMIT
|
||||
|
||||
if insufficientFunds or stackTooDeep:
|
||||
computation.returnData = ""
|
|
@ -6,8 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
../constants, ../utils_numeric, ../computation, ../vm/stack, ../vm_types,
|
||||
helpers, stint
|
||||
helpers, ./impl_std_import
|
||||
|
||||
quasiBoolean(lt, `<`) # Lesser Comparison
|
||||
|
||||
|
@ -35,7 +34,7 @@ proc iszero*(computation: var BaseComputation) =
|
|||
proc notOp*(computation: var BaseComputation) =
|
||||
var value = computation.stack.popInt()
|
||||
|
||||
var res = constants.UINT_256_MAX - value
|
||||
var res = UINT_256_MAX - value
|
||||
pushRes()
|
||||
|
||||
# TODO: seems like there is an implementation or a comment issue
|
|
@ -7,9 +7,7 @@
|
|||
|
||||
import
|
||||
strformat,
|
||||
../constants, ../vm_types, ../errors, ../utils_numeric, ../computation, ../vm_state, ../account, ../db/state_db, ../validation,
|
||||
.. /vm/[stack, message, gas_meter, memory, code_stream], ../utils/[address, padding, bytes], stint,
|
||||
../opcode_values
|
||||
./impl_std_import
|
||||
|
||||
proc balance*(computation: var BaseComputation) =
|
||||
let address = computation.stack.popAddress()
|
|
@ -6,8 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
macros, strformat,
|
||||
../vm_types, ../computation, ../vm/stack
|
||||
macros, strformat, ./impl_std_import
|
||||
|
||||
macro dupXX(position: static[int]): untyped =
|
||||
let name = ident(&"dup{position}")
|
|
@ -6,9 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
strformat, stint,
|
||||
../constants, ../vm_types, ../opcode_values, ../logging, ../errors, ../computation, .. /vm / [code_stream, stack]
|
||||
|
||||
strformat, ./impl_std_import
|
||||
|
||||
{.this: computation.}
|
||||
{.experimental.}
|
|
@ -5,7 +5,7 @@
|
|||
# * 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 macros
|
||||
import macros, stint
|
||||
|
||||
template pushRes*: untyped =
|
||||
computation.stack.push(res)
|
||||
|
@ -22,8 +22,8 @@ macro quasiBoolean*(name: untyped, op: untyped, signed: untyped = nil, nonzero:
|
|||
actualLeftNode = ident("leftSigned")
|
||||
actualRightNode = ident("rightSigned")
|
||||
signedNode = quote:
|
||||
let `actualLeftNode` = unsignedToSigned(`leftNode`)
|
||||
let `actualRightNode` = unsignedToSigned(`rightNode`)
|
||||
let `actualLeftNode` = cast[Int256](`leftNode`)
|
||||
let `actualRightNode` = cast[Int256](`rightNode`)
|
||||
var test = if nonzero.isNil:
|
||||
quote:
|
||||
`op`(`actualLeftNode`, `actualRightNode`)
|
|
@ -0,0 +1,22 @@
|
|||
# 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
|
||||
stint, stint/lenient_stint,
|
||||
../../../constants, ../../../vm_state, ../../../vm_types, ../../../vm_types,
|
||||
../../../errors, ../../../logging, ../../../utils/padding, ../../../utils/bytes,
|
||||
../../stack, ../../computation, ../../stack, ../../memory, ../../message,
|
||||
../../code_stream, ../../utils/utils_numeric,
|
||||
../opcode_values, ../gas_meter, ../gas_costs
|
||||
|
||||
export
|
||||
stint, lenient_stint,
|
||||
constants, vm_state, vm_types, vm_types,
|
||||
errors, logging, padding, bytes,
|
||||
stack, computation, stack, memory, message,
|
||||
code_stream, utils_numeric,
|
||||
opcode_values, gas_meter, gas_costs
|
|
@ -6,7 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
../errors, ../vm_types, ../computation
|
||||
./impl_std_import
|
||||
|
||||
proc invalidOp*(computation: var BaseComputation) =
|
||||
raise newException(InvalidInstruction, "Invalid opcode")
|
|
@ -7,9 +7,7 @@
|
|||
|
||||
import
|
||||
strformat, macros,
|
||||
../constants, ../errors, ../vm_types, ../computation, ../vm/[stack, memory, gas_meter, message], ../utils/bytes,
|
||||
../opcode_values,
|
||||
stint
|
||||
./impl_std_import
|
||||
|
||||
{.this: computation.}
|
||||
{.experimental.}
|
||||
|
@ -53,19 +51,18 @@ macro logXX(topicCount: static[int]): untyped =
|
|||
result.body.add(topicCode)
|
||||
|
||||
let OpName = ident(&"Log{topicCount}")
|
||||
let logicCode = quote:
|
||||
let logicCode = quote do:
|
||||
`computation`.gasMeter.consumeGas(
|
||||
`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
|
||||
`computation`.addLogEntry(
|
||||
account=`computation`.msg.storageAddress,
|
||||
topics=`topics`,
|
||||
data=log_data)
|
||||
account = `computation`.msg.storageAddress,
|
||||
topics = `topics`,
|
||||
data = log_data)
|
||||
|
||||
result.body.add(logicCode)
|
||||
# echo result.repr
|
||||
|
||||
logXX(0)
|
||||
logXX(1)
|
|
@ -6,10 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
../constants, ../computation, ../vm_types, ../vm/[stack, memory, gas_meter], .. /utils/[padding, bytes],
|
||||
../opcode_values,
|
||||
stint
|
||||
|
||||
./impl_std_import
|
||||
|
||||
{.this: computation.}
|
||||
{.experimental.}
|
|
@ -6,21 +6,19 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
../constants, ../utils_numeric, ../utils/[keccak, bytes], ../vm/[stack, memory, gas_meter],
|
||||
../computation, ../vm_types, ../opcode_values,
|
||||
./helpers,
|
||||
stint
|
||||
nimcrypto,
|
||||
./impl_std_import, ./helpers
|
||||
|
||||
proc sha3op*(computation: var BaseComputation) =
|
||||
let (startPosition, size) = computation.stack.popInt(2)
|
||||
let (pos, len) = (startPosition.toInt, size.toInt)
|
||||
|
||||
computation.gasMeter.consumeGas(
|
||||
computation.gasCosts[Sha3].m_handler(computation.memory.len, pos, len),
|
||||
computation.gasCosts[Op.Sha3].m_handler(computation.memory.len, pos, len),
|
||||
reason="SHA3: word gas cost"
|
||||
)
|
||||
|
||||
computation.memory.extend(pos, len)
|
||||
|
||||
var res = keccak("") # TODO: stub
|
||||
var res = keccak256.digest("") # TODO: stub
|
||||
pushRes()
|
|
@ -6,8 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
strformat, macros, sequtils,
|
||||
../vm_types, ../constants, ../errors, ../computation, .. / vm / [stack, code_stream], .. / utils / [padding, bytes], stint
|
||||
strformat, macros, ./impl_std_import
|
||||
|
||||
{.this: computation.}
|
||||
{.experimental.}
|
|
@ -6,11 +6,10 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
../constants, ../vm_types, ../errors, ../computation, ../vm_state,
|
||||
../utils/header,
|
||||
../db/[db_chain, state_db], ../vm/[stack, gas_meter, message],
|
||||
../opcode_values,
|
||||
strformat, stint
|
||||
./impl_std_import, strformat,
|
||||
../../../utils/header,
|
||||
../../../db/[db_chain, state_db]
|
||||
|
||||
|
||||
{.this: computation.}
|
||||
{.experimental.}
|
|
@ -6,8 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
macros, strformat,
|
||||
../vm_types, ../computation, ../vm/stack
|
||||
macros, strformat, ./impl_std_import
|
||||
|
||||
macro swapXX(position: static[int]): untyped =
|
||||
let name = ident(&"swap{position}")
|
|
@ -7,9 +7,7 @@
|
|||
|
||||
import
|
||||
strformat,
|
||||
../constants, ../vm_types, ../errors, ../computation, ../opcode, ../opcode_values, ../logging, ../vm_state, call,
|
||||
.. / vm / [stack, gas_meter, memory, message], .. / utils / [address, hexadecimal, bytes],
|
||||
../opcode_values,
|
||||
./call, ./impl_std_import,
|
||||
stint, byteutils, eth_common
|
||||
|
||||
{.this: computation.}
|
||||
|
@ -70,7 +68,7 @@ method runLogic*(create: Create, computation) =
|
|||
|
||||
let childMsg = computation.prepareChildMessage(
|
||||
gas=0, # TODO refactor gas
|
||||
to=constants.CREATE_CONTRACT_ADDRESS,
|
||||
to=CREATE_CONTRACT_ADDRESS,
|
||||
value=value,
|
||||
data=cast[seq[byte]](@[]),
|
||||
code=callData.toString,
|
|
@ -9,8 +9,8 @@ import
|
|||
../../db/db_chain, ../../constants,
|
||||
../../utils/header,
|
||||
../base,
|
||||
./f20150730_frontier/frontier_vm,
|
||||
./f20161018_tangerine_whistle/tangerine_vm,
|
||||
../forks/f20150730_frontier/frontier_vm,
|
||||
../forks/f20161018_tangerine_whistle/tangerine_vm,
|
||||
stint
|
||||
|
||||
# Note (mamy): refactoring is in progress (2018-05-23), this is redundant with
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
import
|
||||
sequtils, stint,
|
||||
../constants, ../errors, ../logging, ../validation, ../utils_numeric, ../utils/bytes
|
||||
../constants, ../errors, ../logging, ../validation, ../utils/bytes,
|
||||
./utils/utils_numeric
|
||||
|
||||
type
|
||||
Memory* = ref object
|
||||
|
@ -57,3 +58,7 @@ proc write*(memory: var Memory, startPosition: Natural, value: openarray[byte])
|
|||
|
||||
template write*(memory: var Memory, startPosition: Natural, size: Natural, value: cstring) =
|
||||
memory.write(startPosition, 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
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import
|
||||
strformat, strutils, sequtils, macros, rlp, eth_common, nimcrypto,
|
||||
../errors, ../validation, ../utils_numeric, ../constants, stint, ../logging, .. / utils / bytes
|
||||
../errors, ../validation, ./utils/utils_numeric, ../constants, stint, ../logging, .. / utils / bytes
|
||||
|
||||
type
|
||||
Stack* = ref object of RootObj
|
||||
|
@ -99,6 +99,8 @@ proc swap*(stack: var Stack, position: int) =
|
|||
raise newException(InsufficientStack,
|
||||
&"Insufficient stack items for SWAP{position}")
|
||||
|
||||
template getint(x: int): int = x
|
||||
|
||||
proc dup*(stack: var Stack, position: int | UInt256) =
|
||||
## Perform a DUP operation on the stack
|
||||
let position = position.getInt
|
||||
|
|
|
@ -5,14 +5,12 @@
|
|||
# * 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 stint, constants, strformat, strutils, sequtils, endians, macros, utils / padding, rlp
|
||||
import
|
||||
stint, strformat, strutils, sequtils, endians, macros, rlp,
|
||||
../../constants, ../../utils/padding
|
||||
|
||||
# some methods based on py-evm utils/numeric
|
||||
|
||||
proc intToBigEndian*(value: UInt256): Bytes {.deprecated.} =
|
||||
result = newSeq[byte](32)
|
||||
result[0 .. ^1] = value.toByteArrayBE()
|
||||
|
||||
proc bigEndianToInt*(value: openarray[byte]): UInt256 =
|
||||
if value.len == 32:
|
||||
readUintBE[256](value)
|
||||
|
@ -22,14 +20,6 @@ proc bigEndianToInt*(value: openarray[byte]): UInt256 =
|
|||
proc log256*(value: UInt256): Natural =
|
||||
(255 - value.countLeadingZeroBits) div 8 # Compilers optimize to `shr 3`
|
||||
|
||||
proc unsignedToSigned*(value: UInt256): Int256 =
|
||||
0.i256
|
||||
# TODO Remove stub (used in quasiBoolean for signed comparison)
|
||||
|
||||
proc signedToUnsigned*(value: Int256): UInt256 =
|
||||
0.u256
|
||||
# TODO Remove stub (used in quasiBoolean for signed comparison)
|
||||
|
||||
proc unsignedToPseudoSigned*(value: UInt256): UInt256 =
|
||||
result = value
|
||||
if value > INT_256_MAX_AS_UINT256:
|
|
@ -9,7 +9,7 @@ import
|
|||
macros, strformat, tables,
|
||||
stint, eth_common,
|
||||
./logging, ./constants, ./errors, ./transaction, ./db/[db_chain, state_db],
|
||||
./utils/[state, header]
|
||||
./utils/header
|
||||
|
||||
type
|
||||
BaseVMState* = ref object of RootObj
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
import
|
||||
strformat, tables,
|
||||
logging, constants, errors, computation, transaction, vm_types, vm_state, block_types, db / db_chain, utils / [state, header]
|
||||
./logging, ./constants, ./errors, ./vm/computation,
|
||||
./transaction, ./vm_types, ./vm_state, ./block_types, ./db/db_chain, ./utils/header
|
||||
|
||||
method executeTransaction(vmState: var BaseVMState, transaction: BaseTransaction): (BaseComputation, BlockHeader) {.base.}=
|
||||
# Execute the transaction in the vm
|
||||
|
|
|
@ -6,13 +6,11 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
tables,
|
||||
constants, vm_state,
|
||||
opcode_values, stint, eth_common,
|
||||
vm / [code_stream, memory, stack, forks/gas_costs],
|
||||
./logging
|
||||
tables, stint, eth_common,
|
||||
./constants, ./vm_state, ./logging,
|
||||
./vm/[memory, stack, code_stream],
|
||||
./vm/interpreter/[gas_costs, opcode_values] # TODO - will be hidden at a lower layer
|
||||
|
||||
export GasInt, gas_costs
|
||||
|
||||
type
|
||||
BaseComputation* = ref object of RootObj
|
||||
|
@ -32,7 +30,7 @@ type
|
|||
accountsToDelete*: Table[EthAddress, EthAddress]
|
||||
opcodes*: Table[Op, proc(computation: var BaseComputation){.nimcall.}]
|
||||
precompiles*: Table[string, Opcode]
|
||||
gasCosts*: GasCosts # TODO - avoid allocating memory for this const
|
||||
gasCosts*: GasCosts # TODO - will be hidden at a lower layer
|
||||
|
||||
Error* = ref object
|
||||
info*: string
|
||||
|
|
|
@ -10,5 +10,4 @@ import ./test_code_stream,
|
|||
./test_memory,
|
||||
./test_stack,
|
||||
./test_opcode
|
||||
# ./test_vm
|
||||
# ./test_vm_json
|
||||
|
|
|
@ -1,38 +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
|
||||
unittest, strformat, tables, times,
|
||||
stint, eth_keys, eth_common,
|
||||
../nimbus/[constants, chain, vm/base, vm/forks/f20150730_frontier/frontier_vm, utils/header, utils/address, db/db_chain, db/backends/memory_backend]
|
||||
|
||||
proc chainWithoutBlockValidation*: Chain =
|
||||
result = configureChain("TestChain", GENESIS_BLOCK_NUMBER, vmkFrontier, false, false)
|
||||
let privateKey = initPrivateKey("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8")
|
||||
let fundedAddr = privateKey.getPublicKey.toCanonicalAddress
|
||||
let initialBalance = 100_000_000
|
||||
let genesisParams = GenesisParams(
|
||||
blockNumber: GENESIS_BLOCK_NUMBER,
|
||||
difficulty: GENESIS_DIFFICULTY,
|
||||
gasLimit: GENESIS_GAS_LIMIT,
|
||||
parentHash: GENESIS_PARENT_HASH,
|
||||
coinbase: GENESIS_COINBASE,
|
||||
nonce: GENESIS_NONCE,
|
||||
mixHash: GENESIS_MIX_HASH,
|
||||
extraData: GENESIS_EXTRA_DATA,
|
||||
timestamp: fromUnix 1501851927,
|
||||
stateRoot: "9d354f9b5ba851a35eced279ef377111387197581429cfcc7f744ef89a30b5d4".toDigest)
|
||||
let genesisState = {"fundedAddr": FundedAddress(balance: initialBalance.int256, nonce: 0, code: "")}.toTable()
|
||||
result = fromGenesis(
|
||||
result,
|
||||
newBaseChainDB(newMemoryDB()),
|
||||
genesisParams,
|
||||
genesisState)
|
||||
result.fundedAddress = fundedAddr
|
||||
result.fundedAddressInitialBalance = initialBalance
|
||||
result.fundedAddressPrivateKey = privateKey
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import unittest, strutils, sequtils,
|
||||
../nimbus/opcode_values, ../nimbus/vm/code_stream
|
||||
../nimbus/vm/interpreter
|
||||
|
||||
suite "parse bytecode":
|
||||
test "accepts bytes":
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
# * 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 unittest, macros, strformat, strutils, sequtils,
|
||||
import unittest, macros, strformat,
|
||||
stint,
|
||||
../nimbus/[constants, opcode_values, errors, logging, vm_types, vm/gas_meter]
|
||||
../nimbus/[vm_types, errors, logging, vm/interpreter]
|
||||
|
||||
# TODO: quicktest
|
||||
# PS: parametrize can be easily immitated, but still quicktests would be even more useful
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
import
|
||||
os, macros, json, strformat, strutils, parseutils, ospaths, tables,
|
||||
stint, byteutils, eth_common, eth_keys,
|
||||
../nimbus/utils/[hexadecimal, address, padding],
|
||||
../nimbus/[chain, vm_state, constants],
|
||||
../nimbus/db/[db_chain, state_db], ../nimbus/vm/forks/f20150730_frontier/frontier_vm,
|
||||
../nimbus/utils/[address, padding],
|
||||
../nimbus/[vm_state, constants],
|
||||
../nimbus/db/[db_chain, state_db],
|
||||
../nimbus/vm/base, ../nimbus/transaction
|
||||
|
||||
type
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
# * 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 unittest, macros, strformat, strutils, sequtils,
|
||||
import unittest, sequtils,
|
||||
stint,
|
||||
../nimbus/[constants, opcode_values, errors, vm/memory]
|
||||
../nimbus/[constants, errors, vm/memory]
|
||||
|
||||
proc memory32: Memory =
|
||||
result = newMemory()
|
||||
|
|
|
@ -7,14 +7,13 @@
|
|||
|
||||
import
|
||||
unittest, stint, tables, parseutils,
|
||||
../nimbus/[constants, vm_types, errors, logging],
|
||||
../nimbus/[chain, vm_state, computation, opcode, opcode_table],
|
||||
../nimbus/[utils/header, utils/padding],
|
||||
../nimbus/vm/[gas_meter, message, code_stream, stack],
|
||||
../nimbus/vm/forks/vm_forks,
|
||||
../nimbus/[constants, vm_types, logging],
|
||||
../nimbus/vm/interpreter,
|
||||
../nimbus/utils/header,
|
||||
../nimbus/db/[db_chain, state_db, backends/memory_backend],
|
||||
test_helpers
|
||||
./test_helpers
|
||||
|
||||
from eth_common import GasInt
|
||||
|
||||
proc testCode(code: string, initialGas: GasInt, blockNum: UInt256): BaseComputation =
|
||||
let header = BlockHeader(blockNumber: blockNum)
|
||||
|
|
|
@ -5,9 +5,8 @@
|
|||
# * 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 unittest, macros, strformat, strutils, sequtils,
|
||||
stint,
|
||||
../nimbus/[constants, opcode_values, errors, utils_numeric, vm/stack, utils/bytes, utils/padding]
|
||||
import unittest, stint,
|
||||
../nimbus/[constants, errors, vm/interpreter, utils/bytes]
|
||||
|
||||
|
||||
template testPush(value: untyped, expected: untyped): untyped =
|
||||
|
@ -36,9 +35,6 @@ suite "stack":
|
|||
expect(FullStack):
|
||||
stack.push(1025)
|
||||
|
||||
|
||||
|
||||
|
||||
test "dup does not allow stack to exceed 1024":
|
||||
var stack = newStack()
|
||||
stack.push(1.u256)
|
||||
|
|
|
@ -1,43 +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
|
||||
unittest, stint, eth_common,
|
||||
./test_helpers, ./fixtures,
|
||||
../nimbus/[db/backends/memory_backend, db/state_db, chain, constants, utils/hexadecimal, vm_state],
|
||||
../nimbus/[vm/base, computation]
|
||||
|
||||
import typetraits
|
||||
|
||||
suite "VM":
|
||||
test "Apply transaction with no validation":
|
||||
var
|
||||
chain = chainWithoutBlockValidation()
|
||||
vm = chain.getVM()
|
||||
# txIdx = len(vm.`block`.transactions) # Can't take len of a runtime field
|
||||
let
|
||||
recipient = parseAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c")
|
||||
amount = 100.u256
|
||||
ethaddr_from = chain.fundedAddress
|
||||
tx = newTransaction(vm, ethaddr_from, recipient, amount, chain.fundedAddressPrivateKey)
|
||||
# (computation, _) = vm.applyTransaction(tx)
|
||||
# accessLogs = computation.vmState.accessLogs
|
||||
|
||||
# check(not computation.isError)
|
||||
|
||||
let
|
||||
# txGas = tx.gasPrice * constants.GAS_TX
|
||||
state_db = vm.state.readOnlyStateDB
|
||||
b = vm.`block`
|
||||
|
||||
echo state_db.getBalance(ethaddr_from).type.name
|
||||
|
||||
# check:
|
||||
# state_db.getBalance(ethaddr_from) == chain.fundedAddressInitialBalance - amount - txGas # TODO: this really should be i256
|
||||
# state_db.getBalance(recipient) == amount
|
||||
# b.transactions[txIdx] == tx
|
||||
# b.header.gasUsed == constants.GAS_TX
|
|
@ -9,14 +9,12 @@ import
|
|||
unittest, strformat, strutils, sequtils, tables, stint, json, ospaths, times,
|
||||
./test_helpers,
|
||||
../nimbus/[constants, errors, logging],
|
||||
../nimbus/[chain, vm_state, computation, opcode, vm_types],
|
||||
../nimbus/[vm_state, vm_types],
|
||||
../nimbus/utils/[header, padding],
|
||||
../nimbus/vm/[gas_meter, message, code_stream, stack],
|
||||
../nimbus/vm/forks/vm_forks, ../nimbus/db/[db_chain, state_db, backends/memory_backend],
|
||||
../nimbus/vm/interpreter,
|
||||
../nimbus/db/[db_chain, state_db, backends/memory_backend],
|
||||
eth_common
|
||||
|
||||
from ../nimbus/opcode_table import OpLogic
|
||||
|
||||
proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus)
|
||||
|
||||
suite "vm json tests":
|
||||
|
@ -47,7 +45,7 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) =
|
|||
let message = newMessage(
|
||||
to = fexec{"address"}.getStr.parseAddress,
|
||||
sender = fexec{"caller"}.getStr.parseAddress,
|
||||
value = fexec{"value"}.getHexadecimalInt.u256,
|
||||
value = cast[uint](fexec{"value"}.getHexadecimalInt).u256, # Cast workaround for negative value
|
||||
data = fexec{"data"}.getStr.mapIt(it.byte),
|
||||
code = code,
|
||||
gas = fexec{"gas"}.getHexadecimalInt,
|
||||
|
|
Loading…
Reference in New Issue