mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-13 13:55:45 +00:00
38036966a6
* Improve the tests of the local testnet The local testnet test was rather flaky and would occasionally fail. It has been made more robust by adding the ENRs directly to the routing table instead of doing some random lookups. Additionally, the amount of nodes were increased (=64), ip limits configuration was added, and the bits-per-hop value was set to 1 in order to make the lookups more likely to hit the network instead of only the local routing table. Failure is obviously still possible to happen when sufficient packets get lost. If this turns out to be the case with the current amount of nodes, we might have to revise the testing strategy here. * Disable lookup test for State network Disable lookup test for State network due to issue with custom distance function causing the lookup to not always converging towards the target.
157 lines
5.7 KiB
Nim
157 lines
5.7 KiB
Nim
# Nimbus
|
|
# Copyright (c) 2021 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: [Defect].}
|
|
|
|
import
|
|
std/sequtils,
|
|
json_rpc/[rpcproxy, rpcserver], stew/byteutils,
|
|
eth/p2p/discoveryv5/nodes_verification,
|
|
../network/wire/portal_protocol,
|
|
./rpc_types
|
|
|
|
export rpcserver
|
|
|
|
# Note:
|
|
# Using a string for the network parameter will give an error in the rpc macro:
|
|
# Error: Invalid node kind nnkInfix for macros.`$`
|
|
# Using a static string works but some sandwich problem seems to be happening,
|
|
# as the proc becomes generic, where the rpc macro from router.nim can no longer
|
|
# be found, which is why we export rpcserver which should export router.
|
|
proc installPortalApiHandlers*(
|
|
rpcServer: RpcServer|RpcProxy, p: PortalProtocol, network: static string)
|
|
{.raises: [Defect, CatchableError].} =
|
|
## Portal routing table and portal wire json-rpc API is not yet defined but
|
|
## will look something similar as what exists here now:
|
|
## https://github.com/ethereum/portal-network-specs/pull/88
|
|
|
|
rpcServer.rpc("portal_" & network & "_nodeInfo") do() -> NodeInfo:
|
|
return p.routingTable.getNodeInfo()
|
|
|
|
rpcServer.rpc("portal_" & network & "_routingTableInfo") do() -> RoutingTableInfo:
|
|
return getRoutingTableInfo(p.routingTable)
|
|
|
|
rpcServer.rpc("portal_" & network & "_lookupEnr") do(nodeId: NodeId) -> Record:
|
|
let lookup = await p.resolve(nodeId)
|
|
if lookup.isSome():
|
|
return lookup.get().record
|
|
else:
|
|
raise newException(ValueError, "Record not found in DHT lookup.")
|
|
|
|
rpcServer.rpc("portal_" & network & "_addEnrs") do(enrs: seq[Record]) -> bool:
|
|
for enr in enrs:
|
|
let nodeRes = newNode(enr)
|
|
if nodeRes.isOk():
|
|
let node = nodeRes.get()
|
|
discard p.addNode(node)
|
|
p.routingTable.setJustSeen(node)
|
|
|
|
return true
|
|
|
|
rpcServer.rpc("portal_" & network & "_ping") do(
|
|
enr: Record) -> tuple[seqNum: uint64, customPayload: string]:
|
|
let
|
|
node = toNodeWithAddress(enr)
|
|
pong = await p.ping(node)
|
|
|
|
if pong.isErr():
|
|
raise newException(ValueError, $pong.error)
|
|
else:
|
|
let p = pong.get()
|
|
return (p.enrSeq, p.customPayload.asSeq().toHex())
|
|
|
|
rpcServer.rpc("portal_" & network & "_findNodes") do(
|
|
enr: Record, distances: seq[uint16]) -> seq[Record]:
|
|
let
|
|
node = toNodeWithAddress(enr)
|
|
nodes = await p.findNodesVerified(node, distances)
|
|
if nodes.isErr():
|
|
raise newException(ValueError, $nodes.error)
|
|
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.findContentImpl(
|
|
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 & "_findContentExt") do(
|
|
enr: Record, contentKey: string) -> tuple[
|
|
content: Option[string], enrs: Option[seq[Record]]]:
|
|
let
|
|
node = toNodeWithAddress(enr)
|
|
foundContentResult = await p.findContent(
|
|
node, ByteList.init(hexToSeqByte(contentKey)))
|
|
|
|
if foundContentResult.isErr():
|
|
raise newException(ValueError, $foundContentResult.error)
|
|
else:
|
|
let foundContent = foundContentResult.get()
|
|
case foundContent.kind:
|
|
of Content:
|
|
return (
|
|
some("0x" & foundContent.content.toHex()),
|
|
none(seq[Record]))
|
|
of Nodes:
|
|
return (
|
|
none(string),
|
|
some(foundContent.nodes.map(proc(n: Node): Record = n.record)))
|
|
|
|
rpcServer.rpc("portal_" & network & "_offerExt") do(
|
|
enr: Record, contentKey: string) -> bool:
|
|
# Only allow 1 content key for now
|
|
let
|
|
node = toNodeWithAddress(enr)
|
|
contentKeys = ContentKeysList(@[ByteList.init(hexToSeqByte(contentKey))])
|
|
accept = await p.offer(node, contentKeys)
|
|
if accept.isErr():
|
|
raise newException(ValueError, $accept.error)
|
|
else:
|
|
return true
|
|
|
|
rpcServer.rpc("portal_" & network & "_recursiveFindNodes") do() -> seq[Record]:
|
|
let discovered = await p.queryRandom()
|
|
return discovered.map(proc(n: Node): Record = n.record)
|