Merge pull request #2917 from theref/ursula-init

Improve handling of network selection in ursula init
pull/2913/head
KPrasch 2022-05-09 08:25:37 -07:00 committed by GitHub
commit 7f6e033dab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 61 additions and 22 deletions

View File

@ -0,0 +1 @@
Only print relevant network options when running `nucypher ursula init`

View File

@ -22,6 +22,7 @@ class NetworksInventory: # TODO: See #1564
IBEX = 'ibex'
LYNX = 'lynx'
ORYX = 'oryx'
ETH = 'ethereum'
# TODO: Use naming scheme to preserve multiple compatibility with multiple deployments to a single network?
POLYGON = 'polygon'
@ -30,18 +31,22 @@ class NetworksInventory: # TODO: See #1564
UNKNOWN = 'unknown' # TODO: Is there a better way to signal an unknown network?
DEFAULT = MAINNET
__to_ethereum_chain_id = {
__to_chain_id_eth = {
MAINNET: 1, # Ethereum Mainnet
ORYX: 3, # Ropsten
IBEX: 4, # Rinkeby
LYNX: 5, # Goerli
}
__to_chain_id_polygon = {
# TODO: Use naming scheme?
POLYGON: 137, # Polygon Mainnet
MUMBAI: 80001, # Polygon Testnet (Mumbai)
}
NETWORKS = tuple(__to_ethereum_chain_id.keys())
ETH_NETWORKS = tuple(__to_chain_id_eth.keys())
POLY_NETWORKS = tuple(__to_chain_id_polygon.keys())
NETWORKS = ETH_NETWORKS + POLY_NETWORKS
class UnrecognizedNetwork(RuntimeError):
pass

View File

@ -136,13 +136,23 @@ def select_client_account(emitter,
return chosen_account
def select_network(emitter: StdoutEmitter, message: Optional[str] = None) -> str:
def select_network(emitter: StdoutEmitter, network_type: str, message: Optional[str] = None) -> str:
"""Interactively select a network from nucypher networks inventory list"""
emitter.message(message=message or str(), color='yellow')
rows = [[n] for n in NetworksInventory.NETWORKS]
emitter.echo(tabulate(rows, showindex='always'))
choice = click.prompt(SELECT_NETWORK, default=0, type=click.IntRange(0, len(NetworksInventory.NETWORKS)-1))
network = NetworksInventory.NETWORKS[choice]
emitter.message(message=message or str(), color="yellow")
if network_type == NetworksInventory.ETH:
network_list = NetworksInventory.ETH_NETWORKS
elif network_type == NetworksInventory.POLYGON:
network_list = NetworksInventory.POLY_NETWORKS
else:
raise(ValueError("Network type must be either 'eth' or 'polygon'"))
rows = [[n] for n in network_list]
emitter.echo(tabulate(rows, showindex="always"))
choice = click.prompt(
SELECT_NETWORK,
default=0,
type=click.IntRange(0, len(rows) - 1),
)
network = network_list[choice]
return network

View File

@ -23,6 +23,7 @@ from eth_typing import ChecksumAddress
from nucypher.blockchain.eth.agents import ContractAgency, PREApplicationAgent
from nucypher.blockchain.eth.constants import NULL_ADDRESS
from nucypher.blockchain.eth.networks import NetworksInventory
from nucypher.blockchain.eth.signers import Signer
from nucypher.cli.actions.auth import get_client_password
from nucypher.cli.actions.select import select_network
@ -103,7 +104,7 @@ def bond(registry_filepath, eth_provider_uri, signer_uri, operator_address, stak
emitter.message('--signer is required', color='red')
raise click.Abort()
if not network:
network = select_network(emitter=emitter)
network = select_network(emitter=emitter, network_type=NetworksInventory.ETH)
signer = Signer.from_signer_uri(signer_uri)
transacting_power = TransactingPower(account=staking_provider, signer=signer)
@ -167,7 +168,7 @@ def unbond(registry_filepath, eth_provider_uri, signer_uri, staking_provider, ne
emitter.message('--signer is required', color='red')
raise click.Abort()
if not network:
network = select_network(emitter=emitter)
network = select_network(emitter=emitter, network_type=NetworksInventory.ETH)
connect_to_blockchain(eth_provider_uri=eth_provider_uri, emitter=emitter)
registry = get_registry(network=network, registry_filepath=registry_filepath)

View File

@ -21,6 +21,7 @@ from pathlib import Path
import click
from nucypher.blockchain.eth.signers.software import ClefSigner
from nucypher.blockchain.eth.networks import NetworksInventory
from nucypher.cli.actions.auth import get_client_password, get_nucypher_password, recover_keystore
from nucypher.cli.actions.configure import (
destroy_configuration,
@ -73,6 +74,7 @@ from nucypher.config.constants import (
from nucypher.crypto.keystore import Keystore
class UrsulaConfigOptions:
__option_name__ = 'config_options'
@ -341,10 +343,12 @@ def init(general_config, config_options, force, config_root, key_material):
config_root = general_config.config_root
if not config_options.federated_only and not config_options.eth_provider_uri:
raise click.BadOptionUsage('--eth-provider', message=click.style("--eth-provider is required to initialize a new ursula.", fg="red"))
if not config_options.federated_only and not config_options.payment_provider:
raise click.BadOptionUsage('--payment-provider', message=click.style("--payment-provider is required to initialize a new ursula.", fg="red"))
if not config_options.federated_only and not config_options.domain:
config_options.domain = select_network(emitter, message="Select Staking Network")
config_options.domain = select_network(emitter, message="Select Staking Network", network_type=NetworksInventory.ETH)
if not config_options.federated_only and not config_options.payment_network:
config_options.payment_network = select_network(emitter, message="Select Payment Network")
config_options.payment_network = select_network(emitter, message="Select Payment Network", network_type=NetworksInventory.POLYGON)
ursula_config = config_options.generate_config(emitter=emitter,
config_root=config_root,
force=force,

View File

@ -487,6 +487,7 @@ class CharacterConfiguration(BaseConfiguration):
blockchain_args = {'filepath': registry_filepath,
'poa': poa,
'eth_provider_uri': eth_provider_uri,
'payment_provider': payment_provider,
'gas_strategy': gas_strategy,
'max_gas_price': max_gas_price}
if any(blockchain_args.values()):

View File

@ -37,7 +37,8 @@ from tests.constants import (
MOCK_CUSTOM_INSTALLATION_PATH,
MOCK_IP_ADDRESS,
MOCK_IP_ADDRESS_2,
TEST_ETH_PROVIDER_URI
TEST_ETH_PROVIDER_URI,
TEST_POLYGON_PROVIDER_URI
)
@ -129,6 +130,7 @@ def test_coexisting_configurations(click_runner,
'--network', TEMPORARY_DOMAIN,
'--payment-network', TEMPORARY_DOMAIN,
'--eth-provider', TEST_ETH_PROVIDER_URI,
'--payment-provider', TEST_POLYGON_PROVIDER_URI,
'--operator-address', ursula,
'--rest-host', MOCK_IP_ADDRESS,
'--registry-filepath', str(agency_local_registry.filepath.absolute()),
@ -152,6 +154,7 @@ def test_coexisting_configurations(click_runner,
'--rest-host', MOCK_IP_ADDRESS_2,
'--registry-filepath', str(agency_local_registry.filepath.absolute()),
'--eth-provider', TEST_ETH_PROVIDER_URI,
'--payment-provider', TEST_POLYGON_PROVIDER_URI,
'--config-root', str(custom_filepath.absolute()))
result = click_runner.invoke(nucypher_cli, init_args, catch_exceptions=False, env=envvars)
@ -239,6 +242,7 @@ def test_corrupted_configuration(click_runner,
init_args = ('ursula', 'init',
'--eth-provider', TEST_ETH_PROVIDER_URI,
'--payment-provider', TEST_POLYGON_PROVIDER_URI,
'--operator-address', another_ursula,
'--network', TEMPORARY_DOMAIN,
'--payment-network', TEMPORARY_DOMAIN,
@ -270,6 +274,7 @@ def test_corrupted_configuration(click_runner,
'--network', TEMPORARY_DOMAIN,
'--payment-network', TEMPORARY_DOMAIN,
'--eth-provider', TEST_ETH_PROVIDER_URI,
'--payment-provider', TEST_POLYGON_PROVIDER_URI,
'--operator-address', another_ursula,
'--rest-host', MOCK_IP_ADDRESS,
'--registry-filepath', str(agency_local_registry.filepath.absolute()),

View File

@ -37,7 +37,7 @@ from nucypher.config.constants import (
from nucypher.crypto.powers import TransactingPower
from tests.constants import (
MOCK_IP_ADDRESS,
TEST_ETH_PROVIDER_URI, INSECURE_DEVELOPMENT_PASSWORD
TEST_ETH_PROVIDER_URI, INSECURE_DEVELOPMENT_PASSWORD, TEST_POLYGON_PROVIDER_URI
)
from tests.utils.ursula import select_test_port
@ -106,6 +106,7 @@ def test_ursula_and_local_keystore_signer_integration(click_runner,
'--operator-address', worker_account.address,
'--config-root', str(config_root_path.absolute()),
'--eth-provider', TEST_ETH_PROVIDER_URI,
'--payment-provider', TEST_POLYGON_PROVIDER_URI,
'--rest-host', MOCK_IP_ADDRESS,
'--rest-port', deploy_port,

View File

@ -37,7 +37,8 @@ from tests.constants import (
INSECURE_DEVELOPMENT_PASSWORD,
MOCK_IP_ADDRESS,
TEST_ETH_PROVIDER_URI,
YES_ENTER,
TEST_POLYGON_PROVIDER_URI,
YES_ENTER
)
from tests.utils.ursula import select_test_port, start_pytest_ursula_services
@ -182,6 +183,7 @@ def test_persistent_node_storage_integration(click_runner,
init_args = ('ursula', 'init',
'--eth-provider', TEST_ETH_PROVIDER_URI,
'--payment-provider', TEST_POLYGON_PROVIDER_URI,
'--operator-address', another_ursula,
'--network', TEMPORARY_DOMAIN,
'--payment-network', TEMPORARY_DOMAIN,

View File

@ -100,6 +100,8 @@ PYEVM_DEV_URI = "tester://pyevm"
TEST_ETH_PROVIDER_URI = PYEVM_DEV_URI # TODO: Pytest flag entry point?
TEST_POLYGON_PROVIDER_URI = "tester://polygon"
MOCK_ETH_PROVIDER_URI = 'tester://mock'
#

View File

@ -21,16 +21,23 @@ from nucypher.blockchain.eth.networks import NetworksInventory
from nucypher.cli.actions.select import select_network
__NETWORKS = NetworksInventory.NETWORKS
__POLY_NETWORKS = NetworksInventory.POLY_NETWORKS
__ETH_NETWORKS = NetworksInventory.ETH_NETWORKS
@pytest.mark.parametrize('user_input', range(0, len(__NETWORKS)-1))
def test_select_network_cli_action(test_emitter, capsys, mock_stdin, user_input):
@pytest.mark.parametrize('user_input', range(0, len(__ETH_NETWORKS)-1))
def test_select_network_cli_action_eth(test_emitter, capsys, mock_stdin, user_input):
mock_stdin.line(str(user_input))
selection = __NETWORKS[user_input]
result = select_network(emitter=test_emitter)
selection = __ETH_NETWORKS[user_input]
result = select_network(emitter=test_emitter, network_type=NetworksInventory.ETH)
assert result == selection
assert result not in __POLY_NETWORKS
captured = capsys.readouterr()
for name in __NETWORKS:
for name in __ETH_NETWORKS:
assert name in captured.out
assert mock_stdin.empty()
def test_select_network_cli_action_neither(test_emitter):
with pytest.raises(Exception):
select_network(emitter=test_emitter, network_type="FAKE COIN")