Example #1
0
def test_get_pfs_iou(one_to_n_address):
    token_network_address = TokenNetworkAddress(bytes([1] * 20))
    privkey = bytes([2] * 32)
    sender = privatekey_to_address(privkey)
    receiver = factories.make_address()

    response = mocked_json_response(response_data={"last_iou": None})
    with patch.object(session, "get", return_value=response):
        assert (get_last_iou("http://example.com", token_network_address,
                             sender, receiver, PRIVKEY) is None)

        # Previous IOU
        iou = IOU(
            sender=sender,
            receiver=receiver,
            amount=10,
            expiration_block=1000,
            one_to_n_address=one_to_n_address,
            chain_id=4,
        )
        iou.sign(privkey)

    response = mocked_json_response(response_data={"last_iou": iou.as_json()})
    with patch.object(session, "get", return_value=response):
        assert (get_last_iou("http://example.com", token_network_address,
                             sender, receiver, PRIVKEY) == iou)
Example #2
0
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
Example #3
0
def test_post_pfs_feedback(query_paths_args):
    """ Test POST feedback to PFS """

    feedback_token = uuid4()
    token_network_address = factories.make_token_network_address()
    route = [factories.make_address(), factories.make_address()]

    with patch.object(session, "post",
                      return_value=mocked_json_response()) as feedback:
        post_pfs_feedback(
            routing_mode=RoutingMode.PFS,
            pfs_config=query_paths_args["pfs_config"],
            token_network_address=token_network_address,
            route=route,
            token=feedback_token,
            successful=True,
        )

        assert feedback.called
        assert feedback.call_args[0][0].find(
            to_checksum_address(token_network_address)) > 0

        payload = feedback.call_args[1]["json"]
        assert payload["token"] == feedback_token.hex
        assert payload["success"] is True
        assert payload["path"] == [to_checksum_address(addr) for addr in route]

    with patch.object(session, "post",
                      return_value=mocked_json_response()) as feedback:
        post_pfs_feedback(
            routing_mode=RoutingMode.PFS,
            pfs_config=query_paths_args["pfs_config"],
            token_network_address=token_network_address,
            route=route,
            token=feedback_token,
            successful=False,
        )

        assert feedback.called
        assert feedback.call_args[0][0].find(
            to_checksum_address(token_network_address)) > 0

        payload = feedback.call_args[1]["json"]
        assert payload["token"] == feedback_token.hex
        assert payload["success"] is False
        assert payload["path"] == [to_checksum_address(addr) for addr in route]

    with patch.object(session, "post",
                      return_value=mocked_json_response()) as feedback:
        post_pfs_feedback(
            routing_mode=RoutingMode.PRIVATE,
            pfs_config=query_paths_args["pfs_config"],
            token_network_address=token_network_address,
            route=route,
            token=feedback_token,
            successful=False,
        )

        assert not feedback.called
Example #4
0
def test_get_and_update_iou(one_to_n_address):

    request_args = dict(
        url="url",
        token_network_address=factories.UNIT_TOKEN_NETWORK_ADDRESS,
        sender=factories.make_address(),
        receiver=factories.make_address(),
        privkey=PRIVKEY,
    )
    # RequestExceptions should be reraised as ServiceRequestFailed
    with pytest.raises(ServiceRequestFailed):
        with patch.object(session,
                          "get",
                          side_effect=requests.RequestException):
            get_last_iou(**request_args)

    # invalid JSON should raise a ServiceRequestFailed
    response = mocked_failed_response(error=ValueError)

    with pytest.raises(ServiceRequestFailed):
        with patch.object(session, "get", return_value=response):
            get_last_iou(**request_args)

    response = mocked_json_response(response_data={"other_key": "other_value"})
    with patch.object(session, "get", return_value=response):
        iou = get_last_iou(**request_args)
    assert iou is None, "get_pfs_iou should return None if pfs returns no iou."

    last_iou = make_iou(
        pfs_config=PFS_CONFIG,
        our_address=factories.UNIT_TRANSFER_INITIATOR,
        privkey=PRIVKEY,
        block_number=10,
        one_to_n_address=one_to_n_address,
        chain_id=4,
        offered_fee=TokenAmount(1),
    )

    response = mocked_json_response(response_data=dict(
        last_iou=last_iou.as_json()))

    with patch.object(session, "get", return_value=response):
        iou = get_last_iou(**request_args)
    assert iou == last_iou

    new_iou_1 = update_iou(replace(iou), PRIVKEY, added_amount=10)
    assert new_iou_1.amount == last_iou.amount + 10
    assert new_iou_1.sender == last_iou.sender
    assert new_iou_1.receiver == last_iou.receiver
    assert new_iou_1.expiration_block == last_iou.expiration_block
    assert new_iou_1.signature is not None

    new_iou_2 = update_iou(replace(iou), PRIVKEY, expiration_block=45)
    assert new_iou_2.expiration_block == 45
    assert new_iou_1.sender == iou.sender
    assert new_iou_1.receiver == iou.receiver
    assert new_iou_1.expiration_block == iou.expiration_block
    assert new_iou_2.signature is not None
Example #5
0
def test_routing_mocked_pfs_invalid_json_structure(chain_state,
                                                   one_to_n_address,
                                                   token_network_state,
                                                   our_address):
    token_network_state, addresses, _ = create_square_network_topology(
        token_network_state=token_network_state, our_address=our_address)
    address1, address2, address3, address4 = addresses

    # test routing with all nodes available
    chain_state.nodeaddresses_to_networkstates = {
        address1: NetworkState.REACHABLE,
        address2: NetworkState.REACHABLE,
        address3: NetworkState.REACHABLE,
    }

    response = mocked_json_response(response_data={}, status_code=400)

    with patch.object(session, "post", return_value=response):
        routes, feedback_token = get_best_routes_with_iou_request_mocked(
            chain_state=chain_state,
            token_network_state=token_network_state,
            one_to_n_address=one_to_n_address,
            from_address=our_address,
            to_address=address4,
            amount=50,
        )
        # Request to PFS failed, but we do not fall back to internal routing
        assert len(routes) == 0
        assert feedback_token is None
Example #6
0
def happy_path_fixture(chain_state, token_network_state, our_address):
    token_network_state, addresses, channel_states = create_square_network_topology(
        token_network_state=token_network_state, our_address=our_address)
    address1, address2, address3, address4 = addresses

    chain_state.nodeaddresses_to_networkstates = {
        address1: NetworkState.REACHABLE,
        address2: NetworkState.REACHABLE,
        address3: NetworkState.REACHABLE,
        address4: NetworkState.REACHABLE,
    }

    json_data = {
        "result": [{
            "path": [
                to_checksum_address(our_address),
                to_checksum_address(address2),
                to_checksum_address(address3),
                to_checksum_address(address4),
            ],
            "estimated_fee":
            0,
        }],
        "feedback_token":
        DEFAULT_FEEDBACK_TOKEN.hex,
    }

    response = mocked_json_response(response_data=json_data)

    return addresses, chain_state, channel_states, response, token_network_state
    def iou_side_effect(*_, **kwargs):
        assert "params" in kwargs
        body = kwargs["params"]

        assert is_hex_address(body["sender"])
        assert is_hex_address(body["receiver"])
        assert "timestamp" in body
        assert is_hex(body["signature"])
        assert len(body["signature"]) == 65 * 2 + 2  # 65 hex encoded bytes with 0x prefix

        return mocked_json_response(response_data=iou_json_data)
Example #8
0
    def iou_side_effect(*args, **kwargs):
        if args[0].endswith("/info"):
            return mocked_json_response({
                "price_info":
                5,
                "network_info": {
                    "chain_id":
                    42,
                    "token_network_registry_address":
                    to_checksum_address(
                        factories.make_token_network_registry_address()),
                    "user_deposit_address":
                    to_checksum_address(factories.make_address()),
                    "confirmed_block": {
                        "number": 11
                    },
                },
                "version":
                "0.0.3",
                "operator":
                "John Doe",
                "message":
                "This is your favorite pathfinding service",
                "payment_address":
                to_checksum_address(factories.make_address()),
                "matrix_server":
                "http://matrix.example.com",
            })
        else:
            assert "params" in kwargs
            body = kwargs["params"]

            assert is_hex_address(body["sender"])
            assert is_hex_address(body["receiver"])
            assert "timestamp" in body
            assert is_hex(body["signature"])
            assert len(body["signature"]
                       ) == 65 * 2 + 2  # 65 hex encoded bytes with 0x prefix

            return mocked_json_response(response_data=iou_json_data)
Example #9
0
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,
        )
Example #10
0
def test_routing_mocked_pfs_bad_http_code(chain_state, token_network_state,
                                          one_to_n_address, our_address):
    token_network_state, addresses, channel_states = create_square_network_topology(
        token_network_state=token_network_state, our_address=our_address)
    address1, address2, address3, address4 = addresses
    channel_state1, channel_state2 = channel_states

    # test routing with all nodes available
    chain_state.nodeaddresses_to_networkstates = {
        address1: NetworkState.REACHABLE,
        address2: NetworkState.REACHABLE,
        address3: NetworkState.REACHABLE,
    }

    # in case the pfs sends a bad http code but the correct path back
    json_data = {
        "result": [{
            "path": [
                to_checksum_address(our_address),
                to_checksum_address(address2),
                to_checksum_address(address3),
                to_checksum_address(address4),
            ],
            "fees":
            0,
        }]
    }

    response = mocked_json_response(response_data=json_data, status_code=400)

    with patch.object(requests, "post", return_value=response):
        routes, feedback_token = get_best_routes_with_iou_request_mocked(
            chain_state=chain_state,
            token_network_state=token_network_state,
            one_to_n_address=one_to_n_address,
            from_address=our_address,
            to_address=address4,
            amount=50,
        )
        # PFS doesn't work, so internal routing is used, so two possible routes are returned,
        # whereas the path via address1 is shorter (
        # even if the route is not possible from a global perspective)
        # in case the mocked pfs response were used, we would not see address1 on the route
        assert routes[0].next_hop_address == address1
        assert routes[0].forward_channel_id == channel_state1.identifier
        assert routes[1].next_hop_address == address2
        assert routes[1].forward_channel_id == channel_state2.identifier
        assert feedback_token is None
def test_routing_mocked_pfs_unavailable_peer(
    chain_state, token_network_state, one_to_n_address, our_address
):
    token_network_state, addresses, channel_states = create_square_network_topology(
        token_network_state=token_network_state, our_address=our_address
    )
    address1, address2, address3, address4 = addresses
    _, channel_state2 = channel_states

    json_data = {
        "result": [
            {
                "path": [
                    to_checksum_address(our_address),
                    to_checksum_address(address2),
                    to_checksum_address(address3),
                    to_checksum_address(address4),
                ],
                "estimated_fee": 0,
            }
        ],
        "feedback_token": DEFAULT_FEEDBACK_TOKEN.hex,
    }

    # test routing with node 2 unavailable
    chain_state.nodeaddresses_to_networkstates = {
        address1: NetworkState.REACHABLE,
        address2: NetworkState.UNREACHABLE,
        address3: NetworkState.REACHABLE,
    }

    response = mocked_json_response(response_data=json_data, status_code=200)

    with patch.object(requests, "post", return_value=response):
        routes, feedback_token = get_best_routes_with_iou_request_mocked(
            chain_state=chain_state,
            token_network_state=token_network_state,
            one_to_n_address=one_to_n_address,
            from_address=our_address,
            to_address=address4,
            amount=50,
        )
        # Node with address2 is not reachable, so even if the only route sent by the PFS
        # is over address2, the internal routing does not provide
        assert routes[0].next_hop_address == address2
        assert routes[0].forward_channel_id == channel_state2.identifier
        assert feedback_token == DEFAULT_FEEDBACK_TOKEN
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 test_routing_mocked_pfs_bad_http_code(
    chain_state, token_network_state, one_to_n_address, our_address
):
    token_network_state, addresses, _ = create_square_network_topology(
        token_network_state=token_network_state, our_address=our_address
    )
    address1, address2, address3, address4 = addresses

    # test routing with all nodes available
    chain_state.nodeaddresses_to_networkstates = {
        address1: NetworkState.REACHABLE,
        address2: NetworkState.REACHABLE,
        address3: NetworkState.REACHABLE,
    }

    # in case the pfs sends a bad http code but the correct path back
    json_data = {
        "result": [
            {
                "path": [
                    to_checksum_address(our_address),
                    to_checksum_address(address2),
                    to_checksum_address(address3),
                    to_checksum_address(address4),
                ],
                "fees": 0,
            }
        ]
    }

    response = mocked_json_response(response_data=json_data, status_code=400)

    with patch.object(requests, "post", return_value=response):
        routes, feedback_token = get_best_routes_with_iou_request_mocked(
            chain_state=chain_state,
            token_network_state=token_network_state,
            one_to_n_address=one_to_n_address,
            from_address=our_address,
            to_address=address4,
            amount=50,
        )
        # Request to PFS failed, but we do not fall back to internal routing
        assert len(routes) == 0
        assert feedback_token is None
Example #14
0
def test_configure_pfs(service_registry_address, private_keys, web3,
                       contract_manager):
    chain_id = ChainID(int(web3.net.version))
    service_registry, urls = deploy_service_registry_and_set_urls(
        private_keys=private_keys,
        web3=web3,
        contract_manager=contract_manager,
        service_registry_address=service_registry_address,
    )
    json_data = {
        "price_info":
        0,
        "network_info": {
            "chain_id":
            chain_id,
            "token_network_registry_address":
            to_checksum_address(token_network_registry_address_test_default),
            "user_deposit_address":
            to_checksum_address(privatekey_to_address(private_keys[1])),
            "confirmed_block": {
                "number": 10
            },
        },
        "message":
        "This is your favorite pathfinding service",
        "operator":
        "John Doe",
        "version":
        "0.0.1",
        "payment_address":
        to_checksum_address(privatekey_to_address(private_keys[0])),
    }

    response = mocked_json_response(response_data=json_data)

    # With local routing configure_pfs should raise assertion
    with pytest.raises(AssertionError):
        _ = configure_pfs_or_exit(
            pfs_url="",
            routing_mode=RoutingMode.LOCAL,
            service_registry=service_registry,
            node_network_id=chain_id,
            token_network_registry_address=
            token_network_registry_address_test_default,
            pathfinding_max_fee=DEFAULT_PATHFINDING_MAX_FEE,
        )

    # With private routing configure_pfs should raise assertion
    with pytest.raises(AssertionError):
        _ = configure_pfs_or_exit(
            pfs_url="",
            routing_mode=RoutingMode.PRIVATE,
            service_registry=service_registry,
            node_network_id=chain_id,
            token_network_registry_address=
            token_network_registry_address_test_default,
            pathfinding_max_fee=DEFAULT_PATHFINDING_MAX_FEE,
        )

    # Asking for auto address
    # To make this deterministic we need to patch the random selection function
    patch_random = patch("raiden.network.pathfinding.get_random_pfs",
                         return_value="http://foo")
    with patch.object(requests, "get", return_value=response), patch_random:
        config = configure_pfs_or_exit(
            pfs_url=MATRIX_AUTO_SELECT_SERVER,
            routing_mode=RoutingMode.PFS,
            service_registry=service_registry,
            node_network_id=chain_id,
            token_network_registry_address=
            token_network_registry_address_test_default,
            pathfinding_max_fee=DEFAULT_PATHFINDING_MAX_FEE,
        )
    assert config.url in urls
    assert is_canonical_address(config.payment_address)

    # Configuring a valid given address
    given_address = "http://foo"
    with patch.object(requests, "get", return_value=response):
        config = configure_pfs_or_exit(
            pfs_url=given_address,
            routing_mode=RoutingMode.PFS,
            service_registry=service_registry,
            node_network_id=chain_id,
            token_network_registry_address=
            token_network_registry_address_test_default,
            pathfinding_max_fee=DEFAULT_PATHFINDING_MAX_FEE,
        )
    assert config.url == given_address
    assert is_same_address(config.payment_address,
                           json_data["payment_address"])
    assert config.price == json_data["price_info"]

    # Bad address, should exit the program
    bad_address = "http://badaddress"
    with pytest.raises(RaidenError):
        with patch.object(requests,
                          "get",
                          side_effect=requests.RequestException()):
            # Configuring a given address
            _ = configure_pfs_or_exit(
                pfs_url=bad_address,
                routing_mode=RoutingMode.PFS,
                service_registry=service_registry,
                node_network_id=chain_id,
                token_network_registry_address=
                token_network_registry_address_test_default,
                pathfinding_max_fee=DEFAULT_PATHFINDING_MAX_FEE,
            )

    # Addresses of token network registries of pfs and client conflict, should exit the client
    response = mocked_json_response(response_data=json_data)
    with pytest.raises(RaidenError):
        with patch.object(requests, "get", return_value=response):
            _ = configure_pfs_or_exit(
                pfs_url="http://foo",
                routing_mode=RoutingMode.PFS,
                service_registry=service_registry,
                node_network_id=chain_id,
                token_network_registry_address=TokenNetworkRegistryAddress(
                    to_canonical_address(
                        "0x2222222222222222222222222222222222222221")),
                pathfinding_max_fee=DEFAULT_PATHFINDING_MAX_FEE,
            )

    # ChainIDs of pfs and client conflict, should exit the client
    response = mocked_json_response(response_data=json_data)
    with pytest.raises(RaidenError):
        with patch.object(requests, "get", return_value=response):
            configure_pfs_or_exit(
                pfs_url="http://foo",
                routing_mode=RoutingMode.PFS,
                service_registry=service_registry,
                node_network_id=ChainID(chain_id + 1),
                token_network_registry_address=
                token_network_registry_address_test_default,
                pathfinding_max_fee=DEFAULT_PATHFINDING_MAX_FEE,
            )
Example #15
0
 def mocked_json_response_with_sleep(**kwargs):  # pylint: disable=unused-argument
     gevent.sleep(0.2)
     return mocked_json_response()