mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-24 11:11:59 +00:00
CodeStream impl and tests, fix byte and string fields
This commit is contained in:
parent
62f1417439
commit
a233cef719
@ -13,7 +13,7 @@ type
|
||||
## current block number.
|
||||
header*: BlockHeader
|
||||
logger*: Logger
|
||||
networkId*: cstring
|
||||
networkId*: string
|
||||
vmsByRange*: seq[tuple[blockNumber: Int256, vm: VM]] # TODO
|
||||
importBlock*: bool
|
||||
validateBlock*: bool
|
||||
@ -23,18 +23,18 @@ type
|
||||
blockNumber*: Int256
|
||||
difficulty*: Int256
|
||||
gasLimit*: Int256
|
||||
parentHash*: cstring
|
||||
coinbase*: cstring
|
||||
nonce: cstring
|
||||
mixHash: cstring
|
||||
extraData: cstring
|
||||
parentHash*: string
|
||||
coinbase*: string
|
||||
nonce: string
|
||||
mixHash: string
|
||||
extraData: string
|
||||
timestamp: int,
|
||||
stateRoot: cstring
|
||||
stateRoot: string
|
||||
|
||||
FundedAddress* = ref object
|
||||
balance*: Int256
|
||||
nonce*: int
|
||||
code*: cstring
|
||||
code*: string
|
||||
|
||||
|
||||
proc configureChain*(name: string, blockNumber: Int256, vm: VM, importBlock: bool = true, validateBlock: bool = true): Chain =
|
||||
|
@ -23,14 +23,14 @@ type
|
||||
gasMeter*: GasMeter
|
||||
code*: CodeStream
|
||||
children*: seq[BaseComputation]
|
||||
rawOutput*: cstring
|
||||
returnData*: cstring
|
||||
rawOutput*: string
|
||||
returnData*: string
|
||||
error*: Error
|
||||
logEntries*: seq[(cstring, seq[Int256], cstring)]
|
||||
logEntries*: seq[(string, seq[Int256], string)]
|
||||
shouldEraseReturnData*: bool
|
||||
accountsToDelete*: Table[cstring, cstring]
|
||||
accountsToDelete*: Table[string, string]
|
||||
opcodes*: Table[Op, Opcode] # TODO array[Op, Opcode]
|
||||
precompiles*: Table[cstring, Opcode]
|
||||
precompiles*: Table[string, Opcode]
|
||||
|
||||
Error* = ref object
|
||||
info*: string
|
||||
@ -53,7 +53,7 @@ proc newBaseComputation*(vmState: BaseVMState, message: Message): BaseComputatio
|
||||
result.stack = newStack()
|
||||
result.gasMeter = newGasMeter(message.gas)
|
||||
result.children = @[]
|
||||
result.accountsToDelete = initTable[cstring, cstring]()
|
||||
result.accountsToDelete = initTable[string, string]()
|
||||
result.logEntries = @[]
|
||||
result.code = newCodeStream(message.code)
|
||||
|
||||
@ -87,10 +87,10 @@ method shouldEraseReturnData*(c: BaseComputation): bool =
|
||||
method prepareChildMessage*(
|
||||
c: var BaseComputation,
|
||||
gas: Int256,
|
||||
to: cstring,
|
||||
to: string,
|
||||
value: Int256,
|
||||
data: seq[byte],
|
||||
code: cstring,
|
||||
code: string,
|
||||
options: MessageOptions = newMessageOptions()): Message =
|
||||
|
||||
var childOptions = options
|
||||
@ -128,13 +128,13 @@ method extendMemory*(c: var BaseComputation, startPosition: Int256, size: Int256
|
||||
|
||||
c.memory.extend(startPosition, size)
|
||||
|
||||
method output*(c: BaseComputation): cstring =
|
||||
method output*(c: BaseComputation): string =
|
||||
if c.shouldEraseReturnData:
|
||||
cstring""
|
||||
""
|
||||
else:
|
||||
c.rawOutput
|
||||
|
||||
method `output=`*(c: var BaseComputation, value: cstring) =
|
||||
method `output=`*(c: var BaseComputation, value: string) =
|
||||
c.rawOutput = value
|
||||
|
||||
macro generateChildBaseComputation*(t: typed, vmState: typed, childMsg: typed): untyped =
|
||||
@ -157,12 +157,12 @@ method addChildBaseComputation*(c: var BaseComputation, childBaseComputation: Ba
|
||||
if childBaseComputation.msg.isCreate:
|
||||
c.returnData = childBaseComputation.output
|
||||
elif childBaseComputation.shouldBurnGas:
|
||||
c.returnData = cstring""
|
||||
c.returnData = ""
|
||||
else:
|
||||
c.returnData = childBaseComputation.output
|
||||
else:
|
||||
if childBaseComputation.msg.isCreate:
|
||||
c.returnData = cstring""
|
||||
c.returnData = ""
|
||||
else:
|
||||
c.returnData = childBaseComputation.output
|
||||
c.children.add(childBaseComputation)
|
||||
@ -172,7 +172,7 @@ method applyChildBaseComputation*(c: var BaseComputation, childMsg: Message): Ba
|
||||
c.addChildBaseComputation(childBaseComputation)
|
||||
result = childBaseComputation
|
||||
|
||||
method registerAccountForDeletion*(c: var BaseComputation, beneficiary: cstring) =
|
||||
method registerAccountForDeletion*(c: var BaseComputation, beneficiary: string) =
|
||||
validateCanonicalAddress(beneficiary, title="self destruct beneficiary address")
|
||||
|
||||
if c.msg.storageAddress in c.accountsToDelete:
|
||||
@ -181,18 +181,18 @@ method registerAccountForDeletion*(c: var BaseComputation, beneficiary: cstring)
|
||||
"registered for deletion multiple times")
|
||||
c.accountsToDelete[c.msg.storageAddress] = beneficiary
|
||||
|
||||
method addLogEntry*(c: var BaseComputation, account: cstring, topics: seq[Int256], data: cstring) =
|
||||
method addLogEntry*(c: var BaseComputation, account: string, topics: seq[Int256], data: string) =
|
||||
validateCanonicalAddress(account, title="log entry address")
|
||||
c.logEntries.add((account, topics, data))
|
||||
|
||||
method getAccountsForDeletion*(c: BaseComputation): seq[(cstring, cstring)] =
|
||||
method getAccountsForDeletion*(c: BaseComputation): seq[(string, string)] =
|
||||
# TODO
|
||||
if c.isError:
|
||||
result = @[]
|
||||
else:
|
||||
result = @[]
|
||||
|
||||
method getLogEntries*(c: BaseComputation): seq[(cstring, seq[Int256], cstring)] =
|
||||
method getLogEntries*(c: BaseComputation): seq[(string, seq[Int256], string)] =
|
||||
# TODO
|
||||
if c.isError:
|
||||
result = @[]
|
||||
|
@ -86,12 +86,12 @@ let
|
||||
UINT_255_MAX*: Int256 = 2 ^ (256 - 1) - 1
|
||||
UINT_255_CEILING*: Int256 = 2 ^ (256 - 1)
|
||||
|
||||
NULLBYTE* = cstring"\x00"
|
||||
NULLBYTE* = "\x00"
|
||||
EMPTYWORD* = repeat(NULLBYTE, 32)
|
||||
UINT160CEILING*: Int256 = 2 ^ 160
|
||||
CREATE_CONTRACT_ADDRESS* = cstring""
|
||||
ZERO_ADDRESS* = repeat(cstring"\x00", 20)
|
||||
ZERO_HASH32* = repeat(cstring"\x00", 20)
|
||||
CREATE_CONTRACT_ADDRESS* = ""
|
||||
ZERO_ADDRESS* = repeat("\x00", 20)
|
||||
ZERO_HASH32* = repeat("\x00", 20)
|
||||
STACK_DEPTH_LIMIT* = 1024
|
||||
|
||||
GAS_NULL* = 0.i256
|
||||
@ -178,19 +178,19 @@ let
|
||||
SECPK1_Gy* = 0.i256
|
||||
SECPK1_G* = (SECPK1Gx, SECPK1Gy)
|
||||
|
||||
EMPTY_UNCLE_HASH* = cstring"\x1d\xccM\xe8\xde\xc7]z\xab\x85\xb5g\xb6\xcc\xd4\x1a\xd3\x12E\x1b\x94\x8at\x13\xf0\xa1B\xfd@\xd4\x93G"
|
||||
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"
|
||||
|
||||
GENESIS_BLOCK_NUMBER* = 0.i256
|
||||
GENESIS_DIFFICULTY* = 131_072.i256
|
||||
GENESIS_GAS_LIMIT* = 3_141_592.i256
|
||||
GENESIS_PARENT_HASH* = ZERO_HASH32
|
||||
GENESIS_COINBASE* = ZERO_ADDRESS
|
||||
GENESIS_NONCE* = cstring"\x00\x00\x00\x00\x00\x00\x00B"
|
||||
GENESIS_NONCE* = "\x00\x00\x00\x00\x00\x00\x00B"
|
||||
GENESIS_MIX_HASH* = ZERO_HASH32
|
||||
GENESIS_EXTRA_DATA = cstring""
|
||||
GENESIS_EXTRA_DATA = ""
|
||||
|
||||
EMPTYSHA3 = cstring"\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p"
|
||||
BLANK_ROOT_HASH* = cstring"V\xe8\x1f\x17\x1b\xccU\xa6\xff\x83E\xe6\x92\xc0\xf8n[H\xe0\x1b\x99l\xad\xc0\x01b/\xb5\xe3c\xb4!"
|
||||
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!"
|
||||
|
||||
GAS_MOD_EXP_QUADRATIC_DENOMINATOR* = 20.i256
|
||||
|
||||
|
@ -4,15 +4,15 @@ import
|
||||
|
||||
type
|
||||
AccountStateDB* = ref object
|
||||
db*: Table[cstring, Int256]
|
||||
db*: Table[string, Int256]
|
||||
|
||||
proc newAccountStateDB*(db: Table[cstring, Int256], readOnly: bool = false): AccountStateDB =
|
||||
proc newAccountStateDB*(db: Table[string, Int256], readOnly: bool = false): AccountStateDB =
|
||||
result = AccountStateDB(db: db)
|
||||
|
||||
proc logger*(db: AccountStateDB): Logger =
|
||||
logging.getLogger("db.State")
|
||||
|
||||
proc getAccount(db: AccountStateDB, address: cstring): Account =
|
||||
proc getAccount(db: AccountStateDB, address: string): Account =
|
||||
# let rlpAccount = db.trie[address]
|
||||
# if not rlpAccount.isNil:
|
||||
# account = rlp.decode[Account](rlpAccount)
|
||||
@ -21,23 +21,23 @@ proc getAccount(db: AccountStateDB, address: cstring): Account =
|
||||
# account = newAccount()
|
||||
result = newAccount() # TODO
|
||||
|
||||
proc setAccount(db: AccountStateDB, address: cstring, account: Account) =
|
||||
proc setAccount(db: AccountStateDB, address: string, account: Account) =
|
||||
# db.trie[address] = rlp.encode[Account](account)
|
||||
discard # TODO
|
||||
|
||||
# public
|
||||
|
||||
proc getBalance*(db: AccountStateDB, address: cstring): Int256 =
|
||||
proc getBalance*(db: AccountStateDB, address: string): Int256 =
|
||||
validateCanonicalAddress(address, title="Storage Address")
|
||||
let account = db.getAccount(address)
|
||||
account.balance
|
||||
|
||||
proc setBalance*(db: var AccountStateDB, address: cstring, balance: Int256) =
|
||||
proc setBalance*(db: var AccountStateDB, address: string, balance: Int256) =
|
||||
validateCanonicalAddress(address, title="Storage Address")
|
||||
let account = db.getAccount(address)
|
||||
account.balance = balance
|
||||
db.setAccount(address, account)
|
||||
|
||||
proc deltaBalance*(db: var AccountStateDB, address: cstring, delta: Int256) =
|
||||
proc deltaBalance*(db: var AccountStateDB, address: string, delta: Int256) =
|
||||
db.setBalance(address, db.getBalance(address) + delta)
|
||||
|
||||
|
@ -30,16 +30,16 @@ type
|
||||
using
|
||||
computation: var BaseComputation
|
||||
|
||||
method msgExtraGas*(call: BaseCall, computation; gas: Int256, to: cstring, value: Int256): Int256 {.base.} =
|
||||
method msgExtraGas*(call: BaseCall, computation; gas: Int256, to: string, value: Int256): Int256 {.base.} =
|
||||
raise newException(NotImplementedError, "Must be implemented by subclasses")
|
||||
|
||||
method msgGas*(call: BaseCall, computation; gas: Int256, to: cstring, value: Int256): (Int256, Int256) {.base.} =
|
||||
method msgGas*(call: BaseCall, computation; gas: Int256, to: string, value: Int256): (Int256, Int256) {.base.} =
|
||||
let extraGas = call.msgExtraGas(computation, gas, to, value)
|
||||
let totalFee = gas + extraGas
|
||||
let childMsgGas = gas + (if value != 0: GAS_CALL_STIPEND else: 0.i256)
|
||||
(childMsgGas, totalFee)
|
||||
|
||||
method callParams*(call: BaseCall, computation): (Int256, Int256, cstring, cstring, cstring, Int256, Int256, Int256, Int256, bool, bool) {.base.} =
|
||||
method callParams*(call: BaseCall, computation): (Int256, Int256, string, string, string, Int256, Int256, Int256, Int256, bool, bool) {.base.} =
|
||||
raise newException(NotImplementedError, "Must be implemented subclasses")
|
||||
|
||||
method runLogic*(call: BaseCall, computation) =
|
||||
@ -67,7 +67,7 @@ method runLogic*(call: BaseCall, computation) =
|
||||
let stackTooDeep = computation.msg.depth + 1 > constants.STACK_DEPTH_LIMIT
|
||||
|
||||
if insufficientFunds or stackTooDeep:
|
||||
computation.returnData = cstring""
|
||||
computation.returnData = ""
|
||||
var errMessage: string
|
||||
if insufficientFunds:
|
||||
errMessage = &"Insufficient Funds: have: {senderBalance} | need: {value}"
|
||||
@ -86,7 +86,7 @@ method runLogic*(call: BaseCall, computation) =
|
||||
# code = state_db.get_code(code_address)
|
||||
# else:
|
||||
# code = state_db.get_code(to)
|
||||
let code = cstring""
|
||||
let code = ""
|
||||
|
||||
let childMsg = computation.prepareChildMessage(
|
||||
childMsgGas,
|
||||
@ -115,7 +115,7 @@ method runLogic*(call: BaseCall, computation) =
|
||||
if not childComputation.shouldBurnGas:
|
||||
computation.gasMeter.returnGas(childComputation.gasMeter.gasRemaining)
|
||||
|
||||
method msgExtraGas(call: Call, computation; gas: Int256, to: cstring, value: Int256): Int256 =
|
||||
method msgExtraGas(call: Call, computation; gas: Int256, to: string, value: Int256): Int256 =
|
||||
# TODO: db
|
||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||
# let accountExists = db.accountExists(to)
|
||||
@ -125,9 +125,9 @@ method msgExtraGas(call: Call, computation; gas: Int256, to: cstring, value: Int
|
||||
let createGasFee = if not accountExists: GAS_NEW_ACCOUNT else: 0.i256
|
||||
transferGasFee + createGasFee
|
||||
|
||||
method callParams(call: CallCode, computation): (Int256, Int256, cstring, cstring, cstring, Int256, Int256, Int256, Int256, bool, bool) =
|
||||
method callParams(call: CallCode, computation): (Int256, Int256, string, string, string, Int256, Int256, Int256, Int256, bool, bool) =
|
||||
let gas = computation.stack.popInt()
|
||||
let to = cstring(forceBytesToAddress(computation.stack.popBinary))
|
||||
let to = forceBytesToAddress(computation.stack.popBinary)
|
||||
|
||||
let (value,
|
||||
memoryInputStartPosition, memoryInputSize,
|
||||
@ -145,12 +145,12 @@ method callParams(call: CallCode, computation): (Int256, Int256, cstring, cstrin
|
||||
true, # should_transfer_value,
|
||||
computation.msg.isStatic)
|
||||
|
||||
method msgExtraGas(call: CallCode, computation; gas: Int256, to: cstring, value: Int256): Int256 =
|
||||
method msgExtraGas(call: CallCode, computation; gas: Int256, to: string, value: Int256): Int256 =
|
||||
if value != 0: GAS_CALL_VALUE else: 0.i256
|
||||
|
||||
method callParams(call: Call, computation): (Int256, Int256, cstring, cstring, cstring, Int256, Int256, Int256, Int256, bool, bool) =
|
||||
method callParams(call: Call, computation): (Int256, Int256, string, string, string, Int256, Int256, Int256, Int256, bool, bool) =
|
||||
let gas = computation.stack.popInt()
|
||||
let codeAddress = cstring(forceBytesToAddress(computation.stack.popBinary))
|
||||
let codeAddress = forceBytesToAddress(computation.stack.popBinary)
|
||||
|
||||
let (value,
|
||||
memoryInputStartPosition, memoryInputSize,
|
||||
@ -171,15 +171,15 @@ method callParams(call: Call, computation): (Int256, Int256, cstring, cstring, c
|
||||
true, # should_transfer_value,
|
||||
computation.msg.isStatic)
|
||||
|
||||
method msgGas(call: DelegateCall, computation; gas: Int256, to: cstring, value: Int256): (Int256, Int256) =
|
||||
method msgGas(call: DelegateCall, computation; gas: Int256, to: string, value: Int256): (Int256, Int256) =
|
||||
(gas, gas)
|
||||
|
||||
method msgExtraGas(call: DelegateCall, computation; gas: Int256, to: cstring, value: Int256): Int256 =
|
||||
method msgExtraGas(call: DelegateCall, computation; gas: Int256, to: string, value: Int256): Int256 =
|
||||
0.i256
|
||||
|
||||
method callParams(call: DelegateCall, computation): (Int256, Int256, cstring, cstring, cstring, Int256, Int256, Int256, Int256, bool, bool) =
|
||||
method callParams(call: DelegateCall, computation): (Int256, Int256, string, string, string, Int256, Int256, Int256, Int256, bool, bool) =
|
||||
let gas = computation.stack.popInt()
|
||||
let codeAddress = cstring(forceBytesToAddress(computation.stack.popBinary))
|
||||
let codeAddress = forceBytesToAddress(computation.stack.popBinary)
|
||||
|
||||
let (memoryInputStartPosition, memoryInputSize,
|
||||
memoryOutputStartPosition, memoryOutputSize) = computation.stack.popInt(4)
|
||||
@ -211,19 +211,19 @@ proc computeEIP150MsgGas(computation; gas: Int256, extraGas: Int256, value: Int2
|
||||
let childMsgGas = gas + (if value != 0: callStipend else: 0.i256)
|
||||
(childMsgGas, totalFee)
|
||||
|
||||
method msgGas(call: CallEIP150, computation; gas: Int256, to: cstring, value: Int256): (Int256, Int256) =
|
||||
method msgGas(call: CallEIP150, computation; gas: Int256, to: string, value: Int256): (Int256, Int256) =
|
||||
let extraGas = call.msgExtraGas(computation, gas, to, value)
|
||||
computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, GAS_CALL_STIPEND)
|
||||
|
||||
method msgGas(call: CallCodeEIP150, computation; gas: Int256, to: cstring, value: Int256): (Int256, Int256) =
|
||||
method msgGas(call: CallCodeEIP150, computation; gas: Int256, to: string, value: Int256): (Int256, Int256) =
|
||||
let extraGas = call.msgExtraGas(computation, gas, to, value)
|
||||
computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, GAS_CALL_STIPEND)
|
||||
|
||||
method msgGas(call: DelegateCallEIP150, computation; gas: Int256, to: cstring, value: Int256): (Int256, Int256) =
|
||||
method msgGas(call: DelegateCallEIP150, computation; gas: Int256, to: string, value: Int256): (Int256, Int256) =
|
||||
let extraGas = call.msgExtraGas(computation, gas, to, value)
|
||||
computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, 0.i256)
|
||||
|
||||
proc msgExtraGas*(call: CallEIP161, computation; gas: Int256, to: cstring, value: Int256): Int256 =
|
||||
proc msgExtraGas*(call: CallEIP161, computation; gas: Int256, to: string, value: Int256): Int256 =
|
||||
# TODO: with
|
||||
# with computation.vm_state.state_db(read_only=True) as state_db:
|
||||
# account_is_dead = (
|
||||
@ -236,9 +236,9 @@ proc msgExtraGas*(call: CallEIP161, computation; gas: Int256, to: cstring, value
|
||||
transferGasFee + createGasFee
|
||||
|
||||
|
||||
method callParams(call: StaticCall, computation): (Int256, Int256, cstring, cstring, cstring, Int256, Int256, Int256, Int256, bool, bool) =
|
||||
method callParams(call: StaticCall, computation): (Int256, Int256, string, string, string, Int256, Int256, Int256, Int256, bool, bool) =
|
||||
let gas = computation.stack.popInt()
|
||||
let to = cstring(forceBytesToAddress(computation.stack.popBinary))
|
||||
let to = forceBytesToAddress(computation.stack.popBinary)
|
||||
|
||||
let (memoryInputStartPosition, memoryInputSize,
|
||||
memoryOutputStartPosition, memoryOutputSize) = computation.stack.popInt(4)
|
||||
@ -256,7 +256,7 @@ method callParams(call: StaticCall, computation): (Int256, Int256, cstring, cstr
|
||||
true) # is_static
|
||||
|
||||
|
||||
method callParams(call: CallByzantium, computation): (Int256, Int256, cstring, cstring, cstring, Int256, Int256, Int256, Int256, bool, bool) =
|
||||
method callParams(call: CallByzantium, computation): (Int256, Int256, string, string, string, Int256, Int256, Int256, Int256, 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")
|
||||
|
@ -26,8 +26,8 @@ proc callValue*(computation: var BaseComputation) =
|
||||
proc callDataLoad*(computation: var BaseComputation) =
|
||||
# Load call data into memory
|
||||
let startPosition = computation.stack.popInt.getInt
|
||||
let value = computation.msg.data[startPosition ..< startPosition + 32].toCString
|
||||
let paddedValue = padRight(value, 32, cstring"\x00")
|
||||
let value = computation.msg.data[startPosition ..< startPosition + 32].toString
|
||||
let paddedValue = padRight(value, 32, "\x00")
|
||||
let normalizedValue = paddedValue.lStrip(0.char)
|
||||
computation.stack.push(normalizedValue)
|
||||
|
||||
@ -45,8 +45,8 @@ proc callDataCopy*(computation: var BaseComputation) =
|
||||
let wordCount = ceil32(size) div 32
|
||||
let copyGasCost = wordCount * constants.GAS_COPY
|
||||
computation.gasMeter.consumeGas(copyGasCost, reason="CALLDATACOPY fee")
|
||||
let value = computation.msg.data[calldataStartPosition.getInt ..< (calldataStartPosition + size).getInt].toCString
|
||||
let paddedValue = padRight(value, size.getInt, cstring"\x00")
|
||||
let value = computation.msg.data[calldataStartPosition.getInt ..< (calldataStartPosition + size).getInt].toString
|
||||
let paddedValue = padRight(value, size.getInt, "\x00")
|
||||
computation.memory.write(memStartPosition, size, paddedValue)
|
||||
|
||||
|
||||
@ -115,5 +115,5 @@ proc returnDataCopy*(computation: var BaseComputation) =
|
||||
let wordCount = ceil32(size) div 32
|
||||
let copyGasCost = wordCount * constants.GAS_COPY
|
||||
computation.gasMeter.consumeGas(copyGasCost, reason="RETURNDATACOPY fee")
|
||||
let value = cstring(($computation.returnData)[returnDataStartPosition.getInt ..< (returnDataStartPosition + size).getInt])
|
||||
let value = ($computation.returnData)[returnDataStartPosition.getInt ..< (returnDataStartPosition + size).getInt]
|
||||
computation.memory.write(memStartPosition, size, value)
|
||||
|
@ -48,7 +48,7 @@ macro logXX(topicCount: static[int]): untyped =
|
||||
let totalGasCost = dataGasCost + topicGasCost
|
||||
`computation`.gasMeter.consumeGas(totalGasCost, reason="Log topic and data gas cost")
|
||||
`computation`.extendMemory(`memStartPosition`, `size`)
|
||||
let logData = `computation`.memory.read(`memStartPosition`, `size`).toCString
|
||||
let logData = `computation`.memory.read(`memStartPosition`, `size`).toString
|
||||
`computation`.addLogEntry(
|
||||
account=`computation`.msg.storageAddress,
|
||||
topics=`topics`,
|
||||
|
@ -12,8 +12,8 @@ proc mstoreX(computation; x: int) =
|
||||
let start = stack.popInt()
|
||||
let value = stack.popBinary()
|
||||
|
||||
let paddedValue = padLeft(value, x, cstring"\x00")
|
||||
let normalizedValue = cstring(($paddedValue)[^x .. ^1])
|
||||
let paddedValue = padLeft(value, x, "\x00")
|
||||
let normalizedValue = ($paddedValue)[^x .. ^1]
|
||||
|
||||
extendMemory(start, x.int256)
|
||||
memory.write(start, 32.int256, normalizedValue)
|
||||
@ -31,7 +31,7 @@ proc mload*(computation) =
|
||||
|
||||
extendMemory(start, 32.int256)
|
||||
|
||||
let value = memory.read(start, 32.int256).toCstring
|
||||
let value = memory.read(start, 32.int256).toString
|
||||
stack.push(value)
|
||||
|
||||
proc msize*(computation) =
|
||||
|
@ -8,5 +8,5 @@ proc sha3op*(computation: var BaseComputation) =
|
||||
let wordCount = sha3Bytes.len.i256.ceil32 div 32
|
||||
let gasCost = constants.GAS_SHA3_WORD * wordCount
|
||||
computation.gasMeter.consumeGas(gasCost, reason="SHA3: word gas cost")
|
||||
var res = keccak(cstring"")
|
||||
var res = keccak("")
|
||||
pushRes()
|
||||
|
@ -17,12 +17,12 @@ macro pushXX(size: static[int]): untyped =
|
||||
let name = ident(&"push{size}")
|
||||
result = quote:
|
||||
proc `name`*(`computation`: var BaseComputation) =
|
||||
let `value` = `computation`.code.read(`size`).toCString
|
||||
let `value` = `computation`.code.read(`size`).toString
|
||||
let stripped = `value`.strip(0.char)
|
||||
if stripped.len == 0:
|
||||
`computation`.stack.push(0.i256)
|
||||
else:
|
||||
let paddedValue = `value`.padRight(`size`, cstring"\x00")
|
||||
let paddedValue = `value`.padRight(`size`, "\x00")
|
||||
`computation`.stack.push(paddedValue)
|
||||
|
||||
|
||||
|
@ -50,7 +50,7 @@ method runLogic*(create: Create, computation) =
|
||||
# )
|
||||
|
||||
# is_collision = state_db.account_has_code_or_nonce(contract_address)
|
||||
let contractAddress = cstring""
|
||||
let contractAddress = ""
|
||||
let isCollision = false
|
||||
|
||||
if isCollision:
|
||||
@ -63,7 +63,7 @@ method runLogic*(create: Create, computation) =
|
||||
to=constants.CREATE_CONTRACT_ADDRESS,
|
||||
value=value,
|
||||
data=cast[seq[byte]](@[]),
|
||||
code=callData.toCString,
|
||||
code=callData.toString,
|
||||
options=MessageOptions(createAddress: contractAddress))
|
||||
|
||||
# let childComputation = computation.applyChildComputation(childMsg)
|
||||
@ -109,7 +109,7 @@ proc selfdestructEIP161(computation) =
|
||||
# )
|
||||
# _selfdestruct(computation, beneficiary)
|
||||
|
||||
proc selfdestruct(computation; beneficiary: cstring) =
|
||||
proc selfdestruct(computation; beneficiary: string) =
|
||||
discard # TODO: with
|
||||
# with computation.vm_state.state_db() as state_db:
|
||||
# local_balance = state_db.get_balance(computation.msg.storage_address)
|
||||
@ -136,14 +136,14 @@ proc selfdestruct(computation; beneficiary: cstring) =
|
||||
proc returnOp*(computation) =
|
||||
let (startPosition, size) = stack.popInt(2)
|
||||
computation.extendMemory(startPosition, size)
|
||||
let output = memory.read(startPosition, size).toCString
|
||||
let output = memory.read(startPosition, size).toString
|
||||
computation.output = output
|
||||
raise newException(Halt, "RETURN")
|
||||
|
||||
proc revert*(computation) =
|
||||
let (startPosition, size) = stack.popInt(2)
|
||||
computation.extendMemory(startPosition, size)
|
||||
let output = memory.read(startPosition, size).toCString
|
||||
let output = memory.read(startPosition, size).toString
|
||||
computation.output = output
|
||||
raise newException(Revert, $output)
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
# TODO : hex
|
||||
type
|
||||
Op* {.pure.} = enum
|
||||
STOP, # 0
|
||||
STOP = 0x0, # 0
|
||||
ADD, # 1
|
||||
MUL, # 2
|
||||
SUB, # 3
|
||||
@ -14,7 +14,7 @@ type
|
||||
EXP, # 10
|
||||
SIGNEXTEND, # 11
|
||||
|
||||
LT, # 16
|
||||
LT = 0x10, # 16
|
||||
GT, # 17
|
||||
SLT, # 18
|
||||
SGT, # 19
|
||||
@ -26,9 +26,9 @@ type
|
||||
NOT, # 25
|
||||
BYTE, # 26
|
||||
|
||||
SHA3, # 32
|
||||
SHA3 = 0x20, # 32
|
||||
|
||||
ADDRESS, # 48
|
||||
ADDRESS = 0x30,# 48
|
||||
BALANCE, # 49
|
||||
ORIGIN, # 50
|
||||
|
||||
@ -49,7 +49,7 @@ type
|
||||
RETURNDATASIZE, # 61
|
||||
RETURNDATACOPY, # 62
|
||||
|
||||
BLOCKHASH, # 64
|
||||
BLOCKHASH = 0x40,# 64
|
||||
|
||||
COINBASE, # 65
|
||||
|
||||
@ -61,7 +61,7 @@ type
|
||||
|
||||
GASLIMIT, # 69
|
||||
|
||||
POP, # 80
|
||||
POP = 0x50, # 80
|
||||
|
||||
MLOAD, # 81
|
||||
MSTORE, # 82
|
||||
@ -81,7 +81,7 @@ type
|
||||
|
||||
JUMPDEST, # 91
|
||||
|
||||
PUSH1, # 96
|
||||
PUSH1 = 0x60, # 96
|
||||
PUSH2, # 97
|
||||
PUSH3, # 98
|
||||
PUSH4, # 99
|
||||
@ -150,13 +150,13 @@ type
|
||||
LOG2, # 162
|
||||
LOG3, # 163
|
||||
LOG4, # 164
|
||||
CREATE, # 240
|
||||
CREATE = 0xf0, # 240
|
||||
CALL, # 241
|
||||
CALLCODE, # 242
|
||||
RETURN, # 243
|
||||
DELEGATECALL, # 244
|
||||
STATICCALL, # 250
|
||||
REVERT, # 253
|
||||
SELFDESTRUCT # 255
|
||||
STATICCALL = 0xfa,# 250
|
||||
REVERT = 0xfd, # 253
|
||||
SELFDESTRUCT = 0xff,# 255
|
||||
INVALID # invalid
|
||||
|
||||
|
@ -112,10 +112,10 @@ opcodes[Op.Create] = Create(kind: Op.Create)
|
||||
|
||||
var mem = newMemory(pow(1024.int256, 2))
|
||||
|
||||
var to = toCanonicalAddress(cstring"0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6")
|
||||
var sender = toCanonicalAddress(cstring"0xcd1722f3947def4cf144679da39c4c32bdc35681")
|
||||
var to = toCanonicalAddress("0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6")
|
||||
var sender = toCanonicalAddress("0xcd1722f3947def4cf144679da39c4c32bdc35681")
|
||||
|
||||
var code = cstring""
|
||||
var code = ""
|
||||
var data: seq[byte] = @[]
|
||||
|
||||
var msg = newMessage(
|
||||
@ -140,14 +140,14 @@ var c = BaseComputation(
|
||||
gasMeter: newGasMeter(msg.gas),
|
||||
code: newCodeStream(code),
|
||||
children: @[],
|
||||
rawOutput: cstring"",
|
||||
returnData: cstring"",
|
||||
rawOutput: "",
|
||||
returnData: "",
|
||||
error: nil,
|
||||
logEntries: @[],
|
||||
shouldEraseReturnData: false,
|
||||
accountsToDelete: initTable[cstring, cstring](),
|
||||
accountsToDelete: initTable[string, string](),
|
||||
opcodes: opcodes,
|
||||
precompiles: initTable[cstring, Opcode]())
|
||||
precompiles: initTable[string, Opcode]())
|
||||
|
||||
# var c2 = c.applyComputation(c.vmState, c.msg)
|
||||
|
||||
|
@ -6,9 +6,9 @@ type
|
||||
nonce*: Int256
|
||||
gasPrice*: Int256
|
||||
gas*: Int256
|
||||
to*: cstring
|
||||
to*: string
|
||||
value*: Int256
|
||||
data*: cstring
|
||||
data*: string
|
||||
v*: Int256
|
||||
r*: Int256
|
||||
s*: Int256
|
||||
@ -31,6 +31,6 @@ proc validate*(t: BaseTransaction) =
|
||||
raise newException(ValidationError, "Insufficient gas")
|
||||
# self.check_signature_validity()
|
||||
|
||||
proc sender*(t: BaseTransaction): cstring =
|
||||
proc sender*(t: BaseTransaction): string =
|
||||
# TODO
|
||||
cstring""
|
||||
""
|
@ -1,11 +1,19 @@
|
||||
proc toBytes*(value: cstring): seq[byte] =
|
||||
result = newSeq[byte](value.len)
|
||||
for z, c in value:
|
||||
result[z] = c.byte
|
||||
# result = toSeq(value)
|
||||
import strutils, sequtils
|
||||
|
||||
proc toCString*(value: seq[byte]): cstring =
|
||||
var res = ""
|
||||
for c in value:
|
||||
res.add(c.char)
|
||||
cstring(res) # TODO: faster
|
||||
# proc toBytes*(value: cstring): seq[byte] =
|
||||
# result = newSeq[byte](value.len)
|
||||
# for z, c in value:
|
||||
# result[z] = c.byte
|
||||
# # result = toSeq(value)
|
||||
|
||||
# proc toCString*(value: seq[byte]): cstring =
|
||||
# var res = ""
|
||||
# for c in value:
|
||||
# res.add(c.char)
|
||||
# cstring(res) # TODO: faster
|
||||
|
||||
proc toString*(value: seq[byte]): string =
|
||||
value.mapIt(it.char).join("")
|
||||
|
||||
proc toBytes*(value: string): seq[byte] =
|
||||
result = value.mapIt(it.byte)
|
||||
|
@ -5,16 +5,16 @@ type
|
||||
timestamp*: int
|
||||
difficulty*: Int256
|
||||
blockNumber*: Int256
|
||||
hash*: cstring
|
||||
coinbase*: cstring
|
||||
hash*: string
|
||||
coinbase*: string
|
||||
# TODO
|
||||
|
||||
proc generateHeaderFromParentHeader*(
|
||||
computeDifficultyFn: proc(parentHeader: Header, timestamp: int): int,
|
||||
parentHeader: Header,
|
||||
coinbase: cstring,
|
||||
coinbase: string,
|
||||
timestamp: int = -1,
|
||||
extraData: cstring = cstring""): Header =
|
||||
extraData: string = string""): Header =
|
||||
Header()
|
||||
# Generate BlockHeader from state_root and parent_header
|
||||
# if timestamp is None:
|
||||
|
@ -1,11 +1,11 @@
|
||||
import strutils
|
||||
|
||||
proc encodeHex*(value: cstring): string =
|
||||
proc encodeHex*(value: string): string =
|
||||
# return "0x" & codecs.decode(codecs.encode(value, "hex"), "utf8")
|
||||
return $value
|
||||
return value
|
||||
|
||||
proc decodeHex*(value: string): cstring =
|
||||
proc decodeHex*(value: string): string =
|
||||
# var hexPart = value.rsplit("x", 1)[1]
|
||||
return cstring(value)
|
||||
return value
|
||||
# return codecs.decode(hexPart, "hex")
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import
|
||||
keccak_tiny, strutils
|
||||
|
||||
template keccak*(value: string): cstring =
|
||||
cstring($keccak_256(value))
|
||||
template keccak*(value: string): string =
|
||||
$keccak_256(value)
|
||||
|
||||
template keccak*(value: cstring): cstring =
|
||||
template keccak*(value: cstring): string =
|
||||
($value).keccak
|
||||
|
||||
|
@ -88,3 +88,9 @@ proc rStrip*(value: cstring, c: char): cstring =
|
||||
|
||||
proc strip*(value: cstring, c: char): cstring =
|
||||
result = value.lStrip(c).rStrip(c)
|
||||
|
||||
proc lStrip*(value: string, c: char): string =
|
||||
value.strip(chars={c}, trailing=false)
|
||||
|
||||
proc rStip*(value: string, c: char): string =
|
||||
value.strip(chars={c}, leading=false)
|
||||
|
@ -1,9 +1,9 @@
|
||||
import bigints, constants, strformat, macros
|
||||
|
||||
proc intToBigEndian*(value: Int256): cstring =
|
||||
result = cstring""
|
||||
proc intToBigEndian*(value: Int256): string =
|
||||
result = ""
|
||||
|
||||
proc bigEndianToInt*(value: cstring): Int256 =
|
||||
proc bigEndianToInt*(value: string): Int256 =
|
||||
result = 0.int256
|
||||
|
||||
proc unsignedToSigned*(value: Int256): Int256 =
|
||||
|
@ -4,7 +4,7 @@ import
|
||||
strformat,
|
||||
errors, constants, bigints
|
||||
|
||||
proc validateCanonicalAddress*(value: cstring, title: string = "Value") =
|
||||
proc validateCanonicalAddress*(value: string, title: string = "Value") =
|
||||
# TODO
|
||||
if false: #len(value) != 20:
|
||||
raise newException(ValidationError,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import
|
||||
strformat, strutils, sequtils, sets,
|
||||
strformat, strutils, sequtils, sets, macros,
|
||||
../logging, ../constants, ../opcode_values
|
||||
|
||||
type
|
||||
@ -13,37 +13,43 @@ type
|
||||
proc `$`*(b: byte): string =
|
||||
$(b.int)
|
||||
|
||||
proc newCodeStream*(codeBytes: cstring): CodeStream =
|
||||
proc newCodeStream*(codeBytes: seq[byte]): CodeStream =
|
||||
new(result)
|
||||
result.bytes = codeBytes.mapIt(it.byte)
|
||||
result.bytes = codeBytes
|
||||
result.pc = 0
|
||||
result.invalidPositions = initSet[int]()
|
||||
result.depthProcessed = 0
|
||||
result.logger = logging.getLogger("evm.vm.CodeStream")
|
||||
result.logger = logging.getLogger("vm.code_stream")
|
||||
|
||||
proc newCodeStream*(codeBytes: string): CodeStream =
|
||||
newCodeStream(codeBytes.mapIt(it.byte))
|
||||
|
||||
proc read*(c: var CodeStream, size: int): seq[byte] =
|
||||
result = c.bytes[c.pc .. c.pc + size - 1]
|
||||
c.pc += size
|
||||
if c.pc + size - 1 < c.bytes.len:
|
||||
result = c.bytes[c.pc .. c.pc + size - 1]
|
||||
c.pc += size
|
||||
else:
|
||||
result = @[]
|
||||
c.pc = c.bytes.len
|
||||
|
||||
proc len*(c: CodeStream): int =
|
||||
len(c.bytes)
|
||||
|
||||
proc next*(c: var CodeStream): Op =
|
||||
var nextOpcode = c.read(1)
|
||||
if nextOpcode[0] != 0x0.byte:
|
||||
if nextOpcode.len != 0:
|
||||
return Op(nextOpcode[0])
|
||||
else:
|
||||
return Op.STOP
|
||||
|
||||
|
||||
iterator items*(c: var CodeStream): Op =
|
||||
var nextOpcode = c.next()
|
||||
while nextOpcode != Op.STOP:
|
||||
yield nextOpcode
|
||||
nextOpcode = c.next()
|
||||
|
||||
proc `[]`*(c: CodeStream, offset: int): byte =
|
||||
c.bytes[offset]
|
||||
proc `[]`*(c: CodeStream, offset: int): Op =
|
||||
Op(c.bytes[offset])
|
||||
|
||||
proc peek*(c: var CodeStream): Op =
|
||||
var currentPc = c.pc
|
||||
@ -53,14 +59,16 @@ proc peek*(c: var CodeStream): Op =
|
||||
proc updatePc*(c: var CodeStream, value: int) =
|
||||
c.pc = min(value, len(c))
|
||||
|
||||
template seek*(c: var CodeStream, pc: int, handler: untyped): untyped =
|
||||
var anchorPc = pc
|
||||
`c`.pc = pc
|
||||
try:
|
||||
var c = `c` {.inject.}
|
||||
`handler`
|
||||
finally:
|
||||
`c`.pc = anchorPc
|
||||
macro seek*(c: var CodeStream, pc: int, handler: untyped): untyped =
|
||||
let c2 = ident("c")
|
||||
result = quote:
|
||||
var anchorPc = `c`.pc
|
||||
`c`.pc = `pc`
|
||||
try:
|
||||
var `c2` = `c`
|
||||
`handler`
|
||||
finally:
|
||||
`c`.pc = anchorPc
|
||||
|
||||
proc isValidOpcode*(c: var CodeStream, position: int): bool =
|
||||
if position >= len(c):
|
||||
|
@ -5,4 +5,4 @@ import
|
||||
proc expGasCost*(computation: var BaseComputation): Int256 =
|
||||
let arg = computation.stack.getInt(0)
|
||||
result = if arg == 0: 10.i256 else: (10.i256 + 10.i256 * (1.i256 + arg.log256))
|
||||
|
||||
|
||||
|
@ -19,41 +19,41 @@ type
|
||||
|
||||
gas*: Int256
|
||||
gasPrice*: Int256
|
||||
to*: cstring
|
||||
sender*: cstring
|
||||
to*: string
|
||||
sender*: string
|
||||
value*: Int256
|
||||
data*: seq[byte]
|
||||
code*: cstring
|
||||
internalOrigin: cstring
|
||||
internalCodeAddress: cstring
|
||||
code*: string
|
||||
internalOrigin: string
|
||||
internalCodeAddress: string
|
||||
depth*: int
|
||||
internalStorageAddress: cstring
|
||||
internalStorageAddress: string
|
||||
shouldTransferValue*: bool
|
||||
isStatic*: bool
|
||||
isCreate*: bool
|
||||
|
||||
MessageOptions* = ref object
|
||||
origin*: cstring
|
||||
origin*: string
|
||||
depth*: int
|
||||
createAddress*: cstring
|
||||
codeAddress*: cstring
|
||||
createAddress*: string
|
||||
codeAddress*: string
|
||||
shouldTransferValue*: bool
|
||||
isStatic*: bool
|
||||
|
||||
proc `origin=`*(message: var Message, value: cstring) =
|
||||
proc `origin=`*(message: var Message, value: string) =
|
||||
message.internalOrigin = value
|
||||
|
||||
proc `codeAddress=`*(message: var Message, value: cstring) =
|
||||
proc `codeAddress=`*(message: var Message, value: string) =
|
||||
message.internalCodeAddress = value
|
||||
|
||||
proc `storageAddress=`*(message: var Message, value: cstring) =
|
||||
proc `storageAddress=`*(message: var Message, value: string) =
|
||||
message.internalStorageAddress = value
|
||||
|
||||
proc newMessageOptions*(
|
||||
origin: cstring = nil,
|
||||
origin: string = "",
|
||||
depth: int = 0,
|
||||
createAddress: cstring = nil,
|
||||
codeAddress: cstring = nil,
|
||||
createAddress: string = "",
|
||||
codeAddress: string = "",
|
||||
shouldTransferValue: bool = true,
|
||||
isStatic: bool = false): MessageOptions =
|
||||
|
||||
@ -68,11 +68,11 @@ proc newMessageOptions*(
|
||||
proc newMessage*(
|
||||
gas: Int256,
|
||||
gasPrice: Int256,
|
||||
to: cstring,
|
||||
sender: cstring,
|
||||
to: string,
|
||||
sender: string,
|
||||
value: Int256,
|
||||
data: seq[byte],
|
||||
code: cstring,
|
||||
code: string,
|
||||
options: MessageOptions = newMessageOptions()): Message =
|
||||
|
||||
new(result)
|
||||
@ -111,8 +111,8 @@ proc newMessage*(
|
||||
|
||||
result.isStatic = options.isStatic
|
||||
|
||||
proc origin*(message: Message): cstring =
|
||||
if not message.internalOrigin.isNil:
|
||||
proc origin*(message: Message): string =
|
||||
if not message.internalOrigin.len == 0:
|
||||
message.internalOrigin
|
||||
else:
|
||||
message.sender
|
||||
@ -120,14 +120,14 @@ proc origin*(message: Message): cstring =
|
||||
proc isOrigin*(message: Message): bool =
|
||||
message.sender == message.origin
|
||||
|
||||
proc codeAddress*(message: Message): cstring =
|
||||
if not message.internalCodeAddress.isNil:
|
||||
proc codeAddress*(message: Message): string =
|
||||
if not message.internalCodeAddress.len == 0:
|
||||
message.internalCodeAddress
|
||||
else:
|
||||
message.to
|
||||
|
||||
proc `storageAddress`*(message: Message): cstring =
|
||||
if not message.internalStorageAddress.isNil:
|
||||
proc `storageAddress`*(message: Message): string =
|
||||
if not message.internalStorageAddress.len == 0:
|
||||
message.internalStorageAddress
|
||||
else:
|
||||
message.to
|
||||
|
@ -34,7 +34,7 @@ proc push*(stack: var Stack; value: Int256) =
|
||||
|
||||
stack.values.add(Value(kind: VInt, i: value))
|
||||
|
||||
proc push*(stack: var Stack; value: cstring) =
|
||||
proc push*(stack: var Stack; value: string) =
|
||||
## Push a binary onto the stack
|
||||
ensureStackLimit()
|
||||
|
||||
@ -50,13 +50,13 @@ proc internalPop(stack: var Stack; numItems: int): seq[Value] =
|
||||
template toType(i: Int256, _: typedesc[Int256]): Int256 =
|
||||
i
|
||||
|
||||
template toType(i: Int256, _: typedesc[cstring]): cstring =
|
||||
template toType(i: Int256, _: typedesc[string]): string =
|
||||
intToBigEndian(i)
|
||||
|
||||
template toType(b: cstring, _: typedesc[Int256]): Int256 =
|
||||
template toType(b: string, _: typedesc[Int256]): Int256 =
|
||||
bigEndianToInt(b)
|
||||
|
||||
template toType(b: cstring, _: typedesc[cstring]): cstring =
|
||||
template toType(b: string, _: typedesc[string]): string =
|
||||
b
|
||||
|
||||
proc internalPop(stack: var Stack; numItems: int, T: typedesc): seq[T] =
|
||||
@ -136,13 +136,13 @@ macro popInt*(stack: typed; numItems: static[int]): untyped =
|
||||
# result = stack.internalPop(numItems, Int256)
|
||||
# ensurePop(result, numItems)
|
||||
|
||||
proc popBinary*(stack: var Stack): cstring =
|
||||
var elements = stack.internalPop(1, cstring)
|
||||
proc popBinary*(stack: var Stack): string =
|
||||
var elements = stack.internalPop(1, string)
|
||||
ensurePop(elements, 1)
|
||||
result = elements[0]
|
||||
|
||||
proc popBinary*(stack: var Stack; numItems: int): seq[cstring] =
|
||||
result = stack.internalPop(numItems, cstring)
|
||||
proc popBinary*(stack: var Stack; numItems: int): seq[string] =
|
||||
result = stack.internalPop(numItems, string)
|
||||
ensurePop(result, numItems)
|
||||
|
||||
proc newStack*(): Stack =
|
||||
@ -176,7 +176,7 @@ proc getInt*(stack: Stack, position: int): Int256 =
|
||||
else:
|
||||
raise newException(TypeError, "Expected int")
|
||||
|
||||
proc getBinary*(stack: Stack, position: int): cstring =
|
||||
proc getBinary*(stack: Stack, position: int): string =
|
||||
let element = stack.values[position]
|
||||
case element.kind:
|
||||
of VBinary:
|
||||
|
@ -10,7 +10,7 @@ type
|
||||
of VInt:
|
||||
i*: Int256
|
||||
of VBinary:
|
||||
b*: cstring
|
||||
b*: string
|
||||
|
||||
proc `$`*(value: Value): string =
|
||||
case value.kind:
|
||||
@ -25,6 +25,6 @@ proc vint*(i: int): Value =
|
||||
proc vint*(i: Int256): Value =
|
||||
Value(kind: VInt, i: i)
|
||||
|
||||
proc vbinary*(b: cstring): Value =
|
||||
proc vbinary*(b: string): Value =
|
||||
Value(kind: VBinary, b: b)
|
||||
|
||||
|
@ -19,10 +19,10 @@ proc newBaseVMState*: BaseVMState =
|
||||
method logger*(vmState: BaseVMState): Logger =
|
||||
logging.getLogger(&"evm.vmState.{vmState.name}")
|
||||
|
||||
method blockhash*(vmState: BaseVMState): cstring =
|
||||
method blockhash*(vmState: BaseVMState): string =
|
||||
vmState.blockHeader.hash
|
||||
|
||||
method coinbase*(vmState: BaseVMState): cstring =
|
||||
method coinbase*(vmState: BaseVMState): string =
|
||||
vmState.blockHeader.coinbase
|
||||
|
||||
method timestamp*(vmState: BaseVMState): int =
|
||||
@ -37,11 +37,11 @@ method difficulty*(vmState: BaseVMState): Int256 =
|
||||
method gasLimit*(vmState: BaseVMState): Int256 =
|
||||
vmState.blockHeader.gasLimit
|
||||
|
||||
method getAncestorHash*(vmState: BaseVMState, blockNumber: Int256): cstring =
|
||||
method getAncestorHash*(vmState: BaseVMState, blockNumber: Int256): string =
|
||||
var ancestorDepth = vmState.blockHeader.blockNumber - blockNumber - 1.int256
|
||||
if ancestorDepth >= constants.MAX_PREV_HEADER_DEPTH or
|
||||
ancestorDepth < 0 or
|
||||
ancestorDepth >= vmState.prevHeaders.len.int256:
|
||||
return cstring""
|
||||
return ""
|
||||
var header = vmState.prevHeaders[ancestorDepth.getInt]
|
||||
result = header.hash
|
||||
|
@ -7,7 +7,7 @@ method executeTransaction(vmState: var BaseVMState, transaction: BaseTransaction
|
||||
raise newException(ValueError, "Must be implemented by subclasses")
|
||||
|
||||
|
||||
method addTransaction*(vmState: var BaseVMState, transaction: BaseTransaction, computation: BaseComputation, b: Block): (Block, Table[cstring, cstring]) =
|
||||
method addTransaction*(vmState: var BaseVMState, transaction: BaseTransaction, computation: BaseComputation, b: Block): (Block, Table[string, string]) =
|
||||
# Add a transaction to the given block and
|
||||
# return `trieData` to store the transaction data in chaindb in VM layer
|
||||
# Update the bloomFilter, transaction trie and receipt trie roots, bloom_filter,
|
||||
@ -34,13 +34,13 @@ method addTransaction*(vmState: var BaseVMState, transaction: BaseTransaction, c
|
||||
# block.header.gas_used = receipt.gas_used
|
||||
|
||||
# return block, trie_data
|
||||
result = (b, initTable[cstring, cstring]())
|
||||
result = (b, initTable[string, string]())
|
||||
|
||||
method applyTransaction*(
|
||||
vmState: var BaseVMState,
|
||||
transaction: BaseTransaction,
|
||||
b: Block,
|
||||
isStateless: bool): (BaseComputation, Block, Table[cstring, cstring]) =
|
||||
isStateless: bool): (BaseComputation, Block, Table[string, string]) =
|
||||
# Apply transaction to the given block
|
||||
# transaction: the transaction need to be applied
|
||||
# b: the block which the transaction applies on
|
||||
@ -52,10 +52,10 @@ method applyTransaction*(
|
||||
var (computation, blockHeader) = vmState.executeTransaction(transaction)
|
||||
|
||||
ourBlock.header = blockHeader
|
||||
var trieData: Table[cstring, cstring]
|
||||
var trieData: Table[string, string]
|
||||
(ourBlock, trieData) = vmState.addTransaction(transaction, computation, ourBlock)
|
||||
|
||||
result = (computation, ourBlock, trieData)
|
||||
else:
|
||||
var (computation, blockHeader) = vmState.executeTransaction(transaction)
|
||||
return (computation, nil, initTable[cstring, cstring]())
|
||||
return (computation, nil, initTable[string, string]())
|
||||
|
8
tests/README.md
Normal file
8
tests/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# tests
|
||||
|
||||
TODO: more vm tests and fixtures!
|
||||
|
||||
```bash
|
||||
nim c tests/code_stream_test.nim
|
||||
./tests/code_stream_test
|
||||
```
|
108
tests/code_stream_test.nim
Normal file
108
tests/code_stream_test.nim
Normal file
@ -0,0 +1,108 @@
|
||||
import unittest, strutils, sequtils, opcode_values, vm / code_stream
|
||||
|
||||
suite "parse bytecode":
|
||||
test "accepts bytes":
|
||||
let codeStream = newCodeStream("\x01")
|
||||
check(codeStream.len == 1)
|
||||
|
||||
|
||||
# quicktest
|
||||
# @pytest.mark.parametrize("code_bytes", (1010, '1010', True, bytearray(32)))
|
||||
# def test_codeStream_rejects_invalid_code_byte_values(code_bytes):
|
||||
# with pytest.raises(ValidationError):
|
||||
# CodeStream(code_bytes)
|
||||
|
||||
test "next returns the correct opcode":
|
||||
var codeStream = newCodeStream("\x01\x02\x30")
|
||||
check(codeStream.next == Op.ADD)
|
||||
check(codeStream.next == Op.MUL)
|
||||
check(codeStream.next == Op.ADDRESS)
|
||||
|
||||
|
||||
test "peek returns next opcode without changing location":
|
||||
var codeStream = newCodeStream("\x01\x02\x30")
|
||||
check(codeStream.pc == 0)
|
||||
check(codeStream.peek == Op.ADD)
|
||||
check(codeStream.pc == 0)
|
||||
check(codeStream.next == Op.ADD)
|
||||
check(codeStream.pc == 1)
|
||||
check(codeStream.peek == Op.MUL)
|
||||
check(codeStream.pc == 1)
|
||||
|
||||
|
||||
test "stop opcode is returned when end reached":
|
||||
var codeStream = newCodeStream("\x01\x02")
|
||||
discard codeStream.next
|
||||
discard codeStream.next
|
||||
check(codeStream.next == Op.STOP)
|
||||
|
||||
test "seek reverts to original position on exit":
|
||||
var codeStream = newCodeStream("\x01\x02\x30")
|
||||
check(codeStream.pc == 0)
|
||||
codeStream.seek(1):
|
||||
check(codeStream.pc == 1)
|
||||
check(codeStream.next == Op.MUL)
|
||||
check(codeStream.pc == 0)
|
||||
check(codeStream.peek == Op.ADD)
|
||||
|
||||
test "[] returns opcode":
|
||||
let codeStream = newCodeStream("\x01\x02\x30")
|
||||
check(codeStream[0] == Op.ADD)
|
||||
check(codeStream[1] == Op.MUL)
|
||||
check(codeStream[2] == Op.ADDRESS)
|
||||
|
||||
test "isValidOpcode invalidates after PUSHXX":
|
||||
var codeStream = newCodeStream("\x02\x60\x02\x04")
|
||||
check(codeStream.isValidOpcode(0))
|
||||
check(codeStream.isValidOpcode(1))
|
||||
check(not codeStream.isValidOpcode(2))
|
||||
check(codeStream.isValidOpcode(3))
|
||||
check(not codeStream.isValidOpcode(4))
|
||||
|
||||
|
||||
test "isValidOpcode 0":
|
||||
var codeStream = newCodeStream(@[2.byte, 3.byte, 0x72.byte].concat(repeat(4.byte, 32)).concat(@[5.byte]))
|
||||
# valid: 0 - 2 :: 22 - 35
|
||||
# invalid: 3-21 (PUSH19) :: 36+ (too long)
|
||||
check(codeStream.isValidOpcode(0))
|
||||
check(codeStream.isValidOpcode(1))
|
||||
check(codeStream.isValidOpcode(2))
|
||||
check(not codeStream.isValidOpcode(3))
|
||||
check(not codeStream.isValidOpcode(21))
|
||||
check(codeStream.isValidOpcode(22))
|
||||
check(codeStream.isValidOpcode(35))
|
||||
check(not codeStream.isValidOpcode(36))
|
||||
|
||||
|
||||
test "isValidOpcode 1":
|
||||
let test = @[2.byte, 3.byte, 0x7d.byte].concat(repeat(4.byte, 32)).concat(@[5.byte, 0x7e.byte]).concat(repeat(4.byte, 35)).concat(@[1.byte, 0x61.byte, 1.byte, 1.byte, 1.byte])
|
||||
var codeStream = newCodeStream(test)
|
||||
# valid: 0 - 2 :: 33 - 36 :: 68 - 73 :: 76
|
||||
# invalid: 3 - 32 (PUSH30) :: 37 - 67 (PUSH31) :: 74, 75 (PUSH2) :: 77+ (too long)
|
||||
check(codeStream.isValidOpcode(0))
|
||||
check(codeStream.isValidOpcode(1))
|
||||
check(codeStream.isValidOpcode(2))
|
||||
check(not codeStream.isValidOpcode(3))
|
||||
check(not codeStream.isValidOpcode(32))
|
||||
check(codeStream.isValidOpcode(33))
|
||||
check(codeStream.isValidOpcode(36))
|
||||
check(not codeStream.isValidOpcode(37))
|
||||
check(not codeStream.isValidOpcode(67))
|
||||
check(codeStream.isValidOpcode(68))
|
||||
check(codeStream.isValidOpcode(71))
|
||||
check(codeStream.isValidOpcode(72))
|
||||
check(codeStream.isValidOpcode(73))
|
||||
check(not codeStream.isValidOpcode(74))
|
||||
check(not codeStream.isValidOpcode(75))
|
||||
check(codeStream.isValidOpcode(76))
|
||||
check(not codeStream.isValidOpcode(77))
|
||||
|
||||
|
||||
test "right number of bytes invalidates":
|
||||
var codeStream = newCodeStream("\x02\x03\x60\x02\x02")
|
||||
check(codeStream.isValidOpcode(0))
|
||||
check(codeStream.isValidOpcode(1))
|
||||
check(codeStream.isValidOpcode(2))
|
||||
check(not codeStream.isValidOpcode(3))
|
||||
check(codeStream.isValidOpcode(4))
|
||||
check(not codeStream.isValidOpcode(5))
|
1
tests/nim.cfg
Normal file
1
tests/nim.cfg
Normal file
@ -0,0 +1 @@
|
||||
-p:"../src"
|
Loading…
x
Reference in New Issue
Block a user