Exemplo n.º 1
0
def spawn_random_staking_ursulas(miner_agent, addresses: list) -> list:
    """
    Deposit and lock a random amount of tokens in the miner escrow
    from each address, "spawning" new Miners.
    """
    from nucypher.blockchain.eth.actors import Miner

    miners = list()
    for address in addresses:
        miner = Miner(miner_agent=miner_agent, checksum_address=address)
        miners.append(miner)

        # stake a random amount
        min_stake, balance = constants.MIN_ALLOWED_LOCKED, miner.token_balance
        amount = random.randint(min_stake, balance)

        # for a random lock duration
        min_locktime, max_locktime = constants.MIN_LOCKED_PERIODS, constants.MAX_MINTING_PERIODS
        periods = random.randint(min_locktime, max_locktime)

        miner.initialize_stake(amount=amount, lock_periods=periods)

    return miners
Exemplo n.º 2
0
def simulate(config, action, nodes, federated_only):
    """
    Simulate the nucypher blockchain network

    Arguments
    ==========

    action - Which action to perform; The choices are:
           - start: Start a multi-process nucypher network simulation
           - stop: Stop a running simulation gracefully

    Options
    ========

    --nodes - The quantity of nodes (processes) to execute during the simulation
    --duration = The number of periods to run the simulation before termination

    """

    if action == 'init':

        # OK, Try connecting to the blockchain
        click.echo("Connecting to provider endpoint")
        config.connect_to_blockchain()

        # Actual simulation setup logic
        one_million_eth = 10**6 * 10**18
        click.echo("Airdropping {} ETH to {} test accounts".format(
            one_million_eth, len(config.accounts)))
        config.blockchain.ether_airdrop(
            amount=one_million_eth)  # wei -> ether | 1 Million ETH

        # Fin
        click.echo("Blockchain initialized")

    if action == 'deploy':

        if config.simulation_running is True:
            raise RuntimeError("Network simulation already running")

        if not federated_only:
            config.connect_to_blockchain()

            click.confirm("Deploy all nucypher contracts to blockchain?",
                          abort=True)
            click.echo("Bootstrapping simulated blockchain network")

            blockchain = TesterBlockchain.from_config()

            # TODO: Enforce Saftey - ensure this is "fake" #
            conditions = ()
            assert True

            # Parse addresses
            etherbase, *everybody_else = blockchain.interface.w3.eth.accounts

            # Deploy contracts
            token_deployer = NucypherTokenDeployer(blockchain=blockchain,
                                                   deployer_address=etherbase)
            token_deployer.arm()
            token_deployer.deploy()
            token_agent = token_deployer.make_agent()
            click.echo("Deployed {}:{}".format(token_agent.contract_name,
                                               token_agent.contract_address))

            miner_escrow_deployer = MinerEscrowDeployer(
                token_agent=token_agent, deployer_address=etherbase)
            miner_escrow_deployer.arm()
            miner_escrow_deployer.deploy()
            miner_agent = miner_escrow_deployer.make_agent()
            click.echo("Deployed {}:{}".format(miner_agent.contract_name,
                                               miner_agent.contract_address))

            policy_manager_deployer = PolicyManagerDeployer(
                miner_agent=miner_agent, deployer_address=etherbase)
            policy_manager_deployer.arm()
            policy_manager_deployer.deploy()
            policy_agent = policy_manager_deployer.make_agent()
            click.echo("Deployed {}:{}".format(policy_agent.contract_name,
                                               policy_agent.contract_address))

            airdrop_amount = 1000000 * int(constants.M)
            click.echo("Airdropping tokens {} to {} addresses".format(
                airdrop_amount, len(everybody_else)))
            _receipts = token_airdrop(token_agent=token_agent,
                                      origin=etherbase,
                                      addresses=everybody_else,
                                      amount=airdrop_amount)

            click.echo("Connecting to deployed contracts")
            config.connect_to_contracts()

            # Commit the current state of deployment to a registry file.
            click.echo("Writing filesystem registry")
            _sim_registry_name = config.blockchain.interface._registry.commit(
                filepath=DEFAULT_SIMULATION_REGISTRY_FILEPATH)

            # Fin
            click.echo("Ready to simulate decentralized swarm.")

        else:
            click.echo("Ready to run federated swarm.")

    elif action == 'swarm':

        if not federated_only:
            config.connect_to_blockchain()
            config.connect_to_contracts(simulation=True)

        localhost = 'localhost'

        # Select a port range to use on localhost for sim servers
        start_port, stop_port = DEFAULT_SIMULATION_PORT, DEFAULT_SIMULATION_PORT + int(
            nodes)
        port_range = range(start_port, stop_port)
        click.echo("Selected local ports {}-{}".format(start_port, stop_port))

        for index, sim_port_number in enumerate(port_range):

            #
            # Parse ursula parameters
            #

            rest_port, dht_port = sim_port_number, sim_port_number + 100
            db_name = 'sim-{}'.format(rest_port)

            proc_params = '''
            run_ursula --host {} --rest-port {} --dht-port {} --db-name {}
            '''.format(localhost, rest_port, dht_port, db_name).split()

            if federated_only:
                click.echo("Setting federated operating mode")
                proc_params.append('--federated-only')
            else:
                sim_address = config.accounts[index + 1]
                miner = Miner(miner_agent=config.miner_agent,
                              checksum_address=sim_address)

                # stake a random amount
                min_stake, balance = constants.MIN_ALLOWED_LOCKED, miner.token_balance
                value = random.randint(min_stake, balance)

                # for a random lock duration
                min_locktime, max_locktime = constants.MIN_LOCKED_PERIODS, constants.MAX_MINTING_PERIODS
                periods = random.randint(min_locktime, max_locktime)

                miner.initialize_stake(amount=value, lock_periods=periods)
                click.echo(
                    "{} Initialized new stake: {} tokens for {} periods".
                    format(sim_address, value, periods))

                proc_params.extend(
                    '--checksum-address {}'.format(sim_address).split())

            # Spawn
            click.echo("Spawning node #{}".format(index + 1))
            processProtocol = UrsulaProcessProtocol(command=proc_params)
            ursula_proc = reactor.spawnProcess(processProtocol, "nucypher-cli",
                                               proc_params)
            config.sim_processes.append(ursula_proc)

            #
            # post-spawnProcess
            #

            # Start with some basic status data, then build on it

            rest_uri = "http://{}:{}".format(localhost, rest_port)
            dht_uri = "http://{}:{}".format(localhost, dht_port)

            sim_data = "Started simulated Ursula | ReST {} | DHT {} ".format(
                rest_uri, dht_uri)
            rest_uri = "{host}:{port}".format(host=localhost,
                                              port=str(sim_port_number))
            dht_uri = '{host}:{port}'.format(host=localhost, port=dht_port)
            sim_data.format(rest_uri, dht_uri)

            if not federated_only:
                stake_infos = tuple(
                    config.miner_agent.get_all_stakes(
                        miner_address=sim_address))
                sim_data += '| ETH address {}'.format(sim_address)
                sim_data += '| {} Active stakes '.format(len(stake_infos))

            click.echo(sim_data)
            config.simulation_running = True

        click.echo("Starting the reactor")
        try:
            reactor.run()

        finally:

            if config.operating_mode == 'decentralized':
                click.echo("Removing simulation registry")
                os.remove(config.sim_registry_filepath)

            click.echo("Stopping simulated Ursula processes")
            for process in config.sim_processes:
                os.kill(process.pid, 9)
                click.echo("Killed {}".format(process))
            config.simulation_running = False
            click.echo("Simulation stopped")

    elif action == 'stop':
        # Kill the simulated ursulas TODO: read PIDs from storage?
        if config.simulation_running is not True:
            raise RuntimeError("Network simulation is not running")

        for process in config.ursula_processes:
            process.transport.signalProcess('KILL')
        else:
            # TODO: Confirm they are dead
            config.simulation_running = False

    elif action == 'status':

        if not config.simulation_running:
            status_message = "Simulation not running."
        else:

            ursula_processes = len(config.ursula_processes)

            status_message = """
            
            | Node Swarm Simulation Status |
            
            Simulation processes .............. {}
            
            """.format(ursula_processes)

        click.echo(status_message)

    elif action == 'demo':
        """Run the finnegans wake demo"""
        demo_exec = os.path.join(BASE_DIR, 'nucypher_cli', 'demos',
                                 'finnegans-wake-demo.py')
        subprocess.run([sys.executable, demo_exec], stdout=subprocess.PIPE)
Exemplo n.º 3
0
def simulate(config, action, nodes, federated_only, geth):
    """
    Simulate the nucypher blockchain network

    Arguments
    ==========

    action - Which action to perform; The choices are:
           - start: Start a multi-process nucypher network simulation
           - stop: Stop a running simulation gracefully

    Options
    ========

    --nodes - The quantity of nodes (processes) to execute during the simulation
    --duration = The number of periods to run the simulation before termination

    """
    if action == 'start':

        #
        # Blockchain Connection
        #
        if not federated_only:
            if geth:
                test_provider_uri = "ipc:///tmp/geth.ipc"
            else:
                test_provider_uri = "pyevm://tester"

            simulation_registry = TemporaryEthereumContractRegistry()
            simulation_interface = BlockchainDeployerInterface(provider_uri=test_provider_uri,
                                                               registry=simulation_registry,
                                                               compiler=SolidityCompiler())

            blockchain = TesterBlockchain(interface=simulation_interface, test_accounts=nodes, airdrop=False)

            accounts = blockchain.interface.w3.eth.accounts
            origin, *everyone_else = accounts

            # Set the deployer address from the freshly created test account
            simulation_interface.deployer_address = origin

            #
            # Blockchain Action
            #
            blockchain.ether_airdrop(amount=DEVELOPMENT_ETH_AIRDROP_AMOUNT)

            click.confirm("Deploy all nucypher contracts to {}?".format(test_provider_uri), abort=True)
            click.echo("Bootstrapping simulated blockchain network")

            # Deploy contracts
            token_deployer = NucypherTokenDeployer(blockchain=blockchain, deployer_address=origin)
            token_deployer.arm()
            token_deployer.deploy()
            token_agent = token_deployer.make_agent()

            miners_escrow_secret = os.urandom(DISPATCHER_SECRET_LENGTH)
            miner_escrow_deployer = MinerEscrowDeployer(token_agent=token_agent,
                                                        deployer_address=origin,
                                                        secret_hash=miners_escrow_secret)
            miner_escrow_deployer.arm()
            miner_escrow_deployer.deploy()
            miner_agent = miner_escrow_deployer.make_agent()

            policy_manager_secret = os.urandom(DISPATCHER_SECRET_LENGTH)
            policy_manager_deployer = PolicyManagerDeployer(miner_agent=miner_agent,
                                                            deployer_address=origin,
                                                            secret_hash=policy_manager_secret)
            policy_manager_deployer.arm()
            policy_manager_deployer.deploy()
            policy_agent = policy_manager_deployer.make_agent()

            airdrop_amount = DEVELOPMENT_TOKEN_AIRDROP_AMOUNT
            click.echo("Airdropping tokens {} to {} addresses".format(airdrop_amount, len(everyone_else)))
            _receipts = token_airdrop(token_agent=token_agent,
                                      origin=origin,
                                      addresses=everyone_else,
                                      amount=airdrop_amount)

            # Commit the current state of deployment to a registry file.
            click.echo("Writing filesystem registry")
            _sim_registry_name = blockchain.interface.registry.commit(filepath=DEFAULT_SIMULATION_REGISTRY_FILEPATH)

        click.echo("Ready to run swarm.")

        #
        # Swarm
        #

        # Select a port range to use on localhost for sim servers

        if not federated_only:
            sim_addresses = everyone_else
        else:
            sim_addresses = NotImplemented

        start_port = 8787
        counter = 0
        for sim_port_number, sim_address in enumerate(sim_addresses, start=start_port):

            #
            # Parse ursula parameters
            #

            rest_port = sim_port_number
            db_name = 'sim-{}'.format(rest_port)

            cli_exec = os.path.join(BASE_DIR, 'cli', 'main.py')
            python_exec = 'python'

            proc_params = '''
            python3 {} run_ursula --rest-port {} --db-name {}
            '''.format(python_exec, cli_exec, rest_port, db_name).split()

            if federated_only:
                proc_params.append('--federated-only')

            else:
                token_agent = NucypherTokenAgent(blockchain=blockchain)
                miner_agent = MinerAgent(token_agent=token_agent)
                miner = Miner(miner_agent=miner_agent, checksum_address=sim_address)

                # stake a random amount
                min_stake, balance = MIN_ALLOWED_LOCKED, miner.token_balance
                value = random.randint(min_stake, balance)

                # for a random lock duration
                min_locktime, max_locktime = MIN_LOCKED_PERIODS, MAX_MINTING_PERIODS
                periods = random.randint(min_locktime, max_locktime)

                miner.initialize_stake(amount=value, lock_periods=periods)
                click.echo("{} Initialized new stake: {} tokens for {} periods".format(sim_address, value, periods))

                proc_params.extend('--checksum-address {}'.format(sim_address).split())

            # Spawn
            click.echo("Spawning node #{}".format(counter+1))
            processProtocol = UrsulaProcessProtocol(command=proc_params)
            cli_exec = os.path.join(BASE_DIR, 'cli', 'main.py')
            ursula_proc = reactor.spawnProcess(processProtocol, cli_exec, proc_params)

            #
            # post-spawnProcess
            #

            # Start with some basic status data, then build on it

            rest_uri = "http://{}:{}".format('localhost', rest_port)

            sim_data = "Started simulated Ursula | ReST {}".format(rest_uri)
            rest_uri = "{host}:{port}".format(host='localhost', port=str(sim_port_number))
            sim_data.format(rest_uri)

            # if not federated_only:
            #     stake_infos = tuple(config.miner_agent.get_all_stakes(miner_address=sim_address))
            #     sim_data += '| ETH address {}'.format(sim_address)
            #     sim_data += '| {} Active stakes '.format(len(stake_infos))

            click.echo(sim_data)
            counter += 1

        click.echo("Starting the reactor")
        click.confirm("Start the reactor?", abort=True)
        try:
            reactor.run()
        finally:

            if not federated_only:
                click.echo("Removing simulation registry")
                os.remove(DEFAULT_SIMULATION_REGISTRY_FILEPATH)

            click.echo("Stopping simulated Ursula processes")
            for process in config.sim_processes:
                os.kill(process.pid, 9)
                click.echo("Killed {}".format(process))

            click.echo("Simulation completed")

    elif action == 'stop':
        # Kill the simulated ursulas
        for process in config.ursula_processes:
            process.transport.signalProcess('KILL')

    elif action == 'status':

        if not config.simulation_running:
            status_message = "Simulation not running."
        else:

            ursula_processes = len(config.ursula_processes)

            status_message = """
            
            | Node Swarm Simulation Status |
            
            Simulation processes .............. {}
            
            """.format(ursula_processes)

        click.echo(status_message)

    elif action == 'demo':
        """Run the finnegans wake demo"""
        demo_exec = os.path.join(BASE_DIR, 'cli', 'demos', 'finnegans-wake-demo.py')
        process_args = [sys.executable, demo_exec]

        if federated_only:
            process_args.append('--federated-only')

        subprocess.run(process_args, stdout=subprocess.PIPE)