mirror of https://github.com/nucypher/nucypher.git
Take back control of CLI imports, namespaces, and organization. Work on a CLI and tidy CLI.
parent
5992e05897
commit
2e9da4ef31
|
@ -23,8 +23,12 @@ from constant_sorrow.constants import NO_PASSWORD
|
|||
from nacl.exceptions import CryptoError
|
||||
|
||||
from nucypher.blockchain.eth.decorators import validate_checksum_address
|
||||
from nucypher.cli.literature import (COLLECT_ETH_PASSWORD, COLLECT_NUCYPHER_PASSWORD, DECRYPTING_CHARACTER_KEYRING,
|
||||
GENERIC_PASSWORD_PROMPT)
|
||||
from nucypher.cli.literature import (
|
||||
COLLECT_ETH_PASSWORD,
|
||||
COLLECT_NUCYPHER_PASSWORD,
|
||||
DECRYPTING_CHARACTER_KEYRING,
|
||||
GENERIC_PASSWORD_PROMPT
|
||||
)
|
||||
from nucypher.config.constants import NUCYPHER_ENVVAR_KEYRING_PASSWORD
|
||||
from nucypher.config.node import CharacterConfiguration
|
||||
|
||||
|
|
|
@ -26,9 +26,15 @@ from eth_utils.address import is_checksum_address
|
|||
from json.decoder import JSONDecodeError
|
||||
|
||||
from nucypher.blockchain.eth.clients import NuCypherGethGoerliProcess
|
||||
from nucypher.cli.literature import (CHARACTER_DESTRUCTION, CONFIRM_FORGET_NODES, INVALID_CONFIGURATION_FILE_WARNING,
|
||||
INVALID_JSON_IN_CONFIGURATION_WARNING, SUCCESSFUL_DESTRUCTION,
|
||||
SUCCESSFUL_FORGET_NODES, SUCCESSFUL_UPDATE_CONFIGURATION_VALUES)
|
||||
from nucypher.cli.literature import (
|
||||
CHARACTER_DESTRUCTION,
|
||||
CONFIRM_FORGET_NODES,
|
||||
INVALID_CONFIGURATION_FILE_WARNING,
|
||||
INVALID_JSON_IN_CONFIGURATION_WARNING,
|
||||
SUCCESSFUL_DESTRUCTION,
|
||||
SUCCESSFUL_FORGET_NODES,
|
||||
SUCCESSFUL_UPDATE_CONFIGURATION_VALUES
|
||||
)
|
||||
from nucypher.config.characters import UrsulaConfiguration
|
||||
|
||||
|
||||
|
|
|
@ -20,10 +20,18 @@ import click
|
|||
from constant_sorrow.constants import UNKNOWN_DEVELOPMENT_CHAIN_ID
|
||||
|
||||
from nucypher.blockchain.eth.token import NU
|
||||
from nucypher.cli.literature import (ABORT_DEPLOYMENT, CONFIRM_ENABLE_RESTAKING, CONFIRM_ENABLE_WINDING_DOWN,
|
||||
CONFIRM_LARGE_STAKE_DURATION, CONFIRM_LARGE_STAKE_VALUE, CONFIRM_RESTAKING_LOCK,
|
||||
CONFIRM_STAGED_STAKE, RESTAKING_AGREEMENT, RESTAKING_LOCK_AGREEMENT,
|
||||
WINDING_DOWN_AGREEMENT)
|
||||
from nucypher.cli.literature import (
|
||||
ABORT_DEPLOYMENT,
|
||||
CONFIRM_ENABLE_RESTAKING,
|
||||
CONFIRM_ENABLE_WINDING_DOWN,
|
||||
CONFIRM_LARGE_STAKE_DURATION,
|
||||
CONFIRM_LARGE_STAKE_VALUE,
|
||||
CONFIRM_RESTAKING_LOCK,
|
||||
CONFIRM_STAGED_STAKE,
|
||||
RESTAKING_AGREEMENT,
|
||||
RESTAKING_LOCK_AGREEMENT,
|
||||
WINDING_DOWN_AGREEMENT
|
||||
)
|
||||
|
||||
|
||||
def confirm_deployment(emitter, deployer_interface) -> bool:
|
||||
|
|
|
@ -26,9 +26,15 @@ from json.decoder import JSONDecodeError
|
|||
from typing import Dict, List, Optional, Set
|
||||
|
||||
from nucypher.blockchain.eth.registry import BaseContractRegistry
|
||||
from nucypher.cli.literature import (COLLECT_URSULA_IPV4_ADDRESS, CONFIRM_URSULA_IPV4_ADDRESS,
|
||||
FORCE_DETECT_URSULA_IP_WARNING, NO_DOMAIN_PEERS, SEEDNODE_NOT_STAKING_WARNING,
|
||||
START_LOADING_SEEDNODES, UNREADABLE_SEEDNODE_ADVISORY)
|
||||
from nucypher.cli.literature import (
|
||||
COLLECT_URSULA_IPV4_ADDRESS,
|
||||
CONFIRM_URSULA_IPV4_ADDRESS,
|
||||
FORCE_DETECT_URSULA_IP_WARNING,
|
||||
NO_DOMAIN_PEERS,
|
||||
SEEDNODE_NOT_STAKING_WARNING,
|
||||
START_LOADING_SEEDNODES,
|
||||
UNREADABLE_SEEDNODE_ADVISORY
|
||||
)
|
||||
from nucypher.cli.types import IPV4_ADDRESS
|
||||
from nucypher.config.constants import DEFAULT_CONFIG_ROOT
|
||||
from nucypher.network.exceptions import NodeSeemsToBeDown
|
||||
|
|
|
@ -32,10 +32,19 @@ from nucypher.blockchain.eth.registry import InMemoryContractRegistry, Individua
|
|||
from nucypher.blockchain.eth.signers import Signer
|
||||
from nucypher.blockchain.eth.token import NU, Stake
|
||||
from nucypher.cli.actions.config import extract_checksum_address_from_filepath
|
||||
from nucypher.cli.literature import (GENERIC_SELECT_ACCOUNT, IS_THIS_CORRECT, NO_CONFIGURATIONS_ON_DISK,
|
||||
NO_DIVISIBLE_STAKES, NO_ETH_ACCOUNTS, NO_STAKES_FOUND,
|
||||
ONLY_DISPLAYING_DIVISIBLE_STAKES_NOTE, PREALLOCATION_STAKE_ADVISORY,
|
||||
SELECT_NETWORK, SELECT_STAKE, SELECT_STAKING_ACCOUNT_INDEX)
|
||||
from nucypher.cli.literature import (
|
||||
GENERIC_SELECT_ACCOUNT,
|
||||
IS_THIS_CORRECT,
|
||||
NO_CONFIGURATIONS_ON_DISK,
|
||||
NO_DIVISIBLE_STAKES,
|
||||
NO_ETH_ACCOUNTS,
|
||||
NO_STAKES_FOUND,
|
||||
ONLY_DISPLAYING_DIVISIBLE_STAKES_NOTE,
|
||||
PREALLOCATION_STAKE_ADVISORY,
|
||||
SELECT_NETWORK,
|
||||
SELECT_STAKE,
|
||||
SELECT_STAKING_ACCOUNT_INDEX
|
||||
)
|
||||
from nucypher.cli.painting.staking import paint_stakes
|
||||
from nucypher.config.constants import DEFAULT_CONFIG_ROOT, NUCYPHER_ENVVAR_WORKER_ADDRESS
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@ You should have received a copy of the GNU Affero General Public License
|
|||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
from distutils.util import strtobool
|
||||
|
||||
import click
|
||||
|
@ -23,15 +25,33 @@ import shutil
|
|||
from constant_sorrow.constants import NO_CONTROL_PROTOCOL
|
||||
from nacl.exceptions import CryptoError
|
||||
|
||||
from nucypher.blockchain.eth.interfaces import BlockchainInterface, BlockchainInterfaceFactory
|
||||
from nucypher.blockchain.eth.interfaces import (
|
||||
BlockchainDeployerInterface,
|
||||
BlockchainInterface,
|
||||
BlockchainInterfaceFactory
|
||||
)
|
||||
from nucypher.blockchain.eth.registry import BaseContractRegistry, InMemoryContractRegistry, LocalContractRegistry
|
||||
from nucypher.cli.actions.auth import get_nucypher_password, unlock_nucypher_keyring
|
||||
from nucypher.cli.actions.network import load_seednodes
|
||||
from nucypher.cli.literature import (CONNECTING_TO_BLOCKCHAIN, FEDERATED_WARNING, LOCAL_REGISTRY_ADVISORY,
|
||||
PRODUCTION_REGISTRY_ADVISORY)
|
||||
from nucypher.cli.literature import (
|
||||
CONNECTING_TO_BLOCKCHAIN,
|
||||
ETHERSCAN_FLAG_DISABLED_WARNING,
|
||||
ETHERSCAN_FLAG_ENABLED_WARNING,
|
||||
FEDERATED_WARNING,
|
||||
LOCAL_REGISTRY_ADVISORY,
|
||||
NO_HARDWARE_WALLET_WARNING,
|
||||
PRODUCTION_REGISTRY_ADVISORY
|
||||
)
|
||||
from nucypher.config.constants import DEFAULT_CONFIG_ROOT
|
||||
|
||||
|
||||
def setup_emitter(general_config, banner: str = None):
|
||||
emitter = general_config.emitter
|
||||
if banner:
|
||||
emitter.banner(banner)
|
||||
return emitter
|
||||
|
||||
|
||||
def make_cli_character(character_config,
|
||||
emitter,
|
||||
unlock_keyring: bool = True,
|
||||
|
@ -154,10 +174,40 @@ def connect_to_blockchain(provider_uri, emitter, debug: bool = False, light: boo
|
|||
raise click.Abort
|
||||
|
||||
|
||||
def initialize_deployer_interface(poa, provider_uri, emitter, ignore_solidity_check, gas_strategy=None):
|
||||
if not BlockchainInterfaceFactory.is_interface_initialized(provider_uri=provider_uri):
|
||||
deployer_interface = BlockchainDeployerInterface(provider_uri=provider_uri,
|
||||
poa=poa,
|
||||
ignore_solidity_check=ignore_solidity_check,
|
||||
gas_strategy=gas_strategy)
|
||||
BlockchainInterfaceFactory.register_interface(interface=deployer_interface, sync=False,
|
||||
emitter=emitter)
|
||||
else:
|
||||
deployer_interface = BlockchainInterfaceFactory.get_interface(provider_uri=provider_uri)
|
||||
deployer_interface.connect()
|
||||
return deployer_interface
|
||||
|
||||
|
||||
def get_env_bool(var_name: str, default: bool) -> bool:
|
||||
if var_name in os.environ:
|
||||
# TODO: which is better: to fail on an incorrect envvar, or to use the default?
|
||||
# Currently doing the former.
|
||||
return strtobool(os.environ[var_name])
|
||||
else:
|
||||
return default
|
||||
return default
|
||||
|
||||
|
||||
def ensure_config_root(config_root):
|
||||
"""Ensure config root exists, because we need a default place to put output files."""
|
||||
config_root = config_root or DEFAULT_CONFIG_ROOT
|
||||
if not os.path.exists(config_root):
|
||||
os.makedirs(config_root)
|
||||
|
||||
|
||||
def _pre_launch_warnings(emitter, etherscan, hw_wallet):
|
||||
if not hw_wallet:
|
||||
emitter.echo(NO_HARDWARE_WALLET_WARNING, color='yellow')
|
||||
if etherscan:
|
||||
emitter.echo(ETHERSCAN_FLAG_ENABLED_WARNING, color='yellow')
|
||||
else:
|
||||
emitter.echo(ETHERSCAN_FLAG_DISABLED_WARNING, color='yellow')
|
||||
|
|
|
@ -19,25 +19,49 @@ import click
|
|||
import os
|
||||
from constant_sorrow.constants import NO_BLOCKCHAIN_CONNECTION, NO_PASSWORD
|
||||
|
||||
from nucypher.characters.banners import ALICE_BANNER
|
||||
from nucypher.characters.control.emitters import StdoutEmitter
|
||||
from nucypher.characters.control.interfaces import AliceInterface
|
||||
from nucypher.cli.actions.auth import get_client_password, get_nucypher_password
|
||||
from nucypher.cli.actions.config import (destroy_configuration, get_or_update_configuration, get_provider_process,
|
||||
handle_missing_configuration_file)
|
||||
from nucypher.cli.actions.config import (
|
||||
destroy_configuration,
|
||||
get_or_update_configuration,
|
||||
get_provider_process,
|
||||
handle_missing_configuration_file
|
||||
)
|
||||
from nucypher.cli.actions.select import select_client_account
|
||||
from nucypher.cli.actions.utils import make_cli_character
|
||||
from nucypher.cli.actions.utils import make_cli_character, setup_emitter
|
||||
from nucypher.cli.commands.deploy import option_gas_strategy
|
||||
from nucypher.cli.config import group_general_config
|
||||
from nucypher.cli.options import (group_options, option_config_file, option_config_root, option_controller_port,
|
||||
option_dev, option_discovery_port, option_dry_run, option_federated_only,
|
||||
option_force, option_geth, option_hw_wallet, option_light, option_m,
|
||||
option_middleware, option_min_stake, option_n, option_network, option_poa,
|
||||
option_provider_uri, option_registry_filepath, option_signer_uri, option_teacher_uri)
|
||||
from nucypher.cli.options import (
|
||||
group_options,
|
||||
option_config_file,
|
||||
option_config_root,
|
||||
option_controller_port,
|
||||
option_dev,
|
||||
option_discovery_port,
|
||||
option_dry_run,
|
||||
option_federated_only,
|
||||
option_force,
|
||||
option_geth,
|
||||
option_hw_wallet,
|
||||
option_light,
|
||||
option_m,
|
||||
option_middleware,
|
||||
option_min_stake,
|
||||
option_n,
|
||||
option_network,
|
||||
option_poa,
|
||||
option_provider_uri,
|
||||
option_registry_filepath,
|
||||
option_signer_uri,
|
||||
option_teacher_uri
|
||||
)
|
||||
from nucypher.cli.painting.help import paint_new_installation_help
|
||||
from nucypher.cli.types import EIP55_CHECKSUM_ADDRESS
|
||||
from nucypher.config.characters import AliceConfiguration
|
||||
from nucypher.config.constants import NUCYPHER_ENVVAR_ALICE_ETH_PASSWORD
|
||||
from nucypher.config.keyring import NucypherKeyring
|
||||
from nucypher.network.middleware import RestMiddleware
|
||||
from nucypher.utilities.sandbox.constants import TEMPORARY_DOMAIN
|
||||
|
||||
option_bob_verifying_key = click.option(
|
||||
|
@ -55,8 +79,19 @@ class AliceConfigOptions:
|
|||
|
||||
__option_name__ = 'config_options'
|
||||
|
||||
def __init__(self, dev, network, provider_uri, geth, federated_only, discovery_port,
|
||||
pay_with, registry_filepath, middleware, gas_strategy, signer_uri):
|
||||
def __init__(self,
|
||||
dev: bool,
|
||||
network: str,
|
||||
provider_uri: str,
|
||||
geth: bool,
|
||||
federated_only: bool,
|
||||
discovery_port: int,
|
||||
pay_with: str,
|
||||
registry_filepath: str,
|
||||
middleware: RestMiddleware,
|
||||
gas_strategy: str,
|
||||
signer_uri: str
|
||||
):
|
||||
|
||||
if federated_only and geth:
|
||||
raise click.BadOptionUsage(
|
||||
|
@ -145,7 +180,7 @@ class AliceFullConfigOptions:
|
|||
|
||||
__option_name__ = 'full_config_options'
|
||||
|
||||
def __init__(self, config_options, poa, light, m, n, duration_periods):
|
||||
def __init__(self, config_options, poa: bool, light: bool, m: int, n: int, duration_periods: int):
|
||||
self.config_options = config_options
|
||||
self.poa = poa
|
||||
self.light = light
|
||||
|
@ -153,7 +188,7 @@ class AliceFullConfigOptions:
|
|||
self.n = n
|
||||
self.duration_periods = duration_periods
|
||||
|
||||
def generate_config(self, emitter, config_root):
|
||||
def generate_config(self, emitter: StdoutEmitter, config_root: str) -> AliceConfiguration:
|
||||
|
||||
opts = self.config_options
|
||||
|
||||
|
@ -210,15 +245,15 @@ group_full_config_options = group_options(
|
|||
light=option_light,
|
||||
m=option_m,
|
||||
n=option_n,
|
||||
duration_periods=option_duration_periods,
|
||||
)
|
||||
duration_periods=option_duration_periods
|
||||
)
|
||||
|
||||
|
||||
class AliceCharacterOptions:
|
||||
|
||||
__option_name__ = 'character_options'
|
||||
|
||||
def __init__(self, config_options, hw_wallet, teacher_uri, min_stake):
|
||||
def __init__(self, config_options: AliceFullConfigOptions, hw_wallet: bool, teacher_uri: str, min_stake: int):
|
||||
self.config_options = config_options
|
||||
self.hw_wallet = hw_wallet
|
||||
self.teacher_uri = teacher_uri
|
||||
|
@ -262,15 +297,12 @@ group_character_options = group_options(
|
|||
hw_wallet=option_hw_wallet,
|
||||
teacher_uri=option_teacher_uri,
|
||||
min_stake=option_min_stake,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@click.group()
|
||||
def alice():
|
||||
"""
|
||||
"Alice the Policy Authority" management commands.
|
||||
"""
|
||||
pass
|
||||
""""Alice the Policy Authority" management commands."""
|
||||
|
||||
|
||||
@alice.command()
|
||||
|
@ -278,10 +310,8 @@ def alice():
|
|||
@option_config_root
|
||||
@group_general_config
|
||||
def init(general_config, full_config_options, config_root):
|
||||
"""
|
||||
Create a brand new persistent Alice.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""Create a brand new persistent Alice."""
|
||||
emitter = setup_emitter(general_config)
|
||||
if not config_root:
|
||||
config_root = general_config.config_root
|
||||
new_alice_config = full_config_options.generate_config(emitter, config_root)
|
||||
|
@ -293,10 +323,8 @@ def init(general_config, full_config_options, config_root):
|
|||
@group_general_config
|
||||
@group_full_config_options
|
||||
def config(general_config, config_file, full_config_options):
|
||||
"""
|
||||
View and optionally update existing Alice's configuration.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""View and optionally update existing Alice's configuration."""
|
||||
emitter = setup_emitter(general_config)
|
||||
configuration_file_location = config_file or AliceConfiguration.default_filepath()
|
||||
emitter.echo(f"Alice Configuration {configuration_file_location} \n {'='*55}")
|
||||
return get_or_update_configuration(emitter=emitter,
|
||||
|
@ -311,10 +339,8 @@ def config(general_config, config_file, full_config_options):
|
|||
@option_force
|
||||
@group_general_config
|
||||
def destroy(general_config, config_options, config_file, force):
|
||||
"""
|
||||
Delete existing Alice's configuration.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""Delete existing Alice's configuration."""
|
||||
emitter = setup_emitter(general_config)
|
||||
alice_config = config_options.create_config(emitter, config_file)
|
||||
return destroy_configuration(emitter, character_config=alice_config, force=force)
|
||||
|
||||
|
@ -326,10 +352,10 @@ def destroy(general_config, config_options, config_file, force):
|
|||
@group_general_config
|
||||
@group_character_options
|
||||
def run(general_config, character_options, config_file, controller_port, dry_run):
|
||||
"""
|
||||
Start Alice's web controller.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""Start Alice's web controller."""
|
||||
|
||||
# Setup
|
||||
emitter = setup_emitter(general_config)
|
||||
ALICE = character_options.create_character(emitter, config_file, general_config.json_ipc)
|
||||
|
||||
try:
|
||||
|
@ -362,10 +388,8 @@ def run(general_config, character_options, config_file, controller_port, dry_run
|
|||
@option_config_file
|
||||
@group_general_config
|
||||
def public_keys(general_config, character_options, config_file):
|
||||
"""
|
||||
Obtain Alice's public verification and encryption keys.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""Obtain Alice's public verification and encryption keys."""
|
||||
emitter = setup_emitter(general_config)
|
||||
ALICE = character_options.create_character(emitter, config_file, general_config.json_ipc, load_seednodes=False)
|
||||
response = ALICE.controller.public_keys()
|
||||
return response
|
||||
|
@ -377,10 +401,8 @@ def public_keys(general_config, character_options, config_file):
|
|||
@option_config_file
|
||||
@group_general_config
|
||||
def derive_policy_pubkey(general_config, label, character_options, config_file):
|
||||
"""
|
||||
Get a policy public key from a policy label.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""Get a policy public key from a policy label."""
|
||||
emitter = setup_emitter(general_config)
|
||||
ALICE = character_options.create_character(emitter, config_file, general_config.json_ipc, load_seednodes=False)
|
||||
return ALICE.controller.derive_policy_encrypting_key(label=label)
|
||||
|
||||
|
@ -391,21 +413,19 @@ def derive_policy_pubkey(general_config, label, character_options, config_file):
|
|||
@group_general_config
|
||||
@group_character_options
|
||||
def grant(general_config,
|
||||
# Other (required)
|
||||
bob_encrypting_key, bob_verifying_key, label, value, rate,
|
||||
|
||||
# Other
|
||||
expiration, m, n,
|
||||
|
||||
# API Options
|
||||
character_options, config_file
|
||||
):
|
||||
"""
|
||||
Create and enact an access policy for some Bob.
|
||||
"""
|
||||
config_options = character_options.config_options
|
||||
emitter = _setup_emitter(general_config)
|
||||
bob_encrypting_key,
|
||||
bob_verifying_key,
|
||||
label,
|
||||
value,
|
||||
rate,
|
||||
expiration,
|
||||
m, n,
|
||||
character_options,
|
||||
config_file):
|
||||
"""Create and enact an access policy for some Bob. """
|
||||
|
||||
# Setup
|
||||
emitter = setup_emitter(general_config)
|
||||
ALICE = character_options.create_character(emitter, config_file, general_config.json_ipc)
|
||||
|
||||
# Input validation
|
||||
|
@ -441,22 +461,10 @@ def grant(general_config,
|
|||
@group_character_options
|
||||
@option_config_file
|
||||
@group_general_config
|
||||
def revoke(general_config,
|
||||
|
||||
# Other (required)
|
||||
bob_verifying_key, label,
|
||||
|
||||
# API Options
|
||||
character_options, config_file
|
||||
):
|
||||
"""
|
||||
Revoke a policy.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
|
||||
def revoke(general_config, bob_verifying_key, label, character_options, config_file):
|
||||
"""Revoke a policy."""
|
||||
emitter = setup_emitter(general_config)
|
||||
ALICE = character_options.create_character(emitter, config_file, general_config.json_ipc)
|
||||
|
||||
# Request
|
||||
revoke_request = {'label': label, 'bob_verifying_key': bob_verifying_key}
|
||||
return ALICE.controller.revoke(request=revoke_request)
|
||||
|
||||
|
@ -466,31 +474,10 @@ def revoke(general_config,
|
|||
@group_character_options
|
||||
@option_config_file
|
||||
@group_general_config
|
||||
def decrypt(general_config,
|
||||
|
||||
# Other (required)
|
||||
label, message_kit,
|
||||
|
||||
# API Options
|
||||
character_options, config_file
|
||||
):
|
||||
"""
|
||||
Decrypt data encrypted under an Alice's policy public key.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
|
||||
def decrypt(general_config, label, message_kit, character_options, config_file):
|
||||
"""Decrypt data encrypted under an Alice's policy public key."""
|
||||
emitter = setup_emitter(general_config)
|
||||
ALICE = character_options.create_character(emitter, config_file, general_config.json_ipc, load_seednodes=False)
|
||||
|
||||
# Request
|
||||
request_data = {'label': label, 'message_kit': message_kit}
|
||||
response = ALICE.controller.decrypt(request=request_data)
|
||||
return response
|
||||
|
||||
|
||||
def _setup_emitter(general_config):
|
||||
# Banner
|
||||
emitter = general_config.emitter
|
||||
emitter.clear()
|
||||
emitter.banner(ALICE_BANNER)
|
||||
|
||||
return emitter
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import click
|
||||
|
||||
from nucypher.characters.banners import BOB_BANNER
|
||||
from nucypher.characters.control.emitters import StdoutEmitter
|
||||
from nucypher.characters.control.interfaces import BobInterface
|
||||
from nucypher.cli.actions.auth import get_nucypher_password
|
||||
from nucypher.cli.actions.config import (
|
||||
|
@ -9,17 +9,32 @@ from nucypher.cli.actions.config import (
|
|||
handle_missing_configuration_file
|
||||
)
|
||||
from nucypher.cli.actions.select import select_client_account
|
||||
from nucypher.cli.actions.utils import make_cli_character
|
||||
from nucypher.cli.actions.utils import make_cli_character, setup_emitter
|
||||
from nucypher.cli.commands.deploy import option_gas_strategy
|
||||
from nucypher.cli.config import group_general_config
|
||||
from nucypher.cli.options import (group_options, option_checksum_address, option_config_file, option_config_root,
|
||||
option_controller_port, option_dev, option_discovery_port, option_dry_run,
|
||||
option_federated_only, option_force, option_middleware, option_min_stake,
|
||||
option_network, option_provider_uri, option_registry_filepath, option_signer_uri,
|
||||
option_teacher_uri)
|
||||
from nucypher.cli.options import (
|
||||
group_options,
|
||||
option_checksum_address,
|
||||
option_config_file,
|
||||
option_config_root,
|
||||
option_controller_port,
|
||||
option_dev,
|
||||
option_discovery_port,
|
||||
option_dry_run,
|
||||
option_federated_only,
|
||||
option_force,
|
||||
option_middleware,
|
||||
option_min_stake,
|
||||
option_network,
|
||||
option_provider_uri,
|
||||
option_registry_filepath,
|
||||
option_signer_uri,
|
||||
option_teacher_uri
|
||||
)
|
||||
from nucypher.cli.painting.help import paint_new_installation_help
|
||||
from nucypher.config.characters import BobConfiguration
|
||||
from nucypher.crypto.powers import DecryptingPower
|
||||
from nucypher.network.middleware import RestMiddleware
|
||||
from nucypher.utilities.sandbox.constants import TEMPORARY_DOMAIN
|
||||
|
||||
|
||||
|
@ -27,8 +42,17 @@ class BobConfigOptions:
|
|||
|
||||
__option_name__ = 'config_options'
|
||||
|
||||
def __init__(self, provider_uri, network, registry_filepath, checksum_address, discovery_port,
|
||||
dev, middleware, federated_only, gas_strategy, signer_uri):
|
||||
def __init__(self,
|
||||
provider_uri: str,
|
||||
network: str,
|
||||
registry_filepath: str,
|
||||
checksum_address: str,
|
||||
discovery_port: int,
|
||||
dev: bool,
|
||||
middleware: RestMiddleware,
|
||||
federated_only: bool,
|
||||
gas_strategy: str,
|
||||
signer_uri: str):
|
||||
|
||||
self.provider_uri = provider_uri
|
||||
self.signer_uri = signer_uri
|
||||
|
@ -41,7 +65,7 @@ class BobConfigOptions:
|
|||
self.middleware = middleware
|
||||
self.federated_only = federated_only
|
||||
|
||||
def create_config(self, emitter, config_file):
|
||||
def create_config(self, emitter: StdoutEmitter, config_file: str) -> BobConfiguration:
|
||||
if self.dev:
|
||||
return BobConfiguration(
|
||||
emitter=emitter,
|
||||
|
@ -71,7 +95,7 @@ class BobConfigOptions:
|
|||
character_config_class=BobConfiguration,
|
||||
config_file=config_file)
|
||||
|
||||
def generate_config(self, emitter, config_root):
|
||||
def generate_config(self, emitter: StdoutEmitter, config_root: str) -> BobConfiguration:
|
||||
|
||||
checksum_address = self.checksum_address
|
||||
if not checksum_address and not self.federated_only:
|
||||
|
@ -115,21 +139,20 @@ group_config_options = group_options(
|
|||
dev=option_dev,
|
||||
middleware=option_middleware,
|
||||
federated_only=option_federated_only
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class BobCharacterOptions:
|
||||
|
||||
__option_name__ = 'character_options'
|
||||
|
||||
def __init__(self, config_options, teacher_uri, min_stake):
|
||||
def __init__(self, config_options: BobConfigOptions, teacher_uri: str, min_stake: int):
|
||||
self.config_options = config_options
|
||||
self.teacher_uri = teacher_uri
|
||||
self.min_stake = min_stake
|
||||
|
||||
def create_character(self, emitter, config_file):
|
||||
config = self.config_options.create_config(emitter, config_file)
|
||||
|
||||
return make_cli_character(character_config=config,
|
||||
emitter=emitter,
|
||||
unlock_keyring=not self.config_options.dev,
|
||||
|
@ -147,10 +170,7 @@ group_character_options = group_options(
|
|||
|
||||
@click.group()
|
||||
def bob():
|
||||
"""
|
||||
"Bob the Data Recipient" management commands.
|
||||
"""
|
||||
pass
|
||||
""""Bob the Data Recipient" management commands."""
|
||||
|
||||
|
||||
@bob.command()
|
||||
|
@ -159,10 +179,8 @@ def bob():
|
|||
@option_config_root
|
||||
@group_general_config
|
||||
def init(general_config, config_options, config_root):
|
||||
"""
|
||||
Create a brand new persistent Bob.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""Create a brand new persistent Bob."""
|
||||
emitter = setup_emitter(general_config)
|
||||
if not config_root:
|
||||
config_root = general_config.config_root
|
||||
new_bob_config = config_options.generate_config(emitter, config_root)
|
||||
|
@ -176,11 +194,10 @@ def init(general_config, config_options, config_root):
|
|||
@option_dry_run
|
||||
@group_general_config
|
||||
def run(general_config, character_options, config_file, controller_port, dry_run):
|
||||
"""
|
||||
Start Bob's controller.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""Start Bob's controller."""
|
||||
|
||||
# Setup
|
||||
emitter = setup_emitter(general_config)
|
||||
BOB = character_options.create_character(emitter, config_file)
|
||||
|
||||
# RPC
|
||||
|
@ -205,10 +222,8 @@ def run(general_config, character_options, config_file, controller_port, dry_run
|
|||
@group_config_options
|
||||
@group_general_config
|
||||
def config(general_config, config_options, config_file):
|
||||
"""
|
||||
View and optionally update existing Bob's configuration.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""View and optionally update existing Bob's configuration."""
|
||||
emitter = setup_emitter(general_config)
|
||||
bob_config = config_options.create_config(emitter, config_file)
|
||||
filepath = config_file or bob_config.config_file_location
|
||||
emitter.echo(f"Bob Configuration {filepath} \n {'='*55}")
|
||||
|
@ -224,19 +239,12 @@ def config(general_config, config_options, config_file):
|
|||
@option_force
|
||||
@group_general_config
|
||||
def destroy(general_config, config_options, config_file, force):
|
||||
"""
|
||||
Delete existing Bob's configuration.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
|
||||
# Validate
|
||||
"""Delete existing Bob's configuration."""
|
||||
emitter = setup_emitter(general_config)
|
||||
if config_options.dev:
|
||||
message = "'nucypher bob destroy' cannot be used in --dev mode"
|
||||
raise click.BadOptionUsage(option_name='--dev', message=message)
|
||||
|
||||
bob_config = config_options.create_config(emitter, config_file)
|
||||
|
||||
# Request
|
||||
return destroy_configuration(emitter, character_config=bob_config, force=force)
|
||||
|
||||
|
||||
|
@ -246,10 +254,8 @@ def destroy(general_config, config_options, config_file, force):
|
|||
@BobInterface.connect_cli('public_keys')
|
||||
@group_general_config
|
||||
def public_keys(general_config, character_options, config_file):
|
||||
"""
|
||||
Obtain Bob's public verification and encryption keys.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""Obtain Bob's public verification and encryption keys."""
|
||||
emitter = setup_emitter(general_config)
|
||||
BOB = character_options.create_character(emitter, config_file)
|
||||
response = BOB.controller.public_keys()
|
||||
return response
|
||||
|
@ -260,13 +266,17 @@ def public_keys(general_config, character_options, config_file):
|
|||
@option_config_file
|
||||
@BobInterface.connect_cli('retrieve')
|
||||
@group_general_config
|
||||
def retrieve(general_config, character_options, config_file,
|
||||
label, policy_encrypting_key, alice_verifying_key, message_kit):
|
||||
"""
|
||||
Obtain plaintext from encrypted data, if access was granted.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
def retrieve(general_config,
|
||||
character_options,
|
||||
config_file,
|
||||
label,
|
||||
policy_encrypting_key,
|
||||
alice_verifying_key,
|
||||
message_kit):
|
||||
"""Obtain plaintext from encrypted data, if access was granted."""
|
||||
|
||||
# Setup
|
||||
emitter = setup_emitter(general_config)
|
||||
BOB = character_options.create_character(emitter, config_file)
|
||||
|
||||
# Validate
|
||||
|
@ -285,12 +295,3 @@ def retrieve(general_config, character_options, config_file,
|
|||
|
||||
response = BOB.controller.retrieve(request=bob_request_data)
|
||||
return response
|
||||
|
||||
|
||||
def _setup_emitter(general_config):
|
||||
# Banner
|
||||
emitter = general_config.emitter
|
||||
emitter.clear()
|
||||
emitter.banner(BOB_BANNER)
|
||||
|
||||
return emitter
|
||||
|
|
|
@ -20,44 +20,86 @@ import json
|
|||
import click
|
||||
import os
|
||||
from constant_sorrow import constants
|
||||
from constant_sorrow.constants import (
|
||||
FULL
|
||||
)
|
||||
from constant_sorrow.constants import FULL
|
||||
from typing import Tuple
|
||||
|
||||
from nucypher.blockchain.eth.actors import ContractAdministrator, Trustee
|
||||
from nucypher.blockchain.eth.agents import ContractAgency, MultiSigAgent, NucypherTokenAgent
|
||||
from nucypher.blockchain.eth.constants import STAKING_ESCROW_CONTRACT_NAME
|
||||
from nucypher.blockchain.eth.interfaces import BlockchainDeployerInterface, BlockchainInterfaceFactory
|
||||
from nucypher.blockchain.eth.interfaces import BlockchainInterface
|
||||
from nucypher.blockchain.eth.networks import NetworksInventory
|
||||
from nucypher.blockchain.eth.registry import (BaseContractRegistry, GithubRegistrySource, InMemoryContractRegistry,
|
||||
RegistrySourceManager)
|
||||
from nucypher.blockchain.eth.registry import (
|
||||
BaseContractRegistry,
|
||||
GithubRegistrySource,
|
||||
InMemoryContractRegistry,
|
||||
RegistrySourceManager
|
||||
)
|
||||
from nucypher.blockchain.eth.signers import Signer
|
||||
from nucypher.blockchain.eth.token import NU
|
||||
from nucypher.characters.control.emitters import StdoutEmitter
|
||||
from nucypher.cli.actions.auth import get_client_password
|
||||
from nucypher.cli.actions.confirm import confirm_deployment
|
||||
from nucypher.cli.actions.select import select_client_account
|
||||
from nucypher.cli.actions.utils import establish_deployer_registry
|
||||
from nucypher.cli.actions.utils import (_pre_launch_warnings, ensure_config_root, establish_deployer_registry,
|
||||
initialize_deployer_interface)
|
||||
from nucypher.cli.config import group_general_config
|
||||
from nucypher.cli.literature import CANNOT_OVERWRITE_REGISTRY, CONFIRM_BEGIN_UPGRADE, \
|
||||
CONFIRM_BUILD_RETARGET_TRANSACTION, CONFIRM_LOCAL_REGISTRY_DESTRUCTION, CONFIRM_MANUAL_REGISTRY_DOWNLOAD, \
|
||||
CONFIRM_NETWORK_ACTIVATION, CONFIRM_RETARGET, CONFIRM_SELECTED_ACCOUNT, CONFIRM_TOKEN_TRANSFER, \
|
||||
CONTRACT_DEPLOYMENT_SERIES_BEGIN_ADVISORY, CONTRACT_IS_NOT_OWNABLE, DEPLOYER_ADDRESS_ZERO_ETH, DEPLOYER_BALANCE, \
|
||||
DISPLAY_SENDER_TOKEN_BALANCE_BEFORE_TRANSFER, ETHERSCAN_FLAG_DISABLED_WARNING, ETHERSCAN_FLAG_ENABLED_WARNING, \
|
||||
EXISTING_REGISTRY_FOR_DOMAIN, MINIMUM_POLICY_RATE_EXCEEDED_WARNING, NO_HARDWARE_WALLET_WARNING, \
|
||||
PROMPT_FOR_ALLOCATION_DATA_FILEPATH, PROMPT_NEW_DEFAULT_VALUE_FOR_RANGE, PROMPT_NEW_MAXIMUM_RANGE_VALUE, \
|
||||
PROMPT_NEW_MIN_RANGE_VALUE, PROMPT_NEW_OWNER_ADDRESS, PROMPT_RECIPIENT_CHECKSUM_ADDRESS, PROMPT_TOKEN_VALUE, \
|
||||
REGISTRY_NOT_AVAILABLE, SELECT_DEPLOYER_ACCOUNT, SUCCESSFUL_REGISTRY_CREATION, SUCCESSFUL_REGISTRY_DOWNLOAD, \
|
||||
SUCCESSFUL_RETARGET, SUCCESSFUL_RETARGET_TX_BUILT, SUCCESSFUL_SAVE_BATCH_DEPOSIT_RECEIPTS, \
|
||||
SUCCESSFUL_SAVE_DEPLOY_RECEIPTS, SUCCESSFUL_SAVE_MULTISIG_TX_PROPOSAL, SUCCESSFUL_UPGRADE, UNKNOWN_CONTRACT_NAME
|
||||
from nucypher.cli.options import (group_options, option_config_root, option_contract_name, option_etherscan,
|
||||
option_force, option_hw_wallet, option_poa, option_provider_uri, option_signer_uri)
|
||||
from nucypher.cli.painting.deployment import paint_contract_deployment, paint_deployer_contract_inspection, \
|
||||
paint_deployment_delay, paint_staged_deployment
|
||||
from nucypher.cli.literature import (
|
||||
CANNOT_OVERWRITE_REGISTRY,
|
||||
CONFIRM_BEGIN_UPGRADE,
|
||||
CONFIRM_BUILD_RETARGET_TRANSACTION,
|
||||
CONFIRM_LOCAL_REGISTRY_DESTRUCTION,
|
||||
CONFIRM_MANUAL_REGISTRY_DOWNLOAD,
|
||||
CONFIRM_NETWORK_ACTIVATION,
|
||||
CONFIRM_RETARGET,
|
||||
CONFIRM_SELECTED_ACCOUNT,
|
||||
CONFIRM_TOKEN_TRANSFER,
|
||||
CONTRACT_DEPLOYMENT_SERIES_BEGIN_ADVISORY,
|
||||
CONTRACT_IS_NOT_OWNABLE,
|
||||
DEPLOYER_ADDRESS_ZERO_ETH,
|
||||
DEPLOYER_BALANCE,
|
||||
DISPLAY_SENDER_TOKEN_BALANCE_BEFORE_TRANSFER,
|
||||
EXISTING_REGISTRY_FOR_DOMAIN,
|
||||
MINIMUM_POLICY_RATE_EXCEEDED_WARNING,
|
||||
PROMPT_FOR_ALLOCATION_DATA_FILEPATH,
|
||||
PROMPT_NEW_DEFAULT_VALUE_FOR_RANGE,
|
||||
PROMPT_NEW_MAXIMUM_RANGE_VALUE,
|
||||
PROMPT_NEW_MIN_RANGE_VALUE,
|
||||
PROMPT_NEW_OWNER_ADDRESS,
|
||||
PROMPT_RECIPIENT_CHECKSUM_ADDRESS,
|
||||
PROMPT_TOKEN_VALUE,
|
||||
REGISTRY_NOT_AVAILABLE,
|
||||
SELECT_DEPLOYER_ACCOUNT,
|
||||
SUCCESSFUL_REGISTRY_CREATION,
|
||||
SUCCESSFUL_REGISTRY_DOWNLOAD,
|
||||
SUCCESSFUL_RETARGET,
|
||||
SUCCESSFUL_RETARGET_TX_BUILT,
|
||||
SUCCESSFUL_SAVE_BATCH_DEPOSIT_RECEIPTS,
|
||||
SUCCESSFUL_SAVE_DEPLOY_RECEIPTS,
|
||||
SUCCESSFUL_SAVE_MULTISIG_TX_PROPOSAL,
|
||||
SUCCESSFUL_UPGRADE,
|
||||
UNKNOWN_CONTRACT_NAME
|
||||
)
|
||||
from nucypher.cli.options import (
|
||||
group_options,
|
||||
option_config_root,
|
||||
option_contract_name,
|
||||
option_etherscan,
|
||||
option_force,
|
||||
option_hw_wallet,
|
||||
option_poa,
|
||||
option_provider_uri,
|
||||
option_signer_uri
|
||||
)
|
||||
from nucypher.cli.painting.deployment import (
|
||||
paint_contract_deployment,
|
||||
paint_deployer_contract_inspection,
|
||||
paint_deployment_delay,
|
||||
paint_staged_deployment
|
||||
)
|
||||
from nucypher.cli.painting.help import echo_solidity_version
|
||||
from nucypher.cli.painting.multisig import paint_multisig_proposed_transaction
|
||||
from nucypher.cli.painting.transactions import paint_receipt_summary
|
||||
from nucypher.cli.types import EIP55_CHECKSUM_ADDRESS, EXISTING_READABLE_FILE, WEI
|
||||
from nucypher.config.constants import DEFAULT_CONFIG_ROOT
|
||||
|
||||
option_deployer_address = click.option('--deployer-address', help="Deployer's checksum address", type=EIP55_CHECKSUM_ADDRESS)
|
||||
option_registry_infile = click.option('--registry-infile', help="Input path for contract registry file", type=EXISTING_READABLE_FILE)
|
||||
|
@ -70,60 +112,26 @@ option_ignore_deployed = click.option('--ignore-deployed', help="Ignore already
|
|||
option_ignore_solidity_version = click.option('--ignore-solidity-check', help="Ignore solidity version compatibility check", is_flag=True)
|
||||
|
||||
|
||||
def _pre_launch_warnings(emitter, etherscan, hw_wallet):
|
||||
if not hw_wallet:
|
||||
emitter.echo(NO_HARDWARE_WALLET_WARNING, color='yellow')
|
||||
if etherscan:
|
||||
emitter.echo(ETHERSCAN_FLAG_ENABLED_WARNING, color='yellow')
|
||||
else:
|
||||
emitter.echo(ETHERSCAN_FLAG_DISABLED_WARNING, color='yellow')
|
||||
|
||||
|
||||
def _initialize_blockchain(poa, provider_uri, emitter, ignore_solidity_check, gas_strategy=None):
|
||||
if not BlockchainInterfaceFactory.is_interface_initialized(provider_uri=provider_uri):
|
||||
# Note: For test compatibility.
|
||||
deployer_interface = BlockchainDeployerInterface(provider_uri=provider_uri,
|
||||
poa=poa,
|
||||
ignore_solidity_check=ignore_solidity_check,
|
||||
gas_strategy=gas_strategy)
|
||||
|
||||
BlockchainInterfaceFactory.register_interface(interface=deployer_interface,
|
||||
sync=False,
|
||||
emitter=emitter)
|
||||
else:
|
||||
deployer_interface = BlockchainInterfaceFactory.get_interface(provider_uri=provider_uri)
|
||||
|
||||
deployer_interface.connect()
|
||||
return deployer_interface
|
||||
|
||||
|
||||
def _ensure_config_root(config_root):
|
||||
# Ensure config root exists, because we need a default place to put output files.
|
||||
config_root = config_root or DEFAULT_CONFIG_ROOT
|
||||
if not os.path.exists(config_root):
|
||||
os.makedirs(config_root)
|
||||
|
||||
|
||||
class ActorOptions:
|
||||
|
||||
__option_name__ = 'actor_options'
|
||||
|
||||
def __init__(self,
|
||||
provider_uri,
|
||||
deployer_address,
|
||||
contract_name,
|
||||
registry_infile,
|
||||
registry_outfile,
|
||||
hw_wallet,
|
||||
dev,
|
||||
force,
|
||||
poa,
|
||||
config_root,
|
||||
etherscan,
|
||||
provider_uri: str,
|
||||
deployer_address: str,
|
||||
contract_name: str,
|
||||
registry_infile: str,
|
||||
registry_outfile: str,
|
||||
hw_wallet: bool,
|
||||
dev: bool,
|
||||
force: bool,
|
||||
poa: bool,
|
||||
config_root: str,
|
||||
etherscan: bool,
|
||||
se_test_mode,
|
||||
ignore_solidity_check,
|
||||
gas_strategy,
|
||||
signer_uri
|
||||
gas_strategy: str,
|
||||
signer_uri: str
|
||||
):
|
||||
|
||||
self.provider_uri = provider_uri
|
||||
|
@ -142,14 +150,17 @@ class ActorOptions:
|
|||
self.se_test_mode = se_test_mode
|
||||
self.ignore_solidity_check = ignore_solidity_check
|
||||
|
||||
def create_actor(self, emitter, is_multisig: bool = False):
|
||||
def create_actor(self,
|
||||
emitter: StdoutEmitter,
|
||||
is_multisig: bool = False
|
||||
) -> Tuple[ContractAdministrator, str, BlockchainInterface, BaseContractRegistry]:
|
||||
|
||||
_ensure_config_root(self.config_root)
|
||||
deployer_interface = _initialize_blockchain(poa=self.poa,
|
||||
provider_uri=self.provider_uri,
|
||||
emitter=emitter,
|
||||
ignore_solidity_check=self.ignore_solidity_check,
|
||||
gas_strategy=self.gas_strategy)
|
||||
ensure_config_root(self.config_root)
|
||||
deployer_interface = initialize_deployer_interface(poa=self.poa,
|
||||
provider_uri=self.provider_uri,
|
||||
emitter=emitter,
|
||||
ignore_solidity_check=self.ignore_solidity_check,
|
||||
gas_strategy=self.gas_strategy)
|
||||
|
||||
# Warnings
|
||||
_pre_launch_warnings(emitter, self.etherscan, self.hw_wallet)
|
||||
|
@ -219,7 +230,7 @@ group_actor_options = group_options(
|
|||
config_root=option_config_root,
|
||||
etherscan=option_etherscan,
|
||||
ignore_solidity_check=option_ignore_solidity_version
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@click.group()
|
||||
|
@ -230,10 +241,7 @@ group_actor_options = group_options(
|
|||
expose_value=False,
|
||||
is_eager=True)
|
||||
def deploy():
|
||||
"""
|
||||
Manage contract and registry deployment.
|
||||
"""
|
||||
pass
|
||||
"""Manage contract and registry deployment."""
|
||||
|
||||
|
||||
@deploy.command(name='download-registry')
|
||||
|
@ -243,13 +251,11 @@ def deploy():
|
|||
@option_network
|
||||
@option_force
|
||||
def download_registry(general_config, config_root, registry_outfile, network, force):
|
||||
"""
|
||||
Download the latest registry.
|
||||
"""
|
||||
# Init
|
||||
emitter = general_config.emitter
|
||||
_ensure_config_root(config_root)
|
||||
"""Download the latest registry."""
|
||||
|
||||
# Setup
|
||||
emitter = general_config.emitter
|
||||
ensure_config_root(config_root)
|
||||
github_source = GithubRegistrySource(network=network, registry_name=BaseContractRegistry.REGISTRY_NAME)
|
||||
source_manager = RegistrySourceManager(sources=[github_source])
|
||||
|
||||
|
@ -279,23 +285,19 @@ def download_registry(general_config, config_root, registry_outfile, network, fo
|
|||
@option_poa
|
||||
@option_ignore_solidity_version
|
||||
def inspect(general_config, provider_uri, config_root, registry_infile, deployer_address, poa, ignore_solidity_check):
|
||||
"""
|
||||
Echo owner information and bare contract metadata.
|
||||
"""
|
||||
# Init
|
||||
"""Echo owner information and bare contract metadata."""
|
||||
emitter = general_config.emitter
|
||||
_ensure_config_root(config_root)
|
||||
_initialize_blockchain(poa=poa,
|
||||
provider_uri=provider_uri,
|
||||
emitter=emitter,
|
||||
ignore_solidity_check=ignore_solidity_check)
|
||||
|
||||
ensure_config_root(config_root)
|
||||
initialize_deployer_interface(poa=poa,
|
||||
provider_uri=provider_uri,
|
||||
emitter=emitter,
|
||||
ignore_solidity_check=ignore_solidity_check)
|
||||
local_registry = establish_deployer_registry(emitter=emitter,
|
||||
registry_infile=registry_infile,
|
||||
download_registry=not bool(registry_infile))
|
||||
paint_deployer_contract_inspection(emitter=emitter,
|
||||
registry=local_registry,
|
||||
deployer_address=deployer_address)
|
||||
return paint_deployer_contract_inspection(emitter=emitter,
|
||||
registry=local_registry,
|
||||
deployer_address=deployer_address)
|
||||
|
||||
|
||||
@deploy.command()
|
||||
|
@ -369,15 +371,12 @@ def upgrade(general_config, actor_options, retarget, target_address, ignore_depl
|
|||
@group_general_config
|
||||
@group_actor_options
|
||||
def rollback(general_config, actor_options):
|
||||
"""
|
||||
Rollback a proxy contract's target.
|
||||
"""
|
||||
"""Rollback a proxy contract's target."""
|
||||
emitter = general_config.emitter
|
||||
ADMINISTRATOR, _, _, _ = actor_options.create_actor(emitter)
|
||||
|
||||
if not actor_options.contract_name:
|
||||
raise click.BadArgumentUsage(message="--contract-name is required when using --rollback")
|
||||
ADMINISTRATOR.rollback_contract(contract_name=actor_options.contract_name)
|
||||
return ADMINISTRATOR.rollback_contract(contract_name=actor_options.contract_name)
|
||||
|
||||
|
||||
@deploy.command()
|
||||
|
@ -396,10 +395,7 @@ def rollback(general_config, actor_options):
|
|||
)
|
||||
@click.option('--activate', help="Activate a contract that is in idle mode", is_flag=True)
|
||||
def contracts(general_config, actor_options, mode, activate, gas, ignore_deployed, confirmations, parameters):
|
||||
"""
|
||||
Compile and deploy contracts.
|
||||
"""
|
||||
# Init
|
||||
"""Compile and deploy contracts."""
|
||||
|
||||
emitter = general_config.emitter
|
||||
ADMINISTRATOR, _, deployer_interface, local_registry = actor_options.create_actor(emitter)
|
||||
|
@ -507,21 +503,16 @@ def contracts(general_config, actor_options, mode, activate, gas, ignore_deploye
|
|||
@click.option('--allocation-infile', help="Input path for token allocation JSON file", type=EXISTING_READABLE_FILE)
|
||||
@option_gas
|
||||
def allocations(general_config, actor_options, allocation_infile, gas):
|
||||
"""
|
||||
Deposit stake allocations in batches
|
||||
"""
|
||||
"""Deposit stake allocations in batches"""
|
||||
emitter = general_config.emitter
|
||||
ADMINISTRATOR, _, deployer_interface, local_registry = actor_options.create_actor(emitter)
|
||||
|
||||
if not allocation_infile:
|
||||
allocation_infile = click.prompt(PROMPT_FOR_ALLOCATION_DATA_FILEPATH)
|
||||
receipts = ADMINISTRATOR.batch_deposits(allocation_data_filepath=allocation_infile,
|
||||
emitter=emitter,
|
||||
gas_limit=gas,
|
||||
interactive=not actor_options.force)
|
||||
|
||||
receipts_filepath = ADMINISTRATOR.save_deployment_receipts(receipts=receipts,
|
||||
filename_prefix='batch_deposits')
|
||||
receipts_filepath = ADMINISTRATOR.save_deployment_receipts(receipts=receipts, filename_prefix='batch_deposits')
|
||||
if emitter:
|
||||
emitter.echo(SUCCESSFUL_SAVE_BATCH_DEPOSIT_RECEIPTS.format(receipts_filepath=receipts_filepath), color='blue', bold=True)
|
||||
|
||||
|
@ -532,9 +523,8 @@ def allocations(general_config, actor_options, allocation_infile, gas):
|
|||
@option_target_address
|
||||
@click.option('--value', help="Amount of tokens to transfer in the smallest denomination", type=click.INT)
|
||||
def transfer_tokens(general_config, actor_options, target_address, value):
|
||||
"""
|
||||
Transfer tokens from contract's owner address to another address
|
||||
"""
|
||||
"""Transfer tokens from contract's owner address to another address"""
|
||||
|
||||
emitter = general_config.emitter
|
||||
ADMINISTRATOR, deployer_address, _, local_registry = actor_options.create_actor(emitter)
|
||||
|
||||
|
@ -552,7 +542,7 @@ def transfer_tokens(general_config, actor_options, target_address, value):
|
|||
target_address=target_address)
|
||||
click.confirm(confirmation, abort=True)
|
||||
receipt = token_agent.transfer(amount=int(value), sender_address=deployer_address, target_address=target_address)
|
||||
paint_receipt_summary(emitter=emitter, receipt=receipt)
|
||||
return paint_receipt_summary(emitter=emitter, receipt=receipt)
|
||||
|
||||
|
||||
@deploy.command("transfer-ownership")
|
||||
|
@ -607,13 +597,11 @@ def set_range(general_config, actor_options, minimum, default, maximum):
|
|||
"""
|
||||
emitter = general_config.emitter
|
||||
ADMINISTRATOR, _, _, _ = actor_options.create_actor(emitter)
|
||||
|
||||
if not minimum:
|
||||
minimum = click.prompt(PROMPT_NEW_MIN_RANGE_VALUE, type=click.IntRange(min=0))
|
||||
if not default:
|
||||
default = click.prompt(PROMPT_NEW_DEFAULT_VALUE_FOR_RANGE, type=click.IntRange(min=minimum))
|
||||
if not maximum:
|
||||
maximum = click.prompt(PROMPT_NEW_MAXIMUM_RANGE_VALUE, type=click.IntRange(min=default))
|
||||
|
||||
ADMINISTRATOR.set_min_reward_rate_range(minimum=minimum, default=default, maximum=maximum)
|
||||
emitter.echo(MINIMUM_POLICY_RATE_EXCEEDED_WARNING.format(minimum=minimum, maximum=maximum, default=default))
|
||||
|
|
|
@ -1,9 +1,27 @@
|
|||
"""
|
||||
This file is part of nucypher.
|
||||
|
||||
nucypher is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
nucypher is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
|
||||
import click
|
||||
from umbral.keys import UmbralPublicKey
|
||||
|
||||
from nucypher.characters.banners import ENRICO_BANNER
|
||||
from nucypher.characters.control.interfaces import EnricoInterface
|
||||
from nucypher.characters.lawful import Enrico
|
||||
from nucypher.cli.actions.utils import setup_emitter
|
||||
from nucypher.cli.config import group_general_config
|
||||
from nucypher.cli.options import option_dry_run, option_policy_encrypting_key
|
||||
from nucypher.cli.types import NETWORK_PORT
|
||||
|
@ -11,10 +29,7 @@ from nucypher.cli.types import NETWORK_PORT
|
|||
|
||||
@click.group()
|
||||
def enrico():
|
||||
"""
|
||||
"Enrico the Encryptor" management commands.
|
||||
"""
|
||||
pass
|
||||
""""Enrico the Encryptor" management commands."""
|
||||
|
||||
|
||||
@enrico.command()
|
||||
|
@ -23,15 +38,11 @@ def enrico():
|
|||
@click.option('--http-port', help="The host port to run Enrico HTTP services on", type=NETWORK_PORT)
|
||||
@group_general_config
|
||||
def run(general_config, policy_encrypting_key, dry_run, http_port):
|
||||
"""
|
||||
Start Enrico's controller.
|
||||
"""
|
||||
|
||||
### Setup ###
|
||||
emitter = _setup_emitter(general_config, policy_encrypting_key)
|
||||
"""Start Enrico's controller."""
|
||||
|
||||
# Setup
|
||||
emitter = setup_emitter(general_config, policy_encrypting_key)
|
||||
ENRICO = _create_enrico(emitter, policy_encrypting_key)
|
||||
#############
|
||||
|
||||
# RPC
|
||||
if general_config.json_ipc:
|
||||
|
@ -49,33 +60,16 @@ def run(general_config, policy_encrypting_key, dry_run, http_port):
|
|||
@EnricoInterface.connect_cli('encrypt_message')
|
||||
@group_general_config
|
||||
def encrypt(general_config, policy_encrypting_key, message):
|
||||
"""
|
||||
Encrypt a message under a given policy public key.
|
||||
"""
|
||||
|
||||
### Setup ###
|
||||
emitter = _setup_emitter(general_config, policy_encrypting_key)
|
||||
|
||||
"""Encrypt a message under a given policy public key."""
|
||||
emitter = setup_emitter(general_config=general_config, banner=policy_encrypting_key)
|
||||
ENRICO = _create_enrico(emitter, policy_encrypting_key)
|
||||
#############
|
||||
|
||||
# Request
|
||||
encryption_request = {'message': message}
|
||||
response = ENRICO.controller.encrypt_message(request=encryption_request)
|
||||
return response
|
||||
|
||||
|
||||
def _setup_emitter(general_config, policy_encrypting_key):
|
||||
emitter = general_config.emitter
|
||||
emitter.clear()
|
||||
emitter.banner(ENRICO_BANNER.format(policy_encrypting_key))
|
||||
|
||||
return emitter
|
||||
|
||||
|
||||
def _create_enrico(emitter, policy_encrypting_key):
|
||||
def _create_enrico(emitter, policy_encrypting_key) -> Enrico:
|
||||
policy_encrypting_key = UmbralPublicKey.from_bytes(bytes.fromhex(policy_encrypting_key))
|
||||
ENRICO = Enrico(policy_encrypting_key=policy_encrypting_key)
|
||||
ENRICO.controller.emitter = emitter
|
||||
|
||||
return ENRICO
|
||||
|
|
|
@ -1,13 +1,39 @@
|
|||
"""
|
||||
This file is part of nucypher.
|
||||
|
||||
nucypher is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
nucypher is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
|
||||
import click
|
||||
import os
|
||||
from constant_sorrow.constants import NO_BLOCKCHAIN_CONNECTION
|
||||
|
||||
from nucypher.characters.banners import FELIX_BANNER
|
||||
from nucypher.cli.actions.auth import get_client_password, get_nucypher_password, unlock_nucypher_keyring
|
||||
from nucypher.cli.actions.auth import (
|
||||
get_client_password,
|
||||
get_nucypher_password,
|
||||
unlock_nucypher_keyring
|
||||
)
|
||||
from nucypher.cli.actions.config import destroy_configuration, get_provider_process, handle_missing_configuration_file
|
||||
from nucypher.cli.actions.utils import setup_emitter
|
||||
from nucypher.cli.config import group_general_config
|
||||
from nucypher.cli.literature import CONFIRM_OVERWRITE_DATABASE, FELIX_RUN_MESSAGE, SUCCESSFUL_DATABASE_CREATION, \
|
||||
from nucypher.cli.literature import (
|
||||
CONFIRM_OVERWRITE_DATABASE,
|
||||
FELIX_RUN_MESSAGE,
|
||||
SUCCESSFUL_DATABASE_CREATION,
|
||||
SUCCESSFUL_DATABASE_DESTRUCTION
|
||||
)
|
||||
from nucypher.cli.options import (
|
||||
group_options,
|
||||
option_checksum_address,
|
||||
|
@ -39,9 +65,17 @@ class FelixConfigOptions:
|
|||
|
||||
__option_name__ = 'config_options'
|
||||
|
||||
def __init__(
|
||||
self, geth, dev, network, provider_uri, host,
|
||||
db_filepath, checksum_address, registry_filepath, poa, port):
|
||||
def __init__(self,
|
||||
geth,
|
||||
dev,
|
||||
network,
|
||||
provider_uri,
|
||||
host,
|
||||
db_filepath,
|
||||
checksum_address,
|
||||
registry_filepath,
|
||||
poa,
|
||||
port):
|
||||
|
||||
eth_node = NO_BLOCKCHAIN_CONNECTION
|
||||
if geth:
|
||||
|
@ -105,7 +139,7 @@ group_config_options = group_options(
|
|||
registry_filepath=option_registry_filepath,
|
||||
poa=option_poa,
|
||||
port=option_port,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class FelixCharacterOptions:
|
||||
|
@ -150,15 +184,12 @@ group_character_options = group_options(
|
|||
teacher_uri=option_teacher_uri,
|
||||
min_stake=option_min_stake,
|
||||
middleware=option_middleware,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@click.group()
|
||||
def felix():
|
||||
"""
|
||||
"Felix the Faucet" management commands.
|
||||
"""
|
||||
pass
|
||||
""""Felix the Faucet" management commands."""
|
||||
|
||||
|
||||
@felix.command()
|
||||
|
@ -167,14 +198,10 @@ def felix():
|
|||
@option_discovery_port(default=FelixConfiguration.DEFAULT_LEARNER_PORT)
|
||||
@group_config_options
|
||||
def init(general_config, config_options, config_root, discovery_port):
|
||||
"""
|
||||
Create a brand-new Felix.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config, config_options.checksum_address)
|
||||
|
||||
"""Create a brand-new Felix."""
|
||||
emitter = setup_emitter(general_config=general_config, banner=config_options.checksum_address)
|
||||
if not config_root: # Flag
|
||||
config_root = DEFAULT_CONFIG_ROOT # Envvar or init-only default
|
||||
|
||||
try:
|
||||
new_felix_config = config_options.generate_config(config_root, discovery_port)
|
||||
except Exception as e:
|
||||
|
@ -183,8 +210,6 @@ def init(general_config, config_options, config_root, discovery_port):
|
|||
else:
|
||||
emitter.echo(str(e), color='red', bold=True)
|
||||
raise click.Abort
|
||||
|
||||
# Paint Help
|
||||
paint_new_installation_help(emitter, new_configuration=new_felix_config)
|
||||
|
||||
|
||||
|
@ -194,10 +219,8 @@ def init(general_config, config_options, config_root, discovery_port):
|
|||
@option_force
|
||||
@group_general_config
|
||||
def destroy(general_config, config_options, config_file, force):
|
||||
"""
|
||||
Destroy Felix Configuration.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config, config_options.checksum_address)
|
||||
"""Destroy Felix Configuration."""
|
||||
emitter = setup_emitter(general_config, config_options.checksum_address)
|
||||
felix_config = config_options.create_config(emitter, config_file)
|
||||
destroy_configuration(emitter, character_config=felix_config, force=force)
|
||||
|
||||
|
@ -208,19 +231,14 @@ def destroy(general_config, config_options, config_file, force):
|
|||
@option_force
|
||||
@group_general_config
|
||||
def createdb(general_config, character_options, config_file, force):
|
||||
"""
|
||||
Create Felix DB.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config, character_options.config_options.checksum_address)
|
||||
|
||||
"""Create Felix DB."""
|
||||
emitter = setup_emitter(general_config, character_options.config_options.checksum_address)
|
||||
FELIX = character_options.create_character(emitter, config_file, general_config.debug)
|
||||
|
||||
if os.path.isfile(FELIX.db_filepath):
|
||||
if not force:
|
||||
click.confirm(CONFIRM_OVERWRITE_DATABASE, abort=True)
|
||||
os.remove(FELIX.db_filepath)
|
||||
emitter.echo(SUCCESSFUL_DATABASE_DESTRUCTION.format(path=FELIX.db_filepath))
|
||||
|
||||
FELIX.create_tables()
|
||||
emitter.echo(SUCCESSFUL_DATABASE_CREATION.format(path=FELIX.db_filepath), color='green')
|
||||
|
||||
|
@ -230,13 +248,9 @@ def createdb(general_config, character_options, config_file, force):
|
|||
@option_config_file
|
||||
@group_general_config
|
||||
def view(general_config, character_options, config_file):
|
||||
"""
|
||||
View Felix token balance.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config, character_options.config_options.checksum_address)
|
||||
|
||||
"""View Felix token balance."""
|
||||
emitter = setup_emitter(general_config, character_options.config_options.checksum_address)
|
||||
FELIX = character_options.create_character(emitter, config_file, general_config.debug)
|
||||
|
||||
token_balance = FELIX.token_balance
|
||||
eth_balance = FELIX.eth_balance
|
||||
emitter.echo(f"""
|
||||
|
@ -251,13 +265,9 @@ def view(general_config, character_options, config_file):
|
|||
@option_config_file
|
||||
@group_general_config
|
||||
def accounts(general_config, character_options, config_file):
|
||||
"""
|
||||
View Felix known accounts.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config, character_options.config_options.checksum_address)
|
||||
|
||||
"""View Felix known accounts."""
|
||||
emitter = setup_emitter(general_config, character_options.config_options.checksum_address)
|
||||
FELIX = character_options.create_character(emitter, config_file, general_config.debug)
|
||||
|
||||
accounts = FELIX.blockchain.client.accounts
|
||||
for account in accounts:
|
||||
emitter.echo(account)
|
||||
|
@ -269,13 +279,9 @@ def accounts(general_config, character_options, config_file):
|
|||
@option_dry_run
|
||||
@group_general_config
|
||||
def run(general_config, character_options, config_file, dry_run):
|
||||
"""
|
||||
Run Felix service.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config, character_options.config_options.checksum_address)
|
||||
|
||||
"""Run Felix services."""
|
||||
emitter = setup_emitter(general_config, character_options.config_options.checksum_address)
|
||||
FELIX = character_options.create_character(emitter, config_file, general_config.debug)
|
||||
|
||||
host = character_options.config_options.host
|
||||
port = character_options.config_options.port
|
||||
emitter.message(FELIX_RUN_MESSAGE.format(host=host, port=port))
|
||||
|
@ -284,13 +290,3 @@ def run(general_config, character_options, config_file, dry_run):
|
|||
web_services=not dry_run,
|
||||
distribution=True,
|
||||
crash_on_error=general_config.debug)
|
||||
|
||||
|
||||
def _setup_emitter(general_config, checksum_address):
|
||||
emitter = general_config.emitter
|
||||
|
||||
# Intro
|
||||
emitter.clear()
|
||||
emitter.banner(FELIX_BANNER.format(checksum_address or ''))
|
||||
|
||||
return emitter
|
||||
|
|
|
@ -17,11 +17,10 @@ along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
|||
"""
|
||||
|
||||
import click
|
||||
import os
|
||||
|
||||
from nucypher.blockchain.eth.actors import Executive, Trustee
|
||||
from nucypher.blockchain.eth.agents import ContractAgency, MultiSigAgent, NucypherTokenAgent
|
||||
from nucypher.blockchain.eth.interfaces import BlockchainDeployerInterface, BlockchainInterfaceFactory
|
||||
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory
|
||||
from nucypher.blockchain.eth.multisig import Authorization, Proposal
|
||||
from nucypher.blockchain.eth.registry import InMemoryContractRegistry, LocalContractRegistry
|
||||
from nucypher.blockchain.eth.signers import ClefSigner
|
||||
|
@ -31,44 +30,29 @@ from nucypher.cli.actions.select import select_client_account
|
|||
from nucypher.cli.actions.utils import get_registry
|
||||
from nucypher.cli.commands.stake import option_signer_uri
|
||||
from nucypher.cli.config import group_general_config
|
||||
from nucypher.cli.literature import CONFIRM_EXECUTE_MULTISIG_TRANSACTION, MULTISIG_SIGNATURE_RECEIVED, \
|
||||
PROMPT_CONFIRM_MULTISIG_SIGNATURE, PROMPT_FOR_RAW_SIGNATURE, PROMPT_NEW_MULTISIG_THRESHOLD, \
|
||||
SUCCESSFUL_MULTISIG_AUTHORIZATION, SUCCESSFUL_SAVE_MULTISIG_TX_PROPOSAL
|
||||
from nucypher.cli.options import (group_options, option_checksum_address, option_geth, option_hw_wallet, option_light,
|
||||
option_network, option_poa, option_provider_uri, option_registry_filepath)
|
||||
from nucypher.cli.literature import (
|
||||
CONFIRM_EXECUTE_MULTISIG_TRANSACTION,
|
||||
MULTISIG_SIGNATURE_RECEIVED,
|
||||
PROMPT_CONFIRM_MULTISIG_SIGNATURE,
|
||||
PROMPT_FOR_RAW_SIGNATURE,
|
||||
PROMPT_NEW_MULTISIG_THRESHOLD,
|
||||
SUCCESSFUL_MULTISIG_AUTHORIZATION,
|
||||
SUCCESSFUL_SAVE_MULTISIG_TX_PROPOSAL
|
||||
)
|
||||
from nucypher.cli.options import (
|
||||
group_options,
|
||||
option_checksum_address,
|
||||
option_geth,
|
||||
option_hw_wallet,
|
||||
option_light,
|
||||
option_network,
|
||||
option_poa,
|
||||
option_provider_uri,
|
||||
option_registry_filepath
|
||||
)
|
||||
from nucypher.cli.painting.multisig import paint_multisig_contract_info, paint_multisig_proposed_transaction
|
||||
from nucypher.cli.painting.transactions import paint_receipt_summary
|
||||
from nucypher.cli.types import EXISTING_READABLE_FILE
|
||||
from nucypher.config.constants import DEFAULT_CONFIG_ROOT
|
||||
|
||||
|
||||
def _setup_emitter(general_config):
|
||||
emitter = general_config.emitter
|
||||
return emitter
|
||||
|
||||
|
||||
def _initialize_blockchain(poa, provider_uri, emitter, gas_strategy=None):
|
||||
if not BlockchainInterfaceFactory.is_interface_initialized(provider_uri=provider_uri):
|
||||
# Note: For test compatibility.
|
||||
deployer_interface = BlockchainDeployerInterface(provider_uri=provider_uri,
|
||||
poa=poa,
|
||||
gas_strategy=gas_strategy)
|
||||
|
||||
BlockchainInterfaceFactory.register_interface(interface=deployer_interface,
|
||||
sync=False,
|
||||
emitter=emitter)
|
||||
else:
|
||||
deployer_interface = BlockchainInterfaceFactory.get_interface(provider_uri=provider_uri)
|
||||
|
||||
deployer_interface.connect()
|
||||
return deployer_interface
|
||||
|
||||
|
||||
def _ensure_config_root(config_root):
|
||||
# Ensure config root exists, because we need a default place to put output files.
|
||||
config_root = config_root or DEFAULT_CONFIG_ROOT
|
||||
if not os.path.exists(config_root):
|
||||
os.makedirs(config_root)
|
||||
|
||||
|
||||
# TODO: Same option group in nucypher status (called RegistryOptions). Make something generic
|
||||
|
@ -179,29 +163,20 @@ group_multisig_options = group_options(
|
|||
|
||||
@click.group()
|
||||
def multisig():
|
||||
"""
|
||||
Perform operations on NuCypher contracts via a MultiSig
|
||||
"""
|
||||
pass
|
||||
"""Perform operations on NuCypher contracts via a MultiSig"""
|
||||
|
||||
|
||||
@multisig.command()
|
||||
@group_general_config
|
||||
@group_blockchain_options
|
||||
def inspect(general_config, blockchain_options):
|
||||
"""
|
||||
Show information of the MultiSig contract
|
||||
"""
|
||||
# Init
|
||||
"""Show information of the MultiSig contract"""
|
||||
emitter = general_config.emitter
|
||||
_blockchain = blockchain_options.connect_blockchain(emitter, general_config.debug)
|
||||
registry = get_registry(network=blockchain_options.network)
|
||||
|
||||
multisig_agent = ContractAgency.get_agent(MultiSigAgent, registry=registry)
|
||||
token_agent = ContractAgency.get_agent(NucypherTokenAgent, registry=registry)
|
||||
|
||||
paint_multisig_contract_info(emitter, multisig_agent, token_agent)
|
||||
return
|
||||
return paint_multisig_contract_info(emitter, multisig_agent, token_agent)
|
||||
|
||||
|
||||
@multisig.command()
|
||||
|
@ -209,9 +184,7 @@ def inspect(general_config, blockchain_options):
|
|||
@group_blockchain_options
|
||||
@group_multisig_options
|
||||
def propose(general_config, blockchain_options, multisig_options):
|
||||
"""
|
||||
Create a proposal of MultiSig transaction
|
||||
"""
|
||||
"""Create a proposal of MultiSig transaction"""
|
||||
# TODO: Extend this command to cover this list of proposals
|
||||
# - Add new MultiSig owner
|
||||
# - Remove MultiSig owner
|
||||
|
|
|
@ -20,7 +20,6 @@ along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
|||
import click
|
||||
from web3 import Web3
|
||||
|
||||
from nucypher.blockchain.eth.actors import StakeHolder
|
||||
from nucypher.blockchain.eth.constants import MAX_UINT16
|
||||
from nucypher.blockchain.eth.events import EventRecord
|
||||
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory
|
||||
|
@ -29,29 +28,68 @@ from nucypher.blockchain.eth.token import NU, StakeList
|
|||
from nucypher.blockchain.eth.utils import datetime_at_period
|
||||
from nucypher.cli.actions.auth import get_client_password
|
||||
from nucypher.cli.actions.config import get_or_update_configuration, handle_missing_configuration_file
|
||||
from nucypher.cli.actions.confirm import (confirm_enable_restaking, confirm_enable_restaking_lock,
|
||||
confirm_enable_winding_down, confirm_large_stake, confirm_staged_stake)
|
||||
from nucypher.cli.actions.confirm import (
|
||||
confirm_enable_restaking,
|
||||
confirm_enable_restaking_lock,
|
||||
confirm_enable_winding_down,
|
||||
confirm_large_stake,
|
||||
confirm_staged_stake
|
||||
)
|
||||
from nucypher.cli.actions.select import handle_client_account_for_staking, select_stake
|
||||
from nucypher.cli.actions.utils import setup_emitter
|
||||
from nucypher.cli.config import group_general_config
|
||||
from nucypher.cli.literature import (BONDING_DETAILS, BONDING_RELEASE_INFO, COLLECTING_ETH_REWARD,
|
||||
COLLECTING_PREALLOCATION_REWARD, COLLECTING_TOKEN_REWARD,
|
||||
CONFIRM_BROADCAST_STAKE_DIVIDE, CONFIRM_DISABLE_RESTAKING,
|
||||
CONFIRM_DISABLE_WIND_DOWN, CONFIRM_NEW_MIN_POLICY_RATE, CONFIRM_PROLONG,
|
||||
CONFIRM_WORKER_AND_STAKER_ADDRESSES_ARE_EQUAL, DETACH_DETAILS,
|
||||
PERIOD_ADVANCED_WARNING, PROMPT_PROLONG_VALUE, PROMPT_STAKER_MIN_POLICY_RATE,
|
||||
PROMPT_STAKE_DIVIDE_VALUE, PROMPT_STAKE_EXTEND_VALUE, PROMPT_WORKER_ADDRESS,
|
||||
SUCCESSFUL_DETACH_WORKER, SUCCESSFUL_DISABLE_RESTAKING,
|
||||
SUCCESSFUL_DISABLE_WIND_DOWN, SUCCESSFUL_ENABLE_RESTAKE_LOCK,
|
||||
SUCCESSFUL_ENABLE_RESTAKING, SUCCESSFUL_ENABLE_WIND_DOWN,
|
||||
SUCCESSFUL_NEW_STAKEHOLDER_CONFIG, SUCCESSFUL_SET_MIN_POLICY_RATE,
|
||||
SUCCESSFUL_STAKE_DIVIDE, SUCCESSFUL_STAKE_PROLONG, SUCCESSFUL_WORKER_BONDING)
|
||||
from nucypher.cli.options import (group_options, option_config_file, option_config_root, option_event_name,
|
||||
option_force, option_hw_wallet, option_light, option_network, option_poa,
|
||||
option_provider_uri, option_registry_filepath, option_signer_uri,
|
||||
option_staking_address)
|
||||
from nucypher.cli.literature import (
|
||||
BONDING_DETAILS,
|
||||
BONDING_RELEASE_INFO,
|
||||
COLLECTING_ETH_REWARD,
|
||||
COLLECTING_PREALLOCATION_REWARD,
|
||||
COLLECTING_TOKEN_REWARD,
|
||||
CONFIRM_BROADCAST_STAKE_DIVIDE,
|
||||
CONFIRM_DISABLE_RESTAKING, CONFIRM_DISABLE_WIND_DOWN,
|
||||
CONFIRM_NEW_MIN_POLICY_RATE,
|
||||
CONFIRM_PROLONG,
|
||||
CONFIRM_WORKER_AND_STAKER_ADDRESSES_ARE_EQUAL,
|
||||
DETACH_DETAILS,
|
||||
PERIOD_ADVANCED_WARNING,
|
||||
PROMPT_PROLONG_VALUE,
|
||||
PROMPT_STAKER_MIN_POLICY_RATE,
|
||||
PROMPT_STAKE_DIVIDE_VALUE,
|
||||
PROMPT_STAKE_EXTEND_VALUE,
|
||||
PROMPT_WORKER_ADDRESS,
|
||||
SUCCESSFUL_DETACH_WORKER,
|
||||
SUCCESSFUL_DISABLE_RESTAKING, SUCCESSFUL_DISABLE_WIND_DOWN,
|
||||
SUCCESSFUL_ENABLE_RESTAKE_LOCK,
|
||||
SUCCESSFUL_ENABLE_RESTAKING,
|
||||
SUCCESSFUL_ENABLE_WIND_DOWN,
|
||||
SUCCESSFUL_NEW_STAKEHOLDER_CONFIG,
|
||||
SUCCESSFUL_SET_MIN_POLICY_RATE,
|
||||
SUCCESSFUL_STAKE_DIVIDE,
|
||||
SUCCESSFUL_STAKE_PROLONG,
|
||||
SUCCESSFUL_WORKER_BONDING
|
||||
)
|
||||
from nucypher.cli.options import (
|
||||
group_options,
|
||||
option_config_file,
|
||||
option_config_root,
|
||||
option_event_name,
|
||||
option_force,
|
||||
option_hw_wallet,
|
||||
option_light,
|
||||
option_network,
|
||||
option_poa,
|
||||
option_provider_uri,
|
||||
option_registry_filepath,
|
||||
option_signer_uri,
|
||||
option_staking_address
|
||||
)
|
||||
from nucypher.cli.painting.policies import paint_min_rate
|
||||
from nucypher.cli.painting.staking import paint_staged_stake, paint_staged_stake_division, paint_stakes, \
|
||||
paint_staking_accounts, paint_staking_confirmation
|
||||
from nucypher.cli.painting.staking import (
|
||||
paint_staged_stake,
|
||||
paint_staged_stake_division,
|
||||
paint_stakes,
|
||||
paint_staking_accounts,
|
||||
paint_staking_confirmation
|
||||
)
|
||||
from nucypher.cli.painting.status import paint_preallocation_status
|
||||
from nucypher.cli.painting.transactions import paint_receipt_summary
|
||||
from nucypher.cli.types import (
|
||||
|
@ -66,14 +104,6 @@ option_lock_periods = click.option('--lock-periods', help="Duration of stake in
|
|||
option_worker_address = click.option('--worker-address', help="Address to bond as an Ursula-Worker", type=EIP55_CHECKSUM_ADDRESS)
|
||||
|
||||
|
||||
def _setup_emitter(general_config):
|
||||
# Banner
|
||||
emitter = general_config.emitter
|
||||
emitter.banner(StakeHolder.banner)
|
||||
|
||||
return emitter
|
||||
|
||||
|
||||
class StakeHolderConfigOptions:
|
||||
|
||||
__option_name__ = 'config_options'
|
||||
|
@ -161,14 +191,9 @@ class StakerOptions:
|
|||
|
||||
def create_character(self, emitter, config_file, initial_address=None, *args, **kwargs):
|
||||
stakeholder_config = self.config_options.create_config(emitter, config_file)
|
||||
|
||||
if initial_address is None:
|
||||
initial_address = self.staking_address
|
||||
|
||||
return stakeholder_config.produce(
|
||||
initial_address=initial_address,
|
||||
*args, **kwargs
|
||||
)
|
||||
return stakeholder_config.produce(initial_address=initial_address, *args, **kwargs)
|
||||
|
||||
def get_blockchain(self):
|
||||
return BlockchainInterfaceFactory.get_interface(provider_uri=self.config_options.provider_uri) # Eager connection
|
||||
|
@ -253,10 +278,7 @@ group_transacting_staker_options = group_options(
|
|||
|
||||
@click.group()
|
||||
def stake():
|
||||
"""
|
||||
Manage stakes and other staker-related operations.
|
||||
"""
|
||||
pass
|
||||
"""Manage stakes and other staker-related operations."""
|
||||
|
||||
|
||||
@stake.command(name='init-stakeholder')
|
||||
|
@ -266,10 +288,11 @@ def stake():
|
|||
@group_general_config
|
||||
def init_stakeholder(general_config, config_root, force, config_options):
|
||||
"""Create a new stakeholder configuration."""
|
||||
emitter = _setup_emitter(general_config)
|
||||
emitter = setup_emitter(general_config)
|
||||
new_stakeholder = config_options.generate_config(config_root)
|
||||
filepath = new_stakeholder.to_configuration_file(override=force)
|
||||
emitter.echo(SUCCESSFUL_NEW_STAKEHOLDER_CONFIG.format(filepath=filepath), color='green')
|
||||
return # Exit
|
||||
|
||||
|
||||
@stake.command()
|
||||
|
@ -278,7 +301,7 @@ def init_stakeholder(general_config, config_root, force, config_options):
|
|||
@group_config_options
|
||||
def config(general_config, config_file, config_options):
|
||||
"""View and optionally update existing StakeHolder's configuration."""
|
||||
emitter = _setup_emitter(general_config)
|
||||
emitter = setup_emitter(general_config)
|
||||
configuration_file_location = config_file or StakeHolderConfiguration.default_filepath()
|
||||
emitter.echo(f"StakeHolder Configuration {configuration_file_location} \n {'='*55}")
|
||||
return get_or_update_configuration(emitter=emitter,
|
||||
|
@ -293,12 +316,11 @@ def config(general_config, config_file, config_options):
|
|||
@click.option('--all', help="List all stakes, including inactive", is_flag=True)
|
||||
@group_general_config
|
||||
def list_stakes(general_config, staker_options, config_file, all):
|
||||
"""
|
||||
List active stakes for current stakeholder.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""List active stakes for current stakeholder."""
|
||||
emitter = setup_emitter(general_config)
|
||||
STAKEHOLDER = staker_options.create_character(emitter, config_file)
|
||||
paint_stakes(emitter=emitter, stakeholder=STAKEHOLDER, paint_inactive=all)
|
||||
return # Exit
|
||||
|
||||
|
||||
@stake.command()
|
||||
|
@ -306,12 +328,11 @@ def list_stakes(general_config, staker_options, config_file, all):
|
|||
@option_config_file
|
||||
@group_general_config
|
||||
def accounts(general_config, staker_options, config_file):
|
||||
"""
|
||||
Show ETH and NU balances for stakeholder's accounts.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""Show ETH and NU balances for stakeholder's accounts."""
|
||||
emitter = setup_emitter(general_config)
|
||||
STAKEHOLDER = staker_options.create_character(emitter, config_file)
|
||||
paint_staking_accounts(emitter=emitter, wallet=STAKEHOLDER.wallet, registry=STAKEHOLDER.registry)
|
||||
return # Exit
|
||||
|
||||
|
||||
@stake.command('bond-worker')
|
||||
|
@ -321,14 +342,11 @@ def accounts(general_config, staker_options, config_file):
|
|||
@group_general_config
|
||||
@option_worker_address
|
||||
def bond_worker(general_config, transacting_staker_options, config_file, force, worker_address):
|
||||
"""
|
||||
Bond a worker to a staker.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""Bond a worker to a staker."""
|
||||
|
||||
emitter = setup_emitter(general_config)
|
||||
STAKEHOLDER = transacting_staker_options.create_character(emitter, config_file)
|
||||
blockchain = transacting_staker_options.get_blockchain()
|
||||
|
||||
economics = STAKEHOLDER.economics
|
||||
|
||||
client_account, staking_address = handle_client_account_for_staking(
|
||||
|
@ -376,6 +394,7 @@ def bond_worker(general_config, transacting_staker_options, config_file, force,
|
|||
transaction_type='bond_worker')
|
||||
emitter.echo(BONDING_DETAILS.format(current_period=current_period, bonded_date=bonded_date), color='green')
|
||||
emitter.echo(BONDING_RELEASE_INFO.format(release_period=release_period, release_date=release_date), color='green')
|
||||
return # Exit
|
||||
|
||||
|
||||
@stake.command('unbond-worker')
|
||||
|
@ -387,7 +406,7 @@ def unbond_worker(general_config, transacting_staker_options, config_file, force
|
|||
"""
|
||||
Unbond worker currently bonded to a staker.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
emitter = setup_emitter(general_config)
|
||||
|
||||
STAKEHOLDER = transacting_staker_options.create_character(emitter, config_file)
|
||||
blockchain = transacting_staker_options.get_blockchain()
|
||||
|
@ -402,11 +421,8 @@ def unbond_worker(general_config, transacting_staker_options, config_file, force
|
|||
force=force)
|
||||
|
||||
# TODO: Check preconditions (e.g., minWorkerPeriods)
|
||||
|
||||
worker_address = STAKEHOLDER.staking_agent.get_worker_from_staker(staking_address)
|
||||
|
||||
password = transacting_staker_options.get_password(blockchain, client_account)
|
||||
|
||||
STAKEHOLDER.assimilate(checksum_address=client_account, password=password)
|
||||
receipt = STAKEHOLDER.unbond_worker()
|
||||
|
||||
|
@ -421,6 +437,7 @@ def unbond_worker(general_config, transacting_staker_options, config_file, force
|
|||
chain_name=blockchain.client.chain_name,
|
||||
transaction_type='unbond_worker')
|
||||
emitter.echo(DETACH_DETAILS.format(current_period=current_period, bonded_date=bonded_date), color='green')
|
||||
return # Exit
|
||||
|
||||
|
||||
@stake.command()
|
||||
|
@ -431,14 +448,12 @@ def unbond_worker(general_config, transacting_staker_options, config_file, force
|
|||
@option_lock_periods
|
||||
@group_general_config
|
||||
def create(general_config, transacting_staker_options, config_file, force, value, lock_periods):
|
||||
"""
|
||||
Initialize a new stake.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""Initialize a new stake."""
|
||||
|
||||
# Setup
|
||||
emitter = setup_emitter(general_config)
|
||||
STAKEHOLDER = transacting_staker_options.create_character(emitter, config_file)
|
||||
blockchain = transacting_staker_options.get_blockchain()
|
||||
|
||||
economics = STAKEHOLDER.economics
|
||||
|
||||
client_account, staking_address = handle_client_account_for_staking(
|
||||
|
@ -509,7 +524,7 @@ def create(general_config, transacting_staker_options, config_file, force, value
|
|||
STAKEHOLDER.assimilate(checksum_address=client_account, password=password)
|
||||
|
||||
new_stake = STAKEHOLDER.initialize_stake(amount=value, lock_periods=lock_periods)
|
||||
paint_staking_confirmation(emitter=emitter, staker=STAKEHOLDER, new_stake=new_stake)
|
||||
return paint_staking_confirmation(emitter=emitter, staker=STAKEHOLDER, new_stake=new_stake)
|
||||
|
||||
|
||||
@stake.command()
|
||||
|
@ -520,11 +535,10 @@ def create(general_config, transacting_staker_options, config_file, force, value
|
|||
@option_force
|
||||
@group_general_config
|
||||
def restake(general_config, transacting_staker_options, config_file, enable, lock_until, force):
|
||||
"""
|
||||
Manage re-staking with --enable or --disable.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""Manage re-staking with --enable or --disable."""
|
||||
|
||||
# Setup
|
||||
emitter = setup_emitter(general_config)
|
||||
STAKEHOLDER = transacting_staker_options.create_character(emitter, config_file)
|
||||
blockchain = transacting_staker_options.get_blockchain()
|
||||
|
||||
|
@ -537,7 +551,6 @@ def restake(general_config, transacting_staker_options, config_file, enable, loc
|
|||
|
||||
# Authenticate
|
||||
password = transacting_staker_options.get_password(blockchain, client_account)
|
||||
|
||||
STAKEHOLDER.assimilate(checksum_address=client_account, password=password)
|
||||
|
||||
# Inner Exclusive Switch
|
||||
|
@ -559,6 +572,7 @@ def restake(general_config, transacting_staker_options, config_file, enable, loc
|
|||
emitter.echo(SUCCESSFUL_DISABLE_RESTAKING.format(staking_address=staking_address), color='green', verbosity=1)
|
||||
|
||||
paint_receipt_summary(receipt=receipt, emitter=emitter, chain_name=blockchain.client.chain_name)
|
||||
return # Exit
|
||||
|
||||
|
||||
@stake.command()
|
||||
|
@ -569,12 +583,10 @@ def restake(general_config, transacting_staker_options, config_file, enable, loc
|
|||
@option_force
|
||||
@group_general_config
|
||||
def winddown(general_config, transacting_staker_options, config_file, enable, lock_until, force):
|
||||
"""
|
||||
Manage winding down with --enable or --disable.
|
||||
"""
|
||||
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""Manage winding down with --enable or --disable."""
|
||||
|
||||
# Setup
|
||||
emitter = setup_emitter(general_config)
|
||||
STAKEHOLDER = transacting_staker_options.create_character(emitter, config_file)
|
||||
blockchain = transacting_staker_options.get_blockchain()
|
||||
|
||||
|
@ -587,7 +599,6 @@ def winddown(general_config, transacting_staker_options, config_file, enable, lo
|
|||
|
||||
# Authenticate
|
||||
password = transacting_staker_options.get_password(blockchain, client_account)
|
||||
|
||||
STAKEHOLDER.assimilate(checksum_address=client_account, password=password)
|
||||
|
||||
# Inner Exclusive Switch
|
||||
|
@ -603,6 +614,7 @@ def winddown(general_config, transacting_staker_options, config_file, enable, lo
|
|||
emitter.echo(SUCCESSFUL_DISABLE_WIND_DOWN.format(staking_address=staking_address), color='green', verbosity=1)
|
||||
|
||||
paint_receipt_summary(receipt=receipt, emitter=emitter, chain_name=blockchain.client.chain_name)
|
||||
return # Exit
|
||||
|
||||
|
||||
@stake.command()
|
||||
|
@ -614,12 +626,10 @@ def winddown(general_config, transacting_staker_options, config_file, enable, lo
|
|||
@click.option('--index', help="A specific stake index to resume", type=click.INT)
|
||||
@group_general_config
|
||||
def divide(general_config, transacting_staker_options, config_file, force, value, lock_periods, index):
|
||||
"""
|
||||
Create a new stake from part of an existing one.
|
||||
"""
|
||||
"""Create a new stake from part of an existing one."""
|
||||
|
||||
# Setup
|
||||
emitter = _setup_emitter(general_config)
|
||||
emitter = setup_emitter(general_config)
|
||||
STAKEHOLDER = transacting_staker_options.create_character(emitter, config_file)
|
||||
blockchain = transacting_staker_options.get_blockchain()
|
||||
economics = STAKEHOLDER.economics
|
||||
|
@ -698,6 +708,7 @@ def divide(general_config, transacting_staker_options, config_file, force, value
|
|||
|
||||
# Show the resulting stake list
|
||||
paint_stakes(emitter=emitter, stakeholder=STAKEHOLDER)
|
||||
return # Exit
|
||||
|
||||
|
||||
@stake.command()
|
||||
|
@ -711,7 +722,7 @@ def prolong(general_config, transacting_staker_options, config_file, force, lock
|
|||
"""Prolong an existing stake's duration."""
|
||||
|
||||
# Setup
|
||||
emitter = _setup_emitter(general_config)
|
||||
emitter = setup_emitter(general_config)
|
||||
STAKEHOLDER = transacting_staker_options.create_character(emitter, config_file)
|
||||
action_period = STAKEHOLDER.staking_agent.get_current_period()
|
||||
blockchain = transacting_staker_options.get_blockchain()
|
||||
|
@ -777,15 +788,17 @@ def prolong(general_config, transacting_staker_options, config_file, force, lock
|
|||
@click.option('--withdraw-address', help="Send fee collection to an alternate address", type=EIP55_CHECKSUM_ADDRESS)
|
||||
@option_force
|
||||
@group_general_config
|
||||
def collect_reward(general_config, transacting_staker_options, config_file,
|
||||
staking_reward, policy_fee, withdraw_address, force):
|
||||
"""
|
||||
Withdraw staking reward.
|
||||
"""
|
||||
|
||||
### Setup ###
|
||||
emitter = _setup_emitter(general_config)
|
||||
def collect_reward(general_config,
|
||||
transacting_staker_options,
|
||||
config_file,
|
||||
staking_reward,
|
||||
policy_fee,
|
||||
withdraw_address,
|
||||
force):
|
||||
"""Withdraw staking reward."""
|
||||
|
||||
# Setup
|
||||
emitter = setup_emitter(general_config)
|
||||
STAKEHOLDER = transacting_staker_options.create_character(emitter, config_file)
|
||||
blockchain = transacting_staker_options.get_blockchain()
|
||||
|
||||
|
@ -818,7 +831,7 @@ def collect_reward(general_config, transacting_staker_options, config_file,
|
|||
paint_receipt_summary(receipt=policy_receipt,
|
||||
chain_name=STAKEHOLDER.wallet.blockchain.client.chain_name,
|
||||
emitter=emitter)
|
||||
|
||||
return # Exit
|
||||
|
||||
@stake.command()
|
||||
@click.argument('action', type=click.Choice(['status', 'withdraw']))
|
||||
|
@ -827,26 +840,20 @@ def collect_reward(general_config, transacting_staker_options, config_file,
|
|||
@option_force
|
||||
@group_general_config
|
||||
def preallocation(general_config, transacting_staker_options, config_file, action, force):
|
||||
"""
|
||||
Claim token rewards collected by a preallocation contract.
|
||||
"""
|
||||
|
||||
### Setup ###
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""Claim token rewards collected by a preallocation contract."""
|
||||
|
||||
# Setup
|
||||
emitter = setup_emitter(general_config)
|
||||
STAKEHOLDER = transacting_staker_options.create_character(emitter, config_file)
|
||||
blockchain = transacting_staker_options.get_blockchain()
|
||||
|
||||
# Unauthenticated actions: status
|
||||
|
||||
if action == 'status':
|
||||
paint_preallocation_status(emitter=emitter,
|
||||
token_agent=STAKEHOLDER.token_agent,
|
||||
preallocation_agent=STAKEHOLDER.preallocation_escrow_agent)
|
||||
return
|
||||
return paint_preallocation_status(emitter=emitter,
|
||||
token_agent=STAKEHOLDER.token_agent,
|
||||
preallocation_agent=STAKEHOLDER.preallocation_escrow_agent)
|
||||
|
||||
# Authenticated actions: withdraw-tokens
|
||||
|
||||
client_account, staking_address = handle_client_account_for_staking(
|
||||
emitter=emitter,
|
||||
stakeholder=STAKEHOLDER,
|
||||
|
@ -854,9 +861,10 @@ def preallocation(general_config, transacting_staker_options, config_file, actio
|
|||
individual_allocation=STAKEHOLDER.individual_allocation,
|
||||
force=force)
|
||||
|
||||
# Authenticate
|
||||
password = transacting_staker_options.get_password(blockchain, client_account)
|
||||
|
||||
STAKEHOLDER.assimilate(checksum_address=client_account, password=password)
|
||||
|
||||
if action == 'withdraw':
|
||||
token_balance = NU.from_nunits(STAKEHOLDER.token_agent.get_balance(staking_address))
|
||||
locked_tokens = NU.from_nunits(STAKEHOLDER.preallocation_escrow_agent.unvested_tokens)
|
||||
|
@ -868,6 +876,7 @@ def preallocation(general_config, transacting_staker_options, config_file, actio
|
|||
paint_receipt_summary(receipt=receipt,
|
||||
chain_name=STAKEHOLDER.wallet.blockchain.client.chain_name,
|
||||
emitter=emitter)
|
||||
return # Exit
|
||||
|
||||
|
||||
@stake.command()
|
||||
|
@ -876,13 +885,10 @@ def preallocation(general_config, transacting_staker_options, config_file, actio
|
|||
@option_event_name
|
||||
@group_general_config
|
||||
def events(general_config, staker_options, config_file, event_name):
|
||||
"""
|
||||
See blockchain events associated to a staker
|
||||
"""
|
||||
|
||||
### Setup ###
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""See blockchain events associated to a staker"""
|
||||
|
||||
# Setup
|
||||
emitter = setup_emitter(general_config)
|
||||
STAKEHOLDER = staker_options.create_character(emitter, config_file)
|
||||
blockchain = staker_options.get_blockchain()
|
||||
|
||||
|
@ -910,6 +916,7 @@ def events(general_config, staker_options, config_file, event_name):
|
|||
entries = event_filter.get_all_entries()
|
||||
for event_record in entries:
|
||||
emitter.echo(f" - {EventRecord(event_record)}")
|
||||
return # Exit
|
||||
|
||||
|
||||
@stake.command('set-min-rate')
|
||||
|
@ -919,11 +926,10 @@ def events(general_config, staker_options, config_file, event_name):
|
|||
@group_general_config
|
||||
@click.option('--min-rate', help="Minimum acceptable fee rate, set by staker", type=WEI)
|
||||
def set_min_rate(general_config, transacting_staker_options, config_file, force, min_rate):
|
||||
"""
|
||||
Staker sets the minimum acceptable fee rate for their associated worker.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config)
|
||||
"""Staker sets the minimum acceptable fee rate for their associated worker."""
|
||||
|
||||
# Setup
|
||||
emitter = setup_emitter(general_config)
|
||||
STAKEHOLDER = transacting_staker_options.create_character(emitter, config_file)
|
||||
blockchain = transacting_staker_options.get_blockchain()
|
||||
|
||||
|
@ -939,17 +945,15 @@ def set_min_rate(general_config, transacting_staker_options, config_file, force,
|
|||
# TODO check range
|
||||
min_rate = click.prompt(PROMPT_STAKER_MIN_POLICY_RATE, type=WEI)
|
||||
password = transacting_staker_options.get_password(blockchain, client_account)
|
||||
|
||||
if not force:
|
||||
click.confirm(CONFIRM_NEW_MIN_POLICY_RATE.format(min_rate=min_rate), abort=True)
|
||||
|
||||
STAKEHOLDER.assimilate(checksum_address=client_account, password=password)
|
||||
receipt = STAKEHOLDER.set_min_fee_rate(min_rate=min_rate)
|
||||
|
||||
# Report Success
|
||||
message = SUCCESSFUL_SET_MIN_POLICY_RATE.format(min_rate=min_rate, staking_address=staking_address)
|
||||
emitter.echo(message, color='green')
|
||||
paint_receipt_summary(emitter=emitter,
|
||||
receipt=receipt,
|
||||
chain_name=blockchain.client.chain_name,
|
||||
transaction_type='set_min_rate')
|
||||
return paint_receipt_summary(emitter=emitter,
|
||||
receipt=receipt,
|
||||
chain_name=blockchain.client.chain_name,
|
||||
transaction_type='set_min_rate')
|
||||
|
|
|
@ -27,8 +27,7 @@ from nucypher.blockchain.eth.constants import (
|
|||
STAKING_ESCROW_CONTRACT_NAME
|
||||
)
|
||||
from nucypher.blockchain.eth.utils import datetime_at_period
|
||||
from nucypher.characters.banners import NU_BANNER
|
||||
from nucypher.cli.actions.utils import connect_to_blockchain, get_registry
|
||||
from nucypher.cli.actions.utils import connect_to_blockchain, get_registry, setup_emitter
|
||||
from nucypher.cli.config import group_general_config
|
||||
from nucypher.cli.options import (
|
||||
group_options,
|
||||
|
@ -46,7 +45,7 @@ from nucypher.cli.painting.policies import paint_fee_rate_range
|
|||
from nucypher.cli.painting.staking import paint_stakers
|
||||
from nucypher.cli.painting.status import paint_contract_status, paint_locked_tokens_status
|
||||
from nucypher.config.constants import NUCYPHER_ENVVAR_PROVIDER_URI
|
||||
from nucypher.cli.actions import
|
||||
|
||||
|
||||
class RegistryOptions:
|
||||
|
||||
|
@ -61,7 +60,7 @@ class RegistryOptions:
|
|||
self.network = network
|
||||
|
||||
def setup(self, general_config) -> tuple:
|
||||
emitter = _setup_emitter(general_config)
|
||||
emitter = setup_emitter(general_config)
|
||||
registry = get_registry(network=self.network, registry_filepath=self.registry_filepath)
|
||||
blockchain = connect_to_blockchain(emitter=emitter, provider_uri=self.provider_uri)
|
||||
return emitter, registry, blockchain
|
||||
|
@ -78,12 +77,6 @@ group_registry_options = group_options(
|
|||
)
|
||||
|
||||
|
||||
def _setup_emitter(general_config):
|
||||
emitter = general_config.emitter
|
||||
emitter.banner(NU_BANNER)
|
||||
return emitter
|
||||
|
||||
|
||||
@click.group()
|
||||
def status():
|
||||
"""Echo a snapshot of live NuCypher Network metadata."""
|
||||
|
|
|
@ -15,27 +15,52 @@ You should have received a copy of the GNU Affero General Public License
|
|||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
import click
|
||||
import os
|
||||
from constant_sorrow.constants import NO_BLOCKCHAIN_CONNECTION
|
||||
|
||||
from nucypher.blockchain.economics import EconomicsFactory
|
||||
from nucypher.blockchain.eth.utils import datetime_at_period
|
||||
from nucypher.characters.banners import URSULA_BANNER
|
||||
from nucypher.cli.actions.auth import get_client_password, get_nucypher_password
|
||||
from nucypher.cli.actions.config import (destroy_configuration, get_or_update_configuration, get_provider_process,
|
||||
handle_missing_configuration_file)
|
||||
from nucypher.cli.actions.config import (
|
||||
destroy_configuration,
|
||||
get_or_update_configuration,
|
||||
get_provider_process,
|
||||
handle_missing_configuration_file
|
||||
)
|
||||
from nucypher.cli.actions.network import determine_external_ip_address
|
||||
from nucypher.cli.actions.select import select_client_account, select_config_file, select_network
|
||||
from nucypher.cli.actions.utils import make_cli_character
|
||||
from nucypher.cli.actions.utils import make_cli_character, setup_emitter
|
||||
from nucypher.cli.commands.deploy import option_gas_strategy
|
||||
from nucypher.cli.config import group_general_config
|
||||
from nucypher.cli.literature import CONFIRMING_ACTIVITY_NOW, DEVELOPMENT_MODE_WARNING, FORCE_MODE_WARNING, \
|
||||
SUCCESSFUL_CONFIRM_ACTIVITY, SUCCESSFUL_MANUALLY_SAVE_METADATA
|
||||
from nucypher.cli.options import (group_options, option_config_file, option_config_root, option_db_filepath, option_dev,
|
||||
option_dry_run, option_federated_only, option_force, option_geth, option_light,
|
||||
option_min_stake, option_network, option_poa, option_provider_uri,
|
||||
option_registry_filepath, option_signer_uri, option_teacher_uri)
|
||||
from nucypher.cli.literature import (
|
||||
CONFIRMING_ACTIVITY_NOW,
|
||||
DEVELOPMENT_MODE_WARNING,
|
||||
FORCE_MODE_WARNING,
|
||||
SUCCESSFUL_CONFIRM_ACTIVITY,
|
||||
SUCCESSFUL_MANUALLY_SAVE_METADATA
|
||||
)
|
||||
from nucypher.cli.options import (
|
||||
group_options,
|
||||
option_config_file,
|
||||
option_config_root,
|
||||
option_db_filepath,
|
||||
option_dev,
|
||||
option_dry_run,
|
||||
option_federated_only,
|
||||
option_force,
|
||||
option_geth,
|
||||
option_light,
|
||||
option_min_stake,
|
||||
option_network,
|
||||
option_poa,
|
||||
option_provider_uri,
|
||||
option_registry_filepath,
|
||||
option_signer_uri,
|
||||
option_teacher_uri
|
||||
)
|
||||
from nucypher.cli.painting.help import paint_new_installation_help
|
||||
from nucypher.cli.painting.transactions import paint_receipt_summary
|
||||
from nucypher.cli.types import EIP55_CHECKSUM_ADDRESS, NETWORK_PORT
|
||||
|
@ -49,9 +74,22 @@ class UrsulaConfigOptions:
|
|||
|
||||
__option_name__ = 'config_options'
|
||||
|
||||
def __init__(self, geth, provider_uri, worker_address, federated_only, rest_host,
|
||||
rest_port, db_filepath, network, registry_filepath, dev, poa, light,
|
||||
gas_strategy, signer_uri, availability_check):
|
||||
def __init__(self,
|
||||
geth,
|
||||
provider_uri,
|
||||
worker_address,
|
||||
federated_only,
|
||||
rest_host,
|
||||
rest_port,
|
||||
db_filepath,
|
||||
network,
|
||||
registry_filepath,
|
||||
dev,
|
||||
poa,
|
||||
light,
|
||||
gas_strategy,
|
||||
signer_uri,
|
||||
availability_check):
|
||||
|
||||
if federated_only:
|
||||
if geth:
|
||||
|
@ -247,14 +285,13 @@ group_character_options = group_options(
|
|||
config_options=group_config_options,
|
||||
lonely=click.option('--lonely', help="Do not connect to seednodes", is_flag=True),
|
||||
teacher_uri=option_teacher_uri,
|
||||
min_stake=option_min_stake)
|
||||
min_stake=option_min_stake
|
||||
)
|
||||
|
||||
|
||||
@click.group()
|
||||
def ursula():
|
||||
"""
|
||||
"Ursula the Untrusted" PRE Re-encryption node management commands.
|
||||
"""
|
||||
""""Ursula the Untrusted" PRE Re-encryption node management commands."""
|
||||
|
||||
|
||||
@ursula.command()
|
||||
|
@ -266,14 +303,14 @@ def init(general_config, config_options, force, config_root):
|
|||
"""
|
||||
Create a new Ursula node configuration.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config, config_options.worker_address)
|
||||
emitter = setup_emitter(general_config, config_options.worker_address)
|
||||
_pre_launch_warnings(emitter, dev=None, force=force)
|
||||
if not config_root:
|
||||
config_root = general_config.config_root
|
||||
if not config_options.federated_only and not config_options.domains: # TODO: Again, weird network/domains mapping. See UrsulaConfigOptions' constructor. #1580
|
||||
config_options.domains = {select_network(emitter)}
|
||||
ursula_config = config_options.generate_config(emitter, config_root, force)
|
||||
paint_new_installation_help(emitter, new_configuration=ursula_config)
|
||||
return paint_new_installation_help(emitter, new_configuration=ursula_config)
|
||||
|
||||
|
||||
@ursula.command()
|
||||
|
@ -285,14 +322,14 @@ def destroy(general_config, config_options, config_file, force):
|
|||
"""
|
||||
Delete Ursula node configuration.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config, config_options.worker_address)
|
||||
emitter = setup_emitter(general_config, config_options.worker_address)
|
||||
_pre_launch_warnings(emitter, dev=config_options.dev, force=force)
|
||||
if not config_file:
|
||||
config_file = select_config_file(emitter=emitter,
|
||||
checksum_address=config_options.worker_address,
|
||||
config_class=UrsulaConfiguration)
|
||||
ursula_config = config_options.create_config(emitter, config_file)
|
||||
destroy_configuration(emitter, character_config=ursula_config, force=force)
|
||||
return destroy_configuration(emitter, character_config=ursula_config, force=force)
|
||||
|
||||
|
||||
@ursula.command()
|
||||
|
@ -300,13 +337,11 @@ def destroy(general_config, config_options, config_file, force):
|
|||
@option_config_file
|
||||
@group_general_config
|
||||
def forget(general_config, config_options, config_file):
|
||||
"""
|
||||
Forget all known nodes.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config, config_options.worker_address)
|
||||
"""Forget all known nodes."""
|
||||
emitter = setup_emitter(general_config, config_options.worker_address)
|
||||
_pre_launch_warnings(emitter, dev=config_options.dev, force=None)
|
||||
ursula_config = config_options.create_config(emitter, config_file)
|
||||
forget(emitter, configuration=ursula_config)
|
||||
return forget(emitter, configuration=ursula_config)
|
||||
|
||||
|
||||
@ursula.command()
|
||||
|
@ -321,7 +356,7 @@ def run(general_config, character_options, config_file, interactive, dry_run, me
|
|||
"""Run an "Ursula" node."""
|
||||
|
||||
worker_address = character_options.config_options.worker_address
|
||||
emitter = _setup_emitter(general_config, worker_address=worker_address)
|
||||
emitter = setup_emitter(general_config)
|
||||
_pre_launch_warnings(emitter, dev=character_options.config_options.dev, force=None)
|
||||
|
||||
if not character_options.config_options.dev and not config_file:
|
||||
|
@ -329,11 +364,9 @@ def run(general_config, character_options, config_file, interactive, dry_run, me
|
|||
checksum_address=worker_address,
|
||||
config_class=UrsulaConfiguration)
|
||||
|
||||
ursula_config, URSULA = character_options.create_character(
|
||||
emitter=emitter,
|
||||
config_file=config_file,
|
||||
json_ipc=general_config.json_ipc
|
||||
)
|
||||
ursula_config, URSULA = character_options.create_character(emitter=emitter,
|
||||
config_file=config_file,
|
||||
json_ipc=general_config.json_ipc)
|
||||
|
||||
return URSULA.run(emitter=emitter,
|
||||
start_reactor=not dry_run,
|
||||
|
@ -346,10 +379,8 @@ def run(general_config, character_options, config_file, interactive, dry_run, me
|
|||
@option_config_file
|
||||
@group_general_config
|
||||
def save_metadata(general_config, character_options, config_file):
|
||||
"""
|
||||
Manually write node metadata to disk without running.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config, character_options.config_options.worker_address)
|
||||
"""Manually write node metadata to disk without running."""
|
||||
emitter = setup_emitter(general_config, character_options.config_options.worker_address)
|
||||
_pre_launch_warnings(emitter, dev=character_options.config_options.dev, force=None)
|
||||
_, URSULA = character_options.create_character(emitter, config_file, general_config.json_ipc, load_seednodes=False)
|
||||
metadata_path = URSULA.write_node_metadata(node=URSULA)
|
||||
|
@ -361,10 +392,8 @@ def save_metadata(general_config, character_options, config_file):
|
|||
@option_config_file
|
||||
@group_general_config
|
||||
def config(general_config, config_options, config_file):
|
||||
"""
|
||||
View and optionally update the Ursula node's configuration.
|
||||
"""
|
||||
emitter = _setup_emitter(general_config, config_options.worker_address)
|
||||
"""View and optionally update the Ursula node's configuration."""
|
||||
emitter = setup_emitter(general_config, config_options.worker_address)
|
||||
if not config_file:
|
||||
config_file = select_config_file(emitter=emitter,
|
||||
checksum_address=config_options.worker_address,
|
||||
|
@ -385,7 +414,7 @@ def commit_to_next_period(general_config, character_options, config_file):
|
|||
"""Manually make a commitment to the next period."""
|
||||
|
||||
# Setup
|
||||
emitter = _setup_emitter(general_config, character_options.config_options.worker_address)
|
||||
emitter = setup_emitter(general_config, character_options.config_options.worker_address)
|
||||
_pre_launch_warnings(emitter, dev=character_options.config_options.dev, force=None)
|
||||
_, URSULA = character_options.create_character(emitter, config_file, general_config.json_ipc, load_seednodes=False)
|
||||
|
||||
|
@ -406,15 +435,6 @@ def commit_to_next_period(general_config, character_options, config_file):
|
|||
# TODO: Check CommitmentMade event (see #1193)
|
||||
|
||||
|
||||
def _setup_emitter(general_config, worker_address):
|
||||
# Banner
|
||||
emitter = general_config.emitter
|
||||
emitter.clear()
|
||||
emitter.banner(URSULA_BANNER.format(worker_address or ''))
|
||||
|
||||
return emitter
|
||||
|
||||
|
||||
def _pre_launch_warnings(emitter, dev, force):
|
||||
if dev:
|
||||
emitter.echo(DEVELOPMENT_MODE_WARNING, color='yellow', verbosity=1)
|
||||
|
|
|
@ -29,22 +29,46 @@ from nucypher.blockchain.eth.agents import ContractAgency, WorkLockAgent
|
|||
from nucypher.blockchain.eth.signers import Signer
|
||||
from nucypher.blockchain.eth.token import NU
|
||||
from nucypher.blockchain.eth.utils import prettify_eth_amount
|
||||
from nucypher.characters.banners import WORKLOCK_BANNER
|
||||
from nucypher.cli.actions.auth import get_client_password
|
||||
from nucypher.cli.actions.select import select_client_account
|
||||
from nucypher.cli.actions.utils import connect_to_blockchain, get_registry
|
||||
from nucypher.cli.actions.utils import connect_to_blockchain, get_registry, setup_emitter
|
||||
from nucypher.cli.config import group_general_config
|
||||
from nucypher.cli.literature import AVAILABLE_CLAIM_NOTICE, BIDDERS_ALREADY_VERIFIED, BIDDING_WINDOW_CLOSED, \
|
||||
BIDS_VALID_NO_FORCE_REFUND_INDICATED, CLAIM_ALREADY_PLACED, COMPLETED_BID_VERIFICATION, CONFIRM_BID_VERIFICATION, \
|
||||
CONFIRM_COLLECT_WORKLOCK_REFUND, CONFIRM_REQUEST_WORKLOCK_COMPENSATION, CONFIRM_WORKLOCK_CLAIM, \
|
||||
PROMPT_BID_VERIFY_GAS_LIMIT, REQUESTING_WORKLOCK_COMPENSATION, SUBMITTING_WORKLOCK_CLAIM, \
|
||||
SUBMITTING_WORKLOCK_REFUND_REQUEST, SUCCESSFUL_BID_CANCELLATION, WHALE_WARNING, \
|
||||
WORKLOCK_ADDITIONAL_COMPENSATION_AVAILABLE, WORKLOCK_CLAIM_ADVISORY
|
||||
from nucypher.cli.options import (group_options, option_force, option_hw_wallet, option_network, option_provider_uri,
|
||||
option_registry_filepath, option_signer_uri)
|
||||
from nucypher.cli.literature import (
|
||||
AVAILABLE_CLAIM_NOTICE,
|
||||
BIDDERS_ALREADY_VERIFIED,
|
||||
BIDDING_WINDOW_CLOSED,
|
||||
BIDS_VALID_NO_FORCE_REFUND_INDICATED,
|
||||
CLAIM_ALREADY_PLACED,
|
||||
COMPLETED_BID_VERIFICATION,
|
||||
CONFIRM_BID_VERIFICATION,
|
||||
CONFIRM_COLLECT_WORKLOCK_REFUND,
|
||||
CONFIRM_REQUEST_WORKLOCK_COMPENSATION,
|
||||
CONFIRM_WORKLOCK_CLAIM,
|
||||
PROMPT_BID_VERIFY_GAS_LIMIT,
|
||||
REQUESTING_WORKLOCK_COMPENSATION,
|
||||
SUBMITTING_WORKLOCK_CLAIM,
|
||||
SUBMITTING_WORKLOCK_REFUND_REQUEST,
|
||||
SUCCESSFUL_BID_CANCELLATION,
|
||||
WHALE_WARNING,
|
||||
WORKLOCK_ADDITIONAL_COMPENSATION_AVAILABLE,
|
||||
WORKLOCK_CLAIM_ADVISORY
|
||||
)
|
||||
from nucypher.cli.options import (
|
||||
group_options,
|
||||
option_force,
|
||||
option_hw_wallet,
|
||||
option_network,
|
||||
option_provider_uri,
|
||||
option_registry_filepath,
|
||||
option_signer_uri
|
||||
)
|
||||
from nucypher.cli.painting.transactions import paint_receipt_summary
|
||||
from nucypher.cli.painting.worklock import paint_bidder_status, paint_bidding_notice, paint_worklock_claim, \
|
||||
from nucypher.cli.painting.worklock import (
|
||||
paint_bidder_status,
|
||||
paint_bidding_notice,
|
||||
paint_worklock_claim,
|
||||
paint_worklock_status
|
||||
)
|
||||
from nucypher.cli.types import DecimalRange, EIP55_CHECKSUM_ADDRESS
|
||||
from nucypher.config.constants import NUCYPHER_ENVVAR_PROVIDER_URI
|
||||
|
||||
|
@ -53,12 +77,6 @@ option_bidder_address = click.option('--bidder-address',
|
|||
type=EIP55_CHECKSUM_ADDRESS)
|
||||
|
||||
|
||||
def _setup_emitter(general_config, network: str):
|
||||
emitter = general_config.emitter
|
||||
emitter.banner(WORKLOCK_BANNER.format(network))
|
||||
return emitter
|
||||
|
||||
|
||||
class WorkLockOptions:
|
||||
|
||||
__option_name__ = 'worklock_options'
|
||||
|
@ -77,7 +95,7 @@ class WorkLockOptions:
|
|||
self.network = network
|
||||
|
||||
def setup(self, general_config) -> tuple:
|
||||
emitter = _setup_emitter(general_config, network=self.network.capitalize())
|
||||
emitter = setup_emitter(general_config) # TODO: Restore Banner: network=self.network.capitalize()
|
||||
registry = get_registry(network=self.network, registry_filepath=self.registry_filepath)
|
||||
blockchain = connect_to_blockchain(emitter=emitter, provider_uri=self.provider_uri)
|
||||
return emitter, registry, blockchain
|
||||
|
@ -118,10 +136,7 @@ group_worklock_options = group_options(
|
|||
|
||||
@click.group()
|
||||
def worklock():
|
||||
"""
|
||||
Participate in NuCypher's WorkLock to obtain NU tokens
|
||||
"""
|
||||
pass
|
||||
"""Participate in NuCypher's WorkLock to obtain NU tokens"""
|
||||
|
||||
|
||||
@worklock.command()
|
||||
|
|
|
@ -28,7 +28,6 @@ from nucypher.utilities.logging import GlobalLoggerSettings
|
|||
|
||||
|
||||
class GroupGeneralConfig:
|
||||
|
||||
__option_name__ = 'general_config'
|
||||
|
||||
verbosity = 0
|
||||
|
@ -40,15 +39,15 @@ class GroupGeneralConfig:
|
|||
log_to_file = get_env_bool("NUCYPHER_FILE_LOGS", True)
|
||||
|
||||
def __init__(self,
|
||||
json_ipc,
|
||||
verbose,
|
||||
quiet,
|
||||
no_logs,
|
||||
console_logs,
|
||||
file_logs,
|
||||
sentry_logs,
|
||||
log_level,
|
||||
debug):
|
||||
json_ipc: bool,
|
||||
verbose: bool,
|
||||
quiet: bool,
|
||||
no_logs: bool,
|
||||
console_logs: bool,
|
||||
file_logs: bool,
|
||||
sentry_logs: bool,
|
||||
log_level: bool,
|
||||
debug: bool):
|
||||
|
||||
self.log = Logger(self.__class__.__name__)
|
||||
|
||||
|
@ -78,11 +77,9 @@ class GroupGeneralConfig:
|
|||
self.emitter.message("Verbose mode is enabled", color='blue')
|
||||
|
||||
# Logging
|
||||
|
||||
if debug and no_logs:
|
||||
raise click.BadOptionUsage(
|
||||
option_name="no-logs",
|
||||
message="--debug and --no-logs cannot be used at the same time.")
|
||||
message = "--debug and --no-logs cannot be used at the same time."
|
||||
raise click.BadOptionUsage(option_name="no-logs", message=message)
|
||||
|
||||
# Defaults
|
||||
if file_logs is None:
|
||||
|
@ -121,28 +118,39 @@ class GroupGeneralConfig:
|
|||
|
||||
group_general_config = group_options(
|
||||
GroupGeneralConfig,
|
||||
json_ipc=click.option('-J', '--json-ipc', help="Send all IPC output to stdout as JSON, and turn off the rest", is_flag=True),
|
||||
|
||||
verbose=click.option('-v', '--verbose', help="Verbose console messages", is_flag=True),
|
||||
quiet=click.option('-Q', '--quiet', help="Disable console messages", is_flag=True),
|
||||
no_logs=click.option('-L', '--no-logs', help="Disable all logging output", is_flag=True),
|
||||
console_logs=click.option('--console-logs/--no-console-logs',
|
||||
help="Enable/disable logging to console. "
|
||||
"Defaults to `--no-console-logs`.",
|
||||
default=False),
|
||||
file_logs=click.option('--file-logs/--no-file-logs',
|
||||
help="Enable/disable logging to file. "
|
||||
"Defaults to NUCYPHER_FILE_LOGS, or to `--file-logs` if it is not set.",
|
||||
default=None),
|
||||
sentry_logs=click.option('--sentry-logs/--no-sentry-logs',
|
||||
help="Enable/disable logging to Sentry. "
|
||||
"Defaults to NUCYPHER_SENTRY_LOGS, or to `--sentry-logs` if it is not set.",
|
||||
default=None),
|
||||
log_level=click.option('--log-level', help="The log level for this process. Is overridden by --debug.",
|
||||
type=click.Choice(['critical', 'error', 'warn', 'info', 'debug']),
|
||||
default='info'),
|
||||
debug=click.option('-D', '--debug',
|
||||
help="Enable debugging mode, crashing on more exceptions instead of trying to recover. "
|
||||
"Also sets log level to \"debug\", turns on console and file logging "
|
||||
"and turns off Sentry logging.",
|
||||
is_flag=True),
|
||||
)
|
||||
|
||||
json_ipc=click.option('-J', '--json-ipc',
|
||||
help="Send all IPC output to stdout as JSON, and turn off the rest",
|
||||
is_flag=True),
|
||||
|
||||
console_logs=click.option(
|
||||
'--console-logs/--no-console-logs',
|
||||
help="Enable/disable logging to console. Defaults to `--no-console-logs`.",
|
||||
default=False),
|
||||
|
||||
file_logs=click.option(
|
||||
'--file-logs/--no-file-logs',
|
||||
help="Enable/disable logging to file. Defaults to NUCYPHER_FILE_LOGS, or to `--file-logs` if it is not set.",
|
||||
default=None),
|
||||
|
||||
sentry_logs=click.option(
|
||||
'--sentry-logs/--no-sentry-logs',
|
||||
help="Enable/disable logging to Sentry. Defaults to NUCYPHER_SENTRY_LOGS, or to `--sentry-logs` if it is not set.",
|
||||
default=None),
|
||||
|
||||
log_level=click.option(
|
||||
'--log-level', help="The log level for this process. Is overridden by --debug.",
|
||||
type=click.Choice(['critical', 'error', 'warn', 'info', 'debug']),
|
||||
default='info'),
|
||||
|
||||
debug=click.option(
|
||||
'-D', '--debug',
|
||||
help="Enable debugging mode, crashing on more exceptions instead of trying to recover. "
|
||||
"Also sets log level to \"debug\", turns on console and file logging "
|
||||
"and turns off Sentry logging.",
|
||||
is_flag=True),
|
||||
)
|
||||
|
|
|
@ -130,7 +130,7 @@ SUCCESSFUL_DISABLE_WIND_DOWN = 'Successfully disabled winding down for {staking_
|
|||
|
||||
|
||||
#
|
||||
# Restaking Lock
|
||||
# Restaking
|
||||
#
|
||||
|
||||
RESTAKING_LOCK_AGREEMENT = """
|
||||
|
@ -142,11 +142,6 @@ CONFIRM_RESTAKING_LOCK = "Confirm enable re-staking lock for staker {staking_add
|
|||
|
||||
SUCCESSFUL_ENABLE_RESTAKE_LOCK = 'Successfully enabled re-staking lock for {staking_address} until {lock_until}'
|
||||
|
||||
|
||||
#
|
||||
# Restaking
|
||||
#
|
||||
|
||||
RESTAKING_AGREEMENT = """
|
||||
By enabling the re-staking for {staking_address}, all staking rewards will be automatically added to your existing stake.
|
||||
"""
|
||||
|
|
|
@ -24,7 +24,7 @@ from nucypher.cli.painting.help import echo_version
|
|||
@click.group()
|
||||
@click.option('--version', help="Echo the CLI version", is_flag=True, callback=echo_version, expose_value=False, is_eager=True)
|
||||
def nucypher_cli():
|
||||
pass
|
||||
"""Top level command for all things nucypher."""
|
||||
|
||||
|
||||
#
|
||||
|
@ -54,17 +54,17 @@ def nucypher_cli():
|
|||
ENTRY_POINTS = (
|
||||
|
||||
# Characters
|
||||
alice.alice, # Author of Policies
|
||||
bob.bob, # Builder of Capsules
|
||||
enrico.enrico, # Encryptor of Data
|
||||
ursula.ursula, # Untrusted Re-Encryption Proxy
|
||||
alice.alice, # Author of Policies
|
||||
bob.bob, # Builder of Capsules
|
||||
enrico.enrico, # Encryptor of Data
|
||||
ursula.ursula, # Untrusted Re-Encryption Proxy
|
||||
|
||||
# Utility Commands
|
||||
stake.stake, # Stake Management
|
||||
status.status, # Network Status
|
||||
felix.felix, # Faucet
|
||||
stake.stake, # Stake Management
|
||||
status.status, # Network Status
|
||||
felix.felix, # Faucet
|
||||
multisig.multisig, # MultiSig operations
|
||||
worklock.worklock # WorkLock
|
||||
worklock.worklock # WorkLock
|
||||
)
|
||||
|
||||
for entry_point in ENTRY_POINTS:
|
||||
|
|
|
@ -27,6 +27,13 @@ def echo_version(ctx, param, value):
|
|||
ctx.exit()
|
||||
|
||||
|
||||
def echo_solidity_version(ctx, param, value):
|
||||
if not value or ctx.resilient_parsing:
|
||||
return
|
||||
click.secho(f"Supported solidity version: {SOLIDITY_COMPILER_VERSION}", bold=True)
|
||||
ctx.exit()
|
||||
|
||||
|
||||
def paint_new_installation_help(emitter, new_configuration):
|
||||
character_config_class = new_configuration.__class__
|
||||
character_name = character_config_class.NAME.lower()
|
||||
|
@ -54,10 +61,3 @@ def paint_new_installation_help(emitter, new_configuration):
|
|||
how_to_run_message = f"\nTo run {adjective} {character_name.capitalize()} node from the default configuration filepath run: \n\n'{suggested_command}'\n"
|
||||
|
||||
emitter.echo(how_to_run_message.format(suggested_command), color='green')
|
||||
|
||||
|
||||
def echo_solidity_version(ctx, param, value):
|
||||
if not value or ctx.resilient_parsing:
|
||||
return
|
||||
click.secho(f"Supported solidity version: {SOLIDITY_COMPILER_VERSION}", bold=True)
|
||||
ctx.exit()
|
|
@ -17,8 +17,9 @@ along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
|||
|
||||
|
||||
from collections import Counter
|
||||
from typing import List
|
||||
|
||||
import maya
|
||||
from typing import List
|
||||
from web3.main import Web3
|
||||
|
||||
from nucypher.blockchain.eth.agents import AdjudicatorAgent, ContractAgency, NucypherTokenAgent, PolicyManagerAgent, \
|
||||
|
@ -27,6 +28,7 @@ from nucypher.blockchain.eth.constants import NULL_ADDRESS
|
|||
from nucypher.blockchain.eth.interfaces import BlockchainInterfaceFactory
|
||||
from nucypher.blockchain.eth.token import NU
|
||||
from nucypher.blockchain.eth.utils import prettify_eth_amount
|
||||
from nucypher.network.nicknames import nickname_from_seed
|
||||
|
||||
|
||||
def paint_contract_status(registry, emitter):
|
||||
|
|
|
@ -14,6 +14,8 @@ GNU Affero General Public License for more details.
|
|||
You should have received a copy of the GNU Affero General Public License
|
||||
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
|
||||
from collections import deque
|
||||
|
||||
import maya
|
||||
|
|
|
@ -187,7 +187,7 @@ def test_cancel_bid(click_runner,
|
|||
mock_worklock_agent.assert_contract_calls(calls=expected_calls)
|
||||
|
||||
|
||||
@pytest.mark.skip
|
||||
@pytest.mark.skip # TODO
|
||||
def test_post_initialization(click_runner,
|
||||
mocker,
|
||||
mock_worklock_agent,
|
||||
|
|
Loading…
Reference in New Issue