2021-04-30 09:33:14 +00:00
|
|
|
# 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
|
2021-05-03 08:07:56 +00:00
|
|
|
eth/common/eth_types, stint, options, stew/byteutils,
|
2021-05-03 09:04:15 +00:00
|
|
|
".."/[vm_types, vm_types2, vm_state, vm_computation, utils],
|
2021-05-03 08:08:11 +00:00
|
|
|
".."/[db/db_chain, config, vm_state_transactions, rpc/hexstrings],
|
|
|
|
".."/[db/accounts_cache, p2p/executor], eth/trie/db
|
2021-04-30 09:33:14 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
RpcCallData* = object
|
|
|
|
source*: EthAddress
|
|
|
|
to*: EthAddress
|
|
|
|
gas*: GasInt
|
|
|
|
gasPrice*: GasInt
|
|
|
|
value*: UInt256
|
|
|
|
data*: seq[byte]
|
|
|
|
contractCreation*: bool
|
|
|
|
|
2021-05-03 09:04:15 +00:00
|
|
|
proc rpcSetupComputation*(vmState: BaseVMState, call: RpcCallData,
|
|
|
|
fork: Fork, gasLimit: GasInt): Computation =
|
2021-04-30 09:33:14 +00:00
|
|
|
vmState.setupTxContext(
|
|
|
|
origin = call.source,
|
|
|
|
gasPrice = call.gasPrice,
|
|
|
|
forkOverride = some(fork)
|
|
|
|
)
|
|
|
|
|
2021-05-03 09:04:15 +00:00
|
|
|
var msg = Message(
|
|
|
|
kind: if call.contractCreation: evmcCreate else: evmcCall,
|
2021-04-30 09:33:14 +00:00
|
|
|
depth: 0,
|
2021-05-03 09:04:15 +00:00
|
|
|
gas: gasLimit,
|
2021-04-30 09:33:14 +00:00
|
|
|
sender: call.source,
|
2021-05-03 09:04:15 +00:00
|
|
|
contractAddress:
|
|
|
|
if not call.contractCreation:
|
|
|
|
call.to
|
|
|
|
else:
|
|
|
|
generateAddress(call.source, vmState.readOnlyStateDB.getNonce(call.source)),
|
2021-04-30 09:33:14 +00:00
|
|
|
codeAddress: call.to,
|
|
|
|
value: call.value,
|
|
|
|
data: call.data
|
2021-05-03 09:04:15 +00:00
|
|
|
)
|
2021-04-30 09:33:14 +00:00
|
|
|
|
|
|
|
return newComputation(vmState, msg)
|
2021-05-03 08:08:03 +00:00
|
|
|
|
|
|
|
proc rpcDoCall*(call: RpcCallData, header: BlockHeader, chain: BaseChainDB): HexDataStr =
|
|
|
|
# TODO: handle revert and error
|
|
|
|
# TODO: handle contract ABI
|
|
|
|
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)
|
2021-05-03 09:04:15 +00:00
|
|
|
comp = rpcSetupComputation(vmState, call, fork, call.gas)
|
2021-05-03 08:08:03 +00:00
|
|
|
|
|
|
|
comp.execComputation()
|
|
|
|
result = hexDataStr(comp.output)
|
2021-05-03 08:08:11 +00:00
|
|
|
|
2021-05-03 08:07:56 +00:00
|
|
|
proc rpcMakeCall*(call: RpcCallData, header: BlockHeader, chain: BaseChainDB): (string, GasInt, bool) =
|
|
|
|
# TODO: handle revert
|
|
|
|
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)
|
2021-05-03 09:04:15 +00:00
|
|
|
comp = rpcSetupComputation(vmState, call, fork, call.gas)
|
2021-05-03 08:07:56 +00:00
|
|
|
|
|
|
|
let gas = comp.gasMeter.gasRemaining
|
|
|
|
comp.execComputation()
|
|
|
|
return (comp.output.toHex, gas - comp.gasMeter.gasRemaining, comp.isError)
|
|
|
|
|
2021-05-03 08:08:11 +00:00
|
|
|
proc rpcEstimateGas*(call: RpcCallData, header: BlockHeader, chain: BaseChainDB, haveGasLimit: bool): GasInt =
|
|
|
|
# TODO: handle revert and error
|
|
|
|
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)
|
|
|
|
tx = Transaction(
|
|
|
|
accountNonce: vmState.accountdb.getNonce(call.source),
|
|
|
|
gasPrice: call.gasPrice,
|
|
|
|
gasLimit: if haveGasLimit: call.gas else: header.gasLimit - vmState.cumulativeGasUsed,
|
|
|
|
to : call.to,
|
|
|
|
value : call.value,
|
|
|
|
payload : call.data,
|
|
|
|
isContractCreation: call.contractCreation
|
|
|
|
)
|
|
|
|
|
|
|
|
var dbTx = chain.db.beginTransaction()
|
|
|
|
defer: dbTx.dispose()
|
|
|
|
result = processTransaction(tx, call.source, vmState, fork)
|
|
|
|
dbTx.dispose()
|