This repository has been archived on 2024-12-20. You can view files and clone it, but cannot push or open issues or pull requests.
PyBitmessage-2024-12-20/src/network/invthread.py

112 lines
4.2 KiB
Python
Raw Normal View History

2019-09-05 11:06:44 +02:00
"""
2020-01-06 12:44:47 +01:00
Thread to send inv annoucements
2019-09-05 11:06:44 +02:00
"""
import queue as Queue
import random
from time import time
import addresses
import protocol
import state
from network.connectionpool import BMConnectionPool
from network.dandelion import Dandelion
from queues import invQueue
2019-12-23 12:18:37 +01:00
from network.threads import StoppableThread
def handleExpiredDandelion(expired):
"""For expired dandelion objects, mark all remotes as not having
the object"""
if not expired:
return
for i in BMConnectionPool().connections():
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()
class InvThread(StoppableThread):
2020-01-06 12:44:47 +01:00
"""Main thread that sends inv annoucements"""
2019-09-05 11:06:44 +02:00
name = "InvBroadcaster"
2019-09-05 11:06:44 +02:00
@staticmethod
def handleLocallyGenerated(stream, hashId):
"""Locally generated inventory items require special handling"""
Dandelion().addHash(hashId, stream=stream)
for connection in BMConnectionPool().connections():
2020-01-06 12:44:47 +01:00
if state.dandelion and connection != \
Dandelion().objectChildStem(hashId):
2019-09-04 16:24:27 +02:00
continue
connection.objectsNewToThem[hashId] = time()
2020-01-06 12:44:47 +01:00
def run(self): # pylint: disable=too-many-branches
while not state.shutdown: # pylint: disable=too-many-nested-blocks
chunk = []
while True:
# Dandelion fluff trigger by expiration
handleExpiredDandelion(Dandelion().expire())
try:
data = invQueue.get(False)
chunk.append((data[0], data[1]))
# locally generated
if len(data) == 2 or data[2] is None:
self.handleLocallyGenerated(data[0], data[1])
except Queue.Empty:
break
if chunk:
for connection in BMConnectionPool().connections():
fluffs = []
stems = []
for inv in chunk:
if inv[0] not in connection.streams:
continue
try:
with connection.objectsNewToThemLock:
del connection.objectsNewToThem[inv[1]]
except KeyError:
continue
try:
if connection == Dandelion().objectChildStem(inv[1]):
# Fluff trigger by RNG
# auto-ignore if config set to 0, i.e. dandelion is off
if random.randint(1, 100) >= state.dandelion:
fluffs.append(inv[1])
# send a dinv only if the stem node supports dandelion
elif connection.services & protocol.NODE_DANDELION > 0:
stems.append(inv[1])
else:
fluffs.append(inv[1])
except KeyError:
fluffs.append(inv[1])
if fluffs:
random.shuffle(fluffs)
connection.append_write_buf(protocol.CreatePacket(
'inv',
2020-01-06 12:44:47 +01:00
addresses.encodeVarint(
len(fluffs)) + ''.join(fluffs)))
if stems:
random.shuffle(stems)
connection.append_write_buf(protocol.CreatePacket(
'dinv',
2020-01-06 12:44:47 +01:00
addresses.encodeVarint(
len(stems)) + ''.join(stems)))
invQueue.iterate()
2020-01-06 12:44:47 +01:00
for _ in range(len(chunk)):
invQueue.task_done()
if Dandelion().refresh < time():
Dandelion().reRandomiseStems()
self.stop.wait(1)