コード例 #1
0
    def confirm_airdrop(_results):
        recipient = testerchain.interface.w3.eth.accounts[-1]
        miner = Miner(checksum_address=recipient,
                      blockchain=testerchain,
                      is_me=True)

        assert miner.token_balance == NU(15000, 'NU')
コード例 #2
0
ファイル: test_miner.py プロジェクト: Howlla/nucypher
def miner(testerchain, three_agents):
    token_agent, miner_agent, policy_agent = three_agents
    origin, *everybody_else = testerchain.interface.w3.eth.accounts
    token_airdrop(token_agent,
                  origin=testerchain.etherbase_account,
                  addresses=everybody_else,
                  amount=DEVELOPMENT_TOKEN_AIRDROP_AMOUNT)
    miner = Miner(checksum_address=everybody_else[0], is_me=True)
    return miner
コード例 #3
0
ファイル: test_actors.py プロジェクト: ngocson2vn/nucypher
 def miner(self, testerchain, three_agents):
     token_agent, miner_agent, policy_agent = three_agents
     origin, *everybody_else = testerchain.interface.w3.eth.accounts
     token_airdrop(token_agent,
                   origin=origin,
                   addresses=everybody_else,
                   amount=1000000 * constants.M)
     miner = Miner(miner_agent=miner_agent,
                   checksum_address=everybody_else[0])
     return miner
コード例 #4
0
ファイル: test_felix.py プロジェクト: Howlla/nucypher
    def confirm_airdrop(_results):
        recipient = testerchain.interface.w3.eth.accounts[-1]
        miner = Miner(checksum_address=recipient,
                      blockchain=testerchain,
                      is_me=True)

        assert miner.token_balance == NU(15000, 'NU')

        new_eth_balance = original_eth_balance + testerchain.interface.w3.fromWei(
            Felix.ETHER_AIRDROP_AMOUNT, 'ether')
        assert miner.eth_balance == new_eth_balance
コード例 #5
0
ファイル: ursula.py プロジェクト: neuroidss/nucypher
def spawn_random_staking_ursulas(miner_agent, addresses: list) -> list:
    """
    Deposit and lock a random amount of tokens in the miner escrow
    from each address, "spawning" new Miners.
    """
    from nucypher.blockchain.eth.actors import Miner

    miners = list()
    for address in addresses:
        miner = Miner(miner_agent=miner_agent, checksum_address=address)
        miners.append(miner)

        # stake a random amount
        min_stake, balance = constants.MIN_ALLOWED_LOCKED, miner.token_balance
        amount = random.randint(min_stake, balance)

        # for a random lock duration
        min_locktime, max_locktime = constants.MIN_LOCKED_PERIODS, constants.MAX_MINTING_PERIODS
        periods = random.randint(min_locktime, max_locktime)

        miner.initialize_stake(amount=amount, lock_periods=periods)

    return miners
コード例 #6
0
    def spawn_random_miners(self, addresses: list) -> list:
        """
        Deposit and lock a random amount of tokens in the miner escrow
        from each address, "spawning" new Miners.
        """
        from nucypher.blockchain.eth.actors import Miner

        miners = list()
        for address in addresses:
            miner = Miner(miner_agent=self, address=address)
            miners.append(miner)

            # stake a random amount
            min_stake, balance = self.min_allowed_locked, miner.token_balance()
            amount = random.randint(min_stake, balance)

            # for a random lock duration
            min_locktime, max_locktime = self.min_locked_periods, self.max_minting_periods
            periods = random.randint(min_locktime, max_locktime)

            miner.stake(amount=amount, lock_periods=periods)

        return miners
コード例 #7
0
ファイル: policies.py プロジェクト: johanns/nucypher
    def get_arrangement(self, arrangement_id: bytes) -> BlockchainArrangement:
        """Fetch a published arrangement from the blockchain"""

        blockchain_record = self.policy_agent.read().policies(arrangement_id)
        author_address, miner_address, rate, start_block, end_block, downtime_index = blockchain_record

        duration = end_block - start_block

        miner = Miner(address=miner_address,
                      miner_agent=self.policy_agent.miner_agent)
        arrangement = BlockchainArrangement(author=self,
                                            miner=miner,
                                            lock_periods=duration)

        arrangement.is_published = True
        return arrangement
コード例 #8
0
ファイル: policies.py プロジェクト: mallek/nucypher
    def get_arrangement(self, arrangement_id: bytes) -> BlockchainArrangement:
        """Fetch published arrangements from the blockchain"""

        blockchain_record = self.author.policy_agent.read().policies(arrangement_id)
        author_address, miner_address, rate, start_block, end_block, downtime_index = blockchain_record

        duration = end_block - start_block

        miner = Miner(address=miner_address, miner_agent=self.author.policy_agent.miner_agent)
        arrangement = BlockchainArrangement(author=self.author,
                                            miner=miner,
                                            value=rate*duration,   # TODO Check the math/types here
                                            lock_periods=duration,
                                            expiration=end_block)  # TODO: fix missing argument here

        arrangement.is_published = True
        return arrangement
コード例 #9
0
def test_collect_rewards_integration(click_runner, configuration_file_location,
                                     blockchain_alice, blockchain_bob,
                                     random_policy_label, staking_participant,
                                     token_economics, policy_value,
                                     policy_rate):

    blockchain = staking_participant.blockchain

    half_stake_time = token_economics.minimum_locked_periods // 2  # Test setup
    logger = staking_participant.log  # Enter the Teacher's Logger, and
    current_period = 1  # State the initial period for incrementing

    miner = Miner(is_me=True,
                  checksum_address=staking_participant.checksum_address,
                  blockchain=blockchain)

    # The miner is staking.
    assert miner.stakes
    assert miner.is_staking
    pre_stake_token_balance = miner.token_balance

    # Confirm for half the first stake duration
    for _ in range(half_stake_time):
        current_period += 1
        logger.debug(
            f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")
        blockchain.time_travel(periods=1)
        miner.confirm_activity()

    # Alice creates a policy and grants Bob access
    blockchain_alice.selection_buffer = 1

    M, N = 1, 1
    expiration = maya.now() + datetime.timedelta(days=3)
    blockchain_policy = blockchain_alice.grant(
        bob=blockchain_bob,
        label=random_policy_label,
        m=M,
        n=N,
        value=policy_value,
        expiration=expiration,
        handpicked_ursulas={staking_participant})

    # Ensure that the handpicked Ursula was selected for the policy
    arrangement = list(blockchain_policy._accepted_arrangements)[0]
    assert arrangement.ursula == staking_participant

    # Bob learns about the new staker and joins the policy
    blockchain_bob.start_learning_loop()
    blockchain_bob.remember_node(node=staking_participant)
    blockchain_bob.join_policy(random_policy_label,
                               bytes(blockchain_alice.stamp))

    # Enrico Encrypts (of course)
    enrico = Enrico(policy_encrypting_key=blockchain_policy.public_key,
                    network_middleware=MockRestMiddleware())

    verifying_key = blockchain_alice.stamp.as_umbral_pubkey()

    for index in range(half_stake_time - 5):
        logger.debug(
            f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")

        # Encrypt
        random_data = os.urandom(random.randrange(20, 100))
        ciphertext, signature = enrico.encrypt_message(message=random_data)

        # Decrypt
        cleartexts = blockchain_bob.retrieve(message_kit=ciphertext,
                                             data_source=enrico,
                                             alice_verifying_key=verifying_key,
                                             label=random_policy_label)
        assert random_data == cleartexts[0]

        # Ursula Staying online and the clock advancing
        blockchain.time_travel(periods=1)
        miner.confirm_activity()
        current_period += 1

    # Finish the passage of time for the first Stake
    for _ in range(5):  # plus the extended periods from stake division
        current_period += 1
        logger.debug(
            f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")
        blockchain.time_travel(periods=1)
        miner.confirm_activity()

    #
    # WHERES THE MONEY URSULA?? - Collecting Rewards
    #

    # The address the client wants Ursula to send rewards to
    burner_wallet = blockchain.interface.w3.eth.account.create(
        INSECURE_DEVELOPMENT_PASSWORD)

    # The rewards wallet is initially empty, because it is freshly created
    assert blockchain.interface.w3.eth.getBalance(burner_wallet.address) == 0

    # Snag a random teacher from the fleet
    collection_args = ('--mock-networking', 'ursula', 'collect-reward',
                       '--config-file', configuration_file_location,
                       '--withdraw-address', burner_wallet.address, '--force')

    result = click_runner.invoke(nucypher_cli,
                                 collection_args,
                                 input=INSECURE_DEVELOPMENT_PASSWORD,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Policy Reward
    collected_policy_reward = blockchain.interface.w3.eth.getBalance(
        burner_wallet.address)
    expected_collection = policy_rate * 30
    assert collected_policy_reward == expected_collection

    # Finish the passage of time... once and for all
    # Extended periods from stake division
    for _ in range(9):
        current_period += 1
        logger.debug(
            f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")
        blockchain.time_travel(periods=1)
        miner.confirm_activity()

    # Staking Reward
    calculated_reward = miner.miner_agent.calculate_staking_reward(
        checksum_address=miner.checksum_address)
    assert calculated_reward
    assert miner.token_balance > pre_stake_token_balance
コード例 #10
0
ファイル: main.py プロジェクト: OnGridSystems/nucypher
def simulate(config, action, nodes, federated_only, geth):
    """
    Simulate the nucypher blockchain network

    Arguments
    ==========

    action - Which action to perform; The choices are:
           - start: Start a multi-process nucypher network simulation
           - stop: Stop a running simulation gracefully

    Options
    ========

    --nodes - The quantity of nodes (processes) to execute during the simulation
    --duration = The number of periods to run the simulation before termination

    """
    if action == 'start':

        #
        # Blockchain Connection
        #
        if not federated_only:
            if geth:
                test_provider_uri = "ipc:///tmp/geth.ipc"
            else:
                test_provider_uri = "pyevm://tester"

            simulation_registry = TemporaryEthereumContractRegistry()
            simulation_interface = BlockchainDeployerInterface(provider_uri=test_provider_uri,
                                                               registry=simulation_registry,
                                                               compiler=SolidityCompiler())

            blockchain = TesterBlockchain(interface=simulation_interface, test_accounts=nodes, airdrop=False)

            accounts = blockchain.interface.w3.eth.accounts
            origin, *everyone_else = accounts

            # Set the deployer address from the freshly created test account
            simulation_interface.deployer_address = origin

            #
            # Blockchain Action
            #
            blockchain.ether_airdrop(amount=DEVELOPMENT_ETH_AIRDROP_AMOUNT)

            click.confirm("Deploy all nucypher contracts to {}?".format(test_provider_uri), abort=True)
            click.echo("Bootstrapping simulated blockchain network")

            # Deploy contracts
            token_deployer = NucypherTokenDeployer(blockchain=blockchain, deployer_address=origin)
            token_deployer.arm()
            token_deployer.deploy()
            token_agent = token_deployer.make_agent()

            miners_escrow_secret = os.urandom(DISPATCHER_SECRET_LENGTH)
            miner_escrow_deployer = MinerEscrowDeployer(token_agent=token_agent,
                                                        deployer_address=origin,
                                                        secret_hash=miners_escrow_secret)
            miner_escrow_deployer.arm()
            miner_escrow_deployer.deploy()
            miner_agent = miner_escrow_deployer.make_agent()

            policy_manager_secret = os.urandom(DISPATCHER_SECRET_LENGTH)
            policy_manager_deployer = PolicyManagerDeployer(miner_agent=miner_agent,
                                                            deployer_address=origin,
                                                            secret_hash=policy_manager_secret)
            policy_manager_deployer.arm()
            policy_manager_deployer.deploy()
            policy_agent = policy_manager_deployer.make_agent()

            airdrop_amount = DEVELOPMENT_TOKEN_AIRDROP_AMOUNT
            click.echo("Airdropping tokens {} to {} addresses".format(airdrop_amount, len(everyone_else)))
            _receipts = token_airdrop(token_agent=token_agent,
                                      origin=origin,
                                      addresses=everyone_else,
                                      amount=airdrop_amount)

            # Commit the current state of deployment to a registry file.
            click.echo("Writing filesystem registry")
            _sim_registry_name = blockchain.interface.registry.commit(filepath=DEFAULT_SIMULATION_REGISTRY_FILEPATH)

        click.echo("Ready to run swarm.")

        #
        # Swarm
        #

        # Select a port range to use on localhost for sim servers

        if not federated_only:
            sim_addresses = everyone_else
        else:
            sim_addresses = NotImplemented

        start_port = 8787
        counter = 0
        for sim_port_number, sim_address in enumerate(sim_addresses, start=start_port):

            #
            # Parse ursula parameters
            #

            rest_port = sim_port_number
            db_name = 'sim-{}'.format(rest_port)

            cli_exec = os.path.join(BASE_DIR, 'cli', 'main.py')
            python_exec = 'python'

            proc_params = '''
            python3 {} run_ursula --rest-port {} --db-name {}
            '''.format(python_exec, cli_exec, rest_port, db_name).split()

            if federated_only:
                proc_params.append('--federated-only')

            else:
                token_agent = NucypherTokenAgent(blockchain=blockchain)
                miner_agent = MinerAgent(token_agent=token_agent)
                miner = Miner(miner_agent=miner_agent, checksum_address=sim_address)

                # stake a random amount
                min_stake, balance = MIN_ALLOWED_LOCKED, miner.token_balance
                value = random.randint(min_stake, balance)

                # for a random lock duration
                min_locktime, max_locktime = MIN_LOCKED_PERIODS, MAX_MINTING_PERIODS
                periods = random.randint(min_locktime, max_locktime)

                miner.initialize_stake(amount=value, lock_periods=periods)
                click.echo("{} Initialized new stake: {} tokens for {} periods".format(sim_address, value, periods))

                proc_params.extend('--checksum-address {}'.format(sim_address).split())

            # Spawn
            click.echo("Spawning node #{}".format(counter+1))
            processProtocol = UrsulaProcessProtocol(command=proc_params)
            cli_exec = os.path.join(BASE_DIR, 'cli', 'main.py')
            ursula_proc = reactor.spawnProcess(processProtocol, cli_exec, proc_params)

            #
            # post-spawnProcess
            #

            # Start with some basic status data, then build on it

            rest_uri = "http://{}:{}".format('localhost', rest_port)

            sim_data = "Started simulated Ursula | ReST {}".format(rest_uri)
            rest_uri = "{host}:{port}".format(host='localhost', port=str(sim_port_number))
            sim_data.format(rest_uri)

            # if not federated_only:
            #     stake_infos = tuple(config.miner_agent.get_all_stakes(miner_address=sim_address))
            #     sim_data += '| ETH address {}'.format(sim_address)
            #     sim_data += '| {} Active stakes '.format(len(stake_infos))

            click.echo(sim_data)
            counter += 1

        click.echo("Starting the reactor")
        click.confirm("Start the reactor?", abort=True)
        try:
            reactor.run()
        finally:

            if not federated_only:
                click.echo("Removing simulation registry")
                os.remove(DEFAULT_SIMULATION_REGISTRY_FILEPATH)

            click.echo("Stopping simulated Ursula processes")
            for process in config.sim_processes:
                os.kill(process.pid, 9)
                click.echo("Killed {}".format(process))

            click.echo("Simulation completed")

    elif action == 'stop':
        # Kill the simulated ursulas
        for process in config.ursula_processes:
            process.transport.signalProcess('KILL')

    elif action == 'status':

        if not config.simulation_running:
            status_message = "Simulation not running."
        else:

            ursula_processes = len(config.ursula_processes)

            status_message = """
            
            | Node Swarm Simulation Status |
            
            Simulation processes .............. {}
            
            """.format(ursula_processes)

        click.echo(status_message)

    elif action == 'demo':
        """Run the finnegans wake demo"""
        demo_exec = os.path.join(BASE_DIR, 'cli', 'demos', 'finnegans-wake-demo.py')
        process_args = [sys.executable, demo_exec]

        if federated_only:
            process_args.append('--federated-only')

        subprocess.run(process_args, stdout=subprocess.PIPE)
コード例 #11
0
def test_collect_rewards_integration(
        click_runner, funded_blockchain, configuration_file_location,
        alice_blockchain_test_config, bob_blockchain_test_config,
        charlie_blockchain_test_config, random_policy_label,
        blockchain_ursulas, staking_participant):

    blockchain = staking_participant.blockchain

    # Alice creates a policy and grants Bob access
    alice = alice_blockchain_test_config.produce(
        blockchain=funded_blockchain,
        network_middleware=MockRestMiddleware(),
        known_nodes=blockchain_ursulas)

    bob = bob_blockchain_test_config.produce(
        blockchain=blockchain,
        network_middleware=MockRestMiddleware(),
        known_nodes=blockchain_ursulas)

    #
    # Back to the Ursulas...
    #
    half_stake_time = MIN_LOCKED_PERIODS // 2  # Test setup
    logger = staking_participant.log  # Enter the Teacher's Logger, and
    current_period = 1  # State the initial period for incrementing

    miner = Miner(checksum_address=staking_participant.checksum_public_address,
                  blockchain=blockchain,
                  is_me=True)

    pre_stake_eth_balance = miner.eth_balance

    # Finish the passage of time... once and for all
    for _ in range(half_stake_time):
        current_period += 1
        logger.debug(f"period {current_period}")
        blockchain.time_travel(periods=1)
        miner.confirm_activity()

    M, N = 1, 1
    expiration = maya.now() + datetime.timedelta(days=3)
    blockchain_policy = alice.grant(bob=bob,
                                    label=random_policy_label,
                                    m=M,
                                    n=1,
                                    value=POLICY_VALUE,
                                    expiration=expiration,
                                    handpicked_ursulas={staking_participant})

    # Bob joins the policy
    bob.join_policy(random_policy_label, bytes(alice.stamp))

    # Enrico Encrypts (of course)
    enrico = Enrico(policy_encrypting_key=blockchain_policy.public_key,
                    network_middleware=MockRestMiddleware())

    for index, _period in enumerate(range(half_stake_time - 5)):
        logger.debug(f"period {current_period}")

        alphabet = string.ascii_letters + string.digits

        # Random Request Periods
        if not random.choice((True, False)):
            continue  # maybe re-encrypt

        max_reencryptions_per_period = 5
        quantity = random.choice(range(max_reencryptions_per_period + 1))
        quantity *= index  # factorial or 0
        verifying_key = UmbralPublicKey.from_bytes(bytes(alice.stamp))

        # Random Re-encryptions
        for _i in range(quantity):

            # Encrypt
            random_data = ''.join(
                secrets.choice(alphabet)
                for i in range(secrets.choice(range(20, 100))))
            ciphertext, signature = enrico.encrypt_message(
                message=bytes(random_data, encoding='utf-8'))

            # Retrieve
            payload = dict(message_kit=ciphertext,
                           data_source=enrico,
                           alice_verifying_key=verifying_key,
                           label=random_policy_label)

            _cleartext = bob.retrieve(**payload)

        # Ursula Staying online and the clock advancing
        blockchain.time_travel(periods=1)
        miner.confirm_activity()
        current_period += 1

    # Finish the passage of time... once and for all
    for _ in range(5):
        current_period += 1
        logger.debug(f"period {current_period}")
        blockchain.time_travel(periods=1)
        miner.confirm_activity()

    #
    # WHERES THE MONEY URSULA?? - Collecting Rewards
    #

    # The address the client wants Ursula to send rewards to
    burner_wallet = blockchain.interface.w3.eth.account.create(
        INSECURE_DEVELOPMENT_PASSWORD)
    assert blockchain.interface.w3.eth.getBalance(burner_wallet.address) == 0

    # Snag a random teacher from the fleet
    random_teacher = list(blockchain_ursulas).pop()

    collection_args = ('--mock-networking', 'ursula', 'collect-reward',
                       '--teacher-uri', random_teacher.rest_interface,
                       '--config-file', configuration_file_location,
                       '--withdraw-address', burner_wallet.address, '--poa',
                       '--force')

    result = click_runner.invoke(nucypher_cli,
                                 collection_args,
                                 input=INSECURE_DEVELOPMENT_PASSWORD,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    collected_reward = blockchain.interface.w3.eth.getBalance(
        burner_wallet.address)
    assert collected_reward != 0

    expected_reward = Web3.toWei(21, 'gwei') * 30 * M
    assert collected_reward == expected_reward
    assert miner.eth_balance == pre_stake_eth_balance
コード例 #12
0
ファイル: lawful.py プロジェクト: manishvishnoi2/nucypher
    def __init__(
            self,

            # Ursula
            rest_host: str,
            rest_port: int,
            domains: Set = (
                GLOBAL_DOMAIN,
            ),  # For now, serving and learning domains will be the same.
            certificate: Certificate = None,
            certificate_filepath: str = None,
            db_filepath: str = None,
            is_me: bool = True,
            interface_signature=None,
            timestamp=None,

            # Blockchain
            identity_evidence: bytes = constants.NOT_SIGNED,
            checksum_public_address: str = None,

            # Character
            password: str = None,
            abort_on_learning_error: bool = False,
            federated_only: bool = False,
            start_learning_now: bool = None,
            crypto_power=None,
            tls_curve: EllipticCurve = None,
            known_nodes: Iterable = None,
            **character_kwargs) -> None:

        #
        # Character
        #
        self._work_orders = list()
        Character.__init__(self,
                           is_me=is_me,
                           checksum_public_address=checksum_public_address,
                           start_learning_now=start_learning_now,
                           federated_only=federated_only,
                           crypto_power=crypto_power,
                           abort_on_learning_error=abort_on_learning_error,
                           known_nodes=known_nodes,
                           domains=domains,
                           **character_kwargs)

        #
        # Self-Ursula
        #
        if is_me is True:  # TODO: 340
            self._stored_treasure_maps = dict()

            #
            # Staking Ursula
            #
            if not federated_only:
                Miner.__init__(self,
                               is_me=is_me,
                               checksum_address=checksum_public_address)

                # Access staking node via node's transacting keys  TODO: Better handle ephemeral staking self ursula
                blockchain_power = BlockchainPower(
                    blockchain=self.blockchain,
                    account=self.checksum_public_address)
                self._crypto_power.consume_power_up(blockchain_power)

                # Use blockchain power to substantiate stamp, instead of signing key
                self.substantiate_stamp(
                    password=password)  # TODO: Derive from keyring

        #
        # ProxyRESTServer and TLSHostingPower # TODO: Maybe we want _power_ups to be public after all?
        #
        if not crypto_power or (TLSHostingPower
                                not in crypto_power._power_ups):

            #
            # Ephemeral Self-Ursula
            #
            if is_me:
                self.suspicious_activities_witnessed = {
                    'vladimirs': [],
                    'bad_treasure_maps': []
                }

                #
                # REST Server (Ephemeral Self-Ursula)
                #
                rest_app, datastore = make_rest_app(
                    db_filepath=db_filepath,
                    network_middleware=self.network_middleware,
                    federated_only=self.federated_only,  # TODO: 466
                    treasure_map_tracker=self.treasure_maps,
                    node_tracker=self.known_nodes,
                    node_bytes_caster=self.__bytes__,
                    work_order_tracker=self._work_orders,
                    node_recorder=self.remember_node,
                    stamp=self.stamp,
                    verifier=self.verify_from,
                    suspicious_activity_tracker=self.
                    suspicious_activities_witnessed,
                    serving_domains=domains,
                )

                #
                # TLSHostingPower (Ephemeral Self-Ursula)
                #
                tls_hosting_keypair = HostingKeypair(
                    curve=tls_curve,
                    host=rest_host,
                    checksum_public_address=self.checksum_public_address)
                tls_hosting_power = TLSHostingPower(
                    keypair=tls_hosting_keypair, host=rest_host)
                self.rest_server = ProxyRESTServer(
                    rest_host=rest_host,
                    rest_port=rest_port,
                    rest_app=rest_app,
                    datastore=datastore,
                    hosting_power=tls_hosting_power)

            #
            # Stranger-Ursula
            #
            else:

                # TLSHostingPower
                if certificate or certificate_filepath:
                    tls_hosting_power = TLSHostingPower(
                        host=rest_host,
                        public_certificate_filepath=certificate_filepath,
                        public_certificate=certificate)
                else:
                    tls_hosting_keypair = HostingKeypair(
                        curve=tls_curve,
                        host=rest_host,
                        generate_certificate=False)
                    tls_hosting_power = TLSHostingPower(
                        host=rest_host, keypair=tls_hosting_keypair)

                # REST Server
                # Unless the caller passed a crypto power we'll make our own TLSHostingPower for this stranger.
                self.rest_server = ProxyRESTServer(
                    rest_host=rest_host,
                    rest_port=rest_port,
                    hosting_power=tls_hosting_power)

            #
            # OK - Now we have a ProxyRestServer and a TLSHostingPower for some Ursula
            #
            self._crypto_power.consume_power_up(tls_hosting_power)  # Consume!

        #
        # Verifiable Node
        #
        certificate_filepath = self._crypto_power.power_ups(
            TLSHostingPower).keypair.certificate_filepath
        certificate = self._crypto_power.power_ups(
            TLSHostingPower).keypair.certificate
        Teacher.__init__(
            self,
            domains=domains,
            certificate=certificate,
            certificate_filepath=certificate_filepath,
            interface_signature=interface_signature,
            timestamp=timestamp,
            identity_evidence=identity_evidence,
            substantiate_immediately=is_me and not federated_only,
        )

        #
        # Logging / Updating
        #
        if is_me:
            self.known_nodes.record_fleet_state(
                additional_nodes_to_track=[self])
            message = "THIS IS YOU: {}: {}".format(self.__class__.__name__,
                                                   self)
            self.log.info(message)
        else:
            message = "Initialized Stranger {} | {}".format(
                self.__class__.__name__, self)
            self.log.debug(message)
コード例 #13
0
ファイル: main.py プロジェクト: lucianstroie/nucypher
def simulate(config, action, nodes, federated_only):
    """
    Simulate the nucypher blockchain network

    Arguments
    ==========

    action - Which action to perform; The choices are:
           - start: Start a multi-process nucypher network simulation
           - stop: Stop a running simulation gracefully

    Options
    ========

    --nodes - The quantity of nodes (processes) to execute during the simulation
    --duration = The number of periods to run the simulation before termination

    """

    if action == 'init':

        # OK, Try connecting to the blockchain
        click.echo("Connecting to provider endpoint")
        config.connect_to_blockchain()

        # Actual simulation setup logic
        one_million_eth = 10**6 * 10**18
        click.echo("Airdropping {} ETH to {} test accounts".format(
            one_million_eth, len(config.accounts)))
        config.blockchain.ether_airdrop(
            amount=one_million_eth)  # wei -> ether | 1 Million ETH

        # Fin
        click.echo("Blockchain initialized")

    if action == 'deploy':

        if config.simulation_running is True:
            raise RuntimeError("Network simulation already running")

        if not federated_only:
            config.connect_to_blockchain()

            click.confirm("Deploy all nucypher contracts to blockchain?",
                          abort=True)
            click.echo("Bootstrapping simulated blockchain network")

            blockchain = TesterBlockchain.from_config()

            # TODO: Enforce Saftey - ensure this is "fake" #
            conditions = ()
            assert True

            # Parse addresses
            etherbase, *everybody_else = blockchain.interface.w3.eth.accounts

            # Deploy contracts
            token_deployer = NucypherTokenDeployer(blockchain=blockchain,
                                                   deployer_address=etherbase)
            token_deployer.arm()
            token_deployer.deploy()
            token_agent = token_deployer.make_agent()
            click.echo("Deployed {}:{}".format(token_agent.contract_name,
                                               token_agent.contract_address))

            miner_escrow_deployer = MinerEscrowDeployer(
                token_agent=token_agent, deployer_address=etherbase)
            miner_escrow_deployer.arm()
            miner_escrow_deployer.deploy()
            miner_agent = miner_escrow_deployer.make_agent()
            click.echo("Deployed {}:{}".format(miner_agent.contract_name,
                                               miner_agent.contract_address))

            policy_manager_deployer = PolicyManagerDeployer(
                miner_agent=miner_agent, deployer_address=etherbase)
            policy_manager_deployer.arm()
            policy_manager_deployer.deploy()
            policy_agent = policy_manager_deployer.make_agent()
            click.echo("Deployed {}:{}".format(policy_agent.contract_name,
                                               policy_agent.contract_address))

            airdrop_amount = 1000000 * int(constants.M)
            click.echo("Airdropping tokens {} to {} addresses".format(
                airdrop_amount, len(everybody_else)))
            _receipts = token_airdrop(token_agent=token_agent,
                                      origin=etherbase,
                                      addresses=everybody_else,
                                      amount=airdrop_amount)

            click.echo("Connecting to deployed contracts")
            config.connect_to_contracts()

            # Commit the current state of deployment to a registry file.
            click.echo("Writing filesystem registry")
            _sim_registry_name = config.blockchain.interface._registry.commit(
                filepath=DEFAULT_SIMULATION_REGISTRY_FILEPATH)

            # Fin
            click.echo("Ready to simulate decentralized swarm.")

        else:
            click.echo("Ready to run federated swarm.")

    elif action == 'swarm':

        if not federated_only:
            config.connect_to_blockchain()
            config.connect_to_contracts(simulation=True)

        localhost = 'localhost'

        # Select a port range to use on localhost for sim servers
        start_port, stop_port = DEFAULT_SIMULATION_PORT, DEFAULT_SIMULATION_PORT + int(
            nodes)
        port_range = range(start_port, stop_port)
        click.echo("Selected local ports {}-{}".format(start_port, stop_port))

        for index, sim_port_number in enumerate(port_range):

            #
            # Parse ursula parameters
            #

            rest_port, dht_port = sim_port_number, sim_port_number + 100
            db_name = 'sim-{}'.format(rest_port)

            proc_params = '''
            run_ursula --host {} --rest-port {} --dht-port {} --db-name {}
            '''.format(localhost, rest_port, dht_port, db_name).split()

            if federated_only:
                click.echo("Setting federated operating mode")
                proc_params.append('--federated-only')
            else:
                sim_address = config.accounts[index + 1]
                miner = Miner(miner_agent=config.miner_agent,
                              checksum_address=sim_address)

                # stake a random amount
                min_stake, balance = constants.MIN_ALLOWED_LOCKED, miner.token_balance
                value = random.randint(min_stake, balance)

                # for a random lock duration
                min_locktime, max_locktime = constants.MIN_LOCKED_PERIODS, constants.MAX_MINTING_PERIODS
                periods = random.randint(min_locktime, max_locktime)

                miner.initialize_stake(amount=value, lock_periods=periods)
                click.echo(
                    "{} Initialized new stake: {} tokens for {} periods".
                    format(sim_address, value, periods))

                proc_params.extend(
                    '--checksum-address {}'.format(sim_address).split())

            # Spawn
            click.echo("Spawning node #{}".format(index + 1))
            processProtocol = UrsulaProcessProtocol(command=proc_params)
            ursula_proc = reactor.spawnProcess(processProtocol, "nucypher-cli",
                                               proc_params)
            config.sim_processes.append(ursula_proc)

            #
            # post-spawnProcess
            #

            # Start with some basic status data, then build on it

            rest_uri = "http://{}:{}".format(localhost, rest_port)
            dht_uri = "http://{}:{}".format(localhost, dht_port)

            sim_data = "Started simulated Ursula | ReST {} | DHT {} ".format(
                rest_uri, dht_uri)
            rest_uri = "{host}:{port}".format(host=localhost,
                                              port=str(sim_port_number))
            dht_uri = '{host}:{port}'.format(host=localhost, port=dht_port)
            sim_data.format(rest_uri, dht_uri)

            if not federated_only:
                stake_infos = tuple(
                    config.miner_agent.get_all_stakes(
                        miner_address=sim_address))
                sim_data += '| ETH address {}'.format(sim_address)
                sim_data += '| {} Active stakes '.format(len(stake_infos))

            click.echo(sim_data)
            config.simulation_running = True

        click.echo("Starting the reactor")
        try:
            reactor.run()

        finally:

            if config.operating_mode == 'decentralized':
                click.echo("Removing simulation registry")
                os.remove(config.sim_registry_filepath)

            click.echo("Stopping simulated Ursula processes")
            for process in config.sim_processes:
                os.kill(process.pid, 9)
                click.echo("Killed {}".format(process))
            config.simulation_running = False
            click.echo("Simulation stopped")

    elif action == 'stop':
        # Kill the simulated ursulas TODO: read PIDs from storage?
        if config.simulation_running is not True:
            raise RuntimeError("Network simulation is not running")

        for process in config.ursula_processes:
            process.transport.signalProcess('KILL')
        else:
            # TODO: Confirm they are dead
            config.simulation_running = False

    elif action == 'status':

        if not config.simulation_running:
            status_message = "Simulation not running."
        else:

            ursula_processes = len(config.ursula_processes)

            status_message = """
            
            | Node Swarm Simulation Status |
            
            Simulation processes .............. {}
            
            """.format(ursula_processes)

        click.echo(status_message)

    elif action == 'demo':
        """Run the finnegans wake demo"""
        demo_exec = os.path.join(BASE_DIR, 'nucypher_cli', 'demos',
                                 'finnegans-wake-demo.py')
        subprocess.run([sys.executable, demo_exec], stdout=subprocess.PIPE)
コード例 #14
0
ファイル: lawful.py プロジェクト: OnGridSystems/nucypher
    def __init__(self,

                 # Ursula
                 rest_host: str,
                 rest_port: int,
                 certificate: Certificate = None,  # TODO: from_certificate classmethod instead, use only filepath..?
                 certificate_filepath: str = None,
                 db_name: str = None,  # TODO: deprecate db_name, use only filepath.?
                 db_filepath: str = None,
                 is_me: bool = True,
                 interface_signature=None,

                 # Blockchain
                 miner_agent=None,
                 checksum_address: str = None,
                 registry_filepath: str = None,

                 # Character
                 abort_on_learning_error: bool = False,
                 federated_only: bool = False,
                 start_learning_now: bool = None,
                 crypto_power=None,
                 tls_curve: EllipticCurve = None,
                 tls_private_key=None,  # TODO: config here. #361
                 known_nodes: Iterable = None,

                 **character_kwargs
                 ) -> None:

        self._work_orders = []

        Character.__init__(self,
                           is_me=is_me,
                           checksum_address=checksum_address,
                           start_learning_now=start_learning_now,
                           federated_only=federated_only,
                           crypto_power=crypto_power,
                           abort_on_learning_error=abort_on_learning_error,
                           known_nodes=known_nodes,
                           **character_kwargs)

        if not federated_only:
            Miner.__init__(self,
                           is_me=is_me,
                           miner_agent=miner_agent,
                           checksum_address=checksum_address,
                           registry_filepath=registry_filepath)

            blockchain_power = BlockchainPower(blockchain=self.blockchain, account=self.checksum_public_address)
            self._crypto_power.consume_power_up(blockchain_power)

        if is_me is True:
            # TODO: 340
            self._stored_treasure_maps = {}
            if not federated_only:
                self.substantiate_stamp()

        if not crypto_power or (TLSHostingPower not in crypto_power._power_ups):
            # TODO: Maybe we want _power_ups to be public after all?
            # We'll hook all the TLS stuff up unless the crypto_power was already passed.

            if is_me:
                self.suspicious_activities_witnessed = {'vladimirs': [], 'bad_treasure_maps': []}

                rest_routes = ProxyRESTRoutes(
                    db_name=db_name,
                    db_filepath=db_filepath,
                    network_middleware=self.network_middleware,
                    federated_only=self.federated_only,
                    treasure_map_tracker=self.treasure_maps,
                    node_tracker=self.known_nodes,
                    node_bytes_caster=self.__bytes__,
                    work_order_tracker=self._work_orders,
                    node_recorder=self.remember_node,
                    stamp=self.stamp,
                    verifier=self.verify_from,
                    suspicious_activity_tracker=self.suspicious_activities_witnessed,
                    certificate_dir=self.known_certificates_dir,
                )

                rest_server = ProxyRESTServer(
                    rest_host=rest_host,
                    rest_port=rest_port,
                    routes=rest_routes,
                )
                self.rest_url = rest_server.rest_url
                self.datastore = rest_routes.datastore  # TODO: Maybe organize this better?

                tls_hosting_keypair = HostingKeypair(
                    common_name=self.checksum_public_address,
                    private_key=tls_private_key,
                    curve=tls_curve,
                    host=rest_host,
                    certificate=certificate,
                    certificate_dir=self.known_certificates_dir)

                tls_hosting_power = TLSHostingPower(rest_server=rest_server,
                                                    keypair=tls_hosting_keypair)

            else:
                # Unless the caller passed a crypto power, we'll make our own TLSHostingPower for this stranger.
                rest_server = ProxyRESTServer(
                    rest_host=rest_host,
                    rest_port=rest_port
                )
                if certificate or certificate_filepath:
                    tls_hosting_power = TLSHostingPower(rest_server=rest_server,
                                                        certificate_filepath=certificate_filepath,
                                                        certificate=certificate,
                                                        certificate_dir=self.known_certificates_dir,
                                                        common_name=self.checksum_public_address,)
                else:
                    tls_hosting_keypair = HostingKeypair(
                        common_name=self.checksum_public_address,
                        curve=tls_curve,
                        host=rest_host,
                        certificate_filepath=certificate_filepath,
                        certificate_dir=self.known_certificates_dir)

                    tls_hosting_power = TLSHostingPower(rest_server=rest_server,
                                                        keypair=tls_hosting_keypair)

            self._crypto_power.consume_power_up(tls_hosting_power)  # Make this work for not me for certificate to work

        else:
            self.log.info("Not adhering rest_server; we'll use the one on crypto_power..")

        certificate_filepath = self._crypto_power.power_ups(TLSHostingPower).keypair.certificate_filepath
        certificate = self._crypto_power.power_ups(TLSHostingPower).keypair.certificate
        # VerifiableNode.from_tls_hosting_power(tls_hosting_power=self._crypto_power.power_ups(TLSHostingPower))  # TODO: use classmethod
        VerifiableNode.__init__(self,
                                certificate=certificate,
                                certificate_filepath=certificate_filepath,
                                interface_signature=interface_signature)

        if is_me:
            message = "Initialized Self {} | {}".format(self.__class__.__name__, self.checksum_public_address)
            self.log.info(message)
        else:
            message = "Initialized Stranger {} | {}".format(self.__class__.__name__, self.checksum_public_address)
            self.log.debug(message)
コード例 #15
0
ファイル: test_actors.py プロジェクト: johanns/nucypher
 def miner(self, chain, mock_token_agent, mock_miner_agent):
     mock_token_agent.token_airdrop(amount=100000 * mock_token_agent.M)
     _origin, ursula, *everybody_else = chain.interface.w3.eth.accounts
     miner = Miner(miner_agent=mock_miner_agent, address=ursula)
     return miner
コード例 #16
0
    def __init__(
            self,

            # Ursula
            rest_host: str,
            rest_port: int,
            certificate: Certificate = None,
            certificate_filepath: str = None,
            tls_private_key=None,  # TODO: Derive from keyring
            db_name: str = None,
            db_filepath: str = None,
            is_me: bool = True,
            interface_signature=None,
            timestamp=None,

            # Blockchain
            miner_agent=None,
            checksum_address: str = None,

            # Character
            passphrase: str = None,
            abort_on_learning_error: bool = False,
            federated_only: bool = False,
            start_learning_now: bool = None,
            crypto_power=None,
            tls_curve: EllipticCurve = None,
            known_nodes: Iterable = None,
            **character_kwargs) -> None:

        #
        # Character
        #
        self._work_orders = list()
        Character.__init__(self,
                           is_me=is_me,
                           checksum_address=checksum_address,
                           start_learning_now=start_learning_now,
                           federated_only=federated_only,
                           crypto_power=crypto_power,
                           abort_on_learning_error=abort_on_learning_error,
                           known_nodes=known_nodes,
                           **character_kwargs)

        #
        # Self-Ursula
        #
        if is_me is True:  # TODO: 340
            self._stored_treasure_maps = dict()

            if not federated_only:
                Miner.__init__(self,
                               is_me=is_me,
                               miner_agent=miner_agent,
                               checksum_address=checksum_address)

                # Access staking node via node's transacting keys
                blockchain_power = BlockchainPower(
                    blockchain=self.blockchain,
                    account=self.checksum_public_address)
                self._crypto_power.consume_power_up(blockchain_power)

                # Use blockchain power to substantiate stamp
                self.substantiate_stamp(passphrase=passphrase)

        #
        # ProxyRESTServer and TLSHostingPower
        #
        if not crypto_power or (TLSHostingPower
                                not in crypto_power._power_ups):
            # TODO: Maybe we want _power_ups to be public after all?
            # We'll hook all the TLS stuff up unless the crypto_power was already passed.

            #
            # Self-Ursula
            #
            if is_me:
                self.suspicious_activities_witnessed = {
                    'vladimirs': [],
                    'bad_treasure_maps': []
                }

                #
                # REST Server
                #
                rest_routes = ProxyRESTRoutes(
                    db_name=db_name,
                    db_filepath=db_filepath,
                    network_middleware=self.network_middleware,
                    federated_only=self.federated_only,  # TODO: 466
                    treasure_map_tracker=self.treasure_maps,
                    node_tracker=self.known_nodes,
                    node_bytes_caster=self.__bytes__,
                    work_order_tracker=self._work_orders,
                    node_recorder=self.remember_node,
                    stamp=self.stamp,
                    verifier=self.verify_from,
                    suspicious_activity_tracker=self.
                    suspicious_activities_witnessed,
                    certificate_dir=self.known_certificates_dir,
                )

                rest_server = ProxyRESTServer(
                    rest_host=rest_host,
                    rest_port=rest_port,
                    routes=rest_routes,
                )
                self.rest_url = rest_server.rest_url
                self.datastore = rest_routes.datastore  # TODO: Maybe organize this better?

                #
                # TLSHostingPower
                #
                tls_hosting_keypair = HostingKeypair(
                    curve=tls_curve,
                    host=rest_host,
                    certificate=certificate,
                    certificate_filepath=certificate_filepath,
                    private_key=tls_private_key)

                tls_hosting_power = TLSHostingPower(
                    rest_server=rest_server, keypair=tls_hosting_keypair)

            #
            # Stranger-Ursula
            #
            else:

                # REST Server
                # Unless the caller passed a crypto power,
                # we'll make our own TLSHostingPower for this stranger.
                rest_server = ProxyRESTServer(rest_host=rest_host,
                                              rest_port=rest_port)

                #
                # TLSHostingPower
                #
                if certificate or certificate_filepath:
                    tls_hosting_power = TLSHostingPower(
                        rest_server=rest_server,
                        certificate_filepath=certificate_filepath,
                        certificate=certificate)
                else:
                    tls_hosting_keypair = HostingKeypair(
                        curve=tls_curve,
                        host=rest_host,
                        certificate_filepath=certificate_filepath)
                    tls_hosting_power = TLSHostingPower(
                        rest_server=rest_server, keypair=tls_hosting_keypair)

            # OK - Now we have a ProxyRestServer and a TLSHostingPower for some Ursula
            self._crypto_power.consume_power_up(tls_hosting_power)  # Consume!

        else:
            self.log.info(
                "Not adhering rest_server; Using the one on crypto_power.")

        #
        # Verifiable Node
        #
        certificate_filepath = self._crypto_power.power_ups(
            TLSHostingPower).keypair.certificate_filepath
        certificate = self._crypto_power.power_ups(
            TLSHostingPower).keypair.certificate
        VerifiableNode.__init__(self,
                                certificate=certificate,
                                certificate_filepath=certificate_filepath,
                                interface_signature=interface_signature,
                                timestamp=timestamp)

        #
        # Logging
        #
        if is_me:
            message = "Initialized Self {} | {}".format(
                self.__class__.__name__, self.checksum_public_address)
            self.log.info(message)
        else:
            message = "Initialized Stranger {} | {}".format(
                self.__class__.__name__, self.checksum_public_address)
            self.log.debug(message)
コード例 #17
0
ファイル: test_felix.py プロジェクト: Howlla/nucypher
def test_run_felix(click_runner, testerchain, deploy_user_input,
                   mock_primary_registry_filepath):

    clock = Clock()
    Felix._CLOCK = clock
    Felix.DISTRIBUTION_INTERVAL = 5  # seconds
    Felix.DISBURSEMENT_INTERVAL = 0.01  # hours
    Felix.STAGING_DELAY = 2  # seconds

    # Main thread (Flask)
    os.environ['NUCYPHER_FELIX_DB_SECRET'] = INSECURE_DEVELOPMENT_PASSWORD

    # Test subproc (Click)
    envvars = {
        'NUCYPHER_KEYRING_PASSWORD': INSECURE_DEVELOPMENT_PASSWORD,
        'NUCYPHER_FELIX_DB_SECRET': INSECURE_DEVELOPMENT_PASSWORD,
        'FLASK_DEBUG': '1'
    }

    # Deploy contracts
    deploy_args = ('contracts', '--registry-outfile',
                   mock_primary_registry_filepath, '--provider-uri',
                   TEST_PROVIDER_URI, '--poa')

    result = click_runner.invoke(deploy.deploy,
                                 deploy_args,
                                 input=deploy_user_input,
                                 catch_exceptions=False,
                                 env=envvars)
    assert result.exit_code == 0

    # Felix creates a system configuration
    init_args = ('felix', 'init', '--checksum-address',
                 testerchain.interface.w3.eth.accounts[0], '--config-root',
                 MOCK_CUSTOM_INSTALLATION_PATH_2, '--network',
                 TEMPORARY_DOMAIN, '--no-registry', '--provider-uri',
                 TEST_PROVIDER_URI)

    result = click_runner.invoke(nucypher_cli,
                                 init_args,
                                 catch_exceptions=False,
                                 env=envvars)
    assert result.exit_code == 0

    configuration_file_location = os.path.join(MOCK_CUSTOM_INSTALLATION_PATH_2,
                                               'felix.config')

    # Felix Creates a Database
    db_args = ('felix', 'createdb', '--config-file',
               configuration_file_location, '--provider-uri',
               TEST_PROVIDER_URI)

    result = click_runner.invoke(nucypher_cli,
                                 db_args,
                                 catch_exceptions=False,
                                 env=envvars)
    assert result.exit_code == 0

    # Felix Runs Web Services
    def run_felix():
        args = ('--debug', 'felix', 'run', '--config-file',
                configuration_file_location, '--provider-uri',
                TEST_PROVIDER_URI, '--dry-run', '--no-registry')

        result = click_runner.invoke(nucypher_cli,
                                     args,
                                     catch_exceptions=False,
                                     env=envvars)
        assert result.exit_code == 0
        return result

    # A (mocked) client requests Felix's services
    def request_felix_landing_page(_result):

        # Init an equal Felix to the already running one.
        felix_config = FelixConfiguration.from_configuration_file(
            filepath=configuration_file_location)
        felix_config.keyring.unlock(password=INSECURE_DEVELOPMENT_PASSWORD)
        felix = felix_config.produce()

        # Make a flask app
        web_app = felix.make_web_app()
        test_client = web_app.test_client()

        # Load the landing page
        response = test_client.get('/')
        assert response.status_code == 200

        # Register a new recipient
        response = test_client.post(
            '/register',
            data={'address': felix.blockchain.interface.w3.eth.accounts[-1]})
        assert response.status_code == 200

        return

    def time_travel(_result):
        clock.advance(amount=60)

    # Record starting ether balance
    recipient = testerchain.interface.w3.eth.accounts[-1]
    miner = Miner(checksum_address=recipient,
                  blockchain=testerchain,
                  is_me=True)
    original_eth_balance = miner.eth_balance

    # Run the callbacks
    d = threads.deferToThread(run_felix)
    d.addCallback(request_felix_landing_page)
    d.addCallback(time_travel)

    yield d

    def confirm_airdrop(_results):
        recipient = testerchain.interface.w3.eth.accounts[-1]
        miner = Miner(checksum_address=recipient,
                      blockchain=testerchain,
                      is_me=True)

        assert miner.token_balance == NU(15000, 'NU')

        new_eth_balance = original_eth_balance + testerchain.interface.w3.fromWei(
            Felix.ETHER_AIRDROP_AMOUNT, 'ether')
        assert miner.eth_balance == new_eth_balance

    staged_airdrops = Felix._AIRDROP_QUEUE
    next_airdrop = staged_airdrops[0]
    next_airdrop.addCallback(confirm_airdrop)
    yield next_airdrop
コード例 #18
0
def test_collect_rewards_integration(click_runner, configuration_file_location,
                                     blockchain_alice, blockchain_bob,
                                     random_policy_label, blockchain_ursulas,
                                     staking_participant, token_economics,
                                     policy_value, policy_rate):

    blockchain = staking_participant.blockchain

    half_stake_time = token_economics.minimum_locked_periods // 2  # Test setup
    logger = staking_participant.log  # Enter the Teacher's Logger, and
    current_period = 1  # State the initial period for incrementing

    miner = Miner(checksum_address=staking_participant.checksum_public_address,
                  blockchain=blockchain,
                  is_me=True)

    pre_stake_eth_balance = miner.eth_balance

    # Finish the passage of time... once and for all
    for _ in range(half_stake_time):
        current_period += 1
        logger.debug(f"period {current_period}")
        blockchain.time_travel(periods=1)
        miner.confirm_activity()

    # Alice creates a policy and grants Bob access
    M, N = 1, 1
    expiration = maya.now() + datetime.timedelta(days=3)
    blockchain_policy = blockchain_alice.grant(
        bob=blockchain_bob,
        label=random_policy_label,
        m=M,
        n=N,
        value=policy_value,
        expiration=expiration,
        handpicked_ursulas={staking_participant})

    # Bob joins the policy
    blockchain_bob.join_policy(random_policy_label,
                               bytes(blockchain_alice.stamp))

    # Enrico Encrypts (of course)
    enrico = Enrico(policy_encrypting_key=blockchain_policy.public_key,
                    network_middleware=MockRestMiddleware())

    verifying_key = blockchain_alice.stamp.as_umbral_pubkey()

    for index in range(half_stake_time - 5):
        logger.debug(f"period {current_period}")
        random_data = os.urandom(random.randrange(20, 100))
        ciphertext, signature = enrico.encrypt_message(message=random_data)

        # Retrieve
        cleartexts = blockchain_bob.retrieve(message_kit=ciphertext,
                                             data_source=enrico,
                                             alice_verifying_key=verifying_key,
                                             label=random_policy_label)
        assert random_data == cleartexts[0]

        # Ursula Staying online and the clock advancing
        blockchain.time_travel(periods=1)
        miner.confirm_activity()
        current_period += 1

    # Finish the passage of time... once and for all
    for _ in range(5):
        current_period += 1
        logger.debug(f"period {current_period}")
        blockchain.time_travel(periods=1)
        miner.confirm_activity()

    #
    # WHERES THE MONEY URSULA?? - Collecting Rewards
    #

    # The address the client wants Ursula to send rewards to
    burner_wallet = blockchain.interface.w3.eth.account.create(
        INSECURE_DEVELOPMENT_PASSWORD)
    # The rewards wallet is initially empty
    assert blockchain.interface.w3.eth.getBalance(burner_wallet.address) == 0

    # Snag a random teacher from the fleet
    random_teacher = list(blockchain_ursulas).pop()

    collection_args = ('--mock-networking', 'ursula', 'collect-reward',
                       '--teacher-uri', random_teacher.rest_interface,
                       '--config-file', configuration_file_location,
                       '--withdraw-address', burner_wallet.address, '--poa',
                       '--force')

    result = click_runner.invoke(nucypher_cli,
                                 collection_args,
                                 input=INSECURE_DEVELOPMENT_PASSWORD,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    collected_reward = blockchain.interface.w3.eth.getBalance(
        burner_wallet.address)
    assert collected_reward != 0

    expected_reward = policy_rate * 30
    assert collected_reward == expected_reward
    assert miner.eth_balance == pre_stake_eth_balance