mirror of https://github.com/nucypher/nucypher.git
Merge pull request #2474 from KPrasch/hello-operator
Pretty worker & staker console messagespull/2483/head
commit
62ade702c9
|
@ -0,0 +1 @@
|
|||
Improves console messages for stakeholder CLI initialization and worker startup.
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:"
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue