diff --git a/nimbus/graphql/ethapi.nim b/nimbus/graphql/ethapi.nim index 2781af8fa..2337ea90a 100644 --- a/nimbus/graphql/ethapi.nim +++ b/nimbus/graphql/ethapi.nim @@ -15,7 +15,8 @@ import graphql/common/types, graphql/httpserver, ../db/[db_chain, state_db], ../errors, ../utils, ../transaction, ../rpc/rpc_utils, ../vm_state, ../config, - ../vm_computation, ../vm_state_transactions + ../vm_computation, ../vm_state_transactions, + ../transaction/call_evm from eth/p2p import EthereumNode export httpserver @@ -716,9 +717,9 @@ proc blockAccount(ud: RootRef, params: Args, parent: Node): RespResult {.apiPrag let address = hexToByteArray[20](params[0].val.stringVal) ctx.accountNode(h.header, address) -proc toCallData(n: Node): (CallData, bool) = +proc toCallData(n: Node): (RpcCallData, bool) = # phew, probably need to use macro here :) - var cd: CallData + var cd: RpcCallData var gasLimit = false if n[0][1].kind != nkEmpty: cd.source = hextoByteArray[20](n[0][1].stringVal) @@ -744,14 +745,14 @@ proc toCallData(n: Node): (CallData, bool) = (cd, gasLimit) -proc makeCall(ctx: GraphqlContextRef, callData: CallData, header: BlockHeader, chainDB: BaseChainDB): RespResult = +proc makeCall(ctx: GraphqlContextRef, callData: RpcCallData, header: BlockHeader, chainDB: BaseChainDB): RespResult = # TODO: handle revert var # we use current header stateRoot, unlike block validation # which use previous block stateRoot vmState = newBaseVMState(header.stateRoot, header, chainDB) fork = toFork(chainDB.config, header.blockNumber) - comp = setupComputation(vmState, callData, fork) + comp = rpcSetupComputation(vmState, callData, fork) let gas = comp.gasMeter.gasRemaining comp.execComputation() diff --git a/nimbus/rpc/rpc_utils.nim b/nimbus/rpc/rpc_utils.nim index bac7a71bc..0eec165c9 100644 --- a/nimbus/rpc/rpc_utils.nim +++ b/nimbus/rpc/rpc_utils.nim @@ -11,7 +11,8 @@ import hexstrings, eth/[common, rlp, keys, trie/db], stew/byteutils, nimcrypto, ../db/[db_chain, accounts_cache], strutils, algorithm, options, times, json, ../constants, stint, hexstrings, rpc_types, ../config, ../vm_state_transactions, ../vm_state, ../vm_types, ../vm_types2, - ../vm_computation, ../p2p/executor, ../utils, ../transaction + ../vm_computation, ../p2p/executor, ../utils, ../transaction, + ../transaction/call_evm type UnsignedTx* = object @@ -23,15 +24,6 @@ type payload* : Blob contractCreation* {.rlpIgnore.}: bool - CallData* = object - source*: EthAddress - to*: EthAddress - gas*: GasInt - gasPrice*: GasInt - value*: UInt256 - data*: seq[byte] - contractCreation*: bool - proc read(rlp: var Rlp, t: var UnsignedTx, _: type EthAddress): EthAddress {.inline.} = if rlp.blobLen != 0: result = rlp.read(EthAddress) @@ -161,7 +153,7 @@ proc signTransaction*(tx: UnsignedTx, chain: BaseChainDB, privateKey: PrivateKey S: Uint256.fromBytesBE(sig[32..63]) ) -proc callData*(call: EthCall, callMode: bool = true, chain: BaseChainDB): CallData = +proc callData*(call: EthCall, callMode: bool = true, chain: BaseChainDB): RpcCallData = if call.source.isSome: result.source = toAddress(call.source.get) @@ -188,40 +180,20 @@ proc callData*(call: EthCall, callMode: bool = true, chain: BaseChainDB): CallDa if call.data.isSome: result.data = hexToSeqByte(call.data.get.string) -proc setupComputation*(vmState: BaseVMState, call: CallData, fork: Fork) : Computation = - vmState.setupTxContext( - origin = call.source, - gasPrice = call.gasPrice, - forkOverride = some(fork) - ) - - let msg = Message( - kind: evmcCall, - depth: 0, - gas: call.gas, - sender: call.source, - contractAddress: call.to, - codeAddress: call.to, - value: call.value, - data: call.data - ) - - result = newComputation(vmState, msg) - -proc doCall*(call: CallData, header: BlockHeader, chain: BaseChainDB): HexDataStr = +proc doCall*(call: RpcCallData, header: BlockHeader, chain: BaseChainDB): HexDataStr = var # we use current header stateRoot, unlike block validation # which use previous block stateRoot vmState = newBaseVMState(header.stateRoot, header, chain) fork = toFork(chain.config, header.blockNumber) - comp = setupComputation(vmState, call, fork) + comp = rpcSetupComputation(vmState, call, fork) comp.execComputation() result = hexDataStr(comp.output) # TODO: handle revert and error # TODO: handle contract ABI -proc estimateGas*(call: CallData, header: BlockHeader, chain: BaseChainDB, haveGasLimit: bool): GasInt = +proc estimateGas*(call: RpcCallData, header: BlockHeader, chain: BaseChainDB, haveGasLimit: bool): GasInt = var # we use current header stateRoot, unlike block validation # which use previous block stateRoot diff --git a/nimbus/transaction/call_evm.nim b/nimbus/transaction/call_evm.nim new file mode 100644 index 000000000..9ba5b4133 --- /dev/null +++ b/nimbus/transaction/call_evm.nim @@ -0,0 +1,41 @@ +# Nimbus - Various ways of calling the EVM +# +# Copyright (c) 2018-2021 Status Research & Development GmbH +# Licensed under either of +# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) +# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +import + eth/common/eth_types, stint, options, + ".."/[vm_types, vm_types2, vm_state, vm_computation] + +type + RpcCallData* = object + source*: EthAddress + to*: EthAddress + gas*: GasInt + gasPrice*: GasInt + value*: UInt256 + data*: seq[byte] + contractCreation*: bool + +proc rpcSetupComputation*(vmState: BaseVMState, call: RpcCallData, fork: Fork): Computation = + vmState.setupTxContext( + origin = call.source, + gasPrice = call.gasPrice, + forkOverride = some(fork) + ) + + let msg = Message( + kind: evmcCall, + depth: 0, + gas: call.gas, + sender: call.source, + contractAddress: call.to, + codeAddress: call.to, + value: call.value, + data: call.data + ) + + return newComputation(vmState, msg)