2024-06-28 10:34:57 +00:00
|
|
|
|
{.push raises: [].}
|
2021-03-26 08:49:51 +00:00
|
|
|
|
|
|
|
|
|
import
|
2024-01-30 12:28:21 +00:00
|
|
|
|
std/[tables, sequtils, sets, options, strutils],
|
2023-01-23 20:24:46 +00:00
|
|
|
|
chronos,
|
2023-03-09 18:05:50 +00:00
|
|
|
|
eth/p2p/discoveryv5/enr,
|
2021-06-09 14:37:08 +00:00
|
|
|
|
libp2p/builders,
|
2021-03-26 08:49:51 +00:00
|
|
|
|
libp2p/peerstore
|
|
|
|
|
|
2022-11-24 13:11:23 +00:00
|
|
|
|
import
|
2023-04-24 14:37:54 +00:00
|
|
|
|
../../waku_core,
|
2024-01-30 12:28:21 +00:00
|
|
|
|
../../waku_enr/sharding,
|
|
|
|
|
../../waku_enr/capabilities,
|
2023-08-09 17:11:50 +00:00
|
|
|
|
../../common/utils/sequence
|
2022-11-24 13:11:23 +00:00
|
|
|
|
|
2021-06-09 14:37:08 +00:00
|
|
|
|
export peerstore, builders
|
2021-03-26 08:49:51 +00:00
|
|
|
|
|
|
|
|
|
type
|
2024-09-27 12:46:46 +00:00
|
|
|
|
WakuPeerStore* = ref object
|
|
|
|
|
peerStore: PeerStore
|
2022-11-29 16:35:25 +00:00
|
|
|
|
|
2022-11-24 13:11:23 +00:00
|
|
|
|
# Keeps track of the Connectedness state of a peer
|
2022-06-01 09:49:41 +00:00
|
|
|
|
ConnectionBook* = ref object of PeerBook[Connectedness]
|
2021-03-26 08:49:51 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
# Keeps track of the timestamp of the last failed connection attempt
|
2023-01-23 20:24:46 +00:00
|
|
|
|
LastFailedConnBook* = ref object of PeerBook[Moment]
|
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
# Keeps track of the number of failed connection attempts
|
2023-01-23 20:24:46 +00:00
|
|
|
|
NumberFailedConnBook* = ref object of PeerBook[int]
|
|
|
|
|
|
2022-11-24 13:11:23 +00:00
|
|
|
|
# Keeps track of when peers were disconnected in Unix timestamps
|
|
|
|
|
DisconnectBook* = ref object of PeerBook[int64]
|
|
|
|
|
|
|
|
|
|
# Keeps track of the origin of a peer
|
|
|
|
|
SourceBook* = ref object of PeerBook[PeerOrigin]
|
2021-04-21 09:36:56 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
# Keeps track of the direction of a peer connection
|
2023-01-23 20:24:46 +00:00
|
|
|
|
DirectionBook* = ref object of PeerBook[PeerDirection]
|
2022-11-29 16:35:25 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
# Keeps track of the ENR (Ethereum Node Record) of a peer
|
2023-03-09 18:05:50 +00:00
|
|
|
|
ENRBook* = ref object of PeerBook[enr.Record]
|
2021-03-26 08:49:51 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
# Constructor
|
|
|
|
|
proc new*(T: type WakuPeerStore, identify: Identify, capacity = 1000): WakuPeerStore =
|
|
|
|
|
let peerStore = PeerStore.new(identify, capacity)
|
|
|
|
|
WakuPeerStore(peerStore: peerStore)
|
2021-06-15 08:55:47 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc createWakuPeerStore*(peerStore: PeerStore): WakuPeerStore =
|
|
|
|
|
WakuPeerStore(peerStore: peerStore)
|
|
|
|
|
|
|
|
|
|
# Core functionality
|
|
|
|
|
proc `[]`*(wps: WakuPeerStore, T: typedesc): T =
|
|
|
|
|
wps.peerStore[T]
|
2023-01-23 20:24:46 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc getPeer*(wps: WakuPeerStore, peerId: PeerId): RemotePeerInfo =
|
2023-03-09 18:05:50 +00:00
|
|
|
|
RemotePeerInfo(
|
2021-06-15 08:55:47 +00:00
|
|
|
|
peerId: peerId,
|
2024-09-27 12:46:46 +00:00
|
|
|
|
addrs: wps[AddressBook][peerId],
|
2024-03-15 23:08:47 +00:00
|
|
|
|
enr:
|
2024-09-27 12:46:46 +00:00
|
|
|
|
if wps[ENRBook][peerId] != default(enr.Record):
|
|
|
|
|
some(wps[ENRBook][peerId])
|
2024-03-15 23:08:47 +00:00
|
|
|
|
else:
|
2024-09-11 01:51:42 +00:00
|
|
|
|
none(enr.Record),
|
2024-09-27 12:46:46 +00:00
|
|
|
|
protocols: wps[ProtoBook][peerId],
|
|
|
|
|
agent: wps[AgentBook][peerId],
|
|
|
|
|
protoVersion: wps[ProtoVersionBook][peerId],
|
|
|
|
|
publicKey: wps[KeyBook][peerId],
|
|
|
|
|
connectedness: wps[ConnectionBook][peerId],
|
|
|
|
|
disconnectTime: wps[DisconnectBook][peerId],
|
|
|
|
|
origin: wps[SourceBook][peerId],
|
|
|
|
|
direction: wps[DirectionBook][peerId],
|
|
|
|
|
lastFailedConn: wps[LastFailedConnBook][peerId],
|
|
|
|
|
numberFailedConn: wps[NumberFailedConnBook][peerId],
|
2021-06-15 08:55:47 +00:00
|
|
|
|
)
|
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc addPeer*(wps: WakuPeerStore, peer: RemotePeerInfo) =
|
|
|
|
|
wps[AddressBook][peer.peerId] = peer.addrs
|
|
|
|
|
wps[ProtoBook][peer.peerId] = peer.protocols
|
|
|
|
|
wps[AgentBook][peer.peerId] = peer.agent
|
|
|
|
|
wps[ProtoVersionBook][peer.peerId] = peer.protoVersion
|
|
|
|
|
wps[KeyBook][peer.peerId] = peer.publicKey
|
|
|
|
|
wps[ConnectionBook][peer.peerId] = peer.connectedness
|
|
|
|
|
wps[DisconnectBook][peer.peerId] = peer.disconnectTime
|
|
|
|
|
wps[SourceBook][peer.peerId] = peer.origin
|
|
|
|
|
wps[DirectionBook][peer.peerId] = peer.direction
|
|
|
|
|
wps[LastFailedConnBook][peer.peerId] = peer.lastFailedConn
|
|
|
|
|
wps[NumberFailedConnBook][peer.peerId] = peer.numberFailedConn
|
|
|
|
|
if peer.enr.isSome():
|
|
|
|
|
wps[ENRBook][peer.peerId] = peer.enr.get()
|
|
|
|
|
|
|
|
|
|
proc delete*(wps: WakuPeerStore, peerId: PeerId) =
|
|
|
|
|
# Delete all the information of a given peer.
|
|
|
|
|
wps.peerStore.del(peerId)
|
2023-04-12 11:05:34 +00:00
|
|
|
|
|
2022-11-29 16:35:25 +00:00
|
|
|
|
# TODO: Rename peers() to getPeersByProtocol()
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc peers*(wps: WakuPeerStore): seq[RemotePeerInfo] =
|
2024-03-15 23:08:47 +00:00
|
|
|
|
let allKeys = concat(
|
2024-09-27 12:46:46 +00:00
|
|
|
|
toSeq(wps[AddressBook].book.keys()),
|
|
|
|
|
toSeq(wps[ProtoBook].book.keys()),
|
|
|
|
|
toSeq(wps[KeyBook].book.keys()),
|
2024-03-15 23:08:47 +00:00
|
|
|
|
)
|
|
|
|
|
.toHashSet()
|
2021-06-15 08:55:47 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
return allKeys.mapIt(wps.getPeer(it))
|
|
|
|
|
|
|
|
|
|
proc peers*(wps: WakuPeerStore, proto: string): seq[RemotePeerInfo] =
|
|
|
|
|
wps.peers().filterIt(it.protocols.contains(proto))
|
2022-11-24 13:11:23 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc peers*(wps: WakuPeerStore, protocolMatcher: Matcher): seq[RemotePeerInfo] =
|
|
|
|
|
wps.peers().filterIt(it.protocols.anyIt(protocolMatcher(it)))
|
2022-11-24 13:11:23 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc connectedness*(wps: WakuPeerStore, peerId: PeerId): Connectedness =
|
|
|
|
|
wps[ConnectionBook].book.getOrDefault(peerId, NotConnected)
|
2022-11-24 13:11:23 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc hasShard*(wps: WakuPeerStore, peerId: PeerID, cluster, shard: uint16): bool =
|
|
|
|
|
wps[ENRBook].book.getOrDefault(peerId).containsShard(cluster, shard)
|
2024-01-30 12:28:21 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc hasCapability*(wps: WakuPeerStore, peerId: PeerID, cap: Capabilities): bool =
|
|
|
|
|
wps[ENRBook].book.getOrDefault(peerId).supportsCapability(cap)
|
2024-01-30 12:28:21 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc peerExists*(wps: WakuPeerStore, peerId: PeerId): bool =
|
|
|
|
|
wps[AddressBook].contains(peerId)
|
2022-11-24 13:11:23 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc isConnected*(wps: WakuPeerStore, peerId: PeerID): bool =
|
2023-01-26 09:20:20 +00:00
|
|
|
|
# Returns `true` if the peer is connected
|
2024-09-27 12:46:46 +00:00
|
|
|
|
wps.connectedness(peerId) == Connected
|
2023-01-26 09:20:20 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc hasPeer*(wps: WakuPeerStore, peerId: PeerID, proto: string): bool =
|
2022-11-24 13:11:23 +00:00
|
|
|
|
# Returns `true` if peer is included in manager for the specified protocol
|
2024-09-27 12:46:46 +00:00
|
|
|
|
# TODO: What if peer does not exist in the wps?
|
|
|
|
|
wps.getPeer(peerId).protocols.contains(proto)
|
2022-11-24 13:11:23 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc hasPeers*(wps: WakuPeerStore, proto: string): bool =
|
2022-11-24 13:11:23 +00:00
|
|
|
|
# Returns `true` if the peerstore has any peer for the specified protocol
|
2024-09-27 12:46:46 +00:00
|
|
|
|
toSeq(wps[ProtoBook].book.values()).anyIt(it.anyIt(it == proto))
|
2022-11-24 13:11:23 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc hasPeers*(wps: WakuPeerStore, protocolMatcher: Matcher): bool =
|
2022-11-24 13:11:23 +00:00
|
|
|
|
# Returns `true` if the peerstore has any peer matching the protocolMatcher
|
2024-09-27 12:46:46 +00:00
|
|
|
|
toSeq(wps[ProtoBook].book.values()).anyIt(it.anyIt(protocolMatcher(it)))
|
|
|
|
|
|
|
|
|
|
proc getCapacity*(wps: WakuPeerStore): int =
|
|
|
|
|
wps.peerStore.capacity
|
|
|
|
|
|
|
|
|
|
proc setCapacity*(wps: WakuPeerStore, capacity: int) =
|
|
|
|
|
wps.peerStore.capacity = capacity
|
|
|
|
|
|
|
|
|
|
proc getWakuProtos*(wps: WakuPeerStore): seq[string] =
|
|
|
|
|
toSeq(wps[ProtoBook].book.values()).flatten().deduplicate().filterIt(
|
|
|
|
|
it.startsWith("/vac/waku")
|
|
|
|
|
)
|
2022-11-24 13:11:23 +00:00
|
|
|
|
|
2024-03-15 23:08:47 +00:00
|
|
|
|
proc getPeersByDirection*(
|
2024-09-27 12:46:46 +00:00
|
|
|
|
wps: WakuPeerStore, direction: PeerDirection
|
2024-03-15 23:08:47 +00:00
|
|
|
|
): seq[RemotePeerInfo] =
|
2024-09-27 12:46:46 +00:00
|
|
|
|
return wps.peers.filterIt(it.direction == direction)
|
2023-01-18 14:17:56 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc getDisconnectedPeers*(wps: WakuPeerStore): seq[RemotePeerInfo] =
|
|
|
|
|
return wps.peers.filterIt(it.connectedness != Connected)
|
2023-01-26 09:20:20 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc getConnectedPeers*(wps: WakuPeerStore): seq[RemotePeerInfo] =
|
|
|
|
|
return wps.peers.filterIt(it.connectedness == Connected)
|
2023-02-09 15:59:29 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc getPeersByProtocol*(wps: WakuPeerStore, proto: string): seq[RemotePeerInfo] =
|
|
|
|
|
return wps.peers.filterIt(it.protocols.contains(proto))
|
2023-04-19 14:12:00 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc getReachablePeers*(wps: WakuPeerStore): seq[RemotePeerInfo] =
|
|
|
|
|
return
|
|
|
|
|
wps.peers.filterIt(it.connectedness == CanConnect or it.connectedness == Connected)
|
2024-01-30 12:28:21 +00:00
|
|
|
|
|
2024-09-27 12:46:46 +00:00
|
|
|
|
proc getPeersByShard*(wps: WakuPeerStore, cluster, shard: uint16): seq[RemotePeerInfo] =
|
2024-03-15 23:08:47 +00:00
|
|
|
|
return
|
2024-09-27 12:46:46 +00:00
|
|
|
|
wps.peers.filterIt(it.enr.isSome() and it.enr.get().containsShard(cluster, shard))
|
|
|
|
|
|
|
|
|
|
proc getPeersByCapability*(wps: WakuPeerStore, cap: Capabilities): seq[RemotePeerInfo] =
|
|
|
|
|
return wps.peers.filterIt(it.enr.isSome() and it.enr.get().supportsCapability(cap))
|