mirror of https://github.com/nucypher/nucypher.git
Handling 204 response during learning. Fixes #630.
parent
63d0b329a9
commit
bed79d4fac
|
@ -29,8 +29,8 @@ import requests
|
||||||
import time
|
import time
|
||||||
from bytestring_splitter import BytestringSplitter
|
from bytestring_splitter import BytestringSplitter
|
||||||
from bytestring_splitter import VariableLengthBytestring, BytestringSplittingError
|
from bytestring_splitter import VariableLengthBytestring, BytestringSplittingError
|
||||||
from constant_sorrow import constants, constant_or_bytes
|
from constant_sorrow import constant_or_bytes
|
||||||
from constant_sorrow.constants import GLOBAL_DOMAIN
|
from constant_sorrow.constants import GLOBAL_DOMAIN, NO_KNOWN_NODES, NOT_SIGNED, NEVER_SEEN, NO_STORAGE_AVAILIBLE, FLEET_STATES_MATCH
|
||||||
from cryptography.x509 import Certificate
|
from cryptography.x509 import Certificate
|
||||||
from eth_keys.datatypes import Signature as EthSignature
|
from eth_keys.datatypes import Signature as EthSignature
|
||||||
from requests.exceptions import SSLError
|
from requests.exceptions import SSLError
|
||||||
|
@ -63,7 +63,7 @@ GLOBAL_DOMAIN.set_constant_documentation(
|
||||||
def icon_from_checksum(checksum,
|
def icon_from_checksum(checksum,
|
||||||
nickname_metadata,
|
nickname_metadata,
|
||||||
number_of_nodes="Unknown number of "):
|
number_of_nodes="Unknown number of "):
|
||||||
if checksum is constants.NO_KNOWN_NODES:
|
if checksum is NO_KNOWN_NODES:
|
||||||
return "NO FLEET STATE AVAILABLE"
|
return "NO FLEET STATE AVAILABLE"
|
||||||
icon_template = """
|
icon_template = """
|
||||||
<div class="nucypher-nickname-icon" style="border-color:{color};">
|
<div class="nucypher-nickname-icon" style="border-color:{color};">
|
||||||
|
@ -87,11 +87,11 @@ class FleetStateTracker:
|
||||||
"""
|
"""
|
||||||
A representation of a fleet of NuCypher nodes.
|
A representation of a fleet of NuCypher nodes.
|
||||||
"""
|
"""
|
||||||
_checksum = constants.NO_KNOWN_NODES.bool_value(False)
|
_checksum = NO_KNOWN_NODES.bool_value(False)
|
||||||
_nickname = constants.NO_KNOWN_NODES
|
_nickname = NO_KNOWN_NODES
|
||||||
_nickname_metadata = constants.NO_KNOWN_NODES
|
_nickname_metadata = NO_KNOWN_NODES
|
||||||
_tracking = False
|
_tracking = False
|
||||||
most_recent_node_change = constants.NO_KNOWN_NODES
|
most_recent_node_change = NO_KNOWN_NODES
|
||||||
snapshot_splitter = BytestringSplitter(32, 4)
|
snapshot_splitter = BytestringSplitter(32, 4)
|
||||||
log = Logger("Learning")
|
log = Logger("Learning")
|
||||||
state_template = namedtuple("FleetState", ("nickname", "icon", "nodes", "updated"))
|
state_template = namedtuple("FleetState", ("nickname", "icon", "nodes", "updated"))
|
||||||
|
@ -151,8 +151,8 @@ class FleetStateTracker:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def icon(self) -> str:
|
def icon(self) -> str:
|
||||||
if self.nickname_metadata is constants.NO_KNOWN_NODES:
|
if self.nickname_metadata is NO_KNOWN_NODES:
|
||||||
return str(constants.NO_KNOWN_NODES)
|
return str(NO_KNOWN_NODES)
|
||||||
return self.nickname_metadata[0][1]
|
return self.nickname_metadata[0][1]
|
||||||
|
|
||||||
def addresses(self):
|
def addresses(self):
|
||||||
|
@ -272,7 +272,7 @@ class Learner:
|
||||||
character_class=self.__class__)
|
character_class=self.__class__)
|
||||||
|
|
||||||
self.node_storage = node_storage
|
self.node_storage = node_storage
|
||||||
if save_metadata and node_storage is constants.NO_STORAGE_AVAILIBLE:
|
if save_metadata and node_storage is NO_STORAGE_AVAILIBLE:
|
||||||
raise ValueError("Cannot save nodes without a configured node storage")
|
raise ValueError("Cannot save nodes without a configured node storage")
|
||||||
|
|
||||||
known_nodes = known_nodes or tuple()
|
known_nodes = known_nodes or tuple()
|
||||||
|
@ -651,7 +651,15 @@ class Learner:
|
||||||
finally:
|
finally:
|
||||||
self.cycle_teacher_node()
|
self.cycle_teacher_node()
|
||||||
|
|
||||||
if response.status_code not in (200, 204):
|
#
|
||||||
|
# Before we parse the response, let's handle some edge cases.
|
||||||
|
if response.status_code == 204:
|
||||||
|
# In this case, this node knows about no other nodes. Hopefully we've taught it something.
|
||||||
|
if response.content == b"":
|
||||||
|
return NO_KNOWN_NODES
|
||||||
|
# In the other case - where the status code is 204 but the repsonse isn't blank - we'll keep parsing. It's possible that our fleet states match, and we'll check for that later.
|
||||||
|
|
||||||
|
elif response.status_code != 200:
|
||||||
self.log.info("Bad response from teacher {}: {} - {}".format(current_teacher, response, response.content))
|
self.log.info("Bad response from teacher {}: {} - {}".format(current_teacher, response, response.content))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -666,6 +674,8 @@ class Learner:
|
||||||
except current_teacher.InvalidSignature:
|
except current_teacher.InvalidSignature:
|
||||||
# TODO: What to do if the teacher improperly signed the node payload?
|
# TODO: What to do if the teacher improperly signed the node payload?
|
||||||
raise
|
raise
|
||||||
|
# End edge case handling.
|
||||||
|
#
|
||||||
|
|
||||||
fleet_state_checksum_bytes, fleet_state_updated_bytes, node_payload = FleetStateTracker.snapshot_splitter(
|
fleet_state_checksum_bytes, fleet_state_updated_bytes, node_payload = FleetStateTracker.snapshot_splitter(
|
||||||
node_payload,
|
node_payload,
|
||||||
|
@ -679,7 +689,7 @@ class Learner:
|
||||||
# TODO: This doesn't make sense - a decentralized node can still learn about a federated-only node.
|
# TODO: This doesn't make sense - a decentralized node can still learn about a federated-only node.
|
||||||
from nucypher.characters.lawful import Ursula
|
from nucypher.characters.lawful import Ursula
|
||||||
if response.status_code == 204:
|
if response.status_code == 204:
|
||||||
return constants.FLEET_STATES_MATCH
|
return FLEET_STATES_MATCH
|
||||||
|
|
||||||
node_list = Ursula.batch_from_bytes(node_payload, federated_only=self.federated_only) # TODO: 466
|
node_list = Ursula.batch_from_bytes(node_payload, federated_only=self.federated_only) # TODO: 466
|
||||||
|
|
||||||
|
@ -741,9 +751,9 @@ class Teacher:
|
||||||
domains: Set,
|
domains: Set,
|
||||||
certificate: Certificate,
|
certificate: Certificate,
|
||||||
certificate_filepath: str,
|
certificate_filepath: str,
|
||||||
interface_signature=constants.NOT_SIGNED.bool_value(False),
|
interface_signature=NOT_SIGNED.bool_value(False),
|
||||||
timestamp=constants.NOT_SIGNED,
|
timestamp=NOT_SIGNED,
|
||||||
identity_evidence=constants.NOT_SIGNED,
|
identity_evidence=NOT_SIGNED,
|
||||||
substantiate_immediately=False,
|
substantiate_immediately=False,
|
||||||
passphrase=None,
|
passphrase=None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -753,7 +763,7 @@ class Teacher:
|
||||||
self.certificate_filepath = certificate_filepath
|
self.certificate_filepath = certificate_filepath
|
||||||
self._interface_signature_object = interface_signature
|
self._interface_signature_object = interface_signature
|
||||||
self._timestamp = timestamp
|
self._timestamp = timestamp
|
||||||
self.last_seen = constants.NEVER_SEEN("Haven't connected to this node yet.")
|
self.last_seen = NEVER_SEEN("Haven't connected to this node yet.")
|
||||||
self.fleet_state_checksum = None
|
self.fleet_state_checksum = None
|
||||||
self.fleet_state_updated = None
|
self.fleet_state_updated = None
|
||||||
self._evidence_of_decentralized_identity = constant_or_bytes(identity_evidence)
|
self._evidence_of_decentralized_identity = constant_or_bytes(identity_evidence)
|
||||||
|
@ -797,7 +807,7 @@ class Teacher:
|
||||||
|
|
||||||
def _stamp_has_valid_wallet_signature(self):
|
def _stamp_has_valid_wallet_signature(self):
|
||||||
signature_bytes = self._evidence_of_decentralized_identity
|
signature_bytes = self._evidence_of_decentralized_identity
|
||||||
if signature_bytes is constants.NOT_SIGNED:
|
if signature_bytes is NOT_SIGNED:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
signature = EthSignature(signature_bytes)
|
signature = EthSignature(signature_bytes)
|
||||||
|
@ -821,7 +831,7 @@ class Teacher:
|
||||||
|
|
||||||
def _stamp_has_valid_wallet_signature(self):
|
def _stamp_has_valid_wallet_signature(self):
|
||||||
signature_bytes = self._evidence_of_decentralized_identity
|
signature_bytes = self._evidence_of_decentralized_identity
|
||||||
if signature_bytes is constants.NOT_SIGNED:
|
if signature_bytes is NOT_SIGNED:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
signature = EthSignature(signature_bytes)
|
signature = EthSignature(signature_bytes)
|
||||||
|
@ -837,7 +847,7 @@ class Teacher:
|
||||||
if self._stamp_has_valid_wallet_signature():
|
if self._stamp_has_valid_wallet_signature():
|
||||||
self.verified_stamp = True
|
self.verified_stamp = True
|
||||||
return True
|
return True
|
||||||
elif self.federated_only and signature is constants.NOT_SIGNED:
|
elif self.federated_only and signature is NOT_SIGNED:
|
||||||
message = "This node can't be verified in this manner, " \
|
message = "This node can't be verified in this manner, " \
|
||||||
"but is OK to use in federated mode if you" \
|
"but is OK to use in federated mode if you" \
|
||||||
" have reason to believe it is trustworthy."
|
" have reason to believe it is trustworthy."
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from constant_sorrow.constants import FLEET_STATES_MATCH
|
from constant_sorrow.constants import FLEET_STATES_MATCH, NO_KNOWN_NODES
|
||||||
from hendrix.experience import crosstown_traffic
|
from hendrix.experience import crosstown_traffic
|
||||||
from hendrix.utils.test_utils import crosstownTaskListDecoratorFactory
|
from hendrix.utils.test_utils import crosstownTaskListDecoratorFactory
|
||||||
from nucypher.utilities.sandbox.ursula import make_federated_ursulas
|
from nucypher.utilities.sandbox.ursula import make_federated_ursulas
|
||||||
|
@ -17,7 +17,8 @@ def test_learning_from_node_with_no_known_nodes(ursula_federated_test_config):
|
||||||
crosstown_traffic.decorator = crosstownTaskListDecoratorFactory(learning_callers)
|
crosstown_traffic.decorator = crosstownTaskListDecoratorFactory(learning_callers)
|
||||||
|
|
||||||
result = lonely_learner.learn_from_teacher_node()
|
result = lonely_learner.learn_from_teacher_node()
|
||||||
assert False
|
assert result is NO_KNOWN_NODES
|
||||||
|
|
||||||
|
|
||||||
def test_all_nodes_have_same_fleet_state(federated_ursulas):
|
def test_all_nodes_have_same_fleet_state(federated_ursulas):
|
||||||
checksums = [u.known_nodes.checksum for u in federated_ursulas]
|
checksums = [u.known_nodes.checksum for u in federated_ursulas]
|
||||||
|
|
Loading…
Reference in New Issue