Hash256/EthAddrres refactoring
This commit is contained in:
parent
6473610574
commit
8bdf09683b
|
@ -1,2 +1,17 @@
|
|||
# Ignore all files without extensions (unix executable files)
|
||||
*
|
||||
!*.*
|
||||
!*/
|
||||
!LICENSE*
|
||||
|
||||
nimcache/
|
||||
|
||||
# Executables shall be put in an ignored build/ directory
|
||||
# Ignore dynamic, static libs and libtool archive files
|
||||
build/
|
||||
*.so
|
||||
*.dylib
|
||||
*.a
|
||||
*.la
|
||||
*.exe
|
||||
*.dll
|
||||
|
|
|
@ -11,6 +11,7 @@ requires "nim >= 0.18.1",
|
|||
"nimcrypto",
|
||||
"rlp",
|
||||
"stint",
|
||||
"https://github.com/status-im/nim-eth-common",
|
||||
"https://github.com/status-im/nim-eth-p2p",
|
||||
"https://github.com/status-im/nim-eth-keyfile"
|
||||
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
constants, errors, stint, rlp
|
||||
constants, errors, stint, rlp, eth_common
|
||||
|
||||
type
|
||||
Account* = ref object
|
||||
nonce*: UInt256
|
||||
balance*: UInt256
|
||||
storageRoot*: string
|
||||
codeHash*: string
|
||||
storageRoot*: Hash256
|
||||
codeHash*: Hash256
|
||||
|
||||
rlpFields Account, nonce, balance
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
tables, stint,
|
||||
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
|
||||
|
||||
|
@ -23,21 +23,21 @@ type
|
|||
importBlock*: bool
|
||||
validateBlock*: bool
|
||||
db*: BaseChainDB
|
||||
fundedAddress*: string
|
||||
fundedAddress*: EthAddress
|
||||
fundedAddressInitialBalance*: int
|
||||
fundedAddressPrivateKey*: string
|
||||
fundedAddressPrivateKey*: PrivateKey
|
||||
|
||||
GenesisParams* = ref object
|
||||
blockNumber*: UInt256
|
||||
blockNumber*: BlockNumber
|
||||
difficulty*: UInt256
|
||||
gasLimit*: UInt256
|
||||
parentHash*: string
|
||||
coinbase*: string
|
||||
gasLimit*: GasInt
|
||||
parentHash*: Hash256
|
||||
coinbase*: EthAddress
|
||||
nonce*: string
|
||||
mixHash*: string
|
||||
mixHash*: Hash256
|
||||
extraData*: string
|
||||
timestamp*: EthTime
|
||||
stateRoot*: string
|
||||
stateRoot*: Hash256
|
||||
|
||||
FundedAddress* = ref object
|
||||
balance*: Int256
|
||||
|
@ -75,7 +75,7 @@ proc fromGenesis*(
|
|||
# chainDB.persistBlockToDB(result.getBlock)
|
||||
|
||||
|
||||
proc getVMClassForBlockNumber*(chain: Chain, blockNumber: UInt256): VMKind =
|
||||
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`
|
||||
|
@ -91,17 +91,16 @@ proc getVMClassForBlockNumber*(chain: Chain, blockNumber: UInt256): VMKind =
|
|||
|
||||
# TODO - Refactoring: superseded by newNimbusVM for the time being #https://github.com/status-im/nimbus/pull/37
|
||||
|
||||
proc getVM*(chain: Chain, header: BlockHeader = nil): VM =
|
||||
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 header = if header.isNil: chain.header
|
||||
else: header
|
||||
|
||||
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)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
strformat, strutils, sequtils, tables, macros, stint, terminal, math,
|
||||
strformat, strutils, sequtils, tables, macros, stint, terminal, math, eth_common, byteutils,
|
||||
constants, errors, utils/hexadecimal, utils_numeric, validation, vm_state, logging, opcode_values, vm_types,
|
||||
vm / [code_stream, gas_meter, memory, message, stack],
|
||||
|
||||
|
@ -37,7 +37,7 @@ method newBaseComputation*(vmState: FrontierVMState, message: Message): BaseComp
|
|||
result.stack = newStack()
|
||||
result.gasMeter = newGasMeter(message.gas)
|
||||
result.children = @[]
|
||||
result.accountsToDelete = initTable[string, string]()
|
||||
result.accountsToDelete = initTable[EthAddress, EthAddress]()
|
||||
result.logEntries = @[]
|
||||
result.code = newCodeStreamFromUnescaped(message.code) # TODO: what is the best repr
|
||||
result.rawOutput = "0x"
|
||||
|
@ -51,7 +51,7 @@ method newBaseComputation*(vmState: TangerineVMState, message: Message): BaseCom
|
|||
result.stack = newStack()
|
||||
result.gasMeter = newGasMeter(message.gas)
|
||||
result.children = @[]
|
||||
result.accountsToDelete = initTable[string, string]()
|
||||
result.accountsToDelete = initTable[EthAddress, EthAddress]()
|
||||
result.logEntries = @[]
|
||||
result.code = newCodeStreamFromUnescaped(message.code) # TODO: what is the best repr
|
||||
result.rawOutput = "0x"
|
||||
|
@ -87,7 +87,7 @@ method shouldEraseReturnData*(c: BaseComputation): bool =
|
|||
method prepareChildMessage*(
|
||||
c: var BaseComputation,
|
||||
gas: GasInt,
|
||||
to: string,
|
||||
to: EthAddress,
|
||||
value: UInt256,
|
||||
data: seq[byte],
|
||||
code: string,
|
||||
|
@ -169,7 +169,7 @@ method applyChildBaseComputation*(c: var BaseComputation, childMsg: Message): Ba
|
|||
c.addChildBaseComputation(childBaseComputation)
|
||||
result = childBaseComputation
|
||||
|
||||
method registerAccountForDeletion*(c: var BaseComputation, beneficiary: string) =
|
||||
method registerAccountForDeletion*(c: var BaseComputation, beneficiary: EthAddress) =
|
||||
validateCanonicalAddress(beneficiary, title="self destruct beneficiary address")
|
||||
|
||||
if c.msg.storageAddress in c.accountsToDelete:
|
||||
|
@ -178,7 +178,7 @@ method registerAccountForDeletion*(c: var BaseComputation, beneficiary: string)
|
|||
"registered for deletion multiple times")
|
||||
c.accountsToDelete[c.msg.storageAddress] = beneficiary
|
||||
|
||||
method addLogEntry*(c: var BaseComputation, account: string, topics: seq[UInt256], data: string) =
|
||||
method addLogEntry*(c: var BaseComputation, account: EthAddress, topics: seq[UInt256], data: string) =
|
||||
validateCanonicalAddress(account, title="log entry address")
|
||||
c.logEntries.add((account, topics, data))
|
||||
|
||||
|
@ -229,8 +229,8 @@ template inComputation*(c: untyped, handler: untyped): untyped =
|
|||
`c`.logger.debug(
|
||||
"COMPUTATION STARTING: gas: $1 | from: $2 | to: $3 | value: $4 | depth: $5 | static: $6" % [
|
||||
$`c`.msg.gas,
|
||||
$encodeHex(`c`.msg.sender),
|
||||
$encodeHex(`c`.msg.to),
|
||||
toHex(`c`.msg.sender),
|
||||
toHex(`c`.msg.to),
|
||||
$`c`.msg.value,
|
||||
$`c`.msg.depth,
|
||||
if c.msg.isStatic: "y" else: "n"])
|
||||
|
@ -238,8 +238,8 @@ template inComputation*(c: untyped, handler: untyped): untyped =
|
|||
`handler`
|
||||
c.logger.debug(
|
||||
"COMPUTATION SUCCESS: from: $1 | to: $2 | value: $3 | depth: $4 | static: $5 | gas-used: $6 | gas-remaining: $7" % [
|
||||
$encodeHex(c.msg.sender),
|
||||
$encodeHex(c.msg.to),
|
||||
toHex(c.msg.sender),
|
||||
toHex(c.msg.to),
|
||||
$c.msg.value,
|
||||
$c.msg.depth,
|
||||
if c.msg.isStatic: "y" else: "n",
|
||||
|
@ -249,8 +249,8 @@ template inComputation*(c: untyped, handler: untyped): untyped =
|
|||
`c`.logger.debug(
|
||||
"COMPUTATION ERROR: gas: $1 | from: $2 | to: $3 | value: $4 | depth: $5 | static: $6 | error: $7" % [
|
||||
$`c`.msg.gas,
|
||||
$encodeHex(`c`.msg.sender),
|
||||
$encodeHex(`c`.msg.to),
|
||||
toHex(`c`.msg.sender),
|
||||
toHex(`c`.msg.to),
|
||||
$c.msg.value,
|
||||
$c.msg.depth,
|
||||
if c.msg.isStatic: "y" else: "n",
|
||||
|
|
|
@ -1,17 +1,6 @@
|
|||
|
||||
import
|
||||
stint, math, strutils, tables, utils/padding, rlp, times
|
||||
|
||||
# rlpFields UInt256, table
|
||||
|
||||
type
|
||||
TypeHint* {.pure.} = enum UInt256, Bytes, Any # TODO Bytes is in conflict with nim-rlp Bytes = seq[byte]
|
||||
EthTime* = Time
|
||||
|
||||
|
||||
#Bytes* = seq[byte]
|
||||
|
||||
# Int256* = BigInt #distinct int # TODO
|
||||
stint, math, strutils, utils/padding, eth_common
|
||||
|
||||
proc int256*(i: int): Int256 =
|
||||
i.i256
|
||||
|
@ -97,12 +86,6 @@ proc `mod`*(a: UInt256, b: int): UInt256 =
|
|||
proc `div`*(a: UInt256, b: int): UInt256 =
|
||||
a div b.u256
|
||||
|
||||
proc setXLen[T](s: var seq[T]; newlen: Natural) =
|
||||
if s.isNil:
|
||||
s = newSeq[T](newlen)
|
||||
else:
|
||||
s.setLen(newlen)
|
||||
|
||||
template mapOp(op: untyped): untyped =
|
||||
proc `op`*(left: Int256, right: int): Int256 =
|
||||
result = left.i256
|
||||
|
@ -116,6 +99,8 @@ mapOp(`and`)
|
|||
mapOp(`or`)
|
||||
mapOp(`xor`)
|
||||
|
||||
proc default(t: typedesc): t = discard
|
||||
|
||||
# constants
|
||||
|
||||
let
|
||||
|
@ -124,9 +109,9 @@ let
|
|||
NULLBYTE* = "\x00"
|
||||
EMPTYWORD* = repeat(NULLBYTE, 32)
|
||||
UINT160CEILING*: UInt256 = 2.u256 ^ 160
|
||||
CREATE_CONTRACT_ADDRESS* = ""
|
||||
ZERO_ADDRESS* = repeat("\x00", 20)
|
||||
ZERO_HASH32* = repeat("\x00", 20)
|
||||
ZERO_ADDRESS* = default(EthAddress)
|
||||
CREATE_CONTRACT_ADDRESS* = ZERO_ADDRESS
|
||||
ZERO_HASH32* = Hash256()
|
||||
STACK_DEPTH_LIMIT* = 1024
|
||||
|
||||
# GAS_NULL* = 0.u256
|
||||
|
@ -165,7 +150,7 @@ let
|
|||
GAS_TX_CREATE* = 32_000.u256
|
||||
GAS_TX_DATA_ZERO* = 4.u256
|
||||
GAS_TX_DATA_NON_ZERO* = 68.u256
|
||||
GAS_TX* = 21_000.u256
|
||||
GAS_TX* = 21_000
|
||||
GAS_LOG* = 375.u256
|
||||
GAS_LOG_DATA* = 8
|
||||
GAS_LOG_TOPIC* = 375
|
||||
|
@ -186,11 +171,11 @@ let
|
|||
GAS_ECMUL* = 40_000.u256
|
||||
GAS_ECPAIRING_BASE* = 100_000.u256
|
||||
GAS_ECPAIRING_PER_POINT* = 80_000.u256
|
||||
GAS_LIMIT_EMA_DENOMINATOR* = 1_024.u256
|
||||
GAS_LIMIT_ADJUSTMENT_FACTOR* = 1_024.u256
|
||||
GAS_LIMIT_MAXIMUM* = high(int64)
|
||||
GAS_LIMIT_USAGE_ADJUSTMENT_NUMERATOR* = 3.u256
|
||||
GAS_LIMIT_USAGE_ADJUSTMENT_DENOMINATOR* = 2.u256
|
||||
GAS_LIMIT_EMA_DENOMINATOR* = 1_024
|
||||
GAS_LIMIT_ADJUSTMENT_FACTOR* = 1_024
|
||||
GAS_LIMIT_MAXIMUM* = high(GasInt)
|
||||
GAS_LIMIT_USAGE_ADJUSTMENT_NUMERATOR* = 3
|
||||
GAS_LIMIT_USAGE_ADJUSTMENT_DENOMINATOR* = 2
|
||||
|
||||
DIFFICULTY_ADJUSTMENT_DENOMINATOR* = 2_048.u256
|
||||
DIFFICULTY_MINIMUM* = 131_072.u256
|
||||
|
@ -214,20 +199,20 @@ let
|
|||
SECPK1_Gy* = 0.u256
|
||||
SECPK1_G* = (SECPK1Gx, SECPK1Gy)
|
||||
|
||||
EMPTY_UNCLE_HASH* = "\x1d\xccM\xe8\xde\xc7]z\xab\x85\xb5g\xb6\xcc\xd4\x1a\xd3\x12E\x1b\x94\x8at\x13\xf0\xa1B\xfd@\xd4\x93G"
|
||||
EMPTY_UNCLE_HASH* = "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347".toDigest
|
||||
|
||||
GENESIS_BLOCK_NUMBER* = 0.u256
|
||||
GENESIS_DIFFICULTY* = 131_072.u256
|
||||
GENESIS_GAS_LIMIT* = 3_141_592.u256
|
||||
GENESIS_GAS_LIMIT* = 3_141_592
|
||||
GENESIS_PARENT_HASH* = ZERO_HASH32
|
||||
GENESIS_COINBASE* = ZERO_ADDRESS
|
||||
GENESIS_NONCE* = "\x00\x00\x00\x00\x00\x00\x00B"
|
||||
GENESIS_MIX_HASH* = ZERO_HASH32
|
||||
GENESIS_EXTRA_DATA* = ""
|
||||
GAS_LIMIT_MINIMUM* = 5000.u256
|
||||
GAS_LIMIT_MINIMUM* = 5000
|
||||
|
||||
EMPTYSHA3 = "\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p"
|
||||
BLANK_ROOT_HASH* = "V\xe8\x1f\x17\x1b\xccU\xa6\xff\x83E\xe6\x92\xc0\xf8n[H\xe0\x1b\x99l\xad\xc0\x01b/\xb5\xe3c\xb4!"
|
||||
BLANK_ROOT_HASH* = "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421".toDigest()
|
||||
|
||||
GAS_MOD_EXP_QUADRATIC_DENOMINATOR* = 20.u256
|
||||
|
||||
|
|
|
@ -5,26 +5,54 @@
|
|||
# * 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
|
||||
import tables, hashes, eth_common
|
||||
|
||||
type
|
||||
MemoryDB* = ref object
|
||||
kvStore*: Table[string, Int256]
|
||||
DBKeyKind = enum
|
||||
genericHash
|
||||
blockNumberToHash
|
||||
blockHashToScore
|
||||
|
||||
proc newMemoryDB*(kvStore: Table[string, Int256]): MemoryDB =
|
||||
DbKey* = object
|
||||
case kind: DBKeyKind
|
||||
of genericHash, blockHashToScore:
|
||||
h: Hash256
|
||||
of blockNumberToHash:
|
||||
u: BlockNumber
|
||||
|
||||
MemoryDB* = ref object
|
||||
kvStore*: Table[DbKey, seq[byte]]
|
||||
|
||||
proc genericHashKey*(h: Hash256): DbKey {.inline.} = DbKey(kind: genericHash, h: h)
|
||||
proc blockHashToScoreKey*(h: Hash256): DbKey {.inline.} = DbKey(kind: blockHashToScore, h: h)
|
||||
proc blockNumberToHashKey*(u: BlockNumber): DbKey {.inline.} = DbKey(kind: blockNumberToHash, u: u)
|
||||
|
||||
proc hash(k: DbKey): Hash =
|
||||
result = result !& hash(k.kind)
|
||||
case k.kind
|
||||
of genericHash, blockHashToScore:
|
||||
result = result !& hash(k.h)
|
||||
of blockNumberToHash:
|
||||
result = result !& hashData(unsafeAddr k.u, sizeof(k.u))
|
||||
result = result
|
||||
|
||||
proc `==`(a, b: DbKey): bool {.inline.} =
|
||||
equalMem(unsafeAddr a, unsafeAddr b, sizeof(a))
|
||||
|
||||
proc newMemoryDB*(kvStore: Table[DbKey, seq[byte]]): MemoryDB =
|
||||
MemoryDB(kvStore: kvStore)
|
||||
|
||||
proc newMemoryDB*: MemoryDB =
|
||||
MemoryDB(kvStore: initTable[string, Int256]())
|
||||
MemoryDB(kvStore: initTable[DbKey, seq[byte]]())
|
||||
|
||||
proc get*(db: MemoryDB, key: string): Int256 =
|
||||
proc get*(db: MemoryDB, key: DbKey): seq[byte] =
|
||||
db.kvStore[key]
|
||||
|
||||
proc set*(db: var MemoryDB, key: string, value: Int256) =
|
||||
proc set*(db: var MemoryDB, key: DbKey, value: seq[byte]) =
|
||||
db.kvStore[key] = value
|
||||
|
||||
proc exists*(db: MemoryDB, key: string): bool =
|
||||
proc contains*(db: MemoryDB, key: DbKey): bool =
|
||||
db.kvStore.hasKey(key)
|
||||
|
||||
proc delete*(db: var MemoryDB, key: string) =
|
||||
proc delete*(db: var MemoryDB, key: DbKey) =
|
||||
db.kvStore.del(key)
|
||||
|
|
|
@ -5,39 +5,60 @@
|
|||
# * 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, tables, stint, state_db, backends / memory_backend
|
||||
import strformat, tables, stint, rlp, ranges, state_db, backends / memory_backend,
|
||||
../errors, ../utils/header, ../constants, eth_common, byteutils
|
||||
|
||||
type
|
||||
BaseChainDB* = ref object
|
||||
db*: MemoryDB
|
||||
# TODO db*: JournalDB
|
||||
|
||||
KeyType = enum
|
||||
blockNumberToHash
|
||||
blockHashToScore
|
||||
|
||||
proc newBaseChainDB*(db: MemoryDB): BaseChainDB =
|
||||
new(result)
|
||||
result.db = db
|
||||
|
||||
proc exists*(self: BaseChainDB; key: string): bool =
|
||||
return self.db.exists(key)
|
||||
proc contains*(self: BaseChainDB; key: Hash256): bool =
|
||||
return self.db.contains(genericHashKey(key))
|
||||
|
||||
proc `$`*(db: BaseChainDB): string =
|
||||
result = "BaseChainDB"
|
||||
|
||||
proc getBlockHeaderByHash*(self: BaseChainDB; blockHash: Hash256): BlockHeader =
|
||||
## Returns the requested block header as specified by block hash.
|
||||
##
|
||||
## Raises BlockNotFound if it is not present in the db.
|
||||
var blk: seq[byte]
|
||||
try:
|
||||
blk = self.db.get(genericHashKey(blockHash))
|
||||
except KeyError:
|
||||
raise newException(BlockNotFound, "No block with hash " & blockHash.data.toHex)
|
||||
let rng = blk.toRange
|
||||
return decode(rng, BlockHeader)
|
||||
|
||||
# proc getCanonicalHead*(self: BaseChainDB): BlockHeader =
|
||||
# if notself.exists(CANONICALHEADHASHDBKEY):
|
||||
# raise newException(CanonicalHeadNotFound,
|
||||
# "No canonical head set for this chain")
|
||||
# return self.getBlockHeaderByHash(self.db.get(CANONICALHEADHASHDBKEY))
|
||||
|
||||
# proc getCanonicalBlockHeaderByNumber*(self: BaseChainDB; blockNumber: int): BlockHeader =
|
||||
# ## Returns the block header with the given number in the canonical chain.
|
||||
# ##
|
||||
# ## Raises BlockNotFound if there's no block header with the given number in the
|
||||
# ## canonical chain.
|
||||
# validateUint256(blockNumber)
|
||||
# return self.getBlockHeaderByHash(self.lookupBlockHash(blockNumber))
|
||||
proc lookupBlockHash*(self: BaseChainDB; n: BlockNumber): Hash256 {.inline.} =
|
||||
## Return the block hash for the given block number.
|
||||
let numberToHashKey = blockNumberToHashKey(n)
|
||||
result = rlp.decode(self.db.get(numberToHashKey).toRange, Hash256)
|
||||
|
||||
# proc getScore*(self: BaseChainDB; blockHash: cstring): int =
|
||||
# return rlp.decode(self.db.get(makeBlockHashToScoreLookupKey(blockHash)))
|
||||
proc getCanonicalBlockHeaderByNumber*(self: BaseChainDB; n: BlockNumber): BlockHeader =
|
||||
## Returns the block header with the given number in the canonical chain.
|
||||
##
|
||||
## Raises BlockNotFound if there's no block header with the given number in the
|
||||
## canonical chain.
|
||||
self.getBlockHeaderByHash(self.lookupBlockHash(n))
|
||||
|
||||
proc getScore*(self: BaseChainDB; blockHash: Hash256): int =
|
||||
rlp.decode(self.db.get(blockHashToScoreKey(blockHash)).toRange, int)
|
||||
|
||||
# proc setAsCanonicalChainHead*(self: BaseChainDB; header: BlockHeader): void =
|
||||
# ## Sets the header as the canonical chain HEAD.
|
||||
|
@ -50,43 +71,23 @@ proc `$`*(db: BaseChainDB): string =
|
|||
# header.hash))
|
||||
# self.db.set(CANONICALHEADHASHDBKEY, header.hash)
|
||||
|
||||
# iterator findCommonAncestor*(self: BaseChainDB; header: BlockHeader): BlockHeader =
|
||||
# ## Returns the chain leading up from the given header until the first ancestor it has in
|
||||
# ## common with our canonical chain.
|
||||
# var h = header
|
||||
# while true:
|
||||
# yield h
|
||||
# if h.parentHash == GENESISPARENTHASH:
|
||||
# break
|
||||
# try:
|
||||
# var orig = self.getCanonicalBlockHeaderByNumber(h.blockNumber)
|
||||
# except KeyError:
|
||||
# nil
|
||||
# h = self.getBlockHeaderByHash(h.parentHash)
|
||||
iterator findCommonAncestor*(self: BaseChainDB; header: BlockHeader): BlockHeader =
|
||||
## Returns the chain leading up from the given header until the first ancestor it has in
|
||||
## common with our canonical chain.
|
||||
var h = header
|
||||
while true:
|
||||
yield h
|
||||
if h.parentHash == GENESIS_PARENT_HASH:
|
||||
break
|
||||
try:
|
||||
var orig = self.getCanonicalBlockHeaderByNumber(h.blockNumber)
|
||||
except KeyError:
|
||||
discard # TODO: break??
|
||||
h = self.getBlockHeaderByHash(h.parentHash)
|
||||
|
||||
# proc getBlockHeaderByHash*(self: BaseChainDB; blockHash: cstring): BlockHeader =
|
||||
# ## Returns the requested block header as specified by block hash.
|
||||
# ##
|
||||
# ## Raises BlockNotFound if it is not present in the db.
|
||||
# validateWord(blockHash)
|
||||
# try:
|
||||
# var block = self.db.get(blockHash)
|
||||
# except KeyError:
|
||||
# raise newException(BlockNotFound, "No block with hash {0} found".format(
|
||||
# encodeHex(blockHash)))
|
||||
# return rlp.decode(block)
|
||||
|
||||
# proc headerExists*(self: BaseChainDB; blockHash: cstring): bool =
|
||||
# ## Returns True if the header with the given block hash is in our DB.
|
||||
# return self.db.exists(blockHash)
|
||||
|
||||
# proc lookupBlockHash*(self: BaseChainDB; blockNumber: int): cstring =
|
||||
# ## Return the block hash for the given block number.
|
||||
# validateUint256(blockNumber)
|
||||
# var
|
||||
# numberToHashKey = makeBlockNumberToHashLookupKey(blockNumber)
|
||||
# blockHash = rlp.decode(self.db.get(numberToHashKey))
|
||||
# return blockHash
|
||||
proc headerExists*(self: BaseChainDB; blockHash: Hash256): bool =
|
||||
## Returns True if the header with the given block hash is in our DB.
|
||||
self.contains(blockHash)
|
||||
|
||||
# iterator getReceipts*(self: BaseChainDB; header: BlockHeader; receiptClass: typedesc): Receipt =
|
||||
# var receiptDb = HexaryTrie()
|
||||
|
@ -159,7 +160,7 @@ proc `$`*(db: BaseChainDB): string =
|
|||
# proc clear*(self: BaseChainDB): void =
|
||||
# self.db.clear()
|
||||
|
||||
method getStateDb*(self: BaseChainDB; stateRoot: string; readOnly: bool = false): AccountStateDB =
|
||||
method getStateDb*(self: BaseChainDB; stateRoot: Hash256; readOnly: bool = false): AccountStateDB =
|
||||
# TODO
|
||||
result = newAccountStateDB(initTable[string, string]())
|
||||
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
strformat, tables,
|
||||
strformat, tables, eth_common,
|
||||
../constants, ../errors, ../validation, ../account, ../logging, ../utils_numeric, .. / utils / [padding, bytes, keccak],
|
||||
stint, rlp
|
||||
|
||||
type
|
||||
AccountStateDB* = ref object
|
||||
db*: Table[string, BytesRange]
|
||||
rootHash*: string # TODO trie
|
||||
rootHash*: Hash256 # TODO trie
|
||||
|
||||
proc newAccountStateDB*(db: Table[string, string], readOnly: bool = false): AccountStateDB =
|
||||
result = AccountStateDB(db: initTable[string, BytesRange]())
|
||||
|
@ -21,7 +21,7 @@ proc newAccountStateDB*(db: Table[string, string], readOnly: bool = false): Acco
|
|||
proc logger*(db: AccountStateDB): Logger =
|
||||
logging.getLogger("db.State")
|
||||
|
||||
proc getAccount(db: AccountStateDB, address: string): Account =
|
||||
proc getAccount(db: AccountStateDB, address: EthAddress): Account =
|
||||
# let rlpAccount = db.trie[address]
|
||||
# if not rlpAccount.isNil:
|
||||
# account = rlp.decode[Account](rlpAccount)
|
||||
|
@ -30,32 +30,32 @@ proc getAccount(db: AccountStateDB, address: string): Account =
|
|||
# account = newAccount()
|
||||
result = newAccount() # TODO
|
||||
|
||||
proc setAccount(db: AccountStateDB, address: string, account: Account) =
|
||||
proc setAccount(db: AccountStateDB, address: EthAddress, account: Account) =
|
||||
# db.trie[address] = rlp.encode[Account](account)
|
||||
discard # TODO
|
||||
|
||||
|
||||
proc getCodeHash*(db: AccountStateDB, address: string): string =
|
||||
proc getCodeHash*(db: AccountStateDB, address: EthAddress): Hash256 =
|
||||
validateCanonicalAddress(address, title="Storage Address")
|
||||
let account = db.getAccount(address)
|
||||
result = account.codeHash
|
||||
|
||||
proc getBalance*(db: AccountStateDB, address: string): UInt256 =
|
||||
proc getBalance*(db: AccountStateDB, address: EthAddress): UInt256 =
|
||||
validateCanonicalAddress(address, title="Storage Address")
|
||||
let account = db.getAccount(address)
|
||||
account.balance
|
||||
|
||||
proc setBalance*(db: var AccountStateDB, address: string, balance: UInt256) =
|
||||
proc setBalance*(db: var AccountStateDB, address: EthAddress, balance: UInt256) =
|
||||
validateCanonicalAddress(address, title="Storage Address")
|
||||
let account = db.getAccount(address)
|
||||
account.balance = balance
|
||||
db.setAccount(address, account)
|
||||
|
||||
proc deltaBalance*(db: var AccountStateDB, address: string, delta: UInt256) =
|
||||
proc deltaBalance*(db: var AccountStateDB, address: EthAddress, delta: UInt256) =
|
||||
db.setBalance(address, db.getBalance(address) + delta)
|
||||
|
||||
|
||||
proc setStorage*(db: var AccountStateDB, address: string, slot: UInt256, value: UInt256) =
|
||||
proc setStorage*(db: var AccountStateDB, address: EthAddress, slot: UInt256, value: UInt256) =
|
||||
#validateGte(value, 0, title="Storage Value")
|
||||
#validateGte(slot, 0, title="Storage Slot")
|
||||
validateCanonicalAddress(address, title="Storage Address")
|
||||
|
@ -76,7 +76,7 @@ proc setStorage*(db: var AccountStateDB, address: string, slot: UInt256, value:
|
|||
# account.storageRoot = storage.rootHash
|
||||
# db.setAccount(address, account)
|
||||
|
||||
proc getStorage*(db: var AccountStateDB, address: string, slot: UInt256): (UInt256, bool) =
|
||||
proc getStorage*(db: var AccountStateDB, address: EthAddress, slot: UInt256): (UInt256, bool) =
|
||||
validateCanonicalAddress(address, title="Storage Address")
|
||||
#validateGte(slot, 0, title="Storage Slot")
|
||||
|
||||
|
@ -97,7 +97,7 @@ proc getStorage*(db: var AccountStateDB, address: string, slot: UInt256): (UInt2
|
|||
else:
|
||||
result = (0.u256, false)
|
||||
|
||||
proc setNonce*(db: var AccountStateDB, address: string, nonce: UInt256) =
|
||||
proc setNonce*(db: var AccountStateDB, address: EthAddress, nonce: UInt256) =
|
||||
validateCanonicalAddress(address, title="Storage Address")
|
||||
#validateGte(nonce, 0, title="Nonce")
|
||||
|
||||
|
@ -106,13 +106,13 @@ proc setNonce*(db: var AccountStateDB, address: string, nonce: UInt256) =
|
|||
|
||||
db.setAccount(address, account)
|
||||
|
||||
proc getNonce*(db: AccountStateDB, address: string): UInt256 =
|
||||
proc getNonce*(db: AccountStateDB, address: EthAddress): UInt256 =
|
||||
validateCanonicalAddress(address, title="Storage Address")
|
||||
|
||||
let account = db.getAccount(address)
|
||||
return account.nonce
|
||||
|
||||
proc setCode*(db: var AccountStateDB, address: string, code: string) =
|
||||
proc setCode*(db: var AccountStateDB, address: EthAddress, code: string) =
|
||||
validateCanonicalAddress(address, title="Storage Address")
|
||||
|
||||
var account = db.getAccount(address)
|
||||
|
@ -121,7 +121,7 @@ proc setCode*(db: var AccountStateDB, address: string, code: string) =
|
|||
#db.db[account.codeHash] = code
|
||||
db.setAccount(address, account)
|
||||
|
||||
proc getCode*(db: var AccountStateDB, address: string): string =
|
||||
proc getCode*(db: var AccountStateDB, address: EthAddress): string =
|
||||
let codeHash = db.getCodeHash(address)
|
||||
#if db.db.hasKey(codeHash):
|
||||
# result = db.db[codeHash]
|
||||
|
|
|
@ -35,5 +35,4 @@ proc difficulty*(computation) =
|
|||
stack.push(vmState.difficulty)
|
||||
|
||||
proc gaslimit*(computation) =
|
||||
stack.push(vmState.gasLimit)
|
||||
|
||||
stack.push(vmState.gasLimit.u256)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
strformat,
|
||||
strformat, eth_common,
|
||||
../constants, ../vm_types, ../errors, ../computation, ../opcode, ../opcode_values, ../logging,
|
||||
.. / vm / [stack, memory, gas_meter, message],
|
||||
.. / utils / [address, bytes],
|
||||
|
@ -39,16 +39,16 @@ type
|
|||
using
|
||||
computation: var BaseComputation
|
||||
|
||||
method msgExtraGas*(call: BaseCall, computation; gas: GasInt, to: string, value: UInt256): GasInt {.base.} =
|
||||
method msgExtraGas*(call: BaseCall, computation; gas: GasInt, to: EthAddress, value: UInt256): GasInt {.base.} =
|
||||
raise newException(NotImplementedError, "Must be implemented by subclasses")
|
||||
|
||||
method msgGas*(call: BaseCall, computation; gas: GasInt, to: string, value: UInt256): (GasInt, GasInt) {.base.} =
|
||||
method msgGas*(call: BaseCall, computation; gas: GasInt, to: EthAddress, value: UInt256): (GasInt, GasInt) {.base.} =
|
||||
let extraGas = call.msgExtraGas(computation, gas, to, value)
|
||||
let totalFee = gas + extraGas
|
||||
let childMsgGas = gas + (if value != 0: GAS_CALL_STIPEND else: 0)
|
||||
(childMsgGas, totalFee)
|
||||
|
||||
method callParams*(call: BaseCall, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) {.base.} =
|
||||
method callParams*(call: BaseCall, computation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, UInt256, UInt256, UInt256, UInt256, bool, bool) {.base.} =
|
||||
raise newException(NotImplementedError, "Must be implemented subclasses")
|
||||
|
||||
method runLogic*(call: BaseCall, computation) =
|
||||
|
@ -108,7 +108,7 @@ method runLogic*(call: BaseCall, computation) =
|
|||
MessageOptions(
|
||||
shouldTransferValue: shouldTransferValue,
|
||||
isStatic: isStatic))
|
||||
if not sender.isNil:
|
||||
if sender != ZERO_ADDRESS:
|
||||
childMsg.sender = sender
|
||||
# let childComputation = computation.applyChildComputation(childMsg)
|
||||
# TODO
|
||||
|
@ -121,12 +121,11 @@ method runLogic*(call: BaseCall, computation) =
|
|||
let actualOutputSize = min(memOutLen, childComputation.output.len)
|
||||
computation.memory.write(
|
||||
memOutPos,
|
||||
actualOutputSize,
|
||||
childComputation.output.toBytes[0 ..< actualOutputSize])
|
||||
if not childComputation.shouldBurnGas:
|
||||
computation.gasMeter.returnGas(childComputation.gasMeter.gasRemaining)
|
||||
|
||||
method msgExtraGas(call: Call, computation; gas: GasInt, to: string, value: UInt256): GasInt =
|
||||
method msgExtraGas(call: Call, computation; gas: GasInt, to: EthAddress, value: UInt256): GasInt =
|
||||
# TODO: db
|
||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||
# let accountExists = db.accountExists(to)
|
||||
|
@ -136,9 +135,9 @@ method msgExtraGas(call: Call, computation; gas: GasInt, to: string, value: UInt
|
|||
let createGasFee = if not accountExists: GAS_NEW_ACCOUNT else: 0
|
||||
transferGasFee + createGasFee
|
||||
|
||||
method callParams(call: CallCode, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
method callParams(call: CallCode, computation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
let gas = computation.stack.popInt()
|
||||
let to = forceBytesToAddress(computation.stack.popString)
|
||||
let to = computation.stack.popAddress()
|
||||
|
||||
let (value,
|
||||
memoryInputStartPosition, memoryInputSize,
|
||||
|
@ -147,8 +146,8 @@ method callParams(call: CallCode, computation): (UInt256, UInt256, string, strin
|
|||
result = (gas,
|
||||
value,
|
||||
to,
|
||||
nil, # sender
|
||||
nil, # code_address
|
||||
ZERO_ADDRESS, # sender
|
||||
ZERO_ADDRESS, # code_address
|
||||
memoryInputStartPosition,
|
||||
memoryInputSize,
|
||||
memoryOutputStartPosition,
|
||||
|
@ -156,12 +155,12 @@ method callParams(call: CallCode, computation): (UInt256, UInt256, string, strin
|
|||
true, # should_transfer_value,
|
||||
computation.msg.isStatic)
|
||||
|
||||
method msgExtraGas(call: CallCode, computation; gas: GasInt, to: string, value: UInt256): GasInt =
|
||||
method msgExtraGas(call: CallCode, computation; gas: GasInt, to: EthAddress, value: UInt256): GasInt =
|
||||
if value != 0: GAS_CALL_VALUE else: 0
|
||||
|
||||
method callParams(call: Call, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
method callParams(call: Call, computation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
let gas = computation.stack.popInt()
|
||||
let codeAddress = forceBytesToAddress(computation.stack.popString)
|
||||
let codeAddress = computation.stack.popAddress()
|
||||
|
||||
let (value,
|
||||
memoryInputStartPosition, memoryInputSize,
|
||||
|
@ -182,15 +181,15 @@ method callParams(call: Call, computation): (UInt256, UInt256, string, string, s
|
|||
true, # should_transfer_value,
|
||||
computation.msg.isStatic)
|
||||
|
||||
method msgGas(call: DelegateCall, computation; gas: GasInt, to: string, value: UInt256): (GasInt, GasInt) =
|
||||
method msgGas(call: DelegateCall, computation; gas: GasInt, to: EthAddress, value: UInt256): (GasInt, GasInt) =
|
||||
(gas, gas)
|
||||
|
||||
method msgExtraGas(call: DelegateCall, computation; gas: GasInt, to: string, value: UInt256): GasInt =
|
||||
method msgExtraGas(call: DelegateCall, computation; gas: GasInt, to: EthAddress, value: UInt256): GasInt =
|
||||
0
|
||||
|
||||
method callParams(call: DelegateCall, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
method callParams(call: DelegateCall, computation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
let gas = computation.stack.popInt()
|
||||
let codeAddress = forceBytesToAddress(computation.stack.popString)
|
||||
let codeAddress = computation.stack.popAddress()
|
||||
|
||||
let (memoryInputStartPosition, memoryInputSize,
|
||||
memoryOutputStartPosition, memoryOutputSize) = computation.stack.popInt(4)
|
||||
|
@ -222,19 +221,19 @@ proc computeEIP150MsgGas(computation; gas, extraGas: GasInt, value: UInt256, nam
|
|||
let childMsgGas = gas + (if value != 0: callStipend else: 0)
|
||||
(childMsgGas, totalFee)
|
||||
|
||||
method msgGas(call: CallEIP150, computation; gas: GasInt, to: string, value: UInt256): (GasInt, GasInt) =
|
||||
method msgGas(call: CallEIP150, computation; gas: GasInt, to: EthAddress, value: UInt256): (GasInt, GasInt) =
|
||||
let extraGas = call.msgExtraGas(computation, gas, to, value)
|
||||
computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, GAS_CALL_STIPEND)
|
||||
|
||||
method msgGas(call: CallCodeEIP150, computation; gas: GasInt, to: string, value: UInt256): (GasInt, GasInt) =
|
||||
method msgGas(call: CallCodeEIP150, computation; gas: GasInt, to: EthAddress, value: UInt256): (GasInt, GasInt) =
|
||||
let extraGas = call.msgExtraGas(computation, gas, to, value)
|
||||
computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, GAS_CALL_STIPEND)
|
||||
|
||||
method msgGas(call: DelegateCallEIP150, computation; gas: GasInt, to: string, value: UInt256): (GasInt, GasInt) =
|
||||
method msgGas(call: DelegateCallEIP150, computation; gas: GasInt, to: EthAddress, value: UInt256): (GasInt, GasInt) =
|
||||
let extraGas = call.msgExtraGas(computation, gas, to, value)
|
||||
computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, 0)
|
||||
|
||||
proc msgExtraGas*(call: CallEIP161, computation; gas: GasInt, to: string, value: UInt256): GasInt =
|
||||
proc msgExtraGas*(call: CallEIP161, computation; gas: GasInt, to: EthAddress, value: UInt256): GasInt =
|
||||
# TODO: with
|
||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||
# account_is_dead = (
|
||||
|
@ -247,9 +246,9 @@ proc msgExtraGas*(call: CallEIP161, computation; gas: GasInt, to: string, value:
|
|||
transferGasFee + createGasFee
|
||||
|
||||
|
||||
method callParams(call: StaticCall, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
method callParams(call: StaticCall, computation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
let gas = computation.stack.popInt()
|
||||
let to = forceBytesToAddress(computation.stack.popString)
|
||||
let to = computation.stack.popAddress()
|
||||
|
||||
let (memoryInputStartPosition, memoryInputSize,
|
||||
memoryOutputStartPosition, memoryOutputSize) = computation.stack.popInt(4)
|
||||
|
@ -257,8 +256,8 @@ method callParams(call: StaticCall, computation): (UInt256, UInt256, string, str
|
|||
result = (gas,
|
||||
0.u256, # value
|
||||
to,
|
||||
nil, # sender
|
||||
nil, # codeAddress
|
||||
ZERO_ADDRESS, # sender
|
||||
ZERO_ADDRESS, # codeAddress
|
||||
memoryInputStartPosition,
|
||||
memoryInputSize,
|
||||
memoryOutputStartPosition,
|
||||
|
@ -267,7 +266,7 @@ method callParams(call: StaticCall, computation): (UInt256, UInt256, string, str
|
|||
true) # is_static
|
||||
|
||||
|
||||
method callParams(call: CallByzantium, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
method callParams(call: CallByzantium, computation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, UInt256, UInt256, UInt256, UInt256, bool, bool) =
|
||||
result = procCall callParams(call, computation)
|
||||
if computation.msg.isStatic and result[1] != 0:
|
||||
raise newException(WriteProtection, "Cannot modify state while inside of a STATICCALL context")
|
||||
|
|
|
@ -11,7 +11,7 @@ import
|
|||
.. / vm / [stack, message, gas_meter, memory, code_stream], .. / utils / [address, padding, bytes], stint
|
||||
|
||||
proc balance*(computation: var BaseComputation) =
|
||||
let address = forceBytesToAddress(computation.stack.popString)
|
||||
let address = computation.stack.popAddress()
|
||||
var balance: Int256
|
||||
# TODO computation.vmState.stateDB(read_only=True):
|
||||
# balance = db.getBalance(address)
|
||||
|
@ -55,7 +55,7 @@ proc callDataCopy*(computation: var BaseComputation) =
|
|||
computation.gasMeter.consumeGas(copyGasCost, reason="CALLDATACOPY fee")
|
||||
let value = computation.msg.data[callPos ..< callPos + len]
|
||||
let paddedValue = padRight(value, len, 0.byte)
|
||||
computation.memory.write(memPos, len, paddedValue)
|
||||
computation.memory.write(memPos, paddedValue)
|
||||
|
||||
|
||||
proc codesize*(computation: var BaseComputation) =
|
||||
|
@ -86,7 +86,7 @@ proc gasprice*(computation: var BaseComputation) =
|
|||
|
||||
|
||||
proc extCodeSize*(computation: var BaseComputation) =
|
||||
let account = forceBytesToAddress(computation.stack.popString)
|
||||
let account = computation.stack.popAddress()
|
||||
# TODO
|
||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||
# code_size = len(state_db.get_code(account))
|
||||
|
@ -94,7 +94,7 @@ proc extCodeSize*(computation: var BaseComputation) =
|
|||
# computation.stack.push(code_size)
|
||||
|
||||
proc extCodeCopy*(computation: var BaseComputation) =
|
||||
let account = forceBytesToAddress(computation.stack.popString)
|
||||
let account = computation.stack.popAddress()
|
||||
let (memStartPosition, codeStartPosition, size) = computation.stack.popInt(3)
|
||||
let (memPos, codePos, len) = (memStartPosition.toInt, codeStartPosition.toInt, size.toInt)
|
||||
computation.extendMemory(memPos, len)
|
||||
|
|
|
@ -7,10 +7,8 @@
|
|||
|
||||
import macros
|
||||
|
||||
macro pushRes*: untyped =
|
||||
let resNode = ident("res")
|
||||
result = quote:
|
||||
computation.stack.push(`resNode`)
|
||||
template pushRes*: untyped =
|
||||
computation.stack.push(res)
|
||||
|
||||
macro quasiBoolean*(name: untyped, op: untyped, signed: untyped = nil, nonzero: untyped = nil): untyped =
|
||||
var signedNode = newEmptyNode()
|
||||
|
|
|
@ -16,23 +16,22 @@ import
|
|||
using
|
||||
computation: var BaseComputation
|
||||
|
||||
proc mstoreX(computation; x: int) =
|
||||
let start = stack.popInt().toInt
|
||||
let value = stack.popBinary()
|
||||
|
||||
let paddedValue = padLeft(value, x, 0.byte)
|
||||
let normalizedValue = paddedValue[^x .. ^1]
|
||||
|
||||
extendMemory(start, x)
|
||||
memory.write(start, 32, normalizedValue)
|
||||
|
||||
# TODO template handler
|
||||
|
||||
proc mstore*(computation) =
|
||||
mstoreX(32)
|
||||
let start = stack.popInt().toInt
|
||||
let normalizedValue = stack.popInt().toByteArrayBE
|
||||
|
||||
extendMemory(start, 32)
|
||||
memory.write(start, normalizedValue)
|
||||
|
||||
proc mstore8*(computation) =
|
||||
mstoreX(1)
|
||||
let start = stack.popInt().toInt
|
||||
let value = stack.popInt()
|
||||
let normalizedValue = (value and 0xff).toByteArrayBE
|
||||
|
||||
extendMemory(start, 1)
|
||||
memory.write(start, [normalizedValue[0]])
|
||||
|
||||
proc mload*(computation) =
|
||||
let start = stack.popInt().toInt
|
||||
|
|
|
@ -9,7 +9,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],
|
||||
stint
|
||||
stint, byteutils, eth_common
|
||||
|
||||
{.this: computation.}
|
||||
{.experimental.}
|
||||
|
@ -58,11 +58,11 @@ method runLogic*(create: Create, computation) =
|
|||
# )
|
||||
|
||||
# is_collision = state_db.account_has_code_or_nonce(contract_address)
|
||||
let contractAddress = ""
|
||||
let contractAddress = ZERO_ADDRESS
|
||||
let isCollision = false
|
||||
|
||||
if isCollision:
|
||||
computation.vmState.logger.debug(&"Address collision while creating contract: {contractAddress.encodeHex}")
|
||||
computation.vmState.logger.debug(&"Address collision while creating contract: {contractAddress.toHex}")
|
||||
computation.stack.push(0.u256)
|
||||
return
|
||||
|
||||
|
@ -92,7 +92,7 @@ method runLogic*(create: CreateByzantium, computation) =
|
|||
procCall runLogic(create, computation)
|
||||
|
||||
proc selfdestructEIP150(computation) =
|
||||
let beneficiary = forceBytesToAddress(stack.popString)
|
||||
let beneficiary = stack.popAddress()
|
||||
# TODO: with
|
||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||
# if not state_db.account_exists(beneficiary):
|
||||
|
@ -103,7 +103,7 @@ proc selfdestructEIP150(computation) =
|
|||
# _selfdestruct(computation, beneficiary)
|
||||
|
||||
proc selfdestructEIP161(computation) =
|
||||
let beneficiary = forceBytesToAddress(stack.popString)
|
||||
let beneficiary = stack.popAddress()
|
||||
# TODO: with
|
||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||
# is_dead = (
|
||||
|
@ -117,7 +117,7 @@ proc selfdestructEIP161(computation) =
|
|||
# )
|
||||
# _selfdestruct(computation, beneficiary)
|
||||
|
||||
proc selfdestruct(computation; beneficiary: string) =
|
||||
proc selfdestruct(computation; beneficiary: EthAddress) =
|
||||
discard # TODO: with
|
||||
# with computation.vm_state.state_db() as state_db:
|
||||
# local_balance = state_db.get_balance(computation.msg.storage_address)
|
||||
|
@ -158,7 +158,7 @@ proc revert*(computation) =
|
|||
raise newException(Revert, $output)
|
||||
|
||||
proc selfdestruct*(computation) =
|
||||
let beneficiary = forceBytesToAddress(stack.popString)
|
||||
let beneficiary = stack.popAddress()
|
||||
selfdestruct(computation, beneficiary)
|
||||
raise newException(Halt, "SELFDESTRUCT")
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import
|
||||
strformat, strutils, tables, macros,
|
||||
constants, stint, errors, logging, vm_state,
|
||||
vm / [gas_meter, stack, code_stream, memory, message, value], db / db_chain, computation, opcode, opcode_values, utils / [header, address],
|
||||
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
|
||||
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
constants, stint, errors
|
||||
constants, stint, errors, eth_common
|
||||
|
||||
type
|
||||
BaseTransaction* = ref object
|
||||
nonce*: Int256
|
||||
gasPrice*: UInt256
|
||||
gas*: UInt256
|
||||
gasPrice*: GasInt
|
||||
gas*: GasInt
|
||||
to*: string
|
||||
value*: UInt256
|
||||
data*: string
|
||||
|
@ -20,7 +20,7 @@ type
|
|||
r*: Int256
|
||||
s*: Int256
|
||||
|
||||
proc intrinsicGas*(t: BaseTransaction): UInt256 =
|
||||
proc intrinsicGas*(t: BaseTransaction): GasInt =
|
||||
# Compute the baseline gas cost for this transaction. This is the amount
|
||||
# of gas needed to send this transaction (but that is not actually used
|
||||
# for computation)
|
||||
|
|
|
@ -6,44 +6,22 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
|
||||
import ../constants, stint, strformat, times, ../validation
|
||||
import eth_common, ../constants, stint, strformat, times, ../validation, rlp, nimcrypto
|
||||
|
||||
type
|
||||
BlockHeader* = ref object
|
||||
# Note: this is defined in evm/rlp/headers in the original repo
|
||||
timestamp*: EthTime
|
||||
difficulty*: UInt256
|
||||
blockNumber*: UInt256
|
||||
hash*: string
|
||||
unclesHash*: string
|
||||
coinbase*: string
|
||||
stateRoot*: string
|
||||
# TODO: incomplete
|
||||
export BlockHeader
|
||||
|
||||
proc hasUncles*(header: BlockHeader): bool = header.uncles_hash != EMPTY_UNCLE_HASH
|
||||
|
||||
proc gasUsed*(header: BlockHeader): UInt256 =
|
||||
# TODO
|
||||
# Should this be calculated/a proc? Parity and Py-Evm just have it as a field.
|
||||
0.u256
|
||||
|
||||
proc gasLimit*(header: BlockHeader): UInt256 =
|
||||
# TODO
|
||||
0.u256
|
||||
proc hasUncles*(header: BlockHeader): bool = header.ommersHash != EMPTY_UNCLE_HASH
|
||||
|
||||
proc `$`*(header: BlockHeader): string =
|
||||
if header.isNil:
|
||||
result = "nil"
|
||||
else:
|
||||
result = &"BlockHeader(timestamp: {header.timestamp} difficulty: {header.difficulty} blockNumber: {header.blockNumber} gasLimit: {header.gasLimit})"
|
||||
result = &"BlockHeader(timestamp: {header.timestamp} difficulty: {header.difficulty} blockNumber: {header.blockNumber} gasLimit: {header.gasLimit})"
|
||||
|
||||
proc gasLimitBounds*(parent: BlockHeader): (UInt256, UInt256) =
|
||||
proc gasLimitBounds*(parent: BlockHeader): (GasInt, GasInt) =
|
||||
## Compute the boundaries for the block gas limit based on the parent block.
|
||||
let
|
||||
boundary_range = parent.gasLimit div GAS_LIMIT_ADJUSTMENT_FACTOR
|
||||
upper_bound = parent.gas_limit + boundary_range
|
||||
lower_bound = max(GAS_LIMIT_MINIMUM, parent.gas_limit - boundary_range)
|
||||
return (lower_bound, upper_bound)
|
||||
boundaryRange = parent.gasLimit div GAS_LIMIT_ADJUSTMENT_FACTOR
|
||||
upperBound = parent.gasLimit + boundaryRange
|
||||
lowerBound = max(GAS_LIMIT_MINIMUM, parent.gasLimit - boundaryRange)
|
||||
return (lowerBound, upperBound)
|
||||
|
||||
#[
|
||||
proc validate_gaslimit(header: BlockHeader):
|
||||
|
@ -59,7 +37,7 @@ proc validate_gaslimit(header: BlockHeader):
|
|||
encode_hex(header.hash), header.gas_limit, high_bound))
|
||||
]#
|
||||
|
||||
proc computeGasLimit*(parent: BlockHeader, gasLimitFloor: UInt256): UInt256 =
|
||||
proc computeGasLimit*(parent: BlockHeader, gasLimitFloor: GasInt): GasInt =
|
||||
#[
|
||||
For each block:
|
||||
- decrease by 1/1024th of the gas limit from the previous block
|
||||
|
@ -69,16 +47,16 @@ proc computeGasLimit*(parent: BlockHeader, gasLimitFloor: UInt256): UInt256 =
|
|||
If the value is less than the GAS_LIMIT_MINIMUM:
|
||||
- use the GAS_LIMIT_MINIMUM as the new gas limit.
|
||||
]#
|
||||
if gas_limit_floor < GAS_LIMIT_MINIMUM:
|
||||
if gasLimitFloor < GAS_LIMIT_MINIMUM:
|
||||
raise newException(ValueError,
|
||||
&"""
|
||||
The `gas_limit_floor` value must be greater than the GAS_LIMIT_MINIMUM.
|
||||
The `gasLimitFloor` value must be greater than the GAS_LIMIT_MINIMUM.
|
||||
Got {gasLimitFloor}. Must be greater than {GAS_LIMIT_MINIMUM}
|
||||
"""
|
||||
)
|
||||
|
||||
let decay = parent.gasLimit div GAS_LIMIT_EMA_DENOMINATOR
|
||||
var usageIncrease = u256(0)
|
||||
var usageIncrease: GasInt
|
||||
|
||||
if parent.gasUsed > 0:
|
||||
usageIncrease = (
|
||||
|
@ -92,7 +70,7 @@ proc computeGasLimit*(parent: BlockHeader, gasLimitFloor: UInt256): UInt256 =
|
|||
|
||||
if gas_limit < GAS_LIMIT_MINIMUM:
|
||||
return GAS_LIMIT_MINIMUM
|
||||
elif gas_limit < gas_limit_floor:
|
||||
elif gas_limit < gasLimitFloor:
|
||||
return parent.gas_limit + decay
|
||||
else:
|
||||
return gas_limit
|
||||
|
@ -100,21 +78,18 @@ proc computeGasLimit*(parent: BlockHeader, gasLimitFloor: UInt256): UInt256 =
|
|||
proc generateHeaderFromParentHeader*(
|
||||
computeDifficultyFn: proc(parentHeader: BlockHeader, timestamp: int): int,
|
||||
parent: BlockHeader,
|
||||
coinbase: string,
|
||||
coinbase: EthAddress,
|
||||
timestamp: int = -1,
|
||||
extraData: string = ""): BlockHeader =
|
||||
# TODO: validateGt(timestamp, parent.timestamp)
|
||||
result = BlockHeader(
|
||||
timestamp: max(getTime(), parent.timestamp + 1.milliseconds), # Note: Py-evm uses +1 second, not ms
|
||||
block_number: (parent.block_number + u256(1)),
|
||||
blockNumber: (parent.blockNumber + 1.u256),
|
||||
# TODO: difficulty: parent.computeDifficulty(parent.timestamp),
|
||||
#[TODO: Make field? Or do we need to keep as a proc?
|
||||
gas_limit: computeGasLimit(
|
||||
parent,
|
||||
gas_limit_floor=GENESIS_GAS_LIMIT,
|
||||
),]#
|
||||
hash: parent.hash,
|
||||
state_root: parent.state_root,
|
||||
gasLimit: computeGasLimit(parent, gasLimitFloor = GENESIS_GAS_LIMIT),
|
||||
stateRoot: parent.stateRoot,
|
||||
coinbase: coinbase,
|
||||
# TODO: data: extraData,
|
||||
)
|
||||
|
||||
proc hash*(b: BlockHeader): Hash256 {.inline.} = rlpHash(b)
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
|
||||
import strutils
|
||||
|
||||
proc encodeHex*(value: string): string =
|
||||
# return "0x" & codecs.decode(codecs.encode(value, "hex"), "utf8")
|
||||
return value
|
||||
# proc encodeHex*(value: string): string =
|
||||
# # return "0x" & codecs.decode(codecs.encode(value, "hex"), "utf8")
|
||||
# return value
|
||||
|
||||
proc decodeHex*(value: string): string =
|
||||
# var hexPart = value.rsplit("x", 1)[1]
|
||||
return value
|
||||
# return codecs.decode(hexPart, "hex")
|
||||
# proc decodeHex*(value: string): string =
|
||||
# # var hexPart = value.rsplit("x", 1)[1]
|
||||
# return value
|
||||
# # return codecs.decode(hexPart, "hex")
|
||||
|
||||
|
|
|
@ -6,11 +6,14 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
nimcrypto, strutils
|
||||
nimcrypto, strutils, eth_common
|
||||
|
||||
proc keccak*(value: string): string {.inline.}=
|
||||
$keccak256.digest value
|
||||
proc keccak*(value: openarray[byte]): Hash256 {.inline.} =
|
||||
keccak256.digest value
|
||||
|
||||
proc keccak*(value: cstring): string {.inline.}=
|
||||
proc keccak*(value: string): Hash256 {.inline.} =
|
||||
keccak256.digest value
|
||||
|
||||
proc keccak*(value: cstring): Hash256 {.inline.} =
|
||||
# TODO: this is inefficient it allocates for the cstring -> string and then for string -> result
|
||||
keccak $value
|
||||
|
|
|
@ -11,25 +11,15 @@ import stint, constants, strformat, strutils, sequtils, endians, macros, utils /
|
|||
|
||||
# TODO improve
|
||||
|
||||
proc intToBigEndian*(value: UInt256): Bytes =
|
||||
proc intToBigEndian*(value: UInt256): Bytes {.deprecated.} =
|
||||
result = newSeq[byte](32)
|
||||
let v_ptr = cast[ptr array[32, byte]](value.unsafeAddr)
|
||||
result[0 .. ^1] = value.toByteArrayBE()
|
||||
|
||||
for idx, val in result.mpairs:
|
||||
when system.cpuEndian == littleEndian:
|
||||
val = v_ptr[32 - 1 - idx]
|
||||
else:
|
||||
val = v_ptr[idx]
|
||||
|
||||
proc bigEndianToInt*(value: Bytes): UInt256 =
|
||||
var bytes = value.padLeft(32, 0.byte)
|
||||
let v_ptr = cast[ptr array[32, byte]](result.addr)
|
||||
|
||||
for idx, val in bytes:
|
||||
when system.cpuEndian == littleEndian:
|
||||
v_ptr[32 - 1 - idx] = val
|
||||
else:
|
||||
v_ptr[idx] = val
|
||||
proc bigEndianToInt*(value: openarray[byte]): UInt256 =
|
||||
if value.len == 32:
|
||||
readUintBE[256](value)
|
||||
else:
|
||||
readUintBE[256](padLeft(@value, 32, 0.byte))
|
||||
|
||||
#echo intToBigEndian("32482610168005790164680892356840817100452003984372336767666156211029086934369".u256)
|
||||
|
||||
|
|
|
@ -7,16 +7,11 @@
|
|||
|
||||
import
|
||||
strformat,
|
||||
errors, constants, stint
|
||||
|
||||
proc validateCanonicalAddress*(value: string, title: string = "Value") =
|
||||
# TODO
|
||||
if false: #len(value) != 20:
|
||||
raise newException(ValidationError,
|
||||
&"{title} {value} is not a valid canonical address")
|
||||
|
||||
|
||||
errors, constants, stint, eth_common
|
||||
|
||||
template validateCanonicalAddress*(value: EthAddress, title: string = "Value") =
|
||||
# TODO: This needs to be removed
|
||||
discard
|
||||
|
||||
proc validateGte*(value: Int256 | int, minimum: int, title: string = "Value") =
|
||||
if value.i256 < minimum.i256:
|
||||
|
|
|
@ -10,7 +10,7 @@ import
|
|||
../../../constants, ../../../errors, ../../../vm_state, ../../../transaction, ../../../utils/header
|
||||
|
||||
proc validateFrontierTransaction*(vmState: BaseVmState, transaction: BaseTransaction) =
|
||||
let gasCost = transaction.gas * transaction.gasPrice
|
||||
let gasCost = u256(transaction.gas * transaction.gasPrice)
|
||||
var senderBalance: UInt256
|
||||
# inDB(vmState.stateDB(readOnly=true):
|
||||
# senderBalance = db.getBalance(transaction.sender)
|
||||
|
|
|
@ -20,7 +20,7 @@ proc newFrontierVMState*: FrontierVMState =
|
|||
result.prevHeaders = @[]
|
||||
result.name = "FrontierVM"
|
||||
result.accessLogs = newAccessLogs()
|
||||
result.blockHeader = BlockHeader(hash: "TODO", coinbase: "TODO", stateRoot: "TODO")
|
||||
# result.blockHeader = # TODO: ...
|
||||
|
||||
# import
|
||||
# py2nim_helpers, __future__, rlp, evm, evm.constants, evm.exceptions, evm.rlp.logs,
|
||||
|
|
|
@ -10,7 +10,7 @@ import
|
|||
../../../constants, ../../../errors, ../../../vm_state, ../../../transaction, ../../../utils/header
|
||||
|
||||
proc validateTangerineTransaction*(vmState: BaseVmState, transaction: BaseTransaction) =
|
||||
let gasCost = transaction.gas * transaction.gasPrice
|
||||
let gasCost = u256(transaction.gas * transaction.gasPrice)
|
||||
var senderBalance: UInt256
|
||||
# inDB(vmState.stateDB(readOnly=true):
|
||||
# senderBalance = db.getBalance(transaction.sender)
|
||||
|
|
|
@ -20,4 +20,4 @@ proc newTangerineVMState*: TangerineVMState =
|
|||
result.prevHeaders = @[]
|
||||
result.name = "TangerineVM"
|
||||
result.accessLogs = newAccessLogs()
|
||||
result.blockHeader = BlockHeader(hash: "TODO", coinbase: "TODO", stateRoot: "TODO")
|
||||
# result.blockHeader = # TODO: ...
|
||||
|
|
|
@ -23,7 +23,6 @@ proc len*(memory: Memory): int =
|
|||
result = memory.bytes.len
|
||||
|
||||
|
||||
# TODO: why is the size passed as a UInt256?
|
||||
proc extend*(memory: var Memory; startPosition: Natural; size: Natural) =
|
||||
if size == 0:
|
||||
return
|
||||
|
@ -37,19 +36,17 @@ proc newMemory*(size: Natural): Memory =
|
|||
result = newMemory()
|
||||
result.extend(0, size)
|
||||
|
||||
# TODO: why is the size passed as a UInt256?
|
||||
proc read*(memory: var Memory, startPosition: Natural, size: Natural): seq[byte] =
|
||||
result = memory.bytes[startPosition ..< (startPosition + size)]
|
||||
|
||||
# TODO: why is the size passed as a UInt256?
|
||||
proc write*(memory: var Memory, startPosition: Natural, size: Natural, value: seq[byte]) =
|
||||
proc write*(memory: var Memory, startPosition: Natural, value: openarray[byte]) =
|
||||
let size = value.len
|
||||
if size == 0:
|
||||
return
|
||||
#echo size
|
||||
#echo startPosition
|
||||
#validateGte(startPosition, 0)
|
||||
#validateGte(size, 0)
|
||||
validateLength(value, size)
|
||||
validateLte(startPosition + size, memory.len)
|
||||
let index = memory.len
|
||||
if memory.len < startPosition + size:
|
||||
|
@ -59,4 +56,4 @@ proc write*(memory: var Memory, startPosition: Natural, size: Natural, value: se
|
|||
memory.bytes[z + startPosition] = b
|
||||
|
||||
template write*(memory: var Memory, startPosition: Natural, size: Natural, value: cstring) =
|
||||
memory.write(startPosition, size, value.toBytes)
|
||||
memory.write(startPosition, value.toBytes)
|
||||
|
|
|
@ -6,22 +6,23 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
../logging, ../constants, ../validation, stint, ../vm_types
|
||||
stint, eth_common,
|
||||
../logging, ../constants, ../validation, ../vm_types
|
||||
|
||||
proc `origin=`*(message: var Message, value: string) =
|
||||
proc `origin=`*(message: var Message, value: EthAddress) =
|
||||
message.internalOrigin = value
|
||||
|
||||
proc `codeAddress=`*(message: var Message, value: string) =
|
||||
proc `codeAddress=`*(message: var Message, value: EthAddress) =
|
||||
message.internalCodeAddress = value
|
||||
|
||||
proc `storageAddress=`*(message: var Message, value: string) =
|
||||
proc `storageAddress=`*(message: var Message, value: EthAddress) =
|
||||
message.internalStorageAddress = value
|
||||
|
||||
proc newMessageOptions*(
|
||||
origin: string = "",
|
||||
origin = ZERO_ADDRESS,
|
||||
depth: int = 0,
|
||||
createAddress: string = "",
|
||||
codeAddress: string = "",
|
||||
createAddress = ZERO_ADDRESS,
|
||||
codeAddress = ZERO_ADDRESS,
|
||||
shouldTransferValue: bool = true,
|
||||
isStatic: bool = false): MessageOptions =
|
||||
|
||||
|
@ -36,8 +37,8 @@ proc newMessageOptions*(
|
|||
proc newMessage*(
|
||||
gas: GasInt,
|
||||
gasPrice: GasInt,
|
||||
to: string,
|
||||
sender: string,
|
||||
to: EthAddress,
|
||||
sender: EthAddress,
|
||||
value: UInt256,
|
||||
data: seq[byte],
|
||||
code: string,
|
||||
|
@ -58,8 +59,6 @@ proc newMessage*(
|
|||
|
||||
result.data = data
|
||||
|
||||
if not options.origin.isNil:
|
||||
validateCanonicalAddress(options.origin, title="Message.origin")
|
||||
result.internalOrigin = options.origin
|
||||
|
||||
validateGte(options.depth, minimum=0, title="Message.depth")
|
||||
|
@ -67,20 +66,16 @@ proc newMessage*(
|
|||
|
||||
result.code = code
|
||||
|
||||
if not options.createAddress.isNil:
|
||||
validateCanonicalAddress(options.createAddress, title="Message.storage_address")
|
||||
result.storageAddress = options.createAddress
|
||||
|
||||
if not options.codeAddress.isNil:
|
||||
validateCanonicalAddress(options.codeAddress, title="Message.code_address")
|
||||
result.codeAddress = options.codeAddress
|
||||
|
||||
result.shouldTransferValue = options.shouldTransferValue
|
||||
|
||||
result.isStatic = options.isStatic
|
||||
|
||||
proc origin*(message: Message): string =
|
||||
if not message.internalOrigin.len == 0:
|
||||
proc origin*(message: Message): EthAddress =
|
||||
if message.internalOrigin != ZERO_ADDRESS:
|
||||
message.internalOrigin
|
||||
else:
|
||||
message.sender
|
||||
|
@ -88,14 +83,14 @@ proc origin*(message: Message): string =
|
|||
proc isOrigin*(message: Message): bool =
|
||||
message.sender == message.origin
|
||||
|
||||
proc codeAddress*(message: Message): string =
|
||||
if not message.internalCodeAddress.len == 0:
|
||||
proc codeAddress*(message: Message): EthAddress =
|
||||
if message.internalCodeAddress != ZERO_ADDRESS:
|
||||
message.internalCodeAddress
|
||||
else:
|
||||
message.to
|
||||
|
||||
proc `storageAddress`*(message: Message): string =
|
||||
if not message.internalStorageAddress.len == 0:
|
||||
proc `storageAddress`*(message: Message): EthAddress =
|
||||
if message.internalStorageAddress != ZERO_ADDRESS:
|
||||
message.internalStorageAddress
|
||||
else:
|
||||
message.to
|
||||
|
|
|
@ -6,157 +6,84 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
strformat, strutils, sequtils, macros, rlp,
|
||||
value, ../errors, ../validation, ../utils_numeric, ../constants, stint, ../logging, .. / utils / bytes
|
||||
strformat, strutils, sequtils, macros, rlp, eth_common, nimcrypto,
|
||||
../errors, ../validation, ../utils_numeric, ../constants, stint, ../logging, .. / utils / bytes
|
||||
|
||||
type
|
||||
|
||||
Stack* = ref object of RootObj
|
||||
logger*: Logger
|
||||
values*: seq[UInt256]
|
||||
values*: seq[StackElement]
|
||||
|
||||
StackElement = UInt256
|
||||
|
||||
template ensureStackLimit: untyped =
|
||||
if len(stack.values) > 1023:
|
||||
raise newException(FullStack, "Stack limit reached")
|
||||
|
||||
proc len*(stack: Stack): int =
|
||||
proc len*(stack: Stack): int {.inline.} =
|
||||
len(stack.values)
|
||||
|
||||
template toType(i: UInt256, _: typedesc[UInt256]): UInt256 =
|
||||
i
|
||||
proc toStackElement(v: UInt256, elem: var StackElement) {.inline.} = elem = v
|
||||
proc toStackElement(v: uint | int, elem: var StackElement) {.inline.} = elem = v.u256
|
||||
proc toStackElement(v: EthAddress, elem: var StackElement) {.inline.} = elem = bigEndianToInt(v)
|
||||
proc toStackElement(v: MDigest, elem: var StackElement) {.inline.} = elem = readUintBE[256](v.data)
|
||||
|
||||
template toType(i: UInt256, _: typedesc[string]): string =
|
||||
i.intToBigEndian.toString
|
||||
proc fromStackElement(elem: StackElement, v: var UInt256) {.inline.} = v = elem
|
||||
proc fromStackElement(elem: StackElement, v: var EthAddress) {.inline.} = v[0 .. ^1] = elem.toByteArrayBE().toOpenArray(0, 19)
|
||||
proc fromStackElement(elem: StackElement, v: var Hash256) {.inline.} = v.data = elem.toByteArrayBE()
|
||||
|
||||
template toType(i: UInt256, _: typedesc[Bytes]): Bytes =
|
||||
i.intToBigEndian
|
||||
proc toStackElement(v: seq[byte], elem: var StackElement) {.inline.} =
|
||||
# TODO: This needs to go
|
||||
validateStackItem(v)
|
||||
elem = bigEndianToInt(v)
|
||||
|
||||
template toType(b: string, _: typedesc[UInt256]): UInt256 =
|
||||
b.toBytes.bigEndianToInt
|
||||
|
||||
template toType(b: string, _: typedesc[string]): string =
|
||||
b
|
||||
|
||||
template toType(b: string, _: typedesc[Bytes]): Bytes =
|
||||
b.toBytes
|
||||
|
||||
template toType(b: Bytes, _: typedesc[UInt256]): UInt256 =
|
||||
b.bigEndianToInt
|
||||
|
||||
template toType(b: Bytes, _: typedesc[string]): string =
|
||||
b.toString
|
||||
|
||||
template toType(b: Bytes, _: typedesc[Bytes]): Bytes =
|
||||
b
|
||||
|
||||
proc push*(stack: var Stack, value: uint) =
|
||||
## Push an integer onto the stack
|
||||
proc pushAux[T](stack: var Stack, value: T) =
|
||||
ensureStackLimit()
|
||||
stack.values.setLen(stack.values.len + 1)
|
||||
toStackElement(value, stack.values[^1])
|
||||
|
||||
stack.values.add(value.u256)
|
||||
proc push*(stack: var Stack, value: uint | UInt256 | EthAddress | Hash256) {.inline.} =
|
||||
pushAux(stack, value)
|
||||
|
||||
proc push*(stack: var Stack, value: UInt256) =
|
||||
## Push an integer onto the stack
|
||||
ensureStackLimit()
|
||||
proc push*(stack: var Stack, value: seq[byte]) {.inline.} =
|
||||
# TODO: This needs to go...
|
||||
pushAux(stack, value)
|
||||
|
||||
stack.values.add(value)
|
||||
|
||||
proc push*(stack: var Stack, value: string) =
|
||||
## Push a binary onto the stack
|
||||
ensureStackLimit()
|
||||
validateStackItem(value)
|
||||
|
||||
stack.values.add(value.toType(UInt256))
|
||||
|
||||
proc push*(stack: var Stack, value: Bytes) =
|
||||
ensureStackLimit()
|
||||
validateStackItem(value)
|
||||
|
||||
stack.values.add(value.toType(UInt256))
|
||||
|
||||
proc internalPop(stack: var Stack, numItems: int): seq[UInt256] =
|
||||
# TODO: it is very inefficient to allocate a seq
|
||||
assert numItems <= stack.len
|
||||
result = stack.values[^numItems .. ^1]
|
||||
stack.values = stack.values[0 ..< ^numItems]
|
||||
|
||||
proc internalPop(stack: var Stack, numItems: int, T: typedesc): seq[T] =
|
||||
# TODO: it is very inefficient to allocate a seq
|
||||
|
||||
assert numItems <= stack.len
|
||||
result = @[]
|
||||
|
||||
for z in 0 ..< numItems:
|
||||
var value = stack.values.pop()
|
||||
result.add(toType(value, T))
|
||||
|
||||
proc ensurePop(elements: seq|Stack, a: int) =
|
||||
proc ensurePop(elements: Stack, a: int) =
|
||||
let num = elements.len
|
||||
let expected = a
|
||||
if num < expected:
|
||||
raise newException(InsufficientStack,
|
||||
&"Stack underflow: expected {expected} elements, got {num} instead.")
|
||||
|
||||
proc popInt*(stack: var Stack): UInt256 =
|
||||
proc popAux[T](stack: var Stack, value: var T) =
|
||||
ensurePop(stack, 1)
|
||||
var elements = stack.internalPop(1, UInt256)
|
||||
result = elements[0]
|
||||
fromStackElement(stack.values[^1], value)
|
||||
stack.values.setLen(stack.values.len - 1)
|
||||
|
||||
macro internalPopTuple(numItems: static[int]): untyped =
|
||||
var name = ident(&"internalPopTuple{numItems}")
|
||||
var typ = nnkPar.newTree()
|
||||
var t = ident("T")
|
||||
var resultNode = ident("result")
|
||||
var stackNode = ident("stack")
|
||||
for z in 0 ..< numItems:
|
||||
typ.add(t)
|
||||
result = quote:
|
||||
proc `name`*(`stackNode`: var Stack, `t`: typedesc): `typ`
|
||||
result[^1] = nnkStmtList.newTree()
|
||||
result[^1].add quote do:
|
||||
ensurePop(`stackNode`, `numItems`)
|
||||
for z in 0 ..< numItems:
|
||||
var zNode = newLit(z)
|
||||
var element = quote:
|
||||
var value = `stackNode`.values.pop()
|
||||
`resultNode`[`zNode`] = toType(value, `t`)
|
||||
result[^1].add(element)
|
||||
proc internalPopTuple(stack: var Stack, v: var tuple, tupleLen: static[int]) =
|
||||
ensurePop(stack, tupleLen)
|
||||
var i = 0
|
||||
let sz = stack.values.high
|
||||
for f in fields(v):
|
||||
fromStackElement(stack.values[sz - i], f)
|
||||
inc i
|
||||
stack.values.setLen(sz - tupleLen + 1)
|
||||
|
||||
# define pop<T> for tuples
|
||||
internalPopTuple(2)
|
||||
internalPopTuple(3)
|
||||
internalPopTuple(4)
|
||||
internalPopTuple(5)
|
||||
internalPopTuple(6)
|
||||
internalPopTuple(7)
|
||||
proc popInt*(stack: var Stack): UInt256 {.inline.} =
|
||||
popAux(stack, result)
|
||||
|
||||
macro popInt*(stack: typed, numItems: static[int]): untyped =
|
||||
var resultNode = ident("result")
|
||||
if numItems >= 8:
|
||||
result = quote:
|
||||
`stack`.internalPop(`numItems`, UInt256)
|
||||
else:
|
||||
var name = ident(&"internalPopTuple{numItems}")
|
||||
result = quote:
|
||||
`name`(`stack`, UInt256)
|
||||
macro genTupleType(len: static[int], elemType: untyped): untyped =
|
||||
result = nnkTupleConstr.newNimNode()
|
||||
for i in 0 ..< len: result.add(elemType)
|
||||
|
||||
proc popBinary*(stack: var Stack): Bytes =
|
||||
var elements = stack.internalPop(1, Bytes)
|
||||
ensurePop(elements, 1)
|
||||
result = elements[0]
|
||||
proc popInt*(stack: var Stack, numItems: static[int]): auto {.inline.} =
|
||||
var r: genTupleType(numItems, UInt256)
|
||||
stack.internalPopTuple(r, numItems)
|
||||
return r
|
||||
|
||||
proc popBinary*(stack: var Stack, numItems: int): seq[Bytes] =
|
||||
result = stack.internalPop(numItems, Bytes)
|
||||
ensurePop(result, numItems)
|
||||
|
||||
proc popString*(stack: var Stack): string =
|
||||
var elements = stack.internalPop(1, string)
|
||||
ensurePop(elements, 1)
|
||||
result = elements[0]
|
||||
|
||||
proc popString*(stack: var Stack, numItems: int): seq[string] =
|
||||
result = stack.internalPop(numItems, string)
|
||||
ensurePop(result, numItems)
|
||||
proc popAddress*(stack: var Stack): EthAddress {.inline.} =
|
||||
popAux(stack, result)
|
||||
|
||||
proc newStack*(): Stack =
|
||||
new(result)
|
||||
|
@ -174,27 +101,16 @@ proc swap*(stack: var Stack, position: int) =
|
|||
|
||||
proc dup*(stack: var Stack, position: int | UInt256) =
|
||||
## Perform a DUP operation on the stack
|
||||
if (position != 0 and position.getInt < stack.len + 1) or (position == 0 and position.getInt < stack.len):
|
||||
stack.push(stack.values[^position.getInt])
|
||||
let position = position.getInt
|
||||
if position in 1 .. stack.len:
|
||||
stack.push(stack.values[^position])
|
||||
else:
|
||||
raise newException(InsufficientStack,
|
||||
&"Insufficient stack items for DUP{position}")
|
||||
|
||||
|
||||
proc getInt*(stack: Stack, position: int): UInt256 =
|
||||
if stack.values.len <= position:
|
||||
raise newException(InsufficientStack, &"No {position} item")
|
||||
else:
|
||||
stack.values[position]
|
||||
|
||||
proc getBinary*(stack: Stack, position: int): Bytes =
|
||||
stack.values[position].toType(Bytes)
|
||||
|
||||
proc getString*(stack: Stack, position: int): string =
|
||||
stack.values[position].toType(string)
|
||||
|
||||
proc peek*(stack: Stack): UInt256 =
|
||||
stack.getInt(stack.values.len - 1)
|
||||
# This should be used only for testing purposes!
|
||||
fromStackElement(stack.values[^1], result)
|
||||
|
||||
proc `$`*(stack: Stack): string =
|
||||
let values = stack.values.mapIt(&" {$it}").join("\n")
|
||||
|
|
|
@ -1,49 +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,
|
||||
../constants, stint
|
||||
|
||||
type
|
||||
ValueKind* = enum VInt, VBinary
|
||||
|
||||
Value* = ref object
|
||||
case kind*: ValueKind:
|
||||
of VInt:
|
||||
Fi: array[32, byte] #Int256
|
||||
of VBinary:
|
||||
b*: seq[byte]
|
||||
|
||||
# TODO: The Int256 value is stored as array[32, byte], and we bitcast it
|
||||
# back and forth. This is a hacky workaround for the problem that clang
|
||||
# doesn't let you store stint types inside nim variant types (unions). Things
|
||||
# should get better when we switch to mpint.
|
||||
|
||||
proc i*(v: Value): Int256 {.inline.} =
|
||||
cast[ptr Int256](unsafeAddr v.Fi)[]
|
||||
|
||||
proc `$`*(value: Value): string =
|
||||
case value.kind:
|
||||
of VInt:
|
||||
&"Int({value.i})"
|
||||
of VBinary:
|
||||
&"Binary({value.b})"
|
||||
|
||||
proc toArr(i: Int256): array[32, byte] {.inline.} =
|
||||
cast[ptr array[32, byte]](unsafeAddr i)[]
|
||||
|
||||
proc vint*(i: Int256): Value =
|
||||
Value(kind: VInt, Fi: i.toArr)
|
||||
|
||||
proc vint*(i: int): Value {.inline.} = vint(i.int256)
|
||||
|
||||
proc vbinary*(b: string): Value =
|
||||
Value(kind: VBinary, b: b.mapIt(it.byte))
|
||||
|
||||
proc vbinary*(b: seq[byte]): Value =
|
||||
Value(kind: VBinary, b: b)
|
|
@ -7,8 +7,9 @@
|
|||
|
||||
import
|
||||
macros, strformat, tables,
|
||||
stint,
|
||||
./logging, ./constants, ./errors, ./transaction, ./db/[db_chain, state_db], ./utils/state, ./utils/header
|
||||
stint, eth_common,
|
||||
./logging, ./constants, ./errors, ./transaction, ./db/[db_chain, state_db],
|
||||
./utils/[state, header]
|
||||
|
||||
type
|
||||
BaseVMState* = ref object of RootObj
|
||||
|
@ -41,35 +42,35 @@ proc newBaseVMState*: BaseVMState =
|
|||
result.prevHeaders = @[]
|
||||
result.name = "BaseVM"
|
||||
result.accessLogs = newAccessLogs()
|
||||
result.blockHeader = BlockHeader(hash: "TODO", coinbase: "TODO", stateRoot: "TODO")
|
||||
# result.blockHeader = # TODO...
|
||||
|
||||
method logger*(vmState: BaseVMState): Logger =
|
||||
logging.getLogger(&"evm.vmState.{vmState.name}")
|
||||
|
||||
method blockhash*(vmState: BaseVMState): string =
|
||||
method blockhash*(vmState: BaseVMState): Hash256 =
|
||||
vmState.blockHeader.hash
|
||||
|
||||
method coinbase*(vmState: BaseVMState): string =
|
||||
method coinbase*(vmState: BaseVMState): EthAddress =
|
||||
vmState.blockHeader.coinbase
|
||||
|
||||
method timestamp*(vmState: BaseVMState): EthTime =
|
||||
vmState.blockHeader.timestamp
|
||||
|
||||
method blockNumber*(vmState: BaseVMState): UInt256 =
|
||||
method blockNumber*(vmState: BaseVMState): BlockNumber =
|
||||
vmState.blockHeader.blockNumber
|
||||
|
||||
method difficulty*(vmState: BaseVMState): UInt256 =
|
||||
vmState.blockHeader.difficulty
|
||||
|
||||
method gasLimit*(vmState: BaseVMState): UInt256 =
|
||||
method gasLimit*(vmState: BaseVMState): GasInt =
|
||||
vmState.blockHeader.gasLimit
|
||||
|
||||
method getAncestorHash*(vmState: BaseVMState, blockNumber: UInt256): string =
|
||||
method getAncestorHash*(vmState: BaseVMState, blockNumber: BlockNumber): Hash256 =
|
||||
var ancestorDepth = vmState.blockHeader.blockNumber - blockNumber - 1.u256
|
||||
if ancestorDepth >= constants.MAX_PREV_HEADER_DEPTH or
|
||||
ancestorDepth < 0 or
|
||||
ancestorDepth >= vmState.prevHeaders.len.u256:
|
||||
return ""
|
||||
return
|
||||
var header = vmState.prevHeaders[ancestorDepth.toInt]
|
||||
result = header.hash
|
||||
|
||||
|
@ -100,4 +101,4 @@ macro db*(vmState: untyped, readOnly: untyped, handler: untyped): untyped =
|
|||
# state._trie = None
|
||||
|
||||
proc readOnlyStateDB*(vmState: BaseVMState): AccountStateDB {.inline.}=
|
||||
vmState.chaindb.getStateDb("", readOnly = true)
|
||||
vmState.chaindb.getStateDb(Hash256(), readOnly = true)
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
import
|
||||
tables,
|
||||
constants, vm_state,
|
||||
opcode_values, stint,
|
||||
opcode_values, stint, eth_common,
|
||||
vm / [code_stream, memory, stack],
|
||||
./logging
|
||||
|
||||
export GasInt
|
||||
|
||||
type
|
||||
BaseComputation* = ref object of RootObj
|
||||
# The execution computation
|
||||
|
@ -25,9 +27,9 @@ type
|
|||
rawOutput*: string
|
||||
returnData*: string
|
||||
error*: Error
|
||||
logEntries*: seq[(string, seq[UInt256], string)]
|
||||
logEntries*: seq[(EthAddress, seq[UInt256], string)]
|
||||
shouldEraseReturnData*: bool
|
||||
accountsToDelete*: Table[string, string]
|
||||
accountsToDelete*: Table[EthAddress, EthAddress]
|
||||
opcodes*: Table[Op, Opcode] # TODO array[Op, Opcode]
|
||||
precompiles*: Table[string, Opcode]
|
||||
gasCosts*: GasCosts # TODO separate opcode processing and gas computation
|
||||
|
@ -50,10 +52,6 @@ type
|
|||
gasCostKind*: GasCostKind
|
||||
runLogic*: proc(computation: var BaseComputation)
|
||||
|
||||
GasInt* = int64
|
||||
## Type alias used for gas computation
|
||||
# For reference - https://github.com/status-im/nimbus/issues/35#issuecomment-391726518
|
||||
|
||||
GasMeter* = ref object
|
||||
logger*: Logger
|
||||
gasRefunded*: GasInt
|
||||
|
@ -101,23 +99,23 @@ type
|
|||
|
||||
gas*: GasInt
|
||||
gasPrice*: GasInt
|
||||
to*: string
|
||||
sender*: string
|
||||
to*: EthAddress
|
||||
sender*: EthAddress
|
||||
value*: UInt256
|
||||
data*: seq[byte]
|
||||
code*: string
|
||||
internalOrigin*: string
|
||||
internalCodeAddress*: string
|
||||
internalOrigin*: EthAddress
|
||||
internalCodeAddress*: EthAddress
|
||||
depth*: int
|
||||
internalStorageAddress*: string
|
||||
internalStorageAddress*: EthAddress
|
||||
shouldTransferValue*: bool
|
||||
isStatic*: bool
|
||||
isCreate*: bool
|
||||
|
||||
MessageOptions* = ref object
|
||||
origin*: string
|
||||
origin*: EthAddress
|
||||
depth*: int
|
||||
createAddress*: string
|
||||
codeAddress*: string
|
||||
createAddress*: EthAddress
|
||||
codeAddress*: EthAddress
|
||||
shouldTransferValue*: bool
|
||||
isStatic*: bool
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
|
||||
import
|
||||
unittest, strformat, tables, times,
|
||||
stint,
|
||||
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 = "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" # TODO privateKey(decodeHex("0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"))
|
||||
let fundedAddr = privateKey # privateKey.publicKey.toCanonicalAddress
|
||||
let privateKey = initPrivateKey("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8")
|
||||
let fundedAddr = privateKey.getPublicKey.toCanonicalAddress
|
||||
let initialBalance = 100_000_000
|
||||
let genesisParams = GenesisParams(
|
||||
blockNumber: GENESIS_BLOCK_NUMBER,
|
||||
|
@ -25,7 +25,7 @@ proc chainWithoutBlockValidation*: Chain =
|
|||
mixHash: GENESIS_MIX_HASH,
|
||||
extraData: GENESIS_EXTRA_DATA,
|
||||
timestamp: fromUnix 1501851927,
|
||||
stateRoot: "0x9d354f9b5ba851a35eced279ef377111387197581429cfcc7f744ef89a30b5d4") #.decodeHex)
|
||||
stateRoot: "9d354f9b5ba851a35eced279ef377111387197581429cfcc7f744ef89a30b5d4".toDigest)
|
||||
let genesisState = {"fundedAddr": FundedAddress(balance: initialBalance.int256, nonce: 0, code: "")}.toTable()
|
||||
result = fromGenesis(
|
||||
result,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import
|
||||
os, macros, json, strformat, strutils, parseutils, ospaths, tables,
|
||||
stint,
|
||||
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,
|
||||
|
@ -77,8 +77,11 @@ macro jsonTest*(s: static[string], handler: untyped): untyped =
|
|||
raw.add("OK: " & $okCount & "/" & $sum & " Fail: " & $failCount & "/" & $sum & " Skip: " & $skipCount & "/" & $sum & "\n")
|
||||
writeFile(`s` & ".md", raw)
|
||||
|
||||
proc accountFromHex(s: string): EthAddress = hexToByteArray(s, result)
|
||||
|
||||
proc setupStateDB*(desiredState: JsonNode, stateDB: var AccountStateDB) =
|
||||
for account, accountData in desiredState:
|
||||
for ac, accountData in desiredState:
|
||||
let account = accountFromHex(ac)
|
||||
for slot, value in accountData{"storage"}:
|
||||
stateDB.setStorage(account, slot.parseInt.u256, value.getInt.u256)
|
||||
|
||||
|
@ -94,9 +97,9 @@ proc getHexadecimalInt*(j: JsonNode): int =
|
|||
discard parseHex(j.getStr, result)
|
||||
|
||||
method newTransaction*(
|
||||
vm: VM, addr_from, addr_to: string,
|
||||
vm: VM, addr_from, addr_to: EthAddress,
|
||||
amount: UInt256,
|
||||
private_key: string,
|
||||
private_key: PrivateKey,
|
||||
gas_price = 10.u256,
|
||||
gas = 100000.u256,
|
||||
data: seq[byte] = @[]
|
||||
|
|
|
@ -21,7 +21,7 @@ suite "memory":
|
|||
test "write":
|
||||
var mem = memory32()
|
||||
# Test that write creates 32byte string == value padded with zeros
|
||||
mem.write(startPosition = 0, size = 4, value = @[1.byte, 0.byte, 1.byte, 0.byte])
|
||||
mem.write(startPosition = 0, value = @[1.byte, 0.byte, 1.byte, 0.byte])
|
||||
check(mem.bytes == @[1.byte, 0.byte, 1.byte, 0.byte].concat(repeat(0.byte, 28)))
|
||||
|
||||
# test "write rejects invalid position":
|
||||
|
@ -44,15 +44,10 @@ suite "memory":
|
|||
# var mem = memory32()
|
||||
# mem.write(startPosition = 0.u256, size = pow(2.u256, 256), value = @[1.byte, 0.byte])
|
||||
|
||||
test "write rejects invalid value":
|
||||
expect(ValidationError):
|
||||
var mem = memory32()
|
||||
mem.write(startPosition = 0, size = 4, value = @[1.byte, 0.byte])
|
||||
|
||||
test "write rejects valyes beyond memory size":
|
||||
expect(ValidationError):
|
||||
var mem = memory128()
|
||||
mem.write(startPosition = 128, size = 4, value = @[1.byte, 0.byte, 1.byte, 0.byte])
|
||||
mem.write(startPosition = 128, value = @[1.byte, 0.byte, 1.byte, 0.byte])
|
||||
|
||||
test "extends appropriately extends memory":
|
||||
var mem = newMemory()
|
||||
|
@ -68,7 +63,7 @@ suite "memory":
|
|||
|
||||
test "read returns correct bytes":
|
||||
var mem = memory32()
|
||||
mem.write(startPosition = 5, size = 4, value = @[1.byte, 0.byte, 1.byte, 0.byte])
|
||||
mem.write(startPosition = 5, value = @[1.byte, 0.byte, 1.byte, 0.byte])
|
||||
check(mem.read(startPosition = 5, size = 4) == @[1.byte, 0.byte, 1.byte, 0.byte])
|
||||
check(mem.read(startPosition = 6, size = 4) == @[0.byte, 1.byte, 0.byte, 0.byte])
|
||||
check(mem.read(startPosition = 1, size = 3) == @[0.byte, 0.byte, 0.byte])
|
||||
|
|
|
@ -26,8 +26,8 @@ proc testCode(code: string, initialGas: GasInt, blockNum: UInt256): BaseComputat
|
|||
# timestamp: fixture{"env"}{"currentTimestamp"}.getHexadecimalInt)
|
||||
|
||||
let message = newMessage(
|
||||
to="", #fixture{"exec"}{"address"}.getStr,
|
||||
sender="", #fixture{"exec"}{"caller"}.getStr,
|
||||
to=ZERO_ADDRESS, #fixture{"exec"}{"address"}.getStr,
|
||||
sender=ZERO_ADDRESS, #fixture{"exec"}{"caller"}.getStr,
|
||||
value=0.u256,
|
||||
data = @[],
|
||||
code=code,
|
||||
|
@ -42,7 +42,6 @@ proc testCode(code: string, initialGas: GasInt, blockNum: UInt256): BaseComputat
|
|||
c.displayDecompiled()
|
||||
|
||||
var computation = newBaseComputation(vm.state, message)
|
||||
computation.accountsToDelete = initTable[string, string]()
|
||||
computation.opcodes = OPCODE_TABLE
|
||||
computation.precompiles = initTable[string, Opcode]()
|
||||
|
||||
|
|
|
@ -7,18 +7,18 @@
|
|||
|
||||
import unittest, macros, strformat, strutils, sequtils,
|
||||
stint,
|
||||
../nimbus/[constants, opcode_values, errors, utils_numeric, vm/stack, vm/value, utils/bytes, utils/padding]
|
||||
../nimbus/[constants, opcode_values, errors, utils_numeric, vm/stack, utils/bytes, utils/padding]
|
||||
|
||||
|
||||
template testPush(value: untyped, expected: untyped): untyped =
|
||||
var stack = newStack()
|
||||
stack.push(`value`)
|
||||
check(stack.values == @[`expected`])
|
||||
stack.push(value)
|
||||
check(stack.values == @[expected])
|
||||
|
||||
template testFailPush(value: untyped): untyped =
|
||||
var stack = newStack()
|
||||
expect(ValidationError):
|
||||
stack.push(`value`)
|
||||
stack.push(value)
|
||||
|
||||
suite "stack":
|
||||
test "push only valid":
|
||||
|
@ -54,11 +54,6 @@ suite "stack":
|
|||
stack.push(element)
|
||||
check(stack.popInt == 3.u256)
|
||||
|
||||
stack = newStack()
|
||||
stack.push("1".toBytes)
|
||||
check(stack.popBinary == "1".toBytes.pad32)
|
||||
|
||||
|
||||
test "swap correct":
|
||||
var stack = newStack()
|
||||
for z in 0 ..< 5:
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
unittest, stint,
|
||||
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]
|
||||
|
@ -20,7 +20,7 @@ suite "VM":
|
|||
vm = chain.getVM()
|
||||
# txIdx = len(vm.`block`.transactions) # Can't take len of a runtime field
|
||||
let
|
||||
recipient = decodeHex("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c")
|
||||
recipient = parseAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c")
|
||||
amount = 100.u256
|
||||
ethaddr_from = chain.fundedAddress
|
||||
tx = newTransaction(vm, ethaddr_from, recipient, amount, chain.fundedAddressPrivateKey)
|
||||
|
|
Loading…
Reference in New Issue