diff --git a/nimbus/rpc/p2p.nim b/nimbus/rpc/p2p.nim index 701bfee2b..1bc8a81b6 100644 --- a/nimbus/rpc/p2p.nim +++ b/nimbus/rpc/p2p.nim @@ -35,7 +35,7 @@ template balance(addressDb: ReadOnlyStateDb, address: EthAddress): GasInt = addressDb.getBalance(address).truncate(int64) proc binarySearchGas(vmState: var BaseVMState, transaction: Transaction, sender: EthAddress, gasPrice: GasInt, tolerance = 1): GasInt = - proc dummyComputation(vmState: var BaseVMState, transaction: Transaction, sender: EthAddress): BaseComputation = + proc dummyComputation(vmState: var BaseVMState, transaction: Transaction, sender: EthAddress): Computation = let recipient = transaction.getRecipient() # Note that vmState may be altered setupComputation( @@ -276,7 +276,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) = value: UInt256, data: seq[byte], sender, destination: EthAddress, gasLimit, gasPrice: GasInt, - contractCreation: bool): BaseComputation = + contractCreation: bool): Computation = let # Handle optional defaults. message = Message( @@ -292,7 +292,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) = data: data, code: vmState.readOnlyStateDB.getCode(destination).toSeq ) - result = newBaseComputation(vmState, message) + result = newComputation(vmState, message) rpcsrv.rpc("eth_call") do(call: EthCall, quantityTag: string) -> HexDataStr: ## Executes a new message call immediately without creating a transaction on the block chain. diff --git a/nimbus/vm/computation.nim b/nimbus/vm/computation.nim index 7fb318932..be86d734e 100644 --- a/nimbus/vm/computation.nim +++ b/nimbus/vm/computation.nim @@ -17,7 +17,7 @@ import logScope: topics = "vm computation" -proc newBaseComputation*(vmState: BaseVMState, message: Message, forkOverride=none(Fork)): BaseComputation = +proc newComputation*(vmState: BaseVMState, message: Message, forkOverride=none(Fork)): Computation = new result result.vmState = vmState result.msg = message @@ -37,213 +37,213 @@ proc newBaseComputation*(vmState: BaseVMState, message: Message, forkOverride=no result.nextProc = proc() = discard -proc isOriginComputation*(c: BaseComputation): bool = +proc isOriginComputation*(c: Computation): bool = # Is this computation the computation initiated by a transaction c.msg.isOrigin -template isSuccess*(c: BaseComputation): bool = +template isSuccess*(c: Computation): bool = c.error.isNil -template isError*(c: BaseComputation): bool = +template isError*(c: Computation): bool = not c.isSuccess -func shouldBurnGas*(c: BaseComputation): bool = +func shouldBurnGas*(c: Computation): bool = c.isError and c.error.burnsGas -func shouldEraseReturnData*(c: BaseComputation): bool = +func shouldEraseReturnData*(c: Computation): bool = c.isError and c.error.erasesReturnData func bytesToHex(x: openarray[byte]): string {.inline.} = ## TODO: use seq[byte] for raw data and delete this proc foldl(x, a & b.int.toHex(2).toLowerAscii, "0x") -func output*(c: BaseComputation): seq[byte] = +func output*(c: Computation): seq[byte] = if c.shouldEraseReturnData: @[] else: c.rawOutput -func `output=`*(c: BaseComputation, value: openarray[byte]) = +func `output=`*(c: Computation, value: openarray[byte]) = c.rawOutput = @value -proc outputHex*(c: BaseComputation): string = +proc outputHex*(c: Computation): string = if c.shouldEraseReturnData: return "0x" c.rawOutput.bytesToHex -proc isSuicided*(c: BaseComputation, address: EthAddress): bool = +proc isSuicided*(c: Computation, address: EthAddress): bool = result = address in c.suicides -proc snapshot*(comp: BaseComputation) = - comp.dbsnapshot.transaction = comp.vmState.chaindb.db.beginTransaction() - comp.dbsnapshot.intermediateRoot = comp.vmState.accountDb.rootHash +proc snapshot*(c: Computation) = + c.dbsnapshot.transaction = c.vmState.chaindb.db.beginTransaction() + c.dbsnapshot.intermediateRoot = c.vmState.accountDb.rootHash -proc commit*(comp: BaseComputation) = - comp.dbsnapshot.transaction.commit() +proc commit*(c: Computation) = + c.dbsnapshot.transaction.commit() -proc dispose*(comp: BaseComputation) {.inline.} = - comp.dbsnapshot.transaction.dispose() +proc dispose*(c: Computation) {.inline.} = + c.dbsnapshot.transaction.dispose() -proc rollback*(comp: BaseComputation) = - comp.dbsnapshot.transaction.rollback() - comp.vmState.accountDb.rootHash = comp.dbsnapshot.intermediateRoot +proc rollback*(c: Computation) = + c.dbsnapshot.transaction.rollback() + c.vmState.accountDb.rootHash = c.dbsnapshot.intermediateRoot -proc setError*(comp: BaseComputation, msg: string, burnsGas = false) {.inline.} = - comp.error = Error(info: msg, burnsGas: burnsGas) +proc setError*(c: Computation, msg: string, burnsGas = false) {.inline.} = + c.error = Error(info: msg, burnsGas: burnsGas) -proc writeContract*(computation: BaseComputation, fork: Fork): bool {.gcsafe.} = +proc writeContract*(c: Computation, fork: Fork): bool {.gcsafe.} = result = true - let contractCode = computation.output + let contractCode = c.output if contractCode.len == 0: return if fork >= FkSpurious and contractCode.len >= EIP170_CODE_SIZE_LIMIT: debug "Contract code size exceeds EIP170", limit=EIP170_CODE_SIZE_LIMIT, actual=contractCode.len return false - let storageAddr = computation.msg.contractAddress - if computation.isSuicided(storageAddr): return + let storageAddr = c.msg.contractAddress + if c.isSuicided(storageAddr): return let gasParams = GasParams(kind: Create, cr_memLength: contractCode.len) - let codeCost = computation.gasCosts[Create].c_handler(0.u256, gasParams).gasCost - if computation.gasMeter.gasRemaining >= codeCost: - computation.gasMeter.consumeGas(codeCost, reason = "Write contract code for CREATE") - computation.vmState.mutateStateDb: + let codeCost = c.gasCosts[Create].c_handler(0.u256, gasParams).gasCost + if c.gasMeter.gasRemaining >= codeCost: + c.gasMeter.consumeGas(codeCost, reason = "Write contract code for CREATE") + c.vmState.mutateStateDb: db.setCode(storageAddr, contractCode.toRange) result = true else: - if fork < FkHomestead or fork >= FkByzantium: computation.output = @[] + if fork < FkHomestead or fork >= FkByzantium: c.output = @[] result = false -proc transferBalance(computation: BaseComputation, opCode: static[Op]) = - let senderBalance = computation.vmState.readOnlyStateDb(). - getBalance(computation.msg.sender) +proc transferBalance(c: Computation, opCode: static[Op]) = + let senderBalance = c.vmState.readOnlyStateDb(). + getBalance(c.msg.sender) - if senderBalance < computation.msg.value: - computation.setError(&"insufficient funds available={senderBalance}, needed={computation.msg.value}") + if senderBalance < c.msg.value: + c.setError(&"insufficient funds available={senderBalance}, needed={c.msg.value}") return when opCode in {Call, Create}: - computation.vmState.mutateStateDb: - db.subBalance(computation.msg.sender, computation.msg.value) - db.addBalance(computation.msg.contractAddress, computation.msg.value) + c.vmState.mutateStateDb: + db.subBalance(c.msg.sender, c.msg.value) + db.addBalance(c.msg.contractAddress, c.msg.value) -template continuation*(comp: BaseComputation, body: untyped) = +template continuation*(c: Computation, body: untyped) = # this is a helper template to implement continuation # passing and convert all recursion into tail call - var tmpNext = comp.nextProc - comp.nextProc = proc() {.gcsafe.} = + var tmpNext = c.nextProc + c.nextProc = proc() {.gcsafe.} = body tmpNext() proc initAddress(x: int): EthAddress {.compileTime.} = result[19] = x.byte const ripemdAddr = initAddress(3) -proc postExecuteVM(computation: BaseComputation, opCode: static[Op]) {.gcsafe.} = +proc postExecuteVM(c: Computation, opCode: static[Op]) {.gcsafe.} = when opCode == Create: - if computation.isSuccess: - let fork = computation.fork - let contractFailed = not computation.writeContract(fork) + if c.isSuccess: + let fork = c.fork + let contractFailed = not c.writeContract(fork) if contractFailed and fork >= FkHomestead: - computation.setError(&"writeContract failed, depth={computation.msg.depth}", true) + c.setError(&"writeContract failed, depth={c.msg.depth}", true) - if computation.isSuccess: - computation.commit() + if c.isSuccess: + c.commit() else: - computation.rollback() + c.rollback() -proc executeOpcodes*(computation: BaseComputation) {.gcsafe.} +proc executeOpcodes*(c: Computation) {.gcsafe.} -proc applyMessage*(computation: BaseComputation, opCode: static[Op]) = - if computation.msg.depth > MaxCallDepth: - computation.setError(&"Stack depth limit reached depth={computation.msg.depth}") - computation.nextProc() +proc applyMessage*(c: Computation, opCode: static[Op]) = + if c.msg.depth > MaxCallDepth: + c.setError(&"Stack depth limit reached depth={c.msg.depth}") + c.nextProc() return - computation.snapshot() + c.snapshot() defer: - computation.dispose() + c.dispose() # EIP161 nonce incrementation when opCode in {Create, Create2}: - if computation.fork >= FkSpurious: - computation.vmState.mutateStateDb: - db.incNonce(computation.msg.contractAddress) - if computation.fork >= FkByzantium: + if c.fork >= FkSpurious: + c.vmState.mutateStateDb: + db.incNonce(c.msg.contractAddress) + if c.fork >= FkByzantium: # RevertInCreateInInit.json - db.setStorageRoot(computation.msg.contractAddress, emptyRlpHash) + db.setStorageRoot(c.msg.contractAddress, emptyRlpHash) when opCode in {CallCode, Call, Create}: - computation.transferBalance(opCode) - if computation.isError(): - computation.rollback() - computation.nextProc() + c.transferBalance(opCode) + if c.isError(): + c.rollback() + c.nextProc() return - if computation.gasMeter.gasRemaining < 0: - computation.commit() - computation.nextProc() + if c.gasMeter.gasRemaining < 0: + c.commit() + c.nextProc() return - continuation(computation): - postExecuteVM(computation, opCode) + continuation(c): + postExecuteVM(c, opCode) - executeOpcodes(computation) + executeOpcodes(c) -proc addChildComputation*(computation: BaseComputation, child: BaseComputation) = - if child.isError or computation.fork == FKIstanbul: +proc addChildComputation*(c, child: Computation) = + if child.isError or c.fork == FKIstanbul: if not child.msg.isCreate: if child.msg.contractAddress == ripemdAddr: child.vmState.touchedAccounts.incl child.msg.contractAddress if child.isError: if child.shouldBurnGas: - computation.returnData = @[] + c.returnData = @[] else: - computation.returnData = child.output + c.returnData = child.output else: if child.msg.isCreate: - computation.returnData = @[] + c.returnData = @[] else: - computation.returnData = child.output + c.returnData = child.output child.touchedAccounts.incl child.msg.contractAddress - computation.logEntries.add child.logEntries - computation.gasMeter.refundGas(child.gasMeter.gasRefunded) - computation.suicides.incl child.suicides - computation.touchedAccounts.incl child.touchedAccounts + c.logEntries.add child.logEntries + c.gasMeter.refundGas(child.gasMeter.gasRefunded) + c.suicides.incl child.suicides + c.touchedAccounts.incl child.touchedAccounts if not child.shouldBurnGas: - computation.gasMeter.returnGas(child.gasMeter.gasRemaining) + c.gasMeter.returnGas(child.gasMeter.gasRemaining) -proc registerAccountForDeletion*(c: BaseComputation, beneficiary: EthAddress) = +proc registerAccountForDeletion*(c: Computation, beneficiary: EthAddress) = c.touchedAccounts.incl beneficiary c.suicides.incl(c.msg.contractAddress) -proc addLogEntry*(c: BaseComputation, log: Log) {.inline.} = +proc addLogEntry*(c: Computation, log: Log) {.inline.} = c.logEntries.add(log) -iterator accountsForDeletion*(c: BaseComputation): EthAddress = +iterator accountsForDeletion*(c: Computation): EthAddress = if c.isSuccess: for address in c.suicides: yield address -proc getGasRefund*(c: BaseComputation): GasInt = +proc getGasRefund*(c: Computation): GasInt = if c.isSuccess: result = c.gasMeter.gasRefunded -proc getGasUsed*(c: BaseComputation): GasInt = +proc getGasUsed*(c: Computation): GasInt = if c.shouldBurnGas: result = c.msg.gas else: result = max(0, c.msg.gas - c.gasMeter.gasRemaining) -proc getGasRemaining*(c: BaseComputation): GasInt = +proc getGasRemaining*(c: Computation): GasInt = if c.shouldBurnGas: result = 0 else: result = c.gasMeter.gasRemaining -proc collectTouchedAccounts*(c: BaseComputation) = +proc collectTouchedAccounts*(c: Computation) = ## Collect all of the accounts that *may* need to be deleted based on EIP161: ## https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md ## also see: https://github.com/ethereum/EIPs/issues/716 @@ -259,19 +259,19 @@ proc collectTouchedAccounts*(c: BaseComputation) = if c.msg.contractAddress == ripemdAddr: c.vmState.touchedAccounts.incl c.msg.contractAddress -proc tracingEnabled*(c: BaseComputation): bool = +proc tracingEnabled*(c: Computation): bool = c.vmState.tracingEnabled -proc traceOpCodeStarted*(c: BaseComputation, op: Op): int = +proc traceOpCodeStarted*(c: Computation, op: Op): int = c.vmState.tracer.traceOpCodeStarted(c, op) -proc traceOpCodeEnded*(c: BaseComputation, op: Op, lastIndex: int) = +proc traceOpCodeEnded*(c: Computation, op: Op, lastIndex: int) = c.vmState.tracer.traceOpCodeEnded(c, op, lastIndex) -proc traceError*(c: BaseComputation) = +proc traceError*(c: Computation) = c.vmState.tracer.traceError(c) -proc prepareTracer*(c: BaseComputation) = +proc prepareTracer*(c: Computation) = c.vmState.tracer.prepare(c.msg.depth) include interpreter_dispatch diff --git a/nimbus/vm/interpreter/opcodes_impl.nim b/nimbus/vm/interpreter/opcodes_impl.nim index 41a339a03..10b27f93c 100644 --- a/nimbus/vm/interpreter/opcodes_impl.nim +++ b/nimbus/vm/interpreter/opcodes_impl.nim @@ -22,7 +22,7 @@ logScope: template push(x: typed) {.dirty.} = ## Push an expression on the computation stack - computation.stack.push x + c.stack.push x # ################################## # 0s: Stop and Arithmetic Operations @@ -94,8 +94,8 @@ op mulmod, inline = true, lhs, rhs, modulus: op exp, inline = true, base, exponent: ## 0x0A, Exponentiation - computation.gasMeter.consumeGas( - computation.gasCosts[Exp].d_handler(exponent), + c.gasMeter.consumeGas( + c.gasCosts[Exp].d_handler(exponent), reason="EXP: exponent bytes" ) push: @@ -196,18 +196,18 @@ op sha3, inline = true, startPos, length: if pos < 0 or len < 0 or pos > 2147483648: raise newException(OutOfBoundsRead, "Out of bounds memory access") - computation.gasMeter.consumeGas( - computation.gasCosts[Op.Sha3].m_handler(computation.memory.len, pos, len), + c.gasMeter.consumeGas( + c.gasCosts[Op.Sha3].m_handler(c.memory.len, pos, len), reason="SHA3: word gas cost" ) - computation.memory.extend(pos, len) - let endRange = min(pos + len, computation.memory.len) - 1 - if endRange == -1 or pos >= computation.memory.len: + c.memory.extend(pos, len) + let endRange = min(pos + len, c.memory.len) - 1 + if endRange == -1 or pos >= c.memory.len: push(EMPTY_SHA3) else: push: - keccak256.digest computation.memory.bytes.toOpenArray(pos, endRange) + keccak256.digest c.memory.bytes.toOpenArray(pos, endRange) # ########################################## # 30s: Environmental Information @@ -231,45 +231,45 @@ proc writePaddedResult(mem: var Memory, op address, inline = true: ## 0x30, Get address of currently executing account. - push: computation.msg.contractAddress + push: c.msg.contractAddress op balance, inline = true: ## 0x31, Get balance of the given account. - let address = computation.stack.popAddress() - push: computation.vmState.readOnlyStateDB.getBalance(address) + let address = c.stack.popAddress() + push: c.vmState.readOnlyStateDB.getBalance(address) op origin, inline = true: ## 0x32, Get execution origination address. - push: computation.msg.origin + push: c.msg.origin op caller, inline = true: ## 0x33, Get caller address. - push: computation.msg.sender + push: c.msg.sender op callValue, inline = true: ## 0x34, Get deposited value by the instruction/transaction ## responsible for this execution - push: computation.msg.value + push: c.msg.value op callDataLoad, inline = false, startPos: ## 0x35, Get input data of current environment let start = startPos.cleanMemRef - if start >= computation.msg.data.len: + if start >= c.msg.data.len: push: 0 return # If the data does not take 32 bytes, pad with zeros - let endRange = min(computation.msg.data.len - 1, start + 31) + let endRange = min(c.msg.data.len - 1, start + 31) let presentBytes = endRange - start # We rely on value being initialized with 0 by default var value: array[32, byte] - value[0 .. presentBytes] = computation.msg.data.toOpenArray(start, endRange) + value[0 .. presentBytes] = c.msg.data.toOpenArray(start, endRange) push: value op callDataSize, inline = true: ## 0x36, Get size of input data in current environment. - push: computation.msg.data.len.u256 + push: c.msg.data.len.u256 op callDataCopy, inline = false, memStartPos, copyStartPos, size: ## 0x37, Copy input data in current environment to memory. @@ -277,15 +277,15 @@ op callDataCopy, inline = false, memStartPos, copyStartPos, size: let (memPos, copyPos, len) = (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef) - computation.gasMeter.consumeGas( - computation.gasCosts[CallDataCopy].m_handler(computation.memory.len, memPos, len), + c.gasMeter.consumeGas( + c.gasCosts[CallDataCopy].m_handler(c.memory.len, memPos, len), reason="CallDataCopy fee") - computation.memory.writePaddedResult(computation.msg.data, memPos, copyPos, len) + c.memory.writePaddedResult(c.msg.data, memPos, copyPos, len) op codeSize, inline = true: ## 0x38, Get size of code running in current environment. - push: computation.code.len + push: c.code.len op codeCopy, inline = false, memStartPos, copyStartPos, size: ## 0x39, Copy code running in current environment to memory. @@ -293,196 +293,196 @@ op codeCopy, inline = false, memStartPos, copyStartPos, size: let (memPos, copyPos, len) = (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef) - computation.gasMeter.consumeGas( - computation.gasCosts[CodeCopy].m_handler(computation.memory.len, memPos, len), + c.gasMeter.consumeGas( + c.gasCosts[CodeCopy].m_handler(c.memory.len, memPos, len), reason="CodeCopy fee") - computation.memory.writePaddedResult(computation.code.bytes, memPos, copyPos, len) + c.memory.writePaddedResult(c.code.bytes, memPos, copyPos, len) op gasprice, inline = true: ## 0x3A, Get price of gas in current environment. - push: computation.msg.gasPrice + push: c.msg.gasPrice op extCodeSize, inline = true: ## 0x3b, Get size of an account's code - let account = computation.stack.popAddress() - let codeSize = computation.vmState.readOnlyStateDB.getCode(account).len + let account = c.stack.popAddress() + let codeSize = c.vmState.readOnlyStateDB.getCode(account).len push uint(codeSize) op extCodeCopy, inline = true: ## 0x3c, Copy an account's code to memory. - let account = computation.stack.popAddress() - let (memStartPos, codeStartPos, size) = computation.stack.popInt(3) + let account = c.stack.popAddress() + let (memStartPos, codeStartPos, size) = c.stack.popInt(3) let (memPos, codePos, len) = (memStartPos.cleanMemRef, codeStartPos.cleanMemRef, size.cleanMemRef) - computation.gasMeter.consumeGas( - computation.gasCosts[ExtCodeCopy].m_handler(computation.memory.len, memPos, len), + c.gasMeter.consumeGas( + c.gasCosts[ExtCodeCopy].m_handler(c.memory.len, memPos, len), reason="ExtCodeCopy fee") - let codeBytes = computation.vmState.readOnlyStateDB.getCode(account) - computation.memory.writePaddedResult(codeBytes.toOpenArray, memPos, codePos, len) + let codeBytes = c.vmState.readOnlyStateDB.getCode(account) + c.memory.writePaddedResult(codeBytes.toOpenArray, memPos, codePos, len) op returnDataSize, inline = true: ## 0x3d, Get size of output data from the previous call from the current environment. - push: computation.returnData.len + push: c.returnData.len op returnDataCopy, inline = false, memStartPos, copyStartPos, size: ## 0x3e, Copy output data from the previous call to memory. let (memPos, copyPos, len) = (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef) - let gasCost = computation.gasCosts[ReturnDataCopy].m_handler(computation.memory.len, memPos, len) - computation.gasMeter.consumeGas( + let gasCost = c.gasCosts[ReturnDataCopy].m_handler(c.memory.len, memPos, len) + c.gasMeter.consumeGas( gasCost, reason="returnDataCopy fee") - if copyPos + len > computation.returnData.len: + if copyPos + len > c.returnData.len: # TODO Geth additionally checks copyPos + len < 64 # Parity uses a saturating addition # Yellow paper mentions μs[1] + i are not subject to the 2^256 modulo. raise newException(OutOfBoundsRead, "Return data length is not sufficient to satisfy request. Asked \n" & - &"for data from index {copyStartPos} to {copyStartPos + size}. Return data is {computation.returnData.len} in \n" & + &"for data from index {copyStartPos} to {copyStartPos + size}. Return data is {c.returnData.len} in \n" & "length") - computation.memory.writePaddedResult(computation.returnData, memPos, copyPos, len) + c.memory.writePaddedResult(c.returnData, memPos, copyPos, len) # ########################################## # 40s: Block Information op blockhash, inline = true, blockNumber: ## 0x40, Get the hash of one of the 256 most recent complete blocks. - push: computation.vmState.getAncestorHash(blockNumber.vmWordToBlockNumber) + push: c.vmState.getAncestorHash(blockNumber.vmWordToBlockNumber) op coinbase, inline = true: ## 0x41, Get the block's beneficiary address. - push: computation.vmState.coinbase + push: c.vmState.coinbase op timestamp, inline = true: ## 0x42, Get the block's timestamp. - push: computation.vmState.timestamp.toUnix + push: c.vmState.timestamp.toUnix op blocknumber, inline = true: ## 0x43, Get the block's number. - push: computation.vmState.blockNumber.blockNumberToVmWord + push: c.vmState.blockNumber.blockNumberToVmWord op difficulty, inline = true: ## 0x44, Get the block's difficulty - push: computation.vmState.difficulty + push: c.vmState.difficulty op gasLimit, inline = true: ## 0x45, Get the block's gas limit - push: computation.vmState.gasLimit + push: c.vmState.gasLimit op chainId, inline = true: ## 0x46, Get current chain’s EIP-155 unique identifier. # TODO: this is a stub - push: computation.vmState.chaindb.config.chainId + push: c.vmState.chaindb.config.chainId op selfBalance, inline = true: ## 0x47, Get current contract's balance. - let stateDb = computation.vmState.readOnlyStateDb - push: stateDb.getBalance(computation.msg.contractAddress) + let stateDb = c.vmState.readOnlyStateDb + push: stateDb.getBalance(c.msg.contractAddress) # ########################################## # 50s: Stack, Memory, Storage and Flow Operations op pop, inline = true: ## 0x50, Remove item from stack. - discard computation.stack.popInt() + discard c.stack.popInt() op mload, inline = true, memStartPos: ## 0x51, Load word from memory let memPos = memStartPos.cleanMemRef - computation.gasMeter.consumeGas( - computation.gasCosts[MLoad].m_handler(computation.memory.len, memPos, 32), + c.gasMeter.consumeGas( + c.gasCosts[MLoad].m_handler(c.memory.len, memPos, 32), reason="MLOAD: GasVeryLow + memory expansion" ) - computation.memory.extend(memPos, 32) + c.memory.extend(memPos, 32) - push: computation.memory.read(memPos, 32) # TODO, should we convert to native endianness? + push: c.memory.read(memPos, 32) # TODO, should we convert to native endianness? op mstore, inline = true, memStartPos, value: ## 0x52, Save word to memory let memPos = memStartPos.cleanMemRef - computation.gasMeter.consumeGas( - computation.gasCosts[MStore].m_handler(computation.memory.len, memPos, 32), + c.gasMeter.consumeGas( + c.gasCosts[MStore].m_handler(c.memory.len, memPos, 32), reason="MSTORE: GasVeryLow + memory expansion" ) - computation.memory.extend(memPos, 32) - computation.memory.write(memPos, value.toByteArrayBE) # is big-endian correct? Parity/Geth do convert + c.memory.extend(memPos, 32) + c.memory.write(memPos, value.toByteArrayBE) # is big-endian correct? Parity/Geth do convert op mstore8, inline = true, memStartPos, value: ## 0x53, Save byte to memory let memPos = memStartPos.cleanMemRef - computation.gasMeter.consumeGas( - computation.gasCosts[MStore].m_handler(computation.memory.len, memPos, 1), + c.gasMeter.consumeGas( + c.gasCosts[MStore].m_handler(c.memory.len, memPos, 1), reason="MSTORE8: GasVeryLow + memory expansion" ) - computation.memory.extend(memPos, 1) - computation.memory.write(memPos, [value.toByteArrayBE[31]]) + c.memory.extend(memPos, 1) + c.memory.write(memPos, [value.toByteArrayBE[31]]) op sload, inline = true, slot: ## 0x54, Load word from storage. - let (value, _) = computation.vmState.readOnlyStateDB.getStorage(computation.msg.contractAddress, slot) + let (value, _) = c.vmState.readOnlyStateDB.getStorage(c.msg.contractAddress, slot) push(value) op sstore, inline = false, slot, value: ## 0x55, Save word to storage. - checkInStaticContext(computation) + checkInStaticContext(c) - let (currentValue, existing) = computation.vmState.readOnlyStateDB.getStorage(computation.msg.contractAddress, slot) + let (currentValue, existing) = c.vmState.readOnlyStateDB.getStorage(c.msg.contractAddress, slot) let gasParam = GasParams(kind: Op.Sstore, s_isStorageEmpty: currentValue.isZero) - (gasCost, gasRefund) = computation.gasCosts[Sstore].c_handler(value, gasParam) + (gasCost, gasRefund) = c.gasCosts[Sstore].c_handler(value, gasParam) - computation.gasMeter.consumeGas(gasCost, &"SSTORE: {computation.msg.contractAddress}[{slot}] -> {value} ({currentValue})") + c.gasMeter.consumeGas(gasCost, &"SSTORE: {c.msg.contractAddress}[{slot}] -> {value} ({currentValue})") if gasRefund > 0: - computation.gasMeter.refundGas(gasRefund) + c.gasMeter.refundGas(gasRefund) - computation.vmState.mutateStateDB: - db.setStorage(computation.msg.contractAddress, slot, value) + c.vmState.mutateStateDB: + db.setStorage(c.msg.contractAddress, slot, value) -proc jumpImpl(computation: BaseComputation, jumpTarget: UInt256) = - if jumpTarget >= computation.code.len.u256: +proc jumpImpl(c: Computation, jumpTarget: UInt256) = + if jumpTarget >= c.code.len.u256: raise newException(InvalidJumpDestination, "Invalid Jump Destination") let jt = jumpTarget.truncate(int) - computation.code.pc = jt + c.code.pc = jt - let nextOpcode = computation.code.peek + let nextOpcode = c.code.peek if nextOpcode != JUMPDEST: raise newException(InvalidJumpDestination, "Invalid Jump Destination") # TODO: next check seems redundant - if not computation.code.isValidOpcode(jt): + if not c.code.isValidOpcode(jt): raise newException(InvalidInstruction, "Jump resulted in invalid instruction") op jump, inline = true, jumpTarget: ## 0x56, Alter the program counter - jumpImpl(computation, jumpTarget) + jumpImpl(c, jumpTarget) op jumpI, inline = true, jumpTarget, testedValue: ## 0x57, Conditionally alter the program counter. if testedValue != 0: - jumpImpl(computation, jumpTarget) + jumpImpl(c, jumpTarget) op pc, inline = true: ## 0x58, Get the value of the program counter prior to the increment corresponding to this instruction. - push: max(computation.code.pc - 1, 0) + push: max(c.code.pc - 1, 0) op msize, inline = true: ## 0x59, Get the size of active memory in bytes. - push: computation.memory.len + push: c.memory.len op gas, inline = true: ## 0x5a, Get the amount of available gas, including the corresponding reduction for the cost of this instruction. - push: computation.gasMeter.gasRemaining + push: c.gasMeter.gasRemaining op jumpDest, inline = true: ## 0x5b, Mark a valid destination for jumps. This operation has no effect on machine state during execution. @@ -502,53 +502,53 @@ genLog() # ########################################## # f0s: System operations. -proc canTransfer(computation: BaseComputation, memPos, memLen: int, value: Uint256, opCode: static[Op]): bool = +proc canTransfer(c: Computation, memPos, memLen: int, value: Uint256, opCode: static[Op]): bool = let gasParams = GasParams(kind: Create, - cr_currentMemSize: computation.memory.len, + cr_currentMemSize: c.memory.len, cr_memOffset: memPos, cr_memLength: memLen ) - var gasCost = computation.gasCosts[Create].c_handler(1.u256, gasParams).gasCost + var gasCost = c.gasCosts[Create].c_handler(1.u256, gasParams).gasCost let reason = &"CREATE: GasCreate + {memLen} * memory expansion" when opCode == Create2: - gasCost = gasCost + computation.gasCosts[Create2].m_handler(0, 0, memLen) + gasCost = gasCost + c.gasCosts[Create2].m_handler(0, 0, memLen) - computation.gasMeter.consumeGas(gasCost, reason = reason) - computation.memory.extend(memPos, memLen) + c.gasMeter.consumeGas(gasCost, reason = reason) + c.memory.extend(memPos, memLen) # the sender is childmsg sender, not parent msg sender # perhaps we need to move this code somewhere else # to avoid confusion let senderBalance = - computation.vmState.readOnlyStateDb(). - getBalance(computation.msg.contractAddress) + c.vmState.readOnlyStateDb(). + getBalance(c.msg.contractAddress) if senderBalance < value: - debug "Computation Failure", reason = "Insufficient funds available to transfer", required = computation.msg.value, balance = senderBalance + debug "Computation Failure", reason = "Insufficient funds available to transfer", required = c.msg.value, balance = senderBalance return false # unlike the other MaxCallDepth comparison, # this one has not been entered child computation # thats why it has `+ 1` - if computation.msg.depth + 1 > MaxCallDepth: - debug "Computation Failure", reason = "Stack too deep", maximumDepth = MaxCallDepth, depth = computation.msg.depth + if c.msg.depth + 1 > MaxCallDepth: + debug "Computation Failure", reason = "Stack too deep", maximumDepth = MaxCallDepth, depth = c.msg.depth return false result = true -proc setupCreate(computation: BaseComputation, memPos, len: int, value: Uint256, opCode: static[Op]): BaseComputation = +proc setupCreate(c: Computation, memPos, len: int, value: Uint256, opCode: static[Op]): Computation = let - callData = computation.memory.read(memPos, len) + callData = c.memory.read(memPos, len) var - createMsgGas = computation.getGasRemaining() + createMsgGas = c.getGasRemaining() - if computation.fork >= FkTangerine: + if c.fork >= FkTangerine: createMsgGas -= createMsgGas div 64 # Consume gas here that will be passed to child - computation.gasMeter.consumeGas(createMsgGas, reason="CREATE") + c.gasMeter.consumeGas(createMsgGas, reason="CREATE") # Generate new address and check for collisions var @@ -557,20 +557,20 @@ proc setupCreate(computation: BaseComputation, memPos, len: int, value: Uint256, when opCode == Create: const callKind = evmcCreate - computation.vmState.mutateStateDB: + c.vmState.mutateStateDB: # Regarding collisions, see: https://github.com/status-im/nimbus/issues/133 # See: https://github.com/ethereum/EIPs/issues/684 - let creationNonce = db.getNonce(computation.msg.contractAddress) - db.setNonce(computation.msg.contractAddress, creationNonce + 1) + let creationNonce = db.getNonce(c.msg.contractAddress) + db.setNonce(c.msg.contractAddress, creationNonce + 1) - contractAddress = generateAddress(computation.msg.contractAddress, creationNonce) + contractAddress = generateAddress(c.msg.contractAddress, creationNonce) isCollision = db.hasCodeOrNonce(contractAddress) else: const callKind = evmcCreate2 - computation.vmState.mutateStateDB: - db.incNonce(computation.msg.contractAddress) - let salt = computation.stack.popInt() - contractAddress = generateSafeAddress(computation.msg.contractAddress, salt, callData) + c.vmState.mutateStateDB: + db.incNonce(c.msg.contractAddress) + let salt = c.stack.popInt() + contractAddress = generateSafeAddress(c.msg.contractAddress, salt, callData) isCollision = db.hasCodeOrNonce(contractAddress) if isCollision: @@ -580,11 +580,11 @@ proc setupCreate(computation: BaseComputation, memPos, len: int, value: Uint256, let childMsg = Message( kind: callKind, - depth: computation.msg.depth + 1, + depth: c.msg.depth + 1, gas: createMsgGas, - gasPrice: computation.msg.gasPrice, - origin: computation.msg.origin, - sender: computation.msg.contractAddress, + gasPrice: c.msg.gasPrice, + origin: c.msg.origin, + sender: c.msg.contractAddress, contractAddress: contractAddress, codeAddress: CREATE_CONTRACT_ADDRESS, value: value, @@ -592,106 +592,103 @@ proc setupCreate(computation: BaseComputation, memPos, len: int, value: Uint256, code: callData ) - result = newBaseComputation( - computation.vmState, - childMsg, - some(computation.fork)) + result = newComputation(c.vmState, childMsg, some(c.fork)) template genCreate(callName: untyped, opCode: Op): untyped = op callName, inline = false, val, startPosition, size: ## 0xf0, Create a new account with associated code. let (memPos, len) = (startPosition.safeInt, size.safeInt) - if not computation.canTransfer(memPos, len, val, opCode): + if not c.canTransfer(memPos, len, val, opCode): push: 0 return - var childComp = setupCreate(computation, memPos, len, val, opCode) - if childComp.isNil: return + var child = setupCreate(c, memPos, len, val, opCode) + if child.isNil: return - continuation(childComp): - addChildComputation(computation, childComp) + continuation(child): + addChildComputation(c, child) - if childComp.isError: + if child.isError: push: 0 else: - push: childComp.msg.contractAddress + push: child.msg.contractAddress - checkInStaticContext(computation) - childComp.applyMessage(Create) + checkInStaticContext(c) + child.applyMessage(Create) genCreate(create, Create) genCreate(create2, Create2) -proc callParams(computation: BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, CallKind, UInt256, UInt256, UInt256, UInt256, MsgFlags) = - let gas = computation.stack.popInt() - let codeAddress = computation.stack.popAddress() +proc callParams(c: Computation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, CallKind, UInt256, UInt256, UInt256, UInt256, MsgFlags) = + let gas = c.stack.popInt() + let codeAddress = c.stack.popAddress() let (value, memoryInputStartPosition, memoryInputSize, - memoryOutputStartPosition, memoryOutputSize) = computation.stack.popInt(5) + memoryOutputStartPosition, memoryOutputSize) = c.stack.popInt(5) result = (gas, value, codeAddress, # contractAddress - computation.msg.contractAddress, # sender + c.msg.contractAddress, # sender codeAddress, evmcCall, memoryInputStartPosition, memoryInputSize, memoryOutputStartPosition, memoryOutputSize, - computation.msg.flags) + c.msg.flags) -proc callCodeParams(computation: BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, CallKind, UInt256, UInt256, UInt256, UInt256, MsgFlags) = - let gas = computation.stack.popInt() - let codeAddress = computation.stack.popAddress() +proc callCodeParams(c: Computation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, CallKind, UInt256, UInt256, UInt256, UInt256, MsgFlags) = + let gas = c.stack.popInt() + let codeAddress = c.stack.popAddress() let (value, memoryInputStartPosition, memoryInputSize, - memoryOutputStartPosition, memoryOutputSize) = computation.stack.popInt(5) + memoryOutputStartPosition, memoryOutputSize) = c.stack.popInt(5) result = (gas, value, - computation.msg.contractAddress, # contractAddress - computation.msg.contractAddress, # sender + c.msg.contractAddress, # contractAddress + c.msg.contractAddress, # sender codeAddress, evmcCallCode, memoryInputStartPosition, memoryInputSize, memoryOutputStartPosition, memoryOutputSize, - computation.msg.flags) + c.msg.flags) -proc delegateCallParams(computation: BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, CallKind, UInt256, UInt256, UInt256, UInt256, MsgFlags) = - let gas = computation.stack.popInt() - let codeAddress = computation.stack.popAddress() +proc delegateCallParams(c: Computation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, CallKind, UInt256, UInt256, UInt256, UInt256, MsgFlags) = + let gas = c.stack.popInt() + let codeAddress = c.stack.popAddress() let (memoryInputStartPosition, memoryInputSize, - memoryOutputStartPosition, memoryOutputSize) = computation.stack.popInt(4) + memoryOutputStartPosition, memoryOutputSize) = c.stack.popInt(4) result = (gas, - computation.msg.value, # value - computation.msg.contractAddress, # contractAddress - computation.msg.sender, # sender + c.msg.value, # value + c.msg.contractAddress, # contractAddress + c.msg.sender, # sender codeAddress, evmcDelegateCall, memoryInputStartPosition, memoryInputSize, memoryOutputStartPosition, memoryOutputSize, - computation.msg.flags) + c.msg.flags) -proc staticCallParams(computation: BaseComputation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, CallKind, UInt256, UInt256, UInt256, UInt256, MsgFlags) = - let gas = computation.stack.popInt() - let codeAddress = computation.stack.popAddress() +proc staticCallParams(c: Computation): (UInt256, UInt256, EthAddress, EthAddress, EthAddress, CallKind, UInt256, UInt256, UInt256, UInt256, MsgFlags) = + let gas = c.stack.popInt() + let codeAddress = c.stack.popAddress() let (memoryInputStartPosition, memoryInputSize, - memoryOutputStartPosition, memoryOutputSize) = computation.stack.popInt(4) + memoryOutputStartPosition, memoryOutputSize) = c.stack.popInt(4) result = (gas, 0.u256, # value codeAddress, # contractAddress - computation.msg.contractAddress, # sender + c.msg.contractAddress, # sender codeAddress, evmcCall, memoryInputStartPosition, @@ -701,55 +698,55 @@ proc staticCallParams(computation: BaseComputation): (UInt256, UInt256, EthAddre emvcStatic) # is_static template genCall(callName: untyped, opCode: Op): untyped = - proc `callName Setup`(computation: BaseComputation, callNameStr: string): BaseComputation = + proc `callName Setup`(c: Computation, callNameStr: string): Computation = let (gas, value, contractAddress, sender, codeAddress, callKind, memoryInputStartPosition, memoryInputSize, memoryOutputStartPosition, memoryOutputSize, - flags) = `callName Params`(computation) + flags) = `callName Params`(c) let (memInPos, memInLen, memOutPos, memOutLen) = (memoryInputStartPosition.cleanMemRef, memoryInputSize.cleanMemRef, memoryOutputStartPosition.cleanMemRef, memoryOutputSize.cleanMemRef) - let isNewAccount = if computation.fork >= FkSpurious: - computation.vmState.readOnlyStateDb.isDeadAccount(contractAddress) + let isNewAccount = if c.fork >= FkSpurious: + c.vmState.readOnlyStateDb.isDeadAccount(contractAddress) else: - not computation.vmState.readOnlyStateDb.accountExists(contractAddress) + not c.vmState.readOnlyStateDb.accountExists(contractAddress) let (memOffset, memLength) = if calcMemSize(memInPos, memInLen) > calcMemSize(memOutPos, memOutLen): (memInPos, memInLen) else: (memOutPos, memOutLen) - let (childGasFee, childGasLimit) = computation.gasCosts[opCode].c_handler( + let (childGasFee, childGasLimit) = c.gasCosts[opCode].c_handler( value, GasParams(kind: opCode, c_isNewAccount: isNewAccount, - c_gasBalance: computation.gasMeter.gasRemaining, + c_gasBalance: c.gasMeter.gasRemaining, c_contractGas: gas, - c_currentMemSize: computation.memory.len, + c_currentMemSize: c.memory.len, c_memOffset: memOffset, c_memLength: memLength )) if childGasFee >= 0: - computation.gasMeter.consumeGas(childGasFee, reason = $opCode) + c.gasMeter.consumeGas(childGasFee, reason = $opCode) if childGasFee < 0 and childGasLimit <= 0: raise newException(OutOfGas, "Gas not enough to perform calculation (" & callNameStr & ")") - computation.memory.extend(memInPos, memInLen) - computation.memory.extend(memOutPos, memOutLen) + c.memory.extend(memInPos, memInLen) + c.memory.extend(memOutPos, memOutLen) let - callData = computation.memory.read(memInPos, memInLen) - code = computation.vmState.readOnlyStateDb.getCode(codeAddress) + callData = c.memory.read(memInPos, memInLen) + code = c.vmState.readOnlyStateDb.getCode(codeAddress) var childMsg = Message( kind: callKind, - depth: computation.msg.depth + 1, + depth: c.msg.depth + 1, gas: childGasLimit, - gasPrice: computation.msg.gasPrice, - origin: computation.msg.origin, + gasPrice: c.msg.gasPrice, + origin: c.msg.origin, sender: sender, contractAddress: contractAddress, codeAddress: codeAddress, @@ -758,41 +755,38 @@ template genCall(callName: untyped, opCode: Op): untyped = code: code.toSeq, flags: flags) - var childComp = newBaseComputation( - computation.vmState, - childMsg, - some(computation.fork)) + var child = newComputation(c.vmState, childMsg, some(c.fork)) - computation.memOutPos = memOutPos - computation.memOutLen = memOutLen - result = childComp + c.memOutPos = memOutPos + c.memOutLen = memOutLen + result = child op callName, inline = false: ## CALL, 0xf1, Message-Call into an account ## CALLCODE, 0xf2, Message-call into this account with an alternative account's code. ## DELEGATECALL, 0xf4, Message-call into this account with an alternative account's code, but persisting the current values for sender and value. ## STATICCALL, 0xfa, Static message-call into an account. - var childComp = `callName Setup`(computation, callName.astToStr) + var child = `callName Setup`(c, callName.astToStr) - continuation(childComp): - addChildComputation(computation, childComp) + continuation(child): + addChildComputation(c, child) - if childComp.isError: + if child.isError: push: 0 else: push: 1 - if not childComp.shouldEraseReturnData: - let actualOutputSize = min(computation.memOutLen, childComp.output.len) - computation.memory.write( - computation.memOutPos, - childComp.output.toOpenArray(0, actualOutputSize - 1)) + if not child.shouldEraseReturnData: + let actualOutputSize = min(c.memOutLen, child.output.len) + c.memory.write( + c.memOutPos, + child.output.toOpenArray(0, actualOutputSize - 1)) when opCode == Call: - if emvcStatic == computation.msg.flags and childComp.msg.value > 0.u256: + if emvcStatic == c.msg.flags and child.msg.value > 0.u256: raise newException(StaticContextError, "Cannot modify state while inside of a STATICCALL context") - childComp.applyMessage(opCode) + child.applyMessage(opCode) genCall(call, Call) genCall(callCode, CallCode) @@ -803,35 +797,35 @@ op returnOp, inline = false, startPos, size: ## 0xf3, Halt execution returning output data. let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef) - computation.gasMeter.consumeGas( - computation.gasCosts[Return].m_handler(computation.memory.len, pos, len), + c.gasMeter.consumeGas( + c.gasCosts[Return].m_handler(c.memory.len, pos, len), reason = "RETURN" ) - computation.memory.extend(pos, len) - computation.output = computation.memory.read(pos, len) + c.memory.extend(pos, len) + c.output = c.memory.read(pos, len) op revert, inline = false, startPos, size: ## 0xfd, Halt execution reverting state changes but returning data and remaining gas. let (pos, len) = (startPos.cleanMemRef, size.cleanMemRef) - computation.gasMeter.consumeGas( - computation.gasCosts[Revert].m_handler(computation.memory.len, pos, len), + c.gasMeter.consumeGas( + c.gasCosts[Revert].m_handler(c.memory.len, pos, len), reason = "REVERT" ) - computation.memory.extend(pos, len) - computation.output = computation.memory.read(pos, len) + c.memory.extend(pos, len) + c.output = c.memory.read(pos, len) # setError(msg, false) will signal cheap revert - computation.setError("REVERT opcode executed", false) + c.setError("REVERT opcode executed", false) -proc selfDestructImpl(computation: BaseComputation, beneficiary: EthAddress) = +proc selfDestructImpl(c: Computation, beneficiary: EthAddress) = ## 0xff Halt execution and register account for later deletion. # TODO: This is the basic implementation of the self destruct op, # Other forks have some extra functionality around this call. # In particular, EIP150 and EIP161 have extra requirements. - computation.vmState.mutateStateDB: + c.vmState.mutateStateDB: let - localBalance = db.getBalance(computation.msg.contractAddress) + localBalance = db.getBalance(c.msg.contractAddress) beneficiaryBalance = db.getBalance(beneficiary) # Transfer to beneficiary @@ -840,47 +834,47 @@ proc selfDestructImpl(computation: BaseComputation, beneficiary: EthAddress) = # Zero the balance of the address being deleted. # This must come after sending to beneficiary in case the # contract named itself as the beneficiary. - db.setBalance(computation.msg.contractAddress, 0.u256) + db.setBalance(c.msg.contractAddress, 0.u256) # Register the account to be deleted - computation.registerAccountForDeletion(beneficiary) + c.registerAccountForDeletion(beneficiary) trace "SELFDESTRUCT", - contractAddress = computation.msg.contractAddress.toHex, + contractAddress = c.msg.contractAddress.toHex, localBalance = localBalance.toString, beneficiary = beneficiary.toHex op selfDestruct, inline = false: - let beneficiary = computation.stack.popAddress() - selfDestructImpl(computation, beneficiary) + let beneficiary = c.stack.popAddress() + selfDestructImpl(c, beneficiary) op selfDestructEip150, inline = false: - let beneficiary = computation.stack.popAddress() + let beneficiary = c.stack.popAddress() let gasParams = GasParams(kind: SelfDestruct, - sd_condition: not computation.vmState.readOnlyStateDb.accountExists(beneficiary) + sd_condition: not c.vmState.readOnlyStateDb.accountExists(beneficiary) ) - let gasCost = computation.gasCosts[SelfDestruct].c_handler(0.u256, gasParams).gasCost - computation.gasMeter.consumeGas(gasCost, reason = "SELFDESTRUCT EIP150") - selfDestructImpl(computation, beneficiary) + let gasCost = c.gasCosts[SelfDestruct].c_handler(0.u256, gasParams).gasCost + c.gasMeter.consumeGas(gasCost, reason = "SELFDESTRUCT EIP150") + selfDestructImpl(c, beneficiary) op selfDestructEip161, inline = false: - checkInStaticContext(computation) + checkInStaticContext(c) let - beneficiary = computation.stack.popAddress() - stateDb = computation.vmState.readOnlyStateDb + beneficiary = c.stack.popAddress() + stateDb = c.vmState.readOnlyStateDb isDead = stateDb.isDeadAccount(beneficiary) - balance = stateDb.getBalance(computation.msg.contractAddress) + balance = stateDb.getBalance(c.msg.contractAddress) let gasParams = GasParams(kind: SelfDestruct, sd_condition: isDead and not balance.isZero ) - let gasCost = computation.gasCosts[SelfDestruct].c_handler(0.u256, gasParams).gasCost - computation.gasMeter.consumeGas(gasCost, reason = "SELFDESTRUCT EIP161") - selfDestructImpl(computation, beneficiary) + let gasCost = c.gasCosts[SelfDestruct].c_handler(0.u256, gasParams).gasCost + c.gasMeter.consumeGas(gasCost, reason = "SELFDESTRUCT EIP161") + selfDestructImpl(c, beneficiary) # Constantinople's new opcodes op shlOp, inline = true, shift, num: @@ -899,8 +893,8 @@ op shrOp, inline = true, shift, num: push: num shr shiftLen op sarOp, inline = true: - let shiftLen = computation.stack.popInt().safeInt - let num = cast[Int256](computation.stack.popInt()) + let shiftLen = c.stack.popInt().safeInt + let num = cast[Int256](c.stack.popInt()) if shiftLen >= 256: if num.isNegative: push: cast[Uint256]((-1).i256) @@ -912,41 +906,41 @@ op sarOp, inline = true: push: cast[Uint256](num shr shiftLen) op extCodeHash, inline = true: - let address = computation.stack.popAddress() + let address = c.stack.popAddress() # this is very inefficient, it calls underlying # database too much, we can reduce it by implementing accounts # cache - if not computation.vmState.readOnlyStateDB.accountExists(address): + if not c.vmState.readOnlyStateDB.accountExists(address): push: 0 return - if computation.vmState.readOnlyStateDB.isEmptyAccount(address): + if c.vmState.readOnlyStateDB.isEmptyAccount(address): push: 0 else: - push: computation.vmState.readOnlyStateDB.getCodeHash(address) + push: c.vmState.readOnlyStateDB.getCodeHash(address) op sstoreEIP2200, inline = false, slot, value: - checkInStaticContext(computation) + checkInStaticContext(c) const SentryGasEIP2200 = 2300 # Minimum gas required to be present for an SSTORE call, not consumed - if computation.gasMeter.gasRemaining <= SentryGasEIP2200: + if c.gasMeter.gasRemaining <= SentryGasEIP2200: raise newException(OutOfGas, "Gas not enough to perform EIP2200 SSTORE") - let stateDB = computation.vmState.readOnlyStateDB - let (currentValue, existing) = stateDB.getStorage(computation.msg.contractAddress, slot) + let stateDB = c.vmState.readOnlyStateDB + let (currentValue, existing) = stateDB.getStorage(c.msg.contractAddress, slot) let gasParam = GasParams(kind: Op.Sstore, s_isStorageEmpty: currentValue.isZero, s_currentValue: currentValue, - s_originalValue: stateDB.getCommittedStorage(computation.msg.contractAddress, slot) + s_originalValue: stateDB.getCommittedStorage(c.msg.contractAddress, slot) ) - (gasCost, gasRefund) = computation.gasCosts[Sstore].c_handler(value, gasParam) + (gasCost, gasRefund) = c.gasCosts[Sstore].c_handler(value, gasParam) - computation.gasMeter.consumeGas(gasCost, &"SSTORE EIP2200: {computation.msg.contractAddress}[{slot}] -> {value} ({currentValue})") + c.gasMeter.consumeGas(gasCost, &"SSTORE EIP2200: {c.msg.contractAddress}[{slot}] -> {value} ({currentValue})") if gasRefund != 0: - computation.gasMeter.refundGas(gasRefund) + c.gasMeter.refundGas(gasRefund) - computation.vmState.mutateStateDB: - db.setStorage(computation.msg.contractAddress, slot, value) + c.vmState.mutateStateDB: + db.setStorage(c.msg.contractAddress, slot, value) diff --git a/nimbus/vm/interpreter/utils/macros_procs_opcodes.nim b/nimbus/vm/interpreter/utils/macros_procs_opcodes.nim index d398dbdd9..8feb8ddad 100644 --- a/nimbus/vm/interpreter/utils/macros_procs_opcodes.nim +++ b/nimbus/vm/interpreter/utils/macros_procs_opcodes.nim @@ -31,7 +31,7 @@ macro op*(procname: untyped, inline: static[bool], stackParams_body: varargs[unt # we can't have a nicer macro signature `stackParams: varargs[untyped], body: untyped` # see https://github.com/nim-lang/Nim/issues/5855 and are forced to "pop" - let computation = newIdentNode("computation") + let computation = newIdentNode("c") var stackParams = stackParams_body # 1. Separate stackParams and body with pop @@ -59,12 +59,12 @@ macro op*(procname: untyped, inline: static[bool], stackParams_body: varargs[unt # TODO: replace by func to ensure no side effects if inline: result = quote do: - proc `procname`*(`computation`: BaseComputation) {.inline.} = + proc `procname`*(`computation`: Computation) {.inline.} = `popStackStmt` `body` else: result = quote do: - proc `procname`*(`computation`: BaseComputation) {.gcsafe.} = + proc `procname`*(`computation`: Computation) {.gcsafe.} = `popStackStmt` `body` @@ -76,7 +76,7 @@ macro genPush*(): untyped = for size in 1 .. 32: let name = genName(size) result.add quote do: - func `name`*(computation: BaseComputation) {.inline.}= + func `name`*(computation: Computation) {.inline.}= ## Push `size`-byte(s) on the stack computation.stack.push computation.code.readVmWord(`size`) @@ -87,7 +87,7 @@ macro genDup*(): untyped = for pos in 1 .. 16: let name = genName(pos) result.add quote do: - func `name`*(computation: BaseComputation) {.inline.}= + func `name`*(computation: Computation) {.inline.}= computation.stack.dup(`pos`) macro genSwap*(): untyped = @@ -97,16 +97,16 @@ macro genSwap*(): untyped = for pos in 1 .. 16: let name = genName(pos) result.add quote do: - func `name`*(computation: BaseComputation) {.inline.}= + func `name`*(computation: Computation) {.inline.}= computation.stack.swap(`pos`) -template checkInStaticContext*(comp: BaseComputation) = +template checkInStaticContext*(comp: Computation) = # TODO: if possible, this check only appear # when fork >= FkByzantium if emvcStatic == comp.msg.flags: raise newException(StaticContextError, "Cannot modify state while inside of a STATICCALL context") -proc logImpl(c: BaseComputation, opcode: Op, topicCount: int) = +proc logImpl(c: Computation, opcode: Op, topicCount: int) = doAssert(topicCount in 0 .. 4) checkInStaticContext(c) let (memStartPosition, size) = c.stack.popInt(2) @@ -129,8 +129,8 @@ proc logImpl(c: BaseComputation, opcode: Op, topicCount: int) = c.addLogEntry(log) template genLog*() = - proc log0*(c: BaseComputation) {.inline.} = logImpl(c, Log0, 0) - proc log1*(c: BaseComputation) {.inline.} = logImpl(c, Log1, 1) - proc log2*(c: BaseComputation) {.inline.} = logImpl(c, Log2, 2) - proc log3*(c: BaseComputation) {.inline.} = logImpl(c, Log3, 3) - proc log4*(c: BaseComputation) {.inline.} = logImpl(c, Log4, 4) + proc log0*(c: Computation) {.inline.} = logImpl(c, Log0, 0) + proc log1*(c: Computation) {.inline.} = logImpl(c, Log1, 1) + proc log2*(c: Computation) {.inline.} = logImpl(c, Log2, 2) + proc log3*(c: Computation) {.inline.} = logImpl(c, Log3, 3) + proc log4*(c: Computation) {.inline.} = logImpl(c, Log4, 4) diff --git a/nimbus/vm/interpreter_dispatch.nim b/nimbus/vm/interpreter_dispatch.nim index afbf3c657..407249136 100644 --- a/nimbus/vm/interpreter_dispatch.nim +++ b/nimbus/vm/interpreter_dispatch.nim @@ -16,7 +16,7 @@ import logScope: topics = "vm opcode" -func invalidInstruction*(computation: BaseComputation) {.inline.} = +func invalidInstruction*(c: Computation) {.inline.} = raise newException(InvalidInstruction, "Invalid instruction, received an opcode not implemented in the current fork.") let FrontierOpDispatch {.compileTime.}: array[Op, NimNode] = block: @@ -223,9 +223,9 @@ proc genIstanbulJumpTable(ops: array[Op, NimNode]): array[Op, NimNode] {.compile let IstanbulOpDispatch {.compileTime.}: array[Op, NimNode] = genIstanbulJumpTable(ConstantinopleOpDispatch) -proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNode = +proc opTableToCaseStmt(opTable: array[Op, NimNode], c: NimNode): NimNode = - let instr = quote do: `computation`.instr + let instr = quote do: `c`.instr result = nnkCaseStmt.newTree(instr) # Add a branch for each (opcode, proc) pair @@ -236,27 +236,27 @@ proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNo if op == Stop: quote do: trace "op: Stop" - if not `computation`.code.atEnd() and `computation`.tracingEnabled: + if not `c`.code.atEnd() and `c`.tracingEnabled: # we only trace `REAL STOP` and ignore `FAKE STOP` - `computation`.opIndex = `computation`.traceOpCodeStarted(`asOp`) - `computation`.traceOpCodeEnded(`asOp`, `computation`.opIndex) + `c`.opIndex = `c`.traceOpCodeStarted(`asOp`) + `c`.traceOpCodeEnded(`asOp`, `c`.opIndex) break else: if BaseGasCosts[op].kind == GckFixed: quote do: - if `computation`.tracingEnabled: - `computation`.opIndex = `computation`.traceOpCodeStarted(`asOp`) - `computation`.gasMeter.consumeGas(`computation`.gasCosts[`asOp`].cost, reason = $`asOp`) - `opImpl`(`computation`) - if `computation`.tracingEnabled: - `computation`.traceOpCodeEnded(`asOp`, `computation`.opIndex) + if `c`.tracingEnabled: + `c`.opIndex = `c`.traceOpCodeStarted(`asOp`) + `c`.gasMeter.consumeGas(`c`.gasCosts[`asOp`].cost, reason = $`asOp`) + `opImpl`(`c`) + if `c`.tracingEnabled: + `c`.traceOpCodeEnded(`asOp`, `c`.opIndex) else: quote do: - if `computation`.tracingEnabled: - `computation`.opIndex = `computation`.traceOpCodeStarted(`asOp`) - `opImpl`(`computation`) - if `computation`.tracingEnabled: - `computation`.traceOpCodeEnded(`asOp`, `computation`.opIndex) + if `c`.tracingEnabled: + `c`.opIndex = `c`.traceOpCodeStarted(`asOp`) + `opImpl`(`c`) + if `c`.tracingEnabled: + `c`.traceOpCodeEnded(`asOp`, `c`.opIndex) when `asOp` in {Return, Revert, SelfDestruct}: break @@ -267,90 +267,90 @@ proc opTableToCaseStmt(opTable: array[Op, NimNode], computation: NimNode): NimNo # Wrap the case statement in while true + computed goto result = quote do: - if `computation`.tracingEnabled: - `computation`.prepareTracer() + if `c`.tracingEnabled: + `c`.prepareTracer() while true: - `instr` = `computation`.code.next() + `instr` = `c`.code.next() #{.computedGoto.} # computed goto causing stack overflow, it consumes a lot of space # we could use manual jump table instead # TODO lots of macro magic here to unravel, with chronicles... - # `computation`.logger.log($`computation`.stack & "\n\n", fgGreen) + # `c`.logger.log($`c`.stack & "\n\n", fgGreen) `result` -macro genFrontierDispatch(computation: BaseComputation): untyped = - result = opTableToCaseStmt(FrontierOpDispatch, computation) +macro genFrontierDispatch(c: Computation): untyped = + result = opTableToCaseStmt(FrontierOpDispatch, c) -macro genHomesteadDispatch(computation: BaseComputation): untyped = - result = opTableToCaseStmt(HomesteadOpDispatch, computation) +macro genHomesteadDispatch(c: Computation): untyped = + result = opTableToCaseStmt(HomesteadOpDispatch, c) -macro genTangerineDispatch(computation: BaseComputation): untyped = - result = opTableToCaseStmt(TangerineOpDispatch, computation) +macro genTangerineDispatch(c: Computation): untyped = + result = opTableToCaseStmt(TangerineOpDispatch, c) -macro genSpuriousDispatch(computation: BaseComputation): untyped = - result = opTableToCaseStmt(SpuriousOpDispatch, computation) +macro genSpuriousDispatch(c: Computation): untyped = + result = opTableToCaseStmt(SpuriousOpDispatch, c) -macro genByzantiumDispatch(computation: BaseComputation): untyped = - result = opTableToCaseStmt(ByzantiumOpDispatch, computation) +macro genByzantiumDispatch(c: Computation): untyped = + result = opTableToCaseStmt(ByzantiumOpDispatch, c) -macro genConstantinopleDispatch(computation: BaseComputation): untyped = - result = opTableToCaseStmt(ConstantinopleOpDispatch, computation) +macro genConstantinopleDispatch(c: Computation): untyped = + result = opTableToCaseStmt(ConstantinopleOpDispatch, c) -macro genIstanbulDispatch(computation: BaseComputation): untyped = - result = opTableToCaseStmt(IstanbulOpDispatch, computation) +macro genIstanbulDispatch(c: Computation): untyped = + result = opTableToCaseStmt(IstanbulOpDispatch, c) -proc frontierVM(computation: BaseComputation) = - genFrontierDispatch(computation) +proc frontierVM(c: Computation) = + genFrontierDispatch(c) -proc homesteadVM(computation: BaseComputation) = - genHomesteadDispatch(computation) +proc homesteadVM(c: Computation) = + genHomesteadDispatch(c) -proc tangerineVM(computation: BaseComputation) = - genTangerineDispatch(computation) +proc tangerineVM(c: Computation) = + genTangerineDispatch(c) -proc spuriousVM(computation: BaseComputation) {.gcsafe.} = - genSpuriousDispatch(computation) +proc spuriousVM(c: Computation) {.gcsafe.} = + genSpuriousDispatch(c) -proc byzantiumVM(computation: BaseComputation) {.gcsafe.} = - genByzantiumDispatch(computation) +proc byzantiumVM(c: Computation) {.gcsafe.} = + genByzantiumDispatch(c) -proc constantinopleVM(computation: BaseComputation) {.gcsafe.} = - genConstantinopleDispatch(computation) +proc constantinopleVM(c: Computation) {.gcsafe.} = + genConstantinopleDispatch(c) -proc istanbulVM(computation: BaseComputation) {.gcsafe.} = - genIstanbulDispatch(computation) +proc istanbulVM(c: Computation) {.gcsafe.} = + genIstanbulDispatch(c) -proc selectVM(computation: BaseComputation, fork: Fork) {.gcsafe.} = +proc selectVM(c: Computation, fork: Fork) {.gcsafe.} = # TODO: Optimise getting fork and updating opCodeExec only when necessary case fork of FkFrontier..FkThawing: - computation.frontierVM() + c.frontierVM() of FkHomestead..FkDao: - computation.homesteadVM() + c.homesteadVM() of FkTangerine: - computation.tangerineVM() + c.tangerineVM() of FkSpurious: - computation.spuriousVM() + c.spuriousVM() of FkByzantium: - computation.byzantiumVM() + c.byzantiumVM() of FkConstantinople: - computation.constantinopleVM() + c.constantinopleVM() else: - computation.istanbulVM() + c.istanbulVM() -proc executeOpcodes(computation: BaseComputation) = - let fork = computation.fork +proc executeOpcodes(c: Computation) = + let fork = c.fork block: - if computation.execPrecompiles(fork): + if c.execPrecompiles(fork): break try: - computation.selectVM(fork) + c.selectVM(fork) except CatchableError as e: - computation.setError(&"Opcode Dispatch Error msg={e.msg}, depth={computation.msg.depth}", true) + c.setError(&"Opcode Dispatch Error msg={e.msg}, depth={c.msg.depth}", true) - computation.nextProc() - if computation.isError(): - if computation.tracingEnabled: computation.traceError() - debug "executeOpcodes error", msg=computation.error.info + c.nextProc() + if c.isError(): + if c.tracingEnabled: c.traceError() + debug "executeOpcodes error", msg=c.error.info diff --git a/nimbus/vm/precompiles.nim b/nimbus/vm/precompiles.nim index d88f8cccf..72622ab0f 100644 --- a/nimbus/vm/precompiles.nim +++ b/nimbus/vm/precompiles.nim @@ -18,7 +18,7 @@ type # Istanbul paBlake2bf = 9 -proc getSignature(computation: BaseComputation): (array[32, byte], Signature) = +proc getSignature(computation: Computation): (array[32, byte], Signature) = # input is Hash, V, R, S template data: untyped = computation.msg.data var bytes: array[65, byte] # will hold R[32], S[32], V[1], in that order @@ -91,7 +91,7 @@ proc getFR(data: openarray[byte]): FR = if not result.fromBytes2(data): raise newException(ValidationError, "Could not get FR value") -proc ecRecover*(computation: BaseComputation) = +proc ecRecover*(computation: Computation) = computation.gasMeter.consumeGas( GasECRecover, reason="ECRecover Precompile") @@ -107,7 +107,7 @@ proc ecRecover*(computation: BaseComputation) = computation.rawOutput[12..31] = pubKey.toCanonicalAddress() trace "ECRecover precompile", derivedKey = pubKey.toCanonicalAddress() -proc sha256*(computation: BaseComputation) = +proc sha256*(computation: Computation) = let wordCount = wordCount(computation.msg.data.len) gasFee = GasSHA256 + wordCount * GasSHA256Word @@ -116,7 +116,7 @@ proc sha256*(computation: BaseComputation) = computation.rawOutput = @(nimcrypto.sha_256.digest(computation.msg.data).data) trace "SHA256 precompile", output = computation.rawOutput.toHex -proc ripemd160*(computation: BaseComputation) = +proc ripemd160*(computation: Computation) = let wordCount = wordCount(computation.msg.data.len) gasFee = GasRIPEMD160 + wordCount * GasRIPEMD160Word @@ -126,7 +126,7 @@ proc ripemd160*(computation: BaseComputation) = computation.rawOutput[12..31] = @(nimcrypto.ripemd160.digest(computation.msg.data).data) trace "RIPEMD160 precompile", output = computation.rawOutput.toHex -proc identity*(computation: BaseComputation) = +proc identity*(computation: Computation) = let wordCount = wordCount(computation.msg.data.len) gasFee = GasIdentity + wordCount * GasIdentityWord @@ -135,7 +135,7 @@ proc identity*(computation: BaseComputation) = computation.rawOutput = computation.msg.data trace "Identity precompile", output = computation.rawOutput.toHex -proc modExpInternal(computation: BaseComputation, base_len, exp_len, mod_len: int, T: type StUint) = +proc modExpInternal(computation: Computation, base_len, exp_len, mod_len: int, T: type StUint) = template rawMsg: untyped {.dirty.} = computation.msg.data @@ -208,7 +208,7 @@ proc modExpInternal(computation: BaseComputation, base_len, exp_len, mod_len: in computation.rawOutput = newSeq[byte](mod_len) computation.rawOutput[^output.len..^1] = output[0..^1] -proc modExp*(computation: BaseComputation) = +proc modExp*(computation: Computation) = ## Modular exponentiation precompiled contract ## Yellow Paper Appendix E ## EIP-198 - https://github.com/ethereum/EIPs/blob/master/EIPS/eip-198.md @@ -237,7 +237,7 @@ proc modExp*(computation: BaseComputation) = else: raise newException(EVMError, "The Nimbus VM doesn't support modular exponentiation with numbers larger than uint8192") -proc bn256ecAdd*(computation: BaseComputation, fork: Fork = FkByzantium) = +proc bn256ecAdd*(computation: Computation, fork: Fork = FkByzantium) = let gasFee = if fork < FkIstanbul: GasECAdd else: GasECAddIstanbul computation.gasMeter.consumeGas(gasFee, reason = "ecAdd Precompile") @@ -258,7 +258,7 @@ proc bn256ecAdd*(computation: BaseComputation, fork: Fork = FkByzantium) = computation.rawOutput = @output -proc bn256ecMul*(computation: BaseComputation, fork: Fork = FkByzantium) = +proc bn256ecMul*(computation: Computation, fork: Fork = FkByzantium) = let gasFee = if fork < FkIstanbul: GasECMul else: GasECMulIstanbul computation.gasMeter.consumeGas(gasFee, reason="ecMul Precompile") @@ -281,7 +281,7 @@ proc bn256ecMul*(computation: BaseComputation, fork: Fork = FkByzantium) = computation.rawOutput = @output -proc bn256ecPairing*(computation: BaseComputation, fork: Fork = FkByzantium) = +proc bn256ecPairing*(computation: Computation, fork: Fork = FkByzantium) = let msglen = len(computation.msg.data) if msglen mod 192 != 0: raise newException(ValidationError, "Invalid input length") @@ -318,7 +318,7 @@ proc bn256ecPairing*(computation: BaseComputation, fork: Fork = FkByzantium) = computation.rawOutput = @output -proc blake2bf*(computation: BaseComputation) = +proc blake2bf*(computation: Computation) = template input(): untyped = computation.msg.data @@ -337,7 +337,7 @@ proc getMaxPrecompileAddr(fork: Fork): PrecompileAddresses = elif fork < FkIstanbul: paPairing else: PrecompileAddresses.high -proc execPrecompiles*(computation: BaseComputation, fork: Fork): bool {.inline.} = +proc execPrecompiles*(computation: Computation, fork: Fork): bool {.inline.} = for i in 0..18: if computation.msg.codeAddress[i] != 0: return diff --git a/nimbus/vm/transaction_tracer.nim b/nimbus/vm/transaction_tracer.nim index 907964bb2..89edb75e7 100644 --- a/nimbus/vm/transaction_tracer.nim +++ b/nimbus/vm/transaction_tracer.nim @@ -44,7 +44,7 @@ iterator storage(tracer: TransactionTracer, compDepth: int): Uint256 = for key in tracer.storageKeys[compDepth]: yield key -proc traceOpCodeStarted*(tracer: var TransactionTracer, c: BaseComputation, op: Op): int = +proc traceOpCodeStarted*(tracer: var TransactionTracer, c: Computation, op: Op): int = if unlikely tracer.trace.isNil: tracer.initTracer() @@ -90,7 +90,7 @@ proc traceOpCodeStarted*(tracer: var TransactionTracer, c: BaseComputation, op: result = tracer.trace["structLogs"].len - 1 -proc traceOpCodeEnded*(tracer: var TransactionTracer, c: BaseComputation, op: Op, lastIndex: int) = +proc traceOpCodeEnded*(tracer: var TransactionTracer, c: Computation, op: Op, lastIndex: int) = let j = tracer.trace["structLogs"].elems[lastIndex] # TODO: figure out how to get storage @@ -114,7 +114,7 @@ proc traceOpCodeEnded*(tracer: var TransactionTracer, c: BaseComputation, op: Op trace "Op", json = j.pretty() -proc traceError*(tracer: var TransactionTracer, c: BaseComputation) = +proc traceError*(tracer: var TransactionTracer, c: Computation) = if tracer.trace["structLogs"].elems.len > 0: let j = tracer.trace["structLogs"].elems[^1] j["error"] = %(c.error.info) diff --git a/nimbus/vm_state_transactions.nim b/nimbus/vm_state_transactions.nim index a9ca2502b..8bc7f1cf9 100644 --- a/nimbus/vm_state_transactions.nim +++ b/nimbus/vm_state_transactions.nim @@ -26,7 +26,7 @@ proc validateTransaction*(vmState: BaseVMState, tx: Transaction, sender: EthAddr tx.accountNonce == account.nonce and account.balance >= gasCost -proc setupComputation*(vmState: BaseVMState, tx: Transaction, sender, recipient: EthAddress, fork: Fork) : BaseComputation = +proc setupComputation*(vmState: BaseVMState, tx: Transaction, sender, recipient: EthAddress, fork: Fork) : Computation = var gas = tx.gasLimit - tx.intrinsicGas(fork) # TODO: refactor message to use byterange @@ -58,46 +58,46 @@ proc setupComputation*(vmState: BaseVMState, tx: Transaction, sender, recipient: code: code ) - result = newBaseComputation(vmState, msg, some(fork)) + result = newComputation(vmState, msg, some(fork)) doAssert result.isOriginComputation -proc execComputation*(computation: var BaseComputation) = - if computation.msg.isCreate: - computation.applyMessage(Create) +proc execComputation*(c: Computation) = + if c.msg.isCreate: + c.applyMessage(Create) else: - computation.applyMessage(Call) + c.applyMessage(Call) - computation.vmState.mutateStateDB: + c.vmState.mutateStateDB: var suicidedCount = 0 - for deletedAccount in computation.accountsForDeletion: + for deletedAccount in c.accountsForDeletion: db.deleteAccount deletedAccount inc suicidedCount # FIXME: hook this into actual RefundSelfDestruct const RefundSelfDestruct = 24_000 - computation.gasMeter.refundGas(RefundSelfDestruct * suicidedCount) + c.gasMeter.refundGas(RefundSelfDestruct * suicidedCount) - if computation.fork >= FkSpurious: - computation.collectTouchedAccounts() + if c.fork >= FkSpurious: + c.collectTouchedAccounts() - computation.vmstate.status = computation.isSuccess - if computation.isSuccess: - computation.vmState.addLogs(computation.logEntries) + c.vmstate.status = c.isSuccess + if c.isSuccess: + c.vmState.addLogs(c.logEntries) -proc refundGas*(computation: BaseComputation, tx: Transaction, sender: EthAddress): GasInt = +proc refundGas*(c: Computation, tx: Transaction, sender: EthAddress): GasInt = let - gasRemaining = computation.gasMeter.gasRemaining - gasRefunded = computation.getGasRefund() + gasRemaining = c.gasMeter.gasRemaining + gasRefunded = c.getGasRefund() gasUsed = tx.gasLimit - gasRemaining gasRefund = min(gasRefunded, gasUsed div 2) - computation.vmState.mutateStateDB: + c.vmState.mutateStateDB: db.addBalance(sender, (gasRemaining + gasRefund).u256 * tx.gasPrice.u256) result = gasUsed - gasRefund #[ -method executeTransaction(vmState: BaseVMState, transaction: Transaction): (BaseComputation, BlockHeader) {.base.}= +method executeTransaction(vmState: BaseVMState, transaction: Transaction): (Computation, BlockHeader) {.base.}= # Execute the transaction in the vm # TODO: introduced here: https://github.com/ethereum/py-evm/commit/21c57f2d56ab91bb62723c3f9ebe291d0b132dde # Refactored/Removed here: https://github.com/ethereum/py-evm/commit/cc991bf @@ -105,7 +105,7 @@ method executeTransaction(vmState: BaseVMState, transaction: Transaction): (Base raise newException(ValueError, "Must be implemented by subclasses") -method addTransaction*(vmState: BaseVMState, transaction: Transaction, computation: BaseComputation, b: Block): (Block, Table[string, string]) = +method addTransaction*(vmState: BaseVMState, transaction: Transaction, c: Computation, 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, @@ -138,7 +138,7 @@ method applyTransaction*( vmState: BaseVMState, transaction: Transaction, b: Block, - isStateless: bool): (BaseComputation, Block, Table[string, string]) = + isStateless: bool): (Computation, 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 diff --git a/nimbus/vm_types.nim b/nimbus/vm_types.nim index 8b203a2e4..377aeb9f8 100644 --- a/nimbus/vm_types.nim +++ b/nimbus/vm_types.nim @@ -51,7 +51,7 @@ type transaction*: DbTransaction intermediateRoot*: Hash256 - BaseComputation* = ref object of RootObj + Computation* = ref object # The execution computation vmState*: BaseVMState msg*: Message diff --git a/tests/macro_assembler.nim b/tests/macro_assembler.nim index 4f5af217a..8de6bded9 100644 --- a/tests/macro_assembler.nim +++ b/tests/macro_assembler.nim @@ -194,7 +194,7 @@ proc generateVMProxy(boa: Assembler): NimNode = const blockFile = "tests" / "fixtures" / "PersistBlockTests" / "block47205.json" -proc initComputation(vmState: BaseVMState, tx: Transaction, sender: EthAddress, data: seq[byte], forkOverride=none(Fork)) : BaseComputation = +proc initComputation(vmState: BaseVMState, tx: Transaction, sender: EthAddress, data: seq[byte], forkOverride=none(Fork)) : Computation = doAssert tx.isContractCreation let fork = @@ -220,7 +220,7 @@ proc initComputation(vmState: BaseVMState, tx: Transaction, sender: EthAddress, code: tx.payload ) - newBaseComputation(vmState, msg, some(fork)) + newComputation(vmState, msg, some(fork)) proc initDatabase*(): (Uint256, BaseChainDB) = let @@ -236,7 +236,7 @@ proc initDatabase*(): (Uint256, BaseChainDB) = result = (blockNumber, newBaseChainDB(memoryDB, false)) -proc initComputation(blockNumber: Uint256, chainDB: BaseChainDB, payload, data: seq[byte], fork: Fork): BaseComputation = +proc initComputation(blockNumber: Uint256, chainDB: BaseChainDB, payload, data: seq[byte], fork: Fork): Computation = let parentNumber = blockNumber - 1 parent = chainDB.getBlockHeader(parentNumber) diff --git a/tests/test_precompiles.nim b/tests/test_precompiles.nim index 9c9f23cd4..ddcda21dd 100644 --- a/tests/test_precompiles.nim +++ b/tests/test_precompiles.nim @@ -41,7 +41,7 @@ template doTest(fixture: JsonNode, address: byte, action: untyped): untyped = data: data, code: @[] ) - computation = newBaseComputation(vmState, message) + computation = newComputation(vmState, message) echo "Running ", action.astToStr, " - ", test["name"] `action`(computation) let c = computation.rawOutput == expected diff --git a/tests/test_vm_json.nim b/tests/test_vm_json.nim index 4f26e3c9b..fee7beeb8 100644 --- a/tests/test_vm_json.nim +++ b/tests/test_vm_json.nim @@ -59,7 +59,7 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) = code: code ) - var computation = newBaseComputation(vmState, message) + var computation = newComputation(vmState, message) computation.executeOpcodes() if not fixture{"post"}.isNil: