Skip to content

Commit

Permalink
Implement Fluffy JSON-RPC endpoints. (#2364)
Browse files Browse the repository at this point in the history
* Implement eth_getBalance, eth_getTransactionCount, eth_getStorageAt and eth_getCode JSON-RPCs.

* Fixes.
  • Loading branch information
web3-developer committed Jun 14, 2024
1 parent 4c45819 commit 1377f93
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 65 deletions.
2 changes: 1 addition & 1 deletion fluffy/fluffy.nim
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ proc run(config: PortalConf) {.raises: [CatchableError].} =
)
if historyNetwork.isSome():
rpcHttpServerWithProxy.installEthApiHandlers(
historyNetwork.get(), beaconLightClient
historyNetwork.get(), beaconLightClient, stateNetwork
)
rpcHttpServerWithProxy.installPortalApiHandlers(
historyNetwork.get().portalProtocol, "history"
Expand Down
3 changes: 2 additions & 1 deletion fluffy/network/state/state_network.nim
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,8 @@ proc processContentLoop(n: StateNetwork) {.async: (raises: []).} =
trace "processContentLoop canceled"

proc start*(n: StateNetwork) =
info "Starting Portal State Network", protocolId = n.portalProtocol.protocolId
info "Starting Portal execution state network",
protocolId = n.portalProtocol.protocolId
n.portalProtocol.start()

n.processContentLoop = processContentLoop(n)
Expand Down
189 changes: 126 additions & 63 deletions fluffy/rpc/rpc_eth_api.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import
json_rpc/[rpcproxy, rpcserver],
web3/conversions, # sigh, for FixedBytes marshalling
web3/eth_api_types,
eth/[common/eth_types, rlp],
web3/primitives as web3types,
eth/common/eth_types,
beacon_chain/spec/forks,
../network/history/[history_network, history_content],
../network/state/[state_network, state_content, state_endpoints],
../network/beacon/beacon_light_client

from ../../nimbus/transaction import getSender, ValidationError
Expand Down Expand Up @@ -127,6 +129,7 @@ proc installEthApiHandlers*(
rpcServerWithProxy: var RpcProxy,
historyNetwork: HistoryNetwork,
beaconLightClient: Opt[LightClient],
stateNetwork: Opt[StateNetwork],
) =
# Supported API
rpcServerWithProxy.registerProxyMethod("eth_blockNumber")
Expand Down Expand Up @@ -343,65 +346,125 @@ proc installEthApiHandlers*(
return filteredLogs
else:
# bloomfilter returned false, there are no logs matching the criteria
return
@[]

# rpcServerWithProxy.rpc("eth_getBalance") do(
# data: Address, quantityTag: RtBlockIdentifier
# ) -> UInt256:
# ## Returns the balance of the account of given address.
# ##
# ## data: address to check for balance.
# ## quantityTag: integer block number, or the string "latest", "earliest" or "pending", see the default block parameter.
# ## Returns integer of the current balance in wei.
# # TODO
# raiseAssert("Not implemented")

# rpcServerWithProxy.rpc("eth_getTransactionCount") do(
# data: Address, quantityTag: RtBlockIdentifier
# ) -> Quantity:
# ## Returns the number of transactions sent from an address.
# ##
# ## data: address.
# ## quantityTag: integer block number, or the string "latest", "earliest" or "pending", see the default block parameter.
# ## Returns integer of the number of transactions send from this address.
# # TODO
# raiseAssert("Not implemented")

# rpcServerWithProxy.rpc("eth_getStorageAt") do(
# data: Address, slot: UInt256, quantityTag: RtBlockIdentifier
# ) -> FixedBytes[32]:
# ## Returns the value from a storage position at a given address.
# ##
# ## data: address of the storage.
# ## slot: integer of the position in the storage.
# ## quantityTag: integer block number, or the string "latest", "earliest" or "pending", see the default block parameter.
# ## Returns: the value at this storage position.
# # TODO
# raiseAssert("Not implemented")

# rpcServerWithProxy.rpc("eth_getCode") do(
# data: Address, quantityTag: RtBlockIdentifier
# ) -> seq[byte]:
# ## Returns code at a given address.
# ##
# ## data: address
# ## quantityTag: integer block number, or the string "latest", "earliest" or "pending", see the default block parameter.
# ## Returns the code from the given address.
# # TODO
# raiseAssert("Not implemented")

# rpcServerWithProxy.rpc("eth_getProof") do(
# address: Address, slots: seq[UInt256], quantityTag: RtBlockIdentifier
# ) -> ProofResponse:
# ## Returns information about an account and storage slots (if the account is a contract
# ## and the slots are requested) along with account and storage proofs which prove the
# ## existence of the values in the state.
# ## See spec here: https://eips.ethereum.org/EIPS/eip-1186
# ##
# ## data: address of the account.
# ## slots: integers of the positions in the storage to return with storage proofs.
# ## quantityTag: integer block number, or the string "latest", "earliest" or "pending", see the default block parameter.
# ## Returns: the proof response containing the account, account proof and storage proof
# # TODO
# raiseAssert("Not implemented")
return @[]

rpcServerWithProxy.rpc("eth_getBalance") do(
data: web3Types.Address, quantityTag: RtBlockIdentifier
) -> UInt256:
## Returns the balance of the account of given address.
##
## data: address to check for balance.
## quantityTag: integer block number, or the string "latest", "earliest" or "pending", see the default block parameter.
## Returns integer of the current balance in wei.
if stateNetwork.isNone():
raise newException(ValueError, "State sub-network not enabled")

if quantityTag.kind == bidAlias:
# TODO: Implement
raise newException(ValueError, "tag not yet implemented")
else:
let
blockNumber = quantityTag.number.uint64.u256
blockHash = (await historyNetwork.getBlockHashByNumber(blockNumber)).valueOr:
raise newException(ValueError, error)

balance = (await stateNetwork.get().getBalance(blockHash, data.EthAddress)).valueOr:
# Should we return 0 here or throw a more detailed error?
raise newException(ValueError, "Unable to get balance")

return balance

rpcServerWithProxy.rpc("eth_getTransactionCount") do(
data: web3Types.Address, quantityTag: RtBlockIdentifier
) -> Quantity:
## Returns the number of transactions sent from an address.
##
## data: address.
## quantityTag: integer block number, or the string "latest", "earliest" or "pending", see the default block parameter.
## Returns integer of the number of transactions send from this address.
if stateNetwork.isNone():
raise newException(ValueError, "State sub-network not enabled")

if quantityTag.kind == bidAlias:
# TODO: Implement
raise newException(ValueError, "tag not yet implemented")
else:
let
blockNumber = quantityTag.number.uint64.u256
blockHash = (await historyNetwork.getBlockHashByNumber(blockNumber)).valueOr:
raise newException(ValueError, error)

nonce = (
await stateNetwork.get().getTransactionCount(blockHash, data.EthAddress)
).valueOr:
# Should we return 0 here or throw a more detailed error?
raise newException(ValueError, "Unable to get transaction count")
return nonce.Quantity

rpcServerWithProxy.rpc("eth_getStorageAt") do(
data: web3Types.Address, slot: UInt256, quantityTag: RtBlockIdentifier
) -> FixedBytes[32]:
## Returns the value from a storage position at a given address.
##
## data: address of the storage.
## slot: integer of the position in the storage.
## quantityTag: integer block number, or the string "latest", "earliest" or "pending", see the default block parameter.
## Returns: the value at this storage position.
if stateNetwork.isNone():
raise newException(ValueError, "State sub-network not enabled")

if quantityTag.kind == bidAlias:
# TODO: Implement
raise newException(ValueError, "tag not yet implemented")
else:
let
blockNumber = quantityTag.number.uint64.u256
blockHash = (await historyNetwork.getBlockHashByNumber(blockNumber)).valueOr:
raise newException(ValueError, error)

slotValue = (
await stateNetwork.get().getStorageAt(blockHash, data.EthAddress, slot)
).valueOr:
# Should we return 0 here or throw a more detailed error?
raise newException(ValueError, "Unable to get storage slot")
return FixedBytes[32](slotValue.toBytesBE())

rpcServerWithProxy.rpc("eth_getCode") do(
data: web3Types.Address, quantityTag: RtBlockIdentifier
) -> seq[byte]:
## Returns code at a given address.
##
## data: address
## quantityTag: integer block number, or the string "latest", "earliest" or "pending", see the default block parameter.
## Returns the code from the given address.
if stateNetwork.isNone():
raise newException(ValueError, "State sub-network not enabled")

if quantityTag.kind == bidAlias:
# TODO: Implement
raise newException(ValueError, "tag not yet implemented")
else:
let
blockNumber = quantityTag.number.uint64.u256
blockHash = (await historyNetwork.getBlockHashByNumber(blockNumber)).valueOr:
raise newException(ValueError, error)

bytecode = (await stateNetwork.get().getCode(blockHash, data.EthAddress)).valueOr:
# Should we return empty sequence here or throw a more detailed error?
raise newException(ValueError, "Unable to get code")
return bytecode.asSeq()

# rpcServerWithProxy.rpc("eth_getProof") do(
# address: Address, slots: seq[UInt256], quantityTag: RtBlockIdentifier
# ) -> ProofResponse:
# ## Returns information about an account and storage slots (if the account is a contract
# ## and the slots are requested) along with account and storage proofs which prove the
# ## existence of the values in the state.
# ## See spec here: https://eips.ethereum.org/EIPS/eip-1186
# ##
# ## data: address of the account.
# ## slots: integers of the positions in the storage to return with storage proofs.
# ## quantityTag: integer block number, or the string "latest", "earliest" or "pending", see the default block parameter.
# ## Returns: the proof response containing the account, account proof and storage proof
# # TODO
# raiseAssert("Not implemented")

0 comments on commit 1377f93

Please sign in to comment.