def create_character(self, emitter, config_file, debug): felix_config = self.config_options.create_config(emitter, config_file) try: # Authenticate unlock_nucypher_keyring( emitter, character_configuration=felix_config, password=get_nucypher_password(confirm=False)) # Produce Teacher Ursulas teacher_nodes = actions.load_seednodes( emitter, teacher_uris=self.teacher_uris, min_stake=self.min_stake, federated_only=felix_config.federated_only, network_domains=felix_config.domains, network_middleware=self.middleware) # Produce Felix FELIX = felix_config.produce(domains=self.config_options.domains, known_nodes=teacher_nodes) FELIX.make_web_app( ) # attach web application, but dont start service return FELIX except Exception as e: if debug: raise else: emitter.echo(str(e), color='red', bold=True) raise click.Abort
def moe(click_config, teacher_uri, min_stake, network, ws_port, dry_run, http_port, learn_on_launch): """ "Moe the Monitor" management commands. """ emitter = click_config.emitter # Banner emitter.clear() emitter.banner(MOE_BANNER) # Teacher Ursula teacher_uris = [teacher_uri] if teacher_uri else None teacher_nodes = actions.load_seednodes(emitter, teacher_uris=teacher_uris, min_stake=min_stake, federated_only=True, # TODO: hardcoded for now. Is Moe a Character? network_domains={network} if network else None, network_middleware=click_config.middleware) # Make Moe MOE = Moe(domains={network} if network else None, network_middleware=RestMiddleware(), known_nodes=teacher_nodes, federated_only=True) # Run MOE.start_learning_loop(now=learn_on_launch) emitter.message(f"Running Moe on 127.0.0.1:{http_port}") MOE.start(http_port=http_port, ws_port=ws_port, dry_run=dry_run)
def create_crawler(node_db_filepath: str = IN_MEMORY_FILEPATH, dont_set_teacher: bool = False): registry = InMemoryContractRegistry() middleware = RestMiddleware() teacher_nodes = None if not dont_set_teacher: teacher_nodes = actions.load_seednodes( None, # TODO: Needs emitter teacher_uris=[DEFAULT_TEACHER], # TODO: Needs Cleanup min_stake=0, federated_only=False, network_domains={'gemini'}, # TODO: Needs Cleanup network_middleware=middleware) crawler = Crawler( domains={'goerli'}, # TODO: Needs Cleanup network_middleware=middleware, known_nodes=teacher_nodes, registry=registry, start_learning_now=True, learn_on_same_thread=False, influx_host='localhost', # TODO: Needs Cleanup influx_port=8086, # TODO: Needs Cleanup node_storage_filepath=node_db_filepath) return crawler
def crawl(click_config, teacher_uri, registry_filepath, min_stake, network, learn_on_launch, provider_uri, influx_host, influx_port, dry_run): """ Gather NuCypher network information. """ # Banner emitter = click_config.emitter emitter.clear() emitter.banner(MONITOR_BANNER.format(CRAWLER)) registry = _get_registry(provider_uri, registry_filepath) # Teacher Ursula teacher_uris = [teacher_uri] if teacher_uri else None teacher_nodes = actions.load_seednodes( emitter, teacher_uris=teacher_uris, min_stake=min_stake, federated_only=False, network_domains={network} if network else None, network_middleware=click_config.middleware) # Configure Storage crawler = Crawler(domains={network} if network else None, network_middleware=RestMiddleware(), known_nodes=teacher_nodes, registry=registry, start_learning_now=True, learn_on_same_thread=learn_on_launch, blockchain_db_host=influx_host, blockchain_db_port=influx_port) if not dry_run: crawler.start() reactor.run()
def moe(click_config, teacher_uri, min_stake, network, ws_port, dry_run, http_port, learn_on_launch): """ "Moe" NuCypher node monitor CLI. """ if not click_config.json_ipc and not click_config.quiet: click.secho(MOE_BANNER) # Teacher Ursula teacher_uris = [teacher_uri] if teacher_uri else list() teacher_nodes = actions.load_seednodes(teacher_uris=teacher_uris, min_stake=min_stake, federated_only=True, # TODO: hardcoded for now network_middleware=click_config.middleware) # Deserialize network domain name if override passed if network: domain_constant = getattr(constants, network.upper()) domains = {domain_constant} else: domains = None monitor = Moe( domains=domains, network_middleware=RestMiddleware(), known_nodes=teacher_nodes, federated_only=True) monitor.start_learning_loop(now=learn_on_launch) monitor.start(http_port=http_port, ws_port=ws_port, dry_run=dry_run)
def crawl( general_config, teacher_uri, registry_filepath, min_stake, network, learn_on_launch, provider_uri, influx_host, influx_port, http_port, dry_run, eager, poa, ): """ Gather NuCypher network information. """ # Banner emitter = general_config.emitter emitter.clear() emitter.banner(MONITOR_BANNER.format(CRAWLER)) # Setup BlockchainInterfaceFactory.initialize_interface(provider_uri=provider_uri, poa=poa) registry = _get_registry(registry_filepath, network) # Teacher Ursula teacher_uris = [teacher_uri] if teacher_uri else None teacher_nodes = actions.load_seednodes( emitter, teacher_uris=teacher_uris, min_stake=min_stake, federated_only=False, network_domains={network} if network else None, network_middleware=RestMiddleware()) crawler = Crawler(domains={network} if network else None, network_middleware=RestMiddleware(), known_nodes=teacher_nodes, registry=registry, start_learning_now=eager, learn_on_same_thread=learn_on_launch, influx_host=influx_host, influx_port=influx_port) emitter.message(f"Network: {network.capitalize()}", color='blue') emitter.message(f"InfluxDB: {influx_host}:{influx_port}", color='blue') emitter.message(f"Provider: {provider_uri}", color='blue') emitter.message(f"Refresh Rate: {crawler._refresh_rate}s", color='blue') message = f"Running Nucypher Crawler JSON endpoint at http://localhost:{http_port}/stats" emitter.message(message, color='green', bold=True) if not dry_run: crawler.start(eager=eager) reactor.run()
def create_crawler(node_db_filepath: str = IN_MEMORY_FILEPATH, dont_set_teacher: bool = False): registry = InMemoryContractRegistry() middleware = RestMiddleware() teacher_nodes = None if not dont_set_teacher: teacher_nodes = actions.load_seednodes( None, teacher_uris=['https://discover.nucypher.network:9151'], min_stake=0, federated_only=False, network_domains={'goerli'}, network_middleware=middleware) crawler = Crawler(domains={'goerli'}, network_middleware=middleware, known_nodes=teacher_nodes, registry=registry, start_learning_now=True, learn_on_same_thread=False, blockchain_db_host='localhost', blockchain_db_port=8086, node_storage_filepath=node_db_filepath) return crawler
def felix(click_config, action, teacher_uri, enode, min_stake, network, host, dry_run, port, discovery_port, provider_uri, geth, config_root, checksum_address, poa, config_file, db_filepath, no_registry, registry_filepath, dev, force): # Intro click.clear() if not click_config.quiet: click.secho(FELIX_BANNER.format(checksum_address or '')) ETH_NODE = NO_BLOCKCHAIN_CONNECTION if geth: ETH_NODE = actions.get_provider_process(dev=dev) provider_uri = ETH_NODE.provider_uri if action == "init": """Create a brand-new Felix""" if not config_root: # Flag config_root = DEFAULT_CONFIG_ROOT # Envvar or init-only default # Acquire Keyring Password new_password = click_config.get_password(confirm=True) try: new_felix_config = FelixConfiguration.generate( password=new_password, config_root=config_root, rest_host=host, rest_port=discovery_port, db_filepath=db_filepath, domains={network} if network else None, checksum_address=checksum_address, download_registry=not no_registry, registry_filepath=registry_filepath, provider_uri=provider_uri, provider_process=ETH_NODE, poa=poa) except Exception as e: if click_config.debug: raise else: click.secho(str(e), fg='red', bold=True) raise click.Abort # Paint Help painting.paint_new_installation_help( new_configuration=new_felix_config, config_root=config_root, config_file=config_file) return # <-- do not remove (conditional flow control) # Domains -> bytes | or default domains = [network] if network else None # Load Felix from Configuration File with overrides try: felix_config = FelixConfiguration.from_configuration_file( filepath=config_file, domains=domains, registry_filepath=registry_filepath, provider_process=ETH_NODE, provider_uri=provider_uri, rest_host=host, rest_port=port, db_filepath=db_filepath, poa=poa) except FileNotFoundError: click.secho( f"No Felix configuration file found at {config_file}. " f"Check the filepath or run 'nucypher felix init' to create a new system configuration." ) raise click.Abort try: # Connect to Blockchain felix_config.connect_to_blockchain() # Authenticate password = click_config.get_password(confirm=False) click_config.unlock_keyring(character_configuration=felix_config, password=password) # Produce Teacher Ursulas teacher_nodes = actions.load_seednodes( teacher_uris=[teacher_uri] if teacher_uri else None, min_stake=min_stake, federated_only=felix_config.federated_only, network_domains=felix_config.domains, network_middleware=click_config.middleware) # Add ETH Bootnode or Peer if enode: if geth: felix_config.blockchain.interface.w3.geth.admin.addPeer(enode) click.secho(f"Added ethereum peer {enode}") else: raise NotImplemented # TODO: other backends # Produce Felix FELIX = felix_config.produce(domains=network, known_nodes=teacher_nodes) FELIX.make_web_app() # attach web application, but dont start service except Exception as e: if click_config.debug: raise else: click.secho(str(e), fg='red', bold=True) raise click.Abort if action == "createdb": # Initialize Database if os.path.isfile(FELIX.db_filepath): if not force: click.confirm("Overwrite existing database?", abort=True) os.remove(FELIX.db_filepath) click.secho(f"Destroyed existing database {FELIX.db_filepath}") FELIX.create_tables() click.secho(f"\nCreated new database at {FELIX.db_filepath}", fg='green') elif action == 'view': token_balance = FELIX.token_balance eth_balance = FELIX.eth_balance click.secho(f""" Address .... {FELIX.checksum_address} NU ......... {str(token_balance)} ETH ........ {str(eth_balance)} """) elif action == "accounts": accounts = FELIX.blockchain.interface.w3.eth.accounts for account in accounts: click.secho(account) elif action == "destroy": """Delete all configuration files from the disk""" actions.destroy_configuration(character_config=felix_config, force=force) elif action == 'run': # Start web services try: click.secho("Waiting for blockchain sync...", fg='yellow') FELIX.blockchain.sync() FELIX.start(host=host, port=port, web_services=not dry_run, distribution=True, crash_on_error=click_config.debug) finally: FELIX.blockchain.disconnect() else: raise click.BadArgumentUsage("No such argument {}".format(action))
def bob(click_config, action, quiet, teacher_uri, min_stake, http_port, discovery_port, federated_only, network, config_root, config_file, provider_uri, registry_filepath, dev, force, dry_run, label, policy_encrypting_key, alice_verifying_key, message_kit): """ Start and manage a "Bob" character. """ if not click_config.json_ipc and not click_config.quiet: click.secho(BOB_BANNER) if action == 'init': """Create a brand-new persistent Bob""" if dev: actions.handle_control_output( message="WARNING: Using temporary storage area", quiet=quiet, color='yellow', json=click_config.json) if not config_root: # Flag config_root = click_config.config_file # Envvar new_bob_config = BobConfiguration.generate( password=click_config._get_password(confirm=True), config_root=config_root or click_config, rest_host="localhost", domains={network} if network else None, federated_only=federated_only, no_registry=click_config.no_registry, registry_filepath=registry_filepath, provider_uri=provider_uri) return painting.paint_new_installation_help( new_configuration=new_bob_config, config_file=config_file) elif action == "destroy": """Delete all configuration files from the disk""" if dev: message = "'nucypher ursula destroy' cannot be used in --dev mode" raise click.BadOptionUsage(option_name='--dev', message=message) destroyed_path = actions.destroy_system_configuration( config_class=BobConfiguration, config_file=config_file, network=network, config_root=config_root, force=force) return click_config.emitter(message=f"Destroyed {destroyed_path}") # # Get Bob Configuration # if dev: bob_config = BobConfiguration( dev_mode=True, domains={network}, provider_uri=provider_uri, federated_only=True, network_middleware=click_config.middleware) else: bob_config = BobConfiguration.from_configuration_file( filepath=config_file, domains={network or GLOBAL_DOMAIN}, rest_port=discovery_port, provider_uri=provider_uri, network_middleware=click_config.middleware) # Teacher Ursula teacher_uris = [teacher_uri] if teacher_uri else list() teacher_nodes = actions.load_seednodes( teacher_uris=teacher_uris, min_stake=min_stake, federated_only=federated_only, network_middleware=click_config.middleware) if not dev: click_config.unlock_keyring(character_configuration=bob_config) # Produce BOB = bob_config(known_nodes=teacher_nodes, network_middleware=click_config.middleware) # Switch to character control emitter if click_config.json_ipc: BOB.controller.emitter = IPCStdoutEmitter(quiet=click_config.quiet) if action == "run": click_config.emitter( message=f"Bob Verifying Key {bytes(BOB.stamp).hex()}", color='green', bold=True) bob_encrypting_key = bytes(BOB.public_keys(DecryptingPower)).hex() click_config.emitter( message=f"Bob Encrypting Key {bob_encrypting_key}", color="blue", bold=True) controller = BOB.make_web_controller() BOB.log.info('Starting HTTP Character Web Controller') return controller.start(http_port=http_port, dry_run=dry_run) elif action == "view": """Paint an existing configuration to the console""" response = BobConfiguration._read_configuration_file( filepath=config_file or bob_config.config_file_location) return BOB.controller.emitter(response=response) elif action == "public-keys": response = BOB.controller.public_keys() return response elif action == "retrieve": if not all( (label, policy_encrypting_key, alice_verifying_key, message_kit)): input_specification, output_specification = BOB.control.get_specifications( interface_name='retrieve') required_fields = ', '.join(input_specification) raise click.BadArgumentUsage( f'{required_fields} are required flags to retrieve') bob_request_data = { 'label': label, 'policy_encrypting_key': policy_encrypting_key, 'alice_verifying_key': alice_verifying_key, 'message_kit': message_kit, } response = BOB.controller.retrieve(request=bob_request_data) return response else: raise click.BadArgumentUsage(f"No such argument {action}")
def ursula(click_config, action, dev, quiet, dry_run, force, lonely, network, teacher_uri, min_stake, rest_host, rest_port, db_filepath, checksum_address, withdraw_address, federated_only, poa, config_root, config_file, provider_uri, recompile_solidity, no_registry, registry_filepath, value, duration, index, list_, divide ) -> None: """ Manage and run an "Ursula" PRE node. \b Actions ------------------------------------------------- \b init Create a new Ursula node configuration. view View the Ursula node's configuration. run Run an "Ursula" node. save-metadata Manually write node metadata to disk without running forget Forget all known nodes. destroy Delete Ursula node configuration. stake Manage stakes for this node. confirm-activity Manually confirm-activity for the current period. collect-reward Withdraw staking reward. """ # # Boring Setup Stuff # if not quiet: log = Logger('ursula.cli') if click_config.debug and quiet: raise click.BadOptionUsage(option_name="quiet", message="--debug and --quiet cannot be used at the same time.") if not click_config.json_ipc and not click_config.quiet: click.secho(URSULA_BANNER.format(checksum_address or '')) # # Pre-Launch Warnings # if not click_config.quiet: if dev: click.secho("WARNING: Running in Development mode", fg='yellow') if force: click.secho("WARNING: Force is enabled", fg='yellow') # # Unauthenticated Configurations & Un-configured Ursula Control # if action == "init": """Create a brand-new persistent Ursula""" if not network: raise click.BadArgumentUsage('--network is required to initialize a new configuration.') if dev: click_config.emitter(message="WARNING: Using temporary storage area", color='yellow') if not config_root: # Flag config_root = click_config.config_file # Envvar if not rest_host: rest_host = click.prompt("Enter Ursula's public-facing IPv4 address") # TODO: Remove this step ursula_config = UrsulaConfiguration.generate(password=click_config._get_password(confirm=True), config_root=config_root, rest_host=rest_host, rest_port=rest_port, db_filepath=db_filepath, domains={network} if network else None, federated_only=federated_only, checksum_public_address=checksum_address, no_registry=federated_only or no_registry, registry_filepath=registry_filepath, provider_uri=provider_uri, poa=poa) painting.paint_new_installation_help(new_configuration=ursula_config, config_root=config_root, config_file=config_file, federated_only=federated_only) return # # Configured Ursulas # # Development Configuration if dev: ursula_config = UrsulaConfiguration(dev_mode=True, domains={TEMPORARY_DOMAIN}, poa=poa, registry_filepath=registry_filepath, provider_uri=provider_uri, checksum_public_address=checksum_address, federated_only=federated_only, rest_host=rest_host, rest_port=rest_port, db_filepath=db_filepath) # Authenticated Configurations else: # Domains -> bytes | or default domains = [bytes(network, encoding='utf-8')] if network else None # Load Ursula from Configuration File ursula_config = UrsulaConfiguration.from_configuration_file(filepath=config_file, domains=domains, registry_filepath=registry_filepath, provider_uri=provider_uri, rest_host=rest_host, rest_port=rest_port, db_filepath=db_filepath, poa=poa) click_config.unlock_keyring(character_configuration=ursula_config) # # Connect to Blockchain (Non-Federated) # if not ursula_config.federated_only: click_config.connect_to_blockchain(character_configuration=ursula_config, recompile_contracts=recompile_solidity) click_config.ursula_config = ursula_config # Pass Ursula's config onto staking sub-command # # Launch Warnings # if ursula_config.federated_only: click_config.emitter(message="WARNING: Running in Federated mode", color='yellow') # Seed - Step 1 teacher_uris = [teacher_uri] if teacher_uri else list() teacher_nodes = actions.load_seednodes(teacher_uris=teacher_uris, min_stake=min_stake, federated_only=federated_only, network_middleware=click_config.middleware) # Produce - Step 2 URSULA = ursula_config(known_nodes=teacher_nodes, lonely=lonely) # # Action Switch # if action == 'run': """Seed, Produce, Run!""" # GO! try: click_config.emitter( message="Starting Ursula on {}".format(URSULA.rest_interface), color='green', bold=True) # Ursula Deploy Warnings click_config.emitter( message="Connecting to {}".format(','.join(str(d, encoding='utf-8') for d in ursula_config.domains)), color='green', bold=True) if not URSULA.federated_only and URSULA.stakes: click_config.emitter( message=f"Staking {str(URSULA.total_staked)} ~ Keep Ursula Online!", color='blue', bold=True) if not click_config.debug: stdio.StandardIO(UrsulaCommandProtocol(ursula=URSULA)) if dry_run: return # <-- ABORT -X (Last Chance) # Run - Step 3 node_deployer = URSULA.get_deployer() node_deployer.addServices() node_deployer.catalogServers(node_deployer.hendrix) node_deployer.run() # <--- Blocking Call (Reactor) # Handle Crash except Exception as e: ursula_config.log.critical(str(e)) click_config.emitter( message="{} {}".format(e.__class__.__name__, str(e)), color='red', bold=True) raise # Crash :-( # Graceful Exit / Crash finally: click_config.emitter(message="Stopping Ursula", color='green') ursula_config.cleanup() click_config.emitter(message="Ursula Stopped", color='red') return elif action == "save-metadata": """Manually save a node self-metadata file""" metadata_path = ursula.write_node_metadata(node=URSULA) return click_config.emitter(message="Successfully saved node metadata to {}.".format(metadata_path), color='green') elif action == "view": """Paint an existing configuration to the console""" response = UrsulaConfiguration._read_configuration_file(filepath=config_file or ursula_config.config_file_location) return click_config.emitter(response=response) elif action == "forget": actions.forget(configuration=ursula_config) return elif action == "destroy": """Delete all configuration files from the disk""" if dev: message = "'nucypher ursula destroy' cannot be used in --dev mode" raise click.BadOptionUsage(option_name='--dev', message=message) destroyed_filepath = destroy_system_configuration(config_class=UrsulaConfiguration, config_file=config_file, network=network, config_root=ursula_config.config_file_location, force=force) return click_config.emitter(message=f"Destroyed {destroyed_filepath}", color='green') elif action == 'stake': # List Only if list_: if not URSULA.stakes: click.echo(f"There are no existing stakes for {URSULA.checksum_public_address}") painting.paint_stakes(stakes=URSULA.stakes) return # Divide Only if divide: """Divide an existing stake by specifying the new target value and end period""" # Validate if len(URSULA.stakes) == 0: click.secho("There are no active stakes for {}".format(URSULA.checksum_public_address)) return # Selection if index is None: painting.paint_stakes(stakes=URSULA.stakes) index = click.prompt("Select a stake to divide", type=click.IntRange(min=0, max=len(URSULA.stakes)-1)) # Lookup the stake current_stake = URSULA.stakes[index] # Value if not value: value = click.prompt(f"Enter target value (must be less than {str(current_stake.value)})", type=STAKE_VALUE) value = NU(value, 'NU') # Duration if not duration: extension = click.prompt("Enter number of periods to extend", type=STAKE_EXTENSION) else: extension = duration if not force: painting.paint_staged_stake_division(ursula=URSULA, original_index=index, original_stake=current_stake, target_value=value, extension=extension) click.confirm("Is this correct?", abort=True) txhash_bytes = URSULA.divide_stake(stake_index=index, target_value=value, additional_periods=extension) if not quiet: click.secho('Successfully divided stake', fg='green') click.secho(f'Transaction Hash ........... {txhash_bytes.hex()}') # Show the resulting stake list painting.paint_stakes(stakes=URSULA.stakes) return # Confirm new stake init if not force: click.confirm("Stage a new stake?", abort=True) # Validate balance balance = URSULA.token_balance if balance == 0: click.secho(f"{ursula.checksum_public_address} has 0 NU.") raise click.Abort if not quiet: click.echo(f"Current balance: {balance}") # Gather stake value if not value: value = click.prompt(f"Enter stake value", type=STAKE_VALUE, default=NU(MIN_ALLOWED_LOCKED, 'NuNit')) else: value = NU(int(value), 'NU') # Duration if not quiet: message = "Minimum duration: {} | Maximum Duration: {}".format(MIN_LOCKED_PERIODS, MAX_MINTING_PERIODS) click.echo(message) if not duration: duration = click.prompt("Enter stake duration in periods (1 Period = 24 Hours)", type=STAKE_DURATION) start_period = URSULA.miner_agent.get_current_period() end_period = start_period + duration # Review if not force: painting.paint_staged_stake(ursula=URSULA, stake_value=value, duration=duration, start_period=start_period, end_period=end_period) if not dev: actions.confirm_staged_stake(ursula=URSULA, value=value, duration=duration) # Last chance to bail if not force: click.confirm("Publish staged stake to the blockchain?", abort=True) staking_transactions = URSULA.initialize_stake(amount=int(value), lock_periods=duration) painting.paint_staking_confirmation(ursula=URSULA, transactions=staking_transactions) return elif action == 'confirm-activity': if not URSULA.stakes: click.secho("There are no active stakes for {}".format(URSULA.checksum_public_address)) return URSULA.miner_agent.confirm_activity(node_address=URSULA.checksum_public_address) return elif action == 'collect-reward': """Withdraw staking reward to the specified wallet address""" if not force: click.confirm(f"Send {URSULA.calculate_reward()} to {URSULA.checksum_public_address}?") URSULA.collect_policy_reward(collector_address=withdraw_address or checksum_address) URSULA.collect_staking_reward() else: raise click.BadArgumentUsage("No such argument {}".format(action))
def alice(click_config, action, teacher_uri, min_stake, http_port, discovery_port, federated_only, network, config_root, config_file, provider_uri, no_registry, registry_filepath, dev, force, dry_run, bob_encrypting_key, bob_verifying_key, policy_encrypting_key, label, m, n): """ Start and manage an "Alice" character. """ if not click_config.json_ipc and not click_config.quiet: click.secho(ALICE_BANNER) if action == 'init': """Create a brand-new persistent Alice""" if not network: raise click.BadArgumentUsage( '--network is required to initialize a new configuration.') if dev: click_config.emitter( message="WARNING: Using temporary storage area", color='yellow') if not config_root: # Flag config_root = click_config.config_file # Envvar new_alice_config = AliceConfiguration.generate( password=click_config._get_password(confirm=True), config_root=config_root, rest_host="localhost", domains={network} if network else None, federated_only=federated_only, no_registry=no_registry, registry_filepath=registry_filepath, provider_uri=provider_uri) return painting.paint_new_installation_help( new_configuration=new_alice_config, config_root=config_root, config_file=config_file) elif action == "destroy": """Delete all configuration files from the disk""" if dev: message = "'nucypher ursula destroy' cannot be used in --dev mode" raise click.BadOptionUsage(option_name='--dev', message=message) destroyed_path = actions.destroy_system_configuration( config_class=AliceConfiguration, config_file=config_file, network=network, config_root=config_root, force=force) return nucypher_click_config.emitter( message=f"Destroyed {destroyed_path}", color='red') # # Get Alice Configuration # if dev: alice_config = AliceConfiguration( dev_mode=True, network_middleware=click_config.middleware, domains={network}, provider_uri=provider_uri, federated_only=True) else: alice_config = AliceConfiguration.from_configuration_file( filepath=config_file, domains={network or GLOBAL_DOMAIN}, network_middleware=click_config.middleware, rest_port=discovery_port, provider_uri=provider_uri) if not dev: click_config.unlock_keyring(character_configuration=alice_config) # Teacher Ursula teacher_uris = [teacher_uri] if teacher_uri else list() teacher_nodes = actions.load_seednodes( teacher_uris=teacher_uris, min_stake=min_stake, federated_only=federated_only, network_middleware=click_config.middleware) # Produce ALICE = alice_config(known_nodes=teacher_nodes, network_middleware=click_config.middleware) # Switch to character control emitter if click_config.json_ipc: ALICE.controller.emitter = IPCStdoutEmitter(quiet=click_config.quiet) if action == "run": """Start Alice Web Controller""" ALICE.controller.emitter( message=f"Alice Verifying Key {bytes(ALICE.stamp).hex()}", color="green", bold=True) controller = ALICE.make_web_controller( crash_on_error=click_config.debug) ALICE.log.info('Starting HTTP Character Web Controller') return controller.start(http_port=http_port, dry_run=dry_run) elif action == "view": """Paint an existing configuration to the console""" configuration_file_location = config_file or alice_config.config_file_location response = AliceConfiguration._read_configuration_file( filepath=configuration_file_location) return ALICE.controller.emitter( response=response) # TODO: Uses character control instead elif action == "public-keys": response = ALICE.controller.public_keys() return response elif action == "create-policy": if not all((bob_verifying_key, bob_encrypting_key, label)): raise click.BadArgumentUsage( message= "--bob-verifying-key, --bob-encrypting-key, and --label are " "required options to create a new policy.") create_policy_request = { 'bob_encrypting_key': bob_encrypting_key, 'bob_verifying_key': bob_verifying_key, 'label': label, 'm': m, 'n': n, } return ALICE.controller.create_policy(request=create_policy_request) elif action == "derive-policy-pubkey": return ALICE.controller.derive_policy_encrypting_key(label=label) elif action == "grant": grant_request = { 'bob_encrypting_key': bob_encrypting_key, 'bob_verifying_key': bob_verifying_key, 'label': label, 'm': m, 'n': n, 'expiration': (maya.now() + datetime.timedelta(days=3)).iso8601(), # TODO } return ALICE.controller.grant(request=grant_request) elif action == "revoke": return ALICE.controller.revoke( policy_encrypting_key=policy_encrypting_key) else: raise click.BadArgumentUsage(f"No such argument {action}")
def felix(click_config, action, teacher_uri, enode, min_stake, network, host, dry_run, port, discovery_port, provider_uri, geth, config_root, checksum_address, poa, config_file, db_filepath, registry_filepath, dev, force): """ "Felix the Faucet" management commands. """ emitter = click_config.emitter # Intro emitter.clear() emitter.banner(FELIX_BANNER.format(checksum_address or '')) ETH_NODE = NO_BLOCKCHAIN_CONNECTION if geth: ETH_NODE = actions.get_provider_process(dev=dev) provider_uri = ETH_NODE.provider_uri if action == "init": """Create a brand-new Felix""" if not config_root: # Flag config_root = DEFAULT_CONFIG_ROOT # Envvar or init-only default try: new_felix_config = FelixConfiguration.generate( password=get_nucypher_password(confirm=True), config_root=config_root, rest_host=host, rest_port=discovery_port, db_filepath=db_filepath, domains={network} if network else None, checksum_address=checksum_address, registry_filepath=registry_filepath, provider_uri=provider_uri, provider_process=ETH_NODE, poa=poa) except Exception as e: if click_config.debug: raise else: emitter.echo(str(e), color='red', bold=True) raise click.Abort # Paint Help painting.paint_new_installation_help( emitter, new_configuration=new_felix_config) return # <-- do not remove (conditional flow control) # Domains -> bytes | or default domains = [network] if network else None # Load Felix from Configuration File with overrides try: felix_config = FelixConfiguration.from_configuration_file( filepath=config_file, domains=domains, registry_filepath=registry_filepath, provider_process=ETH_NODE, provider_uri=provider_uri, rest_host=host, rest_port=port, db_filepath=db_filepath, poa=poa) except FileNotFoundError: emitter.echo( f"No Felix configuration file found at {config_file}. " f"Check the filepath or run 'nucypher felix init' to create a new system configuration." ) raise click.Abort if action == "destroy": """Delete all configuration files from the disk""" if dev: message = "'nucypher felix destroy' cannot be used in --dev mode" raise click.BadOptionUsage(option_name='--dev', message=message) actions.destroy_configuration(emitter, character_config=felix_config, force=force) return try: # Authenticate unlock_nucypher_keyring(emitter, character_configuration=felix_config, password=get_nucypher_password(confirm=False)) # Produce Teacher Ursulas teacher_nodes = actions.load_seednodes( emitter, teacher_uris=[teacher_uri] if teacher_uri else None, min_stake=min_stake, federated_only=felix_config.federated_only, network_domains=felix_config.domains, network_middleware=click_config.middleware) # Produce Felix FELIX = felix_config.produce(domains=network, known_nodes=teacher_nodes) FELIX.make_web_app() # attach web application, but dont start service except Exception as e: if click_config.debug: raise else: emitter.echo(str(e), color='red', bold=True) raise click.Abort if action == "createdb": # Initialize Database if os.path.isfile(FELIX.db_filepath): if not force: click.confirm("Overwrite existing database?", abort=True) os.remove(FELIX.db_filepath) emitter.echo(f"Destroyed existing database {FELIX.db_filepath}") FELIX.create_tables() emitter.echo(f"\nCreated new database at {FELIX.db_filepath}", color='green') elif action == 'view': token_balance = FELIX.token_balance eth_balance = FELIX.eth_balance emitter.echo(f""" Address .... {FELIX.checksum_address} NU ......... {str(token_balance)} ETH ........ {str(eth_balance)} """) elif action == "accounts": accounts = FELIX.blockchain.client.accounts for account in accounts: emitter.echo(account) elif action == 'run': # Start web services emitter.echo("Waiting for blockchain sync...", color='yellow') emitter.message(f"Running Felix on {host}:{port}") FELIX.start(host=host, port=port, web_services=not dry_run, distribution=True, crash_on_error=click_config.debug) else: raise click.BadArgumentUsage("No such argument {}".format(action))
def felix(click_config, action, teacher_uri, min_stake, network, host, dry_run, port, discovery_port, provider_uri, config_root, checksum_address, poa, config_file, db_filepath, no_registry, registry_filepath, force): if not click_config.quiet: click.secho(FELIX_BANNER.format(checksum_address or '')) if action == "init": """Create a brand-new Felix""" # Validate "Init" Input if not network: raise click.BadArgumentUsage( '--network is required to initialize a new configuration.') # Validate "Init" Input if not checksum_address: raise click.BadArgumentUsage( '--checksum-address is required to initialize a new Felix configuration.' ) # Acquire Keyring Password if not config_root: # Flag config_root = click_config.config_file # Envvar new_password = click_config.get_password(confirm=True) new_felix_config = FelixConfiguration.generate( password=new_password, config_root=config_root, rest_host=host, rest_port=discovery_port, db_filepath=db_filepath, domains={network} if network else None, checksum_public_address=checksum_address, no_registry=no_registry, registry_filepath=registry_filepath, provider_uri=provider_uri, poa=poa) # Paint Help painting.paint_new_installation_help( new_configuration=new_felix_config, config_root=config_root, config_file=config_file) return # <-- do not remove (conditional flow control) # # Authenticated Configurations # # Domains -> bytes | or default domains = [bytes(network, encoding='utf-8')] if network else None # Load Felix from Configuration File with overrides try: felix_config = FelixConfiguration.from_configuration_file( filepath=config_file, domains=domains, registry_filepath=registry_filepath, provider_uri=provider_uri, rest_host=host, rest_port=port, db_filepath=db_filepath, poa=poa) except FileNotFoundError: click.secho( f"No Felix configuration file found at {config_file}. " f"Check the filepath or run 'nucypher felix init' to create a new system configuration." ) raise click.Abort else: # Produce Teacher Ursulas teacher_uris = [teacher_uri] if teacher_uri else list() teacher_nodes = actions.load_seednodes( teacher_uris=teacher_uris, min_stake=min_stake, federated_only=False, network_middleware=click_config.middleware) # Produce Felix click_config.unlock_keyring(character_configuration=felix_config) FELIX = felix_config.produce(domains=network, known_nodes=teacher_nodes) FELIX.make_web_app() # attach web application, but dont start service if action == "createdb": # Initialize Database if os.path.isfile(FELIX.db_filepath): if not force: click.confirm("Overwrite existing database?", abort=True) os.remove(FELIX.db_filepath) click.secho(f"Destroyed existing database {FELIX.db_filepath}") FELIX.create_tables() click.secho(f"Created new database at {FELIX.db_filepath}") elif action == 'view': token_balance = FELIX.token_balance eth_balance = FELIX.eth_balance click.secho(f""" Address .... {FELIX.checksum_public_address} NU ......... {str(token_balance)} ETH ........ {str(eth_balance)} """) return elif action == "accounts": accounts = FELIX.blockchain.interface.w3.eth.accounts for account in accounts: click.secho(account) return elif action == 'run': # Start web services FELIX.start(host=host, port=port, web_services=not dry_run, distribution=True, crash_on_error=click_config.debug) else: # Error raise click.BadArgumentUsage("No such argument {}".format(action))
def ursula( click_config, action, dev, quiet, dry_run, force, lonely, network, teacher_uri, min_stake, rest_host, rest_port, db_filepath, checksum_address, federated_only, poa, config_root, config_file, metadata_dir, # TODO: Start nodes from an additional existing metadata dir provider_uri, recompile_solidity, no_registry, registry_filepath) -> None: """ Manage and run an "Ursula" PRE node. \b Actions ------------------------------------------------- \b run Run an "Ursula" node. init Create a new Ursula node configuration. view View the Ursula node's configuration. forget Forget all known nodes. save-metadata Manually write node metadata to disk without running destroy Delete Ursula node configuration. """ # # Boring Setup Stuff # if not quiet: log = Logger('ursula.cli') if click_config.debug and quiet: raise click.BadOptionUsage( option_name="quiet", message="--debug and --quiet cannot be used at the same time.") if click_config.debug: click_config.log_to_sentry = False click_config.log_to_file = True globalLogPublisher.removeObserver(logToSentry) # Sentry GlobalConsoleLogger.set_log_level("debug") elif quiet: globalLogPublisher.removeObserver(logToSentry) globalLogPublisher.removeObserver(SimpleObserver) globalLogPublisher.removeObserver(getJsonFileObserver()) if not click_config.json_ipc and not click_config.quiet: click.secho(URSULA_BANNER) # # Pre-Launch Warnings # if not quiet: if dev: click.secho("WARNING: Running in development mode", fg='yellow') if force: click.secho("WARNING: Force is enabled", fg='yellow') # # Unauthenticated Configurations # if action == "init": """Create a brand-new persistent Ursula""" if not network: raise click.BadArgumentUsage( '--network is required to initialize a new configuration.') if dev: actions.handle_control_output( message="WARNING: Using temporary storage area", color='yellow', quiet=quiet, json=click_config.json) if not config_root: # Flag config_root = click_config.config_file # Envvar if not rest_host: rest_host = click.prompt( "Enter Ursula's public-facing IPv4 address" ) # TODO: Remove this step ursula_config = UrsulaConfiguration.generate( password=click_config.get_password(confirm=True), config_root=config_root, rest_host=rest_host, rest_port=rest_port, db_filepath=db_filepath, domains={network} if network else None, federated_only=federated_only, checksum_public_address=checksum_address, no_registry=federated_only or no_registry, registry_filepath=registry_filepath, provider_uri=provider_uri, poa=poa) click_config.emitter(message="Generated keyring {}".format( ursula_config.keyring_dir), color='green') click_config.emitter(message="Saved configuration file {}".format( ursula_config.config_file_location), color='green') # Give the use a suggestion as to what to do next... how_to_run_message = "\nTo run an Ursula node from the default configuration filepath run: \n\n'{}'\n" suggested_command = 'nucypher ursula run' if config_root is not None: config_file_location = os.path.join( config_root, config_file or UrsulaConfiguration.CONFIG_FILENAME) suggested_command += ' --config-file {}'.format( config_file_location) return click_config.emitter( message=how_to_run_message.format(suggested_command), color='green') # Development Configuration if dev: ursula_config = UrsulaConfiguration( dev_mode=True, domains={TEMPORARY_DOMAIN}, poa=poa, registry_filepath=registry_filepath, provider_uri=provider_uri, checksum_public_address=checksum_address, federated_only=federated_only, rest_host=rest_host, rest_port=rest_port, db_filepath=db_filepath) # Authenticated Configurations else: # Deserialize network domain name if override passed if network: domain_constant = getattr(constants, network.upper()) domains = {domain_constant} else: domains = None ursula_config = UrsulaConfiguration.from_configuration_file( filepath=config_file, domains=domains, registry_filepath=registry_filepath, provider_uri=provider_uri, rest_host=rest_host, rest_port=rest_port, db_filepath=db_filepath, # TODO: Handle Boolean overrides # poa=poa, # federated_only=federated_only, ) actions.unlock_keyring(configuration=ursula_config, password=click_config.get_password()) if not ursula_config.federated_only: actions.connect_to_blockchain(configuration=ursula_config, recompile_contracts=recompile_solidity) click_config.ursula_config = ursula_config # Pass Ursula's config onto staking sub-command # # Launch Warnings # if ursula_config.federated_only: click_config.emitter(message="WARNING: Running in Federated mode", color='yellow') # # Action Switch # if action == 'run': """Seed, Produce, Run!""" # # Seed - Step 1 # teacher_uris = [teacher_uri] if teacher_uri else list() teacher_nodes = actions.load_seednodes( teacher_uris=teacher_uris, min_stake=min_stake, federated_only=federated_only, network_middleware=click_config.middleware) # # Produce - Step 2 # URSULA = ursula_config(known_nodes=teacher_nodes, lonely=lonely) # GO! try: # # Run - Step 3 # click_config.emitter(message="Connecting to {}".format(','.join( str(d) for d in ursula_config.domains)), color='green', bold=True) click_config.emitter(message="Running Ursula {} on {}".format( URSULA, URSULA.rest_interface), color='green', bold=True) if not click_config.debug: stdio.StandardIO(UrsulaCommandProtocol(ursula=URSULA)) if dry_run: # That's all folks! return URSULA.get_deployer().run() # <--- Blocking Call (Reactor) except Exception as e: ursula_config.log.critical(str(e)) click_config.emitter(message="{} {}".format( e.__class__.__name__, str(e)), color='red', bold=True) raise # Crash :-( finally: click_config.emitter(message="Stopping Ursula", color='green') ursula_config.cleanup() click_config.emitter(message="Ursula Stopped", color='red') return elif action == "save-metadata": """Manually save a node self-metadata file""" URSULA = ursula_config.produce(ursula_config=ursula_config) metadata_path = ursula.write_node_metadata(node=URSULA) return click_config.emitter( message="Successfully saved node metadata to {}.".format( metadata_path), color='green') elif action == "view": """Paint an existing configuration to the console""" response = UrsulaConfiguration._read_configuration_file( filepath=config_file or ursula_config.config_file_location) return click_config.emitter(response=response) elif action == "forget": # TODO: Move to character control actions.forget(configuration=ursula_config) return elif action == "destroy": """Delete all configuration files from the disk""" if dev: message = "'nucypher ursula destroy' cannot be used in --dev mode" raise click.BadOptionUsage(option_name='--dev', message=message) destroyed_filepath = destroy_system_configuration( config_class=UrsulaConfiguration, config_file=config_file, network=network, config_root=ursula_config.config_file_location, force=force) return click_config.emitter(message=f"Destroyed {destroyed_filepath}", color='green') else: raise click.BadArgumentUsage("No such argument {}".format(action))