Initial commit for eth_estimateGas
This commit is contained in:
parent
03c1664c8a
commit
ac9fb37465
|
@ -13,7 +13,7 @@ import
|
|||
eth_common, eth_p2p, eth_keys, eth_trie/db, rlp,
|
||||
../utils/header, ../transaction, ../config, ../vm_state, ../constants, ../vm_types,
|
||||
../vm_state_transactions, ../utils/addresses,
|
||||
../db/[db_chain, state_db, storage_types],
|
||||
../vm/[interpreter_dispatch, computation],
|
||||
rpc_types, rpc_utils, ../vm/[message, computation]
|
||||
|
||||
#[
|
||||
|
@ -33,6 +33,52 @@ template balance(addressDb: ReadOnlyStateDb, address: EthAddress): GasInt =
|
|||
# TODO: Account balance u256 but GasInt is int64?
|
||||
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 =
|
||||
# Note that vmState may be altered
|
||||
setupComputation(
|
||||
vmState.blockHeader,
|
||||
vmState,
|
||||
transaction,
|
||||
sender)
|
||||
|
||||
proc dummyTransaction(gasLimit, gasPrice: GasInt, destination: EthAddress, value: UInt256): Transaction =
|
||||
Transaction(
|
||||
accountNonce: 0.AccountNonce,
|
||||
gasPrice: gasPrice,
|
||||
gasLimit: gasLimit,
|
||||
to: destination,
|
||||
value: value
|
||||
)
|
||||
var
|
||||
hiGas = vmState.gasLimit
|
||||
loGas = transaction.intrinsicGas
|
||||
gasPrice = transaction.gasPrice # TODO: Or zero?
|
||||
|
||||
proc tryTransaction(vmState: var BaseVMState, gasLimit: GasInt): bool =
|
||||
var
|
||||
spoofTransaction = dummyTransaction(gasLimit, gasPrice, transaction.to, transaction.value)
|
||||
computation = vmState.dummyComputation(spoofTransaction, sender)
|
||||
computation.executeOpcodes
|
||||
if not computation.isError:
|
||||
return true
|
||||
|
||||
if vmState.tryTransaction(loGas):
|
||||
return loGas
|
||||
if not vmState.tryTransaction(hiGas):
|
||||
return 0.GasInt # TODO: Reraise error from computation
|
||||
|
||||
var
|
||||
minVal = vmState.gasLimit
|
||||
maxVal = transaction.intrinsicGas
|
||||
while loGas - hiGas > tolerance:
|
||||
let midPoint = (loGas + hiGas) div 2
|
||||
if vmState.tryTransaction(midPoint):
|
||||
minVal = midPoint
|
||||
else:
|
||||
maxVal = midPoint
|
||||
result = minVal
|
||||
|
||||
proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
||||
|
||||
func getAccountDb(header: BlockHeader): ReadOnlyStateDB =
|
||||
|
@ -274,7 +320,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
|
||||
discard comp.execComputation
|
||||
result = ("0x" & nimcrypto.toHex(comp.output)).HexDataStr
|
||||
|
||||
|
||||
rpcsrv.rpc("eth_estimateGas") do(call: EthCall, quantityTag: string) -> GasInt:
|
||||
## Generates and returns an estimate of how much gas is necessary to allow the transaction to complete.
|
||||
## The transaction will not be added to the blockchain. Note that the estimate may be significantly more than
|
||||
|
@ -283,7 +329,28 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||
## call: the transaction call object.
|
||||
## quantityTag: integer block number, or the string "latest", "earliest" or "pending", see the default block parameter.
|
||||
## Returns the amount of gas used.
|
||||
discard
|
||||
# TODO: Use optional fields with EthCall
|
||||
var
|
||||
header = chain.headerFromTag(quantityTag)
|
||||
vmState = newBaseVMState(header, chain)
|
||||
let
|
||||
gasLimit = if call.gas > 0.GasInt: call.gas else: header.gasLimit
|
||||
gasPrice = if call.gasPrice > 0: call.gasPrice else: 0.GasInt
|
||||
curState = chain.getStateDb(header.stateRoot, true)
|
||||
sender = call.source.string.strToAddress
|
||||
destination = call.to.string.strToAddress
|
||||
nonce = curState.getNonce(sender)
|
||||
value = call.value
|
||||
# TODO: Use initTransaction when merged
|
||||
transaction = Transaction(
|
||||
accountNonce: nonce,
|
||||
gasPrice: gasPrice,
|
||||
gasLimit: gasLimit,
|
||||
to: destination,
|
||||
value: value.u256,
|
||||
payload: @[]
|
||||
)
|
||||
result = vmState.binarySearchGas(transaction, sender, gasPrice)
|
||||
|
||||
func populateBlockObject(header: BlockHeader, blockBody: BlockBody): BlockObject =
|
||||
result.number = some(header.blockNumber)
|
||||
|
|
Loading…
Reference in New Issue