示例#1
0
def test_run_lone_federated_default_development_ursula(click_runner):
    deploy_port = select_test_port()
    args = (
        'ursula',
        'run',  # Stat Ursula Command
        '--debug',  # Display log output; Do not attach console
        '--federated-only',  # Operating Mode
        '--rest-port',
        deploy_port,  # Network Port
        '--dev',  # Run in development mode (ephemeral node)
        '--dry-run',  # Disable twisted reactor in subprocess
        '--lonely'  # Do not load seednodes
    )

    result = yield threads.deferToThread(click_runner.invoke,
                                         nucypher_cli,
                                         args,
                                         catch_exceptions=False,
                                         input=INSECURE_DEVELOPMENT_PASSWORD +
                                         '\n')

    time.sleep(Learner._SHORT_LEARNING_DELAY)
    assert result.exit_code == 0, result.output
    assert "Running" in result.output
    assert "127.0.0.1:{}".format(deploy_port) in result.output

    reserved_ports = (UrsulaConfiguration.DEFAULT_REST_PORT,
                      UrsulaConfiguration.DEFAULT_DEVELOPMENT_REST_PORT)
    assert deploy_port not in reserved_ports
def test_ursula_init(click_runner, custom_filepath, agency_local_registry,
                     manual_staker, manual_worker, testerchain):

    deploy_port = select_test_port()

    init_args = ('ursula', 'init', '--network', TEMPORARY_DOMAIN,
                 '--worker-address', manual_worker, '--config-root',
                 str(custom_filepath.absolute()), '--provider',
                 TEST_PROVIDER_URI, '--registry-filepath',
                 str(agency_local_registry.filepath.absolute()), '--rest-host',
                 MOCK_IP_ADDRESS, '--rest-port', deploy_port)

    result = click_runner.invoke(nucypher_cli,
                                 init_args,
                                 input=FAKE_PASSWORD_CONFIRMED,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Files and Directories
    assert custom_filepath.is_dir(), 'Configuration file does not exist'
    assert (custom_filepath / 'keystore').is_dir(), 'KEYSTORE does not exist'
    assert (custom_filepath /
            'known_nodes').is_dir(), 'known_nodes directory does not exist'

    custom_config_filepath = custom_filepath / UrsulaConfiguration.generate_filename(
    )
    assert custom_config_filepath.is_file(
    ), 'Configuration file does not exist'

    with open(custom_config_filepath, 'r') as config_file:
        raw_config_data = config_file.read()
        config_data = json.loads(raw_config_data)
        assert config_data['provider_uri'] == TEST_PROVIDER_URI
        assert config_data['worker_address'] == manual_worker
        assert TEMPORARY_DOMAIN == config_data['domain']
示例#3
0
def test_blockchain_porter_cli_run_simple(click_runner,
                                          blockchain_ursulas,
                                          testerchain,
                                          agency_local_registry,
                                          blockchain_teacher_uri):
    porter_run_command = ('porter', 'run',
                          '--dry-run',
                          '--network', TEMPORARY_DOMAIN,
                          '--eth-provider', TEST_ETH_PROVIDER_URI,
                          '--registry-filepath', agency_local_registry.filepath,
                          '--teacher', blockchain_teacher_uri)
    result = click_runner.invoke(nucypher_cli, porter_run_command, catch_exceptions=False)
    assert result.exit_code == 0
    output = result.output
    assert f"Network: {TEMPORARY_DOMAIN}" in output
    assert f"ETH Provider URI: {TEST_ETH_PROVIDER_URI}" in output
    assert PORTER_RUN_MESSAGE.format(http_scheme="http", http_port=Porter.DEFAULT_PORT) in output

    # Non-default port
    non_default_port = select_test_port()
    porter_run_command = ('porter', 'run',
                          '--dry-run',
                          '--network', TEMPORARY_DOMAIN,
                          '--eth-provider', TEST_ETH_PROVIDER_URI,
                          '--registry-filepath', agency_local_registry.filepath,
                          '--http-port', non_default_port,
                          '--teacher', blockchain_teacher_uri)
    result = click_runner.invoke(nucypher_cli, porter_run_command, catch_exceptions=False)
    assert result.exit_code == 0
    output = result.output
    assert f"Network: {TEMPORARY_DOMAIN}" in output
    assert f"ETH Provider URI: {TEST_ETH_PROVIDER_URI}" in output
    assert PORTER_RUN_MESSAGE.format(http_scheme="http", http_port=non_default_port) in output
示例#4
0
def test_federated_porter_cli_run_simple(click_runner, federated_ursulas,
                                         federated_teacher_uri):
    porter_run_command = ('porter', 'run', '--dry-run', '--federated-only',
                          '--teacher', federated_teacher_uri)
    result = click_runner.invoke(nucypher_cli,
                                 porter_run_command,
                                 catch_exceptions=False)
    assert result.exit_code == 0
    output = result.output
    assert f"Network: {TEMPORARY_DOMAIN}" in output
    assert PORTER_RUN_MESSAGE.format(http_scheme="http",
                                     http_port=Porter.DEFAULT_PORT) in output

    # Non-default port
    non_default_port = select_test_port()
    porter_run_command = ('porter', 'run', '--dry-run', '--federated-only',
                          '--http-port', non_default_port, '--teacher',
                          federated_teacher_uri)
    result = click_runner.invoke(nucypher_cli,
                                 porter_run_command,
                                 catch_exceptions=False)
    assert result.exit_code == 0
    output = result.output
    assert f"Network: {TEMPORARY_DOMAIN}" in output
    assert PORTER_RUN_MESSAGE.format(http_scheme="http",
                                     http_port=non_default_port) in output
def test_initialize_custom_configuration_root(custom_filepath, click_runner):

    deploy_port = select_test_port()
    # Use a custom local filepath for configuration
    init_args = ('ursula', 'init',
                 '--network', TEMPORARY_DOMAIN,
                 '--federated-only',
                 '--config-root', custom_filepath,
                 '--rest-host', MOCK_IP_ADDRESS,
                 '--rest-port', deploy_port)
    result = click_runner.invoke(nucypher_cli, init_args, input=FAKE_PASSWORD_CONFIRMED, catch_exceptions=False)
    assert result.exit_code == 0

    # CLI Output
    assert str(MOCK_CUSTOM_INSTALLATION_PATH) in result.output, "Configuration not in system temporary directory"
    assert "nucypher ursula run" in result.output, 'Help message is missing suggested command'
    assert 'IPv4' not in result.output

    # Files and Directories
    assert os.path.isdir(custom_filepath), 'Configuration file does not exist'
    assert os.path.isdir(os.path.join(custom_filepath, 'keyring')), 'Keyring does not exist'
    assert os.path.isdir(os.path.join(custom_filepath, 'known_nodes')), 'known_nodes directory does not exist'

    custom_config_filepath = os.path.join(custom_filepath, UrsulaConfiguration.generate_filename())
    assert os.path.isfile(custom_config_filepath), 'Configuration file does not exist'

    # Auth
    assert 'Enter NuCypher keyring password' in result.output, 'WARNING: User was not prompted for password'
    assert 'Repeat for confirmation:' in result.output, 'User was not prompted to confirm password'
def test_refund(click_runner, testerchain, agency_local_registry,
                token_economics):

    bidder = testerchain.client.accounts[2]
    worker_address = testerchain.unassigned_accounts[-1]

    #
    # WorkLock Staker-Worker
    #

    worklock_agent = ContractAgency.get_agent(WorkLockAgent,
                                              registry=agency_local_registry)

    # Bidder is now STAKER. Bond a worker.
    staker = Staker(is_me=True,
                    checksum_address=bidder,
                    registry=agency_local_registry)
    receipt = staker.bond_worker(worker_address=worker_address)
    assert receipt['status'] == 1

    worker = Ursula(is_me=True,
                    registry=agency_local_registry,
                    checksum_address=bidder,
                    worker_address=worker_address,
                    rest_host=MOCK_IP_ADDRESS,
                    rest_port=select_test_port(),
                    db_filepath=tempfile.mkdtemp())

    # Ensure there is work to do
    remaining_work = worklock_agent.get_remaining_work(checksum_address=bidder)
    assert remaining_work > 0

    # Unlock
    transacting_power = worker._crypto_power.power_ups(TransactingPower)
    transacting_power.activate(password=INSECURE_DEVELOPMENT_PASSWORD)

    # Do some work
    for i in range(3):
        txhash = worker.commit_to_next_period()
        testerchain.wait_for_receipt(txhash)
        assert receipt['status'] == 1
        testerchain.time_travel(periods=1)

    command = ('refund', '--participant-address', bidder,
               '--registry-filepath', agency_local_registry.filepath,
               '--provider', TEST_PROVIDER_URI, '--network', TEMPORARY_DOMAIN,
               '--force')

    user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n' + 'Y\n'
    result = click_runner.invoke(worklock,
                                 command,
                                 input=user_input,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # Less work to do...
    new_remaining_work = worklock_agent.get_remaining_work(
        checksum_address=bidder)
    assert new_remaining_work < remaining_work
示例#7
0
def test_federated_ursula_learns_via_cli(click_runner, federated_ursulas):
    # Establish a running Teacher Ursula

    teacher = list(federated_ursulas)[0]
    teacher_uri = teacher.seed_node_metadata(as_teacher_uri=True)

    deploy_port = select_test_port()

    def run_ursula():
        i = start_pytest_ursula_services(ursula=teacher)
        args = (
            'ursula',
            'run',
            '--debug',  # Display log output; Do not attach console
            '--federated-only',  # Operating Mode
            '--rest-port',
            deploy_port,  # Network Port
            '--teacher',
            teacher_uri,
            '--dev',  # Run in development mode (ephemeral node)
            '--dry-run'  # Disable twisted reactor
        )

        return threads.deferToThread(click_runner.invoke,
                                     nucypher_cli,
                                     args,
                                     catch_exceptions=False,
                                     input=INSECURE_DEVELOPMENT_PASSWORD +
                                     '\n')

    # Run the Callbacks
    d = run_ursula()
    yield d

    result = d.result

    assert result.exit_code == 0
    assert "Starting services" in result.output
    assert f"127.0.0.1:{deploy_port}" in result.output

    reserved_ports = (UrsulaConfiguration.DEFAULT_REST_PORT,
                      UrsulaConfiguration.DEFAULT_DEVELOPMENT_REST_PORT)
    assert deploy_port not in reserved_ports

    # Check that CLI Ursula reports that it remembers the teacher and saves the TLS certificate
    assert teacher.checksum_address in result.output
    assert f"Saved TLS certificate for {teacher.nickname}" in result.output

    federated_ursulas.clear()
示例#8
0
def test_initialize_custom_configuration_root(click_runner,
                                              custom_filepath: Path):

    deploy_port = select_test_port()
    # Use a custom local filepath for configuration
    init_args = ('ursula', 'init', '--network', TEMPORARY_DOMAIN,
                 '--federated-only', '--config-root',
                 str(custom_filepath.absolute()), '--rest-host',
                 MOCK_IP_ADDRESS, '--rest-port', deploy_port)
    result = click_runner.invoke(nucypher_cli,
                                 init_args,
                                 input=FAKE_PASSWORD_CONFIRMED,
                                 catch_exceptions=False)
    assert result.exit_code == 0

    # CLI Output
    assert str(
        MOCK_CUSTOM_INSTALLATION_PATH
    ) in result.output, "Configuration not in system temporary directory"
    assert "nucypher ursula run" in result.output, 'Help message is missing suggested command'
    assert 'IPv4' not in result.output

    # Files and Directories
    assert custom_filepath.is_dir(), 'Configuration file does not exist'
    assert (custom_filepath / 'keystore').is_dir(), 'KEYSTORE does not exist'

    # TODO: Only using in-memory node storage for now
    # assert (custom_filepath / 'known_nodes').is_dir(), 'known_nodes directory does not exist'
    assert not (custom_filepath /
                'known_nodes').is_dir(), 'known_nodes directory does not exist'

    custom_config_filepath = custom_filepath / UrsulaConfiguration.generate_filename(
    )
    assert custom_config_filepath.is_file(
    ), 'Configuration file does not exist'

    # Auth
    assert COLLECT_NUCYPHER_PASSWORD in result.output, 'WARNING: User was not prompted for password'
    assert 'Repeat for confirmation:' in result.output, 'User was not prompted to confirm password'
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
def test_ursula_and_local_keystore_signer_integration(
        click_runner, tmp_path, staking_providers, application_economics,
        mocker, mock_funded_account_password_keystore, testerchain):
    config_root_path = tmp_path
    ursula_config_path = config_root_path / UrsulaConfiguration.generate_filename(
    )
    worker_account, password, mock_keystore_path = mock_funded_account_password_keystore

    #
    # Operator Steps
    #

    # Good signer...
    mock_signer_uri = f'keystore:{mock_keystore_path}'
    pre_config_signer = KeystoreSigner.from_signer_uri(uri=mock_signer_uri,
                                                       testnet=True)
    assert worker_account.address in pre_config_signer.accounts

    deploy_port = select_test_port()

    init_args = (
        'ursula',
        'init',
        '--network',
        TEMPORARY_DOMAIN,
        '--payment-network',
        TEMPORARY_DOMAIN,
        '--operator-address',
        worker_account.address,
        '--config-root',
        str(config_root_path.absolute()),
        '--eth-provider',
        TEST_ETH_PROVIDER_URI,
        '--payment-provider',
        TEST_POLYGON_PROVIDER_URI,
        '--rest-host',
        MOCK_IP_ADDRESS,
        '--rest-port',
        deploy_port,

        # The bit we are testing for here
        '--signer',
        mock_signer_uri)

    cli_env = {
        NUCYPHER_ENVVAR_KEYSTORE_PASSWORD: password,
        NUCYPHER_ENVVAR_OPERATOR_ETH_PASSWORD: password,
    }
    result = click_runner.invoke(nucypher_cli,
                                 init_args,
                                 catch_exceptions=False,
                                 env=cli_env)
    assert result.exit_code == 0, result.stdout

    # Inspect the configuration file for the signer URI
    with open(ursula_config_path, 'r') as config_file:
        raw_config_data = config_file.read()
        config_data = json.loads(raw_config_data)
        assert config_data['signer_uri'] == mock_signer_uri,\
            "Keystore URI was not correctly included in configuration file"

    # Recreate a configuration with the signer URI preserved
    ursula_config = UrsulaConfiguration.from_configuration_file(
        ursula_config_path)
    assert ursula_config.signer_uri == mock_signer_uri

    # Mock decryption of web3 client keystore
    mocker.patch.object(Account, 'decrypt', return_value=worker_account.key)
    ursula_config.keystore.unlock(password=password)

    # Produce an Ursula with a Keystore signer correctly derived from the signer URI, and don't do anything else!
    ursula = ursula_config.produce()
    ursula.signer.unlock_account(account=worker_account.address,
                                 password=password)

    try:
        # Verify the keystore path is still preserved
        assert isinstance(ursula.signer, KeystoreSigner)
        assert isinstance(ursula.signer.path, Path), "Use Path"
        assert ursula.signer.path.absolute() == mock_keystore_path.absolute()

        # Show that we can produce the exact same signer as pre-config...
        assert pre_config_signer.path == ursula.signer.path

        # ...and that transactions are signed by the keystore signer
        txhash = ursula.confirm_address()
        receipt = testerchain.wait_for_receipt(txhash)
        transaction_data = testerchain.client.w3.eth.getTransaction(
            receipt['transactionHash'])
        assert transaction_data['from'] == worker_account.address
    finally:
        ursula.stop()
示例#11
0
def test_collect_rewards_integration(click_runner,
                                     testerchain,
                                     agency_local_registry,
                                     stakeholder_configuration_file_location,
                                     blockchain_alice,
                                     blockchain_bob,
                                     random_policy_label,
                                     beneficiary,
                                     preallocation_escrow_agent,
                                     mock_allocation_registry,
                                     manual_worker,
                                     token_economics,
                                     mock_transacting_power_activation,
                                     stake_value,
                                     policy_value,
                                     policy_rate):
    # Disable re-staking
    restake_args = ('stake', 'restake',
                    '--disable',
                    '--config-file', stakeholder_configuration_file_location,
                    '--allocation-filepath', MOCK_INDIVIDUAL_ALLOCATION_FILEPATH,
                    '--force')

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

    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 = preallocation_escrow_agent.principal_contract.address
    worker_address = manual_worker

    # The staker is staking.
    stakes = StakeList(registry=agency_local_registry, checksum_address=staker_address)
    stakes.refresh()
    assert stakes

    staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=agency_local_registry)
    assert worker_address == staking_agent.get_worker_from_staker(staker_address=staker_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,
                    start_working_now=False,
                    network_middleware=MockRestMiddleware())

    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(block_identifier='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))
        message_kit, signature = enrico.encrypt_message(message=random_data)

        # Decrypt
        cleartexts = blockchain_bob.retrieve(message_kit,
                                             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 _ in range(5 - 1):  # minus 1 because the first period was already committed to in test_ursula_run
        logger.debug(f">>>>>>>>>>> TEST PERIOD {current_period} <<<<<<<<<<<<<<<<")
        ursula.commit_to_next_period()
        current_period += 1
        testerchain.time_travel(periods=1)

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

    balance = testerchain.client.get_balance(beneficiary)

    # 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} <<<<<<<<<<<<<<<<")

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

    # Collect Policy Fee
    collection_args = ('stake', 'collect-reward',
                       '--config-file', stakeholder_configuration_file_location,
                       '--policy-fee',
                       '--no-staking-reward',
                       '--withdraw-address', beneficiary,
                       '--allocation-filepath', MOCK_INDIVIDUAL_ALLOCATION_FILEPATH,
                       '--force')

    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(beneficiary)
    assert collected_policy_fee > balance

    #
    # Collect Staking Reward
    #
    token_agent = ContractAgency.get_agent(agent_class=NucypherTokenAgent, registry=agency_local_registry)
    balance_before_collecting = token_agent.get_balance(address=staker_address)

    collection_args = ('stake', 'collect-reward',
                       '--config-file', stakeholder_configuration_file_location,
                       '--no-policy-fee',
                       '--staking-reward',
                       '--allocation-filepath', MOCK_INDIVIDUAL_ALLOCATION_FILEPATH,
                       '--force')

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

    # The beneficiary has withdrawn her staking rewards, which are now in the staking contract
    assert token_agent.get_balance(address=staker_address) >= balance_before_collecting
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
def test_ursula_init_with_local_keystore_signer(
        click_runner, temp_dir_path, mocker, mock_testerchain,
        mock_account_password_keystore):
    custom_filepath = temp_dir_path
    custom_config_filepath = temp_dir_path / UrsulaConfiguration.generate_filename(
    )
    worker_account, password, mock_keystore_path = mock_account_password_keystore
    mock_signer_uri = f'keystore://{mock_keystore_path}'

    # Good signer...
    pre_config_signer = KeystoreSigner.from_signer_uri(uri=mock_signer_uri,
                                                       testnet=True)

    deploy_port = select_test_port()

    init_args = (
        'ursula',
        'init',

        # Layer 1
        '--network',
        TEMPORARY_DOMAIN,
        '--eth-provider',
        mock_testerchain.eth_provider_uri,

        # Layer 2
        '--payment-network',
        TEMPORARY_DOMAIN,
        '--payment-provider',
        mock_testerchain.eth_provider_uri,
        '--rest-host',
        MOCK_IP_ADDRESS,
        '--rest-port',
        deploy_port,
        '--operator-address',
        worker_account.address,
        '--config-root',
        str(custom_filepath.absolute()),

        # The bit we are testing here
        '--signer',
        mock_signer_uri)

    cli_env = {
        NUCYPHER_ENVVAR_KEYSTORE_PASSWORD: password,
        NUCYPHER_ENVVAR_OPERATOR_ETH_PASSWORD: password,
    }
    result = click_runner.invoke(nucypher_cli,
                                 init_args,
                                 catch_exceptions=False,
                                 env=cli_env)
    assert result.exit_code == 0, result.stdout

    # Inspect the configuration file for the signer URI
    with open(custom_config_filepath, 'r') as config_file:
        raw_config_data = config_file.read()
        config_data = json.loads(raw_config_data)
        assert config_data['signer_uri'] == mock_signer_uri,\
            "Keystore URI was not correctly included in configuration file"

    # Recreate a configuration with the signer URI preserved
    ursula_config = UrsulaConfiguration.from_configuration_file(
        custom_config_filepath, config_root=custom_filepath)
    assert ursula_config.signer_uri == mock_signer_uri

    # Mock decryption of web3 client keystore
    mocker.patch.object(Account, 'decrypt', return_value=worker_account.key)
    ursula_config.keystore.unlock(password=password)

    # Produce an ursula with a Keystore signer correctly derived from the signer URI, and don't do anything else!
    ursula = ursula_config.produce()
    ursula.signer.unlock_account(account=worker_account.address,
                                 password=password)

    # Verify the keystore path is still preserved
    assert isinstance(ursula.signer, KeystoreSigner)
    assert isinstance(ursula.signer.path, Path), "Use pathlib.Path"
    assert ursula.signer.path.absolute() == mock_keystore_path.absolute()

    # Show that we can produce the exact same signer as pre-config...
    assert pre_config_signer.path == ursula.signer.path
    ursula.stop()
示例#14
0
def test_ursula_and_local_keystore_signer_integration(
        click_runner, tmp_path, manual_staker, stake_value, token_economics,
        mocker, mock_funded_account_password_keystore, testerchain):
    config_root_path = tmp_path
    ursula_config_path = config_root_path / UrsulaConfiguration.generate_filename(
    )
    stakeholder_config_path = config_root_path / StakeHolderConfiguration.generate_filename(
    )
    worker_account, password, mock_keystore_path = mock_funded_account_password_keystore

    #
    # Stakeholder Steps
    #

    init_args = ('stake', 'init-stakeholder', '--config-root',
                 config_root_path, '--provider', TEST_PROVIDER_URI,
                 '--network', TEMPORARY_DOMAIN)
    click_runner.invoke(nucypher_cli, init_args, catch_exceptions=False)

    stake_args = ('stake', 'create', '--config-file', stakeholder_config_path,
                  '--staking-address', manual_staker, '--value',
                  stake_value.to_tokens(), '--lock-periods',
                  token_economics.minimum_locked_periods, '--force')
    # TODO: Is This test is writing to the default system directory and ignoring updates to the passed filepath?
    user_input = f'0\n{password}\nY\n'
    click_runner.invoke(nucypher_cli,
                        stake_args,
                        input=user_input,
                        catch_exceptions=False)

    init_args = ('stake', 'bond-worker', '--config-file',
                 stakeholder_config_path, '--staking-address', manual_staker,
                 '--worker-address', worker_account.address, '--force')
    user_input = password
    click_runner.invoke(nucypher_cli,
                        init_args,
                        input=user_input,
                        catch_exceptions=False)

    #
    # Worker Steps
    #

    # Good signer...
    mock_signer_uri = f'keystore:{mock_keystore_path}'
    pre_config_signer = KeystoreSigner.from_signer_uri(uri=mock_signer_uri,
                                                       testnet=True)
    assert worker_account.address in pre_config_signer.accounts

    deploy_port = select_test_port()

    init_args = (
        'ursula',
        'init',
        '--network',
        TEMPORARY_DOMAIN,
        '--worker-address',
        worker_account.address,
        '--config-root',
        config_root_path,
        '--provider',
        TEST_PROVIDER_URI,
        '--rest-host',
        MOCK_IP_ADDRESS,
        '--rest-port',
        deploy_port,

        # The bit we are testing for here
        '--signer',
        mock_signer_uri)

    cli_env = {
        NUCYPHER_ENVVAR_KEYRING_PASSWORD: password,
        NUCYPHER_ENVVAR_WORKER_ETH_PASSWORD: password,
    }
    result = click_runner.invoke(nucypher_cli,
                                 init_args,
                                 catch_exceptions=False,
                                 env=cli_env)
    assert result.exit_code == 0, result.stdout

    # Inspect the configuration file for the signer URI
    with open(ursula_config_path, 'r') as config_file:
        raw_config_data = config_file.read()
        config_data = json.loads(raw_config_data)
        assert config_data['signer_uri'] == mock_signer_uri,\
            "Keystore URI was not correctly included in configuration file"

    # Recreate a configuration with the signer URI preserved
    ursula_config = UrsulaConfiguration.from_configuration_file(
        ursula_config_path)
    assert ursula_config.signer_uri == mock_signer_uri

    # Mock decryption of web3 client keyring
    mocker.patch.object(Account,
                        'decrypt',
                        return_value=worker_account.privateKey)
    ursula_config.attach_keyring(checksum_address=worker_account.address)
    ursula_config.keyring.unlock(password=password)

    # Produce an Ursula with a Keystore signer correctly derived from the signer URI, and don't do anything else!
    mocker.patch.object(StakeList, 'refresh', autospec=True)
    ursula = ursula_config.produce(client_password=password,
                                   commit_now=False,
                                   block_until_ready=False)

    try:
        # Verify the keystore path is still preserved
        assert isinstance(ursula.signer, KeystoreSigner)
        assert isinstance(ursula.signer.path, str), "Use str"
        assert ursula.signer.path == str(mock_keystore_path)

        # Show that we can produce the exact same signer as pre-config...
        assert pre_config_signer.path == ursula.signer.path

        # ...and that transactions are signed by the keystore signer
        txhash = ursula.commit_to_next_period()
        receipt = testerchain.wait_for_receipt(txhash)
        transaction_data = testerchain.client.w3.eth.getTransaction(
            receipt['transactionHash'])
        assert transaction_data['from'] == worker_account.address
    finally:
        ursula.stop()
def test_ursula_init_with_local_keystore_signer(click_runner, tmp_path, mocker,
                                                mock_testerchain,
                                                mock_account_password_keystore,
                                                test_registry_source_manager):
    custom_filepath = tmp_path
    custom_config_filepath = tmp_path / UrsulaConfiguration.generate_filename()
    worker_account, password, mock_keystore_path = mock_account_password_keystore
    mock_signer_uri = f'keystore:{mock_keystore_path}'

    # Good signer...
    pre_config_signer = KeystoreSigner.from_signer_uri(uri=mock_signer_uri)

    deploy_port = select_test_port()

    init_args = (
        'ursula',
        'init',
        '--network',
        TEMPORARY_DOMAIN,
        '--worker-address',
        worker_account.address,
        '--config-root',
        custom_filepath,
        '--provider',
        mock_testerchain.provider_uri,
        '--rest-host',
        MOCK_IP_ADDRESS,
        '--rest-port',
        deploy_port,

        # The bit we are testing here
        '--signer',
        mock_signer_uri)

    cli_env = {
        NUCYPHER_ENVVAR_KEYRING_PASSWORD: password,
        NUCYPHER_ENVVAR_WORKER_ETH_PASSWORD: password,
    }
    result = click_runner.invoke(nucypher_cli,
                                 init_args,
                                 catch_exceptions=False,
                                 env=cli_env)
    assert result.exit_code == 0, result.stdout

    # Inspect the configuration file for the signer URI
    with open(custom_config_filepath, 'r') as config_file:
        raw_config_data = config_file.read()
        config_data = json.loads(raw_config_data)
        assert config_data['signer_uri'] == mock_signer_uri,\
            "Keystore URI was not correctly included in configuration file"

    # Recreate a configuration with the signer URI preserved
    ursula_config = UrsulaConfiguration.from_configuration_file(
        custom_config_filepath)
    assert ursula_config.signer_uri == mock_signer_uri

    # Mock decryption of web3 client keyring
    mocker.patch.object(Account,
                        'decrypt',
                        return_value=worker_account.privateKey)
    ursula_config.attach_keyring(checksum_address=worker_account.address)
    ursula_config.keyring.unlock(password=password)

    # Produce an ursula with a Keystore signer correctly derived from the signer URI, and dont do anything else!
    mocker.patch.object(StakeList, 'refresh', autospec=True)
    ursula = ursula_config.produce(client_password=password,
                                   block_until_ready=False)

    # Verify the keystore path is still preserved
    assert isinstance(ursula.signer, KeystoreSigner)
    assert isinstance(ursula.signer.path, str), "Use str"
    assert ursula.signer.path == str(mock_keystore_path)

    # Show that we can produce the exact same signer as pre-config...
    assert pre_config_signer.path == ursula.signer.path
    ursula.stop()
示例#16
0
# you will not perform any re-encryptions, and you will not get paid.
# It might be (but might not be) useful for determining whether you have
# the proper dependencies and configuration to run an actual mining node.


from click.testing import CliRunner

from nucypher.cli.main import nucypher_cli
from nucypher.exceptions import DevelopmentInstallationRequired
from nucypher.utilities.networking import LOOPBACK_ADDRESS

try:
    from tests.utils.ursula import select_test_port
except ImportError:
    raise DevelopmentInstallationRequired(importable_name='tests.utils.ursula.select_test_port')

click_runner = CliRunner()

DEMO_NODE_PORT = select_test_port()
DEMO_FLEET_STARTING_PORT = 11500

args = ['ursula', 'run',
        '--debug',
        '--federated-only',
        '--teacher', f'https://{LOOPBACK_ADDRESS}:{DEMO_FLEET_STARTING_PORT}',
        '--rest-port', DEMO_NODE_PORT,
        '--dev'
        ]

nucypher_cli.main(args=args, prog_name="nucypher-cli")