コード例 #1
0
def test_pfs_handler_handle_paymentsentsuccess_without_feedback_token():
    (
        raiden,
        pfs_handler,
        token_network_registry_address,
        token_network_address,
        route,
        _,
    ) = setup_pfs_handler_test(set_feedback_token=False)

    payment_id = make_payment_id()
    amount = PaymentAmount(123)
    target = TargetAddress(route[-1])
    raiden.targets_to_identifiers_to_statuses[target][payment_id] = Mock()

    route_failed_event = EventPaymentSentSuccess(
        token_network_registry_address=token_network_registry_address,
        token_network_address=token_network_address,
        identifier=payment_id,
        amount=amount,
        target=TargetAddress(target),
        secret=make_secret(),
        route=route,
    )

    with patch("raiden.raiden_event_handler.post_pfs_feedback"
               ) as pfs_feedback_handler:
        pfs_handler.on_raiden_events(
            raiden=raiden,
            chain_state=cast(
                ChainState,
                raiden.wal.state_manager.current_state),  # type: ignore
            events=[route_failed_event],
        )
    assert not pfs_feedback_handler.called
コード例 #2
0
def test_channel_withdraw(
    raiden_network: List[App],
    token_addresses: List[TokenAddress],
    deposit: TokenAmount,
    retry_timeout: float,
) -> None:
    """ Withdraw funds after a mediated transfer."""
    alice_app, bob_app = raiden_network
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(alice_app), alice_app.raiden.default_registry.address, token_address
    )
    assert token_network_address

    token_proxy = bob_app.raiden.proxy_manager.token(token_address, BLOCK_ID_LATEST)
    bob_initial_balance = token_proxy.balance_of(bob_app.raiden.address)

    message_handler = WaitForMessage()
    bob_app.raiden.message_handler = message_handler

    alice_to_bob_amount = PaymentAmount(10)
    identifier = PaymentID(1)
    target = TargetAddress(bob_app.raiden.address)
    secret = factories.make_secret()

    payment_status = alice_app.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=alice_to_bob_amount,
        target=target,
        identifier=identifier,
        secret=secret,
    )
    wait_for_unlock = bob_app.raiden.message_handler.wait_for_message(
        Unlock, {"payment_identifier": identifier}
    )
    with block_offset_timeout(alice_app.raiden):
        wait_for_unlock.get()
        msg = (
            f"transfer from {to_checksum_address(alice_app.raiden.address)} "
            f"to {to_checksum_address(bob_app.raiden.address)} failed."
        )
        assert payment_status.payment_done.get(), msg

    total_withdraw = WithdrawAmount(deposit + alice_to_bob_amount)

    bob_alice_channel_state = get_channelstate(bob_app, alice_app, token_network_address)
    bob_app.raiden.withdraw(
        canonical_identifier=bob_alice_channel_state.canonical_identifier,
        total_withdraw=total_withdraw,
    )

    waiting.wait_for_withdraw_complete(
        raiden=bob_app.raiden,
        canonical_identifier=bob_alice_channel_state.canonical_identifier,
        total_withdraw=total_withdraw,
        retry_timeout=retry_timeout,
    )

    bob_balance_after_withdraw = token_proxy.balance_of(bob_app.raiden.address)
    assert bob_initial_balance + total_withdraw == bob_balance_after_withdraw
コード例 #3
0
def test_close_regression(raiden_network, deposit, token_addresses):
    """ The python api was using the wrong balance proof to close the channel,
    thus the close was failing if a transfer was made.
    """
    app0, app1 = raiden_network
    token_address = token_addresses[0]

    api1 = RaidenAPI(app0.raiden)
    api2 = RaidenAPI(app1.raiden)

    registry_address = app0.raiden.default_registry.address
    channel_list = api1.get_channel_list(registry_address, token_address,
                                         app1.raiden.address)
    channel12 = channel_list[0]

    token_proxy = app0.raiden.proxy_manager.token(token_address,
                                                  BLOCK_ID_LATEST)
    node1_balance_before = token_proxy.balance_of(api1.address)
    node2_balance_before = token_proxy.balance_of(api2.address)

    # Initialize app2 balance proof and close the channel
    amount = PaymentAmount(10)
    identifier = PaymentID(42)
    secret, secrethash = factories.make_secret_with_hash()
    timeout = block_offset_timeout(app1.raiden, "Transfer timed out.")
    with watch_for_unlock_failures(*raiden_network), timeout:
        assert api1.transfer_and_wait(
            registry_address=registry_address,
            token_address=token_address,
            amount=amount,
            target=TargetAddress(api2.address),
            identifier=identifier,
            secret=secret,
        )
        timeout.exception_to_throw = ValueError(
            "Waiting for transfer received success in the WAL timed out.")
        result = waiting.wait_for_received_transfer_result(
            raiden=app1.raiden,
            payment_identifier=identifier,
            amount=amount,
            retry_timeout=app1.raiden.alarm.sleep_time,
            secrethash=secrethash,
        )

    msg = f"Unexpected transfer result: {str(result)}"
    assert result == waiting.TransferWaitResult.UNLOCKED, msg

    api2.channel_close(registry_address, token_address, api1.address)

    waiting.wait_for_settle(
        app0.raiden,
        app0.raiden.default_registry.address,
        token_address,
        [channel12.identifier],
        app0.raiden.alarm.sleep_time,
    )
    node1_expected_balance = node1_balance_before + deposit - amount
    node2_expected_balance = node2_balance_before + deposit + amount
    assert token_proxy.balance_of(api1.address) == node1_expected_balance
    assert token_proxy.balance_of(api2.address) == node2_expected_balance
コード例 #4
0
def test_regression_revealsecret_after_secret(
        raiden_network: List[App],
        token_addresses: List[TokenAddress]) -> None:
    """ A RevealSecret message received after a Unlock message must be cleanly
    handled.
    """
    app0, app1, app2 = raiden_network
    token = token_addresses[0]
    identifier = PaymentID(1)
    token_network_registry_address = app0.raiden.default_registry.address
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(app0), token_network_registry_address, token)
    assert token_network_address, "The fixtures must register the token"

    payment_status = app0.raiden.mediated_transfer_async(
        token_network_address,
        amount=PaymentAmount(1),
        target=TargetAddress(app2.raiden.address),
        identifier=identifier,
    )
    with watch_for_unlock_failures(*raiden_network):
        assert payment_status.payment_done.wait()

    assert app1.raiden.wal, "The fixtures must start the app."
    event = raiden_events_search_for_item(app1.raiden, SendSecretReveal, {})
    assert event

    reveal_secret = RevealSecret(
        message_identifier=make_message_identifier(),
        secret=event.secret,
        signature=EMPTY_SIGNATURE,
    )
    app2.raiden.sign(reveal_secret)
    app1.raiden.on_messages([reveal_secret])
コード例 #5
0
def event_filter_for_payments(
    event: Event,
    chain_state: Optional[ChainState] = None,
    partner_address: Optional[Address] = None,
    token_address: Optional[TokenAddress] = None,
) -> bool:
    """Filters payment history related events depending on given arguments

    - If no other args are given, all payment related events match.
    - If a token network identifier is given then only payment events for that match.
    - If a partner is also given then if the event is a payment sent event and the
      target matches it's returned. If it's a payment received and the initiator matches.
      then it's returned.
    - If a token address is given then all events are filtered to be about that token.
    """
    sent_and_target_matches = isinstance(
        event, (EventPaymentSentFailed, EventPaymentSentSuccess)
    ) and (partner_address is None or event.target == TargetAddress(partner_address))
    received_and_initiator_matches = isinstance(event, EventPaymentReceivedSuccess) and (
        partner_address is None or event.initiator == InitiatorAddress(partner_address)
    )

    token_address_matches = True
    if token_address:
        assert chain_state, "Filtering for token_address without a chain state is an error"
        token_network = get_token_network_by_address(
            chain_state=chain_state,
            token_network_address=event.token_network_address,  # type: ignore
        )
        if not token_network:
            token_address_matches = False
        else:
            token_address_matches = token_address == token_network.token_address

    return token_address_matches and (sent_and_target_matches or received_and_initiator_matches)
コード例 #6
0
def test_mediated_transfer_calls_pfs(raiden_network, token_addresses):
    app0, = 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)

    with patch("raiden.routing.query_paths",
               return_value=([], None)) as patched:

        app0.raiden.start_mediated_transfer_with_secret(
            token_network_address=token_network_address,
            amount=10,
            target=factories.HOP1,
            identifier=1,
            secret=b"1" * 32,
        )
        assert not patched.called

        # Setup PFS config
        app0.raiden.config["pfs_config"] = PFSConfig(
            info=PFSInfo(
                url="mock-address",
                chain_id=app0.raiden.rpc_client.chain_id,
                token_network_registry_address=token_network_registry_address,
                payment_address=factories.make_address(),
                message="",
                operator="",
                version="",
                price=TokenAmount(0),
            ),
            maximum_fee=TokenAmount(100),
            iou_timeout=BlockNumber(100),
            max_paths=5,
        )

        app0.raiden.start_mediated_transfer_with_secret(
            token_network_address=token_network_address,
            amount=11,
            target=factories.HOP2,
            identifier=2,
            secret=b"2" * 32,
        )
        assert patched.call_count == 1

        # Mediator should not re-query PFS
        locked_transfer = factories.create(
            factories.LockedTransferProperties(
                amount=TokenAmount(5),
                initiator=factories.HOP1,
                target=TargetAddress(factories.HOP2),
                sender=factories.HOP1,
                pkey=factories.HOP1_KEY,
                token=token_address,
                canonical_identifier=factories.make_canonical_identifier(
                    token_network_address=token_network_address),
            ))
        app0.raiden.mediate_mediated_transfer(locked_transfer)
        assert patched.call_count == 1
コード例 #7
0
def test_automatic_secret_registration(
    raiden_chain: List[App], token_addresses: List[TokenAddress]
) -> None:
    app0, app1 = raiden_chain
    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

    hold_event_handler = app1.raiden.raiden_event_handler
    message_handler = app1.raiden.message_handler

    msg = "hold event handler necessary to control messages"
    assert isinstance(hold_event_handler, HoldRaidenEventHandler), msg
    assert isinstance(message_handler, WaitForMessage), msg

    amount = PaymentAmount(100)
    identifier = factories.make_payment_id()

    target = TargetAddress(app1.raiden.address)
    (secret, secrethash) = factories.make_secret_with_hash()

    hold_event_handler.hold_secretrequest_for(secrethash=secrethash)
    locked_transfer_received = message_handler.wait_for_message(LockedTransfer, {})

    app0.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=amount,
        target=target,
        identifier=identifier,
        secret=secret,
    )

    # Wait for app1 to receive the locked transfer.
    locked_transfer_received.wait()

    # Stop app0 to avoid sending the unlock, this must be done after the locked
    # transfer is sent.
    app0.raiden.transport.stop()

    reveal_secret = RevealSecret(
        message_identifier=MessageID(random.randint(0, UINT64_MAX)),
        secret=secret,
        signature=EMPTY_SIGNATURE,
    )
    app0.raiden.sign(reveal_secret)
    message_handler.on_messages(app1.raiden, [reveal_secret])

    chain_state = views.state_from_app(app1)

    secrethash = sha256_secrethash(secret)
    target_task = chain_state.payment_mapping.secrethashes_to_task[secrethash]
    lock_expiration = target_task.target_state.transfer.lock.expiration  # type: ignore
    app1.raiden.proxy_manager.client.wait_until_block(target_block_number=lock_expiration)

    assert app1.raiden.default_secret_registry.is_secret_registered(
        secrethash=secrethash, block_identifier=BLOCK_ID_LATEST
    )
コード例 #8
0
    def handle_message_lockedtransfer(
        raiden: "RaidenService", message: LockedTransfer  # pylint: disable=unused-argument
    ) -> List[StateChange]:
        secrethash = message.lock.secrethash
        # We must check if the secret was registered against the latest block,
        # even if the block is forked away and the transaction that registers
        # the secret is removed from the blockchain. The rationale here is that
        # someone else does know the secret, regardless of the chain state, so
        # the node must not use it to start a payment.
        #
        # For this particular case, it's preferable to use `latest` instead of
        # having a specific block_hash, because it's preferable to know if the secret
        # was ever known, rather than having a consistent view of the blockchain.
        registered = raiden.default_secret_registry.is_secret_registered(
            secrethash=secrethash, block_identifier=BLOCK_ID_LATEST
        )
        if registered:
            log.warning(
                f"Ignoring received locked transfer with secrethash {to_hex(secrethash)} "
                f"since it is already registered in the secret registry"
            )
            return []

        assert message.sender, "Invalid message dispatched, it should be signed"

        from_transfer = lockedtransfersigned_from_message(message)
        from_hop = HopState(
            node_address=message.sender,
            # pylint: disable=E1101
            channel_identifier=from_transfer.balance_proof.channel_identifier,
        )
        if message.target == TargetAddress(raiden.address):
            raiden.immediate_health_check_for(Address(message.initiator))
            return [
                ActionInitTarget(
                    from_hop=from_hop,
                    transfer=from_transfer,
                    balance_proof=from_transfer.balance_proof,
                    sender=from_transfer.balance_proof.sender,
                )
            ]
        else:
            route_states = routing.resolve_routes(
                routes=message.metadata.routes,
                token_network_address=from_transfer.balance_proof.token_network_address,
                chain_state=views.state_from_raiden(raiden),
            )
            return [
                ActionInitMediator(
                    from_hop=from_hop,
                    route_states=route_states,
                    from_transfer=from_transfer,
                    balance_proof=from_transfer.balance_proof,
                    sender=from_transfer.balance_proof.sender,
                )
            ]
コード例 #9
0
def test_pfs_handler_handle_paymentsentsuccess_with_feedback_token():
    (
        raiden,
        pfs_handler,
        token_network_registry_address,
        token_network_address,
        route,
        feedback_uuid,
    ) = setup_pfs_handler_test(set_feedback_token=True)

    payment_id = make_payment_id()
    amount = PaymentAmount(123)
    target = TargetAddress(route[-1])
    raiden.targets_to_identifiers_to_statuses[target][payment_id] = Mock()

    route_failed_event = EventPaymentSentSuccess(
        token_network_registry_address=token_network_registry_address,
        token_network_address=token_network_address,
        identifier=payment_id,
        amount=amount,
        target=TargetAddress(target),
        secret=make_secret(),
        route=route,
    )

    with patch("raiden.raiden_event_handler.post_pfs_feedback"
               ) as pfs_feedback_handler:
        pfs_handler.on_raiden_event(
            raiden=raiden,
            chain_state=cast(
                ChainState,
                raiden.wal.state_manager.current_state),  # type: ignore
            event=route_failed_event,
        )
    assert pfs_feedback_handler.called
    assert pfs_feedback_handler.call_args == call(
        pfs_config=raiden.config.pfs_config,
        route=route,
        routing_mode=RoutingMode.PRIVATE,
        successful=True,
        token=feedback_uuid,
        token_network_address=token_network_address,
    )
コード例 #10
0
def test_insufficient_funds(raiden_network: List[RaidenService],
                            token_addresses, deposit):
    app0, app1 = raiden_network
    token_address = token_addresses[0]

    result = RaidenAPI(app0).transfer_and_wait(
        app0.default_registry.address,
        token_address,
        deposit + 1,
        target=TargetAddress(app1.address),
    )
    assert isinstance(result.payment_done.get(), EventPaymentSentFailed)
コード例 #11
0
def test_same_addresses_for_payment(raiden_network: List[RaidenService],
                                    token_addresses):
    app0, _ = raiden_network
    api0 = RaidenAPI(app0)
    registry_address = app0.default_registry.address
    token_address = token_addresses[0]

    with pytest.raises(SamePeerAddress):
        api0.transfer_and_wait(
            registry_address=registry_address,
            token_address=token_address,
            target=TargetAddress(app0.address),
            amount=PaymentAmount(1),
        )
コード例 #12
0
def _transfer_expired(
    initiator_app: App,
    target_app: App,
    token_address: TokenAddress,
    amount: PaymentAmount,
    identifier: PaymentID,
    timeout: Optional[float] = None,
) -> SecretHash:
    assert identifier is not None, "The identifier must be provided"
    assert isinstance(target_app.raiden.message_handler, WaitForMessage)

    # This timeout has to be larger then the lock expiration. The lock
    # expiration unit is block numbers, and its value is defined relative to
    # the node's reveal timeout configuration. For the integration tests the
    # reveal timeout is chosen proportionally to the number of nodes, 90
    # seconds is a rough default that should work with the standard
    # configuration.
    if timeout is None:
        timeout = 90

    secret, secrethash = make_secret_with_hash()
    wait_for_remove_expired_lock = target_app.raiden.message_handler.wait_for_message(
        LockExpired, {"secrethash": secrethash}
    )

    token_network_registry_address = initiator_app.raiden.default_registry.address
    token_network_address = views.get_token_network_address_by_token_address(
        chain_state=views.state_from_app(initiator_app),
        token_network_registry_address=token_network_registry_address,
        token_address=token_address,
    )
    assert token_network_address
    payment_status = initiator_app.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=amount,
        target=TargetAddress(target_app.raiden.address),
        identifier=identifier,
        secret=secret,
        secrethash=secrethash,
    )

    with Timeout(seconds=timeout):
        wait_for_remove_expired_lock.get()
        msg = (
            f"transfer from {to_checksum_address(initiator_app.raiden.address)} "
            f"to {to_checksum_address(target_app.raiden.address)} did not expire."
        )
        assert payment_status.payment_done.get() is False, msg

    return secrethash
コード例 #13
0
def test_received_lockedtransfer_closedchannel(
    raiden_network: List[RaidenService], reveal_timeout, token_addresses, deposit
):
    app0, app1 = raiden_network
    registry_address = app0.default_registry.address
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_raiden(app0), app0.default_registry.address, token_address
    )
    assert token_network_address
    channel0 = get_channelstate(app0, app1, token_network_address)

    RaidenAPI(app1).channel_close(registry_address, token_address, app0.address)

    app0.rpc_client.wait_until_block(
        target_block_number=BlockNumber(app0.rpc_client.block_number() + 1)
    )

    # Now receive one mediated transfer for the closed channel
    lock_amount = LockedAmount(10)
    payment_identifier = PaymentID(1)
    expiration = reveal_timeout * 2
    mediated_transfer_message = LockedTransfer(
        chain_id=UNIT_CHAIN_ID,
        message_identifier=make_message_identifier(),
        payment_identifier=payment_identifier,
        nonce=Nonce(1),
        token_network_address=token_network_address,
        token=token_address,
        channel_identifier=channel0.identifier,
        transferred_amount=TokenAmount(0),
        locked_amount=lock_amount,
        recipient=app1.address,
        locksroot=make_locksroot(),
        lock=Lock(
            amount=PaymentWithFeeAmount(lock_amount),
            expiration=expiration,
            secrethash=UNIT_SECRETHASH,
        ),
        target=TargetAddress(app1.address),
        initiator=InitiatorAddress(app0.address),
        signature=EMPTY_SIGNATURE,
        metadata=Metadata(routes=[RouteMetadata(route=[app1.address])]),
    )

    sign_and_inject(mediated_transfer_message, app0.signer, app1)

    # The local state must not change since the channel is already closed
    assert_synced_channel_state(token_network_address, app0, deposit, [], app1, deposit, [])
コード例 #14
0
ファイル: transfer.py プロジェクト: sekmet/raiden
def _transfer_unlocked(
    initiator_app: RaidenService,
    target_app: RaidenService,
    token_address: TokenAddress,
    amount: PaymentAmount,
    identifier: PaymentID,
    timeout: Optional[float] = None,
    expect_unlock_failures: bool = False,
    route_states: List[RouteState] = None,
) -> SecretHash:
    assert isinstance(target_app.message_handler, WaitForMessage)

    if timeout is None:
        timeout = 10

    wait_for_unlock = target_app.message_handler.wait_for_message(
        Unlock, {"payment_identifier": identifier})

    token_network_registry_address = initiator_app.default_registry.address
    token_network_address = views.get_token_network_address_by_token_address(
        chain_state=views.state_from_raiden(initiator_app),
        token_network_registry_address=token_network_registry_address,
        token_address=token_address,
    )
    assert token_network_address
    secret, secrethash = make_secret_with_hash()
    payment_status = initiator_app.mediated_transfer_async(
        token_network_address=token_network_address,
        amount=amount,
        target=TargetAddress(target_app.address),
        identifier=identifier,
        secret=secret,
        secrethash=secrethash,
        route_states=route_states,
    )

    apps = [initiator_app, target_app]
    with watch_for_unlock_failures(
            *apps) if not expect_unlock_failures else nullcontext():
        with Timeout(seconds=timeout):
            wait_for_unlock.get()
            msg = (
                f"transfer from {to_checksum_address(initiator_app.address)} "
                f"to {to_checksum_address(target_app.address)} failed.")
            assert payment_status.payment_done.get(), msg

    return secrethash
コード例 #15
0
def test_event_filter_for_payments():
    secret = factories.make_secret()
    identifier = PaymentID(1)
    target = TargetAddress(factories.make_address())
    event1 = EventPaymentSentSuccess(
        token_network_registry_address=UNIT_TOKEN_NETWORK_REGISTRY_ADDRESS,
        token_network_address=UNIT_TOKEN_NETWORK_ADDRESS,
        identifier=identifier,
        amount=PaymentAmount(5),
        target=target,
        secret=secret,
        route=[],
    )
    assert event_filter_for_payments(event=event1, partner_address=None)
    assert event_filter_for_payments(event=event1,
                                     partner_address=Address(target))
    assert not event_filter_for_payments(
        event=event1, partner_address=factories.make_address())

    initiator = InitiatorAddress(factories.make_address())
    event2 = EventPaymentReceivedSuccess(
        token_network_registry_address=UNIT_TOKEN_NETWORK_REGISTRY_ADDRESS,
        token_network_address=UNIT_TOKEN_NETWORK_ADDRESS,
        identifier=identifier,
        amount=TokenAmount(5),
        initiator=initiator,
    )
    assert event_filter_for_payments(event=event2, partner_address=None)
    assert event_filter_for_payments(event=event2,
                                     partner_address=Address(initiator))
    assert not event_filter_for_payments(
        event=event2, partner_address=factories.make_address())

    event3 = EventPaymentSentFailed(
        token_network_registry_address=UNIT_TOKEN_NETWORK_REGISTRY_ADDRESS,
        token_network_address=UNIT_TOKEN_NETWORK_ADDRESS,
        identifier=identifier,
        target=target,
        reason="whatever",
    )
    assert event_filter_for_payments(event=event3, partner_address=None)
    assert event_filter_for_payments(event=event3,
                                     partner_address=Address(target))
    assert not event_filter_for_payments(
        event=event3, partner_address=factories.make_address())
コード例 #16
0
def test_failsfast_lockedtransfer_exceeding_distributable(
    raiden_network: List[RaidenService], token_addresses, deposit
):
    app0, app1 = raiden_network
    token_address = token_addresses[0]

    token_network_registry_address = app0.default_registry.address
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_raiden(app0), token_network_registry_address, token_address
    )
    assert token_network_address
    payment_status = app0.mediated_transfer_async(
        token_network_address, deposit * 2, TargetAddress(app1.address), identifier=PaymentID(1)
    )

    assert isinstance(payment_status.payment_done.get(timeout=5), EventPaymentSentFailed)
    assert payment_status.payment_done.successful()

    assert_synced_channel_state(token_network_address, app0, deposit, [], app1, deposit, [])
コード例 #17
0
def test_failfast_lockedtransfer_nochannel(raiden_network: List[RaidenService], token_addresses):
    """When the node has no channels it should fail without raising exceptions."""
    token_address = token_addresses[0]
    app0, app1 = raiden_network

    amount = 10
    token_network_registry_address = app0.default_registry.address

    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_raiden(app0), token_network_registry_address, token_address
    )
    assert token_network_address, "token must be registered by the fixtures."

    payment_status = app0.mediated_transfer_async(
        token_network_address,
        PaymentAmount(amount),
        TargetAddress(app1.address),
        identifier=PaymentID(1),
    )
    assert isinstance(payment_status.payment_done.get(), EventPaymentSentFailed)
コード例 #18
0
def test_receive_lockedtransfer_invalidrecipient(
    raiden_network: List[RaidenService], token_addresses, reveal_timeout, deposit
):
    app0, app1 = raiden_network
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_raiden(app0), app0.default_registry.address, token_address
    )
    assert token_network_address
    channel0 = get_channelstate(app0, app1, token_network_address)

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

    sign_and_inject(mediated_transfer_message, app0.signer, app1)

    assert_synced_channel_state(token_network_address, app0, deposit, [], app1, deposit, [])
コード例 #19
0
def test_v1_event_payment_sent_failed_schema():
    event = EventPaymentSentFailed(
        token_network_registry_address=UNIT_TOKEN_NETWORK_REGISTRY_ADDRESS,
        token_network_address=UNIT_TOKEN_NETWORK_ADDRESS,
        identifier=PaymentID(1),
        target=TargetAddress(factories.make_address()),
        reason="whatever",
    )
    log_time = datetime.datetime.now()

    timestamped = TimestampedEvent(event, log_time)

    dumped = EventPaymentSentFailedSchema().dump(timestamped)

    expected = {
        "event": "EventPaymentSentFailed",
        "log_time": log_time.isoformat(),
        "reason": "whatever",
    }

    assert all(dumped.get(key) == value for key, value in expected.items())
コード例 #20
0
def _transfer_secret_not_requested(
    initiator_app: App,
    target_app: App,
    token_address: TokenAddress,
    amount: PaymentAmount,
    identifier: PaymentID,
    timeout: Optional[float] = None,
) -> SecretHash:
    if timeout is None:
        timeout = 10

    secret, secrethash = make_secret_with_hash()

    assert isinstance(target_app.raiden.raiden_event_handler,
                      HoldRaidenEventHandler)
    hold_secret_request = target_app.raiden.raiden_event_handler.hold(
        SendSecretRequest, {"secrethash": secrethash})

    token_network_registry_address = initiator_app.raiden.default_registry.address
    token_network_address = views.get_token_network_address_by_token_address(
        chain_state=views.state_from_app(initiator_app),
        token_network_registry_address=token_network_registry_address,
        token_address=token_address,
    )
    assert token_network_address
    initiator_app.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=amount,
        target=TargetAddress(target_app.raiden.address),
        identifier=identifier,
        secret=secret,
        secrethash=secrethash,
    )

    with Timeout(seconds=timeout):
        hold_secret_request.get()

    return secrethash
コード例 #21
0
def test_different_view_of_last_bp_during_unlock(
    raiden_chain: List[App],
    number_of_nodes,
    token_addresses,
    deposit,
    network_wait,
    retry_timeout,
    blockchain_type,
):
    """Test for https://github.com/raiden-network/raiden/issues/3196#issuecomment-449163888"""
    # Topology:
    #
    #  0 -> 1 -> 2
    #
    app0, app1, app2 = raiden_chain
    token_address = token_addresses[0]
    token_network_registry_address = app0.raiden.default_registry.address
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(app0), token_network_registry_address,
        token_address)
    assert token_network_address
    token_proxy = app0.raiden.proxy_manager.token(token_address)
    initial_balance0 = token_proxy.balance_of(app0.raiden.address)
    initial_balance1 = token_proxy.balance_of(app1.raiden.address)

    # make a transfer to test the path app0 -> app1 -> app2
    identifier_path = PaymentID(1)
    amount_path = PaymentAmount(1)
    transfer(
        initiator_app=app0,
        target_app=app2,
        token_address=token_address,
        amount=amount_path,
        identifier=identifier_path,
        timeout=network_wait * number_of_nodes,
    )

    # drain the channel app1 -> app2
    identifier_drain = PaymentID(2)
    amount_drain = PaymentAmount(deposit * 8 // 10)
    transfer(
        initiator_app=app1,
        target_app=app2,
        token_address=token_address,
        amount=amount_drain,
        identifier=identifier_drain,
        timeout=network_wait,
    )

    with gevent.Timeout(network_wait):
        wait_assert(
            assert_synced_channel_state,
            token_network_address,
            app0,
            deposit - amount_path,
            [],
            app1,
            deposit + amount_path,
            [],
        )
    with gevent.Timeout(network_wait):
        wait_assert(
            assert_synced_channel_state,
            token_network_address,
            app1,
            deposit - amount_path - amount_drain,
            [],
            app2,
            deposit + amount_path + amount_drain,
            [],
        )

    # app0 -> app1 -> app2 is the only available path, but the channel app1 ->
    # app2 doesn't have capacity, so a refund will be sent on app1 -> app0
    identifier_refund = PaymentID(3)
    amount_refund = PaymentAmount(50)
    fee = calculate_fee_for_amount(amount_refund)
    fee_margin = calculate_fee_margin(amount_refund, fee)
    amount_refund_with_fees = amount_refund + fee + fee_margin
    payment_status = app0.raiden.mediated_transfer_async(
        token_network_address, amount_refund,
        TargetAddress(app2.raiden.address), identifier_refund)
    msg = "there is no path with capacity, the transfer must fail"
    assert isinstance(payment_status.payment_done.wait(),
                      EventPaymentSentFailed), msg

    # A lock structure with the correct amount

    send_locked = raiden_events_search_for_item(
        app0.raiden,
        SendLockedTransfer,
        {"transfer": {
            "lock": {
                "amount": amount_refund_with_fees
            }
        }},
    )
    assert send_locked
    secrethash = send_locked.transfer.lock.secrethash

    send_refund = raiden_events_search_for_item(app1.raiden,
                                                SendRefundTransfer, {})
    assert send_refund

    lock = send_locked.transfer.lock
    refund_lock = send_refund.transfer.lock
    assert lock.amount == refund_lock.amount
    assert lock.secrethash
    assert lock.expiration
    assert lock.secrethash == refund_lock.secrethash

    # Both channels have the amount locked because of the refund message
    with gevent.Timeout(network_wait):
        wait_assert(
            assert_synced_channel_state,
            token_network_address,
            app0,
            deposit - amount_path,
            [lock],
            app1,
            deposit + amount_path,
            [refund_lock],
        )
    with gevent.Timeout(network_wait):
        wait_assert(
            assert_synced_channel_state,
            token_network_address,
            app1,
            deposit - amount_path - amount_drain,
            [],
            app2,
            deposit + amount_path + amount_drain,
            [],
        )

    # Additional checks for LockExpired causing nonce mismatch after refund transfer:
    # https://github.com/raiden-network/raiden/issues/3146#issuecomment-447378046
    # At this point make sure that the initiator has not deleted the payment task
    assert secrethash in state_from_raiden(
        app0.raiden).payment_mapping.secrethashes_to_task

    with dont_handle_node_change_network_state():
        # now app1 goes offline
        app1.raiden.stop()
        app1.raiden.greenlet.get()
        assert not app1.raiden

        # Wait for lock expiration so that app0 sends a LockExpired
        wait_for_block(
            raiden=app0.raiden,
            block_number=BlockNumber(
                channel.get_sender_expiration_threshold(lock.expiration) + 1),
            retry_timeout=retry_timeout,
        )

        # make sure that app0 sent a lock expired message for the secrethash
        wait_for_raiden_event(app0.raiden, SendLockExpired,
                              {"secrethash": secrethash}, retry_timeout)

        # now app0 closes the channel
        RaidenAPI(app0.raiden).channel_close(
            registry_address=token_network_registry_address,
            token_address=token_address,
            partner_address=app1.raiden.address,
        )

    count = 0
    on_raiden_event_original = app1.raiden.raiden_event_handler.on_raiden_event

    def patched_on_raiden_event(raiden, chain_state, event):
        if type(event) == ContractSendChannelUpdateTransfer:
            nonlocal count
            count += 1

        on_raiden_event_original(raiden, chain_state, event)

    setattr(app1.raiden.raiden_event_handler, "on_raiden_event",
            patched_on_raiden_event)  # NOQA

    # and now app1 comes back online
    app1.raiden.start()
    # test for https://github.com/raiden-network/raiden/issues/3216
    assert count == 1, "Update transfer should have only been called once during restart"
    channel_identifier = get_channelstate(app0, app1,
                                          token_network_address).identifier

    # and we wait for settlement
    wait_for_settle(
        raiden=app0.raiden,
        token_network_registry_address=token_network_registry_address,
        token_address=token_address,
        channel_ids=[channel_identifier],
        retry_timeout=app0.raiden.alarm.sleep_time,
    )

    timeout = 30 if blockchain_type == "parity" else 10
    with gevent.Timeout(timeout):
        unlock_app0 = wait_for_state_change(
            app0.raiden,
            ContractReceiveChannelBatchUnlock,
            {"receiver": app0.raiden.address},
            retry_timeout,
        )
    assert unlock_app0
    assert unlock_app0.returned_tokens == amount_refund_with_fees
    with gevent.Timeout(timeout):
        unlock_app1 = wait_for_state_change(
            app1.raiden,
            ContractReceiveChannelBatchUnlock,
            {"receiver": app1.raiden.address},
            retry_timeout,
        )
    assert unlock_app1
    assert unlock_app1.returned_tokens == amount_refund_with_fees
    final_balance0 = token_proxy.balance_of(app0.raiden.address)
    final_balance1 = token_proxy.balance_of(app1.raiden.address)

    assert final_balance0 - deposit - initial_balance0 == -1
    assert final_balance1 - deposit - initial_balance1 == 1
コード例 #22
0
def test_pending_transfers_endpoint(raiden_network: List[RaidenService],
                                    token_addresses):
    initiator, mediator, target = raiden_network
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_raiden(mediator), mediator.default_registry.address,
        token_address)
    assert token_network_address

    amount_to_send = PaymentAmount(150)
    # Remove when https://github.com/raiden-network/raiden/issues/4982 is tackled
    expected_fee = FeeAmount(
        int(amount_to_send * INTERNAL_ROUTING_DEFAULT_FEE_PERC))
    fee_margin = calculate_fee_margin(amount_to_send, expected_fee)
    # This is 0,4% of ~150, so ~1.2 which gets rounded to 1
    actual_fee = 1
    identifier = PaymentID(42)

    initiator_server = prepare_api_server(initiator)
    mediator_server = prepare_api_server(mediator)
    target_server = prepare_api_server(target)

    target.message_handler = target_wait = WaitForMessage()
    mediator.message_handler = mediator_wait = WaitForMessage()

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

    request = grequests.get(
        api_url_for(mediator_server,
                    "pending_transfers_resource_by_token",
                    token_address=token_address))
    response = request.send().response
    assert response.status_code == 200 and response.content == b"[]"

    target_hold = target.raiden_event_handler
    assert isinstance(
        target_hold,
        HoldRaidenEventHandler), "test app must use HoldRaidenEventHandler"

    target_hold.hold_secretrequest_for(secrethash=secrethash)

    initiator.mediated_transfer_async(
        token_network_address=token_network_address,
        amount=PaymentAmount(amount_to_send - expected_fee - fee_margin),
        target=TargetAddress(target.address),
        identifier=identifier,
        secret=secret,
        route_states=[
            create_route_state_for_route(
                apps=raiden_network,
                token_address=token_address,
                fee_estimate=expected_fee,
            )
        ],
    )

    transfer_arrived = target_wait.wait_for_message(LockedTransfer,
                                                    {"payment_identifier": 42})
    transfer_arrived.wait(timeout=30.0)

    for server in (initiator_server, mediator_server, target_server):
        request = grequests.get(
            api_url_for(server, "pending_transfers_resource"))
        response = request.send().response
        assert response.status_code == 200
        content = json.loads(response.content)
        assert len(content) == 1
        assert content[0]["payment_identifier"] == str(identifier)
        if server == target_server:
            assert content[0]["locked_amount"] == str(amount_to_send -
                                                      actual_fee)
        else:
            assert content[0]["locked_amount"] == str(amount_to_send)
        assert content[0]["token_address"] == to_checksum_address(
            token_address)
        assert content[0]["token_network_address"] == to_checksum_address(
            token_network_address)

    mediator_unlock = mediator_wait.wait_for_message(Unlock, {})
    target_unlock = target_wait.wait_for_message(Unlock, {})
    target_hold.release_secretrequest_for(target, secrethash)
    gevent.joinall({mediator_unlock, target_unlock}, raise_error=True)

    for server in (initiator_server, mediator_server, target_server):
        request = grequests.get(
            api_url_for(server, "pending_transfers_resource"))
        response = request.send().response
        assert response.status_code == 200 and response.content == b"[]"

    request = grequests.get(
        api_url_for(
            initiator_server,
            "pending_transfers_resource_by_token",
            token_address=to_hex(b"notaregisteredtokenn"),
        ))
    response = request.send().response
    assert response.status_code == 404 and b"Token" in response.content

    request = grequests.get(
        api_url_for(
            target_server,
            "pending_transfers_resource_by_token_and_partner",
            token_address=token_address,
            partner_address=to_hex(b"~nonexistingchannel~"),
        ))
    response = request.send().response
    assert response.status_code == 404 and b"Channel" in response.content
コード例 #23
0
def test_payment_statuses_are_restored(  # pylint: disable=unused-argument
        raiden_network: List[App], token_addresses: List[TokenAddress],
        network_wait: float):
    """ Test that when the Raiden is restarted, the dictionary of
    `targets_to_identifiers_to_statuses` is populated before the transport
    is started.
    This should happen because if a client gets restarted during a transfer
    cycle, once restarted, the client will proceed with the cycle
    until the transfer is successfully sent. However, the dictionary
    `targets_to_identifiers_to_statuses` will not contain the payment
    identifiers that were originally registered when the previous client
    started the transfers.
    Related issue: https://github.com/raiden-network/raiden/issues/3432
    """
    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)
    assert token_network_address

    target_address = TargetAddress(app1.raiden.address)

    # make a few transfers from app0 to app1
    amount = PaymentAmount(1)
    spent_amount = TokenAmount(7)

    for identifier in range(spent_amount):
        # Make sure the transfer is not completed
        secret = make_secret(identifier)

        assert isinstance(app0.raiden.raiden_event_handler,
                          HoldRaidenEventHandler)  # for mypy
        app0.raiden.raiden_event_handler.hold(SendSecretReveal,
                                              {"secret": secret})

        identifier = identifier + 1
        payment_status = app0.raiden.mediated_transfer_async(
            token_network_address=token_network_address,
            amount=amount,
            target=target_address,
            identifier=PaymentID(identifier),
            secret=secret,
        )
        assert payment_status.payment_identifier == identifier

    app0_restart = App(
        config=app0.config,
        rpc_client=app0.raiden.rpc_client,
        proxy_manager=app0.raiden.proxy_manager,
        query_start_block=BlockNumber(0),
        default_registry=app0.raiden.default_registry,
        default_secret_registry=app0.raiden.default_secret_registry,
        default_service_registry=app0.raiden.default_service_registry,
        default_one_to_n_address=app0.raiden.default_one_to_n_address,
        default_msc_address=app0.raiden.default_msc_address,
        transport=MatrixTransport(
            config=app0.raiden.config.transport,
            environment=app0.raiden.config.environment_type),
        raiden_event_handler=RaidenEventHandler(),
        message_handler=MessageHandler(),
        routing_mode=RoutingMode.PRIVATE,
    )
    app0.stop()
    del app0  # from here on the app0_restart should be used
    # stop app1 to make sure that we don't complete the transfers before our checks
    app1.stop()
    app0_restart.start()

    # Check that the payment statuses were restored properly after restart
    for identifier in range(spent_amount):
        identifier = PaymentID(identifier + 1)
        mapping = app0_restart.raiden.targets_to_identifiers_to_statuses
        status = mapping[target_address][identifier]
        assert status.amount == 1
        assert status.payment_identifier == identifier
        assert status.token_network_address == token_network_address

    app1.start()  # now that our checks are done start app1 again

    with watch_for_unlock_failures(*raiden_network):
        waiting.wait_for_healthy(app0_restart.raiden, app1.raiden.address,
                                 network_wait)

        waiting.wait_for_payment_balance(
            raiden=app1.raiden,
            token_network_registry_address=token_network_registry_address,
            token_address=token_address,
            partner_address=app0_restart.raiden.address,
            target_address=Address(target_address),
            target_balance=spent_amount,
            retry_timeout=network_wait,
        )

    # Check that payments are completed after both nodes come online after restart
    for identifier in range(spent_amount):
        assert raiden_events_search_for_item(
            app0_restart.raiden,
            EventPaymentSentSuccess,
            {
                "identifier": identifier + 1,
                "amount": 1
            },
        )
コード例 #24
0
def test_regression_multiple_revealsecret(
        raiden_network: List[App],
        token_addresses: List[TokenAddress]) -> None:
    """ Multiple RevealSecret messages arriving at the same time must be
    handled properly.

    Unlock handling followed these steps:

        The Unlock message arrives
        The secret is registered
        The channel is updated and the correspoding lock is removed
        * A balance proof for the new channel state is created and sent to the
          payer
        The channel is unregistered for the given secrethash

    The step marked with an asterisk above introduced a context-switch. This
    allowed a second Reveal Unlock message to be handled before the channel was
    unregistered. And because the channel was already updated an exception was raised
    for an unknown secret.
    """
    app0, app1 = raiden_network
    token = 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)
    assert token_network_address
    channelstate_0_1 = get_channelstate(app0, app1, token_network_address)

    payment_identifier = PaymentID(1)
    secret, secrethash = make_secret_with_hash()
    expiration = BlockExpiration(app0.raiden.get_block_number() + 100)
    lock_amount = PaymentWithFeeAmount(10)
    lock = Lock(amount=lock_amount,
                expiration=expiration,
                secrethash=secrethash)

    nonce = Nonce(1)
    transferred_amount = TokenAmount(0)
    mediated_transfer = LockedTransfer(
        chain_id=UNIT_CHAIN_ID,
        message_identifier=make_message_identifier(),
        payment_identifier=payment_identifier,
        nonce=nonce,
        token_network_address=token_network_address,
        token=token,
        channel_identifier=channelstate_0_1.identifier,
        transferred_amount=transferred_amount,
        locked_amount=LockedAmount(lock_amount),
        recipient=app1.raiden.address,
        locksroot=Locksroot(lock.lockhash),
        lock=lock,
        target=TargetAddress(app1.raiden.address),
        initiator=InitiatorAddress(app0.raiden.address),
        signature=EMPTY_SIGNATURE,
        metadata=Metadata(routes=[
            RouteMetadata(route=[app0.raiden.address, app1.raiden.address])
        ]),
    )
    app0.raiden.sign(mediated_transfer)
    app1.raiden.on_messages([mediated_transfer])

    reveal_secret = RevealSecret(message_identifier=make_message_identifier(),
                                 secret=secret,
                                 signature=EMPTY_SIGNATURE)
    app0.raiden.sign(reveal_secret)

    token_network_address = channelstate_0_1.token_network_address
    unlock = Unlock(
        chain_id=UNIT_CHAIN_ID,
        message_identifier=make_message_identifier(),
        payment_identifier=payment_identifier,
        nonce=Nonce(mediated_transfer.nonce + 1),
        token_network_address=token_network_address,
        channel_identifier=channelstate_0_1.identifier,
        transferred_amount=TokenAmount(lock_amount),
        locked_amount=LockedAmount(0),
        locksroot=LOCKSROOT_OF_NO_LOCKS,
        secret=secret,
        signature=EMPTY_SIGNATURE,
    )
    app0.raiden.sign(unlock)

    messages = [unlock, reveal_secret]
    receive_method = app1.raiden.on_messages
    wait = set(
        gevent.spawn_later(0.1, receive_method, [data]) for data in messages)

    gevent.joinall(wait, raise_error=True)
コード例 #25
0
def test_receive_secrethashtransfer_unknown(
        raiden_network: List[RaidenService], token_addresses):
    app0 = raiden_network[0]
    token_address = token_addresses[0]

    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_raiden(app0), app0.default_registry.address,
        token_address)
    assert token_network_address

    other_key = HOP1_KEY
    other_signer = LocalSigner(other_key)
    canonical_identifier = factories.make_canonical_identifier(
        token_network_address=token_network_address)

    amount = TokenAmount(10)
    locksroot = Locksroot(make_32bytes())
    refund_transfer_message = factories.create(
        factories.RefundTransferProperties(
            payment_identifier=PaymentID(1),
            nonce=Nonce(1),
            token=token_address,
            canonical_identifier=canonical_identifier,
            transferred_amount=amount,
            recipient=TargetAddress(app0.address),
            locksroot=locksroot,
            amount=amount,
            secret=UNIT_SECRET,
        ))
    sign_and_inject(refund_transfer_message, other_signer, app0)

    unlock = Unlock(
        chain_id=UNIT_CHAIN_ID,
        message_identifier=make_message_identifier(),
        payment_identifier=PaymentID(1),
        nonce=Nonce(1),
        channel_identifier=canonical_identifier.channel_identifier,
        token_network_address=token_network_address,
        transferred_amount=amount,
        locked_amount=LockedAmount(0),
        locksroot=locksroot,
        secret=UNIT_SECRET,
        signature=EMPTY_SIGNATURE,
    )
    sign_and_inject(unlock, other_signer, app0)

    secret_request_message = SecretRequest(
        message_identifier=make_message_identifier(),
        payment_identifier=PaymentID(1),
        secrethash=UNIT_SECRETHASH,
        amount=PaymentAmount(1),
        expiration=refund_transfer_message.lock.expiration,
        signature=EMPTY_SIGNATURE,
    )
    sign_and_inject(secret_request_message, other_signer, app0)

    reveal_secret_message = RevealSecret(
        message_identifier=make_message_identifier(),
        secret=UNIT_SECRET,
        signature=EMPTY_SIGNATURE)
    sign_and_inject(reveal_secret_message, other_signer, app0)
コード例 #26
0
def test_clear_closed_queue(raiden_network: List[App], token_addresses,
                            network_wait):
    """ Closing a channel clears the respective message queue. """
    app0, app1 = raiden_network

    hold_event_handler = app1.raiden.raiden_event_handler
    assert isinstance(hold_event_handler, HoldRaidenEventHandler)

    registry_address = app0.raiden.default_registry.address
    token_address = token_addresses[0]
    chain_state0 = views.state_from_app(app0)
    token_network_address = views.get_token_network_address_by_token_address(
        chain_state0, app0.raiden.default_registry.address, token_address)
    assert token_network_address
    token_network = views.get_token_network_by_address(chain_state0,
                                                       token_network_address)
    assert token_network

    channel_identifier = get_channelstate(app0, app1,
                                          token_network_address).identifier

    assert (channel_identifier
            in token_network.partneraddresses_to_channelidentifiers[
                app1.raiden.address])

    target = app1.raiden.address
    secret = Secret(keccak(target))
    secrethash = sha256_secrethash(secret)
    hold_event_handler.hold_secretrequest_for(secrethash=secrethash)

    # make an unconfirmed transfer to ensure the nodes have communicated
    amount = PaymentAmount(10)
    payment_identifier = PaymentID(1337)
    app0.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=amount,
        target=TargetAddress(target),
        identifier=payment_identifier,
        secret=secret,
    )

    app1.raiden.transport.stop()
    app1.raiden.transport.greenlet.get()

    # make sure to wait until the queue is created
    def has_initiator_events():
        assert app0.raiden.wal, "raiden server must have been started"
        initiator_events = app0.raiden.wal.storage.get_events()
        return search_for_item(initiator_events, SendLockedTransfer, {})

    assert wait_until(has_initiator_events, network_wait)

    # assert the specific queue is present
    chain_state0 = views.state_from_app(app0)
    queues0 = views.get_all_messagequeues(chain_state=chain_state0)
    assert [
        (queue_id, queue) for queue_id, queue in queues0.items()
        if queue_id.recipient == app1.raiden.address and queue_id.
        canonical_identifier.channel_identifier == channel_identifier and queue
    ]

    # A ChannelClose event will be generated, this will be polled by both apps
    RaidenAPI(app0.raiden).channel_close(registry_address, token_address,
                                         app1.raiden.address)

    with block_offset_timeout(app0.raiden, "Could not get close event"):
        waiting.wait_for_close(
            app0.raiden,
            registry_address,
            token_address,
            [channel_identifier],
            app0.raiden.alarm.sleep_time,
        )

    # assert all queues with this partner are gone or empty
    chain_state0 = views.state_from_app(app0)
    queues0 = views.get_all_messagequeues(chain_state=chain_state0)
    assert not [(queue_id, queue) for queue_id, queue in queues0.items()
                if queue_id.recipient == app1.raiden.address and queue]

    chain_state1 = views.state_from_app(app1)
    queues1 = views.get_all_messagequeues(chain_state=chain_state1)
    assert not [(queue_id, queue) for queue_id, queue in queues1.items()
                if queue_id.recipient == app0.raiden.address and queue]
コード例 #27
0
def test_mediated_transfer_calls_pfs(raiden_chain: List[App], token_addresses: List[TokenAddress]):
    app0, app1, app2 = raiden_chain
    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
    )
    assert token_network_address, "Fixture token_addresses don't have correspoding token_network"

    with patch("raiden.routing.query_paths", return_value=([], None)) as patched:

        app0.raiden.start_mediated_transfer_with_secret(
            token_network_address=token_network_address,
            amount=PaymentAmount(10),
            target=TargetAddress(app1.raiden.address),
            identifier=PaymentID(1),
            secret=Secret(b"1" * 32),
        )
        assert not patched.called

        # Setup PFS config
        app0.raiden.config.pfs_config = PFSConfig(
            info=PFSInfo(
                url="mock-address",
                chain_id=app0.raiden.rpc_client.chain_id,
                token_network_registry_address=token_network_registry_address,
                user_deposit_address=factories.make_address(),
                payment_address=factories.make_address(),
                confirmed_block_number=chain_state.block_number,
                message="",
                operator="",
                version="",
                price=TokenAmount(0),
            ),
            maximum_fee=TokenAmount(100),
            iou_timeout=BlockTimeout(100),
            max_paths=5,
        )

        app0.raiden.start_mediated_transfer_with_secret(
            token_network_address=token_network_address,
            amount=PaymentAmount(11),
            target=TargetAddress(app2.raiden.address),
            identifier=PaymentID(2),
            secret=Secret(b"2" * 32),
        )
        assert patched.call_count == 1

        # Mediator should not re-query PFS
        locked_transfer = factories.create(
            factories.LockedTransferProperties(
                amount=TokenAmount(5),
                initiator=factories.HOP1,
                target=TargetAddress(app2.raiden.address),
                sender=factories.HOP1,
                pkey=factories.HOP1_KEY,
                token=token_address,
                canonical_identifier=factories.make_canonical_identifier(
                    token_network_address=token_network_address
                ),
            )
        )
        app0.raiden.on_messages([locked_transfer])
        assert patched.call_count == 1
コード例 #28
0
def transfer_and_assert_path(
    path: List[App],
    token_address: TokenAddress,
    amount: PaymentAmount,
    identifier: PaymentID,
    timeout: float = 10,
) -> SecretHash:
    """ Nice to read shortcut to make successful LockedTransfer.

    Note:
        This utility *does not enforce the path*, however it does check the
        provided path is used in totality. It's the responsability of the
        caller to ensure the path will be used. All nodes in `path` are
        synched.
    """
    assert identifier is not None, "The identifier must be provided"
    secret, secrethash = make_secret_with_hash()

    first_app = path[0]
    token_network_registry_address = first_app.raiden.default_registry.address
    token_network_address = views.get_token_network_address_by_token_address(
        chain_state=views.state_from_app(first_app),
        token_network_registry_address=token_network_registry_address,
        token_address=token_address,
    )
    assert token_network_address

    for app in path:
        assert isinstance(app.raiden.message_handler, WaitForMessage)

        msg = "The apps must be on the same token network registry"
        assert app.raiden.default_registry.address == token_network_registry_address, msg

        app_token_network_address = views.get_token_network_address_by_token_address(
            chain_state=views.state_from_app(app),
            token_network_registry_address=token_network_registry_address,
            token_address=token_address,
        )

        msg = "The apps must be synchronized with the blockchain"
        assert token_network_address == app_token_network_address, msg

    pairs = zip(path[:-1], path[1:])
    receiving = list()
    for from_app, to_app in pairs:
        from_channel_state = views.get_channelstate_by_token_network_and_partner(
            chain_state=views.state_from_app(from_app),
            token_network_address=token_network_address,
            partner_address=to_app.raiden.address,
        )
        to_channel_state = views.get_channelstate_by_token_network_and_partner(
            chain_state=views.state_from_app(to_app),
            token_network_address=token_network_address,
            partner_address=from_app.raiden.address,
        )

        msg = (
            f"{to_checksum_address(from_app.raiden.address)} does not have a channel with "
            f"{to_checksum_address(to_app.raiden.address)} needed to transfer through the "
            f"path {[to_checksum_address(app.raiden.address) for app in path]}."
        )
        assert from_channel_state, msg
        assert to_channel_state, msg

        msg = (
            f"channel among {to_checksum_address(from_app.raiden.address)} and "
            f"{to_checksum_address(to_app.raiden.address)} must be open to be used for a "
            f"transfer")
        assert channel.get_status(
            from_channel_state) == ChannelState.STATE_OPENED, msg
        assert channel.get_status(
            to_channel_state) == ChannelState.STATE_OPENED, msg

        receiving.append((to_app, to_channel_state.identifier))

    assert isinstance(app.raiden.message_handler, WaitForMessage)
    results = [
        app.raiden.message_handler.wait_for_message(
            Unlock,
            {
                "channel_identifier": channel_identifier,
                "token_network_address": token_network_address,
                "payment_identifier": identifier,
                "secret": secret,
            },
        ) for app, channel_identifier in receiving
    ]

    last_app = path[-1]
    payment_status = first_app.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=amount,
        target=TargetAddress(last_app.raiden.address),
        identifier=identifier,
        secret=secret,
    )

    msg = (f"transfer from {to_checksum_address(first_app.raiden.address)} "
           f"to {to_checksum_address(last_app.raiden.address)} for amount "
           f"{amount} failed")
    exception = RuntimeError(msg + " due to Timeout")
    with watch_for_unlock_failures(*path):
        with Timeout(seconds=timeout, exception=exception):
            gevent.wait(results)
            assert payment_status.payment_done.get(), msg

    return secrethash
コード例 #29
0
    def on_transfer(self, transfer: EventPaymentReceivedSuccess) -> None:
        """ This handles the echo logic, as described in
        https://github.com/raiden-network/raiden/issues/651:

            - for transfers with an amount that satisfies `amount % 3 == 0`, it sends a transfer
            with an amount of `amount - 1` back to the initiator
            - for transfers with a "lucky number" amount `amount == 7` it does not send anything
            back immediately -- after having received "lucky number transfers" from 7 different
            addresses it sends a transfer with `amount = 49` to one randomly chosen one
            (from the 7 lucky addresses)
            - consecutive entries to the lucky lottery will receive the current pool size as the
            `echo_amount`
            - for all other transfers it sends a transfer with the same `amount` back to the
            initiator
        """
        echo_amount = PaymentAmount(0)
        if transfer.amount % 3 == 0:
            log.info(
                "Received amount divisible by three",
                node=to_checksum_address(self.api.address),
                initiator=to_checksum_address(transfer.initiator),
                amount=transfer.amount,
                identifier=transfer.identifier,
            )
            echo_amount = PaymentAmount(transfer.amount - 1)

        elif transfer.amount == 7:
            log.info(
                "Received lottery entry",
                node=to_checksum_address(self.api.address),
                initiator=to_checksum_address(transfer.initiator),
                amount=transfer.amount,
                identifier=transfer.identifier,
                poolsize=self.lottery_pool.qsize(),
            )

            # obtain a local copy of the pool
            pool = self.lottery_pool.copy()
            tickets = [pool.get() for _ in range(pool.qsize())]
            assert pool.empty()
            del pool

            if any(ticket.initiator == transfer.initiator for ticket in tickets):
                assert transfer not in tickets
                log.debug(
                    "Duplicate lottery entry",
                    node=to_checksum_address(self.api.address),
                    initiator=to_checksum_address(transfer.initiator),
                    identifier=transfer.identifier,
                    poolsize=len(tickets),
                )
                # signal the poolsize to the participant
                echo_amount = PaymentAmount(len(tickets))

            # payout
            elif len(tickets) == 6:
                log.info("Payout!")
                # reset the pool
                assert self.lottery_pool.qsize() == 6
                self.lottery_pool = Queue()

                # add the new participant
                tickets.append(transfer)

                # choose the winner
                transfer = random.choice(tickets)
                echo_amount = PaymentAmount(49)
            else:
                self.lottery_pool.put(transfer)

        else:
            log.debug(
                "Received transfer",
                node=to_checksum_address(self.api.address),
                initiator=to_checksum_address(transfer.initiator),
                amount=transfer.amount,
                identifier=transfer.identifier,
            )
            echo_amount = PaymentAmount(transfer.amount)

        if echo_amount:
            echo_identifier = PaymentID(transfer.identifier + echo_amount)
            log.debug(
                "Sending echo transfer",
                node=to_checksum_address(self.api.address),
                target=to_checksum_address(transfer.initiator),
                amount=echo_amount,
                original_identifier=transfer.identifier,
                echo_identifier=echo_identifier,
                token_address=to_checksum_address(self.token_address),
                num_handled_transfers=self.num_handled_transfers + 1,
            )

            self.api.transfer(
                registry_address=self.api.raiden.default_registry.address,
                token_address=self.token_address,
                amount=echo_amount,
                target=TargetAddress(transfer.initiator),
                identifier=echo_identifier,
            )

        self.num_handled_transfers += 1
コード例 #30
0
def test_send_queued_messages_after_restart(  # pylint: disable=unused-argument
    raiden_network: List[App],
    deposit: TokenAmount,
    token_addresses: List[TokenAddress],
    network_wait: float,
):
    """Test re-sending of undelivered messages on node restart"""
    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)
    assert token_network_address

    number_of_transfers = 7
    amount_per_transfer = PaymentAmount(1)
    total_transferred_amount = TokenAmount(amount_per_transfer *
                                           number_of_transfers)

    # Make sure none of the transfers will be sent before the restart
    transfers = []
    for secret_seed in range(number_of_transfers):
        secret = make_secret(secret_seed)
        secrethash = sha256_secrethash(secret)
        transfers.append((create_default_identifier(), amount_per_transfer,
                          secret, secrethash))

        assert isinstance(app0.raiden.raiden_event_handler,
                          HoldRaidenEventHandler)  # for mypy
        app0.raiden.raiden_event_handler.hold(
            SendLockedTransfer,
            {"transfer": {
                "lock": {
                    "secrethash": secrethash
                }
            }})

    for identifier, amount, secret, _ in transfers:
        app0.raiden.mediated_transfer_async(
            token_network_address=token_network_address,
            amount=amount,
            target=TargetAddress(app1.raiden.address),
            identifier=identifier,
            secret=secret,
        )

    app0.stop()

    # Restart the app. The pending transfers must be processed.
    new_transport = MatrixTransport(
        config=app0.raiden.config.transport,
        environment=app0.raiden.config.environment_type)
    raiden_event_handler = RaidenEventHandler()
    message_handler = MessageHandler()
    app0_restart = App(
        config=app0.config,
        rpc_client=app0.raiden.rpc_client,
        proxy_manager=app0.raiden.proxy_manager,
        query_start_block=BlockNumber(0),
        default_registry=app0.raiden.default_registry,
        default_secret_registry=app0.raiden.default_secret_registry,
        default_service_registry=app0.raiden.default_service_registry,
        default_one_to_n_address=app0.raiden.default_one_to_n_address,
        default_msc_address=app0.raiden.default_msc_address,
        transport=new_transport,
        raiden_event_handler=raiden_event_handler,
        message_handler=message_handler,
        routing_mode=RoutingMode.PRIVATE,
    )

    del app0
    app0_restart.start()

    # XXX: There is no synchronization among the app and the test, so it is
    # possible between `start` and the check below that some of the transfers
    # have completed, making it flaky.
    #
    # Make sure the transfers are in the queue and fail otherwise.
    chain_state = views.state_from_raiden(app0_restart.raiden)
    for _, _, _, secrethash in transfers:
        msg = "The secrethashes of the pending transfers must be in the queue after a restart."
        assert secrethash in chain_state.payment_mapping.secrethashes_to_task, msg

    with watch_for_unlock_failures(*raiden_network):
        exception = RuntimeError(
            "Timeout while waiting for balance update for app0")
        with gevent.Timeout(20, exception=exception):
            waiting.wait_for_payment_balance(
                raiden=app0_restart.raiden,
                token_network_registry_address=token_network_registry_address,
                token_address=token_address,
                partner_address=app1.raiden.address,
                target_address=app1.raiden.address,
                target_balance=total_transferred_amount,
                retry_timeout=network_wait,
            )
        exception = RuntimeError(
            "Timeout while waiting for balance update for app1")
        with gevent.Timeout(20, exception=exception):
            waiting.wait_for_payment_balance(
                raiden=app1.raiden,
                token_network_registry_address=token_network_registry_address,
                token_address=token_address,
                partner_address=app0_restart.raiden.address,
                target_address=app1.raiden.address,
                target_balance=total_transferred_amount,
                retry_timeout=network_wait,
            )

    assert_synced_channel_state(
        token_network_address,
        app0_restart,
        Balance(deposit - total_transferred_amount),
        [],
        app1,
        Balance(deposit + total_transferred_amount),
        [],
    )
    new_transport.stop()