diff --git a/nucypher/network/nodes.py b/nucypher/network/nodes.py
index 58f17b4cb..b733ffef4 100644
--- a/nucypher/network/nodes.py
+++ b/nucypher/network/nodes.py
@@ -14,17 +14,18 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with nucypher. If not, see .
"""
+import binascii
import os
import random
-from collections import defaultdict
+from collections import defaultdict, OrderedDict
from collections import deque
+from collections import namedtuple
from contextlib import suppress
from logging import Logger
from tempfile import TemporaryDirectory
from typing import Set, Tuple
import OpenSSL
-import binascii
import maya
import requests
import time
@@ -51,7 +52,31 @@ from nucypher.network.protocols import SuspiciousActivity
from nucypher.network.server import TLSHostingPower
-class FleetState:
+def icon_from_checksum(checksum,
+ nickname_metadata,
+ number_of_nodes="Unknown number of "):
+
+ if checksum is constants.NO_KNOWN_NODES:
+ return "NO FLEET STATE AVAILABLE"
+ icon_template = """
+
+
{number_of_nodes} nodes
+
+ {symbol}︎
+
+
+
{fleet_state_checksum}
+
+ """.replace(" ", "").replace('\n', "")
+ return icon_template.format(
+ number_of_nodes=number_of_nodes,
+ color=nickname_metadata[0][0]['hex'],
+ symbol=nickname_metadata[0][1],
+ fleet_state_checksum=checksum[0:8]
+ )
+
+
+class FleetStateTracker:
"""
A representation of a fleet of NuCypher nodes.
"""
@@ -62,18 +87,15 @@ class FleetState:
most_recent_node_change = constants.NO_KNOWN_NODES
snapshot_splitter = BytestringSplitter(32, 4)
log = Logger("Learning")
+ state_template = namedtuple("FleetState", ("nickname", "icon", "nodes", "updated"))
- def __init__(self, do_not_track):
- self.dnt = do_not_track
+ def __init__(self):
self.additional_nodes_to_track = []
self.updated = maya.now()
self._nodes = {}
- self.states = {}
+ self.states = OrderedDict()
def __setitem__(self, key, value):
- if value == self.dnt:
- print(value)
-
self._nodes[key] = value
if self._tracking:
@@ -121,24 +143,9 @@ class FleetState:
return self._nodes.keys()
def icon(self):
- if self.checksum is constants.NO_KNOWN_NODES:
- return "NO FLEET STATE AVAILABLE"
- icon_template = """
-
-
{number_of_nodes} nodes
-
- {symbol}︎
-
-
-
{fleet_state_checksum}
-
- """.replace(" ", "").replace('\n', "")
- return icon_template.format(
- number_of_nodes=len(self),
- color=self.nickname_metadata[0][0]['hex'],
- symbol=self.nickname_metadata[0][1],
- fleet_state_checksum=self.checksum[0:8]
- )
+ return icon_from_checksum(checksum=self.checksum,
+ number_of_nodes=len(self),
+ nickname_metadata=self.nickname_metadata)
def snapshot(self):
fleet_state_checksum_bytes = binascii.unhexlify(self.checksum)
@@ -146,8 +153,17 @@ class FleetState:
return fleet_state_checksum_bytes + fleet_state_updated_bytes
def update_fleet_state(self):
- self.checksum = keccak_digest(b"".join(bytes(n) for n in self.sorted())).hex()
- self.updated = maya.now()
+ checksum = keccak_digest(b"".join(bytes(n) for n in self.sorted())).hex()
+ if checksum != self.checksum:
+ self.checksum = keccak_digest(b"".join(bytes(n) for n in self.sorted())).hex()
+ self.updated = maya.now()
+ # For now we store the sorted node list. Someday we probably spin this out into
+ # its own class, FleetState, and use it as the basis for partial updates.
+ self.states[checksum] = self.state_template(nickname=self.nickname,
+ icon=self.icon(),
+ nodes=self.sorted(),
+ updated=self.updated,
+ )
def start_tracking_state(self, additional_nodes_to_track=[]):
self.additional_nodes_to_track.extend(additional_nodes_to_track)
@@ -210,7 +226,7 @@ class Learner:
self._node_ids_to_learn_about_immediately = set()
self.known_certificates_dir = known_certificates_dir or TemporaryDirectory("nucypher-tmp-certs-").name
- self.__known_nodes = FleetState(self)
+ self.__known_nodes = FleetStateTracker()
self.done_seeding = False