Work on text fitures and decompiling bytecode

This commit is contained in:
Alexander Ivanov 2018-02-12 18:59:12 +02:00
parent 925eb627a5
commit 0d31382e3d
15 changed files with 116 additions and 28 deletions

7
examples/a.nim Normal file
View File

@ -0,0 +1,7 @@
import vm/code_stream, opcode_values
var c = newCodeStream("\x60\x00\x60\x00\x60\x00\x60\x00\x67\x06\xf0\x5b\x59\xd3\xb2\x00\x00\x33\x60\xc8\x5a\x03\xf1")
let opcodes = c.decompile()
for op in opcodes:
echo op[0], " ", op[1], " ", op[2]

1
examples/nim.cfg Normal file
View File

@ -0,0 +1 @@
-p:"../src"

View File

@ -1,5 +1,5 @@
import import
logging, constants, utils/header logging, constants, utils / header, ttmath
type type
CountableList*[T] = ref object CountableList*[T] = ref object

View File

@ -1,6 +1,6 @@
import import
tables, tables, ttmath,
logging, constants, errors, validation, utils / [hexadecimal] logging, constants, errors, validation, utils / hexadecimal, vm / base, db / db_chain
type type
BlockHeader* = ref object BlockHeader* = ref object
@ -18,6 +18,9 @@ type
importBlock*: bool importBlock*: bool
validateBlock*: bool validateBlock*: bool
db*: BaseChainDB db*: BaseChainDB
fundedAddress*: string
fundedAddressInitialBalance*: int
fundedAddressPrivateKey*: string
GenesisParams* = ref object GenesisParams* = ref object
blockNumber*: Int256 blockNumber*: Int256
@ -25,11 +28,11 @@ type
gasLimit*: Int256 gasLimit*: Int256
parentHash*: string parentHash*: string
coinbase*: string coinbase*: string
nonce: string nonce*: string
mixHash: string mixHash*: string
extraData: string extraData*: string
timestamp: int, timestamp*: int
stateRoot: string stateRoot*: string
FundedAddress* = ref object FundedAddress* = ref object
balance*: Int256 balance*: Int256
@ -40,6 +43,8 @@ type
proc configureChain*(name: string, blockNumber: Int256, vm: VM, importBlock: bool = true, validateBlock: bool = true): Chain = proc configureChain*(name: string, blockNumber: Int256, vm: VM, importBlock: bool = true, validateBlock: bool = true): Chain =
new(result) new(result)
result.vmsByRange = @[(blockNumber: blockNumber, vm: vm)] result.vmsByRange = @[(blockNumber: blockNumber, vm: vm)]
result.importBlock = importBlock
result.validateBlock = validateBlock
proc fromGenesis*( proc fromGenesis*(
chain: Chain, chain: Chain,
@ -48,13 +53,18 @@ proc fromGenesis*(
genesisState: Table[string, FundedAddress]): Chain = genesisState: Table[string, FundedAddress]): Chain =
## Initialize the Chain from a genesis state ## Initialize the Chain from a genesis state
var stateDB = chaindb.getStateDB(BLANK_ROOT_HASH) var stateDB = chaindb.getStateDB(BLANK_ROOT_HASH)
for account, accountData in genesisState: # TODO
stateDB.setBalance(account, accountData.balance) # for account, accountData in genesisState:
stateDB.setNonce(account, accountData.nonce) # stateDB.setBalance(account, accountData.balance)
stateDB.setCode(account, accountData.code) # stateDB.setNonce(account, accountData.nonce)
# stateDB.setCode(account, accountData.code)
new(result) new(result)
result.db = chainDB result.db = chainDB
result.header = BlockHeader() result.header = BlockHeader()
result.logger = logging.getLogger("evm.chain.chain.Chain") result.logger = logging.getLogger("evm.chain.chain.Chain")
chainDB.persistBlockToDB(result.getBlock()) result.importBlock = chain.importBlock
result.validateBlock = chain.validateBlock
result.vmsByRange = chain.vmsByRange
# TODO
# chainDB.persistBlockToDB(result.getBlock)

View File

@ -191,7 +191,7 @@ let
GENESIS_COINBASE* = ZERO_ADDRESS GENESIS_COINBASE* = ZERO_ADDRESS
GENESIS_NONCE* = "\x00\x00\x00\x00\x00\x00\x00B" GENESIS_NONCE* = "\x00\x00\x00\x00\x00\x00\x00B"
GENESIS_MIX_HASH* = ZERO_HASH32 GENESIS_MIX_HASH* = ZERO_HASH32
GENESIS_EXTRA_DATA = "" GENESIS_EXTRA_DATA* = ""
EMPTYSHA3 = "\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p" 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* = "V\xe8\x1f\x17\x1b\xccU\xa6\xff\x83E\xe6\x92\xc0\xf8n[H\xe0\x1b\x99l\xad\xc0\x01b/\xb5\xe3c\xb4!"

View File

@ -0,0 +1,23 @@
import tables, ttmath
type
MemoryDB* = ref object
kvStore*: Table[string, Int256]
proc newMemoryDB*(kvStore: Table[string, Int256]): MemoryDB =
MemoryDB(kvStore: kvStore)
proc newMemoryDB*: MemoryDB =
MemoryDB(kvStore: initTable[string, Int256]())
proc get*(db: MemoryDB, key: string): Int256 =
db.kvStore[key]
proc set*(db: var MemoryDB, key: string, value: Int256) =
db.kvStore[key] = value
proc exists*(db: MemoryDB, key: string): bool =
db.kvStore.hasKey(key)
proc delete*(db: var MemoryDB, key: string) =
db.kvStore.del(key)

View File

@ -1,12 +1,15 @@
import strformat, tables, ttmath, state_db, backends / memory_backend
type type
BaseChainDB* = ref object BaseChainDB* = ref object
db*: MemoryDB
# TODO db*: JournalDB # TODO db*: JournalDB
# proc makeBaseChainDB*(db: MemoryDB): BaseChainDB = proc newBaseChainDB*(db: MemoryDB): BaseChainDB =
# result.db = JournalDB(db) result.db = db
# proc exists*(self: BaseChainDB; key: cstring): bool = proc exists*(self: BaseChainDB; key: string): bool =
# return self.db.exists(key) return self.db.exists(key)
# proc getCanonicalHead*(self: BaseChainDB): BlockHeader = # proc getCanonicalHead*(self: BaseChainDB): BlockHeader =
# if notself.exists(CANONICALHEADHASHDBKEY): # if notself.exists(CANONICALHEADHASHDBKEY):
@ -145,7 +148,7 @@ type
# proc clear*(self: BaseChainDB): void = # proc clear*(self: BaseChainDB): void =
# self.db.clear() # self.db.clear()
# proc getStateDb*(self: BaseChainDB; stateRoot: cstring; readOnly: bool): AccountStateDB = method getStateDb*(self: BaseChainDB; stateRoot: string; readOnly: bool = false): AccountStateDB =
# return AccountStateDB() return newAccountStateDB(initTable[string, Int256]())
# var CANONICALHEADHASHDBKEY = cstring"v1:canonical_head_hash" # var CANONICALHEADHASHDBKEY = cstring"v1:canonical_head_hash"

View File

@ -1,5 +1,5 @@
import import
../logging, ../constants, ../errors, ../transaction, ../computation, "../block", ../vm_state, ../vm_state_transactions, ../db/chain, ../utils/header ../logging, ../constants, ../errors, ../transaction, ../computation, "../block", ../vm_state, ../vm_state_transactions, ../db/db_chain, ../utils/header
type type
VM* = ref object of RootObj VM* = ref object of RootObj

View File

@ -94,3 +94,19 @@ proc isValidOpcode*(c: var CodeStream, position: int): bool =
return false return false
else: else:
return true return true
proc decompile*(original: CodeStream): seq[(int, Op, string)] =
# behave as https://etherscan.io/opcode-tool
# TODO
result = @[]
var c = newCodeStream(original.bytes)
while true:
var op = c.next
if op >= PUSH1 and op <= PUSH32:
let bytes = c.read(op.int - 95)
result.add((c.pc - 1, op, "0x" & bytes.mapIt($(it.BiggestInt.toHex(2))).join("")))
elif op != Op.Stop:
result.add((c.pc - 1, op, ""))
else:
result.add((-1, Op.STOP, ""))
break

View File

@ -1,6 +1,6 @@
import import
strformat, strformat,
constants, errors, vm_state, transaction, utils/header constants, errors, ttmath, vm_state, transaction, utils/header
proc validateFrontierTransaction*(vmState: BaseVmState, transaction: BaseTransaction) = proc validateFrontierTransaction*(vmState: BaseVmState, transaction: BaseTransaction) =
let gasCost = transaction.gas * transaction.gasPrice let gasCost = transaction.gas * transaction.gasPrice
@ -9,7 +9,7 @@ proc validateFrontierTransaction*(vmState: BaseVmState, transaction: BaseTransac
# senderBalance = db.getBalance(transaction.sender) # senderBalance = db.getBalance(transaction.sender)
senderBalance = gasCost # TODO senderBalance = gasCost # TODO
if senderBalance < gasCost: if senderBalance < gasCost:
raise newException(ValidationError, %"Sender account balance cannot afford txn gas: {transaction.sender}") raise newException(ValidationError, &"Sender account balance cannot afford txn gas: {transaction.sender}")
let totalCost = transaction.value + gasCost let totalCost = transaction.value + gasCost

View File

@ -1,5 +1,5 @@
import import
logging, constants, errors, vm_state, utils/header, db/chain logging, constants, errors, vm_state, utils/header, db/db_chain
type type
FrontierVMState* = object of BaseVMState FrontierVMState* = object of BaseVMState

View File

@ -1,5 +1,5 @@
import import
logging, constants, errors, "block", vm / [base, stack], db / chain, utils / header, logging, constants, errors, ttmath, "block", vm / [base, stack], db / db_chain, utils / header,
frontier_block, frontier_vm_state, frontier_validation frontier_block, frontier_vm_state, frontier_validation

View File

@ -1,6 +1,6 @@
import import
strformat, tables, strformat, tables,
logging, constants, ttmath, errors, transaction, db/chain, utils/state, utils/header logging, constants, ttmath, errors, transaction, db/db_chain, utils/state, utils/header
type type
BaseVMState* = ref object of RootObj BaseVMState* = ref object of RootObj

View File

@ -1,6 +1,6 @@
import import
strformat, tables, strformat, tables,
logging, constants, errors, computation, transaction, vm_state, "block", db/chain, utils/state, utils/header logging, constants, errors, computation, transaction, vm_state, "block", db / db_chain, utils / [state, header]
method executeTransaction(vmState: var BaseVMState, transaction: BaseTransaction): (BaseComputation, Header) = method executeTransaction(vmState: var BaseVMState, transaction: BaseTransaction): (BaseComputation, Header) =
# Execute the transaction in the vm # Execute the transaction in the vm

28
tests/fixtures.nim Normal file
View File

@ -0,0 +1,28 @@
import unittest, strformat, tables, constants, chain, ttmath, vm / forks / frontier / vm, utils / [header, address], db / db_chain, db / backends / memory_backend
proc chainWithoutBlockValidation: Chain =
result = configureChain("TestChain", GENESIS_BLOCK_NUMBER, newFrontierVM(Header(), newBaseChainDB(newMemoryDB())), false, false)
let privateKey = "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" # TODO privateKey(decodeHex("0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"))
let fundedAddr = privateKey # privateKey.publicKey.toCanonicalAddress
let initialBalance = 100_000_000
let genesisParams = GenesisParams(
blockNumber: GENESIS_BLOCK_NUMBER,
difficulty: GENESIS_DIFFICULTY,
gasLimit: GENESIS_GAS_LIMIT,
parentHash: GENESIS_PARENT_HASH,
coinbase: GENESIS_COINBASE,
nonce: GENESIS_NONCE,
mixHash: GENESIS_MIX_HASH,
extraData: GENESIS_EXTRA_DATA,
timestamp: 1501851927,
stateRoot: "0x9d354f9b5ba851a35eced279ef377111387197581429cfcc7f744ef89a30b5d4") #.decodeHex)
let genesisState = {"fundedAddr": FundedAddress(balance: initialBalance.int256, nonce: 0, code: "")}.toTable()
result = fromGenesis(
result,
newBaseChainDB(newMemoryDB()),
genesisParams,
genesisState)
result.fundedAddress = fundedAddr
result.fundedAddressInitialBalance = initialBalance
result.fundedAddressPrivateKey = privateKey