Skip to content

Commit

Permalink
Fluffy: Configure RPC APIs via CLI parameter (#2657)
Browse files Browse the repository at this point in the history
* Support RPC API namespaces as cli parameter.

* Fluffy now uses rpcFlags on startup.

* Update testnet script to enable all RPC APIs.

* Update Fluffy book and move web3 call into eth calls.
  • Loading branch information
bhartnett authored Sep 25, 2024
1 parent 3820b15 commit 69d58e8
Show file tree
Hide file tree
Showing 11 changed files with 206 additions and 123 deletions.
63 changes: 59 additions & 4 deletions fluffy/conf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,17 @@ const
defaultBucketIpLimitDesc* = $defaultPortalProtocolConfig.tableIpLimits.bucketIpLimit
defaultBitsPerHopDesc* = $defaultPortalProtocolConfig.bitsPerHop
defaultMaxGossipNodesDesc* = $defaultPortalProtocolConfig.maxGossipNodes
defaultRpcApis* = @["eth", "portal"]
defaultRpcApisDesc* = "eth,portal"

type
RpcFlag* {.pure.} = enum
eth
debug
portal
portal_debug
discovery

TrustedDigest* = MDigest[32 * 8]

PortalCmd* = enum
Expand Down Expand Up @@ -179,17 +188,25 @@ type
desc: "Enable the HTTP JSON-RPC server", defaultValue: false, name: "rpc"
.}: bool

rpcPort* {.
desc: "Port for the HTTP JSON-RPC server", defaultValue: 8545, name: "rpc-port"
.}: Port

rpcAddress* {.
desc: "Listening address of the RPC server",
defaultValue: defaultAdminListenAddress,
defaultValueDesc: $defaultAdminListenAddressDesc,
name: "rpc-address"
.}: IpAddress

rpcPort* {.
desc: "Port for the HTTP JSON-RPC server", defaultValue: 8545, name: "rpc-port"
.}: Port

rpcApi* {.
desc:
"Enable specific set of RPC APIs (available: eth, debug, portal, portal_debug, discovery)",
defaultValue: defaultRpcApis,
defaultValueDesc: $defaultRpcApisDesc,
name: "rpc-api"
.}: seq[string]

wsEnabled* {.
desc: "Enable the WebSocket JSON-RPC server", defaultValue: false, name: "ws"
.}: bool
Expand Down Expand Up @@ -367,3 +384,41 @@ chronicles.formatIt(OutDir):
$it
chronicles.formatIt(InputFile):
$it

func processList(v: string, o: var seq[string]) =
## Process comma-separated list of strings.
if len(v) > 0:
for n in v.split({' ', ','}):
if len(n) > 0:
o.add(n)

iterator repeatingList(listOfList: openArray[string]): string =
for strList in listOfList:
var list = newSeq[string]()
processList(strList, list)
for item in list:
yield item

proc getRpcFlags*(rpcApis: openArray[string]): set[RpcFlag] =
if rpcApis.len == 0:
error "No RPC APIs specified"
quit QuitFailure

var rpcFlags: set[RpcFlag]
for apiStr in rpcApis.repeatingList():
case apiStr.toLowerAscii()
of "eth":
rpcFlags.incl RpcFlag.eth
of "debug":
rpcFlags.incl RpcFlag.debug
of "portal":
rpcFlags.incl RpcFlag.portal
of "portal_debug":
rpcFlags.incl RpcFlag.portal_debug
of "discovery":
rpcFlags.incl RpcFlag.discovery
else:
error "Unknown RPC API: ", name = apiStr
quit QuitFailure

rpcFlags
6 changes: 3 additions & 3 deletions fluffy/docs/the_fluffy_book/docs/history-content-bridging.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Run Fluffy and trigger the propagation of data with the
`portal_history_propagateEpochRecords` JSON-RPC API call:

```bash
./build/fluffy --rpc
./build/fluffy --rpc --rpc-api:portal,portal_debug

# From another terminal
curl -s -X POST -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":"1","method":"portal_history_propagateEpochRecords","params":["./user_data_dir/"]}' http://localhost:8545 | jq
Expand All @@ -116,7 +116,7 @@ accumulators are available on the history network:

Make sure you still have a fluffy instance running, if not run:
```bash
./build/fluffy --rpc
./build/fluffy --rpc --rpc-api:portal,portal_debug
```

Run the `content_verifier` tool and see if all epoch accumulators are found:
Expand Down Expand Up @@ -146,7 +146,7 @@ This will store blocks 1 to 10 into a json file located at
`portal_history_propagate` JSON-RPC API call:

```bash
./build/fluffy --rpc
./build/fluffy --rpc --rpc-api:portal,portal_debug

# From another shell
curl -s -X POST -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":"1","method":"portal_history_propagate","params":["./user_data_dir/eth-history-data.json"]}' http://localhost:8545 | jq
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ First build Fluffy as explained [here](./quick-start.md#build-the-fluffy-client)

Next run it with the JSON-RPC server enabled:
```bash
./build/fluffy --rpc --bootstrap-node:enr:<base64 encoding of ENR>
./build/fluffy --rpc --rpc-api:portal,discovery --bootstrap-node:enr:<base64 encoding of ENR>
```

### Testing Discovery v5 Layer
Expand Down
51 changes: 30 additions & 21 deletions fluffy/fluffy.nim
Original file line number Diff line number Diff line change
Expand Up @@ -220,30 +220,39 @@ proc run(

## Start the JSON-RPC APIs

let rpcFlags = getRpcFlags(config.rpcApi)

proc setupRpcServer(
rpcServer: RpcHttpServer | RpcWebSocketServer
) {.raises: [CatchableError].} =
rpcServer.installDiscoveryApiHandlers(d)

if node.stateNetwork.isSome():
rpcServer.installDebugApiHandlers(node.stateNetwork)
rpcServer.installPortalApiHandlers(
node.stateNetwork.value.portalProtocol, "state"
)
if node.historyNetwork.isSome():
rpcServer.installEthApiHandlers(
node.historyNetwork.value, node.beaconLightClient, node.stateNetwork
)
rpcServer.installPortalApiHandlers(
node.historyNetwork.value.portalProtocol, "history"
)
rpcServer.installPortalDebugApiHandlers(
node.historyNetwork.value.portalProtocol, "history"
)
if node.beaconNetwork.isSome():
rpcServer.installPortalApiHandlers(
node.beaconNetwork.value.portalProtocol, "beacon"
)
for rpcFlag in rpcFlags:
case rpcFlag
of RpcFlag.eth:
rpcServer.installEthApiHandlers(
node.historyNetwork, node.beaconLightClient, node.stateNetwork
)
of RpcFlag.debug:
rpcServer.installDebugApiHandlers(node.stateNetwork)
of RpcFlag.portal:
if node.historyNetwork.isSome():
rpcServer.installPortalApiHandlers(
node.historyNetwork.value.portalProtocol, "history"
)
if node.beaconNetwork.isSome():
rpcServer.installPortalApiHandlers(
node.beaconNetwork.value.portalProtocol, "beacon"
)
if node.stateNetwork.isSome():
rpcServer.installPortalApiHandlers(
node.stateNetwork.value.portalProtocol, "state"
)
of RpcFlag.portal_debug:
if node.historyNetwork.isSome():
rpcServer.installPortalDebugApiHandlers(
node.historyNetwork.value.portalProtocol, "history"
)
of RpcFlag.discovery:
rpcServer.installDiscoveryApiHandlers(d)

rpcServer.start()

Expand Down
4 changes: 2 additions & 2 deletions fluffy/rpc/eth_rpc_client.nim
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.

import json_rpc/rpcclient, ./rpc_calls/[rpc_web3_calls, rpc_eth_calls]
import json_rpc/rpcclient, ./rpc_calls/rpc_eth_calls

export rpcclient, rpc_web3_calls, rpc_eth_calls
export rpcclient, rpc_eth_calls
1 change: 1 addition & 0 deletions fluffy/rpc/rpc_calls/rpc_eth_calls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import
export eth_api_types

createRpcSigsFromNim(RpcClient):
proc web3_clientVersion(): string
proc eth_chainId(): Quantity
proc eth_getBlockByHash(data: BlockHash, fullTransactions: bool): Opt[BlockObject]
proc eth_getBlockByNumber(
Expand Down
13 changes: 0 additions & 13 deletions fluffy/rpc/rpc_calls/rpc_web3_calls.nim

This file was deleted.

88 changes: 45 additions & 43 deletions fluffy/rpc/rpc_debug_api.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ import
../common/common_utils,
../network/state/state_endpoints

template getOrRaise(stateNetwork: Opt[StateNetwork]): StateNetwork =
let sn = stateNetwork.valueOr:
raise newException(ValueError, "state sub-network not enabled")
sn

proc installDebugApiHandlers*(rpcServer: RpcServer, stateNetwork: Opt[StateNetwork]) =
rpcServer.rpc("debug_getBalanceByStateRoot") do(
data: web3Types.Address, stateRoot: web3types.Hash256
Expand All @@ -27,15 +32,14 @@ proc installDebugApiHandlers*(rpcServer: RpcServer, stateNetwork: Opt[StateNetwo
## stateRoot: the state root used to search the state trie.
## Returns integer of the current balance in wei.

let sn = stateNetwork.valueOr:
raise newException(ValueError, "State sub-network not enabled")

let balance = (
await sn.getBalanceByStateRoot(
KeccakHash.fromBytes(stateRoot.bytes()), data.EthAddress
)
).valueOr:
raise newException(ValueError, "Unable to get balance")
let
sn = stateNetwork.getOrRaise()
balance = (
await sn.getBalanceByStateRoot(
KeccakHash.fromBytes(stateRoot.bytes()), data.EthAddress
)
).valueOr:
raise newException(ValueError, "Unable to get balance")

return balance

Expand All @@ -48,15 +52,15 @@ proc installDebugApiHandlers*(rpcServer: RpcServer, stateNetwork: Opt[StateNetwo
## stateRoot: the state root used to search the state trie.
## Returns integer of the number of transactions send from this address.

let sn = stateNetwork.valueOr:
raise newException(ValueError, "State sub-network not enabled")
let
sn = stateNetwork.getOrRaise()
nonce = (
await sn.getTransactionCountByStateRoot(
KeccakHash.fromBytes(stateRoot.bytes()), data.EthAddress
)
).valueOr:
raise newException(ValueError, "Unable to get transaction count")

let nonce = (
await sn.getTransactionCountByStateRoot(
KeccakHash.fromBytes(stateRoot.bytes()), data.EthAddress
)
).valueOr:
raise newException(ValueError, "Unable to get transaction count")
return nonce.Quantity

rpcServer.rpc("debug_getStorageAtByStateRoot") do(
Expand All @@ -69,15 +73,15 @@ proc installDebugApiHandlers*(rpcServer: RpcServer, stateNetwork: Opt[StateNetwo
## stateRoot: the state root used to search the state trie.
## Returns: the value at this storage position.

let sn = stateNetwork.valueOr:
raise newException(ValueError, "State sub-network not enabled")
let
sn = stateNetwork.getOrRaise()
slotValue = (
await sn.getStorageAtByStateRoot(
KeccakHash.fromBytes(stateRoot.bytes()), data.EthAddress, slot
)
).valueOr:
raise newException(ValueError, "Unable to get storage slot")

let slotValue = (
await sn.getStorageAtByStateRoot(
KeccakHash.fromBytes(stateRoot.bytes()), data.EthAddress, slot
)
).valueOr:
raise newException(ValueError, "Unable to get storage slot")
return FixedBytes[32](slotValue.toBytesBE())

rpcServer.rpc("debug_getCodeByStateRoot") do(
Expand All @@ -89,15 +93,14 @@ proc installDebugApiHandlers*(rpcServer: RpcServer, stateNetwork: Opt[StateNetwo
## stateRoot: the state root used to search the state trie.
## Returns the code from the given address.

let sn = stateNetwork.valueOr:
raise newException(ValueError, "State sub-network not enabled")

let bytecode = (
await sn.getCodeByStateRoot(
KeccakHash.fromBytes(stateRoot.bytes()), data.EthAddress
)
).valueOr:
raise newException(ValueError, "Unable to get code")
let
sn = stateNetwork.getOrRaise()
bytecode = (
await sn.getCodeByStateRoot(
KeccakHash.fromBytes(stateRoot.bytes()), data.EthAddress
)
).valueOr:
raise newException(ValueError, "Unable to get code")

return bytecode.asSeq()

Expand All @@ -112,15 +115,14 @@ proc installDebugApiHandlers*(rpcServer: RpcServer, stateNetwork: Opt[StateNetwo
## stateRoot: the state root used to search the state trie.
## Returns: the proof response containing the account, account proof and storage proof

let sn = stateNetwork.valueOr:
raise newException(ValueError, "State sub-network not enabled")

let proofs = (
await sn.getProofsByStateRoot(
KeccakHash.fromBytes(stateRoot.bytes()), data.EthAddress, slots
)
).valueOr:
raise newException(ValueError, "Unable to get proofs")
let
sn = stateNetwork.getOrRaise()
proofs = (
await sn.getProofsByStateRoot(
KeccakHash.fromBytes(stateRoot.bytes()), data.EthAddress, slots
)
).valueOr:
raise newException(ValueError, "Unable to get proofs")

var storageProof = newSeqOfCap[StorageProof](slots.len)
for i, slot in slots:
Expand Down
Loading

0 comments on commit 69d58e8

Please sign in to comment.