mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-12 21:34:33 +00:00
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,
|
eth_common, eth_p2p, eth_keys, eth_trie/db, rlp,
|
||||||
../utils/header, ../transaction, ../config, ../vm_state, ../constants, ../vm_types,
|
../utils/header, ../transaction, ../config, ../vm_state, ../constants, ../vm_types,
|
||||||
../vm_state_transactions, ../utils/addresses,
|
../vm_state_transactions, ../utils/addresses,
|
||||||
../db/[db_chain, state_db, storage_types],
|
../vm/[interpreter_dispatch, computation],
|
||||||
rpc_types, rpc_utils, ../vm/[message, 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?
|
# TODO: Account balance u256 but GasInt is int64?
|
||||||
addressDb.getBalance(address).truncate(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) =
|
proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
||||||
|
|
||||||
func getAccountDb(header: BlockHeader): ReadOnlyStateDB =
|
func getAccountDb(header: BlockHeader): ReadOnlyStateDB =
|
||||||
@ -274,7 +320,7 @@ proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) =
|
|||||||
|
|
||||||
discard comp.execComputation
|
discard comp.execComputation
|
||||||
result = ("0x" & nimcrypto.toHex(comp.output)).HexDataStr
|
result = ("0x" & nimcrypto.toHex(comp.output)).HexDataStr
|
||||||
|
|
||||||
rpcsrv.rpc("eth_estimateGas") do(call: EthCall, quantityTag: string) -> GasInt:
|
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.
|
## 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
|
## 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.
|
## call: the transaction call object.
|
||||||
## quantityTag: integer block number, or the string "latest", "earliest" or "pending", see the default block parameter.
|
## quantityTag: integer block number, or the string "latest", "earliest" or "pending", see the default block parameter.
|
||||||
## Returns the amount of gas used.
|
## 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 =
|
func populateBlockObject(header: BlockHeader, blockBody: BlockBody): BlockObject =
|
||||||
result.number = some(header.blockNumber)
|
result.number = some(header.blockNumber)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user