From 01ae82fd70ee8c84fb71e7e4187876012163811d Mon Sep 17 00:00:00 2001 From: tersec Date: Tue, 1 Aug 2023 06:05:22 +0000 Subject: [PATCH] specify exceptions of callback called by exception-free function (#628) --- eth/p2p/discoveryv5/protocol.nim | 16 +++---- eth/p2p/discoveryv5/routing_table.nim | 61 ++++++++++++++------------- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/eth/p2p/discoveryv5/protocol.nim b/eth/p2p/discoveryv5/protocol.nim index c84a15b..e213c76 100644 --- a/eth/p2p/discoveryv5/protocol.nim +++ b/eth/p2p/discoveryv5/protocol.nim @@ -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) @@ -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) @@ -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 @@ -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])) @@ -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): @@ -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) diff --git a/eth/p2p/discoveryv5/routing_table.nim b/eth/p2p/discoveryv5/routing_table.nim index 3792e90..f481e12 100644 --- a/eth/p2p/discoveryv5/routing_table.nim +++ b/eth/p2p/discoveryv5/routing_table.nim @@ -150,7 +150,7 @@ 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, @@ -158,14 +158,14 @@ proc new(T: type KBucket, istart, iend: NodeId, bucketIpLimit: uint): T = 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 @@ -181,7 +181,7 @@ 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 @@ -189,11 +189,11 @@ proc ipLimitDec(r: var RoutingTable, b: KBucket, n: Node) = 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() @@ -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) @@ -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. @@ -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. @@ -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 @@ -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 @@ -419,7 +419,7 @@ 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) @@ -427,16 +427,16 @@ proc getNode*(r: RoutingTable, id: NodeId): Opt[Node] = 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 @@ -457,7 +457,7 @@ 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) @@ -465,7 +465,7 @@ proc neighboursAtDistance*(r: RoutingTable, distance: uint16, # 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 @@ -479,10 +479,10 @@ 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]) @@ -490,7 +490,7 @@ proc moveRight[T](arr: var openArray[T], a, b: int) = 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) @@ -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 @@ -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