Node class, WIP

- for new network subsystem
This commit is contained in:
Peter Šurda 2017-05-07 20:16:49 +02:00
parent 23b9555929
commit d9d3515905
Signed by untrusted user: PeterSurda
GPG Key ID: 0C5F50C0B5F37D87

View File

@ -1,66 +1,66 @@
import socket import time
import protocol
from inventory import PendingDownloadQueue
try:
# pybloomfiltermmap
from pybloomfilter import BloomFilter
except ImportError:
try:
# pybloom
from pybloom import BloomFilter
except ImportError:
# bundled pybloom
from fallback.pybloom import BloomFilter
class Node(object): class Node(object):
TYPE_IPV4 = 1 invCleanPeriod = 300
TYPE_IPV6 = 2 invInitialCapacity = 50000
TYPE_ONION = 3 invErrorRate = 0.03
TYPE_LOCAL = 4
TYPE_LOOPBACK = 8
TYPE_UNDEF = 12
def __init__(self, services, address, port): def __init__(self):
self.services = services self.initInvBloom()
self.address, self.addressType = Node.decodeIPAddress(address) self.initAddrBloom()
self.port = port
def isLocal(self): def initInvBloom(self):
return self.addressType | Node.TYPE_LOCAL > 0 # lock?
self.invBloom = BloomFilter(capacity=Node.invInitialCapacity,
error_rate=Node.invErrorRate)
def isGlobal(self): def initAddrBloom(self):
return self.addressType <= Node.TYPE_ONION # lock?
self.addrBloom = BloomFilter(capacity=Node.invInitialCapacity,
error_rate=Node.invErrorRate)
def isOnion(self): def cleanBloom(self):
return self.addressType | Node.TYPE_ONION > 0 if self.lastcleaned < time.time() - Node.invCleanPeriod:
if PendingDownloadQueue().size() == 0:
self.initInvBloom()
self.initAddrBloom()
def isLoopback(self): def hasInv(self, hashid):
return self.addressType | Node.TYPE_LOOPBACK > 0 return hashid in self.invBloom
@staticmethod def addInv(self, hashid):
def decodeIPAddress(host): self.invBloom.add(hashid)
if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF':
hostStandardFormat = socket.inet_ntop(socket.AF_INET, host[12:])
return Node.decodeIPv4Address(host[12:], hostStandardFormat)
elif host[0:6] == '\xfd\x87\xd8\x7e\xeb\x43':
# Onion, based on BMD/bitcoind
hostStandardFormat = base64.b32encode(host[6:]).lower() + ".onion"
return hostStandardFormat, Node.TYPE_ONION
else:
hostStandardFormat = socket.inet_ntop(socket.AF_INET6, host)
if hostStandardFormat == "":
# This can happen on Windows systems which are not 64-bit compatible
# so let us drop the IPv6 address.
return hostStandardFormat, Node.TYPE_IPV6|Node.TYPE_UNDEF
return Node.decodeIPv6Address(host, hostStandardFormat)
@staticmethod def hasAddr(self, hashid):
def decodeIPv4Address(host, hostStandardFormat): return hashid in self.invBloom
if host[0] == '\x7F': # 127/8
return hostStandardFormat, Node.TYPE_IPV4|Node.TYPE_LOOPBACK def addInv(self, hashid):
if host[0] == '\x0A': # 10/8 self.invBloom.add(hashid)
return hostStandardFormat, Node.TYPE_IPV4|Node.TYPE_LOCAL
if host[0:2] == '\xC0\xA8': # 192.168/16 # addr sending -> per node upload queue, and flush every minute or so
return hostStandardFormat, Node.TYPE_IPV4|Node.TYPE_LOCAL # inv sending -> if not in bloom, inv immediately, otherwise put into a per node upload queue and flush every minute or so
if host[0:2] >= '\xAC\x10' and host[0:2] < '\xAC\x20': # 172.16/12
return hostStandardFormat, Node.TYPE_IPV4|Node.TYPE_LOCAL # no bloom
return hostStandardFormat, Node.TYPE_IPV4 # - if inv arrives
# - if we don't have it, add tracking and download queue
# - if we do have it, remove from tracking
# tracking downloads
# - per node hash of items the node has but we don't
# tracking inv
# - per node hash of items that neither the remote node nor we have
#
@staticmethod
def _checkIPv6Address(host, hostStandardFormat):
if host == ('\x00' * 15) + '\x01':
return hostStandardFormat, Node.TYPE_IPV6|Node.TYPE_LOOPBACK
if host[0] == '\xFE' and (ord(host[1]) & 0xc0) == 0x80:
return hostStandardFormat, Node.TYPE_IPV6|Node.TYPE_LOCAL
if (ord(host[0]) & 0xfe) == 0xfc:
return hostStandardFormat, Node.TYPE_IPV6|Node.TYPE_UNDEF
return hostStandardFormat, Node.TYPE_IPV6