Merge pull request #2474 from KPrasch/hello-operator

Pretty worker & staker console messages
pull/2483/head
K Prasch 2020-12-18 10:15:01 -08:00 committed by GitHub
commit 62ade702c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 55 additions and 38 deletions

View File

@ -0,0 +1 @@
Improves console messages for stakeholder CLI initialization and worker startup.

View File

@ -1551,8 +1551,10 @@ class Worker(NucypherTokenActor):
start = maya.now()
last_provided_feedback = start
emitter = StdoutEmitter() # TODO: Make injectable, or embed this logic into Ursula
emitter.message("Checking worker settings: waiting for bonding and funding ...", color='yellow')
emitter = StdoutEmitter()
message = f"Awaiting worker qualification\n" \
f"Startup will resume when {self.__worker_address} is funded and bonded to a staking account."
emitter.message(message, color='yellow')
funded, bonded = False, False
while True:
@ -1564,12 +1566,12 @@ class Worker(NucypherTokenActor):
# Bonding
if (not bonded) and (staking_address != NULL_ADDRESS):
bonded = True
emitter.message(f" ✓ Worker is bonded to ({staking_address})!", color='green', bold=True)
emitter.message(f"✓ Worker is bonded to ({staking_address})!", color='green', bold=True)
# Balance
if ether_balance and (not funded):
funded, balance = True, Web3.fromWei(ether_balance, 'ether')
emitter.message(f" ✓ Worker is funded with {balance} ETH!", color='green', bold=True)
emitter.message(f"✓ Worker is funded with {balance} ETH!", color='green', bold=True)
# Success and Escape
if staking_address != NULL_ADDRESS and ether_balance:
@ -1588,8 +1590,7 @@ class Worker(NucypherTokenActor):
waiting_for = "bonding and funding"
else:
waiting_for = "bonding" if not bonded else "funding"
emitter.message(f" ⓘ Worker not fully started - still waiting for {waiting_for} ...",
color='yellow')
emitter.message(f"ⓘ Worker not fully started - awaiting {waiting_for} ...", color='blue', bold=True)
last_provided_feedback = now
# Crash on Timeout

View File

@ -22,6 +22,7 @@ import click
from json.decoder import JSONDecodeError
from typing import Optional, Type
from nucypher.config.characters import StakeHolderConfiguration
from nucypher.characters.control.emitters import StdoutEmitter
from nucypher.cli.actions.confirm import confirm_destroy_configuration
from nucypher.cli.literature import (
@ -85,6 +86,8 @@ def handle_missing_configuration_file(character_config_class: Type[CharacterConf
config_file_location = config_file or character_config_class.default_filepath()
init_command = init_command_hint or f"{character_config_class.NAME} init"
name = character_config_class.NAME.capitalize()
if name == StakeHolderConfiguration.NAME.capitalize():
init_command = 'stake init-stakeholder'
message = MISSING_CONFIGURATION_FILE.format(name=name, init_command=init_command)
raise click.FileError(filename=config_file_location, hint=message)

View File

@ -57,7 +57,7 @@ def confirm_deployment(emitter: StdoutEmitter, deployer_interface: BlockchainDep
expected_chain_name = deployer_interface.client.chain_name
if click.prompt(f"Type '{expected_chain_name.upper()}' to continue") != expected_chain_name.upper():
emitter.echo(ABORT_DEPLOYMENT, color='red', bold=True)
raise click.Abort()
raise click.Abort(ABORT_DEPLOYMENT)
return True

View File

@ -547,6 +547,7 @@ def create(general_config: GroupGeneralConfig,
if not force:
confirm_large_stake(value=value, lock_periods=lock_periods)
paint_staged_stake(emitter=emitter,
blockchain=blockchain,
stakeholder=STAKEHOLDER,
staking_address=staking_address,
stake_value=value,
@ -643,6 +644,7 @@ def increase(general_config: GroupGeneralConfig,
confirm_large_stake(value=value, lock_periods=lock_periods)
paint_staged_stake(emitter=emitter,
blockchain=blockchain,
stakeholder=STAKEHOLDER,
staking_address=staking_address,
stake_value=value,
@ -904,6 +906,7 @@ def divide(general_config: GroupGeneralConfig,
if not force:
confirm_large_stake(lock_periods=extension, value=value)
paint_staged_stake_division(emitter=emitter,
blockchain=blockchain,
stakeholder=STAKEHOLDER,
original_stake=current_stake,
target_value=value,

View File

@ -92,7 +92,7 @@ CONFIRM_INCREASING_STAKE = "Confirm increase stake (index: {stake_index}) by {va
INSUFFICIENT_BALANCE_TO_INCREASE = "There are no tokens to increase stake"
INSUFFICIENT_BALANCE_TO_CREATE = "There are not enough tokens to create stake"
INSUFFICIENT_BALANCE_TO_CREATE = "Insufficient NU for stake creation."
MAXIMUM_STAKE_REACHED = "Maximum stake reached, can't lock more"
@ -216,11 +216,10 @@ PROMPT_WORKER_ADDRESS = "Enter worker address"
CONFIRM_WORKER_AND_STAKER_ADDRESSES_ARE_EQUAL = """
{address}
The worker address provided is the same as the staking account.
The worker address provided is the same as the staker.
It is *highly recommended* to use a different accounts for staker and worker roles.
Continue?
"""
Continue using the same account for worker and staker?"""
SUCCESSFUL_WORKER_BONDING = "\nWorker {worker_address} successfully bonded to staker {staking_address}"
@ -300,8 +299,11 @@ NO_FEE_TO_WITHDRAW = "No policy fee can be withdrawn."
# Configuration
#
MISSING_CONFIGURATION_FILE = """No {name} configuration file found.
To create a new persistent {name} run 'nucypher {init_command}'
MISSING_CONFIGURATION_FILE = """
No {name} configuration file found. To create a new {name} configuration run:
nucypher {init_command}
"""
@ -330,7 +332,7 @@ Delete all {name} character files including:
Are you sure?"""
SUCCESSFUL_DESTRUCTION = "Successfully destroyed NuCypher configuration"
SUCCESSFUL_DESTRUCTION = "Successfully destroyed nucypher configuration"
CONFIRM_FORGET_NODES = "Permanently delete all known node data?"
@ -342,16 +344,26 @@ SUCCESSFUL_DATABASE_DESTRUCTION = "Destroyed existing database {path}"
SUCCESSFUL_DATABASE_CREATION = "\nCreated new database at {path}"
SUCCESSFUL_NEW_STAKEHOLDER_CONFIG = "Wrote new stakeholder configuration to {filepath}"
SUCCESSFUL_NEW_STAKEHOLDER_CONFIG = """
Configured new stakeholder!
Wrote JSON configuration to {filepath}
* Review configuration -> nucypher stake config
* View connected accounts -> nucypher stake accounts
* Create a new stake -> nucypher stake create
* Bond a worker -> nucypher stake bond-worker
* List active stakes -> nucypher stake list
"""
#
# Authentication
#
COLLECT_ETH_PASSWORD = "Enter password to unlock account {checksum_address}"
COLLECT_ETH_PASSWORD = "Enter ethereum account password ({checksum_address})"
COLLECT_NUCYPHER_PASSWORD = "Enter NuCypher keyring password"
COLLECT_NUCYPHER_PASSWORD = 'Enter nucypher keyring password'
GENERIC_PASSWORD_PROMPT = "Enter password"
@ -363,7 +375,7 @@ DECRYPTING_CHARACTER_KEYRING = 'Authenticating {name}'
#
CONFIRM_URSULA_IPV4_ADDRESS = "Is this the public-facing IPv4 address ({rest_host}) you want to use for Ursula?"
CONFIRM_URSULA_IPV4_ADDRESS = "Detected IPv4 address ({rest_host}) - Is this the public-facing address of Ursula?"
COLLECT_URSULA_IPV4_ADDRESS = "Enter Ursula's public-facing IPv4 address:"

View File

@ -71,13 +71,8 @@ def paint_new_installation_help(emitter, new_configuration):
emitter.echo(how_to_stake_message, color='green')
# Everyone: Give the use a suggestion as to what to do next
vowels = ('a', 'e', 'i', 'o', 'u')
character_name_starts_with_vowel = character_name[0].lower() in vowels
adjective = 'an' if character_name_starts_with_vowel else 'a'
suggested_command = f'nucypher {character_name} run'
how_to_run_message = f"\nTo run {adjective} {character_name.capitalize()} node from the default configuration " \
f"filepath run: \n\n'{suggested_command}'\n"
how_to_run_message = f"\nTo start {character_name.capitalize()} run '{suggested_command}'\n"
emitter.echo(how_to_run_message.format(suggested_command), color='green')

View File

@ -135,6 +135,7 @@ def prettify_stake(stake, index: int = None) -> str:
def paint_staged_stake_division(emitter,
blockchain,
stakeholder,
original_stake,
target_value,
@ -149,6 +150,7 @@ Staking address: {staking_address}
"""
paint_staged_stake(emitter=emitter,
blockchain=blockchain,
stakeholder=stakeholder,
staking_address=staking_address,
stake_value=target_value,
@ -159,6 +161,7 @@ Staking address: {staking_address}
def paint_staged_stake(emitter,
blockchain,
stakeholder,
staking_address,
stake_value,
@ -185,7 +188,7 @@ def paint_staged_stake(emitter,
emitter.echo(f"""
Staking address: {staking_address}
~ Chain -> ID # {stakeholder.wallet.blockchain.client.chain_id} | {stakeholder.wallet.blockchain.client.chain_name}
~ Chain -> ID # {blockchain.client.chain_id} | {blockchain.client.chain_name}
~ Value -> {stake_value} ({int(stake_value)} NuNits)
~ Duration -> {lock_periods} Days ({lock_periods} Periods)
~ Enactment -> {start_datetime_pretty} (period #{start_period})

View File

@ -16,12 +16,11 @@ along with nucypher. If not, see <https://www.gnu.org/licenses/>.
"""
import json
import random
import pytest
import random
from nucypher.blockchain.eth.actors import ContractAdministrator
from nucypher.blockchain.eth.agents import StakingEscrowAgent, ContractAgency
from nucypher.characters.control.emitters import StdoutEmitter
from nucypher.crypto.powers import TransactingPower
from tests.constants import INSECURE_DEVELOPMENT_PASSWORD, NUMBER_OF_ALLOCATIONS_IN_TESTS

View File

@ -19,7 +19,7 @@ from unittest import mock
import os
from nucypher.cli.literature import SUCCESSFUL_DESTRUCTION
from nucypher.cli.literature import SUCCESSFUL_DESTRUCTION, COLLECT_NUCYPHER_PASSWORD
from nucypher.cli.main import nucypher_cli
from nucypher.config.characters import AliceConfiguration
from nucypher.config.constants import NUCYPHER_ENVVAR_KEYRING_PASSWORD, TEMPORARY_DOMAIN
@ -54,7 +54,7 @@ def test_initialize_alice_defaults(click_runner, mocker, custom_filepath, monkey
assert "nucypher alice run" in result.output
# Auth
assert 'Enter NuCypher keyring password' in result.output, 'WARNING: User was not prompted for password'
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'
@ -103,7 +103,7 @@ def test_initialize_alice_with_custom_configuration_root(custom_filepath, click_
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 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'

View File

@ -25,7 +25,7 @@ import pytest
from nucypher.characters.control.emitters import JSONRPCStdoutEmitter
from nucypher.characters.lawful import Ursula
from nucypher.cli import utils
from nucypher.cli.literature import SUCCESSFUL_DESTRUCTION
from nucypher.cli.literature import SUCCESSFUL_DESTRUCTION, COLLECT_NUCYPHER_PASSWORD
from nucypher.cli.main import nucypher_cli
from nucypher.config.characters import BobConfiguration
from nucypher.config.constants import TEMPORARY_DOMAIN
@ -81,7 +81,7 @@ def test_initialize_bob_with_custom_configuration_root(custom_filepath, click_ru
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 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'

View File

@ -51,7 +51,7 @@ def test_initialize_via_cli(config_class, custom_filepath, click_runner, monkeyp
input=FAKE_PASSWORD_CONFIRMED,
catch_exceptions=False,
env=ENV)
assert result.exit_code == 0
assert result.exit_code == 0, result.output
# CLI Output
assert str(MOCK_CUSTOM_INSTALLATION_PATH) in result.output, "Configuration not in system temporary directory"

View File

@ -147,7 +147,7 @@ def test_coexisting_configurations(click_runner,
'--config-root', custom_filepath)
result = click_runner.invoke(nucypher_cli, init_args, catch_exceptions=False, env=envvars)
assert result.exit_code == 0
assert result.exit_code == 0, result.output
# All configuration files still exist.
assert len(os.listdir(public_keys_dir)) == 8

View File

@ -21,7 +21,7 @@ from json import JSONDecodeError
import os
import pytest
from nucypher.cli.literature import SUCCESSFUL_DESTRUCTION
from nucypher.cli.literature import SUCCESSFUL_DESTRUCTION, COLLECT_NUCYPHER_PASSWORD
from nucypher.cli.main import nucypher_cli
from nucypher.config.characters import UrsulaConfiguration
from nucypher.config.constants import APP_DIR, DEFAULT_CONFIG_ROOT, NUCYPHER_ENVVAR_KEYRING_PASSWORD, TEMPORARY_DOMAIN
@ -46,10 +46,10 @@ def test_initialize_ursula_defaults(click_runner, mocker):
assert result.exit_code == 0
# REST Host
assert 'Is this the public-facing IPv4 address' in result.output
assert "Is this the public-facing address of Ursula? " in result.output
# Auth
assert 'Enter NuCypher keyring password' in result.output, 'WARNING: User was not prompted for password'
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'
@ -80,7 +80,7 @@ def test_initialize_custom_configuration_root(custom_filepath, click_runner):
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 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'