2019-09-05 11:06:44 +02:00
|
|
|
"""
|
|
|
|
src/network/invthread.py
|
|
|
|
========================
|
|
|
|
"""
|
2017-05-29 00:24:07 +02:00
|
|
|
import Queue
|
2019-08-01 13:37:26 +02:00
|
|
|
import random
|
2017-09-25 08:49:21 +02:00
|
|
|
from time import time
|
2017-05-29 00:24:07 +02:00
|
|
|
|
|
|
|
import addresses
|
2019-08-01 13:37:26 +02:00
|
|
|
import protocol
|
|
|
|
import state
|
2017-05-29 00:24:07 +02:00
|
|
|
from helper_threading import StoppableThread
|
|
|
|
from network.connectionpool import BMConnectionPool
|
2017-10-20 01:21:49 +02:00
|
|
|
from network.dandelion import Dandelion
|
2017-05-29 00:24:07 +02:00
|
|
|
from queues import invQueue
|
|
|
|
|
2019-07-11 10:51:10 +02:00
|
|
|
|
|
|
|
def handleExpiredDandelion(expired):
|
|
|
|
"""For expired dandelion objects, mark all remotes as not having
|
|
|
|
the object"""
|
|
|
|
if not expired:
|
|
|
|
return
|
|
|
|
for i in \
|
|
|
|
BMConnectionPool().inboundConnections.values() + \
|
|
|
|
BMConnectionPool().outboundConnections.values():
|
|
|
|
if not i.fullyEstablished:
|
|
|
|
continue
|
|
|
|
for x in expired:
|
|
|
|
streamNumber, hashid, _ = x
|
|
|
|
try:
|
|
|
|
del i.objectsNewToMe[hashid]
|
|
|
|
except KeyError:
|
|
|
|
if streamNumber in i.streams:
|
|
|
|
with i.objectsNewToThemLock:
|
|
|
|
i.objectsNewToThem[hashid] = time()
|
|
|
|
|
|
|
|
|
2019-08-01 13:37:26 +02:00
|
|
|
class InvThread(StoppableThread):
|
2019-09-06 15:34:52 +02:00
|
|
|
"""A thread to send inv annoucements."""
|
2019-09-05 11:06:44 +02:00
|
|
|
|
2019-08-01 13:37:26 +02:00
|
|
|
name = "InvBroadcaster"
|
2017-05-29 00:24:07 +02:00
|
|
|
|
2019-09-05 11:06:44 +02:00
|
|
|
@staticmethod
|
|
|
|
def handleLocallyGenerated(stream, hashId):
|
|
|
|
"""Locally generated inventory items require special handling"""
|
2018-02-03 11:46:39 +01:00
|
|
|
Dandelion().addHash(hashId, stream=stream)
|
2019-07-11 10:51:10 +02:00
|
|
|
for connection in \
|
2019-09-04 16:24:27 +02:00
|
|
|
BMConnectionPool().inboundConnections.values() + \
|
2019-07-11 10:51:10 +02:00
|
|
|
BMConnectionPool().outboundConnections.values():
|
2019-09-04 16:24:27 +02:00
|
|
|
if state.dandelion and connection != Dandelion().objectChildStem(hashId):
|
|
|
|
continue
|
|
|
|
connection.objectsNewToThem[hashId] = time()
|
2018-02-03 11:46:39 +01:00
|
|
|
|
2019-09-05 11:06:44 +02:00
|
|
|
def run(self): # pylint: disable=too-many-branches
|
|
|
|
while not state.shutdown: # pylint: disable=too-many-nested-blocks
|
2017-06-27 13:25:12 +02:00
|
|
|
chunk = []
|
2017-05-29 00:24:07 +02:00
|
|
|
while True:
|
2018-02-03 11:46:39 +01:00
|
|
|
# Dandelion fluff trigger by expiration
|
2019-07-11 10:51:10 +02:00
|
|
|
handleExpiredDandelion(Dandelion().expire())
|
2017-05-29 00:24:07 +02:00
|
|
|
try:
|
2017-05-29 14:52:31 +02:00
|
|
|
data = invQueue.get(False)
|
2017-10-19 08:56:48 +02:00
|
|
|
chunk.append((data[0], data[1]))
|
2017-09-25 08:49:21 +02:00
|
|
|
# locally generated
|
2018-02-03 11:46:39 +01:00
|
|
|
if len(data) == 2 or data[2] is None:
|
|
|
|
self.handleLocallyGenerated(data[0], data[1])
|
2017-05-29 00:24:07 +02:00
|
|
|
except Queue.Empty:
|
|
|
|
break
|
|
|
|
|
2017-06-27 13:25:12 +02:00
|
|
|
if chunk:
|
|
|
|
for connection in BMConnectionPool().inboundConnections.values() + \
|
|
|
|
BMConnectionPool().outboundConnections.values():
|
2017-09-25 08:49:21 +02:00
|
|
|
fluffs = []
|
|
|
|
stems = []
|
2017-06-27 13:25:12 +02:00
|
|
|
for inv in chunk:
|
|
|
|
if inv[0] not in connection.streams:
|
|
|
|
continue
|
2017-05-29 00:24:07 +02:00
|
|
|
try:
|
2017-06-27 13:25:12 +02:00
|
|
|
with connection.objectsNewToThemLock:
|
|
|
|
del connection.objectsNewToThem[inv[1]]
|
2017-05-29 00:24:07 +02:00
|
|
|
except KeyError:
|
|
|
|
continue
|
2017-10-20 01:21:49 +02:00
|
|
|
try:
|
2018-02-03 11:46:39 +01:00
|
|
|
if connection == Dandelion().objectChildStem(inv[1]):
|
2017-09-30 13:42:04 +02:00
|
|
|
# Fluff trigger by RNG
|
|
|
|
# auto-ignore if config set to 0, i.e. dandelion is off
|
2019-08-01 13:37:26 +02:00
|
|
|
if random.randint(1, 100) >= state.dandelion:
|
2018-02-03 11:46:39 +01:00
|
|
|
fluffs.append(inv[1])
|
|
|
|
# send a dinv only if the stem node supports dandelion
|
|
|
|
elif connection.services & protocol.NODE_DANDELION > 0:
|
2017-09-30 13:42:04 +02:00
|
|
|
stems.append(inv[1])
|
|
|
|
else:
|
|
|
|
fluffs.append(inv[1])
|
2017-10-20 01:21:49 +02:00
|
|
|
except KeyError:
|
2017-09-30 13:42:04 +02:00
|
|
|
fluffs.append(inv[1])
|
2017-10-20 01:21:49 +02:00
|
|
|
|
2017-09-25 08:49:21 +02:00
|
|
|
if fluffs:
|
2019-08-01 13:37:26 +02:00
|
|
|
random.shuffle(fluffs)
|
|
|
|
connection.append_write_buf(protocol.CreatePacket(
|
|
|
|
'inv', addresses.encodeVarint(len(fluffs)) +
|
|
|
|
"".join(fluffs)))
|
2017-09-25 08:49:21 +02:00
|
|
|
if stems:
|
2019-08-01 13:37:26 +02:00
|
|
|
random.shuffle(stems)
|
|
|
|
connection.append_write_buf(protocol.CreatePacket(
|
|
|
|
'dinv', addresses.encodeVarint(len(stems)) +
|
|
|
|
"".join(stems)))
|
2017-10-20 01:21:49 +02:00
|
|
|
|
2017-06-27 13:25:12 +02:00
|
|
|
invQueue.iterate()
|
2017-10-19 08:56:48 +02:00
|
|
|
for i in range(len(chunk)):
|
|
|
|
invQueue.task_done()
|
2017-10-20 01:21:49 +02:00
|
|
|
|
|
|
|
if Dandelion().refresh < time():
|
2018-02-03 11:46:39 +01:00
|
|
|
Dandelion().reRandomiseStems()
|
2017-10-20 01:21:49 +02:00
|
|
|
|
2017-05-29 00:24:07 +02:00
|
|
|
self.stop.wait(1)
|