def test_collect_rewards_integration(
        click_runner, testerchain, agency_local_registry,
        stakeholder_configuration_file_location, blockchain_alice,
        blockchain_bob, random_policy_label, manual_staker, manual_worker,
        token_economics, mock_transacting_power_activation, policy_value,
        policy_rate):

    half_stake_time = token_economics.minimum_locked_periods // 2  # Test setup
    logger = Logger("Test-CLI")  # Enter the Teacher's Logger, and
    current_period = 0  # State the initial period for incrementing

    staker_address = manual_staker
    worker_address = manual_worker

    staker = Staker(is_me=True,
                    checksum_address=staker_address,
                    registry=agency_local_registry)
    staker.refresh_stakes()

    # The staker is staking.
    assert staker.is_staking
    assert staker.stakes
    assert staker.worker_address == worker_address

    ursula_port = select_test_port()
    ursula = Ursula(is_me=True,
                    checksum_address=staker_address,
                    worker_address=worker_address,
                    registry=agency_local_registry,
                    rest_host='127.0.0.1',
                    rest_port=ursula_port,
                    network_middleware=MockRestMiddleware(),
                    db_filepath=tempfile.mkdtemp(),
                    domain=TEMPORARY_DOMAIN)

    MOCK_KNOWN_URSULAS_CACHE[ursula_port] = ursula
    assert ursula.worker_address == worker_address
    assert ursula.checksum_address == staker_address

    mock_transacting_power_activation(account=worker_address,
                                      password=INSECURE_DEVELOPMENT_PASSWORD)

    # Make a commitment for half the first stake duration
    for _ in range(half_stake_time):
        logger.debug(
            f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")
        ursula.commit_to_next_period()
        testerchain.time_travel(periods=1)
        current_period += 1

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

    M, N = 1, 1
    days = 3
    now = testerchain.w3.eth.getBlock('latest').timestamp
    expiration = maya.MayaDT(now).add(days=days - 1)
    blockchain_policy = blockchain_alice.grant(bob=blockchain_bob,
                                               label=random_policy_label,
                                               m=M,
                                               n=N,
                                               value=policy_value,
                                               expiration=expiration,
                                               handpicked_ursulas={ursula})

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

    # Bob learns about the new staker and joins the policy
    blockchain_bob.start_learning_loop()
    blockchain_bob.remember_node(node=ursula)
    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} <<<<<<<<<<<<<<<<")
        ursula.commit_to_next_period()

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

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

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

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

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

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

    # The rewards wallet is initially empty, because it is freshly created
    assert testerchain.client.get_balance(burner_wallet.address) == 0

    # Rewards will be unlocked after the
    # final committed period has passed (+1).
    logger.debug(f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")
    testerchain.time_travel(periods=1)
    current_period += 1
    logger.debug(f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")

    # At least half of the tokens are unlocked (restaking was enabled for some prior periods)
    assert staker.locked_tokens() >= token_economics.minimum_allowed_locked

    # Since we are mocking the blockchain connection, manually consume the transacting power of the Staker.
    mock_transacting_power_activation(account=staker_address,
                                      password=INSECURE_DEVELOPMENT_PASSWORD)

    # Collect Policy Fee
    collection_args = ('stake', 'collect-reward', '--config-file',
                       stakeholder_configuration_file_location, '--policy-fee',
                       '--no-staking-reward', '--staking-address',
                       staker_address, '--withdraw-address',
                       burner_wallet.address)
    result = click_runner.invoke(nucypher_cli,
                                 collection_args,
                                 input=INSECURE_DEVELOPMENT_PASSWORD,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Policy Fee
    collected_policy_fee = testerchain.client.get_balance(
        burner_wallet.address)
    expected_collection = policy_rate * 30
    assert collected_policy_fee == expected_collection

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

    #
    # Collect Staking Reward
    #

    balance_before_collecting = staker.token_agent.get_balance(
        address=staker_address)

    collection_args = ('stake', 'collect-reward', '--config-file',
                       stakeholder_configuration_file_location,
                       '--no-policy-fee', '--staking-reward',
                       '--staking-address', staker_address, '--force')

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

    # The staker has withdrawn her staking rewards
    assert staker.token_agent.get_balance(
        address=staker_address) > balance_before_collecting
예제 #2
0
def paint_stakers(emitter, stakers: List[str],
                  registry: BaseContractRegistry) -> None:
    staking_agent = ContractAgency.get_agent(StakingEscrowAgent,
                                             registry=registry)
    current_period = staking_agent.get_current_period()
    emitter.echo(f"\nCurrent period: {current_period}")
    emitter.echo("\n| Stakers |\n")
    emitter.echo(f"{'Checksum address':42}  Staker information")
    emitter.echo('=' * (42 + 2 + 53))

    for staker_address in stakers:
        staker = Staker(is_me=False,
                        checksum_address=staker_address,
                        registry=registry)
        nickname = Nickname.from_seed(staker_address)
        emitter.echo(
            f"{staker_address}  {'Nickname:':10} {nickname} {nickname.icon}")
        tab = " " * len(staker_address)

        owned_tokens = staker.owned_tokens()
        last_committed_period = staker.last_committed_period
        worker = staker.worker_address
        is_restaking = staker.is_restaking
        is_winding_down = staker.is_winding_down
        is_taking_snapshots = staker.is_taking_snapshots

        missing_commitments = current_period - last_committed_period
        owned_in_nu = round(owned_tokens, 2)
        current_locked_tokens = round(staker.locked_tokens(periods=0), 2)
        next_locked_tokens = round(staker.locked_tokens(periods=1), 2)

        emitter.echo(f"{tab}  {'Owned:':10} {owned_in_nu}")
        emitter.echo(
            f"{tab}  Staked in current period: {current_locked_tokens}")
        emitter.echo(f"{tab}  Staked in next period: {next_locked_tokens}")
        if is_restaking:
            emitter.echo(f"{tab}  {'Re-staking:':10} Yes")
        else:
            emitter.echo(f"{tab}  {'Re-staking:':10} No")
        emitter.echo(
            f"{tab}  {'Winding down:':10} {'Yes' if is_winding_down else 'No'}"
        )
        emitter.echo(
            f"{tab}  {'Snapshots:':10} {'Yes' if is_taking_snapshots else 'No'}"
        )
        emitter.echo(f"{tab}  {'Activity:':10} ", nl=False)
        if missing_commitments == -1:
            emitter.echo(f"Next period committed (#{last_committed_period})",
                         color='green')
        elif missing_commitments == 0:
            emitter.echo(
                f"Current period committed (#{last_committed_period}). "
                f"Pending commitment to next period.",
                color='yellow')
        elif missing_commitments == current_period:
            emitter.echo(f"Never made a commitment", color='red')
        else:
            emitter.echo(
                f"Missing {missing_commitments} commitments "
                f"(last time for period #{last_committed_period})",
                color='red')

        emitter.echo(f"{tab}  {'Worker:':10} ", nl=False)
        if worker == NULL_ADDRESS:
            emitter.echo(f"Worker not bonded", color='red')
        else:
            emitter.echo(f"{worker}")

        fees = prettify_eth_amount(staker.calculate_policy_fee())
        emitter.echo(f"{tab}  Unclaimed fees: {fees}")

        min_rate = prettify_eth_amount(staker.min_fee_rate)
        emitter.echo(f"{tab}  Min fee rate: {min_rate}")
def test_collect_rewards_integration(click_runner, testerchain,
                                     stakeholder_configuration_file_location,
                                     blockchain_alice, blockchain_bob,
                                     random_policy_label, manual_staker,
                                     manual_worker, token_economics,
                                     policy_value, policy_rate):

    half_stake_time = token_economics.minimum_locked_periods // 2  # Test setup
    logger = Logger("Test-CLI")  # Enter the Teacher's Logger, and
    current_period = 0  # State the initial period for incrementing

    staker_address = manual_staker
    worker_address = manual_worker

    staker = Staker(is_me=True,
                    checksum_address=staker_address,
                    blockchain=testerchain)

    # The staker is staking.
    assert staker.stakes
    assert staker.is_staking
    assert staker.worker_address == worker_address

    ursula_port = select_test_port()
    ursula = Ursula(is_me=True,
                    checksum_address=staker_address,
                    worker_address=worker_address,
                    blockchain=testerchain,
                    rest_host='127.0.0.1',
                    rest_port=ursula_port,
                    network_middleware=MockRestMiddleware())

    MOCK_KNOWN_URSULAS_CACHE[ursula_port] = ursula
    assert ursula.worker_address == worker_address
    assert ursula.checksum_address == staker_address

    # Mock TransactingPower consumption (Worker-Ursula)
    ursula.blockchain.transacting_power = TransactingPower(
        account=worker_address,
        password=INSECURE_DEVELOPMENT_PASSWORD,
        blockchain=testerchain)
    ursula.blockchain.transacting_power.activate()

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

    # 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={ursula})

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

    # Bob learns about the new staker and joins the policy
    blockchain_bob.start_learning_loop()
    blockchain_bob.remember_node(node=ursula)
    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):
        ursula.confirm_activity()

        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
        testerchain.time_travel(periods=1)
        current_period += 1

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

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

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

    # The rewards wallet is initially empty, because it is freshly created
    assert testerchain.client.get_balance(burner_wallet.address) == 0

    # Rewards will be unlocked after the
    # final confirmed period has passed (+1).
    testerchain.time_travel(periods=1)
    current_period += 1
    logger.debug(f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")

    # Half of the tokens are unlocked.
    assert staker.locked_tokens() == token_economics.minimum_allowed_locked

    # Simulate "Reconnection" within the CLI process to the testerchain
    def connect(self, *args, **kwargs):
        self._attach_provider(testerchain.provider)
        self.w3 = self.Web3(provider=self._provider)
        self.client = Web3Client.from_w3(w3=self.w3)

    BlockchainInterface.connect = connect

    # Since we are mocking the blockchain connection, manually consume the transacting power of the Staker.
    testerchain.transacting_power = TransactingPower(
        account=staker_address,
        password=INSECURE_DEVELOPMENT_PASSWORD,
        blockchain=testerchain)
    testerchain.transacting_power.activate()

    # Collect Policy Reward
    collection_args = ('stake', 'collect-reward', '--mock-networking',
                       '--config-file',
                       stakeholder_configuration_file_location,
                       '--policy-reward', '--no-staking-reward',
                       '--staking-address', staker_address,
                       '--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 = testerchain.client.get_balance(
        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):
        ursula.confirm_activity()
        current_period += 1
        logger.debug(
            f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")
        testerchain.time_travel(periods=1)

    # Collect Inflation Reward
    collection_args = ('stake', 'collect-reward', '--mock-networking',
                       '--config-file',
                       stakeholder_configuration_file_location,
                       '--no-policy-reward', '--staking-reward',
                       '--staking-address', staker_address,
                       '--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

    # The burner wallet has the reward ethers
    assert staker.token_agent.get_balance(address=staker_address)
예제 #4
0
def test_adjudicator_slashes(agency, testerchain, mock_ursula_reencrypts,
                             token_economics, test_registry, mocker):

    staker_account = testerchain.staker_account(0)
    worker_account = testerchain.ursula_account(0)

    ##### STAKING ESCROW STUFF #####

    token_agent, staking_agent, _policy_agent = agency

    locked_tokens = token_economics.minimum_allowed_locked * 5

    # Mock Powerup consumption (Deployer)
    testerchain.transacting_power = TransactingPower(
        password=INSECURE_DEVELOPMENT_PASSWORD,
        account=testerchain.etherbase_account)
    testerchain.transacting_power.activate()

    # The staker receives an initial amount of tokens
    _txhash = token_agent.transfer(
        amount=locked_tokens,
        target_address=staker_account,
        sender_address=testerchain.etherbase_account)

    # Mock Powerup consumption (Staker)
    testerchain.transacting_power = TransactingPower(
        password=INSECURE_DEVELOPMENT_PASSWORD, account=staker_account)
    testerchain.transacting_power.activate()

    # Deposit: The staker deposits tokens in the StakingEscrow contract.
    staker = Staker(checksum_address=staker_account,
                    is_me=True,
                    registry=test_registry)
    staker.initialize_stake(
        amount=NU(locked_tokens, 'NuNit'),
        lock_periods=token_economics.minimum_locked_periods)
    assert staker.locked_tokens(periods=1) == locked_tokens

    # The staker hasn't set a worker yet
    assert BlockchainInterface.NULL_ADDRESS == staking_agent.get_worker_from_staker(
        staker_address=staker_account)

    _txhash = staking_agent.set_worker(staker_address=staker_account,
                                       worker_address=worker_account)

    assert worker_account == staking_agent.get_worker_from_staker(
        staker_address=staker_account)
    assert staker_account == staking_agent.get_staker_from_worker(
        worker_address=worker_account)

    ###### END OF STAKING ESCROW STUFF ####

    adjudicator_agent = AdjudicatorAgent(registry=test_registry)
    bob_account = testerchain.bob_account
    bobby = NucypherTokenActor(checksum_address=bob_account,
                               registry=test_registry)
    ursula = mock_ursula(testerchain, worker_account, mocker=mocker)

    # Let's create a bad cfrag
    evidence = mock_ursula_reencrypts(ursula, corrupt_cfrag=True)

    assert not adjudicator_agent.was_this_evidence_evaluated(evidence)
    bobby_old_balance = bobby.token_balance

    # Mock Powerup consumption (Bob)
    testerchain.transacting_power = TransactingPower(
        password=INSECURE_DEVELOPMENT_PASSWORD, account=bob_account)
    testerchain.transacting_power.activate()

    adjudicator_agent.evaluate_cfrag(evidence=evidence,
                                     sender_address=bob_account)

    assert adjudicator_agent.was_this_evidence_evaluated(evidence)
    investigator_reward = bobby.token_balance - bobby_old_balance

    assert investigator_reward > 0
    assert investigator_reward == token_economics.base_penalty / token_economics.reward_coefficient
    assert staker.locked_tokens(periods=1) < locked_tokens
예제 #5
0
def test_investigator_requests_slashing(testerchain,
                                        test_registry,
                                        agency,
                                        #mock_ursula_reencrypts,
                                        token_economics,
                                        mocker):

    staker_account = testerchain.staker_account(0)
    worker_account = testerchain.ursula_account(0)

    ##### STAKING ESCROW STUFF #####

    token_agent = ContractAgency.get_agent(NucypherTokenAgent, registry=test_registry)
    staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=test_registry)

    locked_tokens = token_economics.minimum_allowed_locked * 5

    # The staker receives an initial amount of tokens
    tpower = TransactingPower(account=testerchain.etherbase_account, signer=Web3Signer(testerchain.client))
    _txhash = token_agent.transfer(amount=locked_tokens,
                                   target_address=staker_account,
                                   transacting_power=tpower)

    # Deposit: The staker deposits tokens in the StakingEscrow contract.
    staker_tpower = TransactingPower(account=staker_account, signer=Web3Signer(testerchain.client))
    staker = Staker(transacting_power=staker_tpower,
                    domain=TEMPORARY_DOMAIN,
                    registry=test_registry)

    staker.initialize_stake(amount=NU(locked_tokens, 'NuNit'),
                            lock_periods=token_economics.minimum_locked_periods)
    assert staker.locked_tokens(periods=1) == locked_tokens

    # The staker hasn't bond a worker yet
    assert NULL_ADDRESS == staking_agent.get_worker_from_staker(staker_address=staker_account)

    _txhash = staking_agent.bond_worker(transacting_power=staker_tpower, worker_address=worker_account)

    assert worker_account == staking_agent.get_worker_from_staker(staker_address=staker_account)
    assert staker_account == staking_agent.get_staker_from_worker(worker_address=worker_account)

    ###### END OF STAKING ESCROW STUFF ####

    bob_account = testerchain.bob_account
    bob_tpower = TransactingPower(account=bob_account, signer=Web3Signer(testerchain.client))
    investigator = Investigator(registry=test_registry,
                                transacting_power=bob_tpower,
                                domain=TEMPORARY_DOMAIN)
    ursula = mock_ursula(testerchain, worker_account, mocker=mocker)

    # Let's create a bad cfrag
    evidence = mock_ursula_reencrypts(ursula, corrupt_cfrag=True)

    assert not investigator.was_this_evidence_evaluated(evidence)
    bobby_old_balance = investigator.token_balance

    investigator.request_evaluation(evidence=evidence)

    assert investigator.was_this_evidence_evaluated(evidence)
    investigator_reward = investigator.token_balance - bobby_old_balance

    assert investigator_reward > 0
    assert investigator_reward == token_economics.base_penalty / token_economics.reward_coefficient
    assert staker.locked_tokens(periods=1) < locked_tokens
예제 #6
0
def test_investigator_requests_slashing(testerchain, test_registry, agency,
                                        mock_ursula_reencrypts,
                                        token_economics,
                                        mock_transacting_power_activation,
                                        mocker):

    staker_account = testerchain.staker_account(0)
    worker_account = testerchain.ursula_account(0)

    ##### STAKING ESCROW STUFF #####

    token_agent, staking_agent, _policy_agent = agency

    locked_tokens = token_economics.minimum_allowed_locked * 5

    mock_transacting_power_activation(account=testerchain.etherbase_account,
                                      password=INSECURE_DEVELOPMENT_PASSWORD)

    # The staker receives an initial amount of tokens
    _txhash = token_agent.transfer(
        amount=locked_tokens,
        target_address=staker_account,
        sender_address=testerchain.etherbase_account)

    mock_transacting_power_activation(account=staker_account,
                                      password=INSECURE_DEVELOPMENT_PASSWORD)

    # Deposit: The staker deposits tokens in the StakingEscrow contract.
    staker = Staker(checksum_address=staker_account,
                    is_me=True,
                    registry=test_registry)
    staker.initialize_stake(
        amount=NU(locked_tokens, 'NuNit'),
        lock_periods=token_economics.minimum_locked_periods)
    assert staker.locked_tokens(periods=1) == locked_tokens

    # The staker hasn't bond a worker yet
    assert NULL_ADDRESS == staking_agent.get_worker_from_staker(
        staker_address=staker_account)

    _txhash = staking_agent.bond_worker(staker_address=staker_account,
                                        worker_address=worker_account)

    assert worker_account == staking_agent.get_worker_from_staker(
        staker_address=staker_account)
    assert staker_account == staking_agent.get_staker_from_worker(
        worker_address=worker_account)

    ###### END OF STAKING ESCROW STUFF ####

    bob_account = testerchain.bob_account

    investigator = Investigator(registry=test_registry,
                                checksum_address=bob_account)
    ursula = mock_ursula(testerchain, worker_account, mocker=mocker)

    # Let's create a bad cfrag
    evidence = mock_ursula_reencrypts(ursula, corrupt_cfrag=True)

    assert not investigator.was_this_evidence_evaluated(evidence)
    bobby_old_balance = investigator.token_balance

    mock_transacting_power_activation(account=bob_account,
                                      password=INSECURE_DEVELOPMENT_PASSWORD)

    investigator.request_evaluation(evidence=evidence)

    assert investigator.was_this_evidence_evaluated(evidence)
    investigator_reward = investigator.token_balance - bobby_old_balance

    assert investigator_reward > 0
    assert investigator_reward == token_economics.base_penalty / token_economics.reward_coefficient
    assert staker.locked_tokens(periods=1) < locked_tokens
def test_collect_rewards_integration(
        click_runner, testerchain, agency_local_registry,
        stakeholder_configuration_file_location, blockchain_alice,
        blockchain_bob, random_policy_label, manual_staker, manual_worker,
        token_economics, policy_value):

    half_stake_time = 2 * token_economics.minimum_locked_periods  # Test setup
    logger = Logger("Test-CLI")  # Enter the Teacher's Logger, and
    current_period = 0  # State the initial period for incrementing

    staker_address = manual_staker
    worker_address = manual_worker

    staker = Staker(domain=TEMPORARY_DOMAIN,
                    checksum_address=staker_address,
                    registry=agency_local_registry)
    staker.refresh_stakes()

    # The staker is staking.
    assert staker.is_staking
    assert staker.stakes
    assert staker.worker_address == worker_address

    ursula_port = select_test_port()
    ursula = Ursula(is_me=True,
                    checksum_address=staker_address,
                    signer=Web3Signer(testerchain.client),
                    worker_address=worker_address,
                    registry=agency_local_registry,
                    rest_host=LOOPBACK_ADDRESS,
                    rest_port=ursula_port,
                    provider_uri=TEST_PROVIDER_URI,
                    network_middleware=MockRestMiddleware(),
                    db_filepath=tempfile.mkdtemp(),
                    domain=TEMPORARY_DOMAIN)

    MOCK_KNOWN_URSULAS_CACHE[ursula_port] = ursula
    assert ursula.worker_address == worker_address
    assert ursula.checksum_address == staker_address

    # Make a commitment for half the first stake duration
    testerchain.time_travel(periods=1)
    for _ in range(half_stake_time):
        logger.debug(
            f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")
        ursula.commit_to_next_period()
        testerchain.time_travel(periods=1)
        current_period += 1

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

    threshold, shares = 1, 1
    duration_in_periods = 3
    days = (duration_in_periods - 1) * (token_economics.hours_per_period // 24)
    now = testerchain.w3.eth.getBlock('latest').timestamp
    expiration = maya.MayaDT(now).add(days=days)
    blockchain_policy = blockchain_alice.grant(bob=blockchain_bob,
                                               label=random_policy_label,
                                               threshold=threshold,
                                               shares=shares,
                                               value=policy_value,
                                               expiration=expiration,
                                               ursulas={ursula})

    # Ensure that the handpicked Ursula was selected for the policy
    treasure_map = blockchain_bob._decrypt_treasure_map(
        blockchain_policy.treasure_map,
        blockchain_policy.publisher_verifying_key)
    assert ursula.canonical_address in treasure_map.destinations

    # Bob learns about the new staker and joins the policy
    blockchain_bob.start_learning_loop()
    blockchain_bob.remember_node(node=ursula)

    # 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} <<<<<<<<<<<<<<<<")
        ursula.commit_to_next_period()

        # Encrypt
        random_data = os.urandom(random.randrange(20, 100))
        message_kit = enrico.encrypt_message(plaintext=random_data)

        # Decrypt
        cleartexts = blockchain_bob.retrieve_and_decrypt(
            [message_kit],
            alice_verifying_key=verifying_key,
            encrypted_treasure_map=blockchain_policy.treasure_map)
        assert random_data == cleartexts[0]

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

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

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

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

    # The rewards wallet is initially empty, because it is freshly created
    assert testerchain.client.get_balance(burner_wallet.address) == 0

    # Rewards will be unlocked after the
    # final committed period has passed (+1).
    logger.debug(f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")
    testerchain.time_travel(periods=1)
    current_period += 1
    logger.debug(f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")

    # At least half of the tokens are unlocked (restaking was enabled for some prior periods)
    assert staker.locked_tokens() >= token_economics.minimum_allowed_locked

    # Collect Policy Fee
    collection_args = ('stake', 'rewards', 'withdraw', '--config-file',
                       str(stakeholder_configuration_file_location.absolute()),
                       '--fees', '--no-tokens', '--staking-address',
                       staker_address, '--withdraw-address',
                       burner_wallet.address)
    result = click_runner.invoke(nucypher_cli,
                                 collection_args,
                                 input=INSECURE_DEVELOPMENT_PASSWORD,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Policy Fee
    collected_policy_fee = testerchain.client.get_balance(
        burner_wallet.address)
    expected_collection = policy_value
    assert collected_policy_fee == expected_collection

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

    #
    # Collect Staking Reward
    #

    balance_before_collecting = staker.token_agent.get_balance(
        address=staker_address)

    collection_args = ('stake', 'rewards', 'withdraw', '--config-file',
                       str(stakeholder_configuration_file_location.absolute()),
                       '--no-fees', '--tokens', '--staking-address',
                       staker_address, '--force')

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

    # The staker has withdrawn her staking rewards
    assert staker.token_agent.get_balance(
        address=staker_address) > balance_before_collecting
예제 #8
0
def test_investigator_requests_slashing(session_testerchain,
                                        session_agency,
                                        mock_ursula_reencrypts,
                                        token_economics,
                                        slashing_economics):
    testerchain = session_testerchain

    staker_account = testerchain.staker_account(0)
    worker_account = testerchain.ursula_account(0)

    ##### STAKING ESCROW STUFF #####

    token_agent, staking_agent, _policy_agent = session_agency

    locked_tokens = token_economics.minimum_allowed_locked * 5

    # Mock Powerup consumption (Deployer)
    testerchain.transacting_power = TransactingPower(blockchain=testerchain, account=testerchain.etherbase_account)
    testerchain.transacting_power.activate()

    # The staker receives an initial amount of tokens
    _txhash = token_agent.transfer(amount=locked_tokens,
                                   target_address=staker_account,
                                   sender_address=testerchain.etherbase_account)

    # Mock Powerup consumption (Staker)
    testerchain.transacting_power = TransactingPower(blockchain=testerchain, account=staker_account)
    testerchain.transacting_power.activate()

    # Deposit: The staker deposits tokens in the StakingEscrow contract.
    staker = Staker(checksum_address=staker_account, is_me=True, blockchain=testerchain)
    staker.initialize_stake(amount=NU(locked_tokens, 'NuNit'),
                            lock_periods=token_economics.minimum_locked_periods)
    assert staker.locked_tokens(periods=1) == locked_tokens

    # The staker hasn't set a worker yet
    assert BlockchainInterface.NULL_ADDRESS == staking_agent.get_worker_from_staker(staker_address=staker_account)

    _txhash = staking_agent.set_worker(staker_address=staker_account,
                                       worker_address=worker_account)

    assert worker_account == staking_agent.get_worker_from_staker(staker_address=staker_account)
    assert staker_account == staking_agent.get_staker_from_worker(worker_address=worker_account)

    ###### END OF STAKING ESCROW STUFF ####

    bob_account = testerchain.bob_account

    investigator = Investigator(blockchain=testerchain, checksum_address=bob_account)
    ursula = mock_ursula(testerchain, worker_account)

    # Let's create a bad cfrag
    evidence = mock_ursula_reencrypts(ursula, corrupt_cfrag=True)

    assert not investigator.was_this_evidence_evaluated(evidence)
    bobby_old_balance = investigator.token_balance

    # Mock Powerup consumption (Bob)
    testerchain.transacting_power = TransactingPower(blockchain=testerchain, account=bob_account)
    testerchain.transacting_power.activate()

    investigator.request_evaluation(evidence=evidence)

    assert investigator.was_this_evidence_evaluated(evidence)
    investigator_reward = investigator.token_balance - bobby_old_balance

    assert investigator_reward > 0
    assert investigator_reward == slashing_economics.base_penalty / slashing_economics.reward_coefficient
    assert staker.locked_tokens(periods=1) < locked_tokens