diff --git a/nimbus/vm/computation.nim b/nimbus/vm/computation.nim index 83b717a86..e8ce9fc5c 100644 --- a/nimbus/vm/computation.nim +++ b/nimbus/vm/computation.nim @@ -7,7 +7,7 @@ import chronicles, strformat, strutils, sequtils, macros, terminal, math, tables, options, - eth/[common, keys], + eth/[common, keys], eth/trie/db as triedb, ../constants, ../errors, ../validation, ../vm_state, ../vm_types, ./interpreter/[opcode_values, gas_meter, gas_costs, vm_forks], ./code_stream, ./memory, ./message, ./stack, ../db/[state_db, db_chain], @@ -93,24 +93,23 @@ proc prepareChildMessage*( code, childOptions) -type - ComputationSnapshot* = object - snapshot: Snapshot - computation: BaseComputation +proc snapshot*(comp: BaseComputation) = + comp.dbsnapshot.transaction = comp.vmState.chaindb.db.beginTransaction() + comp.dbsnapshot.intermediateRoot = comp.vmState.accountDb.rootHash + comp.vmState.blockHeader.stateRoot = comp.vmState.accountDb.rootHash -proc snapshot*(computation: BaseComputation): ComputationSnapshot = - result.snapshot = computation.vmState.snapshot() - result.computation = computation +proc revert*(comp: BaseComputation, burnsGas = false) = + comp.dbsnapshot.transaction.rollback() + comp.vmState.accountDb.rootHash = comp.dbsnapshot.intermediateRoot + comp.vmState.blockHeader.stateRoot = comp.dbsnapshot.intermediateRoot + comp.error = Error(info: getCurrentExceptionMsg(), burnsGas: burnsGas) -proc revert*(snapshot: var ComputationSnapshot, burnsGas: bool = false) = - snapshot.snapshot.revert() - snapshot.computation.error = Error(info: getCurrentExceptionMsg(), burnsGas: burnsGas) +proc commit*(comp: BaseComputation) = + comp.dbsnapshot.transaction.commit() + comp.vmState.accountDb.rootHash = comp.vmState.blockHeader.stateRoot -proc commit*(snapshot: var ComputationSnapshot) {.inline.} = - snapshot.snapshot.commit() - -proc dispose*(snapshot: var ComputationSnapshot) {.inline.} = - snapshot.snapshot.dispose() +proc dispose*(comp: BaseComputation) {.inline.} = + comp.dbsnapshot.transaction.dispose() proc getFork*(computation: BaseComputation): Fork = result = @@ -165,16 +164,16 @@ proc transferBalance(computation: var BaseComputation, opCode: static[Op]): bool proc executeOpcodes*(computation: var BaseComputation) {.gcsafe.} proc applyMessage*(computation: var BaseComputation, opCode: static[Op]): bool = - var snapshot = computation.snapshot() - defer: snapshot.dispose() + computation.snapshot() + defer: computation.dispose() when opCode in {CallCode, Call, Create}: if not computation.transferBalance(opCode): - snapshot.revert() + computation.revert() return if computation.gasMeter.gasRemaining < 0: - snapshot.commit() + computation.commit() return try: @@ -197,9 +196,9 @@ proc applyMessage*(computation: var BaseComputation, opCode: static[Op]): bool = result = not(contractFailed and fork == FkHomestead) if result: - snapshot.commit() + computation.commit() else: - snapshot.revert(true) + computation.revert(true) proc addChildComputation(computation: var BaseComputation, child: BaseComputation) = if child.isError: diff --git a/nimbus/vm/interpreter_dispatch.nim b/nimbus/vm/interpreter_dispatch.nim index 1b3453ff0..a4445cc7e 100644 --- a/nimbus/vm/interpreter_dispatch.nim +++ b/nimbus/vm/interpreter_dispatch.nim @@ -186,7 +186,7 @@ let HomesteadOpDispatch {.compileTime.}: array[Op, NimNode] = genHomesteadJumpTa proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNode = - let instr = genSym(nskVar) + let instr = quote do: `computation`.instr result = nnkCaseStmt.newTree(instr) # Add a branch for each (opcode, proc) pair @@ -199,28 +199,26 @@ proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNo trace "op: Stop" if not `computation`.code.atEnd() and `computation`.tracingEnabled: # we only trace `REAL STOP` and ignore `FAKE STOP` - let lastOpIndex = `computation`.traceOpCodeStarted(`asOp`) - `computation`.traceOpCodeEnded(`asOp`, lastOpIndex) + `computation`.opIndex = `computation`.traceOpCodeStarted(`asOp`) + `computation`.traceOpCodeEnded(`asOp`, `computation`.opIndex) break else: if BaseGasCosts[op].kind == GckFixed: quote do: - var lastOpIndex: int if `computation`.tracingEnabled: - lastOpIndex = `computation`.traceOpCodeStarted(`asOp`) + `computation`.opIndex = `computation`.traceOpCodeStarted(`asOp`) `computation`.gasMeter.consumeGas(`computation`.gasCosts[`asOp`].cost, reason = $`asOp`) `opImpl`(`computation`) if `computation`.tracingEnabled: - `computation`.traceOpCodeEnded(`asOp`, lastOpIndex) + `computation`.traceOpCodeEnded(`asOp`, `computation`.opIndex) `instr` = `computation`.code.next() else: quote do: - var lastOpIndex: int if `computation`.tracingEnabled: - lastOpIndex = `computation`.traceOpCodeStarted(`asOp`) + `computation`.opIndex = `computation`.traceOpCodeStarted(`asOp`) `opImpl`(`computation`) if `computation`.tracingEnabled: - `computation`.traceOpCodeEnded(`asOp`, lastOpIndex) + `computation`.traceOpCodeEnded(`asOp`, `computation`.opIndex) when `asOp` in {Return, Revert, SelfDestruct}: break else: @@ -235,7 +233,7 @@ proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNo result = quote do: if `computation`.tracingEnabled: `computation`.prepareTracer() - var `instr` = `computation`.code.next() + `computation`.instr = `computation`.code.next() while true: {.computedGoto.} # TODO lots of macro magic here to unravel, with chronicles... diff --git a/nimbus/vm_state.nim b/nimbus/vm_state.nim index d1fcd9167..800a0b8a5 100644 --- a/nimbus/vm_state.nim +++ b/nimbus/vm_state.nim @@ -132,33 +132,6 @@ template mutateStateDB*(vmState: BaseVMState, body: untyped) = if finalStateRoot != initialStateRoot: vmState.blockHeader.stateRoot = finalStateRoot -export DbTransaction, commit, rollback, dispose, safeDispose - -type - Snapshot* = object - transaction: DbTransaction - intermediateRoot: Hash256 - vmState: BaseVMState - -proc snapshot*(vmState: BaseVMState): Snapshot = - # TODO: use AccountStateDB revert/commit after JournalDB implemented - result.transaction = vmState.chaindb.db.beginTransaction() - result.intermediateRoot = vmState.accountDb.rootHash - vmState.blockHeader.stateRoot = vmState.accountDb.rootHash - result.vmState = vmState - -proc revert*(s: var Snapshot) = - s.transaction.rollback() - s.vmState.accountDb.rootHash = s.intermediateRoot - s.vmState.blockHeader.stateRoot = s.intermediateRoot - -proc commit*(s: var Snapshot) = - s.transaction.commit() - s.vmState.accountDb.rootHash = s.vmState.blockHeader.stateRoot - -proc dispose*(s: var Snapshot) {.inline.} = - s.transaction.dispose() - proc getTracingResult*(vmState: BaseVMState): JsonNode = doAssert(vmState.tracingEnabled) vmState.tracer.trace @@ -189,4 +162,3 @@ iterator tracedAccountsPairs*(vmState: BaseVMState): (int, EthAddress) = proc removeTracedAccounts*(vmState: BaseVMState, accounts: varargs[EthAddress]) = for acc in accounts: vmState.tracer.accounts.excl acc - diff --git a/nimbus/vm_types.nim b/nimbus/vm_types.nim index 82e5bbddb..54767397c 100644 --- a/nimbus/vm_types.nim +++ b/nimbus/vm_types.nim @@ -6,8 +6,8 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - tables, eth/common, options, - ./constants, json, sets, + tables, eth/common, eth/trie/db, + options, ./constants, json, sets, ./vm/[memory, stack, code_stream], ./vm/interpreter/[gas_costs, opcode_values, vm_forks], # TODO - will be hidden at a lower layer ./db/[db_chain, state_db] @@ -44,6 +44,10 @@ type accounts*: HashSet[EthAddress] storageKeys*: seq[HashSet[Uint256]] + Snapshot* = object + transaction*: DbTransaction + intermediateRoot*: Hash256 + BaseComputation* = ref object of RootObj # The execution computation vmState*: BaseVMState @@ -56,12 +60,13 @@ type rawOutput*: seq[byte] returnData*: seq[byte] error*: Error - shouldEraseReturnData*: bool accountsToDelete*: Table[EthAddress, EthAddress] - opcodes*: Table[Op, proc(computation: var BaseComputation){.nimcall.}] gasCosts*: GasCosts # TODO - will be hidden at a lower layer forkOverride*: Option[Fork] logEntries*: seq[Log] + dbsnapshot*: Snapshot + instr*: Op + opIndex*: int Error* = ref object info*: string