From 820f41bdc01b4e5e6b0ac5817882cd0b5c0b4f3d Mon Sep 17 00:00:00 2001 From: Kieran Prasch Date: Thu, 7 Jun 2018 11:57:03 -0700 Subject: [PATCH] Blockchain make arrangement lock periods, and consideration --- nucypher/blockchain/eth/actors.py | 8 +++--- nucypher/blockchain/eth/policies.py | 28 +++++++++++++------- nucypher/characters.py | 11 +++----- nucypher/policy/models.py | 27 +++++++------------ tests/blockchain/eth/entities/test_actors.py | 4 +-- tests/utilities.py | 2 +- 6 files changed, 38 insertions(+), 42 deletions(-) diff --git a/nucypher/blockchain/eth/actors.py b/nucypher/blockchain/eth/actors.py index 479a979c0..ae8d9af46 100644 --- a/nucypher/blockchain/eth/actors.py +++ b/nucypher/blockchain/eth/actors.py @@ -311,12 +311,12 @@ class PolicyAuthor(NucypherTokenActor): txhash = arrangement.revoke() return txhash - def recruit(self, quantity: int, **options) -> List[Miner]: + def recruit(self, quantity: int, **options) -> Generator[Miner, None, None]: """Uses sampling logic to gather miners from the blockchain""" - miner_addresses = self.policy_agent.miner_agent.sample(quantity=quantity, **options) - miners = [Miner(ether_address=address, miner_agent=self.miner_agent) for address in miner_addresses] - return miners + for address in miner_addresses: + miner = Miner(ether_address=address, miner_agent=self.miner_agent) + yield miner def create_policy(self, *args, **kwargs): from nucypher.blockchain.eth.policies import BlockchainPolicy diff --git a/nucypher/blockchain/eth/policies.py b/nucypher/blockchain/eth/policies.py index dd24efaa0..3c6f9d9c5 100644 --- a/nucypher/blockchain/eth/policies.py +++ b/nucypher/blockchain/eth/policies.py @@ -1,4 +1,5 @@ import math +from typing import List, Set import maya from constant_sorrow import constants @@ -7,6 +8,7 @@ from nucypher.blockchain.eth.actors import PolicyAuthor from nucypher.blockchain.eth.actors import Miner from nucypher.blockchain.eth.agents import MinerAgent +from nucypher.characters import Ursula from nucypher.policy.models import Arrangement, Policy @@ -95,23 +97,31 @@ class BlockchainPolicy(Policy): return arrangement def make_arrangements(self, network_middleware, quantity: int, - deposit: int, expiration: maya.MayaDT, - federated_only=False) -> None: + deposit: int, expiration: maya.MayaDT, ursulas: Set[Ursula]=None) -> None: """ Create and consider n Arangement objects from sampled miners. """ - try: - sampled_miners = self.alice.recruit(quantity=quantity or self.n) - except MinerAgent.NotEnoughMiners: - raise # TODO - for miner in sampled_miners: # TODO: + if ursulas is not None: + # if len(ursulas) < self.n: + # raise Exception # TODO: Validate ursulas + pass + + else: + try: + sampled_miners = self.alice.recruit(quantity=quantity or self.n) + except MinerAgent.NotEnoughMiners: + raise # TODO + else: + ursulas = (Ursula.from_miner(miner, is_me=False) for miner in sampled_miners) + + for ursula in ursulas: delta = expiration - maya.now() - hours = delta.seconds / 60 / 60 + hours = (delta.total_seconds() / 60) / 60 periods = int(math.ceil(hours / int(constants.HOURS_PER_PERIOD))) - blockchain_arrangement = BlockchainArrangement(author=self.alice, miner=miner, + blockchain_arrangement = BlockchainArrangement(author=self.alice, miner=ursula, value=deposit, lock_periods=periods, expiration=expiration, hrac=self.hrac) diff --git a/nucypher/characters.py b/nucypher/characters.py index b4b1666f8..44ea568c7 100644 --- a/nucypher/characters.py +++ b/nucypher/characters.py @@ -653,13 +653,8 @@ class Ursula(Character, ProxyRESTServer, Miner): return self._rest_app @classmethod - def from_config(cls, config: CharacterConfiguration) -> 'Ursula': - """TODO""" - - # Use BlockchainConfig to default to the first wallet address - wallet_address = config.blockchain.wallet_addresses[0] - - instance = cls(ether_address=wallet_address) + def from_miner(cls, miner, *args, **kwargs): + instance = cls(miner_agent=miner.miner_agent, ether_address=miner.ether_address, *args, **kwargs) return instance @classmethod @@ -712,7 +707,7 @@ class Ursula(Character, ProxyRESTServer, Miner): value = self.interface_info_with_metadata() setter = self.dht_server.set(key=ursula_id, value=value) - self.publish_data(ursula_id) + self.publish_datastore(ursula_id) loop = asyncio.get_event_loop() loop.run_until_complete(setter) diff --git a/nucypher/policy/models.py b/nucypher/policy/models.py index a1b496707..6a3895c26 100644 --- a/nucypher/policy/models.py +++ b/nucypher/policy/models.py @@ -2,7 +2,7 @@ import binascii import uuid from abc import ABC, abstractmethod from collections import OrderedDict -from typing import Generator +from typing import Generator, List import maya import msgpack @@ -113,7 +113,6 @@ class Policy(ABC): Once Alice has secured agreement with n Ursulas to enact a Policy, she sends each a KFrag, and generates a TreasureMap for the Policy, recording which Ursulas got a KFrag. """ - _ursula = None def __init__(self, alice, label, bob=None, kfrags=(constants.UNKNOWN_KFRAG,), public_key=None, m=None, alices_signature=constants.NOT_SIGNED): @@ -148,18 +147,6 @@ class Policy(ABC): def n(self): return len(self.kfrags) - @property - def ursula(self): - if not self._ursula: - raise Ursula.NotFound - else: - return self._ursula - - @ursula.setter - def ursula(self, ursula_object): - self.alice.learn_about_actor(ursula_object) - self._ursula = ursula_object - def hrac(self): """ The "hashed resource authentication code". @@ -258,7 +245,7 @@ class Policy(ABC): self.publish() def consider_arrangement(self, network_middleware, arrangement): - ursula, negotiation_response = network_middleware.consider_arrangement(ursula=self.ursula, + ursula, negotiation_response = network_middleware.consider_arrangement(ursula=arrangement.ursula, arrangement=arrangement) # TODO: check out the response: need to assess the result and see if we're actually good to go. @@ -271,14 +258,18 @@ class Policy(ABC): @abstractmethod def make_arrangements(self, network_middleware, quantity: int, - deposit: int, expiration: maya.MayaDT) -> None: + deposit: int, expiration: maya.MayaDT, ursulas: List[Ursula]=None) -> None: """ Create and consider n Arangement objects. """ - ursulas = NotImplemented + if not ursulas: + ursulas = NotImplemented + for ursula in ursulas: arrangement = Arrangement(alice=NotImplemented, - ursula=ursula, hrac=self.hrac, expiration=expiration) + ursula=ursula, + hrac=self.hrac, + expiration=expiration) self.consider_arrangement(network_middleware=network_middleware, arrangement=arrangement) diff --git a/tests/blockchain/eth/entities/test_actors.py b/tests/blockchain/eth/entities/test_actors.py index f6d67735f..1cd37f582 100644 --- a/tests/blockchain/eth/entities/test_actors.py +++ b/tests/blockchain/eth/entities/test_actors.py @@ -65,7 +65,7 @@ class TestMiner: # Publish Miner IDs to the DHT some_data = os.urandom(32) - _txhash = miner.publish_data(some_data) + _txhash = miner.publish_datastore(some_data) # Fetch the miner Ids stored_miner_ids = miner.fetch_data() @@ -75,7 +75,7 @@ class TestMiner: # Repeat, with another miner ID another_mock_miner_id = os.urandom(32) - _txhash = miner.publish_data(another_mock_miner_id) + _txhash = miner.publish_datastore(another_mock_miner_id) stored_miner_ids = miner.fetch_data() diff --git a/tests/utilities.py b/tests/utilities.py index e98d52cf0..868f57a51 100644 --- a/tests/utilities.py +++ b/tests/utilities.py @@ -32,7 +32,7 @@ def make_ursulas(ether_addresses: list, ursula_starting_port: int, miners=False) _ursulas = [] for _counter, ether_address in enumerate(ether_addresses): port = ursula_starting_port + _counter - ursula = Ursula(ether_address=ether_address, dht_port=port, db_name="test-{}".format(port), + ursula = Ursula(is_me=True, ether_address=ether_address, dht_port=port, db_name="test-{}".format(port), ip_address="127.0.0.1", rest_port=port + 100) class MockDatastoreThreadPool(object):