mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-12 21:34:33 +00:00
Implement RPC method eth_getAccessList (#2091)
* Implement RPC method eth_getAccessList * Fix comment
This commit is contained in:
parent
8ed40c78e0
commit
7ea6d719d9
@ -208,9 +208,6 @@ proc exchangeCapabilities*(client: RpcClient,
|
|||||||
wrapTrySimpleRes:
|
wrapTrySimpleRes:
|
||||||
client.engine_exchangeCapabilities(methods)
|
client.engine_exchangeCapabilities(methods)
|
||||||
|
|
||||||
proc toBlockNumber(n: Quantity): common.BlockNumber =
|
|
||||||
n.uint64.toBlockNumber
|
|
||||||
|
|
||||||
proc toBlockNonce(n: Option[FixedBytes[8]]): common.BlockNonce =
|
proc toBlockNonce(n: Option[FixedBytes[8]]): common.BlockNonce =
|
||||||
if n.isNone:
|
if n.isNone:
|
||||||
return default(BlockNonce)
|
return default(BlockNonce)
|
||||||
@ -265,21 +262,6 @@ proc toBlockHeader*(bc: BlockObject): common.BlockHeader =
|
|||||||
parentBeaconBlockRoot: ethHash bc.parentBeaconBlockRoot,
|
parentBeaconBlockRoot: ethHash bc.parentBeaconBlockRoot,
|
||||||
)
|
)
|
||||||
|
|
||||||
func storageKeys(list: seq[FixedBytes[32]]): seq[StorageKey] =
|
|
||||||
for x in list:
|
|
||||||
result.add StorageKey(x)
|
|
||||||
|
|
||||||
func accessList(list: openArray[AccessTuple]): AccessList =
|
|
||||||
for x in list:
|
|
||||||
result.add AccessPair(
|
|
||||||
address : ethAddr x.address,
|
|
||||||
storageKeys: storageKeys x.storageKeys,
|
|
||||||
)
|
|
||||||
|
|
||||||
func accessList(x: Option[seq[AccessTuple]]): AccessList =
|
|
||||||
if x.isNone: return
|
|
||||||
else: accessList(x.get)
|
|
||||||
|
|
||||||
func vHashes(x: Option[seq[Web3Hash]]): seq[common.Hash256] =
|
func vHashes(x: Option[seq[Web3Hash]]): seq[common.Hash256] =
|
||||||
if x.isNone: return
|
if x.isNone: return
|
||||||
else: ethHashes(x.get)
|
else: ethHashes(x.get)
|
||||||
@ -296,7 +278,7 @@ proc toTransaction(tx: TransactionObject): Transaction =
|
|||||||
to : ethAddr tx.to,
|
to : ethAddr tx.to,
|
||||||
value : tx.value,
|
value : tx.value,
|
||||||
payload : tx.input,
|
payload : tx.input,
|
||||||
accessList : accessList(tx.accessList),
|
accessList : ethAccessList(tx.accessList),
|
||||||
maxFeePerBlobGas: tx.maxFeePerBlobGas.get(0.u256),
|
maxFeePerBlobGas: tx.maxFeePerBlobGas.get(0.u256),
|
||||||
versionedHashes : vHashes(tx.blobVersionedHashes),
|
versionedHashes : vHashes(tx.blobVersionedHashes),
|
||||||
V : tx.v.int64,
|
V : tx.v.int64,
|
||||||
|
@ -161,6 +161,21 @@ func ethTxs*(list: openArray[Web3Tx], removeBlobs = false):
|
|||||||
for x in list:
|
for x in list:
|
||||||
result.add ethTx(x)
|
result.add ethTx(x)
|
||||||
|
|
||||||
|
func storageKeys(list: seq[FixedBytes[32]]): seq[StorageKey] =
|
||||||
|
for x in list:
|
||||||
|
result.add StorageKey(x)
|
||||||
|
|
||||||
|
func ethAccessList*(list: openArray[AccessTuple]): common.AccessList =
|
||||||
|
for x in list:
|
||||||
|
result.add common.AccessPair(
|
||||||
|
address : ethAddr x.address,
|
||||||
|
storageKeys: storageKeys x.storageKeys,
|
||||||
|
)
|
||||||
|
|
||||||
|
func ethAccessList*(x: Option[seq[AccessTuple]]): common.AccessList =
|
||||||
|
if x.isSome:
|
||||||
|
return ethAccessList(x.get)
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Eth types to Web3 types
|
# Eth types to Web3 types
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@ -188,6 +203,11 @@ func w3Hash*(x: Option[common.Hash256]): Option[BlockHash] =
|
|||||||
func w3Hash*(x: common.BlockHeader): BlockHash =
|
func w3Hash*(x: common.BlockHeader): BlockHash =
|
||||||
BlockHash rlpHash(x).data
|
BlockHash rlpHash(x).data
|
||||||
|
|
||||||
|
func w3Hash*(list: openArray[StorageKey]): seq[Web3Hash] =
|
||||||
|
result = newSeqOfCap[Web3Hash](list.len)
|
||||||
|
for x in list:
|
||||||
|
result.add Web3Hash x
|
||||||
|
|
||||||
func w3Addr*(x: common.EthAddress): Web3Address =
|
func w3Addr*(x: common.EthAddress): Web3Address =
|
||||||
Web3Address x
|
Web3Address x
|
||||||
|
|
||||||
@ -266,3 +286,14 @@ func w3Txs*(list: openArray[common.Transaction]): seq[Web3Tx] =
|
|||||||
result = newSeqOfCap[Web3Tx](list.len)
|
result = newSeqOfCap[Web3Tx](list.len)
|
||||||
for tx in list:
|
for tx in list:
|
||||||
result.add w3Tx(tx)
|
result.add w3Tx(tx)
|
||||||
|
|
||||||
|
proc w3AccessTuple*(ac: AccessPair): AccessTuple =
|
||||||
|
AccessTuple(
|
||||||
|
address: w3Addr ac.address,
|
||||||
|
storageKeys: w3Hash(ac.storageKeys)
|
||||||
|
)
|
||||||
|
|
||||||
|
proc w3AccessList*(list: openArray[AccessPair]): seq[AccessTuple] =
|
||||||
|
result = newSeqOfCap[AccessTuple](list.len)
|
||||||
|
for x in list:
|
||||||
|
result.add w3AccessTuple(x)
|
||||||
|
@ -75,3 +75,20 @@ func getAccessList*(ac: AccessList): common.AccessList =
|
|||||||
address : address,
|
address : address,
|
||||||
storageKeys: slots.toStorageKeys,
|
storageKeys: slots.toStorageKeys,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func equal*(ac: AccessList, other: var AccessList): bool =
|
||||||
|
if ac.slots.len != other.slots.len:
|
||||||
|
return false
|
||||||
|
|
||||||
|
for address, slots in ac.slots:
|
||||||
|
other.slots.withValue(address, otherSlots):
|
||||||
|
if slots.len != otherSlots[].len:
|
||||||
|
return false
|
||||||
|
|
||||||
|
for slot in slots:
|
||||||
|
if slot notin otherSlots[]:
|
||||||
|
return false
|
||||||
|
do:
|
||||||
|
return false
|
||||||
|
|
||||||
|
true
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Nimbus
|
# Nimbus
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018-2024 Status Research & Development GmbH
|
||||||
# Licensed under either of
|
# Licensed under either of
|
||||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0)
|
# http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
@ -75,6 +75,10 @@ iterator activePrecompiles*(fork: EVMFork): EthAddress =
|
|||||||
res[^1] = c.byte
|
res[^1] = c.byte
|
||||||
yield res
|
yield res
|
||||||
|
|
||||||
|
func activePrecompilesList*(fork: EVMFork): seq[EthAddress] =
|
||||||
|
for address in activePrecompiles(fork):
|
||||||
|
result.add address
|
||||||
|
|
||||||
proc getSignature(c: Computation): (array[32, byte], Signature) =
|
proc getSignature(c: Computation): (array[32, byte], Signature) =
|
||||||
# input is Hash, V, R, S
|
# input is Hash, V, R, S
|
||||||
template data: untyped = c.msg.data
|
template data: untyped = c.msg.data
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Nimbus
|
# Nimbus
|
||||||
# Copyright (c) 2018 Status Research & Development GmbH
|
# Copyright (c) 2018-2024 Status Research & Development GmbH
|
||||||
# Licensed under either of
|
# Licensed under either of
|
||||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
# * 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)
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||||
@ -132,5 +132,9 @@ proc peekInt*(stack: Stack): UInt256 =
|
|||||||
ensurePop(stack, 1)
|
ensurePop(stack, 1)
|
||||||
fromStackElement(stack.values[^1], result)
|
fromStackElement(stack.values[^1], result)
|
||||||
|
|
||||||
|
proc peekAddress*(stack: Stack): EthAddress =
|
||||||
|
ensurePop(stack, 1)
|
||||||
|
fromStackElement(stack.values[^1], result)
|
||||||
|
|
||||||
proc top*(stack: Stack, value: uint | int | GasInt | UInt256 | EthAddress | Hash256) {.inline.} =
|
proc top*(stack: Stack, value: uint | int | GasInt | UInt256 | EthAddress | Hash256) {.inline.} =
|
||||||
toStackElement(value, stack.values[^1])
|
toStackElement(value, stack.values[^1])
|
||||||
|
77
nimbus/evm/tracer/access_list_tracer.nim
Normal file
77
nimbus/evm/tracer/access_list_tracer.nim
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
# Nimbus
|
||||||
|
# Copyright (c) 2023-2024 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
|
||||||
|
std/[sets],
|
||||||
|
eth/common/eth_types as common,
|
||||||
|
".."/[types, stack],
|
||||||
|
../interpreter/op_codes,
|
||||||
|
../../db/access_list,
|
||||||
|
../../errors
|
||||||
|
|
||||||
|
type
|
||||||
|
AccessListTracer* = ref object of TracerRef
|
||||||
|
list: access_list.AccessList
|
||||||
|
excl: HashSet[EthAddress]
|
||||||
|
|
||||||
|
proc new*(T: type AccessListTracer,
|
||||||
|
acl: common.AccessList,
|
||||||
|
sender: EthAddress,
|
||||||
|
to: EthAddress,
|
||||||
|
precompiles: openArray[EthAddress]): T =
|
||||||
|
let act = T()
|
||||||
|
act.excl.incl sender
|
||||||
|
act.excl.incl to
|
||||||
|
|
||||||
|
for address in precompiles:
|
||||||
|
act.excl.incl address
|
||||||
|
|
||||||
|
for acp in acl:
|
||||||
|
if acp.address notin act.excl:
|
||||||
|
act.list.add acp.address
|
||||||
|
for slot in acp.storageKeys:
|
||||||
|
act.list.add(acp.address, UInt256.fromBytesBE(slot))
|
||||||
|
|
||||||
|
act
|
||||||
|
|
||||||
|
# Opcode level
|
||||||
|
method captureOpStart*(act: AccessListTracer, c: Computation,
|
||||||
|
fixed: bool, pc: int, op: Op, gas: GasInt,
|
||||||
|
depth: int): int {.gcsafe.} =
|
||||||
|
let stackLen = c.stack.len
|
||||||
|
try:
|
||||||
|
if (op in [Sload, Sstore]) and (stackLen >= 1):
|
||||||
|
let slot = c.stack.peekInt()
|
||||||
|
act.list.add(c.msg.contractAddress, slot)
|
||||||
|
|
||||||
|
if (op in [ExtCodeCopy, ExtCodeHash, ExtCodeSize, Balance, SelfDestruct]) and (stackLen >= 1):
|
||||||
|
let address = c.stack.peekAddress()
|
||||||
|
if address notin act.excl:
|
||||||
|
act.list.add address
|
||||||
|
|
||||||
|
if (op in [DelegateCall, Call, StaticCall, CallCode]) and (stackLen >= 5):
|
||||||
|
let address = c.stack[^2, EthAddress]
|
||||||
|
if address notin act.excl:
|
||||||
|
act.list.add address
|
||||||
|
except InsufficientStack as exc:
|
||||||
|
# should not raise, because we already check the stack len
|
||||||
|
# this try..except block is to prevent unlisted exception error
|
||||||
|
discard exc
|
||||||
|
except ValueError as exc:
|
||||||
|
discard exc
|
||||||
|
|
||||||
|
# AccessListTracer is not using captureOpEnd
|
||||||
|
# no need to return op index
|
||||||
|
|
||||||
|
func equal*(ac: AccessListTracer, other: AccessListTracer): bool =
|
||||||
|
ac.list.equal(other.list)
|
||||||
|
|
||||||
|
func accessList*(ac: AccessListTracer): common.AccessList =
|
||||||
|
ac.list.getAccessList()
|
@ -575,6 +575,19 @@ proc setupEthRpc*(
|
|||||||
return Opt.some(recs)
|
return Opt.some(recs)
|
||||||
except CatchableError:
|
except CatchableError:
|
||||||
return Opt.none(seq[ReceiptObject])
|
return Opt.none(seq[ReceiptObject])
|
||||||
|
|
||||||
|
server.rpc("eth_createAccessList") do(args: TransactionArgs, quantityTag: BlockTag) -> AccessListResult:
|
||||||
|
try:
|
||||||
|
let
|
||||||
|
header = chainDB.headerFromTag(quantityTag)
|
||||||
|
args = callData(args)
|
||||||
|
|
||||||
|
return createAccessList(header, com, args)
|
||||||
|
except CatchableError as exc:
|
||||||
|
return AccessListResult(
|
||||||
|
error: some("createAccessList error: " & exc.msg),
|
||||||
|
)
|
||||||
|
|
||||||
#[
|
#[
|
||||||
server.rpc("eth_newFilter") do(filterOptions: FilterOptions) -> int:
|
server.rpc("eth_newFilter") do(filterOptions: FilterOptions) -> int:
|
||||||
## Creates a filter object, based on filter options, to notify when the state changes (logs).
|
## Creates a filter object, based on filter options, to notify when the state changes (logs).
|
||||||
|
@ -12,14 +12,21 @@
|
|||||||
import
|
import
|
||||||
std/[strutils, algorithm, options],
|
std/[strutils, algorithm, options],
|
||||||
./rpc_types,
|
./rpc_types,
|
||||||
eth/[common, keys],
|
eth/keys,
|
||||||
|
../common/common,
|
||||||
../db/core_db,
|
../db/core_db,
|
||||||
|
../db/ledger,
|
||||||
../constants, stint,
|
../constants, stint,
|
||||||
../utils/utils,
|
../utils/utils,
|
||||||
../transaction,
|
../transaction,
|
||||||
../transaction/call_evm,
|
../transaction/call_evm,
|
||||||
../core/eip4844,
|
../core/eip4844,
|
||||||
../beacon/web3_eth_conv
|
../beacon/web3_eth_conv,
|
||||||
|
../vm_types,
|
||||||
|
../vm_state,
|
||||||
|
../evm/precompiles,
|
||||||
|
../evm/tracer/access_list_tracer
|
||||||
|
|
||||||
|
|
||||||
const
|
const
|
||||||
defaultTag = blockId("latest")
|
defaultTag = blockId("latest")
|
||||||
@ -108,19 +115,18 @@ template optionalU256(src, dst: untyped) =
|
|||||||
if src.isSome:
|
if src.isSome:
|
||||||
dst = some(src.get)
|
dst = some(src.get)
|
||||||
|
|
||||||
template optionalBytes(src, dst: untyped) =
|
proc callData*(args: TransactionArgs): RpcCallData {.gcsafe, raises: [].} =
|
||||||
if src.isSome:
|
optionalAddress(args.source, result.source)
|
||||||
dst = src.get
|
optionalAddress(args.to, result.to)
|
||||||
|
optionalGas(args.gas, result.gasLimit)
|
||||||
proc callData*(call: TransactionArgs): RpcCallData {.gcsafe, raises: [].} =
|
optionalGas(args.gasPrice, result.gasPrice)
|
||||||
optionalAddress(call.source, result.source)
|
optionalGas(args.maxFeePerGas, result.maxFee)
|
||||||
optionalAddress(call.to, result.to)
|
optionalGas(args.maxPriorityFeePerGas, result.maxPriorityFee)
|
||||||
optionalGas(call.gas, result.gasLimit)
|
optionalU256(args.value, result.value)
|
||||||
optionalGas(call.gasPrice, result.gasPrice)
|
result.data = args.payload()
|
||||||
optionalGas(call.maxFeePerGas, result.maxFee)
|
if args.blobVersionedHashes.isSome:
|
||||||
optionalGas(call.maxPriorityFeePerGas, result.maxPriorityFee)
|
result.versionedHashes = ethHashes args.blobVersionedHashes.get
|
||||||
optionalU256(call.value, result.value)
|
result.accessList = ethAccessList args.accessList
|
||||||
optionalBytes(call.data, result.data)
|
|
||||||
|
|
||||||
proc toWd(wd: Withdrawal): WithdrawalObject =
|
proc toWd(wd: Withdrawal): WithdrawalObject =
|
||||||
WithdrawalObject(
|
WithdrawalObject(
|
||||||
@ -135,22 +141,6 @@ proc toWdList(list: openArray[Withdrawal]): seq[WithdrawalObject] =
|
|||||||
for x in list:
|
for x in list:
|
||||||
result.add toWd(x)
|
result.add toWd(x)
|
||||||
|
|
||||||
proc toHashList(list: openArray[StorageKey]): seq[Web3Hash] =
|
|
||||||
result = newSeqOfCap[Web3Hash](list.len)
|
|
||||||
for x in list:
|
|
||||||
result.add Web3Hash x
|
|
||||||
|
|
||||||
proc toAccessTuple(ac: AccessPair): AccessTuple =
|
|
||||||
AccessTuple(
|
|
||||||
address: w3Addr ac.address,
|
|
||||||
storageKeys: toHashList(ac.storageKeys)
|
|
||||||
)
|
|
||||||
|
|
||||||
proc toAccessTupleList(list: openArray[AccessPair]): seq[AccessTuple] =
|
|
||||||
result = newSeqOfCap[AccessTuple](list.len)
|
|
||||||
for x in list:
|
|
||||||
result.add toAccessTuple(x)
|
|
||||||
|
|
||||||
proc populateTransactionObject*(tx: Transaction,
|
proc populateTransactionObject*(tx: Transaction,
|
||||||
optionalHeader: Option[BlockHeader] = none(BlockHeader),
|
optionalHeader: Option[BlockHeader] = none(BlockHeader),
|
||||||
txIndex: Option[int] = none(int)): TransactionObject
|
txIndex: Option[int] = none(int)): TransactionObject
|
||||||
@ -180,7 +170,7 @@ proc populateTransactionObject*(tx: Transaction,
|
|||||||
|
|
||||||
if tx.txType >= TxEip2930:
|
if tx.txType >= TxEip2930:
|
||||||
result.chainId = some(Web3Quantity(tx.chainId))
|
result.chainId = some(Web3Quantity(tx.chainId))
|
||||||
result.accessList = some(toAccessTupleList(tx.accessList))
|
result.accessList = some(w3AccessList(tx.accessList))
|
||||||
|
|
||||||
if tx.txType >= TxEIP4844:
|
if tx.txType >= TxEIP4844:
|
||||||
result.maxFeePerBlobGas = some(tx.maxFeePerBlobGas)
|
result.maxFeePerBlobGas = some(tx.maxFeePerBlobGas)
|
||||||
@ -301,3 +291,55 @@ proc populateReceipt*(receipt: Receipt, gasUsed: GasInt, tx: Transaction,
|
|||||||
if tx.txType == TxEip4844:
|
if tx.txType == TxEip4844:
|
||||||
result.blobGasUsed = some(w3Qty(tx.versionedHashes.len.uint64 * GAS_PER_BLOB.uint64))
|
result.blobGasUsed = some(w3Qty(tx.versionedHashes.len.uint64 * GAS_PER_BLOB.uint64))
|
||||||
result.blobGasPrice = some(getBlobBaseFee(header.excessBlobGas.get(0'u64)))
|
result.blobGasPrice = some(getBlobBaseFee(header.excessBlobGas.get(0'u64)))
|
||||||
|
|
||||||
|
proc createAccessList*(header: BlockHeader,
|
||||||
|
com: CommonRef,
|
||||||
|
args: RpcCallData): AccessListResult {.gcsafe, raises:[CatchableError].} =
|
||||||
|
var args = args
|
||||||
|
|
||||||
|
# If the gas amount is not set, default to RPC gas cap.
|
||||||
|
if args.gasLimit.isNone:
|
||||||
|
args.gasLimit = some(DEFAULT_RPC_GAS_CAP)
|
||||||
|
|
||||||
|
let
|
||||||
|
vmState = BaseVMState.new(header, com)
|
||||||
|
fork = com.toEVMFork(forkDeterminationInfo(header.blockNumber, header.timestamp))
|
||||||
|
sender = args.source.get(ZERO_ADDRESS)
|
||||||
|
# TODO: nonce should be retrieved from txPool
|
||||||
|
nonce = vmState.stateDB.getNonce(sender)
|
||||||
|
to = if args.to.isSome: args.to.get
|
||||||
|
else: generateAddress(sender, nonce)
|
||||||
|
precompiles = activePrecompilesList(fork)
|
||||||
|
|
||||||
|
var prevTracer = AccessListTracer.new(
|
||||||
|
args.accessList,
|
||||||
|
sender,
|
||||||
|
to,
|
||||||
|
precompiles)
|
||||||
|
|
||||||
|
while true:
|
||||||
|
# Retrieve the current access list to expand
|
||||||
|
let accessList = prevTracer.accessList()
|
||||||
|
|
||||||
|
# Set the accesslist to the last accessList
|
||||||
|
# generated by prevTracer
|
||||||
|
args.accessList = accessList
|
||||||
|
|
||||||
|
# Apply the transaction with the access list tracer
|
||||||
|
let
|
||||||
|
tracer = AccessListTracer.new(accessList, sender, to, precompiles)
|
||||||
|
vmState = BaseVMState.new(header, com, tracer)
|
||||||
|
res = rpcCallEvm(args, header, com, vmState)
|
||||||
|
|
||||||
|
if res.isError:
|
||||||
|
return AccessListResult(
|
||||||
|
error: some("failed to apply transaction: " & res.error),
|
||||||
|
)
|
||||||
|
|
||||||
|
if tracer.equal(prevTracer):
|
||||||
|
return AccessListResult(
|
||||||
|
accessList: w3AccessList accessList,
|
||||||
|
gasUsed: w3Qty res.gasUsed,
|
||||||
|
)
|
||||||
|
|
||||||
|
prevTracer = tracer
|
||||||
|
@ -97,6 +97,19 @@ proc rpcCallEvm*(call: RpcCallData, header: BlockHeader, com: CommonRef): CallRe
|
|||||||
|
|
||||||
runComputation(params)
|
runComputation(params)
|
||||||
|
|
||||||
|
proc rpcCallEvm*(call: RpcCallData,
|
||||||
|
header: BlockHeader,
|
||||||
|
com: CommonRef,
|
||||||
|
vmState: BaseVMState): CallResult
|
||||||
|
{.gcsafe, raises: [CatchableError].} =
|
||||||
|
const globalGasCap = 0 # TODO: globalGasCap should configurable by user
|
||||||
|
let params = toCallParams(vmState, call, globalGasCap, header.fee)
|
||||||
|
|
||||||
|
var dbTx = com.db.beginTransaction()
|
||||||
|
defer: dbTx.dispose() # always dispose state changes
|
||||||
|
|
||||||
|
runComputation(params)
|
||||||
|
|
||||||
proc rpcEstimateGas*(cd: RpcCallData, header: BlockHeader, com: CommonRef, gasCap: GasInt): GasInt
|
proc rpcEstimateGas*(cd: RpcCallData, header: BlockHeader, com: CommonRef, gasCap: GasInt): GasInt
|
||||||
{.gcsafe, raises: [CatchableError].} =
|
{.gcsafe, raises: [CatchableError].} =
|
||||||
# Binary search the gas requirement, as it may be higher than the amount used
|
# Binary search the gas requirement, as it may be higher than the amount used
|
||||||
|
Loading…
x
Reference in New Issue
Block a user