# Path: electrumx/lib/util.py
# class cachedproperty(object):
# 
#     def __init__(self, f):
#         self.f = f
# 
#     def __get__(self, obj, type_):
#         obj = obj or type_
#         value = self.f(obj)
#         setattr(obj, self.f.__name__, value)
#         return value
# 
# def protocol_tuple(s):
#     '''Converts a protocol version number, such as "1.0" to a tuple (1, 0).
# 
#     If the version number is bad, (0, ) indicating version 0 is returned.'''
#     try:
#         return tuple(int(part) for part in s.split('.'))
#     except (TypeError, ValueError, AttributeError):
#         return (0, )
# 
# def version_string(ptuple):
#     '''Convert a version tuple such as (1, 2) to "1.2".
#     There is always at least one dot, so (1, ) becomes "1.0".'''
#     while len(ptuple) < 2:
#         ptuple += (0, )
#     return '.'.join(str(p) for p in ptuple)


from ipaddress import ip_address, IPv4Address, IPv6Address, IPv4Network, IPv6Network
from socket import AF_INET, AF_INET6
from aiorpcx import is_valid_hostname
from electrumx.lib.util import cachedproperty, protocol_tuple, version_string
        self.host = host
        self.features = features.copy()
        # Canonicalize / clean-up
        for feature in self.FEATURES:
            self.features[feature] = getattr(self, feature)
        # Metadata
        self.source = source
        self.ip_addr = ip_addr
        # last_good represents the last connection that was
        # successful *and* successfully verified, at which point
        # try_count is set to 0.  Failure to connect or failure to
        # verify increment the try_count.
        self.last_good = last_good
        self.last_try = last_try
        self.try_count = try_count
        # Transient, non-persisted metadata
        self.bad = False
        self.other_port_pairs = set()

    @classmethod
    def peers_from_features(cls, features, source):
        peers = []
        if isinstance(features, dict):
            hosts = features.get('hosts')
            if isinstance(hosts, dict):
                peers = [Peer(host, features, source=source)
                         for host in hosts if isinstance(host, str)]
        return peers

    @classmethod

# Path: electrumx/lib/util.py
# class cachedproperty(object):
# 
#     def __init__(self, f):
#         self.f = f
# 
#     def __get__(self, obj, type_):
#         obj = obj or type_
#         value = self.f(obj)
#         setattr(obj, self.f.__name__, value)
#         return value
# 
# def protocol_tuple(s):
#     '''Converts a protocol version number, such as "1.0" to a tuple (1, 0).
# 
#     If the version number is bad, (0, ) indicating version 0 is returned.'''
#     try:
#         return tuple(int(part) for part in s.split('.'))
#     except (TypeError, ValueError, AttributeError):
#         return (0, )
# 
# def version_string(ptuple):
#     '''Convert a version tuple such as (1, 2) to "1.2".
#     There is always at least one dot, so (1, ) becomes "1.0".'''
#     while len(ptuple) < 2:
#         ptuple += (0, )
#     return '.'.join(str(p) for p in ptuple)


# Path: electrumx/lib/peer.py
from ipaddress import ip_address, IPv4Address, IPv6Address, IPv4Network, IPv6Network
from socket import AF_INET, AF_INET6
from aiorpcx import is_valid_hostname
from electrumx.lib.util import cachedproperty, protocol_tuple, version_string

        self.host = host
        self.features = features.copy()
        # Canonicalize / clean-up
        for feature in self.FEATURES:
            self.features[feature] = getattr(self, feature)
        # Metadata
        self.source = source
        self.ip_addr = ip_addr
        # last_good represents the last connection that was
        # successful *and* successfully verified, at which point
        # try_count is set to 0.  Failure to connect or failure to
        # verify increment the try_count.
        self.last_good = last_good
        self.last_try = last_try
        self.try_count = try_count
        # Transient, non-persisted metadata
        self.bad = False
        self.other_port_pairs = set()

    @classmethod
    def peers_from_features(cls, features, source):
        peers = []
        if isinstance(features, dict):
            hosts = features.get('hosts')
            if isinstance(hosts, dict):
                peers = [Peer(host, features, source=source)
                         for host in hosts if isinstance(host, str)]
        return peers

    @classmethod

    def deserialize(cls, item):