From a9e53a4a84d8eda66d009255e6a6a9ccad387649 Mon Sep 17 00:00:00 2001 From: cheatfate Date: Fri, 4 Oct 2024 03:18:30 +0300 Subject: [PATCH] Attempt to fix issue with AnyLocal addresses in last-seen-p2p-address field. --- beacon_chain/rpc/rest_node_api.nim | 78 +++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/beacon_chain/rpc/rest_node_api.nim b/beacon_chain/rpc/rest_node_api.nim index b96e0724b..31e8e0b03 100644 --- a/beacon_chain/rpc/rest_node_api.nim +++ b/beacon_chain/rpc/rest_node_api.nim @@ -7,6 +7,7 @@ {.push raises: [].} import + std/algorithm, stew/byteutils, chronicles, eth/p2p/discoveryv5/enr, @@ -97,15 +98,80 @@ proc toString(direction: PeerType): string = of PeerType.Outgoing: "outbound" +proc getProtocolArgument(ma: MultiAddress, + codec: MultiCodec): MaResult[seq[byte]] = + var buffer: seq[byte] + for item in ma: + let + ritem = ? item + code = ? ritem.protoCode() + if code == codec: + let arg = ? ritem.protoAddress() + return ok(arg) + err("Multiaddress codec has not been found") + proc getLastSeenAddress(node: BeaconNode, id: PeerId): string = - # TODO (cheatfate): We need to provide filter here, which will be able to - # filter such multiaddresses like `/ip4/0.0.0.0` or local addresses or - # addresses with peer ids. - let addrs = node.network.switch.peerStore[AddressBook][id] - if len(addrs) > 0: - $addrs[len(addrs) - 1] + # Because `last_seen_p2p_address` is single address but libp2p reports lot of + # addresses, we going to sort list of addresses before selecting one. Here + # sort order list: + # 1. Globally routable IPv6 address. + # 2. Globally routable IPv4 address. + # 3. Non IPv4/IPv6 multiaddress. + # 4. Site-local IPv6 address. + # 5. Site-local IPv4 address. + # 6. Link-local IPv6 address. + # 7. Link-local IPv4 address. + # 8. Loopback IPv6 address. + # 9. Loopback IPv4 address. + # 10. All other IPv6 address types. + # 11. All other IPv4 address types. + proc compare( + a, b: tuple[address: MultiAddress, position: int] + ): int {.closure.} = cmp(a.position, b.position) + let addresses = node.network.switch.peerStore[AddressBook][id] + var temp: seq[tuple[address: MultiAddress, position: int]] + for address in addresses: + let res = + if IP4.matchPartial(address): + let address4 = address.getProtocolArgument(multiCodec("ip4")).valueOr: + continue + var ta4 = TransportAddress(family: AddressFamily.IPv4) + ta4.address_v4[0 .. 3] = address4[0 .. 3] + if ta4.isLoopback(): + (address, 9) + elif ta4.isLinkLocal(): + (address, 7) + elif ta4.isSiteLocal(): + (address, 5) + elif ta4.isGlobal(): + (address, 2) + else: + (address, 11) + elif IP6.matchPartial(address): + let address6 = address.getProtocolArgument(multiCodec("ip4")).valueOr: + continue + var ta6 = TransportAddress(family: AddressFamily.IPv4) + ta6.address_v6[0 .. 15] = address6[0 .. 15] + if ta6.isLoopback(): + (address, 8) + elif ta6.isLinkLocal(): + (address, 6) + elif ta6.isSiteLocal(): + (address, 4) + elif ta6.isGlobal(): + (address, 1) + else: + (address, 10) + else: + (address, 3) + temp.add(res) + + if len(temp) > 0: + sort(temp, compare, SortOrder.Ascending) + $temp[0].address else: "" + proc getDiscoveryAddresses(node: BeaconNode): seq[string] = let typedRec = TypedRecord.fromRecord(node.network.enrRecord())