예제 #1
0
def test_get_state_change_with_transfer_by_secrethash():
    serializer = JSONSerializer()
    storage = SerializedSQLiteStorage(":memory:", serializer)

    mediator_secret, mediator_secrethash = factories.make_secret_with_hash()
    channels = factories.mediator_make_channel_pair()
    mediator_transfer = factories.create(
        factories.LockedTransferSignedStateProperties(
            secret=mediator_secret,
            target=channels.partner_address(1),
            initiator=channels.partner_address(0),
        )
    )
    mediator_state_change = factories.mediator_make_init_action(channels, mediator_transfer)

    target_secret, target_secrethash = factories.make_secret_with_hash()
    from_channel = factories.create(
        factories.NettingChannelStateProperties(
            partner_state=factories.NettingChannelEndStateProperties(
                balance=100, address=factories.make_address()
            )
        )
    )
    target_transfer = factories.create(
        factories.LockedTransferSignedStateProperties(
            secret=target_secret,
            target=channels.our_address(0),
            initiator=channels.partner_address(1),
        )
    )

    target_state_change = ActionInitTarget(
        from_hop=HopState(
            node_address=from_channel.partner_state.address,
            channel_identifier=from_channel.canonical_identifier.channel_identifier,
        ),
        transfer=target_transfer,
        balance_proof=target_transfer.balance_proof,
        sender=target_transfer.balance_proof.sender,  # pylint: disable=no-member
    )

    assert storage.count_state_changes() == 0
    storage.write_state_changes([mediator_state_change, target_state_change])
    assert storage.count_state_changes() == 2

    restored = get_state_change_with_transfer_by_secrethash(storage, mediator_secrethash)
    assert isinstance(restored.data, ActionInitMediator)
    assert restored.data.from_transfer == mediator_transfer

    restored = get_state_change_with_transfer_by_secrethash(storage, target_secrethash)
    assert isinstance(restored.data, ActionInitTarget)
    assert restored.data.transfer == target_transfer
예제 #2
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
예제 #3
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
    )
예제 #4
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)
    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 = 10
    identifier = 42
    secret, secrethash = factories.make_secret_with_hash()
    assert api1.transfer_and_wait(
        registry_address=registry_address,
        token_address=token_address,
        amount=amount,
        target=api2.address,
        identifier=identifier,
        secret=secret,
        transfer_timeout=10,
    )
    exception = ValueError(
        "Waiting for transfer received success in the WAL timed out")
    with gevent.Timeout(seconds=5, exception=exception):
        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
예제 #5
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
예제 #6
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
예제 #7
0
def test_api_payments_with_secret_and_hash(api_server_test_instance: APIServer,
                                           raiden_network: List[RaidenService],
                                           token_addresses):
    _, app1 = raiden_network
    token_address = token_addresses[0]
    target_address = app1.address
    secret, secret_hash = factories.make_secret_with_hash()

    our_address = api_server_test_instance.rest_api.raiden_api.address

    payment = {
        "initiator_address": to_checksum_address(our_address),
        "target_address": to_checksum_address(target_address),
        "token_address": to_checksum_address(token_address),
        "amount": DEFAULT_AMOUNT,
        "identifier": DEFAULT_ID,
    }

    request = grequests.post(
        api_url_for(
            api_server_test_instance,
            "token_target_paymentresource",
            token_address=to_checksum_address(token_address),
            target_address=to_checksum_address(target_address),
        ),
        json={
            "amount": DEFAULT_AMOUNT,
            "identifier": DEFAULT_ID,
            "secret": to_hex(secret),
            "secret_hash": to_hex(secret_hash),
        },
    )
    with watch_for_unlock_failures(*raiden_network):
        response = request.send().response
    assert_proper_response(response)
    json_response = get_json_response(response)
    assert_payment_secret_and_hash(json_response, payment)
    assert to_hex(secret) == json_response["secret"]
    assert to_hex(secret_hash) == json_response["secret_hash"]
예제 #8
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
예제 #9
0
def test_payment_events_endpoints(api_server_test_instance: APIServer,
                                  raiden_network: List[RaidenService],
                                  token_addresses):
    app0, app1, app2 = raiden_network

    token_address0 = token_addresses[0]
    token_address1 = token_addresses[1]

    app0_server = api_server_test_instance
    app1_server = prepare_api_server(app1)
    app2_server = prepare_api_server(app2)

    # Payment 1: app0 is sending tokens of token0 to app1
    identifier1 = PaymentID(10)
    amount1 = PaymentAmount(10)
    secret1, secrethash1 = factories.make_secret_with_hash()
    request = grequests.post(
        api_url_for(
            app0_server,
            "token_target_paymentresource",
            token_address=to_checksum_address(token_address0),
            target_address=to_checksum_address(app1.address),
        ),
        json={
            "amount": str(amount1),
            "identifier": str(identifier1),
            "secret": to_hex(secret1)
        },
    )
    request.send()

    # Payment 2: app0 is sending some tokens of token1 to app2
    identifier2 = PaymentID(20)
    amount2 = PaymentAmount(10)
    secret2, secrethash2 = factories.make_secret_with_hash()
    request = grequests.post(
        api_url_for(
            app0_server,
            "token_target_paymentresource",
            token_address=to_checksum_address(token_address1),
            target_address=to_checksum_address(app2.address),
        ),
        json={
            "amount": str(amount2),
            "identifier": str(identifier2),
            "secret": to_hex(secret2)
        },
    )
    request.send()

    # Payment 3: app0 is sending some tokens of token0 to app2
    identifier3 = PaymentID(30)
    amount3 = PaymentAmount(17)
    secret3, secrethash3 = factories.make_secret_with_hash()
    request = grequests.post(
        api_url_for(
            app0_server,
            "token_target_paymentresource",
            token_address=to_checksum_address(token_address0),
            target_address=to_checksum_address(app1.address),
        ),
        json={
            "amount": str(amount3),
            "identifier": str(identifier3),
            "secret": to_hex(secret3)
        },
    )
    request.send()

    timeout = block_offset_timeout(
        app2, "Waiting for transfer received success in the WAL timed out")
    with watch_for_unlock_failures(*raiden_network), timeout:
        result = wait_for_received_transfer_result(app1, identifier1, amount1,
                                                   app1.alarm.sleep_time,
                                                   secrethash1)
        msg = f"Unexpected transfer result: {str(result)}"
        assert result == TransferWaitResult.UNLOCKED, msg
        result = wait_for_received_transfer_result(app2, identifier2, amount2,
                                                   app2.alarm.sleep_time,
                                                   secrethash2)
        msg = f"Unexpected transfer result: {str(result)}"
        assert result == TransferWaitResult.UNLOCKED, msg
        result = wait_for_received_transfer_result(app1, identifier3, amount3,
                                                   app1.alarm.sleep_time,
                                                   secrethash3)
        msg = f"Unexpected transfer result: {str(result)}"
        assert result == TransferWaitResult.UNLOCKED, msg

    # predefine events for later use in assertions
    event_sent_1 = {
        "event": "EventPaymentSentSuccess",
        "identifier": str(identifier1),
        "target": to_checksum_address(app1.address),
        "token_address": to_checksum_address(token_address0),
    }
    event_sent_2 = {
        "event": "EventPaymentSentSuccess",
        "identifier": str(identifier2),
        "target": to_checksum_address(app2.address),
        "token_address": to_checksum_address(token_address1),
    }
    event_sent_3 = {
        "event": "EventPaymentSentSuccess",
        "identifier": str(identifier3),
        "target": to_checksum_address(app1.address),
        "token_address": to_checksum_address(token_address0),
    }
    event_received_1 = {
        "event": "EventPaymentReceivedSuccess",
        "identifier": str(identifier1),
        "initiator": to_checksum_address(app0.address),
        "token_address": to_checksum_address(token_address0),
    }
    event_received_2 = {
        "event": "EventPaymentReceivedSuccess",
        "identifier": str(identifier2),
        "initiator": to_checksum_address(app0.address),
        "token_address": to_checksum_address(token_address1),
    }
    event_received_3 = {
        "event": "EventPaymentReceivedSuccess",
        "identifier": str(identifier3),
        "initiator": to_checksum_address(app0.address),
        "token_address": to_checksum_address(token_address0),
    }

    # test app0 endpoint without (partner and token) for sender
    request = grequests.get(api_url_for(app0_server, "paymentresource"))
    with watch_for_unlock_failures(*raiden_network):
        response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)

    assert must_have_event(json_response, event_sent_1)
    assert must_have_event(json_response, event_sent_2)
    assert must_have_event(json_response, event_sent_3)

    # test endpoint without (partner and token) for target1
    request = grequests.get(api_url_for(app1_server, "paymentresource"))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert must_have_event(json_response, event_received_1)
    assert must_have_event(json_response, event_received_3)

    # test endpoint without (partner and token) for target2
    request = grequests.get(api_url_for(app2_server, "paymentresource"))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert must_have_event(json_response, event_received_2)

    # test endpoint without partner for app0
    request = grequests.get(
        api_url_for(app0_server,
                    "token_paymentresource",
                    token_address=token_address0))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)

    assert must_have_event(json_response, event_sent_1)
    assert must_have_event(json_response, event_sent_3)

    # test endpoint without partner for app0 but with limit/offset to get only first
    request = grequests.get(
        api_url_for(
            app0_server,
            "token_paymentresource",
            token_address=token_address0,
            limit=1,
            offset=0,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)

    assert must_have_event(json_response, event_sent_1)
    assert len(json_response) == 1

    # test endpoint without partner for app0 but with limit/offset
    # to get only second transfer of token_address
    request = grequests.get(
        api_url_for(
            app0_server,
            "token_paymentresource",
            token_address=token_address0,
            limit=1,
            offset=1,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)

    # this should return only payment 3, since payment 1 is offset
    # and payment 2 is of another token address
    assert len(json_response) == 1
    assert must_have_event(json_response, event_sent_3)

    # test endpoint of app1 without partner for token_address
    request = grequests.get(
        api_url_for(app1_server,
                    "token_paymentresource",
                    token_address=token_address0))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert must_have_events(json_response, event_received_1)
    assert must_have_events(json_response, event_received_3)

    # test endpoint of app2 without partner for token_address
    request = grequests.get(
        api_url_for(app2_server,
                    "token_paymentresource",
                    token_address=token_address0))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert len(json_response) == 0

    # test endpoint of app2 without partner for token_address2
    request = grequests.get(
        api_url_for(app2_server,
                    "token_paymentresource",
                    token_address=token_address1))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert must_have_events(json_response, event_received_2)

    # test endpoint for token_address0 and partner for app0
    request = grequests.get(
        api_url_for(
            app0_server,
            "token_target_paymentresource",
            token_address=token_address0,
            target_address=app1.address,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert len(json_response) == 2
    assert must_have_event(json_response, event_sent_1)
    assert must_have_event(json_response, event_sent_3)

    request = grequests.get(
        api_url_for(
            app0_server,
            "token_target_paymentresource",
            token_address=token_address1,
            target_address=app2.address,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert len(json_response) == 1
    assert must_have_event(json_response, event_sent_2)

    # test endpoint for token_address0 and partner for app1. Check both partners
    # to see that filtering works correctly
    request = grequests.get(
        api_url_for(
            app1_server,
            "token_target_paymentresource",
            token_address=token_address0,
            target_address=app2.address,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert len(json_response) == 0

    request = grequests.get(
        api_url_for(
            app1_server,
            "token_target_paymentresource",
            token_address=token_address0,
            target_address=app0.address,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert len(json_response) == 2
    assert must_have_event(json_response, event_received_1)
    assert must_have_event(json_response, event_received_3)

    # test app1 checking payments to himself
    request = grequests.get(
        api_url_for(
            app1_server,
            "token_target_paymentresource",
            token_address=token_address0,
            target_address=app1.address,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert len(json_response) == 0

    # test endpoint for token and partner for app2
    request = grequests.get(
        api_url_for(
            app2_server,
            "token_target_paymentresource",
            token_address=token_address0,
            target_address=app0.address,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    # Since app2 has no payment with app0 in token_address
    assert len(json_response) == 0

    # test endpoint for token2 and partner for app2
    request = grequests.get(
        api_url_for(
            app2_server,
            "token_target_paymentresource",
            token_address=token_address1,
            target_address=app0.address,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)

    # app2 has one payment with app0 in token_address2
    assert len(json_response) == 1
    assert must_have_events(json_response, event_received_2)

    request = grequests.get(
        api_url_for(
            app2_server,
            "token_target_paymentresource",
            token_address=token_address0,
            target_address=app1.address,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert not must_have_event(json_response, event_received_2)

    # also add a test for filtering by wrong token address
    request = grequests.get(
        api_url_for(
            app2_server,
            "token_target_paymentresource",
            token_address=app1.address,
            target_address=app1.address,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.BAD_REQUEST)

    app1_server.stop()
    app2_server.stop()
예제 #10
0
def test_echo_node_response(token_addresses, raiden_chain, retry_timeout):
    app0, app1, echo_app = raiden_chain
    token_address = token_addresses[0]
    registry_address = echo_app.raiden.default_registry.address

    echo_api = RaidenAPI(echo_app.raiden)
    echo_node = EchoNode(echo_api, token_address)

    message_handler = WaitForMessage()
    echo_app.raiden.message_handler = message_handler

    echo_node.ready.wait(timeout=30)
    assert echo_node.ready.is_set()

    transfer_timeout = 10

    wait_for = list()
    for num, app in enumerate([app0, app1]):
        amount = PaymentAmount(1 + num)
        identifier = PaymentID(10 ** (num + 1))
        secret, secrethash = make_secret_with_hash()

        payment_status = RaidenAPI(app.raiden).transfer_async(
            registry_address=registry_address,
            token_address=token_address,
            amount=amount,
            target=echo_app.raiden.address,
            identifier=identifier,
            secret=secret,
            secrethash=secrethash,
        )

        wait = message_handler.wait_for_message(Unlock, {"secret": secret})
        wait_for.append((wait, app.raiden.address, amount, identifier))

        msg = (
            f"Transfer {identifier} from "
            f"{to_checksum_address(app.raiden.address)} to "
            f"{to_checksum_address(echo_app.raiden.address)} timed out after "
            f"{transfer_timeout}"
        )
        timeout = gevent.Timeout(transfer_timeout, exception=RuntimeError(msg))
        with watch_for_unlock_failures(*raiden_chain), timeout:
            payment_status.payment_done.wait()

        echo_identifier = PaymentID(identifier + amount)
        msg = (
            f"Response transfer {echo_identifier} from echo node "
            f"{to_checksum_address(echo_app.raiden.address)} to "
            f"{to_checksum_address(app.raiden.address)} timed out after "
            f"{transfer_timeout}"
        )
        with gevent.Timeout(transfer_timeout, exception=RuntimeError(msg)):
            result = wait_for_received_transfer_result(
                raiden=app.raiden,
                payment_identifier=echo_identifier,
                amount=amount,
                retry_timeout=retry_timeout,
                secrethash=secrethash,
            )
            assert result == TransferWaitResult.UNLOCKED

    for wait, sender, amount, ident in wait_for:
        wait.wait()
        assert search_for_item(
            echo_app.raiden.wal.storage.get_events(),
            EventPaymentReceivedSuccess,
            {
                "amount": amount,
                "identifier": ident,
                "initiator": sender,
                "token_network_registry_address": registry_address,
            },
        )

    echo_node.stop()
예제 #11
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)
예제 #12
0
def test_secret_revealed_on_chain(raiden_chain, deposit, settle_timeout,
                                  token_addresses, retry_interval_initial):
    """ A node must reveal the secret on-chain if it's known and the channel is closed. """
    app0, app1, app2 = 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

    amount = 10
    identifier = 1
    target = app2.raiden.address
    secret, secrethash = factories.make_secret_with_hash()

    # Reveal the secret, but do not unlock it off-chain
    app1_hold_event_handler = app1.raiden.raiden_event_handler
    app1_hold_event_handler.hold_unlock_for(secrethash=secrethash)

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

    with watch_for_unlock_failures(*raiden_chain), block_offset_timeout(
            app0.raiden):
        wait_for_state_change(app2.raiden, ReceiveSecretReveal,
                              {"secrethash": secrethash},
                              retry_interval_initial)

    channel_state2_1 = get_channelstate(app2, app1, token_network_address)
    pending_lock = channel_state2_1.partner_state.secrethashes_to_unlockedlocks.get(
        secrethash)
    msg = "The lock must be registered in unlocked locks since the secret is known"
    assert pending_lock is not None, msg

    # The channels are out-of-sync. app1 has sent the unlock, however we are
    # intercepting it and app2 has not received the updated balance proof

    # Close the channel. This must register the secret on chain
    balance_proof = channel_state2_1.partner_state.balance_proof
    assert isinstance(balance_proof, BalanceProofSignedState)
    channel_close_event = ContractSendChannelClose(
        canonical_identifier=channel_state2_1.canonical_identifier,
        balance_proof=balance_proof,
        triggered_by_block_hash=app0.raiden.rpc_client.
        blockhash_from_blocknumber(BLOCK_ID_LATEST),
    )
    current_state = app2.raiden.wal.state_manager.current_state
    app2.raiden.raiden_event_handler.on_raiden_events(
        raiden=app2.raiden,
        chain_state=current_state,
        events=[channel_close_event])

    settle_expiration = (app0.raiden.rpc_client.block_number() +
                         settle_timeout +
                         DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS)
    app0.raiden.proxy_manager.client.wait_until_block(
        target_block_number=settle_expiration)

    # TODO:
    # - assert on the transferred amounts on-chain (for settle and unlock)

    # The channel app0-app1 should continue with the protocol off-chain, once
    # the secret is released on-chain by app2
    assert_synced_channel_state(token_network_address, app0, deposit - amount,
                                [], app1, deposit + amount, [])

    with watch_for_unlock_failures(*raiden_chain), gevent.Timeout(10):
        wait_for_state_change(
            app2.raiden,
            ContractReceiveSecretReveal,
            {"secrethash": secrethash},
            retry_interval_initial,
        )
예제 #13
0
def test_payment_events_endpoints(api_server_test_instance: APIServer,
                                  raiden_network, token_addresses):
    app0, app1, app2 = raiden_network
    amount1 = PaymentAmount(10)
    identifier1 = PaymentID(42)
    secret1, secrethash1 = factories.make_secret_with_hash()
    token_address = token_addresses[0]

    app0_address = app0.raiden.address
    target1_address = app1.raiden.address
    target2_address = app2.raiden.address

    app1_server = prepare_api_server(app1)
    app2_server = prepare_api_server(app2)

    # app0 is sending tokens to target 1
    request = grequests.post(
        api_url_for(
            api_server_test_instance,
            "token_target_paymentresource",
            token_address=to_checksum_address(token_address),
            target_address=to_checksum_address(target1_address),
        ),
        json={
            "amount": str(amount1),
            "identifier": str(identifier1),
            "secret": to_hex(secret1)
        },
    )
    request.send()
    # app0 is sending some tokens to target 2
    identifier2 = PaymentID(43)
    amount2 = PaymentAmount(10)
    secret2, secrethash2 = factories.make_secret_with_hash()
    request = grequests.post(
        api_url_for(
            api_server_test_instance,
            "token_target_paymentresource",
            token_address=to_checksum_address(token_address),
            target_address=to_checksum_address(target2_address),
        ),
        json={
            "amount": str(amount2),
            "identifier": str(identifier2),
            "secret": to_hex(secret2)
        },
    )
    request.send()

    # target1 also sends some tokens to target 2
    identifier3 = PaymentID(44)
    amount3 = PaymentAmount(5)
    secret3, secrethash3 = factories.make_secret_with_hash()
    request = grequests.post(
        api_url_for(
            app1_server,
            "token_target_paymentresource",
            token_address=to_checksum_address(token_address),
            target_address=to_checksum_address(target2_address),
        ),
        json={
            "amount": str(amount3),
            "identifier": str(identifier3),
            "secret": to_hex(secret3)
        },
    )
    request.send()

    timeout = block_offset_timeout(
        app2.raiden,
        "Waiting for transfer received success in the WAL timed out")
    with watch_for_unlock_failures(*raiden_network), timeout:
        result = wait_for_received_transfer_result(
            app1.raiden, identifier1, amount1, app1.raiden.alarm.sleep_time,
            secrethash1)
        msg = f"Unexpected transfer result: {str(result)}"
        assert result == TransferWaitResult.UNLOCKED, msg
        result = wait_for_received_transfer_result(
            app2.raiden, identifier2, amount2, app2.raiden.alarm.sleep_time,
            secrethash2)
        msg = f"Unexpected transfer result: {str(result)}"
        assert result == TransferWaitResult.UNLOCKED, msg
        result = wait_for_received_transfer_result(
            app2.raiden, identifier3, amount3, app2.raiden.alarm.sleep_time,
            secrethash3)
        msg = f"Unexpected transfer result: {str(result)}"
        assert result == TransferWaitResult.UNLOCKED, msg

    # test endpoint without (partner and token) for sender
    request = grequests.get(
        api_url_for(api_server_test_instance, "paymentresource"))
    with watch_for_unlock_failures(*raiden_network):
        response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert must_have_event(
        json_response,
        {
            "event": "EventPaymentSentSuccess",
            "identifier": str(identifier1),
            "target": to_checksum_address(target1_address),
            "token_address": to_checksum_address(token_address),
        },
    )
    assert must_have_event(
        json_response,
        {
            "event": "EventPaymentSentSuccess",
            "identifier": str(identifier2),
            "target": to_checksum_address(target2_address),
            "token_address": to_checksum_address(token_address),
        },
    )

    # test endpoint without (partner and token) for target1
    request = grequests.get(api_url_for(app1_server, "paymentresource"))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert must_have_event(
        json_response,
        {
            "event": "EventPaymentReceivedSuccess",
            "identifier": str(identifier1),
            "token_address": to_checksum_address(token_address),
        },
    )
    assert must_have_event(
        json_response,
        {
            "event": "EventPaymentSentSuccess",
            "identifier": str(identifier3),
            "token_address": to_checksum_address(token_address),
        },
    )
    # test endpoint without (partner and token) for target2
    request = grequests.get(api_url_for(app2_server, "paymentresource"))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert must_have_event(
        json_response,
        {
            "event": "EventPaymentReceivedSuccess",
            "identifier": str(identifier2),
            "token_address": to_checksum_address(token_address),
        },
    )
    assert must_have_event(
        json_response,
        {
            "event": "EventPaymentReceivedSuccess",
            "identifier": str(identifier3),
            "token_address": to_checksum_address(token_address),
        },
    )

    # test endpoint without partner for app0
    request = grequests.get(
        api_url_for(api_server_test_instance,
                    "token_paymentresource",
                    token_address=token_address))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert must_have_event(
        json_response,
        {
            "event": "EventPaymentSentSuccess",
            "identifier": str(identifier1),
            "target": to_checksum_address(target1_address),
            "token_address": to_checksum_address(token_address),
        },
    )
    assert must_have_event(
        json_response,
        {
            "event": "EventPaymentSentSuccess",
            "identifier": str(identifier2),
            "target": to_checksum_address(target2_address),
            "token_address": to_checksum_address(token_address),
        },
    )

    # test endpoint without partner for app0 but with limit/offset to get only first
    request = grequests.get(
        api_url_for(
            api_server_test_instance,
            "token_paymentresource",
            token_address=token_address,
            limit=1,
            offset=0,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)

    assert must_have_event(
        json_response,
        {
            "event": "EventPaymentSentSuccess",
            "identifier": str(identifier1),
            "target": to_checksum_address(target1_address),
            "token_address": to_checksum_address(token_address),
        },
    )
    assert len(json_response) == 1
    # test endpoint without partner for app0 but with limit/offset to get only second
    request = grequests.get(
        api_url_for(
            api_server_test_instance,
            "token_paymentresource",
            token_address=token_address,
            limit=1,
            offset=1,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert must_have_event(
        json_response,
        {
            "event": "EventPaymentSentSuccess",
            "identifier": str(identifier2),
            "target": to_checksum_address(target2_address),
            "token_address": to_checksum_address(token_address),
        },
    )

    # test endpoint without partner for target1
    request = grequests.get(
        api_url_for(app1_server,
                    "token_paymentresource",
                    token_address=token_address))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert must_have_events(
        json_response,
        {
            "event": "EventPaymentReceivedSuccess",
            "identifier": str(identifier1),
            "token_address": to_checksum_address(token_address),
        },
        {
            "event": "EventPaymentSentSuccess",
            "identifier": str(identifier3),
            "target": to_checksum_address(target2_address),
            "token_address": to_checksum_address(token_address),
        },
    )
    # test endpoint without partner for target2
    request = grequests.get(
        api_url_for(app2_server,
                    "token_paymentresource",
                    token_address=token_address))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert must_have_events(
        json_response,
        {
            "event": "EventPaymentReceivedSuccess",
            "identifier": str(identifier2),
            "token_address": to_checksum_address(token_address),
        },
        {
            "event": "EventPaymentReceivedSuccess",
            "identifier": str(identifier3),
            "token_address": to_checksum_address(token_address),
        },
    )

    # test endpoint for token and partner for app0
    request = grequests.get(
        api_url_for(
            api_server_test_instance,
            "token_target_paymentresource",
            token_address=token_address,
            target_address=target1_address,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert must_have_event(
        json_response,
        {
            "event": "EventPaymentSentSuccess",
            "identifier": str(identifier1),
            "target": to_checksum_address(target1_address),
            "token_address": to_checksum_address(token_address),
        },
    )
    assert not must_have_event(
        json_response,
        {
            "event": "EventPaymentSentSuccess",
            "identifier": str(identifier2),
            "target": to_checksum_address(target2_address),
            "token_address": to_checksum_address(token_address),
        },
    )
    # test endpoint for token and partner for target1. Check both partners
    # to see that filtering works correctly
    request = grequests.get(
        api_url_for(
            app1_server,
            "token_target_paymentresource",
            token_address=token_address,
            target_address=target2_address,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert must_have_event(
        json_response,
        {
            "event": "EventPaymentSentSuccess",
            "identifier": str(identifier3),
            "target": to_checksum_address(target2_address),
            "token_address": to_checksum_address(token_address),
        },
    )
    assert not must_have_event(
        response,
        {
            "event": "EventPaymentReceivedSuccess",
            "identifier": str(identifier1),
            "token_address": to_checksum_address(token_address),
        },
    )
    request = grequests.get(
        api_url_for(
            app1_server,
            "token_target_paymentresource",
            token_address=token_address,
            target_address=target1_address,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert len(json_response) == 0
    # test endpoint for token and partner for target2
    request = grequests.get(
        api_url_for(
            app2_server,
            "token_target_paymentresource",
            token_address=token_address,
            target_address=app0_address,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert must_have_events(
        json_response,
        {
            "event": "EventPaymentReceivedSuccess",
            "identifier": str(identifier2),
            "token_address": to_checksum_address(token_address),
        },
    )
    assert not must_have_event(
        json_response,
        {
            "event": "EventPaymentReceivedSuccess",
            "identifier": str(identifier1),
            "token_address": to_checksum_address(token_address),
        },
    )
    assert not must_have_event(
        json_response,
        {
            "event": "EventPaymentReceivedSuccess",
            "identifier": str(identifier3),
            "token_address": to_checksum_address(token_address),
        },
    )
    request = grequests.get(
        api_url_for(
            app2_server,
            "token_target_paymentresource",
            token_address=token_address,
            target_address=target1_address,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert must_have_events(
        json_response,
        {
            "event": "EventPaymentReceivedSuccess",
            "identifier": str(identifier3),
            "token_address": to_checksum_address(token_address),
        },
    )
    assert not must_have_event(
        json_response,
        {
            "event": "EventPaymentReceivedSuccess",
            "identifier": str(identifier2),
            "token_address": to_checksum_address(token_address),
        },
    )
    assert not must_have_event(
        json_response,
        {
            "event": "EventPaymentReceivedSuccess",
            "identifier": str(identifier1),
            "token_address": to_checksum_address(token_address),
        },
    )

    # also add a test for filtering by wrong token address
    request = grequests.get(
        api_url_for(
            app2_server,
            "token_target_paymentresource",
            token_address=target1_address,
            target_address=target1_address,
        ))
    response = request.send().response
    assert_proper_response(response, HTTPStatus.OK)
    json_response = get_json_response(response)
    assert len(json_response) == 0

    app1_server.stop()
    app2_server.stop()
예제 #14
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
예제 #15
0
def test_start_end_attack(
    token_addresses: List[TokenAddress], raiden_chain: List[App], deposit: List[App]
) -> None:
    """ An attacker can try to steal tokens from a hub or the last node in a
    path.

    The attacker needs to use two addresses (A1 and A2) and connect both to the
    hub H. Once connected a mediated transfer is initialized from A1 to A2
    through H. Once the node A2 receives the mediated transfer the attacker
    uses the known secret and reveal to close and settle the channel H-A2,
    without revealing the secret to H's raiden node.

    The intention is to make the hub transfer the token but for him to be
    unable to require the token A1."""

    token = token_addresses[0]
    app0, app1, app2 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking
    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

    hold_event_handler = app2.raiden.raiden_event_handler
    msg = "hold event handler necessary to control messages"
    assert isinstance(hold_event_handler, HoldRaidenEventHandler), msg

    # the attacker owns app0 and app2 and creates a transfer through app1
    amount = PaymentAmount(30)
    identifier = PaymentID(1)
    target = TargetAddress(app2.raiden.address)
    secret, secrethash = factories.make_secret_with_hash()

    hold_event_handler.hold_secretrequest_for(secrethash=secrethash)

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

    attack_channel = get_channelstate(app2, app1, token_network_address)
    attack_transfer = None  # TODO
    attack_contract = attack_channel.external_state.netting_channel.address  # type: ignore
    hub_contract = get_channelstate(  # type: ignore
        app1, app0, token_network_address
    ).external_state.netting_channel.address

    # start the settle counter
    attack_balance_proof = attack_transfer.to_balanceproof()  # type: ignore
    attack_channel.netting_channel.channel_close(attack_balance_proof)  # type: ignore

    # wait until the last block to reveal the secret, hopefully we are not
    # missing a block during the test
    assert attack_transfer
    app2.raiden.rpc_client.wait_until_block(
        target_block_number=attack_transfer.lock.expiration - 1
    )

    # since the attacker knows the secret he can net the lock
    # <the commented code below is left for documentation purposes>
    # attack_channel.netting_channel.unlock(
    #     UnlockProofState(unlock_proof, attack_transfer.lock, secret)
    # )
    # XXX: verify that the secret was publicized

    # at this point the hub might not know the secret yet, and won't be able to
    # claim the token from the channel A1 - H

    # the attacker settles the contract
    app2.raiden.rpc_client.wait_until_block(
        target_block_number=app2.raiden.rpc_client.block_number() + 1
    )

    attack_channel.netting_channel.settle(token, attack_contract)

    # at this point the attacker has the "stolen" funds
    attack_contract = app2.raiden.proxy_manager.token_hashchannel[token][attack_contract]
    assert attack_contract.participants[app2.raiden.address]["netted"] == deposit + amount
    assert attack_contract.participants[app1.raiden.address]["netted"] == deposit - amount

    # and the hub's channel A1-H doesn't
    hub_contract = app1.raiden.proxy_manager.token_hashchannel[token][hub_contract]
    assert hub_contract.participants[app0.raiden.address]["netted"] == deposit
    assert hub_contract.participants[app1.raiden.address]["netted"] == deposit

    # to mitigate the attack the Hub _needs_ to use a lower expiration for the
    # locked transfer between H-A2 than A1-H. For A2 to acquire the token
    # it needs to make the secret public in the blockchain so it publishes the
    # secret through an event and the Hub is able to require its funds
    app1.raiden.rpc_client.wait_until_block(
        target_block_number=app1.raiden.rpc_client.block_number() + 1
    )

    # XXX: verify that the Hub has found the secret, close and settle the channel

    # the hub has acquired its token
    hub_contract = app1.raiden.proxy_manager.token_hashchannel[token][hub_contract]
    assert hub_contract.participants[app0.raiden.address]["netted"] == deposit + amount
    assert hub_contract.participants[app1.raiden.address]["netted"] == deposit - amount