Example #1
0
    def __init__(self, config, chain, discovery, transport_class=UDPTransport):
        self.config = config
        self.discovery = discovery

        if config.get('socket'):
            transport = transport_class(
                None,
                None,
                socket=config['socket'],
            )
        else:
            transport = transport_class(
                config['host'],
                config['port'],
            )

        transport.throttle_policy = TokenBucket(
            config['protocol']['throttle_capacity'],
            config['protocol']['throttle_fill_rate'])
        self.raiden = RaidenService(
            chain,
            decode_hex(config['privatekey_hex']),
            transport,
            discovery,
            config,
        )
        self.start_console = self.config['console']
Example #2
0
    def __init__(self, config, chain, discovery, transport_class=UDPTransport):
        self.config = config
        self.discovery = discovery

        if config.get('socket'):
            transport = transport_class(
                None,
                None,
                socket=config['socket'],
            )
        else:
            transport = transport_class(
                config['host'],
                config['port'],
            )

        transport.throttle_policy = TokenBucket(
            config['protocol']['throttle_capacity'],
            config['protocol']['throttle_fill_rate'])
        self.raiden = RaidenService(
            chain,
            decode_hex(config['privatekey_hex']),
            transport,
            discovery,
            config,
        )
        self.start_console = self.config['console']

        # raiden.ui.console:Console assumes that a services
        # attribute is available for auto-registration
        self.services = dict()
def test_token_bucket():
    capacity = 2
    fill_rate = 2
    token_refill = 1. / fill_rate

    # return constant time to have a predictable refill result
    time = lambda: 1

    bucket = TokenBucket(
        capacity,
        fill_rate,
        time,
    )

    assert bucket.consume(1) == 0
    assert bucket.consume(1) == 0

    for num in range(1, 9):
        assert num * token_refill == bucket.consume(1)
Example #4
0
 def __init__(self, config, chain, discovery, transport_class=UDPTransport):
     self.config = config
     self.discovery = discovery
     self.transport = transport_class(config['host'], config['port'])
     self.transport.throttle_policy = TokenBucket(
         config['throttle_capacity'], config['throttle_fill_rate'])
     self.raiden = RaidenService(
         chain,
         decode_hex(config['privatekey_hex']),
         self.transport,
         discovery,
         config,
     )
     self.services = {'raiden': self.raiden}
     self.start_console = True
Example #5
0
    def __init__(self,
                 config,
                 chain,
                 default_registry,
                 discovery,
                 transport_class=UDPTransport):
        self.config = config
        self.discovery = discovery

        if config.get('socket'):
            transport = transport_class(
                None,
                None,
                socket=config['socket'],
            )
        else:
            transport = transport_class(
                config['host'],
                config['port'],
            )

        transport.throttle_policy = TokenBucket(
            config['protocol']['throttle_capacity'],
            config['protocol']['throttle_fill_rate'])
        try:
            self.raiden = RaidenService(
                chain,
                default_registry,
                decode_hex(config['privatekey_hex']),
                transport,
                discovery,
                config,
            )
        except filelock.Timeout:
            pubkey = privatekey_to_address(
                decode_hex(self.config['privatekey_hex']))
            print(
                'FATAL: Another Raiden instance already running for account 0x%s'
                % str(pubkey).encode('hex'))
            sys.exit(1)
        self.start_console = self.config['console']

        # raiden.ui.console:Console assumes that a services
        # attribute is available for auto-registration
        self.services = dict()
Example #6
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

    if not mapped_socket:
        raise RuntimeError('Missing socket')

    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)

    (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 = 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
    config['socket'] = mapped_socket.socket
    config['external_ip'] = mapped_socket.external_ip
    config['external_port'] = mapped_socket.external_port
    config['protocol']['nat_keepalive_retries'] = DEFAULT_NAT_KEEPALIVE_RETRIES
    timeout = max_unresponsive_time / DEFAULT_NAT_KEEPALIVE_RETRIES
    config['protocol']['nat_keepalive_timeout'] = timeout

    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,
    )

    blockchain_service = BlockChainService(
        privatekey_bin,
        rpc_client,
        gas_price,
    )

    # this assumes the eth node is already online
    check_json_rpc(rpc_client)
    check_discovery_registration_gas(blockchain_service, address)

    net_id = int(blockchain_service.client.rpccall_with_retry('net_version'))
    if sync_check:
        check_synced(net_id, blockchain_service)

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

    registry = blockchain_service.registry(registry_contract_address, )

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

    registry = blockchain_service.registry(registry_contract_address)

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

    transport = UDPTransport(
        discovery,
        mapped_socket.socket,
        throttle_policy,
        config['protocol'],
    )

    raiden_app = App(
        config,
        blockchain_service,
        registry,
        discovery,
        transport,
    )

    return raiden_app
def run(
        privatekey,
        registry_contract_address,
        discovery_contract_address,
        listen_address,
        logging,
        logfile,
        scenario,
        stage_prefix
):  # pylint: disable=unused-argument

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

    (listen_host, listen_port) = split_endpoint(listen_address)

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

    privatekey_bin = decode_hex(privatekey)

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

    blockchain_service = BlockChainService(
        privatekey_bin,
        rpc_client,
        GAS_PRICE,
    )

    discovery = ContractDiscovery(
        blockchain_service,
        decode_hex(discovery_contract_address)
    )

    registry = blockchain_service.registry(
        registry_contract_address
    )

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

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

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

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

    app.raiden.register_payment_network(app.raiden.default_registry.address)

    if scenario:
        script = json.load(scenario)

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

        transfers_by_peer = {}

        tokens = script['tokens']
        token_address = None
        peer = None
        our_node = 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)
            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 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 #8
0
def test_throttle_policy_ping(monkeypatch, raiden_network):
    app0, app1 = raiden_network  # pylint: disable=unbalanced-tuple-unpacking

    # initial policy is DummyPolicy
    assert isinstance(app0.raiden.protocol.transport.throttle_policy,
                      DummyPolicy)

    test_time = fake_time()

    sleeps = sleeper()

    monkeypatch.setattr(raiden.network.transport, 'time', test_time)
    monkeypatch.setattr(raiden.network.transport.gevent, 'sleep', sleeps.sleep)

    for app in (app0, app1):
        monkeypatch.setattr(app.raiden.protocol.transport, 'throttle_policy',
                            TokenBucket(capacity=2, fill_rate=2))

    # monkey patching successful
    assert app0.raiden.protocol.transport.throttle_policy.capacity == 2.

    messages = setup_messages_cb()

    # In total 10 packets will be sent and the timing interval will be asserted.
    packets = list()
    for nonce in range(10):
        ping = Ping(nonce=nonce)
        app0.raiden.sign(ping)
        packets.append(ping)

    # the token refill rate is 1s / 2 = 0.5s per token
    token_refill = 1. / app0.raiden.protocol.transport.throttle_policy.fill_rate
    assert token_refill == 0.5

    # send all the packets, the throughput must be limited by the policy
    events = [
        app0.raiden.protocol.send_async(app1.raiden.address, p)
        for p in packets
    ]

    events[-1].wait()
    # Each token corresponds to a single message, the initial capacity is 2
    # meaning the first burst is of 2 packets.
    node_count = 2
    initial_packets = 2

    # The initial sequence Ping, Ack, Ping, Ack has no sleeptimes/throttling
    assert all(t == 0.0
               for t in sleeps.sleeptimes[:node_count *
                                          initial_packets]), sleeps.sleeptimes

    # the pattern of sleeps is the same for pinging and acking node:
    ping_sleeps = [sleeps.sleeptimes[i] for i in range(0, len(messages), 2)]
    ack_sleeps = [sleeps.sleeptimes[i + 1] for i in range(0, len(messages), 2)]

    assert ping_sleeps == ack_sleeps

    # since we didn't progress time in test, the sleep times will add up:
    for num, t in enumerate(ping_sleeps[initial_packets:], 1):
        assert num * token_refill == t

    # all 10 Pings and their Acks
    assert len(messages) == 20

    # sanity check messages
    pings = list()
    pings_raw = list()
    acks = list()
    for packet in messages:
        message = decode(packet)

        if isinstance(message, Ping):
            pings.append(message)
            pings_raw.append(packet)

        if isinstance(message, Ack):
            acks.append(message)

    for nonce, message in enumerate(pings):
        assert message.nonce == nonce

    for ping_packet, ack in zip(pings_raw, acks):
        assert ack.echo == sha3(ping_packet + app1.raiden.address)
Example #9
0
def test_throttle_policy_ping(monkeypatch, raiden_network):
    app0, app1 = raiden_network  # pylint: disable=unbalanced-tuple-unpacking

    # initial policy is DummyPolicy
    assert isinstance(app0.raiden.protocol.transport.throttle_policy, DummyPolicy)

    for app in (app0, app1):
        monkeypatch.setattr(
            app.raiden.protocol.transport,
            'throttle_policy',
            TokenBucket(capacity=2, fill_rate=2)
        )

    # monkey patching successful
    assert app0.raiden.protocol.transport.throttle_policy.capacity == 2.

    messages = setup_messages_cb()

    # In total 10 packets will be sent and the timing interval will be asserted.
    packets = list()
    for nonce in range(10):
        ping = Ping(nonce=nonce)
        app0.raiden.sign(ping)
        packets.append(ping)

    # We need to take into account some indeterminism of task switching and the
    # additional time for the Ack, let's allow for a 10% difference of the
    # "perfect" value of a message every 0.5s
    token_refill = 0.5
    tolerance = 0.05

    # time sensitive test, the interval is instantiated just before the protocol
    # is used.
    check = IntervalCheck()

    # send all the packets, the throughput must be limited by the policy
    events = [
        app0.raiden.protocol.send_async(app1.raiden.address, p)
        for p in packets
    ]

    # Each token corresponds to a single message, the initial capacity is 2
    # meaning the first burst is of 2 packets.
    events[1].wait()
    check.elapsed(seconds=0, tolerance=tolerance)

    assert len(messages) == 4  # two Pings and the corresponding Acks

    # Now check the fill_rate for the remaining packets
    for i in range(2, 10):
        events[i].wait()
        check.elapsed(token_refill, tolerance)

    # all 10 Pings and their Acks
    assert len(messages) == 20

    # sanity check messages
    pings = list()
    pings_raw = list()
    acks = list()
    for packet in messages:
        message = decode(packet)

        if isinstance(message, Ping):
            pings.append(message)
            pings_raw.append(packet)

        if isinstance(message, Ack):
            acks.append(message)

    for nonce, message in enumerate(pings):
        assert message.nonce == nonce

    for ping_packet, ack in zip(pings_raw, acks):
        assert ack.echo == sha3(ping_packet + app1.raiden.address)
Example #10
0
def tps_run(host, port, config, privatekey, rpc_server, registry_address,
            token_address, transfer_amount, parallel):
    # pylint: disable=too-many-locals,too-many-arguments
    ourprivkey, _ = hostport_to_privkeyaddr(host, port)

    rpc_connection = rpc_server.split(':')
    rpc_connection = (rpc_connection[0], int(rpc_connection[1]))

    with codecs.open(config, encoding='utf8') as handler:
        config = yaml.load(handler)

    config['host'] = host
    config['port'] = port
    config['privkey'] = ourprivkey

    rpc_connection = rpc_server.split(':')
    host, port = (rpc_connection[0], int(rpc_connection[1]))

    rpc_client = JSONRPCClient(
        host,
        port,
        privatekey,
    )

    blockchain_service = BlockChainService(
        privatekey,
        rpc_client,
        GAS_PRICE,
    )

    discovery = Discovery()
    found_ouraddress = False
    for node in config['nodes']:
        _, address = hostport_to_privkeyaddr(node['host'], node['port'])

        discovery.register(address, node['host'], node['port'])

        if host == node['host'] and str(port) == node['port']:
            found_ouraddress = True

    if not found_ouraddress:
        print('We are not registered in the configuration file')
        sys.exit(1)

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

    transport = UDPTransport(
        discovery,
        server._udp_socket((host, port)),
        throttle_policy,
        config['protocol'],
    )

    # FIXME: This is missing the registry
    app = App(
        config,
        blockchain_service,
        transport,
        discovery,
    )

    for _ in range(parallel):
        gevent.spawn(random_transfer, app, token_address, transfer_amount)

    # 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 #11
0
def create_apps(
    blockchain_services,
    endpoint_discovery_services,
    registry_address,
    raiden_udp_ports,
    reveal_timeout,
    settle_timeout,
    database_paths,
    retry_interval,
    retries_before_backoff,
    throttle_capacity,
    throttle_fill_rate,
    nat_invitation_timeout,
    nat_keepalive_retries,
    nat_keepalive_timeout,
):
    """ Create the apps."""
    # pylint: disable=too-many-locals
    services = zip(blockchain_services, endpoint_discovery_services)

    apps = []
    for idx, (blockchain, discovery) in enumerate(services):
        port = raiden_udp_ports[idx]
        private_key = blockchain.private_key
        nodeid = privatekey_to_address(private_key)

        host = '127.0.0.1'

        discovery.register(nodeid, host, port)

        config = {
            'host': host,
            'port': port,
            'external_ip': host,
            'external_port': port,
            'privatekey_hex': hexlify(private_key),
            'reveal_timeout': reveal_timeout,
            'settle_timeout': settle_timeout,
            'database_path': database_paths[idx],
            'protocol': {
                'retry_interval': retry_interval,
                'retries_before_backoff': retries_before_backoff,
                'throttle_capacity': throttle_capacity,
                'throttle_fill_rate': throttle_fill_rate,
                'nat_invitation_timeout': nat_invitation_timeout,
                'nat_keepalive_retries': nat_keepalive_retries,
                'nat_keepalive_timeout': nat_keepalive_timeout,
            },
            'rpc': True,
            'console': False,
        }
        config_copy = App.DEFAULT_CONFIG.copy()
        config_copy.update(config)

        registry = blockchain.registry(registry_address)

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

        transport = UDPTransport(
            discovery,
            server._udp_socket((host, port)),  # pylint: disable=protected-access
            throttle_policy,
            config['protocol'],
        )

        app = App(
            config_copy,
            blockchain,
            registry,
            discovery,
            transport,
        )
        apps.append(app)

    return apps