RPC: Move EVM-calling function estimateGas to rpcEstimateGas

`estimateGas` used by JSON-RPC is another way to setup and call the EVM,
also used by GraphQL.  Move it to `transaction/call_evm`.

This function has too much direct knowledge of details that shouldn't be used
outside transaction handling code, details we need to change when changing the
db and transaction memory layer.

Moving this one exposed quite a bit of abstraction leakage, as it calls
directly to the hexary trie db around `processTransaction`.

It looks like the _intended_ functionality of `estimateGas` is similar to
`rpcDoCall` with the only real difference being to not store the final state.
It looks like the extra stuff in `estimateGas` compared with `doCall` is a
messy workaround for computation not exposing the right API ("don't save final
state") for RPC to use.

Signed-off-by: Jamie Lokier <jamie@shareable.org>
This commit is contained in:
Jamie Lokier 2021-05-03 09:08:11 +01:00
parent 2732af99eb
commit 8bda81496a
No known key found for this signature in database
GPG Key ID: CBC25C68435C30A2
4 changed files with 26 additions and 25 deletions

View File

@ -778,7 +778,7 @@ proc blockEstimateGas(ud: RootRef, params: Args, parent: Node): RespResult {.api
let param = params[0].val
try:
let (callData, gasLimit) = toCallData(param)
let gasUsed = estimateGas(callData, h.header, ctx.chainDB, gasLimit)
let gasUsed = rpcEstimateGas(callData, h.header, ctx.chainDB, gasLimit)
longNode(gasUsed)
except Exception as em:
err("estimateGas error: " & em.msg)

View File

@ -275,7 +275,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB , server: RpcServer) =
let
header = chain.headerFromTag(quantityTag)
callData = callData(call, false, chain)
gasUsed = estimateGas(callData, header, chain, call.gas.isSome)
gasUsed = rpcEstimateGas(callData, header, chain, call.gas.isSome)
result = encodeQuantity(gasUsed.uint64)
server.rpc("eth_getBlockByHash") do(data: EthHashStr, fullTransactions: bool) -> Option[BlockObject]:

View File

@ -180,28 +180,6 @@ proc callData*(call: EthCall, callMode: bool = true, chain: BaseChainDB): RpcCal
if call.data.isSome:
result.data = hexToSeqByte(call.data.get.string)
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
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()
# TODO: handle revert and error
proc populateTransactionObject*(tx: Transaction, header: BlockHeader, txIndex: int): TransactionObject =
result.blockHash = some(header.hash)
result.blockNumber = some(encodeQuantity(header.blockNumber))

View File

@ -9,7 +9,8 @@
import
eth/common/eth_types, stint, options,
".."/[vm_types, vm_types2, vm_state, vm_computation],
".."/[db/db_chain, config, vm_state_transactions, rpc/hexstrings]
".."/[db/db_chain, config, vm_state_transactions, rpc/hexstrings],
".."/[db/accounts_cache, p2p/executor], eth/trie/db
type
RpcCallData* = object
@ -53,3 +54,25 @@ proc rpcDoCall*(call: RpcCallData, header: BlockHeader, chain: BaseChainDB): Hex
comp.execComputation()
result = hexDataStr(comp.output)
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()