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.
129 lines
4.5 KiB
Nim
129 lines
4.5 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/protocol as discv5_protocol,
|
|
./rpc_types
|
|
|
|
export rpc_types # tasty sandwich
|
|
|
|
type
|
|
PongResponse* = object
|
|
enrSeq: uint64
|
|
recipientIP: string
|
|
recipientPort: uint16
|
|
|
|
proc installDiscoveryApiHandlers*(rpcServer: RpcServer|RpcProxy,
|
|
d: discv5_protocol.Protocol) {.raises: [Defect, CatchableError].} =
|
|
## Discovery v5 JSON-RPC API such as defined here:
|
|
## https://ddht.readthedocs.io/en/latest/jsonrpc.html
|
|
## and here:
|
|
## https://github.com/ethereum/portal-network-specs/pull/88
|
|
## Note: There are quite some discrepancies between the two, can only
|
|
## implement exactly once specification has settled.
|
|
|
|
rpcServer.rpc("discv5_routingTableInfo") do() -> RoutingTableInfo:
|
|
return getRoutingTableInfo(d.routingTable)
|
|
|
|
rpcServer.rpc("discv5_nodeInfo") do() -> NodeInfo:
|
|
return d.routingTable.getNodeInfo()
|
|
|
|
rpcServer.rpc("discv5_updateNodeInfo") do(
|
|
kvPairs: seq[(string, string)]) -> NodeInfo:
|
|
let enrFields = kvPairs.map(
|
|
proc(n: (string, string)): (string, seq[byte]) =
|
|
(n[0], hexToSeqByte(n[1]))
|
|
)
|
|
let updated = d.updateRecord(enrFields)
|
|
if updated.isErr():
|
|
raise newException(ValueError, $updated.error)
|
|
|
|
return d.routingTable.getNodeInfo()
|
|
|
|
rpcServer.rpc("discv5_addEnrs") do(enrs: seq[Record]) -> bool:
|
|
# TODO: We could also adjust the API of addNode & newNode to accept a seen
|
|
# parameter, but perhaps only if that makes sense on other locations in
|
|
# discv5/portal that are not testing/debug related.
|
|
for enr in enrs:
|
|
let nodeRes = newNode(enr)
|
|
if nodeRes.isOk():
|
|
let node = nodeRes.get()
|
|
discard d.addNode(node)
|
|
d.routingTable.setJustSeen(node)
|
|
|
|
return true
|
|
|
|
rpcServer.rpc("discv5_getEnr") do(nodeId: NodeId) -> Record:
|
|
let node = d.getNode(nodeId)
|
|
if node.isSome():
|
|
return node.get().record
|
|
else:
|
|
raise newException(ValueError, "Record not in local routing table.")
|
|
|
|
rpcServer.rpc("discv5_deleteEnr") do(nodeId: NodeId) -> bool:
|
|
# TODO: Adjust `removeNode` to accept NodeId as param and to return bool.
|
|
let node = d.getNode(nodeId)
|
|
if node.isSome():
|
|
d.routingTable.removeNode(node.get())
|
|
return true
|
|
else:
|
|
raise newException(ValueError, "Record not in local routing table.")
|
|
|
|
rpcServer.rpc("discv5_lookupEnr") do(nodeId: NodeId) -> Record:
|
|
# TODO: Not using seqNum, what is the use case of this?
|
|
let lookup = await d.resolve(nodeId)
|
|
if lookup.isSome():
|
|
return lookup.get().record
|
|
else:
|
|
raise newException(ValueError, "Record not found in DHT lookup.")
|
|
|
|
rpcServer.rpc("discv5_ping") do(enr: Record) -> PongResponse:
|
|
let
|
|
node = toNodeWithAddress(enr)
|
|
pong = await d.ping(node)
|
|
|
|
if pong.isErr():
|
|
raise newException(ValueError, $pong.error)
|
|
else:
|
|
let p = pong.get()
|
|
return PongResponse(
|
|
enrSeq: p.enrSeq,
|
|
recipientIP: $p.ip,
|
|
recipientPort: p.port
|
|
)
|
|
|
|
rpcServer.rpc("discv5_findNode") do(
|
|
enr: Record, distances: seq[uint16]) -> seq[Record]:
|
|
let
|
|
node = toNodeWithAddress(enr)
|
|
nodes = await d.findNode(node, distances)
|
|
if nodes.isErr():
|
|
raise newException(ValueError, $nodes.error)
|
|
else:
|
|
return nodes.get().map(proc(n: Node): Record = n.record)
|
|
|
|
rpcServer.rpc("discv5_talkReq") do(enr: Record, protocol, payload: string) -> string:
|
|
let
|
|
node = toNodeWithAddress(enr)
|
|
talkresp = await d.talkreq(
|
|
node, hexToSeqByte(protocol), hexToSeqByte(payload))
|
|
if talkresp.isErr():
|
|
raise newException(ValueError, $talkresp.error)
|
|
else:
|
|
return talkresp.get().toHex()
|
|
|
|
rpcServer.rpc("discv5_recursiveFindNodes") do() -> seq[Record]:
|
|
# TODO: Not according to the specification currently as the node_id is a
|
|
# parameter to be passed, but in that case it would be very similar to
|
|
# discv5_lookupEnr.
|
|
let discovered = await d.lookup(NodeId.random(d.rng[]))
|
|
return discovered.map(proc(n: Node): Record = n.record)
|