def get_network_to_broadcast_rooms( api: GMatrixHttpApi) -> Dict[str, List[RoomInfo]]: room_alias_fragments = [ DISCOVERY_DEFAULT_ROOM, PATH_FINDING_BROADCASTING_ROOM, MONITORING_BROADCASTING_ROOM, ] server = urlparse(api.base_url).netloc network_to_broadcast: Dict[str, List[RoomInfo]] = dict() for network in Networks: broadcast_room_infos: List[RoomInfo] = list() network_to_broadcast[str(network.value)] = broadcast_room_infos for room_alias_fragment in room_alias_fragments: broadcast_room_alias = make_room_alias(ChainID(network.value), room_alias_fragment) local_room_alias = f"#{broadcast_room_alias}:{server}" try: room_id = api.get_room_id(local_room_alias) broadcast_room_infos.append( RoomInfo(room_id, broadcast_room_alias, server)) except MatrixError as ex: click.secho( f"Could not find room {broadcast_room_alias} with error {ex}" ) return network_to_broadcast
def test_pfs_send_capacity_updates_on_deposit_and_withdraw( raiden_network: List[App], token_addresses: List[TokenAddress]) -> None: # We need to test if PFSCapacityUpdates and PFSFeeUpdates are being # sent after a deposit and withdraw. # Therefore, we create two Raiden nodes app0 and app1. # The nodes open a channel but do not deposit # a pfs matrix room is mocked to see what is sent to it app0, app1 = raiden_network transport0 = app0.raiden.transport pfs_room_name = make_room_alias(transport0.chain_id, PATH_FINDING_BROADCASTING_ROOM) pfs_room = transport0._broadcast_rooms.get(pfs_room_name) # need to assert for mypy that pfs_room is not None assert isinstance(pfs_room, Room) pfs_room.send_text = MagicMock(spec=pfs_room.send_text) api0 = RaidenAPI(app0.raiden) api0.channel_open( token_address=token_addresses[0], registry_address=app0.raiden.default_registry.address, partner_address=app1.raiden.address, ) # the room should not have been called at channel opening assert pfs_room.send_text.call_count == 0 api0.set_total_channel_deposit( token_address=token_addresses[0], registry_address=app0.raiden.default_registry.address, partner_address=app1.raiden.address, total_deposit=TokenAmount(10), ) # now we expect the room to be called the 1st time with a PFSCapacityUpdate # and a PFSFeeUpdate after the deposit assert "PFSCapacityUpdate" in str(pfs_room.send_text.call_args_list[0]) assert "PFSFeeUpdate" in str(pfs_room.send_text.call_args_list[0]) api0.set_total_channel_withdraw( token_address=token_addresses[0], registry_address=app0.raiden.default_registry.address, partner_address=app1.raiden.address, total_withdraw=WithdrawAmount(5), ) # now we expect the room to be called the 2nd time with a PFSCapacityUpdate # after the withdraw assert "PFSCapacityUpdate" in str(pfs_room.send_text.call_args_list[1]) assert "PFSFeeUpdate" in str(pfs_room.send_text.call_args_list[1])
def get_discovery_room(api: GMatrixHttpApi, network_value: int) -> Optional[RoomInfo]: server = urlparse(api.base_url).netloc discovery_room_alias = make_room_alias(ChainID(network_value), DISCOVERY_DEFAULT_ROOM) local_room_alias = f"#{discovery_room_alias}:{server}" try: room_id = api.get_room_id(local_room_alias) return RoomInfo(room_id, discovery_room_alias, server) except MatrixError as ex: click.secho( f"Could not find room {discovery_room_alias} with error {ex}") return None
def test_pfs_send_capacity_updates_during_mediated_transfer( raiden_network, number_of_nodes, deposit, token_addresses, network_wait): app0, app1 = raiden_network token_address = token_addresses[0] chain_state = views.state_from_app(app0) token_network_registry_address = app0.raiden.default_registry.address token_network_address = views.get_token_network_address_by_token_address( chain_state, token_network_registry_address, token_address) # Mock send_text on the PFS room transport0 = app0.raiden.transport pfs_room_name = make_room_alias(transport0.chain_id, PATH_FINDING_BROADCASTING_ROOM) pfs_room = transport0._broadcast_rooms.get(pfs_room_name) # need to assert for mypy that pfs_room is not None assert isinstance(pfs_room, Room) pfs_room.send_text = MagicMock(spec=pfs_room.send_text) amount = PaymentAmount(10) secrethash = transfer( initiator_app=app0, target_app=app1, token_address=token_address, amount=amount, identifier=PaymentID(1), timeout=network_wait * number_of_nodes, ) with block_timeout_for_transfer_by_secrethash(app1.raiden, secrethash): wait_assert( assert_succeeding_transfer_invariants, token_network_address, app0, deposit - amount, [], app1, deposit + amount, [], ) # We expect one PFSCapacityUpdate when locking and one when unlocking assert pfs_room.send_text.call_count == 2 assert "PFSCapacityUpdate" in str(pfs_room.send_text.call_args_list[0])
def ensure_rooms(self) -> None: exceptions = {} for network in Networks: for alias_fragment in [ DISCOVERY_DEFAULT_ROOM, MONITORING_BROADCASTING_ROOM, PATH_FINDING_BROADCASTING_ROOM, ]: try: room_alias_prefix = make_room_alias(ChainID(network.value), alias_fragment) self._first_server_actions(room_alias_prefix) log.info(f"Ensuring {alias_fragment} room for {network.name}") self._ensure_room_for_network(room_alias_prefix) except (MatrixError, EnsurerError) as ex: log.exception(f"Error while ensuring room for {network.name}.") exceptions[network] = ex if exceptions: log.error("Exceptions happened", exceptions=exceptions) raise MultipleErrors(exceptions)
def _ensure_room_for_network(self, network: Networks, alias_fragment: str) -> None: log.info(f"Ensuring {alias_fragment} room for {network.name}") room_alias_prefix = make_room_alias(ChainID(network.value), alias_fragment) room_infos: Dict[str, Optional[RoomInfo]] = { server_name: self._get_room(server_name, room_alias_prefix) for server_name in self._known_servers.keys() } first_server_room_info = room_infos[self._first_server_name] if not first_server_room_info: log.warning("First server room missing") if self._is_first_server: log.info("Creating room", server_name=self._own_server_name) first_server_room_info = self._create_room( self._own_server_name, room_alias_prefix) room_infos[self._first_server_name] = first_server_room_info else: raise EnsurerError("First server room missing.") are_all_rooms_the_same = all( room_info is not None and room_info.room_id == first_server_room_info.room_id for room_info in room_infos.values()) if not are_all_rooms_the_same: log.warning( "Room id mismatch", alias_prefix=room_alias_prefix, expected=first_server_room_info.room_id, found={ server_name: room_info.room_id if room_info else None for server_name, room_info in room_infos.items() }, ) own_server_room_info = room_infos.get(self._own_server_name) own_server_room_alias = f"#{room_alias_prefix}:{self._own_server_name}" first_server_room_alias = f"#{room_alias_prefix}:{self._first_server_name}" if not own_server_room_info: log.warning( "Room missing on own server, adding alias", server_name=self._own_server_name, room_id=first_server_room_info.room_id, new_room_alias=own_server_room_alias, ) self._join_and_alias_room(first_server_room_alias, own_server_room_alias) log.info("Room alias set", alias=own_server_room_alias) elif own_server_room_info.room_id != first_server_room_info.room_id: log.warning( "Conflicting local room, reassigning alias", server_name=self._own_server_name, expected_room_id=first_server_room_info.room_id, current_room_id=own_server_room_info.room_id, ) self._own_api.remove_room_alias(own_server_room_alias) self._join_and_alias_room(first_server_room_alias, own_server_room_alias) log.info( "Room alias updated", alias=own_server_room_alias, room_id=first_server_room_info.room_id, ) else: log.warning( "Mismatching rooms on other servers. Doing nothing.") else: log.info( "Room state ok.", network=network, server_rooms={ server_name: room_info.room_id if room_info else None for server_name, room_info in room_infos.items() }, )
def run_raiden_service( address: Address, keystore_path: str, gas_price: Callable, eth_rpc_endpoint: str, user_deposit_contract_address: Optional[UserDepositAddress], api_address: Endpoint, rpc: bool, rpccorsdomain: str, sync_check: bool, console: bool, password_file: TextIO, web_ui: bool, datadir: Optional[str], matrix_server: str, chain_id: ChainID, environment_type: Environment, unrecoverable_error_should_crash: bool, pathfinding_service_address: str, pathfinding_max_paths: int, enable_monitoring: bool, resolver_endpoint: str, default_reveal_timeout: BlockTimeout, default_settle_timeout: BlockTimeout, routing_mode: RoutingMode, flat_fee: Tuple[Tuple[TokenAddress, FeeAmount], ...], proportional_fee: Tuple[Tuple[TokenAddress, ProportionalFeeAmount], ...], proportional_imbalance_fee: Tuple[Tuple[TokenAddress, ProportionalFeeAmount], ...], blockchain_query_interval: float, cap_mediation_fees: bool, ** kwargs: Any, # FIXME: not used here, but still receives stuff in smoketest ) -> RaidenService: # pylint: disable=too-many-locals,too-many-branches,too-many-statements,unused-argument token_network_registry_deployed_at: Optional[BlockNumber] smart_contracts_start_at: BlockNumber if datadir is None: datadir = os.path.join(os.path.expanduser("~"), ".raiden") account_manager = AccountManager(keystore_path) web3 = Web3(HTTPProvider(rpc_normalized_endpoint(eth_rpc_endpoint))) check_sql_version() check_ethereum_has_accounts(account_manager) check_ethereum_chain_id(chain_id, web3) address, privatekey = get_account_and_private_key(account_manager, address, password_file) api_host, api_port = split_endpoint(api_address) if not api_port: api_port = DEFAULT_HTTP_SERVER_PORT domain_list = [] if rpccorsdomain: if "," in rpccorsdomain: for domain in rpccorsdomain.split(","): domain_list.append(str(domain)) else: domain_list.append(str(rpccorsdomain)) # Set up config fee_config = prepare_mediation_fee_config( cli_token_to_flat_fee=flat_fee, cli_token_to_proportional_fee=proportional_fee, cli_token_to_proportional_imbalance_fee=proportional_imbalance_fee, cli_cap_mediation_fees=cap_mediation_fees, ) rest_api_config = RestApiConfig( rest_api_enabled=rpc, web_ui_enabled=rpc and web_ui, cors_domain_list=domain_list, eth_rpc_endpoint=eth_rpc_endpoint, host=api_host, port=api_port, ) config = RaidenConfig( chain_id=chain_id, environment_type=environment_type, reveal_timeout=default_reveal_timeout, settle_timeout=default_settle_timeout, console=console, mediation_fees=fee_config, unrecoverable_error_should_crash=unrecoverable_error_should_crash, resolver_endpoint=resolver_endpoint, rest_api=rest_api_config, ) config.blockchain.query_interval = blockchain_query_interval config.services.monitoring_enabled = enable_monitoring config.services.pathfinding_max_paths = pathfinding_max_paths config.transport.server = matrix_server contracts = load_deployed_contracts_data(config, chain_id) rpc_client = JSONRPCClient( web3=web3, privkey=privatekey, gas_price_strategy=gas_price, block_num_confirmations=DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS, ) token_network_registry_deployed_at = None if "TokenNetworkRegistry" in contracts: token_network_registry_deployed_at = BlockNumber( contracts[CONTRACT_TOKEN_NETWORK_REGISTRY]["block_number"]) if token_network_registry_deployed_at is None: smart_contracts_start_at = get_smart_contracts_start_at(chain_id) else: smart_contracts_start_at = token_network_registry_deployed_at proxy_manager = ProxyManager( rpc_client=rpc_client, contract_manager=ContractManager(config.contracts_path), metadata=ProxyManagerMetadata( token_network_registry_deployed_at= token_network_registry_deployed_at, filters_start_at=smart_contracts_start_at, ), ) api_server: Optional[APIServer] = None if config.rest_api.rest_api_enabled: api_server = start_api_server(rpc_client=rpc_client, config=config.rest_api, eth_rpc_endpoint=eth_rpc_endpoint) if sync_check: check_synced(rpc_client) # The user has the option to launch Raiden with a custom # user deposit contract address. This can be used to load # the addresses for the rest of the deployed contracts. # The steps done here make sure that if a UDC address is provided, # the address has to be valid and all the connected contracts # are configured properly. # If a UDC address was not provided, Raiden would fall back # to using the ones deployed and provided by the raiden-contracts package. if user_deposit_contract_address is not None: if not is_address(user_deposit_contract_address): raise RaidenError("The user deposit address is invalid") deployed_addresses = load_deployment_addresses_from_udc( proxy_manager=proxy_manager, user_deposit_address=user_deposit_contract_address, block_identifier=BLOCK_ID_LATEST, ) else: deployed_addresses = load_deployment_addresses_from_contracts( contracts=contracts) # Load the available matrix servers when no matrix server is given # The list is used in a PFS check if config.transport.server == MATRIX_AUTO_SELECT_SERVER: fetch_available_matrix_servers(config.transport, environment_type) raiden_bundle = raiden_bundle_from_contracts_deployment( proxy_manager=proxy_manager, token_network_registry_address=deployed_addresses. token_network_registry_address, secret_registry_address=deployed_addresses.secret_registry_address, ) services_bundle = services_bundle_from_contracts_deployment( config=config, deployed_addresses=deployed_addresses, proxy_manager=proxy_manager, routing_mode=routing_mode, pathfinding_service_address=pathfinding_service_address, enable_monitoring=enable_monitoring, ) check_ethereum_confirmed_block_is_not_pruned( jsonrpc_client=rpc_client, secret_registry=raiden_bundle.secret_registry, confirmation_blocks=config.blockchain.confirmation_blocks, ) database_path = Path( os.path.join( datadir, f"node_{pex(address)}", f"netid_{chain_id}", f"network_{pex(raiden_bundle.token_network_registry.address)}", f"v{RAIDEN_DB_VERSION}_log.db", )) config.database_path = database_path print(f"Raiden is running in {environment_type.value.lower()} mode") print("\nYou are connected to the '{}' network and the DB path is: {}". format(ID_TO_CHAINNAME.get(chain_id, chain_id), database_path)) matrix_transport = setup_matrix(config.transport, config.services, environment_type, routing_mode) event_handler: EventHandler = RaidenEventHandler() # User should be told how to set fees, if using default fee settings log.debug("Fee Settings", fee_settings=fee_config) has_default_fees = (len(fee_config.token_to_flat_fee) == 0 and len(fee_config.token_to_proportional_fee) == 0 and len(fee_config.token_to_proportional_imbalance_fee) == 0) if has_default_fees: click.secho( "Default fee settings are used. " "If you want use Raiden with mediation fees - flat, proportional and imbalance fees - " "see https://raiden-network.readthedocs.io/en/latest/overview_and_guide.html#firing-it-up", # noqa: E501 fg="yellow", ) # Only send feedback when PFS is used if routing_mode == RoutingMode.PFS: event_handler = PFSFeedbackEventHandler(event_handler) message_handler = MessageHandler() raiden_service = RaidenService( config=config, rpc_client=rpc_client, proxy_manager=proxy_manager, query_start_block=smart_contracts_start_at, raiden_bundle=raiden_bundle, services_bundle=services_bundle, transport=matrix_transport, raiden_event_handler=event_handler, message_handler=message_handler, routing_mode=routing_mode, api_server=api_server, ) raiden_service.start() if config.pfs_config is not None: # This has to be done down here since there is a circular dependency # between the PFS and Transport pfs_broadcast_room_key = make_room_alias( config.chain_id, PATH_FINDING_BROADCASTING_ROOM) check_pfs_transport_configuration( pfs_info=config.pfs_config.info, pfs_was_autoselected=( pathfinding_service_address == MATRIX_AUTO_SELECT_SERVER), transport_pfs_broadcast_room_id=matrix_transport. broadcast_rooms[pfs_broadcast_room_key].room_id, matrix_server_url=matrix_transport.server_url, matrix_server_was_autoselected=( config.transport.server == MATRIX_AUTO_SELECT_SERVER), ) return raiden_service