chia-blockchain/chia/server/introducer_peers.py

77 lines
2.3 KiB
Python

import random
import time
from typing import Set, List, Optional
from dataclasses import dataclass
from chia.types.peer_info import PeerInfo
from chia.util.ints import uint64, uint16
@dataclass(frozen=False)
class VettedPeer:
host: str
port: uint16
# 0 means we have not attempted to vet this peer yet
# a negative number means we have failed that many vetting attempts in a row
# a positive number means we have successfully vetted the peer this many
# times in a row
vetted: int = 0
# the timestamp of the last *successful* vetting of this peer
vetted_timestamp: uint64 = uint64(0)
# the last time we attempted to vet this peer, or 0 if we haven't tried yet
# we set this regardless of whether the vetting is successful or not
last_attempt: uint64 = uint64(0)
time_added: uint64 = uint64(0)
def __init__(self, h: str, p: uint16):
self.host = h
self.port = p
def __eq__(self, rhs):
return self.host == rhs.host and self.port == rhs.port
def __hash__(self):
return hash((self.host, self.port))
class IntroducerPeers:
"""
Has the list of known full node peers that are already connected or may be
connected to, and the time that they were last added.
"""
def __init__(self) -> None:
self._peers: Set[VettedPeer] = set()
def add(self, peer: Optional[PeerInfo]) -> bool:
if peer is None or not peer.port:
return False
p = VettedPeer(peer.host, peer.port)
p.time_added = uint64(int(time.time()))
if p in self._peers:
return True
self._peers.add(p)
return True
def remove(self, peer: Optional[VettedPeer]) -> bool:
if peer is None or not peer.port:
return False
try:
self._peers.remove(peer)
return True
except ValueError:
return False
def get_peers(self, max_peers: int = 0, randomize: bool = False, recent_threshold=9999999) -> List[VettedPeer]:
target_peers = [peer for peer in self._peers if time.time() - peer.time_added < recent_threshold]
if not max_peers or max_peers > len(target_peers):
max_peers = len(target_peers)
if randomize:
return random.sample(target_peers, max_peers)
else:
return target_peers[:max_peers]