Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

specify exceptions of callback called by exception-free function #628

Merged
merged 1 commit into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions eth/p2p/discoveryv5/protocol.nim
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ proc addNode*(d: Protocol, enr: EnrUri): bool =
if res:
return d.addNode(r)

proc getNode*(d: Protocol, id: NodeId): Opt[Node] =
func getNode*(d: Protocol, id: NodeId): Opt[Node] =
## Get the node with id from the routing table.
d.routingTable.getNode(id)

Expand All @@ -214,7 +214,7 @@ proc randomNodes*(d: Protocol, maxAmount: int): seq[Node] =
d.routingTable.randomNodes(maxAmount)

proc randomNodes*(d: Protocol, maxAmount: int,
pred: proc(x: Node): bool {.gcsafe, noSideEffect.}): seq[Node] =
pred: proc(x: Node): bool {.raises: [], gcsafe, noSideEffect.}): seq[Node] =
## Get a `maxAmount` of random nodes from the local routing table with the
## `pred` predicate function applied as filter on the nodes selected.
d.routingTable.randomNodes(maxAmount, pred)
Expand All @@ -225,17 +225,17 @@ proc randomNodes*(d: Protocol, maxAmount: int,
## the nodes selected are filtered by provided `enrField`.
d.randomNodes(maxAmount, proc(x: Node): bool = x.record.contains(enrField))

proc neighbours*(d: Protocol, id: NodeId, k: int = BUCKET_SIZE,
func neighbours*(d: Protocol, id: NodeId, k: int = BUCKET_SIZE,
seenOnly = false): seq[Node] =
## Return up to k neighbours (closest node ids) of the given node id.
d.routingTable.neighbours(id, k, seenOnly)

proc neighboursAtDistances*(d: Protocol, distances: seq[uint16],
func neighboursAtDistances*(d: Protocol, distances: seq[uint16],
k: int = BUCKET_SIZE, seenOnly = false): seq[Node] =
## Return up to k neighbours (closest node ids) at given distances.
d.routingTable.neighboursAtDistances(distances, k, seenOnly)

proc nodesDiscovered*(d: Protocol): int = d.routingTable.len
func nodesDiscovered*(d: Protocol): int = d.routingTable.len

func privKey*(d: Protocol): lent PrivateKey =
d.privateKey
Expand All @@ -244,7 +244,7 @@ func getRecord*(d: Protocol): Record =
## Get the ENR of the local node.
d.localNode.record

proc updateRecord*(
func updateRecord*(
d: Protocol, enrFields: openArray[(string, seq[byte])]): DiscResult[void] =
## Update the ENR of the local node with provided `enrFields` k:v pairs.
let fields = mapIt(enrFields, toFieldPair(it[0], it[1]))
Expand Down Expand Up @@ -382,7 +382,7 @@ proc handleMessage(d: Protocol, srcId: NodeId, fromAddr: Address,
trace "Timed out or unrequested message", kind = message.kind,
origin = fromAddr

proc registerTalkProtocol*(d: Protocol, protocolId: seq[byte],
func registerTalkProtocol*(d: Protocol, protocolId: seq[byte],
protocol: TalkProtocol): DiscResult[void] =
# Currently allow only for one handler per talk protocol.
if d.talkProtocols.hasKeyOrPut(protocolId, protocol):
Expand Down Expand Up @@ -617,7 +617,7 @@ proc talkReq*(d: Protocol, toNode: Node, protocol, request: seq[byte]):
discovery_message_requests_outgoing.inc(labelValues = ["no_response"])
return err("Talk response message not received in time")

proc lookupDistances*(target, dest: NodeId): seq[uint16] =
func lookupDistances*(target, dest: NodeId): seq[uint16] =
let td = logDistance(target, dest)
let tdAsInt = int(td)
result.add(td)
Expand Down
61 changes: 31 additions & 30 deletions eth/p2p/discoveryv5/routing_table.nim
Original file line number Diff line number Diff line change
Expand Up @@ -150,22 +150,22 @@ func logDistance*(r: RoutingTable, a, b: NodeId): uint16 =
func idAtDistance*(r: RoutingTable, id: NodeId, dist: uint16): NodeId =
r.distanceCalculator.calculateIdAtDistance(id, dist)

proc new(T: type KBucket, istart, iend: NodeId, bucketIpLimit: uint): T =
func new(T: type KBucket, istart, iend: NodeId, bucketIpLimit: uint): T =
KBucket(
istart: istart,
iend: iend,
nodes: @[],
replacementCache: @[],
ipLimits: IpLimits(limit: bucketIpLimit))

proc midpoint(k: KBucket): NodeId =
func midpoint(k: KBucket): NodeId =
k.istart + (k.iend - k.istart) div 2.u256

proc len(k: KBucket): int = k.nodes.len
func len(k: KBucket): int = k.nodes.len

proc tail(k: KBucket): Node = k.nodes[high(k.nodes)]
func tail(k: KBucket): Node = k.nodes[high(k.nodes)]

proc ipLimitInc(r: var RoutingTable, b: KBucket, n: Node): bool =
func ipLimitInc(r: var RoutingTable, b: KBucket, n: Node): bool =
## Check if the ip limits of the routing table and the bucket are reached for
## the specified `Node` its ip.
## When one of the ip limits is reached return false, else increment them and
Expand All @@ -181,19 +181,19 @@ proc ipLimitInc(r: var RoutingTable, b: KBucket, n: Node): bool =

return true

proc ipLimitDec(r: var RoutingTable, b: KBucket, n: Node) =
func ipLimitDec(r: var RoutingTable, b: KBucket, n: Node) =
## Decrement the ip limits of the routing table and the bucket for the
## specified `Node` its ip.
let ip = n.address.get().ip # Node from table should always have an address

b.ipLimits.dec(ip)
r.ipLimits.dec(ip)

proc add(k: KBucket, n: Node) =
func add(k: KBucket, n: Node) =
k.nodes.add(n)
routing_table_nodes.inc()

proc remove(k: KBucket, n: Node): bool =
func remove(k: KBucket, n: Node): bool =
let i = k.nodes.find(n)
if i != -1:
routing_table_nodes.dec()
Expand All @@ -204,7 +204,7 @@ proc remove(k: KBucket, n: Node): bool =
else:
false

proc split(k: KBucket): tuple[lower, upper: KBucket] =
func split(k: KBucket): tuple[lower, upper: KBucket] =
## Split the kbucket `k` at the median id.
let splitid = k.midpoint
result.lower = KBucket.new(k.istart, splitid, k.ipLimits.limit)
Expand All @@ -224,12 +224,12 @@ proc split(k: KBucket): tuple[lower, upper: KBucket] =
doAssert(bucket.ipLimits.inc(node.address.get().ip),
"IpLimit increment should work as all buckets have the same limits")

proc inRange(k: KBucket, n: Node): bool =
func inRange(k: KBucket, n: Node): bool =
k.istart <= n.id and n.id <= k.iend

proc contains(k: KBucket, n: Node): bool = n in k.nodes
func contains(k: KBucket, n: Node): bool = n in k.nodes

proc binaryGetBucketForNode*(buckets: openArray[KBucket],
func binaryGetBucketForNode*(buckets: openArray[KBucket],
id: NodeId): KBucket =
## Given a list of ordered buckets, returns the bucket for a given `NodeId`.
## Returns nil if no bucket in range for given `id` is found.
Expand Down Expand Up @@ -263,7 +263,7 @@ proc computeSharedPrefixBits(nodes: openArray[NodeId]): int =
# Reaching this would mean that all node ids are equal.
doAssert(false, "Unable to calculate number of shared prefix bits")

proc init*(T: type RoutingTable, localNode: Node, bitsPerHop = DefaultBitsPerHop,
func init*(T: type RoutingTable, localNode: Node, bitsPerHop = DefaultBitsPerHop,
ipLimits = DefaultTableIpLimits, rng: ref HmacDrbgContext,
distanceCalculator = XorDistanceCalculator): T =
## Initialize the routing table for provided `Node` and bitsPerHop value.
Expand All @@ -276,18 +276,18 @@ proc init*(T: type RoutingTable, localNode: Node, bitsPerHop = DefaultBitsPerHop
distanceCalculator: distanceCalculator,
rng: rng)

proc splitBucket(r: var RoutingTable, index: int) =
func splitBucket(r: var RoutingTable, index: int) =
let bucket = r.buckets[index]
let (a, b) = bucket.split()
r.buckets[index] = a
r.buckets.insert(b, index + 1)

proc bucketForNode(r: RoutingTable, id: NodeId): KBucket =
func bucketForNode(r: RoutingTable, id: NodeId): KBucket =
result = binaryGetBucketForNode(r.buckets, id)
doAssert(not result.isNil(),
"Routing table should always cover the full id space")

proc addReplacement(r: var RoutingTable, k: KBucket, n: Node): NodeStatus =
func addReplacement(r: var RoutingTable, k: KBucket, n: Node): NodeStatus =
## Add the node to the tail of the replacement cache of the KBucket.
##
## If the replacement cache is full, the oldest (first entry) node will be
Expand Down Expand Up @@ -398,13 +398,13 @@ proc addNode*(r: var RoutingTable, n: Node): NodeStatus =
# When bucket doesn't get split the node is added to the replacement cache
return r.addReplacement(bucket, n)

proc removeNode*(r: var RoutingTable, n: Node) =
func removeNode*(r: var RoutingTable, n: Node) =
## Remove the node `n` from the routing table.
let b = r.bucketForNode(n.id)
if b.remove(n):
ipLimitDec(r, b, n)

proc replaceNode*(r: var RoutingTable, n: Node) =
func replaceNode*(r: var RoutingTable, n: Node) =
## Replace node `n` with last entry in the replacement cache. If there are
## no entries in the replacement cache, node `n` will simply be removed.
# TODO: Kademlia paper recommends here to not remove nodes if there are no
Expand All @@ -419,24 +419,24 @@ proc replaceNode*(r: var RoutingTable, n: Node) =
b.add(b.replacementCache[high(b.replacementCache)])
b.replacementCache.delete(high(b.replacementCache))

proc getNode*(r: RoutingTable, id: NodeId): Opt[Node] =
func getNode*(r: RoutingTable, id: NodeId): Opt[Node] =
## Get the `Node` with `id` as `NodeId` from the routing table.
## If no node with provided node id can be found,`none` is returned .
let b = r.bucketForNode(id)
for n in b.nodes:
if n.id == id:
return Opt.some(n)

proc contains*(r: RoutingTable, n: Node): bool = n in r.bucketForNode(n.id)
func contains*(r: RoutingTable, n: Node): bool = n in r.bucketForNode(n.id)
# Check if the routing table contains node `n`.

proc bucketsByDistanceTo(r: RoutingTable, id: NodeId): seq[KBucket] =
func bucketsByDistanceTo(r: RoutingTable, id: NodeId): seq[KBucket] =
sortedByIt(r.buckets, r.distance(it.midpoint, id))

proc nodesByDistanceTo(r: RoutingTable, k: KBucket, id: NodeId): seq[Node] =
func nodesByDistanceTo(r: RoutingTable, k: KBucket, id: NodeId): seq[Node] =
sortedByIt(k.nodes, r.distance(it.id, id))

proc neighbours*(r: RoutingTable, id: NodeId, k: int = BUCKET_SIZE,
func neighbours*(r: RoutingTable, id: NodeId, k: int = BUCKET_SIZE,
seenOnly = false): seq[Node] =
## Return up to k neighbours of the given node id.
## When seenOnly is set to true, only nodes that have been contacted
Expand All @@ -457,15 +457,15 @@ proc neighbours*(r: RoutingTable, id: NodeId, k: int = BUCKET_SIZE,
if result.len > k:
result.setLen(k)

proc neighboursAtDistance*(r: RoutingTable, distance: uint16,
func neighboursAtDistance*(r: RoutingTable, distance: uint16,
k: int = BUCKET_SIZE, seenOnly = false): seq[Node] =
## Return up to k neighbours at given logarithmic distance.
result = r.neighbours(r.idAtDistance(r.localNode.id, distance), k, seenOnly)
# This is a bit silly, first getting closest nodes then to only keep the ones
# that are exactly the requested distance.
keepIf(result, proc(n: Node): bool = r.logDistance(n.id, r.localNode.id) == distance)

proc neighboursAtDistances*(r: RoutingTable, distances: seq[uint16],
func neighboursAtDistances*(r: RoutingTable, distances: seq[uint16],
k: int = BUCKET_SIZE, seenOnly = false): seq[Node] =
## Return up to k neighbours at given logarithmic distances.
# TODO: This will currently return nodes with neighbouring distances on the
Expand All @@ -479,18 +479,18 @@ proc neighboursAtDistances*(r: RoutingTable, distances: seq[uint16],
keepIf(result, proc(n: Node): bool =
distances.contains(r.logDistance(n.id, r.localNode.id)))

proc len*(r: RoutingTable): int =
func len*(r: RoutingTable): int =
for b in r.buckets: result += b.len

proc moveRight[T](arr: var openArray[T], a, b: int) =
func moveRight[T](arr: var openArray[T], a, b: int) =
## In `arr` move elements in range [a, b] right by 1.
var t: T
shallowCopy(t, arr[b + 1])
for i in countdown(b, a):
shallowCopy(arr[i + 1], arr[i])
shallowCopy(arr[a], t)

proc setJustSeen*(r: RoutingTable, n: Node) =
func setJustSeen*(r: RoutingTable, n: Node) =
## Move `n` to the head (most recently seen) of its bucket.
## If `n` is not in the routing table, do nothing.
let b = r.bucketForNode(n.id)
Expand All @@ -503,7 +503,7 @@ proc setJustSeen*(r: RoutingTable, n: Node) =
b.nodes[0].seen = true
routing_table_nodes.inc(labelValues = ["seen"])

proc nodeToRevalidate*(r: RoutingTable): Node =
func nodeToRevalidate*(r: RoutingTable): Node =
## Return a node to revalidate. The least recently seen node from a random
## bucket is selected.
var buckets = r.buckets
Expand All @@ -515,7 +515,8 @@ proc nodeToRevalidate*(r: RoutingTable): Node =
return b.nodes[^1]

proc randomNodes*(r: RoutingTable, maxAmount: int,
pred: proc(x: Node): bool {.gcsafe, noSideEffect.} = nil): seq[Node] =
pred: proc(x: Node): bool {.raises: [], gcsafe, noSideEffect.} = nil):
seq[Node] =
## Get a `maxAmount` of random nodes from the routing table with the `pred`
## predicate function applied as filter on the nodes selected.
var maxAmount = maxAmount
Expand Down
Loading