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']
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)
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
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()
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()
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)
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)
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()
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