def assert_failed_pfs_request( paths_args: typing.Dict[str, typing.Any], responses: typing.List[typing.Dict], status_codes: typing.Sequence[int] = (400, 400), expected_requests: int = MAX_PATHS_QUERY_ATTEMPTS, expected_get_iou_requests: int = None, expected_success: bool = False, exception_type: typing.Type = ServiceRequestFailed, ): while len(responses) < MAX_PATHS_QUERY_ATTEMPTS: responses.append(responses[0]) for response in responses: if "error_code" in response: response["errors"] = "broken iou" path_mocks = [ mocked_json_response(response_data=data, status_code=status_code) for data, status_code in zip(responses, status_codes) ] with patch("raiden.network.pathfinding.get_pfs_info") as mocked_pfs_info: mocked_pfs_info.return_value = PFS_CONFIG.info with patch.object(session, "get", return_value=mocked_json_response()) as get_iou: with patch.object(session, "post", side_effect=path_mocks) as post_paths: if expected_success: query_paths(**paths_args) else: with pytest.raises(exception_type) as raised_exception: query_paths(**paths_args) assert "broken iou" in str(raised_exception) assert get_iou.call_count == (expected_get_iou_requests or expected_requests) assert post_paths.call_count == expected_requests
def assert_failed_pfs_request( paths_args: typing.Dict[str, typing.Any], responses: typing.List[typing.Dict], status_codes: typing.List[int] = (400, 400), expected_requests: int = MAX_PATHS_QUERY_ATTEMPTS, expected_get_iou_requests: int = None, expected_success: bool = False, exception_type: typing.Type = None, ): while len(responses) < MAX_PATHS_QUERY_ATTEMPTS: responses.append(responses[0]) for response in responses: if "error_code" in response: response["errors"] = "broken iou" path_mocks = [request_mock(*data) for data in zip(responses, status_codes)] with patch.object(requests, "get", return_value=request_mock()) as get_iou: with patch.object(requests, "post", side_effect=path_mocks) as post_paths: if expected_success: query_paths(**paths_args) else: with pytest.raises( exception_type or ServiceRequestFailed) as raised_exception: query_paths(**paths_args) assert "broken iou" in str(raised_exception) assert get_iou.call_count == expected_get_iou_requests or expected_requests assert post_paths.call_count == expected_requests
def test_no_iou_when_pfs_price_0(query_paths_args): """ Test that no IOU is sent when PFS is for free """ query_paths_args["pfs_config"] = PFSConfig( info=PFSInfo( url="abc", price=TokenAmount(0), chain_id=ChainID(42), token_network_registry_address=factories. make_token_network_registry_address(), user_deposit_address=factories.make_address(), payment_address=factories.make_address(), confirmed_block_number=dict(number=BlockNumber(1)), message="", operator="", version="", matrix_server="http://matrix.example.com", matrix_room_id="!room-id:matrix.example.com", ), maximum_fee=TokenAmount(100), iou_timeout=BlockNumber(100), max_paths=5, ) with patch("raiden.network.pathfinding.get_pfs_info") as mocked_pfs_info: mocked_pfs_info.return_value = PFS_CONFIG.info with patch.object(pathfinding, "post_pfs_paths", return_value=mocked_json_response()) as post_path: query_paths( pfs_config=query_paths_args["pfs_config"], our_address=query_paths_args["our_address"], privkey=query_paths_args["privkey"], current_block_number=query_paths_args["current_block_number"], token_network_address=query_paths_args[ "token_network_address"], one_to_n_address=query_paths_args["one_to_n_address"], chain_id=query_paths_args["chain_id"], route_from=query_paths_args["route_from"], route_to=query_paths_args["route_to"], value=query_paths_args["value"], pfs_wait_for_block=query_paths_args["pfs_wait_for_block"], ) assert post_path.call_args == call( payload={ "from": to_checksum_address(query_paths_args["route_from"]), "to": to_checksum_address(query_paths_args["route_to"]), "value": query_paths_args["value"], "max_paths": query_paths_args["pfs_config"].max_paths, }, token_network_address=query_paths_args["token_network_address"], url=query_paths_args["pfs_config"].info.url, )
def test_no_iou_when_pfs_price_0(query_paths_args): """ Test that no IOU is sent when PFS is for free """ query_paths_args["pfs_config"] = PFSConfig( info=PFSInfo( url="abc", price=TokenAmount(0), chain_id=ChainID(42), token_network_registry_address=factories. make_token_network_address(), payment_address=factories.make_address(), message="", operator="", version="", ), maximum_fee=TokenAmount(100), iou_timeout=BlockNumber(100), max_paths=5, ) with patch.object(pathfinding, "post_pfs_paths", return_value=mocked_json_response()) as post_path: query_paths( pfs_config=query_paths_args["pfs_config"], our_address=query_paths_args["our_address"], privkey=query_paths_args["privkey"], current_block_number=query_paths_args["current_block_number"], token_network_address=query_paths_args["token_network_address"], one_to_n_address=query_paths_args["one_to_n_address"], chain_id=query_paths_args["chain_id"], route_from=query_paths_args["route_from"], route_to=query_paths_args["route_to"], value=query_paths_args["value"], ) assert post_path.call_args == call( payload={ "from": to_checksum_address(query_paths_args["route_from"]), "to": to_checksum_address(query_paths_args["route_to"]), "value": query_paths_args["value"], "max_paths": query_paths_args["pfs_config"].max_paths, }, token_network_address=query_paths_args["token_network_address"], url=query_paths_args["pfs_config"].info.url, )
def get_best_routes_pfs( chain_state: ChainState, token_network_address: TokenNetworkAddress, one_to_n_address: OneToNAddress, from_address: InitiatorAddress, to_address: TargetAddress, amount: PaymentAmount, previous_address: Optional[Address], pfs_config: PFSConfig, privkey: bytes, pfs_wait_for_block: BlockNumber, ) -> Tuple[Optional[str], List[RouteState], Optional[UUID]]: try: pfs_routes, feedback_token = query_paths( pfs_config=pfs_config, our_address=chain_state.our_address, privkey=privkey, current_block_number=chain_state.block_number, token_network_address=token_network_address, one_to_n_address=one_to_n_address, chain_id=chain_state.chain_id, route_from=from_address, route_to=to_address, value=amount, pfs_wait_for_block=pfs_wait_for_block, ) except ServiceRequestFailed as e: log_message = ("PFS: " + e.args[0]) if e.args[0] else None log_info = e.args[1] if len(e.args) > 1 else {} log.warning("An error with the path request occurred", log_message=log_message, **log_info) return log_message, [], None paths = [] for path_object in pfs_routes: path = path_object["path"] estimated_fee = path_object["estimated_fee"] canonical_path = [to_canonical_address(node) for node in path] # get the second entry, as the first one is the node itself # also needs to be converted to canonical representation partner_address = canonical_path[1] # don't route back if partner_address == previous_address: continue channel_state = views.get_channelstate_by_token_network_and_partner( chain_state=chain_state, token_network_address=token_network_address, partner_address=partner_address, ) if not channel_state: continue # check channel state if channel.get_status(channel_state) != ChannelState.STATE_OPENED: log.info( "Channel is not opened, ignoring", from_address=to_checksum_address(from_address), partner_address=to_checksum_address(partner_address), routing_source="Pathfinding Service", ) continue paths.append( RouteState( route=canonical_path, forward_channel_id=channel_state.identifier, estimated_fee=estimated_fee, )) return None, paths, feedback_token
def get_best_routes_pfs( chain_state: ChainState, token_network_id: TokenNetworkID, one_to_n_address: Address, from_address: InitiatorAddress, to_address: TargetAddress, amount: PaymentAmount, previous_address: Optional[Address], config: Dict[str, Any], privkey: bytes, ) -> Tuple[bool, List[RouteState], Optional[UUID]]: try: pfs_routes, feedback_token = query_paths( service_config=config, our_address=chain_state.our_address, privkey=privkey, current_block_number=chain_state.block_number, token_network_address=token_network_id, one_to_n_address=one_to_n_address, chain_id=chain_state.chain_id, route_from=from_address, route_to=to_address, value=amount, ) except ServiceRequestFailed as e: log_message = e.args[0] log_info = e.args[1] if len(e.args) > 1 else {} log.warning(log_message, **log_info) return False, [], None paths = [] for path_object in pfs_routes: path = path_object["path"] # get the second entry, as the first one is the node itself # also needs to be converted to canonical representation partner_address = to_canonical_address(path[1]) # don't route back if partner_address == previous_address: continue channel_state = views.get_channelstate_by_token_network_and_partner( chain_state=chain_state, token_network_id=token_network_id, partner_address=partner_address, ) if not channel_state: continue # check channel state if channel.get_status(channel_state) != CHANNEL_STATE_OPENED: log.info( "Channel is not opened, ignoring", from_address=to_checksum_address(from_address), partner_address=to_checksum_address(partner_address), routing_source="Pathfinding Service", ) continue paths.append( RouteState(node_address=partner_address, channel_identifier=channel_state.identifier)) return True, paths, feedback_token