From f4ca598c03b1d77a973a9e0f287641ec30ae06d4 Mon Sep 17 00:00:00 2001 From: Kim De Mey Date: Mon, 20 Dec 2021 11:57:55 +0100 Subject: [PATCH] Some version of the findContent JSON-RPC proc (#918) Also includes fixing instantiation of the history network json-rpc API handles. --- fluffy/docs/protocol_interop.md | 4 +++ fluffy/fluffy.nim | 2 +- fluffy/network/wire/portal_protocol.nim | 4 +-- fluffy/rpc/rpc_portal_api.nim | 44 +++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/fluffy/docs/protocol_interop.md b/fluffy/docs/protocol_interop.md index f837aed57..c2411ba7c 100644 --- a/fluffy/docs/protocol_interop.md +++ b/fluffy/docs/protocol_interop.md @@ -48,6 +48,10 @@ curl -s -X POST -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":"1 # Extra parameter is an array of requested logarithmic distances curl -s -X POST -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":"1","method":"portal_state_findNodes","params":["enr:", [254, 255, 256]]}' http://localhost:8545 | jq +# FindContent / Content +# A request with an invalid content key will not receive a response +curl -s -X POST -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":"1","method":"portal_state_findContent","params":["enr:", "02829bd824b016326a401d083b33d092293333a830d1c390624d3bd4e409a61a858e5dcc5517729a9170d014a6c96530d64dd8621d"]}' http://localhost:8545 | jq + # Read out the Portal state network routing table contents curl -s -X POST -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","id":"1","method":"portal_state_routingTableInfo","params":[]}' http://localhost:8545 | jq ``` diff --git a/fluffy/fluffy.nim b/fluffy/fluffy.nim index b79a6db4e..4f78e3580 100644 --- a/fluffy/fluffy.nim +++ b/fluffy/fluffy.nim @@ -99,7 +99,7 @@ proc run(config: PortalConf) {.raises: [CatchableError, Defect].} = rpcHttpServerWithProxy.installEthApiHandlers() rpcHttpServerWithProxy.installDiscoveryApiHandlers(d) rpcHttpServerWithProxy.installPortalApiHandlers(stateNetwork.portalProtocol, "state") - rpcHttpServerWithProxy.installPortalApiHandlers(stateNetwork.portalProtocol, "history") + rpcHttpServerWithProxy.installPortalApiHandlers(historyNetwork.portalProtocol, "history") # TODO for now we can only proxy to local node (or remote one without ssl) to make it possible # to call infura https://github.com/status-im/nim-json-rpc/pull/101 needs to get merged for http client to support https/ waitFor rpcHttpServerWithProxy.start() diff --git a/fluffy/network/wire/portal_protocol.nim b/fluffy/network/wire/portal_protocol.nim index d37886b1e..8dc6e8e70 100644 --- a/fluffy/network/wire/portal_protocol.nim +++ b/fluffy/network/wire/portal_protocol.nim @@ -24,7 +24,7 @@ logScope: const alpha = 3 ## Kademlia concurrency factor - enrsResultLimit = 32 ## Maximum amount of ENRs in the total Nodes messages + enrsResultLimit* = 32 ## Maximum amount of ENRs in the total Nodes messages ## that will be processed refreshInterval = 5.minutes ## Interval of launching a random query to ## refresh the routing table. @@ -308,7 +308,7 @@ proc offer*(p: PortalProtocol, dst: Node, contentKeys: ContentKeysList): # id, and initiate an uTP stream with given uTP connection id to get the data # out. -proc recordsFromBytes(rawRecords: List[ByteList, 32]): PortalResult[seq[Record]] = +proc recordsFromBytes*(rawRecords: List[ByteList, 32]): PortalResult[seq[Record]] = var records: seq[Record] for r in rawRecords.asSeq(): var record: Record diff --git a/fluffy/rpc/rpc_portal_api.nim b/fluffy/rpc/rpc_portal_api.nim index d69708c94..93a3b966d 100644 --- a/fluffy/rpc/rpc_portal_api.nim +++ b/fluffy/rpc/rpc_portal_api.nim @@ -10,6 +10,7 @@ import std/sequtils, json_rpc/[rpcproxy, rpcserver], stew/byteutils, + eth/p2p/discoveryv5/nodes_verification, ../network/wire/portal_protocol, ./rpc_types @@ -63,6 +64,49 @@ proc installPortalApiHandlers*( else: return nodes.get().map(proc(n: Node): Record = n.record) + # TODO: This returns null values for the `none`s. Not sure what it should be + # according to spec, no k:v pair at all? + # Note: Would it not be nice to have a call that resturns either content or + # ENRs, and that the connection id is used in the background instead of this + # "raw" `findContent` call. + rpcServer.rpc("portal_" & network & "_findContent") do( + enr: Record, contentKey: string) -> tuple[ + connectionId: Option[string], + content: Option[string], + enrs: Option[seq[Record]]]: + let + node = toNodeWithAddress(enr) + content = await p.findContent( + node, ByteList.init(hexToSeqByte(contentKey))) + + if content.isErr(): + raise newException(ValueError, $content.error) + else: + let contentMessage = content.get() + case contentMessage.contentMessageType: + of connectionIdType: + return ( + some("0x" & contentMessage.connectionId.toHex()), + none(string), + none(seq[Record])) + of contentType: + return ( + none(string), + some("0x" & contentMessage.content.asSeq().toHex()), + none(seq[Record])) + of enrsType: + let records = recordsFromBytes(contentMessage.enrs) + if records.isErr(): + raise newException(ValueError, $records.error) + else: + return ( + none(string), + none(string), + # Note: Could also pass not verified nodes + some(verifyNodesRecords( + records.get(), node, enrsResultLimit).map( + proc(n: Node): Record = n.record))) + rpcServer.rpc("portal_" & network & "_recursiveFindNodes") do() -> seq[Record]: let discovered = await p.queryRandom() return discovered.map(proc(n: Node): Record = n.record)