This commit is contained in:
andri lim 2018-12-31 10:27:02 +07:00 committed by zah
parent 041ed689aa
commit e78fb72ef6
13 changed files with 140 additions and 96 deletions

View File

@ -13,11 +13,6 @@ import
type
BaseChainDB* = ref object
db* : TrieDatabaseRef
# XXX: intentionally simple stand-in for one use of full JournalDB
# Doesn't handle CREATE+revert, etc. But also creates minimal tech
# debt while setting a CI baseline from which to improve/replace.
accountCodes*: TableRef[Hash256, ByteRange]
# TODO db*: JournalDB
pruneTrie*: bool
KeyType = enum
@ -31,7 +26,6 @@ type
proc newBaseChainDB*(db: TrieDatabaseRef, pruneTrie: bool = true): BaseChainDB =
new(result)
result.db = db
result.accountCodes = newTable[Hash256, ByteRange]()
result.pruneTrie = pruneTrie
proc `$`*(db: BaseChainDB): string =
@ -263,34 +257,6 @@ proc persistBlockToDb*(self: BaseChainDB; blk: Block): ValidationResult =
debug "ommersHash mismatch"
return ValidationResult.Error
# proc addTransaction*(self: BaseChainDB; blockHeader: BlockHeader; indexKey: cstring;
# transaction: FrontierTransaction): cstring =
# var transactionDb = HexaryTrie(self.db)
# transactionDb[indexKey] = rlp.encode(transaction)
# return transactionDb.rootHash
# proc addReceipt*(self: BaseChainDB; blockHeader: BlockHeader; indexKey: cstring;
# receipt: Receipt): cstring =
# var receiptDb = HexaryTrie()
# receiptDb[indexKey] = rlp.encode(receipt)
# return receiptDb.rootHash
#proc snapshot*(self: BaseChainDB): UUID =
# Snapshots are a combination of the state_root at the time of the
# snapshot and the id of the changeset from the journaled DB.
#return self.db.snapshot()
# proc commit*(self: BaseChainDB; checkpoint: UUID): void =
# self.db.commit(checkpoint)
# proc clear*(self: BaseChainDB): void =
# self.db.clear()
proc getStateDb*(self: BaseChainDB; stateRoot: Hash256; readOnly: bool = false): AccountStateDB =
# TODO: readOnly is not used.
result = newAccountStateDB(self.db, stateRoot, self.pruneTrie, readOnly, self.accountCodes)
# Deprecated:
proc getBlockHeaderByHash*(self: BaseChainDB; blockHash: Hash256): BlockHeader {.deprecated.} =
self.getBlockHeader(blockHash)

View File

@ -1,4 +1,4 @@
const nimbus_db_backend {.strdefine.} = "rocksdb"
const nimbus_db_backend* {.strdefine.} = "rocksdb"
when nimbus_db_backend == "sqlite":
import ./backends/sqlite_backend as database_backend

View File

@ -17,20 +17,19 @@ logScope:
type
AccountStateDB* = ref object
trie: SecureHexaryTrie
accountCodes: TableRef[Hash256, ByteRange]
proc rootHash*(accountDb: AccountStateDB): KeccakHash =
accountDb.trie.rootHash
ReadOnlyStateDB* = distinct AccountStateDB
# proc `rootHash=`*(db: var AccountStateDB, value: string) =
# TODO: self.Trie.rootHash = value
proc rootHash*(db: AccountStateDB): KeccakHash =
db.trie.rootHash
proc `rootHash=`*(db: AccountStateDB, root: KeccakHash) =
db.trie = initSecureHexaryTrie(HexaryTrie(db.trie).db, root, db.trie.isPruning)
proc newAccountStateDB*(backingStore: TrieDatabaseRef,
root: KeccakHash, pruneTrie: bool, readOnly: bool = false,
accountCodes = newTable[Hash256, ByteRange]()): AccountStateDB =
root: KeccakHash, pruneTrie: bool): AccountStateDB =
result.new()
result.trie = initSecureHexaryTrie(backingStore, root, pruneTrie)
result.accountCodes = accountCodes
template createRangeFromAddress(address: EthAddress): ByteRange =
## XXX: The name of this proc is intentionally long, because it
@ -142,7 +141,7 @@ proc getStorage*(db: AccountStateDB, address: EthAddress, slot: UInt256): (UInt2
else:
result = (0.u256, false)
proc setNonce*(db: var AccountStateDB, address: EthAddress, newNonce: AccountNonce) =
proc setNonce*(db: AccountStateDB, address: EthAddress, newNonce: AccountNonce) =
var account = db.getAccount(address)
if newNonce != account.nonce:
account.nonce = newNonce
@ -152,18 +151,25 @@ proc getNonce*(db: AccountStateDB, address: EthAddress): AccountNonce =
let account = db.getAccount(address)
account.nonce
proc setCode*(db: var AccountStateDB, address: EthAddress, code: ByteRange) =
proc setCode*(db: AccountStateDB, address: EthAddress, code: ByteRange) =
var account = db.getAccount(address)
let newCodeHash = keccak256.digest code.toOpenArray
if newCodeHash != account.codeHash:
# TODO: implement JournalDB to store code and storage
# also use JournalDB to revert state trie
let
newCodeHash = keccak256.digest code.toOpenArray
triedb = HexaryTrie(db.trie).db
if code.len != 0:
triedb.put(contractHashKey(newCodeHash).toOpenArray, code.toOpenArray)
account.codeHash = newCodeHash
db.accountCodes[newCodeHash] = code
# XXX: this uses the journaldb in py-evm
# db.trie.put(account.codeHash.toByteRange_Unnecessary, code)
db.setAccount(address, account)
proc getCode*(db: AccountStateDB, address: EthAddress): ByteRange =
db.accountCodes.getOrDefault(db.getCodeHash(address))
let triedb = HexaryTrie(db.trie).db
let data = triedb.get(contractHashKey(db.getCodeHash(address)).toOpenArray)
data.toRange
proc hasCodeOrNonce*(account: AccountStateDB, address: EthAddress): bool {.inline.} =
account.getNonce(address) != 0 or account.getCodeHash(address) != EMPTY_SHA3
@ -172,3 +178,12 @@ proc dumpAccount*(db: AccountStateDB, addressS: string): string =
let address = addressS.parseAddress
return fmt"{addressS}: Storage: {db.getStorage(address, 0.u256)}; getAccount: {db.getAccount address}"
proc rootHash*(db: ReadOnlyStateDB): KeccakHash {.borrow.}
proc getAccount*(db: ReadOnlyStateDB, address: EthAddress): Account {.borrow.}
proc getCodeHash*(db: ReadOnlyStateDB, address: EthAddress): Hash256 {.borrow.}
proc getBalance*(db: ReadOnlyStateDB, address: EthAddress): UInt256 {.borrow.}
proc getStorageRoot*(db: ReadOnlyStateDB, address: EthAddress): Hash256 {.borrow.}
proc getStorage*(db: ReadOnlyStateDB, address: EthAddress, slot: UInt256): (UInt256, bool) {.borrow.}
proc getNonce*(db: ReadOnlyStateDB, address: EthAddress): AccountNonce {.borrow.}
proc getCode*(db: ReadOnlyStateDB, address: EthAddress): ByteRange {.borrow.}
proc hasCodeOrNonce*(account: ReadOnlyStateDB, address: EthAddress): bool {.borrow.}

View File

@ -9,6 +9,7 @@ type
transactionHashToBlock
canonicalHeadHash
slotHashToSlot
contractHash
DbKey* = object
# The first byte stores the key type. The rest are key-specific values
@ -48,6 +49,11 @@ proc slotHashToSlotKey*(h: openArray[byte]): DbKey {.inline.} =
result.data[1 .. 32] = h
result.dataEndPos = uint8 32
proc contractHashKey*(h: Hash256): DbKey {.inline.} =
result.data[0] = byte ord(contractHash)
result.data[1 .. 32] = h.data
result.dataEndPos = uint8 32
const hashHolderKinds = {genericHash, blockHashToScore, transactionHashToBlock}
template toOpenArray*(k: DbKey): openarray[byte] =

View File

@ -1,15 +1,54 @@
import eth_common, ranges, chronicles, eth_bloom, nimcrypto,
import options,
eth_common, ranges, chronicles, eth_bloom, nimcrypto,
../db/[db_chain, state_db],
../utils, ../constants, ../transaction,
../vm_state, ../vm_types, ../vm_state_transactions,
../vm/[computation, interpreter_dispatch, message],
../vm/interpreter/vm_forks
proc processTransaction*(db: var AccountStateDB, t: Transaction, sender: EthAddress, vmState: BaseVMState): UInt256 =
proc contractCall(t: Transaction, vmState: BaseVMState, sender: EthAddress, forkOverride=none(Fork)): UInt256 =
# TODO: this function body was copied from GST with it's comments and TODOs.
# Right now it's main purpose is to produce VM tracing when syncing block with
# contract call. At later stage, this proc together with applyCreateTransaction
# and processTransaction need to be restructured.
# TODO: replace with cachingDb or similar approach; necessary
# when calls/subcalls/etc come in, too.
var db = vmState.accountDb
let storageRoot = db.getStorageRoot(t.to)
var computation = setupComputation(vmState, t, sender, forkOverride)
# contract creation transaction.to == 0, so ensure happens after
db.addBalance(t.to, t.value)
let header = vmState.blockHeader
let gasCost = t.gasLimit.u256 * t.gasPrice.u256
if execComputation(computation):
let
gasRemaining = computation.gasMeter.gasRemaining.u256
gasRefunded = computation.gasMeter.gasRefunded.u256
gasUsed = t.gasLimit.u256 - gasRemaining
gasRefund = min(gasRefunded, gasUsed div 2)
gasRefundAmount = (gasRefund + gasRemaining) * t.gasPrice.u256
db.addBalance(sender, gasRefundAmount)
return (t.gasLimit.u256 - gasRemaining - gasRefund) * t.gasPrice.u256
else:
db.subBalance(t.to, t.value)
db.addBalance(sender, t.value)
db.setStorageRoot(t.to, storageRoot)
if computation.tracingEnabled: computation.traceError()
vmState.clearLogs()
return t.gasLimit.u256 * t.gasPrice.u256
proc processTransaction*(t: Transaction, sender: EthAddress, vmState: BaseVMState): UInt256 =
## Process the transaction, write the results to db.
## Returns amount of ETH to be rewarded to miner
trace "Sender", sender
trace "txHash", rlpHash = t.rlpHash
var db = vmState.accountDb
# Inct nonce:
db.setNonce(sender, db.getNonce(sender) + 1)
var transactionFailed = false
@ -43,7 +82,7 @@ proc processTransaction*(db: var AccountStateDB, t: Transaction, sender: EthAddr
else:
if t.isContractCreation:
# TODO: re-derive sender in callee for cleaner interface, perhaps
return applyCreateTransaction(db, t, vmState, sender)
return applyCreateTransaction(t, vmState, sender)
else:
let code = db.getCode(t.to)
@ -56,8 +95,9 @@ proc processTransaction*(db: var AccountStateDB, t: Transaction, sender: EthAddr
# Contract call
trace "Contract call"
trace "Transaction", sender, to = t.to, value = t.value, hasCode = code.len != 0
let msg = newMessage(t.gasLimit, t.gasPrice, t.to, sender, t.value, t.payload, code.toSeq)
# TODO: Run the vm
#let msg = newMessage(t.gasLimit, t.gasPrice, t.to, sender, t.value, t.payload, code.toSeq)
# TODO: Run the vm with proper fork
return contractCall(t, vmState, sender)
if gasUsed > t.gasLimit:
gasUsed = t.gasLimit
@ -88,12 +128,9 @@ func createBloom*(receipts: openArray[Receipt]): Bloom =
bloom.value = bloom.value or logsBloom(receipt.logs).value
result = bloom.value.toByteArrayBE
proc makeReceipt(vmState: BaseVMState, stateRoot: Hash256, cumulativeGasUsed: GasInt, fork = FkFrontier): Receipt =
proc makeReceipt(vmState: BaseVMState, cumulativeGasUsed: GasInt, fork = FkFrontier): Receipt =
if fork < FkByzantium:
# TODO: which one: vmState.blockHeader.stateRoot or stateDb.rootHash?
# currently, vmState.blockHeader.stateRoot vs stateDb.rootHash can be different
# need to wait #188 solved
result.stateRootOrStatus = hashOrStatus(stateRoot)
result.stateRootOrStatus = hashOrStatus(vmState.accountDb.rootHash)
else:
# TODO: post byzantium fork use status instead of rootHash
let vmStatus = true # success or failure
@ -106,12 +143,11 @@ proc makeReceipt(vmState: BaseVMState, stateRoot: Hash256, cumulativeGasUsed: Ga
proc processBlock*(chainDB: BaseChainDB, head, header: BlockHeader, body: BlockBody, vmState: BaseVMState): ValidationResult =
let blockReward = 5.u256 * pow(10.u256, 18) # 5 ETH
var stateDb = newAccountStateDB(chainDB.db, head.stateRoot, chainDB.pruneTrie)
if body.transactions.calcTxRoot != header.txRoot:
debug "Mismatched txRoot", blockNumber=header.blockNumber
return ValidationResult.Error
var stateDb = vmState.accountDb
if header.txRoot != BLANK_ROOT_HASH:
if body.transactions.len == 0:
debug "No transactions in body", blockNumber=header.blockNumber
@ -124,7 +160,7 @@ proc processBlock*(chainDB: BaseChainDB, head, header: BlockHeader, body: BlockB
for txIndex, tx in body.transactions:
var sender: EthAddress
if tx.getSender(sender):
let txFee = processTransaction(stateDb, tx, sender, vmState)
let txFee = processTransaction(tx, sender, vmState)
# perhaps this can be altered somehow
# or processTransaction return only gasUsed
@ -137,7 +173,7 @@ proc processBlock*(chainDB: BaseChainDB, head, header: BlockHeader, body: BlockB
else:
debug "Could not get sender", txIndex, tx
return ValidationResult.Error
vmState.receipts[txIndex] = makeReceipt(vmState, stateDb.rootHash, cumulativeGasUsed)
vmState.receipts[txIndex] = makeReceipt(vmState, cumulativeGasUsed)
var mainReward = blockReward
if header.ommersHash != EMPTY_UNCLE_HASH:

View File

@ -29,18 +29,18 @@ import
proc `%`*(value: Time): JsonNode =
result = %value.toSeconds
template balance(addressDb: AccountStateDb, address: EthAddress): GasInt =
template balance(addressDb: ReadOnlyStateDb, address: EthAddress): GasInt =
# TODO: Account balance u256 but GasInt is int64?
addressDb.getBalance(address).truncate(int64)
proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
func getAccountDb(header: BlockHeader, readOnly = true): AccountStateDb =
func getAccountDb(header: BlockHeader): ReadOnlyStateDB =
## Retrieves the account db from canonical head
let vmState = newBaseVMState(header, chain)
result = vmState.chaindb.getStateDb(vmState.blockHeader.hash, readOnly)
result = vmState.readOnlyStateDB()
func accountDbFromTag(tag: string, readOnly = true): AccountStateDb =
func accountDbFromTag(tag: string, readOnly = true): ReadOnlyStateDB =
result = getAccountDb(chain.headerFromTag(tag))
proc getBlockBody(hash: KeccakHash): BlockBody =
@ -188,7 +188,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
## data: address.
## message: message to sign.
## Returns signature.
let accountDb = getAccountDb(chain.getCanonicalHead(), true)
let accountDb = getAccountDb(chain.getCanonicalHead())
var privateKey: PrivateKey # TODO: Get from key store
result = ("0x" & sign(privateKey, message.string)).HexDataStr
@ -341,7 +341,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
proc populateTransactionObject(transaction: Transaction, txIndex: int64, blockHeader: BlockHeader, blockHash: Hash256): TransactionObject =
let
vmState = newBaseVMState(blockHeader, chain)
accountDb = vmState.chaindb.getStateDb(blockHash, true)
accountDb = vmState.readOnlyStateDB()
address = transaction.getSender()
txCount = accountDb.getNonce(address)
txHash = transaction.rlpHash

View File

@ -27,7 +27,7 @@ proc dumpReceipts*(chainDB: BaseChainDB, header: BlockHeader): JsonNode =
for receipt in chainDB.getReceipts(header):
result.add receipt.toJson
proc toJson(receipts: seq[Receipt]): JsonNode =
proc toJson*(receipts: seq[Receipt]): JsonNode =
result = newJArray()
for receipt in receipts:
result.add receipt.toJson
@ -88,7 +88,7 @@ proc traceTransaction*(db: BaseChainDB, header: BlockHeader,
captureChainDB = newBaseChainDB(captureTrieDB, false) # prune or not prune?
vmState = newBaseVMState(parent, captureChainDB, tracerFlags + {EnableAccount})
var stateDb = newAccountStateDB(captureTrieDB, parent.stateRoot, db.pruneTrie)
var stateDb = vmState.accountDb
if header.txRoot == BLANK_ROOT_HASH: return newJNull()
assert(body.transactions.calcTxRoot == header.txRoot)
@ -113,7 +113,7 @@ proc traceTransaction*(db: BaseChainDB, header: BlockHeader,
stateDiff["beforeRoot"] = %($stateDb.rootHash)
beforeRoot = stateDb.rootHash
let txFee = processTransaction(stateDb, tx, sender, vmState)
let txFee = processTransaction(tx, sender, vmState)
stateDb.addBalance(header.coinbase, txFee)
if idx == txIndex:
@ -203,9 +203,6 @@ proc traceBlock*(db: BaseChainDB, header: BlockHeader, body: BlockBody, tracerFl
captureChainDB = newBaseChainDB(captureTrieDB, false)
vmState = newBaseVMState(parent, captureChainDB, tracerFlags + {EnableTracing})
var
stateDb = newAccountStateDB(captureTrieDB, parent.stateRoot, db.pruneTrie)
if header.txRoot == BLANK_ROOT_HASH: return newJNull()
assert(body.transactions.calcTxRoot == header.txRoot)
assert(body.transactions.len != 0)
@ -215,7 +212,7 @@ proc traceBlock*(db: BaseChainDB, header: BlockHeader, body: BlockBody, tracerFl
for tx in body.transactions:
let
sender = tx.getSender
txFee = processTransaction(stateDb, tx, sender, vmState)
txFee = processTransaction(tx, sender, vmState)
gasUsed = gasUsed + (txFee div tx.gasPrice.u256).truncate(GasInt)
result = vmState.getTracingResult()

View File

@ -99,8 +99,8 @@ proc applyMessage(computation: var BaseComputation, opCode: static[Op]) =
if computation.msg.value != 0:
let senderBalance =
computation.vmState.chainDb.getStateDb(
computation.vmState.blockHeader.hash, false).
computation.vmState.getStateDb(
computation.vmState.blockHeader.hash).
getBalance(computation.msg.sender)
var newBalance = senderBalance

View File

@ -518,8 +518,8 @@ op create, inline = false, value, startPosition, size:
computation.memory.extend(memPos, len)
let senderBalance =
computation.vmState.chainDb.getStateDb(
computation.vmState.blockHeader.rlphash, false).
computation.vmState.getStateDb(
computation.vmState.blockHeader.rlphash).
getBalance(computation.msg.sender)
if senderBalance < value:

View File

@ -67,7 +67,7 @@ proc traceOpCodeEnded*(tracer: var TransactionTracer, c: BaseComputation, op: Op
# when contract execution interrupted by exception
if TracerFlags.DisableStorage notin tracer.flags:
var storage = newJObject()
var stateDB = c.vmState.chaindb.getStateDb(c.vmState.blockHeader.stateRoot, readOnly = true)
var stateDB = c.vmState.accountDb
for key, value in stateDB.storage(c.msg.storageAddress):
storage[key.dumpHex] = %(value.dumpHex)
j["storage"] = storage

View File

@ -34,6 +34,10 @@ proc newBaseVMState*(header: BlockHeader, chainDB: BaseChainDB, tracerFlags: set
result.tracer.initTracer(tracerFlags)
result.tracingEnabled = TracerFlags.EnableTracing in tracerFlags
result.logEntries = @[]
result.accountDb = newAccountStateDB(chainDB.db, header.stateRoot, chainDB.pruneTrie)
proc stateRoot*(vmState: BaseVMState): Hash256 =
vmState.blockHeader.stateRoot
method blockhash*(vmState: BaseVMState): Hash256 =
vmState.blockHeader.hash
@ -94,11 +98,20 @@ when false:
# TODO `db`.db = nil
# state._trie = None
proc getStateDb*(vmState: BaseVMState; stateRoot: Hash256): AccountStateDB =
# TODO: use AccountStateDB revert/commit after JournalDB implemented
vmState.accountDb.rootHash = stateRoot
vmState.accountDb
proc readOnlyStateDB*(vmState: BaseVMState): ReadOnlyStateDB {.inline.} =
ReadOnlyStateDB(vmState.accountDb)
template mutateStateDB*(vmState: BaseVMState, body: untyped) =
# This should provide more clever change handling in the future
# TODO: use AccountStateDB revert/commit after JournalDB implemented
block:
let initialStateRoot = vmState.blockHeader.stateRoot
var db {.inject.} = vmState.chaindb.getStateDB(initialStateRoot, false)
var db {.inject.} = vmState.getStateDB(initialStateRoot)
body
@ -106,9 +119,6 @@ template mutateStateDB*(vmState: BaseVMState, body: untyped) =
if finalStateRoot != initialStateRoot:
vmState.blockHeader.stateRoot = finalStateRoot
proc readOnlyStateDB*(vmState: BaseVMState): AccountStateDB {.inline.}=
vmState.chaindb.getStateDb(vmState.blockHeader.stateRoot, readOnly = true)
export DbTransaction, commit, rollback, dispose, safeDispose
proc beginTransaction*(vmState: BaseVMState): DbTransaction =

View File

@ -33,7 +33,7 @@ proc validateTransaction*(vmState: BaseVMState, transaction: Transaction, sender
transaction.accountNonce == readOnlyDB.getNonce(sender) and
readOnlyDB.getBalance(sender) >= gas_cost
proc setupComputation*(header: BlockHeader, vmState: BaseVMState, transaction: Transaction, sender: EthAddress, forkOverride=none(Fork)) : BaseComputation =
proc setupComputation*(vmState: BaseVMState, transaction: Transaction, sender: EthAddress, forkOverride=none(Fork)) : BaseComputation =
let message = newMessage(
gas = transaction.gasLimit - transaction.payload.intrinsicGas,
gasPrice = transaction.gasPrice,
@ -45,10 +45,15 @@ proc setupComputation*(header: BlockHeader, vmState: BaseVMState, transaction: T
options = newMessageOptions(origin = sender,
createAddress = transaction.to))
result = newBaseComputation(vmState, header.blockNumber, message, forkOverride)
result = newBaseComputation(vmState, vmState.blockNumber, message, forkOverride)
doAssert result.isOriginComputation
proc execComputation*(computation: var BaseComputation): bool =
# TODO: use AccountStateDB revert/commit after JournalDB implemented
let stateDb = computation.vmState.accountDb
let intermediateRoot = stateDb.rootHash
computation.vmState.blockHeader.stateRoot = stateDb.rootHash
try:
computation.executeOpcodes()
computation.vmState.mutateStateDB:
@ -59,7 +64,12 @@ proc execComputation*(computation: var BaseComputation): bool =
except ValueError:
result = false
proc applyCreateTransaction*(db: var AccountStateDB, t: Transaction, vmState: BaseVMState, sender: EthAddress, forkOverride=none(Fork)): UInt256 =
if result:
stateDb.rootHash = computation.vmState.blockHeader.stateRoot
else:
stateDb.rootHash = intermediateRoot
proc applyCreateTransaction*(t: Transaction, vmState: BaseVMState, sender: EthAddress, forkOverride=none(Fork)): UInt256 =
doAssert t.isContractCreation
# TODO: clean up params
trace "Contract creation"
@ -76,9 +86,11 @@ proc applyCreateTransaction*(db: var AccountStateDB, t: Transaction, vmState: Ba
let msg = newMessage(t.gasLimit - gasUsed, t.gasPrice, t.to, sender, t.value, @[], t.payload,
options = newMessageOptions(origin = sender,
createAddress = contractAddress))
var c = newBaseComputation(vmState, vmState.blockNumber, msg, forkOverride)
if execComputation(c):
var db = vmState.accountDb
db.addBalance(contractAddress, t.value)
# XXX: copy/pasted from GST fixture
@ -111,6 +123,7 @@ proc applyCreateTransaction*(db: var AccountStateDB, t: Transaction, vmState: Ba
# FIXME: don't do this revert, but rather only subBalance correctly
# the if transactionfailed at end is what is supposed to pick it up
# especially when it's cross-function, it's ugly/fragile
var db = vmState.accountDb
db.addBalance(sender, t.value)
debug "execComputation() error", isError = c.isError
if c.tracingEnabled:

View File

@ -10,7 +10,7 @@ import
./constants, json,
./vm/[memory, stack, code_stream],
./vm/interpreter/[gas_costs, opcode_values, vm_forks], # TODO - will be hidden at a lower layer
./db/db_chain
./db/[db_chain, state_db]
type
BaseVMState* = ref object of RootObj
@ -23,6 +23,7 @@ type
tracer* : TransactionTracer
logEntries* : seq[Log]
receipts* : seq[Receipt]
accountDb* : AccountStateDB
AccessLogs* = ref object
reads*: Table[string, string]