Clean-up of some Portal json-rpc code (#2073)

- Use the new createRpcSigsFromNim for client json-rpc API
- Avoid importing any nimbus/rpc specifics, use only web3 and
fluffy local rpc code
- Adjust tools making use of the client side API
This commit is contained in:
Kim De Mey 2024-03-13 16:58:50 +01:00 committed by GitHub
parent 849607cfd1
commit 7287efc7b4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 225 additions and 183 deletions

View File

@ -1,22 +1,10 @@
# Nimbus
# fluffy
# Copyright (c) 2022-2024 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * 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
std/os,
json_rpc/rpcclient,
json_rpc/errors, # TODO: should be exported in json_rpc/clients/httpclient
web3/conversions, # sigh
../../nimbus/rpc/[rpc_types]
import json_rpc/[rpcclient, errors], ./rpc_calls/[rpc_web3_calls, rpc_eth_calls]
export rpcclient, rpc_types, errors
createRpcSigs(
RpcClient, currentSourcePath.parentDir / "rpc_calls" / "rpc_eth_calls.nim"
)
createRpcSigs(
RpcClient, currentSourcePath.parentDir / "rpc_calls" / "rpc_web3_calls.nim"
)
export rpcclient, errors, rpc_web3_calls, rpc_eth_calls

View File

@ -1,4 +1,4 @@
# Nimbus
# fluffy
# Copyright (c) 2021-2024 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
@ -6,20 +6,8 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
std/[os, json],
json_rpc/rpcclient,
json_rpc/errors, # TODO: should be exported in json_rpc/clients/httpclient
./rpc_types,
rpc_discovery_api # for the PongResponse
./rpc_calls/[rpc_discovery_calls, rpc_portal_calls, rpc_portal_debug_calls]
export rpcclient, rpc_types, errors
createRpcSigs(
RpcClient, currentSourcePath.parentDir / "rpc_calls" / "rpc_discovery_calls.nim"
)
createRpcSigs(
RpcClient, currentSourcePath.parentDir / "rpc_calls" / "rpc_portal_calls.nim"
)
createRpcSigs(
RpcClient, currentSourcePath.parentDir / "rpc_calls" / "rpc_portal_debug_calls.nim"
)
export rpcclient, errors, rpc_discovery_calls, rpc_portal_calls, rpc_portal_debug_calls

View File

@ -1,16 +1,30 @@
# Discovery v5 json-rpc calls
proc discv5_nodeInfo(): NodeInfo
proc discv5_updateNodeInfo(kvPairs: seq[(string, string)]): RoutingTableInfo
proc discv5_routingTableInfo(): RoutingTableInfo
# fluffy
# Copyright (c) 2021-2024 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * 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.
proc discv5_addEnr(enr: Record): bool
proc discv5_addEnrs(enrs: seq[Record]): bool
proc discv5_getEnr(nodeId: NodeId): Record
proc discv5_deleteEnr(nodeId: NodeId): bool
proc discv5_lookupEnr(nodeId: NodeId): Record
{.push raises: [].}
proc discv5_ping(nodeId: Record): PongResponse
proc discv5_findNode(nodeId: Record, distances: seq[uint16]): seq[Record]
proc discv5_talkReq(nodeId: Record, protocol, payload: string): string
import json_rpc/rpcclient, ../rpc_types, ../rpc_discovery_api
proc discv5_recursiveFindNodes(nodeId: NodeId): seq[Record]
export rpc_types, rpc_discovery_api
createRpcSigsFromNim(RpcClient):
# Discovery v5 json-rpc calls
proc discv5_nodeInfo(): NodeInfo
proc discv5_updateNodeInfo(kvPairs: seq[(string, string)]): RoutingTableInfo
proc discv5_routingTableInfo(): RoutingTableInfo
proc discv5_addEnr(enr: Record): bool
proc discv5_addEnrs(enrs: seq[Record]): bool
proc discv5_getEnr(nodeId: NodeId): Record
proc discv5_deleteEnr(nodeId: NodeId): bool
proc discv5_lookupEnr(nodeId: NodeId): Record
proc discv5_ping(nodeId: Record): PongResponse
proc discv5_findNode(nodeId: Record, distances: seq[uint16]): seq[Record]
proc discv5_talkReq(nodeId: Record, protocol, payload: string): string
proc discv5_recursiveFindNodes(nodeId: NodeId): seq[Record]

View File

@ -1,19 +1,32 @@
# Fluffy
# fluffy
# Copyright (c) 2021-2024 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * 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.
proc eth_chaindId(): Quantity
proc eth_getBlockByHash(data: Hash256, fullTransactions: bool): Option[BlockObject]
proc eth_getBlockByNumber(
quantityTag: string, fullTransactions: bool
): Option[BlockObject]
{.push raises: [].}
proc eth_getBlockTransactionCountByHash(data: Hash256): Quantity
proc eth_getTransactionReceipt(data: Hash256): Option[ReceiptObject]
proc eth_getLogs(filterOptions: FilterOptions): seq[FilterLog]
import
std/json,
json_serialization/stew/results,
json_rpc/[client, jsonmarshal],
web3/conversions,
web3/eth_api_types
# Not supported: Only supported by Alchemy
proc eth_getBlockReceipts(data: Hash256): seq[ReceiptObject]
export eth_api_types
createRpcSigsFromNim(RpcClient):
proc eth_chainId(): Quantity
proc eth_getBlockByHash(data: BlockHash, fullTransactions: bool): Opt[BlockObject]
proc eth_getBlockByNumber(
blockId: BlockIdentifier, fullTransactions: bool
): Opt[BlockObject]
proc eth_getBlockTransactionCountByHash(data: BlockHash): Quantity
proc eth_getTransactionReceipt(data: TxHash): Opt[ReceiptObject]
proc eth_getLogs(filterOptions: FilterOptions): seq[LogObject]
proc eth_getBlockReceipts(blockId: string): Opt[seq[ReceiptObject]]
proc eth_getBlockReceipts(blockId: BlockNumber): Opt[seq[ReceiptObject]]
proc eth_getBlockReceipts(blockId: RtBlockIdentifier): Opt[seq[ReceiptObject]]

View File

@ -1,61 +1,71 @@
# Nimbus
# fluffy
# Copyright (c) 2021-2024 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * 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.
## Portal State Network json-rpc calls
proc portal_stateNodeInfo(): NodeInfo
proc portal_stateRoutingTableInfo(): RoutingTableInfo
proc portal_stateAddEnr(enr: Record): bool
proc portal_stateAddEnrs(enrs: seq[Record]): bool
proc portal_stateGetEnr(nodeId: NodeId): Record
proc portal_stateDeleteEnr(nodeId: NodeId): bool
proc portal_stateLookupEnr(nodeId: NodeId): Record
proc portal_statePing(enr: Record): PingResult
proc portal_stateFindNodes(enr: Record): seq[Record]
proc portal_stateFindContent(enr: Record, contentKey: string): JsonNode
proc portal_stateOffer(enr: Record, contentKey: string, contentValue: string): string
proc portal_stateRecursiveFindNodes(nodeId: NodeId): seq[Record]
proc portal_stateRecursiveFindContent(contentKey: string): string
proc portal_stateStore(contentKey: string, contentValue: string): bool
proc portal_stateLocalContent(contentKey: string): string
proc portal_stateGossip(contentKey: string, contentValue: string): int
{.push raises: [].}
## Portal History Network json-rpc calls
proc portal_historyNodeInfo(): NodeInfo
proc portal_historyRoutingTableInfo(): RoutingTableInfo
proc portal_historyAddEnr(enr: Record): bool
proc portal_historyAddEnrs(enrs: seq[Record]): bool
proc portal_historyGetEnr(nodeId: NodeId): Record
proc portal_historyDeleteEnr(nodeId: NodeId): bool
proc portal_historyLookupEnr(nodeId: NodeId): Record
proc portal_historyPing(enr: Record): PingResult
proc portal_historyFindNodes(enr: Record): seq[Record]
proc portal_historyFindContent(enr: Record, contentKey: string): JsonNode
proc portal_historyOffer(enr: Record, contentKey: string, contentValue: string): string
proc portal_historyRecursiveFindNodes(nodeId: NodeId): seq[Record]
proc portal_historyRecursiveFindContent(contentKey: string): string
proc portal_historyStore(contentKey: string, contentValue: string): bool
proc portal_historyLocalContent(contentKey: string): string
proc portal_historyGossip(contentKey: string, contentValue: string): int
import std/json, json_rpc/rpcclient, ../rpc_types
## Portal Beacon Light Client Network json-rpc calls
proc portal_beaconNodeInfo(): NodeInfo
proc portal_beaconRoutingTableInfo(): RoutingTableInfo
proc portal_beaconAddEnr(enr: Record): bool
proc portal_beaconAddEnrs(enrs: seq[Record]): bool
proc portal_beaconGetEnr(nodeId: NodeId): Record
proc portal_beaconDeleteEnr(nodeId: NodeId): bool
proc portal_beaconLookupEnr(nodeId: NodeId): Record
proc portal_beaconPing(enr: Record): PingResult
proc portal_beaconFindNodes(enr: Record): seq[Record]
proc portal_beaconFindContent(enr: Record, contentKey: string): JsonNode
proc portal_beaconOffer(enr: Record, contentKey: string, contentValue: string): string
proc portal_beaconRecursiveFindNodes(nodeId: NodeId): seq[Record]
proc portal_beaconRecursiveFindContent(contentKey: string): string
proc portal_beaconStore(contentKey: string, contentValue: string): bool
proc portal_beaconLocalContent(contentKey: string): string
proc portal_beaconGossip(contentKey: string, contentValue: string): int
proc portal_beaconRandomGossip(contentKey: string, contentValue: string): int
export rpc_types
createRpcSigsFromNim(RpcClient):
## Portal State Network json-rpc calls
proc portal_stateNodeInfo(): NodeInfo
proc portal_stateRoutingTableInfo(): RoutingTableInfo
proc portal_stateAddEnr(enr: Record): bool
proc portal_stateAddEnrs(enrs: seq[Record]): bool
proc portal_stateGetEnr(nodeId: NodeId): Record
proc portal_stateDeleteEnr(nodeId: NodeId): bool
proc portal_stateLookupEnr(nodeId: NodeId): Record
proc portal_statePing(enr: Record): PingResult
proc portal_stateFindNodes(enr: Record): seq[Record]
proc portal_stateFindContent(enr: Record, contentKey: string): JsonNode
proc portal_stateOffer(enr: Record, contentKey: string, contentValue: string): string
proc portal_stateRecursiveFindNodes(nodeId: NodeId): seq[Record]
proc portal_stateRecursiveFindContent(contentKey: string): string
proc portal_stateStore(contentKey: string, contentValue: string): bool
proc portal_stateLocalContent(contentKey: string): string
proc portal_stateGossip(contentKey: string, contentValue: string): int
## Portal History Network json-rpc calls
proc portal_historyNodeInfo(): NodeInfo
proc portal_historyRoutingTableInfo(): RoutingTableInfo
proc portal_historyAddEnr(enr: Record): bool
proc portal_historyAddEnrs(enrs: seq[Record]): bool
proc portal_historyGetEnr(nodeId: NodeId): Record
proc portal_historyDeleteEnr(nodeId: NodeId): bool
proc portal_historyLookupEnr(nodeId: NodeId): Record
proc portal_historyPing(enr: Record): PingResult
proc portal_historyFindNodes(enr: Record): seq[Record]
proc portal_historyFindContent(enr: Record, contentKey: string): JsonNode
proc portal_historyOffer(
enr: Record, contentKey: string, contentValue: string
): string
proc portal_historyRecursiveFindNodes(nodeId: NodeId): seq[Record]
proc portal_historyRecursiveFindContent(contentKey: string): string
proc portal_historyStore(contentKey: string, contentValue: string): bool
proc portal_historyLocalContent(contentKey: string): string
proc portal_historyGossip(contentKey: string, contentValue: string): int
## Portal Beacon Light Client Network json-rpc calls
proc portal_beaconNodeInfo(): NodeInfo
proc portal_beaconRoutingTableInfo(): RoutingTableInfo
proc portal_beaconAddEnr(enr: Record): bool
proc portal_beaconAddEnrs(enrs: seq[Record]): bool
proc portal_beaconGetEnr(nodeId: NodeId): Record
proc portal_beaconDeleteEnr(nodeId: NodeId): bool
proc portal_beaconLookupEnr(nodeId: NodeId): Record
proc portal_beaconPing(enr: Record): PingResult
proc portal_beaconFindNodes(enr: Record): seq[Record]
proc portal_beaconFindContent(enr: Record, contentKey: string): JsonNode
proc portal_beaconOffer(enr: Record, contentKey: string, contentValue: string): string
proc portal_beaconRecursiveFindNodes(nodeId: NodeId): seq[Record]
proc portal_beaconRecursiveFindContent(contentKey: string): string
proc portal_beaconStore(contentKey: string, contentValue: string): bool
proc portal_beaconLocalContent(contentKey: string): string
proc portal_beaconGossip(contentKey: string, contentValue: string): int
proc portal_beaconRandomGossip(contentKey: string, contentValue: string): int

View File

@ -5,20 +5,34 @@
# * 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.
## Portal History Network json-rpc debug & testing calls
proc portal_history_storeContent(dataFile: string): bool
proc portal_history_propagate(dataFile: string): bool
proc portal_history_propagateHeaders(dataFile: string): bool
proc portal_history_propagateBlock(dataFile: string, blockHash: string): bool
proc portal_history_propagateEpochAccumulator(dataFile: string): bool
proc portal_history_propagateEpochAccumulators(path: string): bool
proc portal_history_storeContentInNodeRange(
dbPath: string, max: uint32, starting: uint32
): bool
{.push raises: [].}
proc portal_history_offerContentInNodeRange(
dbPath: string, nodeId: NodeId, max: uint32, starting: uint32
): int
import json_rpc/rpcclient, ../rpc_types
proc portal_history_depthContentPropagate(dbPath: string, max: uint32): bool
proc portal_history_breadthContentPropagate(dbPath: string): bool
export rpc_types
Opt[string].useDefaultSerializationIn JrpcConv
createRpcSigsFromNim(RpcClient):
## Portal History Network json-rpc debug & custom calls
proc portal_historyGossipHeaders(
era1File: string, epochAccumulatorFile: Opt[string]
): bool
proc portal_historyGossipBlockContent(era1File: string): bool
proc portal_history_storeContent(dataFile: string): bool
proc portal_history_propagate(dataFile: string): bool
proc portal_history_propagateHeaders(dataFile: string): bool
proc portal_history_propagateBlock(dataFile: string, blockHash: string): bool
proc portal_history_propagateEpochAccumulator(dataFile: string): bool
proc portal_history_propagateEpochAccumulators(path: string): bool
proc portal_history_storeContentInNodeRange(
dbPath: string, max: uint32, starting: uint32
): bool
proc portal_history_offerContentInNodeRange(
dbPath: string, nodeId: NodeId, max: uint32, starting: uint32
): int
proc portal_history_depthContentPropagate(dbPath: string, max: uint32): bool
proc portal_history_breadthContentPropagate(dbPath: string): bool

View File

@ -1 +1,13 @@
proc web3_clientVersion(): string
# fluffy
# Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * 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.
{.push raises: [].}
import json_rpc/rpcclient
createRpcSigsFromNim(RpcClient):
proc web3_clientVersion(): string

View File

@ -15,7 +15,7 @@ import
stew/byteutils,
eth/p2p/discoveryv5/random2,
eth/keys,
../../nimbus/rpc/[rpc_types],
../common/common_types,
../rpc/portal_rpc_client,
../rpc/eth_rpc_client,
../eth_data/[history_data_seeding, history_data_json_store, history_data_ssz_e2s],
@ -44,6 +44,9 @@ type
name: "base-rpc-port"
.}: uint16
func w3Hash*(x: common_types.BlockHash): eth_api_types.BlockHash =
eth_api_types.BlockHash(x.data)
proc connectToRpcServers(config: PortalTestnetConf): Future[seq[RpcClient]] {.async.} =
var clients: seq[RpcClient]
for i in 0 ..< config.nodeCount:
@ -278,7 +281,7 @@ procSuite "Portal testnet tests":
# add a json-rpc debug proc that returns whether the offer queue is empty or
# not. And then poll every node until all nodes have an empty queue.
let content = await retryUntil(
proc(): Future[Option[BlockObject]] {.async.} =
proc(): Future[Opt[BlockObject]] {.async.} =
try:
let res = await client.eth_getBlockByHash(w3Hash hash, true)
await client.close()
@ -287,7 +290,7 @@ procSuite "Portal testnet tests":
await client.close()
raise exc
,
proc(mc: Option[BlockObject]): bool =
proc(mc: Opt[BlockObject]): bool =
return mc.isSome()
,
"Did not receive expected Block with hash " & hash.data.toHex(),
@ -304,7 +307,7 @@ procSuite "Portal testnet tests":
let filterOptions = FilterOptions(blockHash: some(w3Hash hash))
let logs = await retryUntil(
proc(): Future[seq[FilterLog]] {.async.} =
proc(): Future[seq[LogObject]] {.async.} =
try:
let res = await client.eth_getLogs(filterOptions)
await client.close()
@ -313,7 +316,7 @@ procSuite "Portal testnet tests":
await client.close()
raise exc
,
proc(mc: seq[FilterLog]): bool =
proc(mc: seq[LogObject]): bool =
return true
,
"",

View File

@ -16,51 +16,46 @@ import
chronicles,
chronicles/topics_registry,
stew/byteutils,
eth/common/eth_types,
../../nimbus/rpc/[rpc_types],
../../nimbus/errors,
web3/primitives,
../rpc/eth_rpc_client
type
Hash256 = eth_types.Hash256
type BlockWalkConf* = object
logLevel* {.
defaultValue: LogLevel.INFO,
defaultValueDesc: $LogLevel.INFO,
desc: "Sets the log level",
name: "log-level"
.}: LogLevel
BlockWalkConf* = object
logLevel* {.
defaultValue: LogLevel.INFO,
defaultValueDesc: $LogLevel.INFO,
desc: "Sets the log level",
name: "log-level"
.}: LogLevel
rpcAddress* {.
desc: "Address of the JSON-RPC service",
defaultValue: "127.0.0.1",
name: "rpc-address"
.}: string
rpcAddress* {.
desc: "Address of the JSON-RPC service",
defaultValue: "127.0.0.1",
name: "rpc-address"
.}: string
rpcPort* {.
defaultValue: 8545, desc: "Port of the JSON-RPC service", name: "rpc-port"
.}: uint16
rpcPort* {.
defaultValue: 8545, desc: "Port of the JSON-RPC service", name: "rpc-port"
.}: uint16
blockHash* {.
desc: "The block hash from where to start walking the blocks backwards",
name: "block-hash"
.}: BlockHash
blockHash* {.
desc: "The block hash from where to start walking the blocks backwards",
name: "block-hash"
.}: Hash256
proc parseCmdArg*(T: type Hash256, p: string): T {.raises: [ValueError].} =
var hash: Hash256
proc parseCmdArg*(T: type BlockHash, p: string): T {.raises: [ValueError].} =
var hash: array[32, byte]
try:
hexToByteArray(p, hash.data)
hexToByteArray(p, hash)
except ValueError:
raise newException(ValueError, "Invalid Hash256")
return hash
return BlockHash(hash)
proc completeCmdArg*(T: type Hash256, val: string): seq[string] =
proc completeCmdArg*(T: type BlockHash, val: string): seq[string] =
return @[]
proc walkBlocks(client: RpcClient, startHash: Hash256) {.async.} =
var parentHash = w3Hash startHash
proc walkBlocks(client: RpcClient, startHash: BlockHash) {.async: (raises: []).} =
var parentHash = startHash
var blockNumber: Quantity
# Should be 0x0, but block 0 does not exist in the json data file
@ -73,16 +68,18 @@ proc walkBlocks(client: RpcClient, startHash: Hash256) {.async.} =
# in this case.
fatal "Error occured on JSON-RPC request", error = e.msg
quit 1
except ValidationError as e:
# ValidationError from buildBlockObject, should not occur with proper
# blocks
except CatchableError as e:
fatal "Error occured on JSON-RPC request", error = e.msg
quit 1
# Using the http connection re-use seems to slow down these sequentual
# requests considerably. Force a new connection setup by doing a close after
# each request.
await client.close()
try:
await client.close()
except CatchableError as e:
fatal "Error closing RPC client connection", error = e.msg
quit 1
if parentBlockOpt.isNone():
fatal "Failed getting parent block", hash = parentHash
@ -92,11 +89,15 @@ proc walkBlocks(client: RpcClient, startHash: Hash256) {.async.} =
blockNumber = parentBlock.number
parentHash = parentBlock.parentHash
echo "Block " & $blockNumber & ": " & $parentBlock.hash
echo "Block " & $distinctBase(blockNumber) & ": " & $parentBlock.hash
proc run(config: BlockWalkConf) {.async.} =
proc run(config: BlockWalkConf) {.async: (raises: []).} =
let client = newRpcHttpClient()
await client.connect(config.rpcAddress, Port(config.rpcPort), false)
try:
await client.connect(config.rpcAddress, Port(config.rpcPort), false)
except CatchableError as e:
fatal "Error connecting to JSON-RPC service", error = e.msg
quit 1
await walkBlocks(client, config.blockHash)

View File

@ -6,7 +6,7 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
std/[options, sequtils, sugar, strutils],
std/[options, sequtils, sugar],
unittest2,
testutils,
chronos,

View File

@ -4,8 +4,15 @@
# * 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.
proc utp_connect(enr: Record): SKey
proc utp_write(k: SKey, b: string): bool
proc utp_read(k: SKey, n: int): string
proc utp_get_connections(): seq[SKey]
proc utp_close(k: SKey): bool
{.push raises: [].}
import json_rpc/rpcclient, ../../rpc/rpc_types, ./utp_rpc_types
export utp_rpc_types
createRpcSigsFromNim(RpcClient):
proc utp_connect(enr: Record): SKey
proc utp_write(k: SKey, b: string): bool
proc utp_read(k: SKey, n: int): string
proc utp_get_connections(): seq[SKey]
proc utp_close(k: SKey): bool

View File

@ -5,14 +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
std/os, json_rpc/rpcclient, ./utp_rpc_types, ../../rpc/[rpc_types, rpc_discovery_api]
import json_rpc/rpcclient, ../../rpc/rpc_calls/rpc_discovery_calls, ./utp_test_rpc_calls
export utp_rpc_types, rpc_types
createRpcSigs(RpcClient, currentSourcePath.parentDir / "utp_test_rpc_calls.nim")
createRpcSigs(
RpcClient,
currentSourcePath.parentDir /../ "" /../ "rpc" / "rpc_calls" /
"rpc_discovery_calls.nim",
)
export rpcclient, rpc_discovery_calls, utp_test_rpc_calls