Example #1
0
    def _serve_webui(self, file_name='index.html'):  # pylint: disable=redefined-builtin
        try:
            if not file_name:
                raise NotFound

            web3 = self.flask_app.config.get('WEB3_ENDPOINT')
            if 'config.' in file_name and file_name.endswith('.json'):
                environment_type = self.rest_api.raiden_api.raiden.config[
                    'environment_type'
                ].name.lower()
                config = {
                    'raiden': self._api_prefix,
                    'web3': web3,
                    'settle_timeout': self.rest_api.raiden_api.raiden.config['settle_timeout'],
                    'reveal_timeout': self.rest_api.raiden_api.raiden.config['reveal_timeout'],
                    'environment_type': environment_type,
                }

                # if raiden sees eth rpc endpoint as localhost, replace it by Host header,
                # which is the hostname by which the client/browser sees/access the raiden node
                host = request.headers.get('Host')
                if web3 and host:
                    web3_host, web3_port = split_endpoint(web3)
                    if web3_host in ('localhost', '127.0.0.1'):
                        host, _ = split_endpoint(host)
                        web3 = f'http://{host}:{web3_port}'
                        config['web3'] = web3

                response = jsonify(config)
            else:
                response = send_from_directory(self.flask_app.config['WEBUI_PATH'], file_name)
        except (NotFound, AssertionError):
            response = send_from_directory(self.flask_app.config['WEBUI_PATH'], 'index.html')
        return response
Example #2
0
def run(ctx, **kwargs):
    if ctx.invoked_subcommand is None:
        from raiden.api.python import RaidenAPI
        from raiden.ui.console import Console

        slogging.configure(kwargs['logging'], log_file=kwargs['logfile'])

        # TODO:
        # - Ask for confirmation to quit if there are any locked transfers that did
        # not timeout.
        (listen_host, listen_port) = split_endpoint(kwargs['listen_address'])
        with socket_factory(listen_host, listen_port) as mapped_socket:
            kwargs['mapped_socket'] = mapped_socket

            app_ = ctx.invoke(app, **kwargs)

            domain_list = []
            if kwargs['rpccorsdomain']:
                if ',' in kwargs['rpccorsdomain']:
                    for domain in kwargs['rpccorsdomain'].split(','):
                        domain_list.append(str(domain))
                else:
                    domain_list.append(str(kwargs['rpccorsdomain']))

            http_server = None
            if ctx.params['rpc']:
                raiden_api = RaidenAPI(app_.raiden)
                rest_api = RestAPI(raiden_api)
                api_server = APIServer(rest_api, cors_domain_list=domain_list)
                (api_host, api_port) = split_endpoint(kwargs["api_address"])

                http_server = WSGIServer((api_host, api_port),
                                         api_server.flask_app,
                                         log=slogging.getLogger('flask'))
                http_server.start()

                print(
                    "The Raiden API RPC server is now running at http://{}:{}/.\n\n"
                    "See the Raiden documentation for all available endpoints at\n"
                    "https://github.com/raiden-network/raiden/blob/master"
                    "/docs/Rest-Api.rst".format(
                        api_host,
                        api_port,
                    ))

            if ctx.params['console']:
                console = Console(app_)
                console.start()

            # wait for interrupt
            event = gevent.event.Event()
            gevent.signal(signal.SIGQUIT, event.set)
            gevent.signal(signal.SIGTERM, event.set)
            gevent.signal(signal.SIGINT, event.set)
            event.wait()

        if http_server:
            http_server.stop(5)
        app_.stop(leave_channels=False)
Example #3
0
def test_split_endpoint_valid():
    host, port = split_endpoint("https://rpc.slock.it/goerli")
    assert host == "rpc.slock.it"
    assert port == 0

    host, port = split_endpoint("https://rpc.slock.it:443/goerli")
    assert host == "rpc.slock.it"
    assert port == 443
Example #4
0
def app(privatekey, eth_rpc_endpoint, registry_contract_address,
        discovery_contract_address, listen_address, external_listen_address,
        logging, logfile):

    slogging.configure(logging, log_file=logfile)

    if not external_listen_address:
        # notify('if you are behind a NAT, you should set
        # `external_listen_address` and configure port forwarding on your router')
        external_listen_address = listen_address

    # config_file = args.config_file
    (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

    endpoint = eth_rpc_endpoint
    use_ssl = False

    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://"):]
        use_ssl = True
        rpc_port = 443

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

    jsonrpc_client = JSONRPCClient(
        privkey=privatekey,
        host=rpc_host,
        port=rpc_port,
        print_communication=False,
        use_ssl=use_ssl,
    )

    blockchain_service = BlockChainService(
        privatekey.decode('hex'),
        registry_contract_address.decode('hex'),
    )
    discovery = ContractDiscovery(
        jsonrpc_client,
        discovery_contract_address.decode('hex'))  # FIXME: double encoding

    app = App(config, blockchain_service, discovery)

    discovery.register(app.raiden.address,
                       *split_endpoint(external_listen_address))

    app.raiden.register_registry(blockchain_service.default_registry)
    return app
Example #5
0
def app(privatekey, eth_rpc_endpoint, registry_contract_address,
        discovery_contract_address, listen_address, external_listen_address,
        logging):

    slogging.configure(logging)

    if not external_listen_address:
        # notify('if you are behind a NAT, you should set
        # `external_listen_address` and configure port forwarding on your router')
        external_listen_address = listen_address

    # config_file = args.config_file
    rpc_connection = split_endpoint(eth_rpc_endpoint)
    (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

    jsonrpc_client = JSONRPCClient(
        privkey=privatekey,
        host=rpc_connection[0],
        port=rpc_connection[1],
        print_communication=False,
    )

    blockchain_service = BlockChainService(
        jsonrpc_client,
        registry_contract_address.decode('hex'),
    )
    discovery = ContractDiscovery(
        jsonrpc_client,
        discovery_contract_address.decode('hex'))  # FIXME: double encoding

    app = App(config, blockchain_service, discovery)

    discovery.register(app.raiden.address,
                       *split_endpoint(external_listen_address))

    app.raiden.register_registry(blockchain_service.default_registry)

    # TODO:
    # - Ask for confirmation to quit if there are any locked transfers that did
    # not timeout.

    console = Console(app)
    console.start()

    # wait for interrupt
    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()
Example #6
0
def app(privatekey, eth_rpc_endpoint, registry_contract_address,
        discovery_contract_address, listen_address, external_listen_address, logging):

    slogging.configure(logging)

    if not external_listen_address:
        # notify('if you are behind a NAT, you should set
        # `external_listen_address` and configure port forwarding on your router')
        external_listen_address = listen_address

    # config_file = args.config_file
    rpc_connection = split_endpoint(eth_rpc_endpoint)
    (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

    jsonrpc_client = JSONRPCClient(
        privkey=privatekey,
        host=rpc_connection[0],
        port=rpc_connection[1],
        print_communication=False,
    )

    blockchain_service = BlockChainService(
        jsonrpc_client,
        registry_contract_address.decode('hex'),
    )
    discovery = ContractDiscovery(jsonrpc_client, discovery_contract_address.decode('hex'))  # FIXME: double encoding

    app = App(config, blockchain_service, discovery)

    discovery.register(app.raiden.address, *split_endpoint(external_listen_address))

    app.raiden.register_registry(blockchain_service.default_registry)

    # TODO:
    # - Ask for confirmation to quit if there are any locked transfers that did
    # not timeout.

    console = Console(app)
    console.start()

    # wait for interrupt
    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()
Example #7
0
def run(ctx, external_listen_address, **kwargs):
    # TODO:
    # - Ask for confirmation to quit if there are any locked transfers that did
    # not timeout.

    if not external_listen_address:
        # notify('if you are behind a NAT, you should set
        # `external_listen_address` and configure port forwarding on your router')
        external_listen_address = kwargs['listen_address']

    ctx.params.pop('external_listen_address')
    app_ = ctx.invoke(app, **kwargs)

    app_.discovery.register(
        app_.raiden.address,
        *split_endpoint(external_listen_address)
    )

    app_.raiden.register_registry(app_.raiden.chain.default_registry)

    console = Console(app_)
    console.start()

    # wait for interrupt
    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()
Example #8
0
def run(ctx, **kwargs):
    from raiden.api.python import RaidenAPI
    from raiden.ui.console import Console

    # TODO:
    # - Ask for confirmation to quit if there are any locked transfers that did
    # not timeout.
    (listen_host, listen_port) = split_endpoint(kwargs['listen_address'])
    with socket_factory(listen_host, listen_port) as mapped_socket:
        kwargs['socket'] = mapped_socket.socket

        app_ = ctx.invoke(app, **kwargs)

        # spawn address registration to avoid block while waiting for the next block
        registry_event = gevent.spawn(
            app_.discovery.register,
            app_.raiden.address,
            mapped_socket.external_ip,
            mapped_socket.external_port,
        )
        app_.raiden.register_registry(
            app_.raiden.chain.default_registry.address)

        domain_list = []
        if kwargs['rpccorsdomain']:
            if ',' in kwargs['rpccorsdomain']:
                for domain in kwargs['rpccorsdomain'].split(','):
                    domain_list.append(str(domain))
            else:
                domain_list.append(str(kwargs['rpccorsdomain']))

        if ctx.params['rpc']:
            raiden_api = RaidenAPI(app_.raiden)
            rest_api = RestAPI(raiden_api)
            api_server = APIServer(rest_api, cors_domain_list=domain_list)

            Greenlet.spawn(api_server.run,
                           ctx.params['api_port'],
                           debug=False,
                           use_evalex=False)

            print(
                "The RPC server is now running at http://localhost:{}/.\n\n"
                "See the Raiden documentation for all available endpoints at\n"
                "https://github.com/raiden-network/raiden/blob/master/docs/Rest-Api.rst"
                .format(ctx.params['api_port'], ))

        if ctx.params['console']:
            console = Console(app_)
            console.start()

        registry_event.join()
        # wait for interrupt
        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(graceful=True)
Example #9
0
File: app.py Project: cyl-e/raiden
def run(ctx, external_listen_address, **kwargs):
    # TODO:
    # - Ask for confirmation to quit if there are any locked transfers that did
    # not timeout.

    if not external_listen_address:
        # notify('if you are behind a NAT, you should set
        # `external_listen_address` and configure port forwarding on your router')
        external_listen_address = kwargs['listen_address']

    ctx.params.pop('external_listen_address')
    app_ = ctx.invoke(app, **kwargs)

    app_.discovery.register(app_.raiden.address,
                            *split_endpoint(external_listen_address))

    app_.raiden.register_registry(app_.raiden.chain.default_registry)

    console = Console(app_)
    console.start()

    # wait for interrupt
    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()
Example #10
0
 def _serve_webui(self, file_name='index.html'):  # pylint: disable=redefined-builtin
     try:
         assert file_name
         web3 = self.flask_app.config.get('WEB3_ENDPOINT')
         if web3 and 'config.' in file_name and file_name.endswith('.json'):
             host = request.headers.get('Host')
             if any(h in web3 for h in ('localhost', '127.0.0.1')) and host:
                 _, _port = split_endpoint(web3)
                 _host, _ = split_endpoint(host)
                 web3 = 'http://{}:{}'.format(_host, _port)
             response = jsonify({'raiden': self._api_prefix, 'web3': web3})
         else:
             response = send_from_directory(self.flask_app.config['WEBUI_PATH'], file_name)
     except (NotFound, AssertionError):
         response = send_from_directory(self.flask_app.config['WEBUI_PATH'], 'index.html')
     return response
Example #11
0
 def get(self, nodeid):
     endpoint = self.find_endpoint(nodeid)
     if endpoint is '':
         raise KeyError('Unknow address {}'.format(pex(nodeid)))
     host, port = split_endpoint(endpoint)
     port = int(port)
     return (host, port)
Example #12
0
 def _serve_webui(self, file_name='index.html'):  # pylint: disable=redefined-builtin
     try:
         assert file_name
         web3 = self.flask_app.config.get('WEB3_ENDPOINT')
         if web3 and 'config.' in file_name and file_name.endswith('.json'):
             host = request.headers.get('Host')
             if any(h in web3 for h in ('localhost', '127.0.0.1')) and host:
                 _, _port = split_endpoint(web3)
                 _host, _ = split_endpoint(host)
                 web3 = 'http://{}:{}'.format(_host, _port)
             response = jsonify({'raiden': self._api_prefix, 'web3': web3})
         else:
             response = send_from_directory(self.flask_app.config['WEBUI_PATH'], file_name)
     except (NotFound, AssertionError):
         response = send_from_directory(self.flask_app.config['WEBUI_PATH'], 'index.html')
     return response
Example #13
0
    def _run_smoketest():
        print_step('Starting Raiden')

        config = deepcopy(App.DEFAULT_CONFIG)
        if args.get('extra_config', dict()):
            merge_dict(config, args['extra_config'])
            del args['extra_config']
        args['config'] = config

        # invoke the raiden app
        app = run_app(**args)

        raiden_api = RaidenAPI(app.raiden)
        rest_api = RestAPI(raiden_api)
        api_server = APIServer(rest_api)
        (api_host, api_port) = split_endpoint(args['api_address'])
        api_server.start(api_host, api_port)

        raiden_api.channel_open(
            registry_address=contract_addresses[
                CONTRACT_TOKEN_NETWORK_REGISTRY],
            token_address=to_canonical_address(token.contract.address),
            partner_address=to_canonical_address(TEST_PARTNER_ADDRESS),
        )
        raiden_api.set_total_channel_deposit(
            contract_addresses[CONTRACT_TOKEN_NETWORK_REGISTRY],
            to_canonical_address(token.contract.address),
            to_canonical_address(TEST_PARTNER_ADDRESS),
            TEST_DEPOSIT_AMOUNT,
        )
        token_addresses = [to_checksum_address(token.contract.address)]

        success = False
        try:
            print_step('Running smoketest')
            error = run_smoketests(
                app.raiden,
                args['transport'],
                token_addresses,
                contract_addresses[CONTRACT_ENDPOINT_REGISTRY],
                debug=debug,
            )
            if error is not None:
                append_report('Smoketest assertion error', error)
            else:
                success = True
        finally:
            app.stop()
            node = ethereum[0]
            node.send_signal(2)
            err, out = node.communicate()

            append_report('Ethereum stdout', out)
            append_report('Ethereum stderr', err)
        if success:
            print_step(f'Smoketest successful')
        else:
            print_step(f'Smoketest had errors', error=True)
        return success
Example #14
0
    def get(self, nodeid):
        # check whether to encode or decode nodeid
        endpoint = self.discovery_proxy.findEndpointByAddress.call(nodeid.encode('hex'))

        if endpoint is '':
            raise KeyError('Unknow address {}'.format(pex(nodeid)))

        return split_endpoint(endpoint)
Example #15
0
    def _run_app():
        # this catches exceptions raised when waiting for the stalecheck to complete
        try:
            app_ = ctx.invoke(app, **kwargs)
        except EthNodeCommunicationError as err:
            sys.exit(1)

        domain_list = []
        if kwargs['rpccorsdomain']:
            if ',' in kwargs['rpccorsdomain']:
                for domain in kwargs['rpccorsdomain'].split(','):
                    domain_list.append(str(domain))
            else:
                domain_list.append(str(kwargs['rpccorsdomain']))

        api_server = None
        if ctx.params['rpc']:
            raiden_api = RaidenAPI(app_.raiden)
            rest_api = RestAPI(raiden_api)
            api_server = APIServer(
                rest_api,
                cors_domain_list=domain_list,
                web_ui=ctx.params['web_ui'],
                eth_rpc_endpoint=ctx.params['eth_rpc_endpoint'],
            )
            (api_host, api_port) = split_endpoint(kwargs['api_address'])
            api_server.start(api_host, api_port)

            print(
                'The Raiden API RPC server is now running at http://{}:{}/.\n\n'
                'See the Raiden documentation for all available endpoints at\n'
                'http://raiden-network.readthedocs.io/en/stable/rest_api.html'.
                format(
                    api_host,
                    api_port,
                ))

        if ctx.params['console']:
            console = Console(app_)
            console.start()

        # wait for interrupt
        event = gevent.event.Event()
        gevent.signal(signal.SIGQUIT, event.set)
        gevent.signal(signal.SIGTERM, event.set)
        gevent.signal(signal.SIGINT, event.set)

        gevent.signal(signal.SIGUSR1, toogle_cpu_profiler)
        gevent.signal(signal.SIGUSR2, toggle_trace_profiler)

        event.wait()
        print('Signal received. Shutting down ...')
        if api_server:
            api_server.stop()

        return app_
Example #16
0
File: app.py Project: cyl-e/raiden
def app(privatekey, eth_rpc_endpoint, registry_contract_address,
        discovery_contract_address, listen_address, logging, logfile):

    slogging.configure(logging, log_file=logfile)

    # config_file = args.config_file
    (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

    endpoint = eth_rpc_endpoint

    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)

    blockchain_service = BlockChainService(
        decode_hex(privatekey),
        decode_hex(registry_contract_address),
        host=rpc_host,
        port=rpc_port,
    )

    discovery = ContractDiscovery(
        blockchain_service,
        decode_hex(discovery_contract_address)  # FIXME: double encoding
    )

    return App(config, blockchain_service, discovery)
Example #17
0
    def _serve_webui(self, file_name="index.html"):  # pylint: disable=redefined-builtin
        try:
            if not file_name:
                raise NotFound

            web3 = self.flask_app.config.get("WEB3_ENDPOINT")
            if "config." in file_name and file_name.endswith(".json"):
                environment_type = self.rest_api.raiden_api.raiden.config[
                    "environment_type"].name.lower()
                config = {
                    "raiden":
                    self._api_prefix,
                    "web3":
                    web3,
                    "settle_timeout":
                    self.rest_api.raiden_api.raiden.config["settle_timeout"],
                    "reveal_timeout":
                    self.rest_api.raiden_api.raiden.config["reveal_timeout"],
                    "environment_type":
                    environment_type,
                }

                # if raiden sees eth rpc endpoint as localhost, replace it by Host header,
                # which is the hostname by which the client/browser sees/access the raiden node
                host = request.headers.get("Host")
                if web3 and host:
                    web3_host, web3_port = split_endpoint(web3)
                    if web3_host in ("localhost", "127.0.0.1"):
                        host, _ = split_endpoint(host)
                        web3 = f"http://{host}:{web3_port}"
                        config["web3"] = web3

                response = jsonify(config)
            else:
                response = send_from_directory(
                    self.flask_app.config["WEBUI_PATH"], file_name)
        except (NotFound, AssertionError):
            response = send_from_directory(self.flask_app.config["WEBUI_PATH"],
                                           "index.html")
        return response
Example #18
0
def run(ctx, external_listen_address, **kwargs):
    # TODO:
    # - Ask for confirmation to quit if there are any locked transfers that did
    # not timeout.

    if not external_listen_address:
        # notify('if you are behind a NAT, you should set
        # `external_listen_address` and configure port forwarding on your router')
        external_listen_address = kwargs['listen_address']

    ctx.params.pop('external_listen_address')
    app_ = ctx.invoke(app, **kwargs)

    app_.discovery.register(
        app_.raiden.address,
        *split_endpoint(external_listen_address)
    )

    app_.raiden.register_registry(app_.raiden.chain.default_registry.address)

    if ctx.params['rpc']:
        # instance of the raiden-api
        raiden_api = app_.raiden.api
        # wrap the raiden-api with rest-logic and encoding
        rest_api = RestAPI(raiden_api)
        # create the server and link the api-endpoints with flask / flask-restful middleware
        api_server = APIServer(rest_api)
        # run the server
        Greenlet.spawn(api_server.run, ctx.params['api_port'], debug=False, use_evalex=False)
        print(
            "The RPC server is now running",
            "at http://localhost:{0}/.".format(ctx.params['api_port'])
        )
        print(
            "See the Raiden documentation for all available endpoints at",
            "https://github.com/raiden-network/raiden/blob/master/docs/api.rst"
        )

    if ctx.params['console']:
        console = Console(app_)
        console.start()

    # wait for interrupt
    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()
Example #19
0
File: cli.py Project: timxor/raiden
def run(ctx, **kwargs):
    # TODO:
    # - Ask for confirmation to quit if there are any locked transfers that did
    # not timeout.
    (listen_host, listen_port) = split_endpoint(kwargs['listen_address'])
    with socket_factory(listen_host, listen_port) as mapped_socket:
        kwargs['socket'] = mapped_socket.socket

        app_ = ctx.invoke(app, **kwargs)

        app_.discovery.register(
            app_.raiden.address,
            mapped_socket.external_ip,
            mapped_socket.external_port,
        )

        app_.raiden.register_registry(
            app_.raiden.chain.default_registry.address)

        if ctx.params['rpc']:
            raiden_api = RaidenAPI(app_.raiden)
            rest_api = RestAPI(raiden_api)
            api_server = APIServer(rest_api)

            Greenlet.spawn(api_server.run,
                           ctx.params['api_port'],
                           debug=False,
                           use_evalex=False)

            print(
                "The RPC server is now running at http://localhost:{}/.\n\n"
                "See the Raiden documentation for all available endpoints at\n"
                "https://github.com/raiden-network/raiden/blob/master/docs/api.rst"
                .format(ctx.params['api_port'], ))

        if ctx.params['console']:
            console = Console(app_)
            console.start()

        # wait for interrupt
        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()
Example #20
0
    def run(self):
        super().run()

        (listen_host, listen_port) = split_endpoint(self._options['listen_address'])
        try:
            with SocketFactory(
                listen_host, listen_port, strategy=self._options['nat'],
            ) as mapped_socket:
                self._options['mapped_socket'] = mapped_socket
                app = self._start_services()

        except RaidenServicePortInUseError:
            click.secho(
                'ERROR: Address %s:%s is in use. '
                'Use --listen-address <host:port> to specify port to listen on.' %
                (listen_host, listen_port),
                fg='red',
            )
            sys.exit(1)
        return app
Example #21
0
    def _run_smoketest():
        # invoke the raiden app
        app_ = ctx.invoke(app, **args)

        raiden_api = RaidenAPI(app_.raiden)
        rest_api = RestAPI(raiden_api)
        api_server = APIServer(rest_api)
        (api_host, api_port) = split_endpoint(args['api_address'])
        api_server.start(api_host, api_port)

        success = False
        try:
            print('[4/5] running smoketests...')
            error = run_smoketests(app_.raiden, smoketest_config, debug=debug)
            if error is not None:
                append_report('smoketest assertion error', error)
            else:
                success = True
        finally:
            app_.stop()
            ethereum.send_signal(2)

            err, out = ethereum.communicate()
            append_report('geth init stdout',
                          ethereum_config['init_log_out'].decode('utf-8'))
            append_report('geth init stderr',
                          ethereum_config['init_log_err'].decode('utf-8'))
            append_report('ethereum stdout', out)
            append_report('ethereum stderr', err)
            append_report('smoketest configuration',
                          json.dumps(smoketest_config))
        if success:
            print(
                '[5/5] smoketest successful, report was written to {}'.format(
                    report_file))
        else:
            print(
                '[5/5] smoketest had errors, report was written to {}'.format(
                    report_file))
        return success
Example #22
0
    def run(self):
        super().run()

        (listen_host,
         listen_port) = split_endpoint(self._options["listen_address"])
        try:
            factory = SocketFactory(listen_host,
                                    listen_port,
                                    strategy=self._options["nat"])
            with factory as mapped_socket:
                self._options["mapped_socket"] = mapped_socket
                app = self._start_services()

        except RaidenServicePortInUseError:
            click.secho(
                "ERROR: Address %s:%s is in use. "
                "Use --listen-address <host:port> to specify port to listen on."
                % (listen_host, listen_port),
                fg="red",
            )
            sys.exit(1)
        return app
Example #23
0
    def run(self):
        super().run()

        (listen_host, listen_port) = split_endpoint(self._options['listen_address'])
        try:
            factory = SocketFactory(
                listen_host,
                listen_port,
                strategy=self._options['nat'],
            )
            with factory as mapped_socket:
                self._options['mapped_socket'] = mapped_socket
                app = self._start_services()

        except RaidenServicePortInUseError:
            click.secho(
                'ERROR: Address %s:%s is in use. '
                'Use --listen-address <host:port> to specify port to listen on.' %
                (listen_host, listen_port),
                fg='red',
            )
            sys.exit(1)
        return app
Example #24
0
def run(ctx, **kwargs):
    # pylint: disable=too-many-locals,too-many-branches,too-many-statements

    if ctx.invoked_subcommand is None:
        print('Welcome to Raiden, version {}!'.format(get_system_spec()['raiden']))
        from raiden.ui.console import Console
        from raiden.api.python import RaidenAPI

        slogging.configure(
            kwargs['logging'],
            log_json=kwargs['log_json'],
            log_file=kwargs['logfile']
        )
        if kwargs['logfile']:
            # Disable stream logging
            root = slogging.getLogger()
            for handler in root.handlers:
                if isinstance(handler, slogging.logging.StreamHandler):
                    root.handlers.remove(handler)
                    break

        # TODO:
        # - Ask for confirmation to quit if there are any locked transfers that did
        # not timeout.
        (listen_host, listen_port) = split_endpoint(kwargs['listen_address'])
        try:
            with SocketFactory(listen_host, listen_port, strategy=kwargs['nat']) as mapped_socket:
                kwargs['mapped_socket'] = mapped_socket

                app_ = ctx.invoke(app, **kwargs)

                domain_list = []
                if kwargs['rpccorsdomain']:
                    if ',' in kwargs['rpccorsdomain']:
                        for domain in kwargs['rpccorsdomain'].split(','):
                            domain_list.append(str(domain))
                    else:
                        domain_list.append(str(kwargs['rpccorsdomain']))

                if ctx.params['rpc']:
                    raiden_api = RaidenAPI(app_.raiden)
                    rest_api = RestAPI(raiden_api)
                    api_server = APIServer(
                        rest_api,
                        cors_domain_list=domain_list,
                        web_ui=ctx.params['web_ui'],
                        eth_rpc_endpoint=ctx.params['eth_rpc_endpoint'],
                    )
                    (api_host, api_port) = split_endpoint(kwargs['api_address'])
                    api_server.start(api_host, api_port)

                    print(
                        'The Raiden API RPC server is now running at http://{}:{}/.\n\n'
                        'See the Raiden documentation for all available endpoints at\n'
                        'http://raiden-network.readthedocs.io/en/stable/rest_api.html'.format(
                            api_host,
                            api_port,
                        )
                    )

                if ctx.params['console']:
                    console = Console(app_)
                    console.start()

                # wait for interrupt
                event = gevent.event.Event()
                gevent.signal(signal.SIGQUIT, event.set)
                gevent.signal(signal.SIGTERM, event.set)
                gevent.signal(signal.SIGINT, event.set)

                gevent.signal(signal.SIGUSR1, toogle_cpu_profiler)
                gevent.signal(signal.SIGUSR2, toggle_trace_profiler)

                event.wait()
                print('Signal received. Shutting down ...')
                try:
                    api_server.stop()
                except NameError:
                    pass
        except socket.error as v:
            if v.args[0] == errno.EADDRINUSE:
                print('ERROR: Address %s:%s is in use. '
                      'Use --listen-address <host:port> to specify port to listen on.' %
                      (listen_host, listen_port))
                sys.exit(1)
            raise
        app_.stop(leave_channels=False)
    else:
        # Pass parsed args on to subcommands.
        ctx.obj = kwargs
Example #25
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

    blockchain_service = BlockChainService(
        decode_hex(privatekey),
        decode_hex(registry_contract_address),
        host="127.0.0.1",
        port="8545",
    )

    discovery = ContractDiscovery(blockchain_service,
                                  decode_hex(discovery_contract_address))

    app = App(config, blockchain_service, discovery)

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

    app.raiden.register_registry(app.raiden.chain.default_registry)

    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 not our_node in nodes:
                continue

            # 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")

            while not all(
                    tools.ping(node) for node in nodes if node != our_node):
                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]

                channel_manager = 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))
                        app.raiden.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))
                        channel = app.raiden.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):
                    app.raiden.api.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()
Example #26
0
def smoketest(ctx, debug, **kwargs):
    """ Test, that the raiden installation is sane.
    """
    from raiden.api.python import RaidenAPI
    from raiden.blockchain.abi import get_static_or_compile
    from raiden.utils import get_contract_path

    # Check the solidity compiler early in the smoketest.
    #
    # Binary distributions don't need the solidity compiler but source
    # distributions do. Since this is checked by `get_static_or_compile`
    # function, use it as a proxy for validating the setup.
    get_static_or_compile(
        get_contract_path('HumanStandardToken.sol'),
        'HumanStandardToken',
    )

    report_file = tempfile.mktemp(suffix='.log')
    open(report_file, 'w+')

    def append_report(subject, data):
        with open(report_file, 'a', encoding='UTF-8') as handler:
            handler.write('{:=^80}'.format(' %s ' % subject.upper()) +
                          os.linesep)
            if data is not None:
                if isinstance(data, bytes):
                    data = data.decode()
                handler.writelines([data + os.linesep])

    append_report('raiden version', json.dumps(get_system_spec()))
    append_report('raiden log', None)

    print('[1/5] getting smoketest configuration')
    smoketest_config = load_or_create_smoketest_config()

    print('[2/5] starting ethereum')
    ethereum, ethereum_config = start_ethereum(smoketest_config['genesis'])

    print('[3/5] starting raiden')

    # setup logging to log only into our report file
    slogging.configure(':DEBUG', log_file=report_file)
    root = slogging.getLogger()
    for handler in root.handlers:
        if isinstance(handler, slogging.logging.StreamHandler):
            root.handlers.remove(handler)
            break
    # setup cli arguments for starting raiden
    args = dict(
        discovery_contract_address=smoketest_config['contracts']
        ['discovery_address'],
        registry_contract_address=smoketest_config['contracts']
        ['registry_address'],
        eth_rpc_endpoint='http://127.0.0.1:{}'.format(ethereum_config['rpc']),
        keystore_path=ethereum_config['keystore'],
        address=ethereum_config['address'],
    )
    for option in app.params:
        if option.name in args.keys():
            args[option.name] = option.process_value(ctx, args[option.name])
        else:
            args[option.name] = option.default

    password_file = os.path.join(args['keystore_path'], 'password')
    with open(password_file, 'w') as handler:
        handler.write('password')

    args['mapped_socket'] = None
    args['password_file'] = click.File()(password_file)
    args['datadir'] = args['keystore_path']
    args['api_address'] = 'localhost:' + str(
        next(get_free_port('127.0.0.1', 5001)))
    args['sync_check'] = False

    # invoke the raiden app
    app_ = ctx.invoke(app, **args)

    raiden_api = RaidenAPI(app_.raiden)
    rest_api = RestAPI(raiden_api)
    api_server = APIServer(rest_api)
    (api_host, api_port) = split_endpoint(args['api_address'])
    api_server.start(api_host, api_port)

    success = False
    try:
        print('[4/5] running smoketests...')
        error = run_smoketests(app_.raiden, smoketest_config, debug=debug)
        if error is not None:
            append_report('smoketest assertion error', error)
        else:
            success = True
    finally:
        app_.stop()
        ethereum.send_signal(2)

        err, out = ethereum.communicate()
        append_report('geth init stdout',
                      ethereum_config['init_log_out'].decode('utf-8'))
        append_report('geth init stderr',
                      ethereum_config['init_log_err'].decode('utf-8'))
        append_report('ethereum stdout', out)
        append_report('ethereum stderr', err)
        append_report('smoketest configuration', json.dumps(smoketest_config))
    if success:
        print('[5/5] smoketest successful, report was written to {}'.format(
            report_file))
    else:
        print('[5/5] smoketest had errors, report was written to {}'.format(
            report_file))
        sys.exit(1)
Example #27
0
def app(address, keystore_path, gas_price, 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.blockchain_service 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 = hexlify(privatekey_bin)
    config['privatekey_hex'] = privatekey_hex

    endpoint = eth_rpc_endpoint

    # Fallback to 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,
        gas_price,
    )

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

    blockchain_service = BlockChainService(
        privatekey_bin,
        rpc_client,
        gas_price,
    )

    if sync_check:
        check_synced(blockchain_service)

    discovery_tx_cost = rpc_client.gasprice() * DISCOVERY_TX_GAS_LIMIT
    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 into this account.'.format(
                  discovery_tx_cost / denoms.ether, balance / 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,
    )
Example #28
0
    def _run_smoketest():
        print_step('Starting Raiden')

        config = deepcopy(App.DEFAULT_CONFIG)
        if args.get('extra_config', dict()):
            merge_dict(config, args['extra_config'])
            del args['extra_config']
        args['config'] = config

        raiden_stdout = StringIO()
        with contextlib.redirect_stdout(raiden_stdout):
            try:
                # invoke the raiden app
                app = run_app(**args)

                raiden_api = RaidenAPI(app.raiden)
                rest_api = RestAPI(raiden_api)
                api_server = APIServer(rest_api)
                (api_host, api_port) = split_endpoint(args['api_address'])
                api_server.start(api_host, api_port)

                raiden_api.channel_open(
                    registry_address=contract_addresses[CONTRACT_TOKEN_NETWORK_REGISTRY],
                    token_address=to_canonical_address(token.contract.address),
                    partner_address=to_canonical_address(TEST_PARTNER_ADDRESS),
                )
                raiden_api.set_total_channel_deposit(
                    contract_addresses[CONTRACT_TOKEN_NETWORK_REGISTRY],
                    to_canonical_address(token.contract.address),
                    to_canonical_address(TEST_PARTNER_ADDRESS),
                    TEST_DEPOSIT_AMOUNT,
                )
                token_addresses = [to_checksum_address(token.contract.address)]

                success = False
                print_step('Running smoketest')
                error = run_smoketests(
                    app.raiden,
                    args['transport'],
                    token_addresses,
                    contract_addresses[CONTRACT_ENDPOINT_REGISTRY],
                    debug=debug,
                )
                if error is not None:
                    append_report('Smoketest assertion error', error)
                else:
                    success = True
            finally:
                app.stop()
                app.raiden.get()
                node = ethereum[0]
                node.send_signal(2)
                err, out = node.communicate()

                append_report('Ethereum stdout', out)
                append_report('Ethereum stderr', err)
        append_report('Raiden Node stdout', raiden_stdout.getvalue())
        if success:
            print_step(f'Smoketest successful')
        else:
            print_step(f'Smoketest had errors', error=True)
        return success
Example #29
0
def run_app(
    address,
    keystore_path,
    gas_price,
    eth_rpc_endpoint,
    tokennetwork_registry_contract_address,
    secret_registry_contract_address,
    endpoint_registry_contract_address,
    listen_address,
    mapped_socket,
    max_unresponsive_time,
    api_address,
    rpc,
    sync_check,
    console,
    password_file,
    web_ui,
    datadir,
    transport,
    matrix_server,
    network_id,
    environment_type,
    unrecoverable_error_should_crash,
    pathfinding_service_address,
    config=None,
    extra_config=None,
    **kwargs,
):
    # pylint: disable=too-many-locals,too-many-branches,too-many-statements,unused-argument

    from raiden.app import App

    _assert_sql_version()

    if transport == 'udp' and not mapped_socket:
        raise RuntimeError('Missing socket')

    if datadir is None:
        datadir = os.path.join(os.path.expanduser('~'), '.raiden')

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

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

    config['transport']['udp']['host'] = listen_host
    config['transport']['udp']['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['transport']['udp']['external_ip'] = mapped_socket.external_ip
        config['transport']['udp'][
            'external_port'] = mapped_socket.external_port
    config['transport_type'] = transport
    config['transport']['matrix']['server'] = matrix_server
    config['transport']['udp'][
        'nat_keepalive_retries'] = DEFAULT_NAT_KEEPALIVE_RETRIES
    timeout = max_unresponsive_time / DEFAULT_NAT_KEEPALIVE_RETRIES
    config['transport']['udp']['nat_keepalive_timeout'] = timeout
    config['privatekey_hex'] = encode_hex(privatekey_bin)
    config[
        'unrecoverable_error_should_crash'] = unrecoverable_error_should_crash
    config['services'][
        'pathfinding_service_address'] = pathfinding_service_address

    parsed_eth_rpc_endpoint = urlparse(eth_rpc_endpoint)
    if not parsed_eth_rpc_endpoint.scheme:
        eth_rpc_endpoint = f'http://{eth_rpc_endpoint}'

    web3 = _setup_web3(eth_rpc_endpoint)

    rpc_client = JSONRPCClient(
        web3,
        privatekey_bin,
        gas_price_strategy=gas_price,
        block_num_confirmations=DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS,
        uses_infura='infura.io' in eth_rpc_endpoint,
    )

    blockchain_service = BlockChainService(
        privatekey_bin=privatekey_bin,
        jsonrpc_client=rpc_client,
        # Not giving the contract manager here, but injecting it later
        # since we first need blockchain service to calculate the network id
    )

    given_network_id = network_id
    node_network_id = blockchain_service.network_id
    known_given_network_id = given_network_id in ID_TO_NETWORKNAME
    known_node_network_id = node_network_id in ID_TO_NETWORKNAME

    if node_network_id != given_network_id:
        if known_given_network_id and known_node_network_id:
            click.secho(
                f"The chosen ethereum network '{ID_TO_NETWORKNAME[given_network_id]}' "
                f"differs from the ethereum client '{ID_TO_NETWORKNAME[node_network_id]}'. "
                "Please update your settings.",
                fg='red',
            )
        else:
            click.secho(
                f"The chosen ethereum network id '{given_network_id}' differs "
                f"from the ethereum client '{node_network_id}'. "
                "Please update your settings.",
                fg='red',
            )
        sys.exit(1)

    config['chain_id'] = given_network_id

    # interpret the provided string argument
    if environment_type == Environment.PRODUCTION:
        # Safe configuration: restrictions for mainnet apply and matrix rooms have to be private
        config['environment_type'] = Environment.PRODUCTION
        config['transport']['matrix']['private_rooms'] = True
    else:
        config['environment_type'] = Environment.DEVELOPMENT

    environment_type = config['environment_type']
    print(f'Raiden is running in {environment_type.value.lower()} mode')

    chain_config = {}
    contract_addresses_known = False
    contracts = dict()
    contracts_version = 'pre_limits' if environment_type == Environment.DEVELOPMENT else None
    config['contracts_path'] = contracts_precompiled_path(contracts_version)
    if node_network_id in ID_TO_NETWORKNAME and ID_TO_NETWORKNAME[
            node_network_id] != 'smoketest':
        deployment_data = get_contracts_deployed(node_network_id,
                                                 contracts_version)
        not_allowed = (  # for now we only disallow mainnet with test configuration
            network_id == 1 and environment_type == Environment.DEVELOPMENT)
        if not_allowed:
            click.secho(
                f'The chosen network ({ID_TO_NETWORKNAME[node_network_id]}) is not a testnet, '
                'but the "development" environment was selected.\n'
                'This is not allowed. Please start again with a safe environment setting '
                '(--environment production).',
                fg='red',
            )
            sys.exit(1)

        contracts = deployment_data['contracts']
        contract_addresses_known = True

    blockchain_service.inject_contract_manager(
        ContractManager(config['contracts_path']))

    if sync_check:
        check_synced(blockchain_service, known_node_network_id)

    contract_addresses_given = (
        tokennetwork_registry_contract_address is not None
        and secret_registry_contract_address is not None
        and endpoint_registry_contract_address is not None)

    if not contract_addresses_given and not contract_addresses_known:
        click.secho(
            f"There are no known contract addresses for network id '{given_network_id}'. "
            "Please provide them on the command line or in the configuration file.",
            fg='red',
        )
        sys.exit(1)

    try:
        token_network_registry = blockchain_service.token_network_registry(
            tokennetwork_registry_contract_address or to_canonical_address(
                contracts[CONTRACT_TOKEN_NETWORK_REGISTRY]['address'], ), )
    except ContractVersionMismatch as e:
        handle_contract_version_mismatch(e)
    except AddressWithoutCode:
        handle_contract_no_code('token network registry',
                                tokennetwork_registry_contract_address)
    except AddressWrongContract:
        handle_contract_wrong_address(
            'token network registry',
            tokennetwork_registry_contract_address,
        )

    try:
        secret_registry = blockchain_service.secret_registry(
            secret_registry_contract_address or to_canonical_address(
                contracts[CONTRACT_SECRET_REGISTRY]['address'], ), )
    except ContractVersionMismatch as e:
        handle_contract_version_mismatch(e)
    except AddressWithoutCode:
        handle_contract_no_code('secret registry',
                                secret_registry_contract_address)
    except AddressWrongContract:
        handle_contract_wrong_address('secret registry',
                                      secret_registry_contract_address)

    database_path = os.path.join(
        datadir,
        f'node_{pex(address)}',
        f'netid_{given_network_id}',
        f'network_{pex(token_network_registry.address)}',
        f'v{RAIDEN_DB_VERSION}_log.db',
    )
    config['database_path'] = database_path

    print(
        '\nYou are connected to the \'{}\' network and the DB path is: {}'.
        format(
            ID_TO_NETWORKNAME.get(given_network_id, given_network_id),
            database_path,
        ), )

    discovery = None
    if transport == 'udp':
        transport, discovery = _setup_udp(
            config,
            blockchain_service,
            address,
            contracts,
            endpoint_registry_contract_address,
        )
    elif transport == 'matrix':
        transport = _setup_matrix(config)
    else:
        raise RuntimeError(f'Unknown transport type "{transport}" given')

    raiden_event_handler = RaidenEventHandler()
    message_handler = MessageHandler()

    try:
        if 'contracts' in chain_config:
            start_block = chain_config['contracts']['TokenNetworkRegistry'][
                'block_number']
        else:
            start_block = 0

        raiden_app = App(
            config=config,
            chain=blockchain_service,
            query_start_block=start_block,
            default_registry=token_network_registry,
            default_secret_registry=secret_registry,
            transport=transport,
            raiden_event_handler=raiden_event_handler,
            message_handler=message_handler,
            discovery=discovery,
        )
    except RaidenError as e:
        click.secho(f'FATAL: {e}', fg='red')
        sys.exit(1)

    try:
        raiden_app.start()
    except RuntimeError as e:
        click.secho(f'FATAL: {e}', fg='red')
        sys.exit(1)
    except filelock.Timeout:
        name_or_id = ID_TO_NETWORKNAME.get(given_network_id, given_network_id)
        click.secho(
            f'FATAL: Another Raiden instance already running for account {address_hex} on '
            f'network id {name_or_id}',
            fg='red',
        )
        sys.exit(1)

    return raiden_app
Example #30
0
def app(
        address,
        keystore_path,
        gas_price,
        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.blockchain_service 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 = hexlify(privatekey_bin)
    config['privatekey_hex'] = privatekey_hex

    endpoint = eth_rpc_endpoint

    # Fallback to 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
    if not check_json_rpc(rpc_client):
        sys.exit(1)

    blockchain_service = BlockChainService(
        privatekey_bin,
        rpc_client,
        GAS_LIMIT,
        gas_price,
    )

    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 into this account.'
            .format(discovery_tx_cost / denoms.ether, balance / 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,
    )
Example #31
0
    def _run_app():
        # this catches exceptions raised when waiting for the stalecheck to complete
        try:
            app_ = ctx.invoke(app, **kwargs)
        except EthNodeCommunicationError:
            print(
                '\n'
                'Could not contact the ethereum node through JSON-RPC.\n'
                'Please make sure that JSON-RPC is enabled for these interfaces:\n'
                '\n'
                '    eth_*, net_*, web3_*\n'
                '\n'
                'geth: https://github.com/ethereum/go-ethereum/wiki/Management-APIs\n',
            )
            sys.exit(1)

        domain_list = []
        if kwargs['rpccorsdomain']:
            if ',' in kwargs['rpccorsdomain']:
                for domain in kwargs['rpccorsdomain'].split(','):
                    domain_list.append(str(domain))
            else:
                domain_list.append(str(kwargs['rpccorsdomain']))

        api_server = None
        if ctx.params['rpc']:
            raiden_api = RaidenAPI(app_.raiden)
            rest_api = RestAPI(raiden_api)
            api_server = APIServer(
                rest_api,
                cors_domain_list=domain_list,
                web_ui=ctx.params['web_ui'],
                eth_rpc_endpoint=ctx.params['eth_rpc_endpoint'],
            )
            (api_host, api_port) = split_endpoint(kwargs['api_address'])

            try:
                api_server.start(api_host, api_port)
            except APIServerPortInUseError:
                print(
                    'ERROR: API Address %s:%s is in use. '
                    'Use --api-address <host:port> to specify port to listen on.' %
                    (api_host, api_port),
                )
                sys.exit(1)

            print(
                'The Raiden API RPC server is now running at http://{}:{}/.\n\n'
                'See the Raiden documentation for all available endpoints at\n'
                'http://raiden-network.readthedocs.io/en/stable/rest_api.html'.format(
                    api_host,
                    api_port,
                ),
            )

        if ctx.params['console']:
            console = Console(app_)
            console.start()

        # spawning a thread to handle the version checking
        gevent.spawn(check_version)

        # wait for interrupt
        event = gevent.event.Event()
        gevent.signal(signal.SIGQUIT, event.set)
        gevent.signal(signal.SIGTERM, event.set)
        gevent.signal(signal.SIGINT, event.set)

        try:
            event.wait()
            print('Signal received. Shutting down ...')
        except RaidenError as ex:
            click.secho(f'FATAL: {ex}', fg='red')
        except Exception as ex:
            with NamedTemporaryFile(
                'w',
                prefix='raiden-exception',
                suffix='.txt',
                delete=False,
            ) as traceback_file:
                traceback.print_exc(file=traceback_file)
                click.secho(
                    f'FATAL: An unexpected exception occured.'
                    f'A traceback has been written to {traceback_file.name}\n'
                    f'{ex}',
                    fg='red',
                )

        if api_server:
            api_server.stop()

        return app_
Example #32
0
def app(address,
        keystore_path,
        eth_rpc_endpoint,
        registry_contract_address,
        discovery_contract_address,
        listen_address,
        logging,
        logfile,
        max_unresponsive_time,
        send_ping_time):

    slogging.configure(logging, log_file=logfile)

    # config_file = args.config_file
    (listen_host, listen_port) = split_endpoint(listen_address)

    config = App.default_config.copy()
    config['host'] = listen_host
    config['port'] = listen_port
    config['max_unresponsive_time'] = max_unresponsive_time
    config['send_ping_time'] = send_ping_time

    accmgr = AccountManager(keystore_path)
    if not accmgr.accounts:
        raise RuntimeError('No Ethereum accounts found in the user\'s system')

    if not accmgr.address_in_keystore(address):
        addresses = list(accmgr.accounts.keys())
        formatted_addresses = [
            '[{:3d}] - 0x{}'.format(idx, addr)
            for idx, addr in enumerate(addresses)
        ]

        should_prompt = True
        while should_prompt:
            idx = click.prompt(
                "The following accounts were found in your machine:\n\n{}"
                "\nSelect one of them by index to continue: ".format(
                    "\n".join(formatted_addresses)),
                type=int
            )
            if idx >= 0 and idx < len(addresses):
                should_prompt = False
            else:
                print("\nError: Provided index '{}' is out of bounds\n".format(idx))

        address = addresses[idx]

    privatekey = accmgr.get_privkey(address)
    config['privatekey_hex'] = encode_hex(privatekey)

    endpoint = eth_rpc_endpoint

    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)

    blockchain_service = BlockChainService(
        privatekey,
        decode_hex(registry_contract_address),
        host=rpc_host,
        port=rpc_port,
    )

    discovery = ContractDiscovery(
        blockchain_service,
        decode_hex(discovery_contract_address)  # FIXME: double encoding
    )

    return App(config, blockchain_service, discovery)
Example #33
0
def run(
        privatekey,
        registry_contract_address,
        secret_registry_contract_address,
        discovery_contract_address,
        listen_address,
        structlog,
        logfile,
        scenario,
        stage_prefix,
):  # pylint: disable=unused-argument

    # TODO: only enabled structlog on "initiators"
    structlog.configure(structlog, 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.token_network_registry(
        registry_contract_address,
    )

    secret_registry = blockchain_service.secret_registry(
        secret_registry_contract_address,
    )

    throttle_policy = TokenBucket(
        config['protocol']['throttle_capacity'],
        config['protocol']['throttle_fill_rate'],
    )

    transport = UDPTransport(
        discovery=discovery,
        udpsocket=gevent.server._udp_socket((listen_host, listen_port)),
        throttle_policy=throttle_policy,
        config=config['protocol'],
    )

    app = App(
        config=config,
        chain=blockchain_service,
        query_start_block=0,
        default_registry=registry,
        default_secret_registry=secret_registry,
        transport=transport,
        discovery=discovery,
    )

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

    from_block = 0
    app.raiden.install_all_blockchain_filters(
        app.raiden.default_registry,
        app.raiden.default_secret_registry,
        from_block,
    )

    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 = hexlify(app.raiden.address)
        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(registry_contract_address)

            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.token_network_register(app.raiden.default_registry.address, 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.channel_open(app.raiden.default_registry.address, 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.channel_deposit(
                            app.raiden.default_registry.address,
                            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)

        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 range(total_transfers):
                    RaidenAPI(app.raiden).transfer(
                        app.raiden.default_registry.address,
                        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()

        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()
Example #34
0
def app(address,
        keystore_path,
        eth_rpc_endpoint,
        registry_contract_address,
        discovery_contract_address,
        listen_address,
        rpccorsdomain,  # pylint: disable=unused-argument
        mapped_socket,
        logging,
        logfile,
        log_json,
        max_unresponsive_time,
        send_ping_time,
        api_address,
        rpc,
        console,
        password_file,
        web_ui,
        datadir):

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

    # config_file = args.config_file
    (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

    retries = max_unresponsive_time / DEFAULT_NAT_KEEPALIVE_RETRIES
    config['protocol']['nat_keepalive_retries'] = retries
    config['protocol']['nat_keepalive_timeout'] = send_ping_time

    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)

    try:
        blockchain_service = BlockChainService(
            privatekey_bin,
            registry_contract_address,
            host=rpc_host,
            port=rpc_port,
        )
    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)

    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)

    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, discovery)
Example #35
0
def run(ctx, **kwargs):
    if ctx.invoked_subcommand is None:
        from raiden.api.python import RaidenAPI
        from raiden.ui.console import Console

        slogging.configure(
            kwargs['logging'],
            log_json=kwargs['log_json'],
            log_file=kwargs['logfile']
        )

        # TODO:
        # - Ask for confirmation to quit if there are any locked transfers that did
        # not timeout.
        (listen_host, listen_port) = split_endpoint(kwargs['listen_address'])
        try:
            with socket_factory(listen_host, listen_port) as mapped_socket:
                kwargs['mapped_socket'] = mapped_socket

                app_ = ctx.invoke(app, **kwargs)

                domain_list = []
                if kwargs['rpccorsdomain']:
                    if ',' in kwargs['rpccorsdomain']:
                        for domain in kwargs['rpccorsdomain'].split(','):
                            domain_list.append(str(domain))
                    else:
                        domain_list.append(str(kwargs['rpccorsdomain']))

                if ctx.params['rpc']:
                    raiden_api = RaidenAPI(app_.raiden)
                    rest_api = RestAPI(raiden_api)
                    api_server = APIServer(
                        rest_api,
                        cors_domain_list=domain_list,
                        web_ui=ctx.params['web_ui'],
                    )
                    (api_host, api_port) = split_endpoint(kwargs["api_address"])
                    api_server.start(api_host, api_port)

                    print(
                        "The Raiden API RPC server is now running at http://{}:{}/.\n\n"
                        "See the Raiden documentation for all available endpoints at\n"
                        "https://github.com/raiden-network/raiden/blob/master"
                        "/docs/Rest-Api.rst".format(
                            api_host,
                            api_port,
                        )
                    )

                if ctx.params['console']:
                    console = Console(app_)
                    console.start()

                # wait for interrupt
                event = gevent.event.Event()
                gevent.signal(signal.SIGQUIT, event.set)
                gevent.signal(signal.SIGTERM, event.set)
                gevent.signal(signal.SIGINT, event.set)

                gevent.signal(signal.SIGUSR1, toogle_cpu_profiler)
                gevent.signal(signal.SIGUSR2, toggle_trace_profiler)

                event.wait()

                try:
                    api_server.stop()
                except NameError:
                    pass
        except socket.error as v:
            if v.args[0] == errno.EADDRINUSE:
                print("ERROR: Address %s:%s is in use. "
                      "Use --listen-address <host:port> to specify port to listen on." %
                      (listen_host, listen_port))
                sys.exit(1)
            raise
        app_.stop(leave_channels=False)
    else:
        # Pass parsed args on to subcommands.
        ctx.obj = kwargs
Example #36
0
def run(ctx, **kwargs):
    # pylint: disable=too-many-locals,too-many-branches,too-many-statements

    if ctx.invoked_subcommand is not None:
        # Pass parsed args on to subcommands.
        ctx.obj = kwargs
        return

    click.secho('Welcome to Raiden, version {}!'.format(get_system_spec()['raiden']), fg='green')
    click.secho(
        '''
----------------------------------------------------------------------
| This is an Alpha version of experimental open source software      |
| released under the MIT license and may contain errors and/or bugs. |
| Use of the software is at your own risk and discretion. No         |
| guarantee whatsoever is made regarding its suitability for your    |
| intended purposes and its compliance with applicable law and       |
| regulations. It is up to the user to determine the software´s      |
| quality and suitability and whether its use is compliant with its  |
| respective regulatory regime, especially in the case that you are  |
| operating in a commercial context.                                 |
----------------------------------------------------------------------''',
        fg='yellow',
    )
    from raiden.ui.console import Console
    from raiden.api.python import RaidenAPI

    if kwargs['config_file']:
        paramname_to_param = {param.name: param for param in run.params}
        path_params = {
            param.name
            for param in run.params
            if isinstance(param.type, (click.Path, click.File))
        }

        config_file_path = Path(kwargs['config_file'])
        config_file_values = dict()
        try:
            with config_file_path.open() as config_file:
                config_file_values = pytoml.load(config_file)
        except OSError as ex:
            # Silently ignore if 'file not found' and the config file path is the default
            config_file_param = paramname_to_param['config_file']
            config_file_default_path = Path(
                config_file_param.type.expand_default(config_file_param.get_default(ctx), kwargs),
            )
            default_config_missing = (
                ex.errno == errno.ENOENT and
                config_file_path.resolve() == config_file_default_path.resolve()
            )
            if default_config_missing:
                kwargs['config_file'] = None
            else:
                click.secho(f"Error opening config file: {ex}", fg='red')
                sys.exit(2)
        except TomlError as ex:
            click.secho(f'Error loading config file: {ex}', fg='red')
            sys.exit(2)

        for config_name, config_value in config_file_values.items():
            config_name_int = config_name.replace('-', '_')

            if config_name_int not in paramname_to_param:
                click.secho(
                    f"Unknown setting '{config_name}' found in config file - ignoring.",
                    fg='yellow',
                )
                continue

            if config_name_int in path_params:
                # Allow users to use `~` in paths in the config file
                config_value = os.path.expanduser(config_value)

            if config_name_int == LOG_CONFIG_OPTION_NAME:
                # Uppercase log level names
                config_value = {k: v.upper() for k, v in config_value.items()}
            else:
                # Pipe config file values through cli converter to ensure correct types
                # We exclude `log-config` because it already is a dict when loading from toml
                try:
                    config_value = paramname_to_param[config_name_int].type.convert(
                        config_value,
                        paramname_to_param[config_name_int],
                        ctx,
                    )
                except click.BadParameter as ex:
                    click.secho(f"Invalid config file setting '{config_name}': {ex}", fg='red')
                    sys.exit(2)

            # Use the config file value if the value from the command line is the default
            if kwargs[config_name_int] == paramname_to_param[config_name_int].get_default(ctx):
                kwargs[config_name_int] = config_value

    configure_logging(
        kwargs['log_config'],
        log_json=kwargs['log_json'],
        log_file=kwargs['log_file'],
    )

    # Do this here so logging is configured
    if kwargs['config_file']:
        log.debug('Using config file', config_file=kwargs['config_file'])

    # TODO:
    # - Ask for confirmation to quit if there are any locked transfers that did
    # not timeout.

    def _run_app():
        # this catches exceptions raised when waiting for the stalecheck to complete
        try:
            app_ = ctx.invoke(app, **kwargs)
        except EthNodeCommunicationError:
            print(
                '\n'
                'Could not contact the ethereum node through JSON-RPC.\n'
                'Please make sure that JSON-RPC is enabled for these interfaces:\n'
                '\n'
                '    eth_*, net_*, web3_*\n'
                '\n'
                'geth: https://github.com/ethereum/go-ethereum/wiki/Management-APIs\n',
            )
            sys.exit(1)

        domain_list = []
        if kwargs['rpccorsdomain']:
            if ',' in kwargs['rpccorsdomain']:
                for domain in kwargs['rpccorsdomain'].split(','):
                    domain_list.append(str(domain))
            else:
                domain_list.append(str(kwargs['rpccorsdomain']))

        api_server = None
        if ctx.params['rpc']:
            raiden_api = RaidenAPI(app_.raiden)
            rest_api = RestAPI(raiden_api)
            api_server = APIServer(
                rest_api,
                cors_domain_list=domain_list,
                web_ui=ctx.params['web_ui'],
                eth_rpc_endpoint=ctx.params['eth_rpc_endpoint'],
            )
            (api_host, api_port) = split_endpoint(kwargs['api_address'])

            try:
                api_server.start(api_host, api_port)
            except APIServerPortInUseError:
                print(
                    'ERROR: API Address %s:%s is in use. '
                    'Use --api-address <host:port> to specify port to listen on.' %
                    (api_host, api_port),
                )
                sys.exit(1)

            print(
                'The Raiden API RPC server is now running at http://{}:{}/.\n\n'
                'See the Raiden documentation for all available endpoints at\n'
                'http://raiden-network.readthedocs.io/en/stable/rest_api.html'.format(
                    api_host,
                    api_port,
                ),
            )

        if ctx.params['console']:
            console = Console(app_)
            console.start()

        # spawning a thread to handle the version checking
        gevent.spawn(check_version)

        # wait for interrupt
        event = gevent.event.Event()
        gevent.signal(signal.SIGQUIT, event.set)
        gevent.signal(signal.SIGTERM, event.set)
        gevent.signal(signal.SIGINT, event.set)

        try:
            event.wait()
            print('Signal received. Shutting down ...')
        except RaidenError as ex:
            click.secho(f'FATAL: {ex}', fg='red')
        except Exception as ex:
            with NamedTemporaryFile(
                'w',
                prefix='raiden-exception',
                suffix='.txt',
                delete=False,
            ) as traceback_file:
                traceback.print_exc(file=traceback_file)
                click.secho(
                    f'FATAL: An unexpected exception occured.'
                    f'A traceback has been written to {traceback_file.name}\n'
                    f'{ex}',
                    fg='red',
                )

        if api_server:
            api_server.stop()

        return app_

    # TODO:
    # - Ask for confirmation to quit if there are any locked transfers that did
    # not timeout.
    try:
        if kwargs['transport'] == 'udp':
            (listen_host, listen_port) = split_endpoint(kwargs['listen_address'])
            try:
                with SocketFactory(
                        listen_host, listen_port, strategy=kwargs['nat'],
                ) as mapped_socket:
                    kwargs['mapped_socket'] = mapped_socket
                    app_ = _run_app()

            except RaidenServicePortInUseError:
                print(
                    'ERROR: Address %s:%s is in use. '
                    'Use --listen-address <host:port> to specify port to listen on.' %
                    (listen_host, listen_port),
                )
                sys.exit(1)
        elif kwargs['transport'] == 'matrix':
            kwargs['mapped_socket'] = None
            app_ = _run_app()
        else:
            # Shouldn't happen
            raise RuntimeError(f"Invalid transport type '{kwargs['transport']}'")
        app_.stop(leave_channels=False)
    except ReplacementTransactionUnderpriced as e:
        print(
            '{}. Please make sure that this Raiden node is the '
            'only user of the selected account'.format(str(e)),
        )
        sys.exit(1)
Example #37
0
 def get(self, node_address):
     endpoint = self.discovery_proxy.endpoint_by_address(node_address)
     host_port = split_endpoint(endpoint)
     return host_port
Example #38
0
def app(
        address,
        keystore_path,
        gas_price,
        eth_rpc_endpoint,
        registry_contract_address,
        secret_registry_contract_address,
        discovery_contract_address,
        listen_address,
        rpccorsdomain,
        mapped_socket,
        log_config,
        log_file,
        log_json,
        max_unresponsive_time,
        send_ping_time,
        api_address,
        rpc,
        sync_check,
        console,
        password_file,
        web_ui,
        datadir,
        nat,
        transport,
        matrix_server,
        network_id,
        config_file,
        extra_config=None,
):
    # pylint: disable=too-many-locals,too-many-branches,too-many-statements,unused-argument

    from raiden.app import App

    if transport == 'udp' and not mapped_socket:
        raise RuntimeError('Missing socket')

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

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

    if datadir is None:
        datadir = os.path.join(os.path.expanduser('~'), '.raiden')

    config = deepcopy(App.DEFAULT_CONFIG)
    if extra_config:
        merge_dict(config, extra_config)

    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
    config['transport_type'] = transport
    config['matrix']['server'] = matrix_server
    config['transport']['nat_keepalive_retries'] = DEFAULT_NAT_KEEPALIVE_RETRIES
    timeout = max_unresponsive_time / DEFAULT_NAT_KEEPALIVE_RETRIES
    config['transport']['nat_keepalive_timeout'] = timeout

    privatekey_hex = hexlify(privatekey_bin)
    config['privatekey_hex'] = privatekey_hex

    rpc_host, rpc_port = eth_endpoint_to_hostport(eth_rpc_endpoint)

    rpc_client = JSONRPCClient(
        rpc_host,
        rpc_port,
        privatekey_bin,
        gas_price,
    )

    blockchain_service = BlockChainService(privatekey_bin, rpc_client)

    net_id = blockchain_service.network_id
    if net_id != network_id:
        if network_id in constants.ID_TO_NETWORKNAME and net_id in constants.ID_TO_NETWORKNAME:
            print((
                "The chosen ethereum network '{}' differs from the ethereum client '{}'. "
                'Please update your settings.'
            ).format(constants.ID_TO_NETWORKNAME[network_id], constants.ID_TO_NETWORKNAME[net_id]))
        else:
            print((
                "The chosen ethereum network id '{}' differs from the ethereum client '{}'. "
                'Please update your settings.'
            ).format(network_id, net_id))
        sys.exit(1)

    config['chain_id'] = network_id

    if sync_check:
        check_synced(blockchain_service)

    database_path = os.path.join(datadir, 'netid_%s' % net_id, address_hex[:8], 'log.db')
    config['database_path'] = database_path
    print(
        '\nYou are connected to the \'{}\' network and the DB path is: {}'.format(
            constants.ID_TO_NETWORKNAME.get(net_id) or net_id,
            database_path,
        ),
    )

    try:
        token_network_registry = blockchain_service.token_network_registry(
            registry_contract_address,
        )
    except ContractVersionMismatch:
        print(
            'Deployed registry contract version mismatch. '
            'Please update your Raiden installation.',
        )
        sys.exit(1)

    try:
        secret_registry = blockchain_service.secret_registry(
            secret_registry_contract_address,
        )
    except ContractVersionMismatch:
        print(
            'Deployed secret registry contract version mismatch. '
            'Please update your Raiden installation.',
        )
        sys.exit(1)

    discovery = None
    if transport == 'udp':
        check_discovery_registration_gas(blockchain_service, address)
        try:
            discovery = ContractDiscovery(
                blockchain_service.node_address,
                blockchain_service.discovery(discovery_contract_address),
            )
        except ContractVersionMismatch:
            print('Deployed discovery contract version mismatch. '
                  'Please update your Raiden installation.')
            sys.exit(1)
        throttle_policy = TokenBucket(
            config['transport']['throttle_capacity'],
            config['transport']['throttle_fill_rate'],
        )

        transport = UDPTransport(
            discovery,
            mapped_socket.socket,
            throttle_policy,
            config['transport'],
        )
    elif transport == 'matrix':
        # matrix gets spammed with the default retry-interval of 1s, wait a little more
        if config['transport']['retry_interval'] == DEFAULT_TRANSPORT_RETRY_INTERVAL:
            config['transport']['retry_interval'] *= 5
        try:
            transport = MatrixTransport(config['matrix'])
        except RaidenError as ex:
            click.secho(f'FATAL: {ex}', fg='red')
            sys.exit(1)
    else:
        raise RuntimeError(f'Unknown transport type "{transport}" given')

    try:
        raiden_app = App(
            config=config,
            chain=blockchain_service,
            query_start_block=constants.ID_TO_QUERY_BLOCK[net_id],
            default_registry=token_network_registry,
            default_secret_registry=secret_registry,
            transport=transport,
            discovery=discovery,
        )
    except RaidenError as e:
        click.secho(f'FATAL: {e}', fg='red')
        sys.exit(1)

    return raiden_app
Example #39
0
def run_app(
    address,
    keystore_path,
    gas_price,
    eth_rpc_endpoint,
    tokennetwork_registry_contract_address,
    secret_registry_contract_address,
    service_registry_contract_address,
    endpoint_registry_contract_address,
    user_deposit_contract_address,
    listen_address,
    mapped_socket,
    max_unresponsive_time,
    api_address,
    rpc,
    sync_check,
    console,
    password_file,
    web_ui,
    datadir,
    transport,
    matrix_server,
    network_id,
    environment_type,
    unrecoverable_error_should_crash,
    pathfinding_service_address,
    pathfinding_eth_address,
    pathfinding_max_paths,
    enable_monitoring,
    resolver_endpoint,
    routing_mode,
    config=None,
    extra_config=None,
    **kwargs,
):
    # pylint: disable=too-many-locals,too-many-branches,too-many-statements,unused-argument

    from raiden.app import App

    check_sql_version()

    if transport == "udp" and not mapped_socket:
        raise RuntimeError("Missing socket")

    if datadir is None:
        datadir = os.path.join(os.path.expanduser("~"), ".raiden")

    account_manager = AccountManager(keystore_path)
    check_has_accounts(account_manager)

    if not address:
        address_hex = prompt_account(account_manager)
    else:
        address_hex = to_normalized_address(address)

    if password_file:
        privatekey_bin = unlock_account_with_passwordfile(
            account_manager=account_manager,
            address_hex=address_hex,
            password_file=password_file)
    else:
        privatekey_bin = unlock_account_with_passwordprompt(
            account_manager=account_manager, address_hex=address_hex)

    address = to_canonical_address(address_hex)

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

    config["transport"]["udp"]["host"] = listen_host
    config["transport"]["udp"]["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
    config["resolver_endpoint"] = resolver_endpoint
    if mapped_socket:
        config["socket"] = mapped_socket.socket
        config["transport"]["udp"]["external_ip"] = mapped_socket.external_ip
        config["transport"]["udp"][
            "external_port"] = mapped_socket.external_port
    config["transport_type"] = transport
    config["transport"]["matrix"]["server"] = matrix_server
    config["transport"]["udp"][
        "nat_keepalive_retries"] = DEFAULT_NAT_KEEPALIVE_RETRIES
    timeout = max_unresponsive_time / DEFAULT_NAT_KEEPALIVE_RETRIES
    config["transport"]["udp"]["nat_keepalive_timeout"] = timeout
    config[
        "unrecoverable_error_should_crash"] = unrecoverable_error_should_crash
    config["services"]["pathfinding_max_paths"] = pathfinding_max_paths
    config["services"]["monitoring_enabled"] = enable_monitoring

    parsed_eth_rpc_endpoint = urlparse(eth_rpc_endpoint)
    if not parsed_eth_rpc_endpoint.scheme:
        eth_rpc_endpoint = f"http://{eth_rpc_endpoint}"

    web3 = Web3(HTTPProvider(eth_rpc_endpoint))
    check_ethereum_version(web3)
    check_network_id(network_id, web3)
    config["chain_id"] = network_id

    setup_environment(config, environment_type)

    contracts = setup_contracts_or_exit(config, network_id)

    rpc_client = JSONRPCClient(
        web3,
        privatekey_bin,
        gas_price_strategy=gas_price,
        block_num_confirmations=DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS,
        uses_infura="infura.io" in eth_rpc_endpoint,
    )

    blockchain_service = BlockChainService(jsonrpc_client=rpc_client,
                                           contract_manager=ContractManager(
                                               config["contracts_path"]))

    if sync_check:
        check_synced(blockchain_service)

    proxies = setup_proxies_or_exit(
        config=config,
        tokennetwork_registry_contract_address=
        tokennetwork_registry_contract_address,
        secret_registry_contract_address=secret_registry_contract_address,
        endpoint_registry_contract_address=endpoint_registry_contract_address,
        user_deposit_contract_address=user_deposit_contract_address,
        service_registry_contract_address=service_registry_contract_address,
        blockchain_service=blockchain_service,
        contracts=contracts,
        routing_mode=routing_mode,
        pathfinding_service_address=pathfinding_service_address,
        pathfinding_eth_address=pathfinding_eth_address,
    )

    database_path = os.path.join(
        datadir,
        f"node_{pex(address)}",
        f"netid_{network_id}",
        f"network_{pex(proxies.token_network_registry.address)}",
        f"v{RAIDEN_DB_VERSION}_log.db",
    )
    config["database_path"] = database_path

    print("\nYou are connected to the '{}' network and the DB path is: {}".
          format(ID_TO_NETWORKNAME.get(network_id, network_id), database_path))

    discovery = None
    if transport == "udp":
        transport, discovery = setup_udp_or_exit(
            config, blockchain_service, address, contracts,
            endpoint_registry_contract_address)
    elif transport == "matrix":
        transport = _setup_matrix(config)
    else:
        raise RuntimeError(f'Unknown transport type "{transport}" given')

    raiden_event_handler = RaidenEventHandler()

    message_handler = MessageHandler()

    try:
        start_block = 0
        if "TokenNetworkRegistry" in contracts:
            start_block = contracts["TokenNetworkRegistry"]["block_number"]

        raiden_app = App(
            config=config,
            chain=blockchain_service,
            query_start_block=start_block,
            default_registry=proxies.token_network_registry,
            default_secret_registry=proxies.secret_registry,
            default_service_registry=proxies.service_registry,
            transport=transport,
            raiden_event_handler=raiden_event_handler,
            message_handler=message_handler,
            discovery=discovery,
            user_deposit=proxies.user_deposit,
        )
    except RaidenError as e:
        click.secho(f"FATAL: {e}", fg="red")
        sys.exit(1)

    try:
        raiden_app.start()
    except RuntimeError as e:
        click.secho(f"FATAL: {e}", fg="red")
        sys.exit(1)
    except filelock.Timeout:
        name_or_id = ID_TO_NETWORKNAME.get(network_id, network_id)
        click.secho(
            f"FATAL: Another Raiden instance already running for account {address_hex} on "
            f"network id {name_or_id}",
            fg="red",
        )
        sys.exit(1)

    return raiden_app
Example #40
0
    def _run_smoketest():
        print_step('Starting Raiden')

        # invoke the raiden app
        app_ = ctx.invoke(app, **args)

        raiden_api = RaidenAPI(app_.raiden)
        rest_api = RestAPI(raiden_api)
        api_server = APIServer(rest_api)
        (api_host, api_port) = split_endpoint(args['api_address'])
        api_server.start(api_host, api_port)

        raiden_api.channel_open(
            contract_addresses[CONTRACT_TOKEN_NETWORK_REGISTRY],
            to_canonical_address(token.contract.address),
            to_canonical_address(TEST_PARTNER_ADDRESS),
            None,
            None,
        )
        raiden_api.set_total_channel_deposit(
            contract_addresses[CONTRACT_TOKEN_NETWORK_REGISTRY],
            to_canonical_address(token.contract.address),
            to_canonical_address(TEST_PARTNER_ADDRESS),
            TEST_DEPOSIT_AMOUNT,
        )

        smoketest_config['contracts']['registry_address'] = to_checksum_address(
            contract_addresses[CONTRACT_TOKEN_NETWORK_REGISTRY],
        )
        smoketest_config['contracts']['secret_registry_address'] = to_checksum_address(
            contract_addresses[CONTRACT_SECRET_REGISTRY],
        )
        smoketest_config['contracts']['discovery_address'] = to_checksum_address(
            contract_addresses[CONTRACT_ENDPOINT_REGISTRY],
        )
        smoketest_config['contracts']['token_address'] = to_checksum_address(
            token.contract.address,
        )

        success = False
        try:
            print_step('Running smoketest')
            error = run_smoketests(app_.raiden, smoketest_config, debug=debug)
            if error is not None:
                append_report('Smoketest assertion error', error)
            else:
                success = True
        finally:
            app_.stop()
            ethereum.send_signal(2)

            err, out = ethereum.communicate()
            append_report('Ethereum init stdout', ethereum_config['init_log_out'].decode('utf-8'))
            append_report('Ethereum init stderr', ethereum_config['init_log_err'].decode('utf-8'))
            append_report('Ethereum stdout', out)
            append_report('Ethereum stderr', err)
            append_report('Smoketest configuration', json.dumps(smoketest_config))
        if success:
            print_step(f'Smoketest successful, report was written to {report_file}')
        else:
            print_step(f'Smoketest had errors, report was written to {report_file}', error=True)
        return success
Example #41
0
def run(ctx, **kwargs):
    # pylint: disable=too-many-locals,too-many-branches,too-many-statements

    if ctx.invoked_subcommand is None:
        print('Welcome to Raiden, version {}!'.format(
            get_system_spec()['raiden']))
        from raiden.ui.console import Console
        from raiden.api.python import RaidenAPI

        slogging.configure(kwargs['logging'],
                           log_json=kwargs['log_json'],
                           log_file=kwargs['logfile'])
        if kwargs['logfile']:
            # Disable stream logging
            root = slogging.getLogger()
            for handler in root.handlers:
                if isinstance(handler, slogging.logging.StreamHandler):
                    root.handlers.remove(handler)
                    break

        # TODO:
        # - Ask for confirmation to quit if there are any locked transfers that did
        # not timeout.
        (listen_host, listen_port) = split_endpoint(kwargs['listen_address'])
        try:
            with SocketFactory(listen_host,
                               listen_port,
                               strategy=kwargs['nat']) as mapped_socket:
                kwargs['mapped_socket'] = mapped_socket

                app_ = ctx.invoke(app, **kwargs)

                domain_list = []
                if kwargs['rpccorsdomain']:
                    if ',' in kwargs['rpccorsdomain']:
                        for domain in kwargs['rpccorsdomain'].split(','):
                            domain_list.append(str(domain))
                    else:
                        domain_list.append(str(kwargs['rpccorsdomain']))

                if ctx.params['rpc']:
                    raiden_api = RaidenAPI(app_.raiden)
                    rest_api = RestAPI(raiden_api)
                    api_server = APIServer(
                        rest_api,
                        cors_domain_list=domain_list,
                        web_ui=ctx.params['web_ui'],
                        eth_rpc_endpoint=ctx.params['eth_rpc_endpoint'],
                    )
                    (api_host,
                     api_port) = split_endpoint(kwargs['api_address'])
                    api_server.start(api_host, api_port)

                    print(
                        'The Raiden API RPC server is now running at http://{}:{}/.\n\n'
                        'See the Raiden documentation for all available endpoints at\n'
                        'http://raiden-network.readthedocs.io/en/stable/rest_api.html'
                        .format(
                            api_host,
                            api_port,
                        ))

                if ctx.params['console']:
                    console = Console(app_)
                    console.start()

                # wait for interrupt
                event = gevent.event.Event()
                gevent.signal(signal.SIGQUIT, event.set)
                gevent.signal(signal.SIGTERM, event.set)
                gevent.signal(signal.SIGINT, event.set)

                gevent.signal(signal.SIGUSR1, toogle_cpu_profiler)
                gevent.signal(signal.SIGUSR2, toggle_trace_profiler)

                event.wait()
                print('Signal received. Shutting down ...')
                try:
                    api_server.stop()
                except NameError:
                    pass
        except socket.error as v:
            if v.args[0] == errno.EADDRINUSE:
                print(
                    'ERROR: Address %s:%s is in use. '
                    'Use --listen-address <host:port> to specify port to listen on.'
                    % (listen_host, listen_port))
                sys.exit(1)
            raise
        app_.stop(leave_channels=False)
    else:
        # Pass parsed args on to subcommands.
        ctx.obj = kwargs
Example #42
0
def app(address, keystore_path, eth_rpc_endpoint, registry_contract_address,
        discovery_contract_address, listen_address, logging, logfile,
        max_unresponsive_time, send_ping_time):

    slogging.configure(logging, log_file=logfile)

    # config_file = args.config_file
    (listen_host, listen_port) = split_endpoint(listen_address)

    config = App.default_config.copy()
    config['host'] = listen_host
    config['port'] = listen_port
    config['max_unresponsive_time'] = max_unresponsive_time
    config['send_ping_time'] = send_ping_time

    accmgr = AccountManager(keystore_path)
    if not accmgr.accounts:
        raise RuntimeError('No Ethereum accounts found in the user\'s system')

    if not accmgr.address_in_keystore(address):
        addresses = list(accmgr.accounts.keys())
        formatted_addresses = [
            '[{:3d}] - 0x{}'.format(idx, addr)
            for idx, addr in enumerate(addresses)
        ]

        should_prompt = True
        while should_prompt:
            idx = click.prompt(
                "The following accounts were found in your machine:\n\n{}"
                "\nSelect one of them by index to continue: ".format(
                    "\n".join(formatted_addresses)),
                type=int)
            if idx >= 0 and idx < len(addresses):
                should_prompt = False
            else:
                print("\nError: Provided index '{}' is out of bounds\n".format(
                    idx))

        address = addresses[idx]

    privatekey = accmgr.get_privkey(address)
    config['privatekey_hex'] = encode_hex(privatekey)

    endpoint = eth_rpc_endpoint

    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)

    blockchain_service = BlockChainService(
        privatekey,
        decode_hex(registry_contract_address),
        host=rpc_host,
        port=rpc_port,
    )

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

    return App(config, blockchain_service, discovery)
Example #43
0
 def get(self, node_address: bytes):
     endpoint = self.discovery_proxy.endpoint_by_address(node_address)
     host_port = split_endpoint(endpoint)
     return host_port
Example #44
0
    def _start_services(self):
        from raiden.api.python import RaidenAPI

        config = deepcopy(App.DEFAULT_CONFIG)
        config["reveal_timeout"] = self._options["default_reveal_timeout"]
        config["settle_timeout"] = self._options["default_settle_timeout"]
        if self._options.get("extra_config", dict()):
            merge_dict(config, self._options["extra_config"])
            del self._options["extra_config"]
        self._options["config"] = config

        if self._options["showconfig"]:
            print("Configuration Dump:")
            dump_config(config)
            dump_cmd_options(self._options)
            dump_module("settings", settings)
            dump_module("constants", constants)

        # this catches exceptions raised when waiting for the stalecheck to complete
        try:
            app_ = run_app(**self._options)
        except (ConnectionError, ConnectTimeout, RequestsConnectionError):
            print(ETHEREUM_NODE_COMMUNICATION_ERROR)
            sys.exit(1)
        except RuntimeError as e:
            click.secho(str(e), fg="red")
            sys.exit(1)
        except EthNodeInterfaceError as e:
            click.secho(str(e), fg="red")
            sys.exit(1)

        tasks = [app_.raiden]  # RaidenService takes care of Transport and AlarmTask

        domain_list = []
        if self._options["rpccorsdomain"]:
            if "," in self._options["rpccorsdomain"]:
                for domain in self._options["rpccorsdomain"].split(","):
                    domain_list.append(str(domain))
            else:
                domain_list.append(str(self._options["rpccorsdomain"]))

        self._raiden_api = RaidenAPI(app_.raiden)

        if self._options["rpc"]:
            rest_api = RestAPI(self._raiden_api)
            (api_host, api_port) = split_endpoint(self._options["api_address"])

            if not api_port:
                api_port = Port(settings.DEFAULT_HTTP_SERVER_PORT)

            api_server = APIServer(
                rest_api,
                config={"host": api_host, "port": api_port},
                cors_domain_list=domain_list,
                web_ui=self._options["web_ui"],
                eth_rpc_endpoint=self._options["eth_rpc_endpoint"],
            )

            try:
                api_server.start()
            except APIServerPortInUseError:
                click.secho(
                    f"ERROR: API Address {api_host}:{api_port} is in use. "
                    f"Use --api-address <host:port> to specify a different port.",
                    fg="red",
                )
                sys.exit(1)

            print(
                "The Raiden API RPC server is now running at http://{}:{}/.\n\n"
                "See the Raiden documentation for all available endpoints at\n"
                "http://raiden-network.readthedocs.io/en/stable/rest_api.html".format(
                    api_host, api_port
                )
            )
            tasks.append(api_server)

        if self._options["console"]:
            from raiden.ui.console import Console

            console = Console(app_)
            console.start()
            tasks.append(console)

        # spawn a greenlet to handle the version checking
        version = get_system_spec()["raiden"]
        tasks.append(gevent.spawn(check_version, version))

        # spawn a greenlet to handle the gas reserve check
        tasks.append(gevent.spawn(check_gas_reserve, app_.raiden))
        # spawn a greenlet to handle the periodic check for the network id
        tasks.append(
            gevent.spawn(
                check_network_id, app_.raiden.rpc_client.chain_id, app_.raiden.rpc_client.web3
            )
        )

        spawn_user_deposit_task = app_.user_deposit and (
            self._options["pathfinding_service_address"] or self._options["enable_monitoring"]
        )
        if spawn_user_deposit_task:
            # spawn a greenlet to handle RDN deposits check
            tasks.append(gevent.spawn(check_rdn_deposits, app_.raiden, app_.user_deposit))

        # spawn a greenlet to handle the functions

        self._startup_hook()

        # wait for interrupt
        event: "AsyncResult[None]" = AsyncResult()

        def sig_set(sig=None, _frame=None):
            event.set(sig)

        gevent.signal(signal.SIGQUIT, sig_set)
        gevent.signal(signal.SIGTERM, sig_set)
        gevent.signal(signal.SIGINT, sig_set)

        # quit if any task exits, successfully or not
        for task in tasks:
            task.link(event)

        try:
            event.get()
            print("Signal received. Shutting down ...")
        except (ConnectionError, ConnectTimeout, RequestsConnectionError):
            print(ETHEREUM_NODE_COMMUNICATION_ERROR)
            sys.exit(1)
        except RaidenError as ex:
            click.secho(f"FATAL: {ex}", fg="red")
        except Exception as ex:
            file = NamedTemporaryFile(
                "w",
                prefix=f"raiden-exception-{datetime.utcnow():%Y-%m-%dT%H-%M}",
                suffix=".txt",
                delete=False,
            )
            with file as traceback_file:
                traceback.print_exc(file=traceback_file)
                click.secho(
                    f"FATAL: An unexpected exception occured. "
                    f"A traceback has been written to {traceback_file.name}\n"
                    f"{ex}",
                    fg="red",
                )
        finally:
            self._shutdown_hook()

            app_.stop()

            def stop_task(task):
                try:
                    if isinstance(task, Runnable):
                        task.stop()
                    else:
                        task.kill()
                finally:
                    task.get()  # re-raise

            gevent.joinall(
                [gevent.spawn(stop_task, task) for task in tasks],
                app_.config.get("shutdown_timeout", settings.DEFAULT_SHUTDOWN_TIMEOUT),
                raise_error=True,
            )

        return app_
Example #45
0
def smoketest(ctx, debug, **kwargs):
    """ Test, that the raiden installation is sane.
    """
    from raiden.api.python import RaidenAPI
    from raiden.blockchain.abi import get_static_or_compile
    from raiden.utils import get_contract_path

    # Check the solidity compiler early in the smoketest.
    #
    # Binary distributions don't need the solidity compiler but source
    # distributions do. Since this is checked by `get_static_or_compile`
    # function, use it as a proxy for validating the setup.
    get_static_or_compile(
        get_contract_path('HumanStandardToken.sol'),
        'HumanStandardToken',
    )

    report_file = tempfile.mktemp(suffix='.log')
    open(report_file, 'w+')

    def append_report(subject, data):
        with open(report_file, 'a') as handler:
            handler.write('{:=^80}'.format(' %s ' % subject.upper()) + os.linesep)
            if data is not None:
                if isinstance(data, bytes):
                    data = data.decode()
                handler.writelines([data + os.linesep])

    append_report('raiden version', json.dumps(get_system_spec()))
    append_report('raiden log', None)

    print('[1/5] getting smoketest configuration')
    smoketest_config = load_or_create_smoketest_config()

    print('[2/5] starting ethereum')
    ethereum, ethereum_config = start_ethereum(smoketest_config['genesis'])

    print('[3/5] starting raiden')

    # setup logging to log only into our report file
    slogging.configure(':DEBUG', log_file=report_file)
    root = slogging.getLogger()
    for handler in root.handlers:
        if isinstance(handler, slogging.logging.StreamHandler):
            root.handlers.remove(handler)
            break
    # setup cli arguments for starting raiden
    args = dict(
        discovery_contract_address=smoketest_config['contracts']['discovery_address'],
        registry_contract_address=smoketest_config['contracts']['registry_address'],
        eth_rpc_endpoint='http://127.0.0.1:{}'.format(ethereum_config['rpc']),
        keystore_path=ethereum_config['keystore'],
        address=ethereum_config['address'],
    )
    for option in app.params:
        if option.name in args.keys():
            args[option.name] = option.process_value(ctx, args[option.name])
        else:
            args[option.name] = option.default

    password_file = os.path.join(args['keystore_path'], 'password')
    with open(password_file, 'w') as handler:
        handler.write('password')

    args['mapped_socket'] = None
    args['password_file'] = click.File()(password_file)
    args['datadir'] = args['keystore_path']
    args['api_address'] = 'localhost:' + str(next(get_free_port('127.0.0.1', 5001)))
    args['sync_check'] = False

    # invoke the raiden app
    app_ = ctx.invoke(app, **args)

    raiden_api = RaidenAPI(app_.raiden)
    rest_api = RestAPI(raiden_api)
    api_server = APIServer(rest_api)
    (api_host, api_port) = split_endpoint(args['api_address'])
    api_server.start(api_host, api_port)

    success = False
    try:
        print('[4/5] running smoketests...')
        error = run_smoketests(app_.raiden, smoketest_config, debug=debug)
        if error is not None:
            append_report('smoketest assertion error', error)
        else:
            success = True
    finally:
        app_.stop()
        ethereum.send_signal(2)

        err, out = ethereum.communicate()
        append_report('geth init stdout', ethereum_config['init_log_out'].decode('utf-8'))
        append_report('geth init stderr', ethereum_config['init_log_err'].decode('utf-8'))
        append_report('ethereum stdout', out)
        append_report('ethereum stderr', err)
        append_report('smoketest configuration', json.dumps(smoketest_config))
    if success:
        print('[5/5] smoketest successful, report was written to {}'.format(report_file))
    else:
        print('[5/5] smoketest had errors, report was written to {}'.format(report_file))
        sys.exit(1)
Example #46
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

    blockchain_service = BlockChainService(
        decode_hex(privatekey),
        decode_hex(registry_contract_address),
        host="127.0.0.1",
        port="8545",
    )

    discovery = ContractDiscovery(
        blockchain_service,
        decode_hex(discovery_contract_address)
    )

    app = App(config, blockchain_service, discovery)

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

    app.raiden.register_registry(app.raiden.chain.default_registry)

    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['assets']
        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/assets that we're not part of
            nodes = token['channels']
            if not our_node in nodes:
                continue

            # 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")

            while not all(tools.ping(node) for node in nodes if node != our_node):
                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]

                channel_manager = tools.register_asset(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))
                        app.raiden.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))
                        channel = app.raiden.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):
                    app.raiden.api.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()
Example #47
0
def run_app(
        address,
        keystore_path,
        gas_price,
        eth_rpc_endpoint,
        tokennetwork_registry_contract_address,
        secret_registry_contract_address,
        endpoint_registry_contract_address,
        listen_address,
        mapped_socket,
        max_unresponsive_time,
        api_address,
        rpc,
        sync_check,
        console,
        password_file,
        web_ui,
        datadir,
        transport,
        matrix_server,
        network_id,
        environment_type,
        unrecoverable_error_should_crash,
        pathfinding_service_address,
        pathfinding_max_paths,
        config=None,
        extra_config=None,
        **kwargs,
):
    # pylint: disable=too-many-locals,too-many-branches,too-many-statements,unused-argument

    from raiden.app import App

    _assert_sql_version()

    if transport == 'udp' and not mapped_socket:
        raise RuntimeError('Missing socket')

    if datadir is None:
        datadir = os.path.join(os.path.expanduser('~'), '.raiden')

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

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

    config['transport']['udp']['host'] = listen_host
    config['transport']['udp']['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['transport']['udp']['external_ip'] = mapped_socket.external_ip
        config['transport']['udp']['external_port'] = mapped_socket.external_port
    config['transport_type'] = transport
    config['transport']['matrix']['server'] = matrix_server
    config['transport']['udp']['nat_keepalive_retries'] = DEFAULT_NAT_KEEPALIVE_RETRIES
    timeout = max_unresponsive_time / DEFAULT_NAT_KEEPALIVE_RETRIES
    config['transport']['udp']['nat_keepalive_timeout'] = timeout
    config['privatekey_hex'] = encode_hex(privatekey_bin)
    config['unrecoverable_error_should_crash'] = unrecoverable_error_should_crash
    config['services']['pathfinding_service_address'] = pathfinding_service_address
    config['services']['pathfinding_max_paths'] = pathfinding_max_paths

    parsed_eth_rpc_endpoint = urlparse(eth_rpc_endpoint)
    if not parsed_eth_rpc_endpoint.scheme:
        eth_rpc_endpoint = f'http://{eth_rpc_endpoint}'

    web3 = _setup_web3(eth_rpc_endpoint)

    rpc_client = JSONRPCClient(
        web3,
        privatekey_bin,
        gas_price_strategy=gas_price,
        block_num_confirmations=DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS,
        uses_infura='infura.io' in eth_rpc_endpoint,
    )

    blockchain_service = BlockChainService(
        privatekey_bin=privatekey_bin,
        jsonrpc_client=rpc_client,
        # Not giving the contract manager here, but injecting it later
        # since we first need blockchain service to calculate the network id
    )

    given_network_id = network_id
    node_network_id = blockchain_service.network_id
    known_given_network_id = given_network_id in ID_TO_NETWORKNAME
    known_node_network_id = node_network_id in ID_TO_NETWORKNAME

    if node_network_id != given_network_id:
        if known_given_network_id and known_node_network_id:
            click.secho(
                f"The chosen ethereum network '{ID_TO_NETWORKNAME[given_network_id]}' "
                f"differs from the ethereum client '{ID_TO_NETWORKNAME[node_network_id]}'. "
                "Please update your settings.",
                fg='red',
            )
        else:
            click.secho(
                f"The chosen ethereum network id '{given_network_id}' differs "
                f"from the ethereum client '{node_network_id}'. "
                "Please update your settings.",
                fg='red',
            )
        sys.exit(1)

    config['chain_id'] = given_network_id

    # interpret the provided string argument
    if environment_type == Environment.PRODUCTION:
        # Safe configuration: restrictions for mainnet apply and matrix rooms have to be private
        config['environment_type'] = Environment.PRODUCTION
        config['transport']['matrix']['private_rooms'] = True
    else:
        config['environment_type'] = Environment.DEVELOPMENT

    environment_type = config['environment_type']
    print(f'Raiden is running in {environment_type.value.lower()} mode')

    chain_config = {}
    contract_addresses_known = False
    contracts = dict()
    contracts_version = 'pre_limits' if environment_type == Environment.DEVELOPMENT else None
    config['contracts_path'] = contracts_precompiled_path(contracts_version)
    if node_network_id in ID_TO_NETWORKNAME and ID_TO_NETWORKNAME[node_network_id] != 'smoketest':
        deployment_data = get_contracts_deployed(node_network_id, contracts_version)
        not_allowed = (  # for now we only disallow mainnet with test configuration
            network_id == 1 and
            environment_type == Environment.DEVELOPMENT
        )
        if not_allowed:
            click.secho(
                f'The chosen network ({ID_TO_NETWORKNAME[node_network_id]}) is not a testnet, '
                'but the "development" environment was selected.\n'
                'This is not allowed. Please start again with a safe environment setting '
                '(--environment production).',
                fg='red',
            )
            sys.exit(1)

        contracts = deployment_data['contracts']
        contract_addresses_known = True

    blockchain_service.inject_contract_manager(ContractManager(config['contracts_path']))

    if sync_check:
        check_synced(blockchain_service, known_node_network_id)

    contract_addresses_given = (
        tokennetwork_registry_contract_address is not None and
        secret_registry_contract_address is not None and
        endpoint_registry_contract_address is not None
    )

    if not contract_addresses_given and not contract_addresses_known:
        click.secho(
            f"There are no known contract addresses for network id '{given_network_id}'. "
            "Please provide them on the command line or in the configuration file.",
            fg='red',
        )
        sys.exit(1)

    try:
        token_network_registry = blockchain_service.token_network_registry(
            tokennetwork_registry_contract_address or to_canonical_address(
                contracts[CONTRACT_TOKEN_NETWORK_REGISTRY]['address'],
            ),
        )
    except ContractVersionMismatch as e:
        handle_contract_version_mismatch(e)
    except AddressWithoutCode:
        handle_contract_no_code('token network registry', tokennetwork_registry_contract_address)
    except AddressWrongContract:
        handle_contract_wrong_address(
            'token network registry',
            tokennetwork_registry_contract_address,
        )

    try:
        secret_registry = blockchain_service.secret_registry(
            secret_registry_contract_address or to_canonical_address(
                contracts[CONTRACT_SECRET_REGISTRY]['address'],
            ),
        )
    except ContractVersionMismatch as e:
        handle_contract_version_mismatch(e)
    except AddressWithoutCode:
        handle_contract_no_code('secret registry', secret_registry_contract_address)
    except AddressWrongContract:
        handle_contract_wrong_address('secret registry', secret_registry_contract_address)

    database_path = os.path.join(
        datadir,
        f'node_{pex(address)}',
        f'netid_{given_network_id}',
        f'network_{pex(token_network_registry.address)}',
        f'v{RAIDEN_DB_VERSION}_log.db',
    )
    config['database_path'] = database_path

    print(
        '\nYou are connected to the \'{}\' network and the DB path is: {}'.format(
            ID_TO_NETWORKNAME.get(given_network_id, given_network_id),
            database_path,
        ),
    )

    discovery = None
    if transport == 'udp':
        transport, discovery = _setup_udp(
            config,
            blockchain_service,
            address,
            contracts,
            endpoint_registry_contract_address,
        )
    elif transport == 'matrix':
        transport = _setup_matrix(config)
    else:
        raise RuntimeError(f'Unknown transport type "{transport}" given')

    raiden_event_handler = RaidenEventHandler()
    message_handler = MessageHandler()

    try:
        if 'contracts' in chain_config:
            start_block = chain_config['contracts']['TokenNetworkRegistry']['block_number']
        else:
            start_block = 0

        raiden_app = App(
            config=config,
            chain=blockchain_service,
            query_start_block=start_block,
            default_registry=token_network_registry,
            default_secret_registry=secret_registry,
            transport=transport,
            raiden_event_handler=raiden_event_handler,
            message_handler=message_handler,
            discovery=discovery,
        )
    except RaidenError as e:
        click.secho(f'FATAL: {e}', fg='red')
        sys.exit(1)

    try:
        raiden_app.start()
    except RuntimeError as e:
        click.secho(f'FATAL: {e}', fg='red')
        sys.exit(1)
    except filelock.Timeout:
        name_or_id = ID_TO_NETWORKNAME.get(given_network_id, given_network_id)
        click.secho(
            f'FATAL: Another Raiden instance already running for account {address_hex} on '
            f'network id {name_or_id}',
            fg='red',
        )
        sys.exit(1)

    return raiden_app
Example #48
0
    def _start_services(self):
        from raiden.ui.console import Console
        from raiden.api.python import RaidenAPI

        config = deepcopy(App.DEFAULT_CONFIG)
        if self._options.get('extra_config', dict()):
            merge_dict(config, self._options['extra_config'])
            del self._options['extra_config']
        self._options['config'] = config

        if self._options['showconfig']:
            print('Configuration Dump:')
            dump_config(config)
            dump_cmd_options(self._options)
            dump_module('settings', settings)
            dump_module('constants', constants)

        # this catches exceptions raised when waiting for the stalecheck to complete
        try:
            app_ = run_app(**self._options)
        except (EthNodeCommunicationError, RequestsConnectionError):
            print(ETHEREUM_NODE_COMMUNICATION_ERROR)
            sys.exit(1)
        except RuntimeError as e:
            click.secho(str(e), fg='red')
            sys.exit(1)
        except EthNodeInterfaceError as e:
            click.secho(str(e), fg='red')
            sys.exit(1)

        tasks = [app_.raiden]  # RaidenService takes care of Transport and AlarmTask

        domain_list = []
        if self._options['rpccorsdomain']:
            if ',' in self._options['rpccorsdomain']:
                for domain in self._options['rpccorsdomain'].split(','):
                    domain_list.append(str(domain))
            else:
                domain_list.append(str(self._options['rpccorsdomain']))

        self._raiden_api = RaidenAPI(app_.raiden)

        if self._options['rpc']:
            rest_api = RestAPI(self._raiden_api)
            api_server = APIServer(
                rest_api,
                cors_domain_list=domain_list,
                web_ui=self._options['web_ui'],
                eth_rpc_endpoint=self._options['eth_rpc_endpoint'],
            )
            (api_host, api_port) = split_endpoint(self._options['api_address'])

            try:
                api_server.start(api_host, api_port)
            except APIServerPortInUseError:
                click.secho(
                    f'ERROR: API Address {api_host}:{api_port} is in use. '
                    f'Use --api-address <host:port> to specify a different port.',
                    fg='red',
                )
                sys.exit(1)

            print(
                'The Raiden API RPC server is now running at http://{}:{}/.\n\n'
                'See the Raiden documentation for all available endpoints at\n'
                'http://raiden-network.readthedocs.io/en/stable/rest_api.html'.format(
                    api_host,
                    api_port,
                ),
            )
            tasks.append(api_server)

        if self._options['console']:
            console = Console(app_)
            console.start()
            tasks.append(console)

        # spawn a greenlet to handle the version checking
        version = get_system_spec()['raiden']
        tasks.append(gevent.spawn(check_version, version))

        # spawn a greenlet to handle the gas reserve check
        tasks.append(gevent.spawn(check_gas_reserve, app_.raiden))

        self._startup_hook()

        # wait for interrupt
        event = AsyncResult()

        def sig_set(sig=None, _frame=None):
            event.set(sig)

        gevent.signal(signal.SIGQUIT, sig_set)
        gevent.signal(signal.SIGTERM, sig_set)
        gevent.signal(signal.SIGINT, sig_set)

        # quit if any task exits, successfully or not
        for task in tasks:
            task.link(event)

        try:
            event.get()
            print('Signal received. Shutting down ...')
        except (EthNodeCommunicationError, RequestsConnectionError):
            print(ETHEREUM_NODE_COMMUNICATION_ERROR)
            sys.exit(1)
        except RaidenError as ex:
            click.secho(f'FATAL: {ex}', fg='red')
        except Exception as ex:
            file = NamedTemporaryFile(
                'w',
                prefix=f'raiden-exception-{datetime.utcnow():%Y-%m-%dT%H-%M}',
                suffix='.txt',
                delete=False,
            )
            with file as traceback_file:
                traceback.print_exc(file=traceback_file)
                click.secho(
                    f'FATAL: An unexpected exception occured. '
                    f'A traceback has been written to {traceback_file.name}\n'
                    f'{ex}',
                    fg='red',
                )
        finally:
            self._shutdown_hook()

            def stop_task(task):
                try:
                    if isinstance(task, Runnable):
                        task.stop()
                    else:
                        task.kill()
                finally:
                    task.get()  # re-raise

            gevent.joinall(
                [gevent.spawn(stop_task, task) for task in tasks],
                app_.config.get('shutdown_timeout', settings.DEFAULT_SHUTDOWN_TIMEOUT),
                raise_error=True,
            )

        return app_