Skip to content

Commit

Permalink
add capabilities to address_metadata_endpoint (#942)
Browse files Browse the repository at this point in the history
* add capabilities to address_metadata_endpoint

* rename to address_metadata

* fix test
  • Loading branch information
fredo committed Mar 29, 2021
1 parent 9f06b87 commit a4be443
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 29 deletions.
22 changes: 15 additions & 7 deletions src/pathfinding_service/api.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import collections
from dataclasses import dataclass, field
from datetime import MINYEAR, datetime
from typing import Any, ClassVar, Dict, List, Optional, Tuple, Type, TypeVar, cast
from typing import Any, ClassVar, Dict, List, Optional, Tuple, Type, TypeVar, Union, cast
from uuid import UUID

import marshmallow
Expand Down Expand Up @@ -44,6 +44,7 @@
Address,
BlockNumber,
PaymentAmount,
PeerCapabilities,
Signature,
TokenAmount,
TokenNetworkAddress,
Expand Down Expand Up @@ -458,19 +459,21 @@ def get(self) -> Tuple[dict, int]:
return info, 200


class UserResource(PathfinderResource):
def get(self, user_address: str) -> Tuple[Dict[str, str], int]:
address = self._validate_address_argument(user_address)
class AddressMetadataResource(PathfinderResource):
def get(self, checksummed_address: str) -> Tuple[Dict[str, Union[str, PeerCapabilities]], int]:
address = self._validate_address_argument(checksummed_address)
user_manager = self.pathfinding_service.matrix_listener.user_manager
user_ids = user_manager.get_userids_for_address(address)

for user_id in user_ids:
if user_manager.get_userid_presence(user_id) in [
UserPresence.ONLINE,
UserPresence.UNAVAILABLE,
]:
return {"user_id": user_id}, 200
capabilities = user_manager.get_address_capabilities(address)
return {"user_id": user_id, "capabilities": capabilities}, 200

raise exceptions.AddressNotOnline(address=user_address)
raise exceptions.AddressNotOnline(address=checksummed_address)

@staticmethod
def _validate_address_argument(address: str) -> Address:
Expand Down Expand Up @@ -664,7 +667,12 @@ def after_request(response: Response) -> Response: # pylint: disable=unused-var
),
("/v1/info", InfoResource, {}, "info"),
("/v2/info", InfoResource2, {}, "info2"),
("/v1/user/<user_address>", UserResource, {}, "user"),
(
"/v1/address/<checksummed_address>/metadata",
AddressMetadataResource,
{},
"address_metadata",
),
]

if debug_mode:
Expand Down
25 changes: 16 additions & 9 deletions src/pathfinding_service/model/token_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from copy import copy
from datetime import datetime, timedelta
from itertools import islice
from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple
from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, Union

import networkx as nx
import structlog
Expand Down Expand Up @@ -30,6 +30,7 @@
FeeAmount,
PaymentAmount,
PaymentWithFeeAmount,
PeerCapabilities,
TokenAmount,
TokenNetworkAddress,
)
Expand Down Expand Up @@ -79,8 +80,8 @@ def __init__(
self.value = value
self.reachability_state = reachability_state
self.fees = self._check_validity_and_calculate_fees()
self.matrix_users = self._get_matrix_users() if self.fees is not None else None
self.is_valid = self.fees is not None and self.matrix_users is not None
self.metadata = self._get_address_metadata() if self.fees is not None else None
self.is_valid = self.fees is not None and self.metadata is not None
log.debug("Created Path object", nodes=nodes, is_valid=self.is_valid, fees=self.fees)

def _calculate_fees(self) -> Optional[List[FeeAmount]]:
Expand Down Expand Up @@ -141,9 +142,11 @@ def _calculate_fees(self) -> Optional[List[FeeAmount]]:

return fees

def _get_matrix_users(self) -> Optional[Dict[str, str]]:
def _get_address_metadata(
self,
) -> Optional[Dict[str, Dict[str, Union[str, PeerCapabilities]]]]:
# Check node reachabilities
user_ids: Dict[str, str] = {}
metadata: Dict[str, Dict[str, Union[str, PeerCapabilities]]] = {}
for node in self.nodes:
node_user_ids = self.reachability_state.get_userids_for_address(node)
checksummed_address = to_checksum_address(node)
Expand All @@ -152,20 +155,24 @@ def _get_matrix_users(self) -> Optional[Dict[str, str]]:
UserPresence.ONLINE,
UserPresence.UNAVAILABLE,
]:
user_ids[checksummed_address] = user_id
capabilities = self.reachability_state.get_address_capabilities(node)
metadata[checksummed_address] = {
"user_id": user_id,
"capabilities": capabilities,
}
# if a reachable user is found we arbitrarily choose
# this user for the given address. There should not be another user online
break

if checksummed_address not in user_ids:
if checksummed_address not in metadata:
log.debug(
"Path invalid because of unavailable node",
node=node,
node_reachability=self.reachability_state.get_address_reachability(node),
)
return None

return user_ids
return metadata

def _check_validity_and_calculate_fees(self) -> Optional[List[FeeAmount]]:
"""Checks validity of this path and calculates fees if valid.
Expand Down Expand Up @@ -227,7 +234,7 @@ def to_dict(self) -> dict:
try:
return dict(
path=[to_checksum_address(node) for node in self.nodes],
matrix_users=self.matrix_users,
address_metadata=self.metadata,
estimated_fee=self.estimated_fee,
)
except KeyError:
Expand Down
5 changes: 4 additions & 1 deletion src/pathfinding_service/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from raiden.messages.path_finding_service import PFSCapacityUpdate, PFSFeeUpdate
from raiden.network.transport.matrix import UserPresence
from raiden.network.transport.matrix.utils import AddressReachability
from raiden.utils.typing import Address
from raiden.utils.typing import Address, PeerCapabilities

DeferableMessage = Union[PFSFeeUpdate, PFSCapacityUpdate]

Expand All @@ -21,3 +21,6 @@ def get_userid_presence(self, user_id: str) -> UserPresence:

def get_userids_for_address(self, address: Address) -> Set[str]:
...

def get_address_capabilities(self, address: Address) -> PeerCapabilities:
...
22 changes: 11 additions & 11 deletions tests/pathfinding/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from raiden_contracts.utils.type_aliases import PrivateKey
from raiden_libs.utils import private_key_to_address
from tests.pathfinding.test_database import db_has_feedback_for
from tests.pathfinding.utils import get_user_id_from_address
from tests.pathfinding.utils import get_address_metadata, get_user_id_from_address

ID_12 = 12
ID_123 = 123
Expand Down Expand Up @@ -85,10 +85,10 @@ def test_get_paths_via_debug_endpoint_a(
{
"path": [hex_addrs[0], hex_addrs[1], hex_addrs[2]],
"estimated_fee": 0,
"matrix_users": {
hex_addrs[0]: get_user_id_from_address(hex_addrs[0]),
hex_addrs[1]: get_user_id_from_address(hex_addrs[1]),
hex_addrs[2]: get_user_id_from_address(hex_addrs[2]),
"address_metadata": {
hex_addrs[0]: get_address_metadata(hex_addrs[0]),
hex_addrs[1]: get_address_metadata(hex_addrs[1]),
hex_addrs[2]: get_address_metadata(hex_addrs[2]),
},
}
]
Expand Down Expand Up @@ -355,10 +355,10 @@ def test_get_paths(api_url: str, addresses: List[Address], token_network_model:
assert paths == [
{
"path": [hex_addrs[0], hex_addrs[1], hex_addrs[2]],
"matrix_users": {
hex_addrs[0]: get_user_id_from_address(hex_addrs[0]),
hex_addrs[1]: get_user_id_from_address(hex_addrs[1]),
hex_addrs[2]: get_user_id_from_address(hex_addrs[2]),
"address_metadata": {
hex_addrs[0]: get_address_metadata(hex_addrs[0]),
hex_addrs[1]: get_address_metadata(hex_addrs[1]),
hex_addrs[2]: get_address_metadata(hex_addrs[2]),
},
"estimated_fee": 0,
}
Expand Down Expand Up @@ -519,10 +519,10 @@ def test_get_info2(api_url: str, api_sut, pathfinding_service_mock):


@pytest.mark.usefixtures("api_sut")
def test_get_user(api_url: str, api_sut: PFSApi):
def test_get_address_metadata(api_url: str, api_sut: PFSApi):
address = make_signer().address
checksummed_address = to_checksum_address(address)
url = f"{api_url}/v1/user/{checksummed_address}"
url = f"{api_url}/v1/address/{checksummed_address}/metadata"
response = requests.get(url)
assert response.status_code == 404

Expand Down
17 changes: 16 additions & 1 deletion tests/pathfinding/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,22 @@

from raiden.network.transport.matrix import AddressReachability, UserPresence
from raiden.network.transport.matrix.utils import ReachabilityState, address_from_userid
from raiden.utils.typing import Address, Dict
from raiden.settings import CapabilitiesConfig
from raiden.utils.capabilities import capconfig_to_dict
from raiden.utils.typing import Address, Dict, PeerCapabilities


def get_user_id_from_address(address: Union[str, bytes]):
return f"@{to_normalized_address(address)}:homeserver.com"


def get_address_metadata(address: Union[str, bytes]):
return {
"user_id": get_user_id_from_address(address),
"capabilities": PeerCapabilities(capconfig_to_dict(CapabilitiesConfig())),
}


class SimpleReachabilityContainer: # pylint: disable=too-few-public-methods
def __init__(self, reachabilities: Dict[Address, AddressReachability]) -> None:
self.reachabilities = reachabilities
Expand Down Expand Up @@ -43,3 +52,9 @@ def get_userid_presence(self, user_id: str) -> UserPresence:
def get_userids_for_address(self, address: Address) -> Set[str]:
""" Return all known user ids for the given ``address``. """
return self._address_to_userids[address]

def get_address_capabilities(self, address: Address) -> PeerCapabilities:
""" Return the protocol capabilities for ``address``. """
if address in self.reachabilities:
return PeerCapabilities(capconfig_to_dict(CapabilitiesConfig()))
return PeerCapabilities({})

0 comments on commit a4be443

Please sign in to comment.