Ejemplo n.º 1
0
def _jsonrpc_services(deploy_key,
                      deploy_client,
                      private_keys,
                      verbose,
                      poll_timeout,
                      registry_address=None):

    # we cannot instantiate BlockChainService without a registry, so first
    # deploy it directly with a JSONRPCClient
    if registry_address is None:
        address = privatekey_to_address(deploy_key)

        registry_path = get_contract_path('Registry.sol')
        registry_contracts = compile_file(registry_path, libraries=dict())

        log.info('Deploying registry contract')
        registry_proxy = deploy_client.deploy_solidity_contract(
            address,
            'Registry',
            registry_contracts,
            dict(),
            tuple(),
            contract_path=registry_path,
            gasprice=default_gasprice,
            timeout=poll_timeout,
        )
        registry_address = registry_proxy.address

    # at this point the blockchain must be running, this will overwrite the
    # method so even if the client is patched twice, it should work fine
    patch_send_transaction(deploy_client)

    deploy_blockchain = BlockChainService(deploy_key, deploy_client)
    deploy_registry = deploy_blockchain.registry(registry_address)

    host = '0.0.0.0'
    blockchain_services = list()
    for privkey in private_keys:
        rpc_client = JSONRPCClient(
            privkey=privkey,
            host=host,
            port=deploy_client.port,
            print_communication=False,
        )
        patch_send_transaction(rpc_client)
        patch_send_message(rpc_client)

        blockchain = BlockChainService(
            privkey,
            rpc_client,
        )
        blockchain_services.append(blockchain)

    return BlockchainServices(
        deploy_registry,
        deploy_blockchain,
        blockchain_services,
    )
Ejemplo n.º 2
0
def app(address,
        keystore_path,
        eth_rpc_endpoint,
        registry_contract_address,
        discovery_contract_address,
        listen_address,
        rpccorsdomain,
        mapped_socket,
        logging,
        logfile,
        log_json,
        max_unresponsive_time,
        send_ping_time,
        api_address,
        rpc,
        sync_check,
        console,
        password_file,
        web_ui,
        datadir,
        eth_client_communication,
        nat):

    # pylint: disable=too-many-locals,too-many-branches,too-many-statements,unused-argument

    from raiden.app import App
    from raiden.network.rpc.client import BlockChainService

    (listen_host, listen_port) = split_endpoint(listen_address)
    (api_host, api_port) = split_endpoint(api_address)

    config = App.DEFAULT_CONFIG.copy()
    config['host'] = listen_host
    config['port'] = listen_port
    config['console'] = console
    config['rpc'] = rpc
    config['web_ui'] = rpc and web_ui
    config['api_host'] = api_host
    config['api_port'] = api_port

    if mapped_socket:
        config['socket'] = mapped_socket.socket
        config['external_ip'] = mapped_socket.external_ip
        config['external_port'] = mapped_socket.external_port
    else:
        config['socket'] = None
        config['external_ip'] = listen_host
        config['external_port'] = listen_port

    config['protocol']['nat_keepalive_retries'] = DEFAULT_NAT_KEEPALIVE_RETRIES
    timeout = max_unresponsive_time / DEFAULT_NAT_KEEPALIVE_RETRIES
    config['protocol']['nat_keepalive_timeout'] = timeout

    address_hex = address_encoder(address) if address else None
    address_hex, privatekey_bin = prompt_account(address_hex, keystore_path, password_file)
    address = address_decoder(address_hex)

    privatekey_hex = privatekey_bin.encode('hex')
    config['privatekey_hex'] = privatekey_hex

    endpoint = eth_rpc_endpoint

    # Fallback default port if only an IP address is given
    rpc_port = 8545
    if eth_rpc_endpoint.startswith("http://"):
        endpoint = eth_rpc_endpoint[len("http://"):]
        rpc_port = 80
    elif eth_rpc_endpoint.startswith("https://"):
        endpoint = eth_rpc_endpoint[len("https://"):]
        rpc_port = 443

    if ':' not in endpoint:  # no port was given in url
        rpc_host = endpoint
    else:
        rpc_host, rpc_port = split_endpoint(endpoint)

    rpc_client = JSONRPCClient(
        rpc_host,
        rpc_port,
        privatekey_bin,
    )

    # this assumes the eth node is already online
    patch_send_transaction(rpc_client)
    patch_send_message(rpc_client)
    if not check_json_rpc(rpc_client):
        sys.exit(1)

    blockchain_service = BlockChainService(
        privatekey_bin,
        rpc_client,
    )

    if sync_check:
        check_synced(blockchain_service)

    discovery_tx_cost = GAS_PRICE * DISCOVERY_REGISTRATION_GAS
    while True:
        balance = blockchain_service.client.balance(address)
        if discovery_tx_cost <= balance:
            break
        print(
            'Account has insufficient funds for discovery registration.\n'
            'Needed: {} ETH\n'
            'Available: {} ETH.\n'
            'Please deposit additional funds on this account.'
            .format(discovery_tx_cost / float(denoms.ether), balance / float(denoms.ether))
        )
        if not click.confirm('Try again?'):
            sys.exit(1)

    registry = blockchain_service.registry(
        registry_contract_address,
    )

    discovery = ContractDiscovery(
        blockchain_service.node_address,
        blockchain_service.discovery(discovery_contract_address)
    )

    if datadir is None:
        # default database directory
        raiden_directory = os.path.join(os.path.expanduser('~'), '.raiden')
    else:
        raiden_directory = datadir

    if not os.path.exists(raiden_directory):
        os.makedirs(raiden_directory)
    user_db_dir = os.path.join(raiden_directory, address_hex[:8])
    if not os.path.exists(user_db_dir):
        os.makedirs(user_db_dir)
    database_path = os.path.join(user_db_dir, 'log.db')
    config['database_path'] = database_path

    return App(
        config,
        blockchain_service,
        registry,
        discovery,
    )
Ejemplo n.º 3
0
def app(address, keystore_path, eth_rpc_endpoint, registry_contract_address,
        discovery_contract_address, listen_address, rpccorsdomain,
        mapped_socket, logging, logfile, log_json, max_unresponsive_time,
        send_ping_time, api_address, rpc, sync_check, console, password_file,
        web_ui, datadir, eth_client_communication, nat):

    # pylint: disable=too-many-locals,too-many-branches,too-many-statements,unused-argument

    from raiden.app import App
    from raiden.network.rpc.client import BlockChainService

    (listen_host, listen_port) = split_endpoint(listen_address)
    (api_host, api_port) = split_endpoint(api_address)

    config = App.DEFAULT_CONFIG.copy()
    config['host'] = listen_host
    config['port'] = listen_port
    config['console'] = console
    config['rpc'] = rpc
    config['web_ui'] = rpc and web_ui
    config['api_host'] = api_host
    config['api_port'] = api_port

    if mapped_socket:
        config['socket'] = mapped_socket.socket
        config['external_ip'] = mapped_socket.external_ip
        config['external_port'] = mapped_socket.external_port
    else:
        config['socket'] = None
        config['external_ip'] = listen_host
        config['external_port'] = listen_port

    config['protocol']['nat_keepalive_retries'] = DEFAULT_NAT_KEEPALIVE_RETRIES
    timeout = max_unresponsive_time / DEFAULT_NAT_KEEPALIVE_RETRIES
    config['protocol']['nat_keepalive_timeout'] = timeout

    address_hex = address_encoder(address) if address else None
    address_hex, privatekey_bin = prompt_account(address_hex, keystore_path,
                                                 password_file)

    privatekey_hex = privatekey_bin.encode('hex')
    config['privatekey_hex'] = privatekey_hex

    endpoint = eth_rpc_endpoint

    # Fallback default port if only an IP address is given
    rpc_port = 8545
    if eth_rpc_endpoint.startswith("http://"):
        endpoint = eth_rpc_endpoint[len("http://"):]
        rpc_port = 80
    elif eth_rpc_endpoint.startswith("https://"):
        endpoint = eth_rpc_endpoint[len("https://"):]
        rpc_port = 443

    if ':' not in endpoint:  # no port was given in url
        rpc_host = endpoint
    else:
        rpc_host, rpc_port = split_endpoint(endpoint)

    rpc_client = JSONRPCClient(
        privkey=privatekey_bin,
        host=rpc_host,
        port=rpc_port,
        print_communication=eth_client_communication,
    )

    # this assumes the eth node is already online
    patch_send_transaction(rpc_client)
    patch_send_message(rpc_client)

    try:
        blockchain_service = BlockChainService(
            privatekey_bin,
            rpc_client,
        )
    except ValueError as e:
        # ValueError exception raised if:
        # - The registry contract address doesn't have code, this might happen
        # if the connected geth process is not synced or if the wrong address
        # is provided (e.g. using the address from a smart contract deployed on
        # ropsten with a geth node connected to morden)
        print(e.message)
        sys.exit(1)

    if sync_check:
        try:
            net_id = int(blockchain_service.client.call('net_version'))
            network = ID_TO_NETWORKNAME[net_id]
        except:  # pylint: disable=bare-except
            print(
                "Couldn't determine the network the ethereum node is connected to.\n"
                "Because of this there is not way to determine the latest\n"
                "block with an oracle, and the events from the ethereum\n"
                "node cannot be trusted. Giving up.\n")
            sys.exit(1)

        url = ETHERSCAN_API.format(
            network=network,
            action='eth_blockNumber',
        )
        wait_for_sync(
            blockchain_service,
            url=url,
            tolerance=ORACLE_BLOCKNUMBER_DRIFT_TOLERANCE,
            sleep=3,
        )

    discovery_tx_cost = GAS_PRICE * DISCOVERY_REGISTRATION_GAS
    while True:
        balance = blockchain_service.client.balance(address_hex)
        if discovery_tx_cost <= balance:
            break
        print('Account has insufficient funds for discovery registration.\n'
              'Needed: {} ETH\n'
              'Available: {} ETH.\n'
              'Please deposit additional funds on this account.'.format(
                  discovery_tx_cost / float(denoms.ether),
                  balance / float(denoms.ether)))
        if not click.confirm('Try again?'):
            sys.exit(1)

    registry = blockchain_service.registry(registry_contract_address, )

    discovery = ContractDiscovery(
        blockchain_service.node_address,
        blockchain_service.discovery(discovery_contract_address))

    if datadir is None:
        # default database directory
        raiden_directory = os.path.join(os.path.expanduser('~'), '.raiden')
    else:
        raiden_directory = datadir

    if not os.path.exists(raiden_directory):
        os.makedirs(raiden_directory)
    user_db_dir = os.path.join(raiden_directory, address_hex[:8])
    if not os.path.exists(user_db_dir):
        os.makedirs(user_db_dir)
    database_path = os.path.join(user_db_dir, 'log.db')
    config['database_path'] = database_path

    return App(
        config,
        blockchain_service,
        registry,
        discovery,
    )
Ejemplo n.º 4
0
def run(privatekey, registry_contract_address, discovery_contract_address,
        listen_address, logging, logfile, scenario, stage_prefix,
        results_filename):  # pylint: disable=unused-argument

    # TODO: only enabled logging on "initiators"
    slogging.configure(logging, log_file=logfile)

    (listen_host, listen_port) = split_endpoint(listen_address)

    config = App.DEFAULT_CONFIG.copy()
    config['host'] = listen_host
    config['port'] = listen_port
    config['privatekey_hex'] = privatekey

    privatekey_bin = decode_hex(privatekey)

    rpc_client = JSONRPCClient(
        '127.0.0.1',
        '8545',
        privatekey_bin,
    )

    blockchain_service = BlockChainService(
        privatekey_bin,
        rpc_client,
    )

    discovery = ContractDiscovery(blockchain_service,
                                  decode_hex(discovery_contract_address))

    registry = blockchain_service.registry(registry_contract_address)

    app = App(
        config,
        blockchain_service,
        registry,
        discovery,
    )

    app.discovery.register(
        app.raiden.address,
        listen_host,
        listen_port,
    )

    app.raiden.register_registry(app.raiden.default_registry.address)

    if scenario:
        script = json.load(scenario)

        tools = ConsoleTools(
            app.raiden,
            app.discovery,
            app.config['settle_timeout'],
            app.config['reveal_timeout'],
        )

        transfers_by_peer = {}

        tokens = script['tokens']
        token_address = None
        peer = None
        our_node = app.raiden.address.encode('hex')
        log.warning("our address is {}".format(our_node))
        for token in tokens:
            # skip tokens that we're not part of
            nodes = token['channels']
            if our_node not in nodes:
                continue

            partner_nodes = [node for node in nodes if node != our_node]

            # allow for prefunded tokens
            if 'token_address' in token:
                token_address = token['token_address']
            else:
                token_address = tools.create_token()

            transfers_with_amount = token['transfers_with_amount']

            # FIXME: in order to do bidirectional channels, only one side
            # (i.e. only token['channels'][0]) should
            # open; others should join by calling
            # raiden.api.deposit, AFTER the channel came alive!

            # NOTE: leaving unidirectional for now because it most
            #       probably will get to higher throughput

            log.warning("Waiting for all nodes to come online")

            api = RaidenAPI(app.raiden)

            for node in partner_nodes:
                api.start_health_check_for(node)

            while True:
                all_reachable = all(
                    api.get_node_network_state(node) == NODE_NETWORK_REACHABLE
                    for node in partner_nodes)

                if all_reachable:
                    break

                gevent.sleep(5)

            log.warning("All nodes are online")

            if our_node != nodes[-1]:
                our_index = nodes.index(our_node)
                peer = nodes[our_index + 1]

                tools.register_token(token_address)
                amount = transfers_with_amount[nodes[-1]]

                while True:
                    try:
                        app.discovery.get(peer.decode('hex'))
                        break
                    except KeyError:
                        log.warning(
                            "Error: peer {} not found in discovery".format(
                                peer))
                        time.sleep(random.randrange(30))

                while True:
                    try:
                        log.warning("Opening channel with {} for {}".format(
                            peer, token_address))
                        api.open(token_address, peer)
                        break
                    except KeyError:
                        log.warning(
                            "Error: could not open channel with {}".format(
                                peer))
                        time.sleep(random.randrange(30))

                while True:
                    try:
                        log.warning("Funding channel with {} for {}".format(
                            peer, token_address))
                        api.deposit(token_address, peer, amount)
                        break
                    except Exception:
                        log.warning(
                            "Error: could not deposit {} for {}".format(
                                amount, peer))
                        time.sleep(random.randrange(30))

                if our_index == 0:
                    last_node = nodes[-1]
                    transfers_by_peer[last_node] = int(amount)
            else:
                peer = nodes[-2]

        if stage_prefix is not None:
            open('{}.stage1'.format(stage_prefix), 'a').close()
            log.warning("Done with initialization, waiting to continue...")
            event = gevent.event.Event()
            gevent.signal(signal.SIGUSR2, event.set)
            event.wait()

        transfer_results = {'total_time': 0, 'timestamps': []}

        def transfer(token_address, amount_per_transfer, total_transfers, peer,
                     is_async):
            def transfer_():
                log.warning("Making {} transfers to {}".format(
                    total_transfers, peer))
                initial_time = time.time()
                times = [0] * total_transfers
                for index in xrange(total_transfers):
                    RaidenAPI(app.raiden).transfer(
                        token_address.decode('hex'),
                        amount_per_transfer,
                        peer,
                    )
                    times[index] = time.time()

                transfer_results['total_time'] = time.time() - initial_time
                transfer_results['timestamps'] = times

                log.warning("Making {} transfers took {}".format(
                    total_transfers, transfer_results['total_time']))
                log.warning("Times: {}".format(times))

            if is_async:
                return gevent.spawn(transfer_)
            else:
                transfer_()

        # If sending to multiple targets, do it asynchronously, otherwise
        # keep it simple and just send to the single target on my thread.
        if len(transfers_by_peer) > 1:
            greenlets = []
            for peer_, amount in transfers_by_peer.items():
                greenlet = transfer(token_address, 1, amount, peer_, True)
                if greenlet is not None:
                    greenlets.append(greenlet)

            gevent.joinall(greenlets)

        elif len(transfers_by_peer) == 1:
            for peer_, amount in transfers_by_peer.items():
                transfer(token_address, 1, amount, peer_, False)

        log.warning("Waiting for termination")

        open('{}.stage2'.format(stage_prefix), 'a').close()
        log.warning("Waiting for transfers to finish, will write results...")
        event = gevent.event.Event()
        gevent.signal(signal.SIGUSR2, event.set)
        event.wait()

        results = tools.channel_stats_for(token_address, peer)
        if transfer_results['total_time'] != 0:
            results['total_time'] = transfer_results['total_time']
        if len(transfer_results['timestamps']) > 0:
            results['timestamps'] = transfer_results['timestamps']
        results['channel'] = repr(results['channel'])  # FIXME

        log.warning("Results: {}".format(results))

        with open(results_filename, 'w') as fp:
            json.dump(results, fp, indent=2)

        open('{}.stage3'.format(stage_prefix), 'a').close()
        event = gevent.event.Event()
        gevent.signal(signal.SIGQUIT, event.set)
        gevent.signal(signal.SIGTERM, event.set)
        gevent.signal(signal.SIGINT, event.set)
        event.wait()

    else:
        log.warning("No scenario file supplied, doing nothing!")

        open('{}.stage2'.format(stage_prefix), 'a').close()
        event = gevent.event.Event()
        gevent.signal(signal.SIGQUIT, event.set)
        gevent.signal(signal.SIGTERM, event.set)
        gevent.signal(signal.SIGINT, event.set)
        event.wait()

    app.stop()