fully deprecates the node storage API

remotes/origin/v7.4.x
KPrasch 2024-01-12 12:48:24 +01:00 committed by Derek Pierre
parent c98e31c366
commit 1fcf3c84a8
19 changed files with 7 additions and 536 deletions

View File

@ -1 +1 @@
Peer TLS certificates a no longer stored on the node's disk.
Peer TLS certificates are no longer stored on the node's disk.

View File

@ -90,7 +90,6 @@ from nucypher.characters.banners import (
URSULA_BANNER,
)
from nucypher.characters.base import Character, Learner
from nucypher.config.storages import NodeStorage
from nucypher.crypto.keypairs import HostingKeypair
from nucypher.crypto.powers import (
DecryptingPower,
@ -1231,10 +1230,6 @@ class Ursula(Teacher, Character, Operator):
return potential_seed_node
@classmethod
def from_storage(cls, node_storage: NodeStorage, checksum_adress: str) -> "Ursula":
return node_storage.get(checksum_address=checksum_adress)
#
# Properties
#

View File

@ -371,18 +371,6 @@ def destroy(general_config, config_options, config_file, force):
destroy_configuration(emitter, character_config=ursula_config, force=force)
@ursula.command()
@group_config_options
@option_config_file
@group_general_config
def forget(general_config, config_options, config_file):
"""Forget all known nodes."""
emitter = setup_emitter(general_config, config_options.operator_address)
_pre_launch_warnings(emitter, dev=config_options.dev, force=None)
ursula_config = config_options.create_config(emitter, config_file)
forget_nodes(emitter, configuration=ursula_config)
@ursula.command()
@group_character_options
@option_config_file

View File

@ -25,7 +25,6 @@ from nucypher.blockchain.eth.registry import (
from nucypher.blockchain.eth.signers import Signer
from nucypher.characters.lawful import Ursula
from nucypher.config import constants
from nucypher.config.storages import NodeStorage
from nucypher.config.util import cast_paths_from
from nucypher.crypto.keystore import Keystore
from nucypher.crypto.powers import CryptoPower, CryptoPowerUp
@ -328,7 +327,7 @@ class CharacterConfiguration(BaseConfiguration):
'Sideways Engagement' of Character classes; a reflection of input parameters.
"""
VERSION = 8 # bump when static payload scheme changes
VERSION = 9 # bump when static payload scheme changes
CHARACTER_CLASS = NotImplemented
MNEMONIC_KEYSTORE = False
@ -384,7 +383,6 @@ class CharacterConfiguration(BaseConfiguration):
lonely: bool = False,
# Node Storage
known_nodes: Optional[set] = None,
node_storage: Optional[NodeStorage] = None,
reload_metadata: bool = True,
save_metadata: bool = True,
# Blockchain
@ -500,13 +498,11 @@ class CharacterConfiguration(BaseConfiguration):
if dev_mode:
self.__temp_dir = UNINITIALIZED_CONFIGURATION
self._setup_node_storage()
self.initialize(password=DEVELOPMENT_CONFIGURATION)
else:
self.__temp_dir = LIVE_CONFIGURATION
self.config_root = config_root or self.DEFAULT_CONFIG_ROOT
self._cache_runtime_filepaths()
self._setup_node_storage(node_storage=node_storage)
# Network
self.network_middleware = network_middleware or self.DEFAULT_NETWORK_MIDDLEWARE(
@ -604,15 +600,6 @@ class CharacterConfiguration(BaseConfiguration):
def dev_mode(self) -> bool:
return self.__dev_mode
def _setup_node_storage(self, node_storage: Optional = None) -> None:
node_storage = node_storage or NodeStorage()
self.node_storage = node_storage
def forget_nodes(self) -> None:
self.node_storage.clear()
message = "Removed all stored node node metadata and certificates"
self.log.debug(message)
def destroy(self) -> None:
"""Parse a node configuration and remove all associated files from the filesystem"""
self.config_file_location.unlink()
@ -744,7 +731,6 @@ class CharacterConfiguration(BaseConfiguration):
network_middleware=self.network_middleware
or self.DEFAULT_NETWORK_MIDDLEWARE(),
known_nodes=self.known_nodes,
node_storage=self.node_storage,
keystore=self.keystore,
crypto_power_ups=self.derive_node_power_ups(),
)
@ -855,16 +841,6 @@ class CharacterConfiguration(BaseConfiguration):
return self.keystore
@classmethod
def load_node_storage(cls, storage_payload: dict):
from nucypher.config.storages import NodeStorage
node_storage_subclasses = {storage._name: storage for storage in [NodeStorage]}
storage_type = storage_payload[NodeStorage._TYPE_LABEL]
storage_class = node_storage_subclasses[storage_type]
node_storage = storage_class()
return node_storage
def configure_pre_payment_method(self):
# TODO: finalize config fields
#

View File

@ -6,6 +6,7 @@ from .configuration_v4_to_v5 import configuration_v4_to_v5
from .configuration_v5_to_v6 import configuration_v5_to_v6
from .configuration_v6_to_v7 import configuration_v6_to_v7
from .configuration_v7_to_v8 import configuration_v7_to_v8
from .configuration_v8_to_v9 import configuration_v8_to_v9
MIGRATIONS = OrderedDict(
{
@ -16,5 +17,6 @@ MIGRATIONS = OrderedDict(
(5, 6): configuration_v5_to_v6,
(6, 7): configuration_v6_to_v7,
(7, 8): configuration_v7_to_v8,
(8, 9): configuration_v8_to_v9,
}
)

View File

@ -1,53 +0,0 @@
from nucypher.blockchain.eth.decorators import validate_checksum_address
from nucypher.crypto.signing import SignatureStamp
from nucypher.utilities.logging import Logger
class NodeStorage:
_TYPE_LABEL = "storage_type"
_name = ":memory:"
class NodeStorageError(Exception):
pass
class UnknownNode(NodeStorageError):
pass
def __init__(self, character_class=None):
self.__metadata = dict()
from nucypher.characters.lawful import Ursula
self.character_class = character_class or Ursula
self.log = Logger(self.__class__.__name__)
def __getitem__(self, item):
return self.get(checksum_address=item)
def __setitem__(self, key, value):
return self.set(node=value)
def __iter__(self):
return self.all()
def all(self) -> set:
return set(self.__metadata.values())
@validate_checksum_address
def get(self, host: str = None, stamp: SignatureStamp = None):
if not bool(stamp) ^ bool(host):
message = "Either pass stamp or host; Not both. Got ({} {})".format(
stamp, host
)
raise ValueError(message)
try:
return self.__metadata[stamp or host]
except KeyError:
raise self.UnknownNode
def set(self, node) -> bytes:
self.__metadata[node.stamp] = node
return self.__metadata[node.stamp]
def clear(self) -> None:
"""Forget all stored nodes and certificates"""
self.__metadata = dict()

View File

@ -30,7 +30,6 @@ from nucypher.blockchain.eth.constants import NULL_ADDRESS
from nucypher.blockchain.eth.domains import TACoDomain
from nucypher.blockchain.eth.registry import ContractRegistry
from nucypher.config.constants import SeednodeMetadata
from nucypher.config.storages import NodeStorage
from nucypher.crypto.powers import (
CryptoPower,
DecryptingPower,
@ -218,9 +217,6 @@ class Learner:
_LONG_LEARNING_DELAY = 90
LEARNING_TIMEOUT = 10
_ROUNDS_WITHOUT_NODES_AFTER_WHICH_TO_SLOW_DOWN = 10
# For Keeps
__DEFAULT_NODE_STORAGE = NodeStorage
__DEFAULT_MIDDLEWARE_CLASS = RestMiddleware
_crashed = (
@ -257,7 +253,6 @@ class Learner:
learn_on_same_thread: bool = False,
known_nodes: tuple = None,
seed_nodes: Tuple[tuple] = None,
node_storage=None,
save_metadata: bool = False,
abort_on_learning_error: bool = False,
lonely: bool = False,
@ -288,11 +283,6 @@ class Learner:
self._learning_deferred = None
self._discovery_canceller = DiscoveryCanceller()
node_storage = node_storage or self.__DEFAULT_NODE_STORAGE()
self.node_storage = node_storage
if save_metadata and node_storage is NO_STORAGE_AVAILABLE:
raise ValueError("Cannot save nodes without a configured node storage")
self.node_class = node_class or characters.lawful.Ursula
known_nodes = known_nodes or tuple()
@ -342,9 +332,9 @@ class Learner:
def known_nodes(self):
return self.__known_nodes
def load_seednodes(self, read_storage: bool = True, record_fleet_state=False):
def load_seednodes(self, record_fleet_state=False):
"""
Engage known nodes from storages and pre-fetch hardcoded seednode certificates for node learning.
Pre-fetch hardcoded seednode certificates for node learning.
TODO: Dehydrate this with nucypher.utilities.seednodes.load_seednodes
"""
@ -404,38 +394,11 @@ class Learner:
self.done_seeding = True
nodes_restored_from_storage = (
self.read_nodes_from_storage() if read_storage else []
)
discovered.extend(nodes_restored_from_storage)
if discovered and record_fleet_state:
self.known_nodes.record_fleet_state()
return discovered
def read_nodes_from_storage(self) -> List:
stored_nodes = self.node_storage.all()
restored_from_disk = []
invalid_nodes = defaultdict(list)
for node in stored_nodes:
if str(node.domain) != str(self.domain):
invalid_nodes[node.domain].append(node)
continue
restored_node = self.remember_node(
node, record_fleet_state=False
) # TODO: Validity status 1866
restored_from_disk.append(restored_node)
if invalid_nodes:
self.log.warn(
f"We're learning about domain '{self.domain}', but found nodes from other domains; "
f"let's ignore them. These domains and nodes are: {dict(invalid_nodes)}"
)
return restored_from_disk
def remember_node(
self,
node,
@ -464,9 +427,6 @@ class Learner:
node
) # FIXME - dont always remember nodes, bucket them.
if self.save_metadata:
self.node_storage.set(node=node)
if eager:
node.mature()
registry = self.registry if self._verify_node_bonding else None

View File

@ -66,7 +66,7 @@ def _request(url: str, certificate=None) -> Union[str, None]:
def _request_from_node(
teacher,
eth_endpoint: str,
client: Optional["NucypherMiddlewareClient"] = None,
client: Optional[NucypherMiddlewareClient] = None,
timeout: int = 2,
log: Logger = IP_DETECTION_LOGGER,
) -> Union[str, None]:

View File

@ -130,83 +130,3 @@ def test_ursula_learns_via_cli(click_runner, ursulas, testerchain):
# Check that CLI Ursula reports that it remembers the teacher and saves the TLS certificate
assert f"Saved TLS certificate for {LOOPBACK_ADDRESS}" in result.output
@pytest.mark.skip(reason="This test is poorly written and is failing.")
@pt.inlineCallbacks
def test_persistent_node_storage_integration(
click_runner, custom_filepath, testerchain, ursulas, agency_local_registry, mocker
):
mocker.patch.object(ActiveRitualTracker, "start")
(
alice,
ursula,
another_ursula,
staking_provider,
*all_yall,
) = testerchain.unassigned_accounts
filename = UrsulaConfiguration.generate_filename()
another_ursula_configuration_file_location = custom_filepath / filename
init_args = (
"ursula",
"init",
"--eth-endpoint",
TEST_ETH_PROVIDER_URI,
"--polygon-endpoint",
TEST_POLYGON_PROVIDER_URI,
"--operator-address",
another_ursula,
"--domain",
TEMPORARY_DOMAIN_NAME,
"--rest-host",
MOCK_IP_ADDRESS,
"--config-root",
str(custom_filepath.absolute()),
"--registry-filepath",
str(agency_local_registry.filepath.absolute()),
)
envvars = {NUCYPHER_ENVVAR_KEYSTORE_PASSWORD: INSECURE_DEVELOPMENT_PASSWORD}
result = click_runner.invoke(
nucypher_cli, init_args, catch_exceptions=False, env=envvars
)
assert result.exit_code == 0
teacher = ursulas[-1]
teacher_uri = teacher.rest_information()[0].uri
start_pytest_ursula_services(ursula=teacher)
user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n'
run_args = ('ursula', 'run',
'--dry-run',
'--debug',
'--config-file', str(another_ursula_configuration_file_location.absolute()),
'--teacher', teacher_uri)
Operator.READY_TIMEOUT = 1
with pytest.raises(Operator.ActorError):
# Operator init success, but not bonded.
result = yield threads.deferToThread(click_runner.invoke,
nucypher_cli, run_args,
catch_exceptions=False,
input=user_input,
env=envvars)
assert result.exit_code == 0
# Run an Ursula amidst the other configuration files
run_args = ('ursula', 'run',
'--dry-run',
'--debug',
'--config-file', str(another_ursula_configuration_file_location.absolute()))
with pytest.raises(Operator.ActorError):
# Operator init success, but not bonded.
result = yield threads.deferToThread(click_runner.invoke,
nucypher_cli, run_args,
catch_exceptions=False,
input=user_input,
env=envvars)
assert result.exit_code == 0

View File

@ -58,7 +58,6 @@ from tests.mock.interfaces import MockBlockchain
from tests.mock.performance_mocks import (
mock_cert_generation,
mock_cert_loading,
mock_cert_storage,
mock_keep_learning,
mock_message_verification,
mock_record_fleet_state,

View File

@ -67,17 +67,6 @@ def config(request, mocker):
mocker.resetall() # dont carry over context between functions
def test_forget_cli_action(alice_test_config, test_emitter, mock_stdin, mocker, capsys):
mock_forget = mocker.patch.object(CharacterConfiguration, 'forget_nodes')
mock_stdin.line(YES)
forget(emitter=test_emitter, configuration=alice_test_config)
mock_forget.assert_called_once()
assert mock_stdin.empty()
captured = capsys.readouterr()
assert CONFIRM_FORGET_NODES in captured.out
assert SUCCESSFUL_FORGET_NODES in captured.out
def test_update_configuration_cli_action(config, test_emitter, capsys):
config_class, config_file = config.__class__, config.filepath
updates = dict(domain=TEMPORARY_DOMAIN_NAME)

View File

@ -67,10 +67,6 @@ def test_initialize_via_cli(
assert custom_filepath.is_dir(), 'Configuration file does not exist'
assert (custom_filepath / 'keystore').is_dir(), 'Keystore does not exist'
# TODO: Only using in-memory node storage for now
# assert (custom_filepath / 'known_nodes').is_dir(), 'known_nodes directory does not exist'
assert not (custom_filepath / 'known_nodes').is_dir(), 'known_nodes directory does not exist'
@pytest.mark.parametrize("config_class", CONFIG_CLASSES)
def test_reconfigure_via_cli(

View File

@ -130,8 +130,6 @@ def test_corrupted_configuration(
assert default_filename in top_level_config_root, "JSON configuration file was not created"
expected_fields = [
# TODO: Only using in-memory node storage for now
# 'known_nodes',
'keystore',
default_filename
]

View File

@ -120,10 +120,6 @@ def test_initialize_custom_configuration_root(
assert custom_filepath.is_dir(), 'Configuration file does not exist'
assert (custom_filepath / 'keystore').is_dir(), 'KEYSTORE does not exist'
# TODO: Only using in-memory node storage for now
# assert (custom_filepath / 'known_nodes').is_dir(), 'known_nodes directory does not exist'
assert not (custom_filepath / 'known_nodes').is_dir(), 'known_nodes directory does not exist'
custom_config_filepath = custom_filepath / UrsulaConfiguration.generate_filename()
assert custom_config_filepath.is_file(), 'Configuration file does not exist'

View File

@ -14,7 +14,6 @@ from nucypher.config.characters import (
UrsulaConfiguration,
)
from nucypher.config.constants import TEMPORARY_DOMAIN_NAME
from nucypher.config.storages import NodeStorage
from nucypher.crypto.keystore import Keystore
from tests.constants import (
INSECURE_DEVELOPMENT_PASSWORD,
@ -75,10 +74,6 @@ def test_development_character_configurations(
# Domain
assert TEMPORARY_DOMAIN_NAME == str(thing_one.domain)
# Node Storage
assert isinstance(thing_one.node_storage, NodeStorage)
assert ":memory:" in thing_one.node_storage._name
# All development characters are unique
_characters = [thing_one, thing_two]
for _ in range(3):
@ -187,8 +182,6 @@ def test_ursula_development_configuration(testerchain):
# A Temporary Ursula
port = ursula_one.rest_information()[0].port
assert port == UrsulaConfiguration.DEFAULT_DEVELOPMENT_REST_PORT
assert isinstance(ursula_one.node_storage, NodeStorage)
assert ":memory:" in ursula_one.node_storage._name
# Alternate way to produce a character with a direct call
ursula_two = config.produce()

View File

@ -1,88 +0,0 @@
import pytest
from nucypher.blockchain.eth.signers.software import Web3Signer
from nucypher.characters.lawful import Ursula
from nucypher.config.constants import TEMPORARY_DOMAIN_NAME
from nucypher.policy.payment import SubscriptionManagerPayment
from nucypher.utilities.networking import LOOPBACK_ADDRESS
from tests.constants import MOCK_ETH_PROVIDER_URI, TESTERCHAIN_CHAIN_ID
from tests.utils.ursula import select_test_port
ADDITIONAL_NODES_TO_LEARN_ABOUT = 10
def make_header(brand: bytes, major: int, minor: int) -> bytes:
# Hardcoding this since it's too much trouble to expose it all the way from Rust
assert len(brand) == 4
major_bytes = major.to_bytes(2, 'big')
minor_bytes = minor.to_bytes(2, 'big')
header = brand + major_bytes + minor_bytes
return header
class BaseTestNodeStorageBackends:
character_class = Ursula
storage_backend = NotImplemented
def _read_and_write_metadata(self, ursula, node_storage, operator_addresses, signer):
# Write Node
node_storage.set(node=ursula)
# Read Node
node_from_storage = node_storage.get(stamp=ursula.stamp)
assert ursula == node_from_storage, "Node storage {} failed".format(node_storage)
pre_payment_method = SubscriptionManagerPayment(
blockchain_endpoint=MOCK_ETH_PROVIDER_URI, domain=TEMPORARY_DOMAIN_NAME
)
# Save more nodes
all_known_nodes = set()
for i in range(ADDITIONAL_NODES_TO_LEARN_ABOUT):
node = Ursula(
rest_host=LOOPBACK_ADDRESS,
rest_port=select_test_port(),
domain=TEMPORARY_DOMAIN_NAME,
signer=signer,
eth_endpoint=MOCK_ETH_PROVIDER_URI,
polygon_endpoint=MOCK_ETH_PROVIDER_URI,
checksum_address=operator_addresses[i],
operator_address=operator_addresses[i],
pre_payment_method=pre_payment_method,
condition_blockchain_endpoints={
TESTERCHAIN_CHAIN_ID: [MOCK_ETH_PROVIDER_URI]
},
)
node_storage.set(node=node)
all_known_nodes.add(node)
# Read all nodes from storage
all_stored_nodes = node_storage.all()
all_known_nodes.add(ursula)
assert len(all_known_nodes) == len(all_stored_nodes) == 1 + ADDITIONAL_NODES_TO_LEARN_ABOUT
known_checksums = sorted(n.checksum_address for n in all_known_nodes)
stored_checksums = sorted(n.checksum_address for n in all_stored_nodes)
assert known_checksums == stored_checksums
# Read random nodes
for i in range(3):
random_node = all_known_nodes.pop()
random_node_from_storage = node_storage.get(stamp=random_node.stamp)
assert random_node.checksum_address == random_node_from_storage.checksum_address
return True
#
# Storage Backend Tests
#
@pytest.mark.usefixtures("mock_registry_sources")
def test_read_and_write_to_storage(self, light_ursula, testerchain):
assert self._read_and_write_metadata(ursula=light_ursula,
node_storage=self.storage_backend,
operator_addresses=testerchain.ursulas_accounts,
signer=Web3Signer(testerchain.client))
self.storage_backend.clear()

View File

@ -1,15 +1,10 @@
import pytest
import tests
from nucypher.acumen.perception import FleetSensor
from nucypher.blockchain.eth.domains import TACoDomain
from nucypher.blockchain.eth.registry import ContractRegistry
from nucypher.characters.lawful import Ursula
from nucypher.config.storages import NodeStorage
from nucypher.network.nodes import TEACHER_NODES
from tests.constants import TEMPORARY_DOMAIN, TESTERCHAIN_CHAIN_INFO
from tests.utils.registry import MockRegistrySource
from tests.utils.ursula import make_ursulas
@pytest.fixture(scope="module")
@ -105,155 +100,3 @@ def test_learner_learns_about_domains_separately(
assert hero_learner in new_first_domain_learner.known_nodes
assert other_first_domain_learner in new_first_domain_learner.known_nodes
assert _nobody in new_first_domain_learner.known_nodes
def test_learner_restores_metadata_from_storage(
lonely_ursula_maker, tmpdir, domain_1, domain_2
):
# Create a local file-based node storage
old_storage = NodeStorage()
# Use the ursula maker with this storage so it's populated with nodes from one domain
_some_ursulas = lonely_ursula_maker(
domain=domain_1,
node_storage=old_storage,
know_each_other=True,
quantity=3,
save_metadata=True,
)
# Create a pair of new learners in a different domain, using the previous storage, and learn from it
new_learners = lonely_ursula_maker(
domain=domain_2,
node_storage=old_storage,
quantity=2,
know_each_other=True,
save_metadata=False,
)
learner, buddy = new_learners
buddy._Learner__known_nodes = FleetSensor(domain=domain_1)
# The learner shouldn't learn about any node from the first domain, since it's different.
learner.learn_from_teacher_node()
for restored_node in learner.known_nodes:
assert restored_node.mature().domain == learner.domain
# In fact, since the storage only contains nodes from a different domain,
# the learner should only know its buddy from the second domain.
assert set(learner.known_nodes) == {buddy}
def test_learner_ignores_stored_nodes_from_other_domains(
lonely_ursula_maker,
domain_1,
domain_2,
registry_1,
registry_2,
tmpdir,
testerchain,
ursula_test_config,
):
learner, other_staker = make_ursulas(
ursula_test_config,
domain=domain_1,
registry=registry_1,
quantity=2,
know_each_other=True,
staking_provider_addresses=testerchain.stake_providers_accounts[:2],
operator_addresses=testerchain.ursulas_accounts[:2],
)
pest, *other_ursulas_from_the_wrong_side_of_the_tracks = make_ursulas(
ursula_test_config,
domain=domain_2,
registry=registry_2,
quantity=5,
know_each_other=True,
staking_provider_addresses=testerchain.stake_providers_accounts[2:],
operator_addresses=testerchain.ursulas_accounts[2:],
)
assert pest not in other_staker.known_nodes
assert pest not in learner.known_nodes
pest._current_teacher_node = learner
pest.learn_from_teacher_node()
assert pest not in other_staker.known_nodes
##################################
# Prior to #2423, learner remembered pest because POSTed node metadata was not domain-checked.
# This is how ibex nodes initially made their way into mainnet fleet states.
assert pest not in learner.known_nodes # But not anymore.
# Once pest made its way into learner, learner taught passed it to other mainnet nodes.
assert pest not in learner.known_nodes # But not anymore.
learner.known_nodes.record_node(pest) # This used to happen anyway.
other_staker._current_teacher_node = learner
other_staker.learn_from_teacher_node() # And once it did, the node from the wrong domain spread.
assert pest not in other_staker.known_nodes # But not anymore.
def test_learner_with_empty_storage_uses_fallback_nodes(
lonely_ursula_maker, domain_1, mocker
):
mocker.patch.dict(TEACHER_NODES, {domain_1: ("teacher-uri",)}, clear=True)
# Create a learner and a teacher
learner, teacher = lonely_ursula_maker(
domain=domain_1, quantity=2, save_metadata=False
)
mocker.patch.object(Ursula, "from_teacher_uri", return_value=teacher)
# Since there are no nodes in local node storage, the learner should only learn about the teacher
learner.learn_from_teacher_node()
assert set(learner.known_nodes) == {teacher}
def test_learner_uses_both_nodes_from_storage_and_fallback_nodes(
lonely_ursula_maker,
domain_1,
registry_1,
tmpdir,
mocker,
test_registry,
ursula_test_config,
testerchain,
):
mocker.patch.dict(TEACHER_NODES, {domain_1: ("teacher-uri",)}, clear=True)
# Create a local file-based node storage
node_storage = NodeStorage()
# Create some nodes and persist them to local storage
other_nodes = make_ursulas(
ursula_test_config,
domain=domain_1,
registry=registry_1,
node_storage=node_storage,
know_each_other=True,
quantity=3,
save_metadata=True,
staking_provider_addresses=testerchain.stake_providers_accounts[:3],
operator_addresses=testerchain.ursulas_accounts[:3],
)
# Create a teacher and a learner using existing node storage
learner, teacher = lonely_ursula_maker(
domain=domain_1,
registry=registry_1,
node_storage=node_storage,
quantity=2,
know_each_other=True,
staking_provider_addresses=testerchain.stake_providers_accounts[3:],
operator_addresses=testerchain.ursulas_accounts[3:],
)
# mocker.patch.object(Ursula, 'from_teacher_uri', return_value=teacher)
# The learner should learn about all nodes
learner.learn_from_teacher_node()
all_nodes = {teacher}
all_nodes.update(other_nodes)
assert learner not in all_nodes
assert learner not in set(learner.known_nodes)
assert set(learner.known_nodes) == all_nodes

View File

@ -1,41 +0,0 @@
import maya
import pytest
import pytest_twisted as pt
from twisted.internet.threads import deferToThread
@pt.inlineCallbacks
def test_one_node_stores_a_bunch_of_others(ursulas, lonely_ursula_maker):
the_chosen_seednode = list(ursulas)[2] # ...neo?
seed_node = the_chosen_seednode.seed_node_metadata()
newcomer = lonely_ursula_maker(
quantity=1,
save_metadata=True,
seed_nodes=[seed_node]).pop()
assert not newcomer.known_nodes
newcomer.start_learning_loop(now=True)
def start_lonely_learning_loop():
newcomer.start_learning_loop()
start = maya.now()
# Loop until the_chosen_seednode is in storage.
while the_chosen_seednode.checksum_address not in [
u.checksum_address for u in newcomer.node_storage.all()
]:
passed = maya.now() - start
if passed.seconds > 2:
pytest.fail("Didn't find the seed node.")
yield deferToThread(start_lonely_learning_loop)
matured_known_nodes = list(node.mature() for node in newcomer.known_nodes)
assert list(matured_known_nodes)
assert len(matured_known_nodes) == len(
list(newcomer.node_storage.all())
) # TODO: why are certificates note being stored here?
assert set(matured_known_nodes) == set(list(newcomer.node_storage.all()))

View File

@ -6,8 +6,6 @@ from nucypher_core.umbral import PublicKey
from nucypher.network.server import make_rest_app
from tests.mock.serials import good_serials
mock_cert_storage = patch("nucypher.config.storages.ForgetfulNodeStorage.store_node_certificate",
new=lambda *args, **kwargs: "this_might_normally_be_a_filepath")
mock_message_verification = patch('nucypher.characters.lawful.Alice.verify_from', new=lambda *args, **kwargs: None)