def test_receive_lockedtransfer_invalidnonce(raiden_network, number_of_nodes,
                                             deposit, token_addresses,
                                             reveal_timeout, network_wait):
    app0, app1, app2 = raiden_network
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(app0), app0.raiden.default_registry.address,
        token_address)
    assert token_network_address
    channel0 = get_channelstate(app0, app1, token_network_address)

    amount = 10
    payment_identifier = PaymentID(1)
    secrethash = transfer(
        initiator_app=app0,
        target_app=app2,
        token_address=token_address,
        amount=PaymentAmount(10),
        identifier=payment_identifier,
        timeout=network_wait * number_of_nodes,
    )

    repeated_nonce = Nonce(1)
    expiration = reveal_timeout * 2
    mediated_transfer_message = LockedTransfer(
        chain_id=UNIT_CHAIN_ID,
        message_identifier=make_message_identifier(),
        payment_identifier=payment_identifier,
        nonce=repeated_nonce,
        token_network_address=token_network_address,
        token=token_address,
        channel_identifier=channel0.identifier,
        transferred_amount=TokenAmount(amount),
        locked_amount=TokenAmount(amount),
        recipient=app1.raiden.address,
        locksroot=make_locksroot(),
        lock=Lock(amount=PaymentWithFeeAmount(amount),
                  expiration=expiration,
                  secrethash=UNIT_SECRETHASH),
        target=app2.raiden.address,
        initiator=app0.raiden.address,
        signature=EMPTY_SIGNATURE,
        metadata=Metadata(routes=[
            RouteMetadata(route=[app1.raiden.address, app2.raiden.address])
        ]),
    )

    sign_and_inject(mediated_transfer_message, app0.raiden.signer, app1)

    with block_timeout_for_transfer_by_secrethash(app1.raiden, secrethash):
        wait_assert(
            assert_synced_channel_state,
            token_network_address,
            app0,
            deposit - amount,
            [],
            app1,
            deposit + amount,
            [],
        )
def test_mediated_transfer(
    raiden_network, number_of_nodes, deposit, token_addresses, network_wait
):
    app0, app1, app2 = 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
    )

    amount = PaymentAmount(10)
    secrethash = transfer(
        initiator_app=app0,
        target_app=app2,
        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,
            [],
        )
    with block_timeout_for_transfer_by_secrethash(app1.raiden, secrethash):
        wait_assert(
            assert_succeeding_transfer_invariants,
            token_network_address,
            app1,
            deposit - amount,
            [],
            app2,
            deposit + amount,
            [],
        )
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 test_mediated_transfer_messages_out_of_order(  # pylint: disable=unused-argument
        raiden_network, deposit, token_addresses, network_wait):
    """Raiden must properly handle repeated locked transfer messages."""
    app0, app1, app2 = raiden_network

    app1_wait_for_message = WaitForMessage()
    app2_wait_for_message = WaitForMessage()

    app1.raiden.message_handler = app1_wait_for_message
    app2.raiden.message_handler = app2_wait_for_message

    secret = factories.make_secret(0)
    secrethash = sha256_secrethash(secret)

    # Save the messages, these will be processed again
    app1_mediatedtransfer = app1_wait_for_message.wait_for_message(
        LockedTransfer, {"lock": {
            "secrethash": secrethash
        }})
    app2_mediatedtransfer = app2_wait_for_message.wait_for_message(
        LockedTransfer, {"lock": {
            "secrethash": secrethash
        }})
    # Wait until the node receives a reveal secret to redispatch the locked
    # transfer message
    app1_revealsecret = app1_wait_for_message.wait_for_message(
        RevealSecret, {"secret": secret})
    app2_revealsecret = app2_wait_for_message.wait_for_message(
        RevealSecret, {"secret": secret})

    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)

    amount = 10
    identifier = 1
    transfer_received = app0.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=amount,
        target=app2.raiden.address,
        identifier=identifier,
        secret=secret,
    )

    # - Wait until reveal secret is received to replay the message
    # - The secret is revealed backwards, app2 should be first
    # - The locked transfer is sent before the secret reveal, so the mediated
    #   transfers async results must be set and `get_nowait` can be used
    app2_revealsecret.get(timeout=network_wait)
    mediated_transfer_msg = app2_mediatedtransfer.get_nowait()
    app2.raiden.message_handler.handle_message_lockedtransfer(
        app2.raiden, mediated_transfer_msg)

    app1_revealsecret.get(timeout=network_wait)
    app1.raiden.message_handler.handle_message_lockedtransfer(
        app1.raiden, app1_mediatedtransfer.get_nowait())

    transfer_received.payment_done.wait()
    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,
            [],
        )

    with block_timeout_for_transfer_by_secrethash(app2.raiden, secrethash):
        wait_assert(
            assert_succeeding_transfer_invariants,
            token_network_address,
            app1,
            deposit - amount,
            [],
            app2,
            deposit + amount,
            [],
        )
def test_mediated_transfer_with_entire_deposit(raiden_network, number_of_nodes,
                                               token_addresses, deposit,
                                               network_wait) -> None:
    app0, app1, app2 = 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)

    # The test uses internal routing at the moment, that's why this is set like that.
    # However, the actual calculated fee is 3 instead of the 4 calculated here, therefore
    # the amounts are adjusted below
    fee1 = FeeAmount(int(deposit * INTERNAL_ROUTING_DEFAULT_FEE_PERC))
    fee_margin1 = calculate_fee_margin(deposit, fee1)
    fee_difference = 1
    secrethash = transfer_and_assert_path(
        path=raiden_network,
        token_address=token_address,
        amount=deposit - fee1 - fee_margin1,
        identifier=PaymentID(1),
        timeout=network_wait * number_of_nodes,
    )

    with block_timeout_for_transfer_by_secrethash(app1.raiden, secrethash):
        wait_assert(
            func=assert_succeeding_transfer_invariants,
            token_network_address=token_network_address,
            app0=app0,
            balance0=0,
            pending_locks0=[],
            app1=app1,
            balance1=deposit * 2,
            pending_locks1=[],
        )
    with block_timeout_for_transfer_by_secrethash(app2.raiden, secrethash):
        wait_assert(
            func=assert_succeeding_transfer_invariants,
            token_network_address=token_network_address,
            app0=app1,
            balance0=fee1 - fee_difference,
            pending_locks0=[],
            app1=app2,
            balance1=deposit * 2 - fee1 + fee_difference,
            pending_locks1=[],
        )

    app2_capacity = 2 * deposit - fee1
    fee2 = FeeAmount(
        int(round(app2_capacity * INTERNAL_ROUTING_DEFAULT_FEE_PERC)))
    fee_margin2 = calculate_fee_margin(app2_capacity, fee2)
    reverse_path = list(raiden_network[::-1])
    transfer_and_assert_path(
        path=reverse_path,
        token_address=token_address,
        amount=app2_capacity - fee2 - fee_margin2,
        identifier=PaymentID(2),
        timeout=network_wait * number_of_nodes,
    )

    with block_timeout_for_transfer_by_secrethash(app1.raiden, secrethash):
        wait_assert(
            func=assert_succeeding_transfer_invariants,
            token_network_address=token_network_address,
            app0=app0,
            balance0=2 * deposit - fee2 + fee_difference,
            pending_locks0=[],
            app1=app1,
            balance1=fee2 - fee_difference,
            pending_locks1=[],
        )
    with block_timeout_for_transfer_by_secrethash(app2.raiden, secrethash):
        wait_assert(
            func=assert_succeeding_transfer_invariants,
            token_network_address=token_network_address,
            app0=app1,
            balance0=deposit * 2 - fee_difference,
            pending_locks0=[],
            app1=app2,
            balance1=fee_difference,
            pending_locks1=[],
        )
def test_mediated_transfer_with_entire_deposit(raiden_network, number_of_nodes,
                                               token_addresses, deposit,
                                               network_wait):
    app0, app1, app2 = 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)

    fee1 = int(deposit * INTERNAL_ROUTING_DEFAULT_FEE_PERC)
    secrethash = transfer_and_assert_path(
        path=raiden_network,
        token_address=token_address,
        amount=deposit - fee1,
        identifier=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,
            0,
            [],
            app1,
            deposit * 2,
            [],
        )
    with block_timeout_for_transfer_by_secrethash(app2.raiden, secrethash):
        wait_assert(
            assert_succeeding_transfer_invariants,
            token_network_address,
            app1,
            fee1,
            [],
            app2,
            deposit * 2 - fee1,
            [],
        )

    app2_capacity = 2 * deposit - fee1
    fee2 = int(round(app2_capacity * INTERNAL_ROUTING_DEFAULT_FEE_PERC))
    reverse_path = list(raiden_network[::-1])
    transfer_and_assert_path(
        path=reverse_path,
        token_address=token_address,
        amount=app2_capacity - fee2,
        identifier=2,
        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,
            2 * deposit - fee2,
            [],
            app1,
            fee2,
            [],
        )
    with block_timeout_for_transfer_by_secrethash(app2.raiden, secrethash):
        wait_assert(
            assert_succeeding_transfer_invariants,
            token_network_address,
            app1,
            deposit * 2,
            [],
            app2,
            0,
            [],
        )
def test_pfs_send_capacity_updates_during_mediated_transfer(
        raiden_network, number_of_nodes, deposit, token_addresses,
        network_wait):
    """
    Tests that PFSCapacityUpdates and PFSFeeUpdates are being
    sent during a mediated transfer.
    """
    app0, app1, app2 = 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)

    # There have been two PFSCapacityUpdates and two PFSFeeUpdates per channel per node
    assert len(get_messages(app0)) == 4
    # The mediator has two channels
    assert len(get_messages(app1)) == 8
    assert len(get_messages(app2)) == 4

    # Reset message lists for more understandable assertions
    reset_messages(app0)
    reset_messages(app1)
    reset_messages(app2)

    amount = PaymentAmount(10)
    secrethash = transfer(
        initiator_app=app0,
        target_app=app2,
        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,
            [],
        )

    with block_timeout_for_transfer_by_secrethash(app1.raiden, secrethash):
        wait_assert(
            assert_succeeding_transfer_invariants,
            token_network_address,
            app1,
            deposit - amount,
            [],
            app2,
            deposit + amount,
            [],
        )

    # Initiator: we expect one PFSCapacityUpdate when locking and one when unlocking
    messages0 = get_messages(app0)
    assert len(messages0) == 2
    assert len([x for x in messages0 if isinstance(x, PFSCapacityUpdate)]) == 2
    assert len([x for x in messages0 if isinstance(x, PFSFeeUpdate)]) == 0

    # Mediator:
    #   incoming channel: we expect one PFSCapacityUpdate when locking and one when unlocking
    #   outgoing channel: we expect one PFSCapacityUpdate when funds are unlocked
    messages1 = get_messages(app1)
    assert len(messages1) == 3
    assert len([x for x in messages1 if isinstance(x, PFSCapacityUpdate)]) == 3
    assert len([x for x in messages1 if isinstance(x, PFSFeeUpdate)]) == 0

    # Target: we expect one PFSCapacityUpdate when funds are unlocked
    messages2 = get_messages(app2)
    assert len(messages2) == 1
    assert len([x for x in messages2 if isinstance(x, PFSCapacityUpdate)]) == 1
    assert len([x for x in messages2 if isinstance(x, PFSFeeUpdate)]) == 0