Improve the populating of the routing table (#886)

- Search for the node on an incoming portal message and try to add
it to the routing table
- Don't rely on discv5 nodes for bootstrapping portal networks for
now.
- Attempt to repopulate the routing table when it is at 0 or drops
to 0.
This commit is contained in:
Kim De Mey 2021-11-16 17:50:08 +01:00 committed by GitHub
parent 7066b48303
commit 414fdafab9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 22 additions and 25 deletions

View File

@ -93,11 +93,6 @@ func localNode*(p: PortalProtocol): Node = p.baseProtocol.localNode
proc neighbours*(p: PortalProtocol, id: NodeId, seenOnly = false): seq[Node] = proc neighbours*(p: PortalProtocol, id: NodeId, seenOnly = false): seq[Node] =
p.routingTable.neighbours(id = id, seenOnly = seenOnly) p.routingTable.neighbours(id = id, seenOnly = seenOnly)
# TODO:
# - On incoming portal ping of unknown node: add node to routing table by
# grabbing ENR from discv5 routing table (might not have it)?
# - ENRs with portal protocol capabilities as field?
proc handlePing(p: PortalProtocol, ping: PingMessage): proc handlePing(p: PortalProtocol, ping: PingMessage):
seq[byte] = seq[byte] =
let customPayload = CustomPayload(dataRadius: p.dataRadius) let customPayload = CustomPayload(dataRadius: p.dataRadius)
@ -189,6 +184,15 @@ proc messageHandler*(protocol: TalkProtocol, request: seq[byte],
if decoded.isOk(): if decoded.isOk():
let message = decoded.get() let message = decoded.get()
trace "Received message request", srcId, srcUdpAddress, kind = message.kind trace "Received message request", srcId, srcUdpAddress, kind = message.kind
# Received a proper Portal message, check if this node exists in the base
# routing table and add if so.
# TODO: Could add a findNodes with distance 0 call when not, and perhaps,
# optionally pass ENRs if the message was a discv5 handshake containing the
# ENR.
let node = p.baseProtocol.getNode(srcId)
if node.isSome():
discard p.routingTable.addNode(node.get())
case message.kind case message.kind
of MessageKind.ping: of MessageKind.ping:
p.handlePing(message.ping) p.handlePing(message.ping)
@ -540,25 +544,15 @@ proc queryRandom*(p: PortalProtocol): Future[seq[Node]] =
p.query(NodeId.random(p.baseProtocol.rng[])) p.query(NodeId.random(p.baseProtocol.rng[]))
proc seedTable*(p: PortalProtocol) = proc seedTable*(p: PortalProtocol) =
## Seed the table with nodes from the discv5 table and with specifically ## Seed the table with specifically provided Portal bootstrap nodes. These are
## provided bootstrap nodes. The latter are then supposed to be nodes ## nodes that must support the wire protocol for the specific content network.
## supporting the wire protocol for the specific content network.
# Note: We allow replacing the bootstrap nodes in the routing table as it is # Note: We allow replacing the bootstrap nodes in the routing table as it is
# possible that some of these are not supporting the specific portal network. # possible that some of these are not supporting the specific portal network.
# Other note: One could also pick nodes from the discv5 routing table to
# bootstrap the portal networks, however it would require a flag in the ENR to
# be added and there might be none in the routing table due to low amount of
# Portal nodes versus other nodes.
# TODO: Picking some nodes from discv5 routing table now. Should definitely
# add supported Portal network info in a k:v pair in the ENRs and filter on
# that.
let closestNodes = p.baseProtocol.neighbours(
NodeId.random(p.baseProtocol.rng[]), seenOnly = true)
for node in closestNodes:
if p.routingTable.addNode(node) == Added:
debug "Added node from discv5 routing table", uri = toURI(node.record)
else:
debug "Node from discv5 routing table could not be added", uri = toURI(node.record)
# Seed the table with bootstrap nodes.
for record in p.bootstrapRecords: for record in p.bootstrapRecords:
if p.addNode(record): if p.addNode(record):
debug "Added bootstrap node", uri = toURI(record), debug "Added bootstrap node", uri = toURI(record),
@ -612,9 +606,14 @@ proc refreshLoop(p: PortalProtocol) {.async.} =
## no queries were done since `refreshInterval` or more. ## no queries were done since `refreshInterval` or more.
## It also refreshes the majority address voted for via pong responses. ## It also refreshes the majority address voted for via pong responses.
try: try:
await p.populateTable()
while true: while true:
# TODO: It would be nicer and more secure if this was event based and/or
# steered from the routing table.
while p.routingTable.len() == 0:
p.seedTable()
await p.populateTable()
await sleepAsync(5.seconds)
let currentTime = now(chronos.Moment) let currentTime = now(chronos.Moment)
if currentTime > (p.lastLookup + RefreshInterval): if currentTime > (p.lastLookup + RefreshInterval):
let randomQuery = await p.queryRandom() let randomQuery = await p.queryRandom()
@ -626,8 +625,6 @@ proc refreshLoop(p: PortalProtocol) {.async.} =
trace "refreshLoop canceled" trace "refreshLoop canceled"
proc start*(p: PortalProtocol) = proc start*(p: PortalProtocol) =
p.seedTable()
p.refreshLoop = refreshLoop(p) p.refreshLoop = refreshLoop(p)
p.revalidateLoop = revalidateLoop(p) p.revalidateLoop = revalidateLoop(p)