Ejemplo n.º 1
0
def run_test_token_registered_race(raiden_chain, token_amount, retry_timeout, contract_manager):
    app0, app1 = raiden_chain

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

    # Recreate the race condition by making sure the non-registering app won't
    # register at all by watching for the TokenAdded blockchain event.
    event_listeners = app1.raiden.blockchain_events.event_listeners
    app1.raiden.blockchain_events.event_listeners = list()

    token_address = deploy_contract_web3(
        contract_name=CONTRACT_HUMAN_STANDARD_TOKEN,
        deploy_client=app1.raiden.chain.client,
        contract_manager=contract_manager,
        constructor_arguments=(
            token_amount,
            2,
            'raiden',
            'Rd',
        ),
    )

    gevent.sleep(1)

    registry_address = app0.raiden.default_registry.address
    assert token_address not in api0.get_tokens_list(registry_address)
    assert token_address not in api1.get_tokens_list(registry_address)

    api0.token_network_register(
        registry_address=registry_address,
        token_address=token_address,
        channel_participant_deposit_limit=UINT256_MAX,
        token_network_deposit_limit=UINT256_MAX,
    )
    exception = RuntimeError('Did not see the token registration within 30 seconds')
    with gevent.Timeout(seconds=30, exception=exception):
        wait_for_state_change(
            app0.raiden,
            ContractReceiveNewTokenNetwork,
            {
                'token_network': {
                    'token_address': token_address,
                },
            },
            retry_timeout,
        )

    assert token_address in api0.get_tokens_list(registry_address)
    assert token_address not in api1.get_tokens_list(registry_address)

    # The next time when the event is polled, the token is registered
    app1.raiden.blockchain_events.event_listeners = event_listeners
    waiting.wait_for_block(
        app1.raiden,
        app1.raiden.get_block_number() + 1,
        retry_timeout,
    )

    assert token_address in api1.get_tokens_list(registry_address)
Ejemplo n.º 2
0
def run_test_set_deposit_limit_crash(
        raiden_network,
        token_amount,
        contract_manager,
        retry_timeout,
):
    app1 = raiden_network[0]

    registry_address = app1.raiden.default_registry.address

    token_address = deploy_contract_web3(
        contract_name=CONTRACT_HUMAN_STANDARD_TOKEN,
        deploy_client=app1.raiden.chain.client,
        contract_manager=contract_manager,
        constructor_arguments=(
            token_amount,
            2,
            'raiden',
            'Rd',
        ),
    )

    api1 = RaidenAPI(app1.raiden)
    assert token_address not in api1.get_tokens_list(registry_address)

    api1.token_network_register(
        registry_address=registry_address,
        token_address=token_address,
        channel_participant_deposit_limit=RED_EYES_PER_CHANNEL_PARTICIPANT_LIMIT,
        token_network_deposit_limit=RED_EYES_PER_TOKEN_NETWORK_LIMIT,
    )
    exception = RuntimeError('Did not see the token registration within 30 seconds')
    with gevent.Timeout(seconds=30, exception=exception):
        wait_for_state_change(
            app1.raiden,
            ContractReceiveNewTokenNetwork,
            {
                'token_network': {
                    'token_address': token_address,
                },
            },
            retry_timeout,
        )
    assert token_address in api1.get_tokens_list(registry_address)

    partner_address = make_address()
    api1.channel_open(
        registry_address=app1.raiden.default_registry.address,
        token_address=token_address,
        partner_address=partner_address,
    )
    with pytest.raises(DepositOverLimit):
        api1.set_total_channel_deposit(
            registry_address=app1.raiden.default_registry.address,
            token_address=token_address,
            partner_address=partner_address,
            total_deposit=10000000000000000000000,
        )
Ejemplo n.º 3
0
def test_set_deposit_limit_crash(raiden_network, token_amount,
                                 contract_manager, retry_timeout):
    """The development contracts as of 10/12/2018 were crashing if more than an amount was given
    Regression test for https://github.com/raiden-network/raiden/issues/3135
    """
    app1 = raiden_network[0]

    registry_address = app1.raiden.default_registry.address

    token_address = deploy_contract_web3(
        contract_name=CONTRACT_HUMAN_STANDARD_TOKEN,
        deploy_client=app1.raiden.chain.client,
        contract_manager=contract_manager,
        constructor_arguments=(
            token_amount,
            2,
            'raiden',
            'Rd',
        ),
    )

    api1 = RaidenAPI(app1.raiden)
    assert token_address not in api1.get_tokens_list(registry_address)

    api1.token_network_register(registry_address, token_address)
    exception = RuntimeError(
        'Did not see the token registration within 30 seconds')
    with gevent.Timeout(seconds=30, exception=exception):
        wait_for_state_change(
            app1.raiden,
            ContractReceiveNewTokenNetwork,
            {
                'token_network': {
                    'token_address': token_address,
                },
            },
            retry_timeout,
        )
    assert token_address in api1.get_tokens_list(registry_address)

    partner_address = make_address()
    api1.channel_open(
        registry_address=app1.raiden.default_registry.address,
        token_address=token_address,
        partner_address=partner_address,
    )
    with pytest.raises(DepositOverLimit):
        api1.set_total_channel_deposit(
            registry_address=app1.raiden.default_registry.address,
            token_address=token_address,
            partner_address=partner_address,
            total_deposit=10000000000000000000000,
        )
Ejemplo n.º 4
0
def test_set_deposit_limit_crash(raiden_network, token_amount, contract_manager, retry_timeout):
    """The development contracts as of 10/12/2018 were crashing if more than an amount was given
    Regression test for https://github.com/raiden-network/raiden/issues/3135
    """
    app1 = raiden_network[0]

    registry_address = app1.raiden.default_registry.address

    token_address = deploy_contract_web3(
        contract_name=CONTRACT_HUMAN_STANDARD_TOKEN,
        deploy_client=app1.raiden.chain.client,
        contract_manager=contract_manager,
        constructor_arguments=(
            token_amount,
            2,
            'raiden',
            'Rd',
        ),
    )

    api1 = RaidenAPI(app1.raiden)
    assert token_address not in api1.get_tokens_list(registry_address)

    api1.token_network_register(registry_address, token_address)
    exception = RuntimeError('Did not see the token registration within 30 seconds')
    with gevent.Timeout(seconds=30, exception=exception):
        wait_for_state_change(
            app1.raiden,
            ContractReceiveNewTokenNetwork,
            {
                'token_network': {
                    'token_address': token_address,
                },
            },
            retry_timeout,
        )
    assert token_address in api1.get_tokens_list(registry_address)

    partner_address = make_address()
    api1.channel_open(
        registry_address=app1.raiden.default_registry.address,
        token_address=token_address,
        partner_address=partner_address,
    )
    with pytest.raises(DepositOverLimit):
        api1.set_total_channel_deposit(
            registry_address=app1.raiden.default_registry.address,
            token_address=token_address,
            partner_address=partner_address,
            total_deposit=10000000000000000000000,
        )
Ejemplo n.º 5
0
def run_test_register_token(raiden_network, token_amount, contract_manager, retry_timeout):
    app1 = raiden_network[0]

    registry_address = app1.raiden.default_registry.address

    token_address = deploy_contract_web3(
        contract_name=CONTRACT_HUMAN_STANDARD_TOKEN,
        deploy_client=app1.raiden.chain.client,
        contract_manager=contract_manager,
        constructor_arguments=(
            token_amount,
            2,
            'raiden',
            'Rd',
        ),
    )

    api1 = RaidenAPI(app1.raiden)
    assert token_address not in api1.get_tokens_list(registry_address)

    api1.token_network_register(
        registry_address=registry_address,
        token_address=token_address,
        channel_participant_deposit_limit=UINT256_MAX,
        token_network_deposit_limit=UINT256_MAX,
    )
    exception = RuntimeError('Did not see the token registration within 30 seconds')
    with gevent.Timeout(seconds=30, exception=exception):
        wait_for_state_change(
            app1.raiden,
            ContractReceiveNewTokenNetwork,
            {
                'token_network': {
                    'token_address': token_address,
                },
            },
            retry_timeout,
        )
    assert token_address in api1.get_tokens_list(registry_address)

    # Exception if we try to reregister
    with pytest.raises(AlreadyRegisteredTokenAddress):
        api1.token_network_register(
            registry_address=registry_address,
            token_address=token_address,
            channel_participant_deposit_limit=UINT256_MAX,
            token_network_deposit_limit=UINT256_MAX,
        )
Ejemplo n.º 6
0
def test_register_token(raiden_network, token_amount, contract_manager, retry_timeout):
    app1 = raiden_network[0]

    registry_address = app1.raiden.default_registry.address

    token_address = deploy_contract_web3(
        contract_name=CONTRACT_HUMAN_STANDARD_TOKEN,
        deploy_client=app1.raiden.rpc_client,
        contract_manager=contract_manager,
        constructor_arguments=(token_amount, 2, "raiden", "Rd"),
    )

    # Wait until Raiden can start using the token contract.
    # Here, the block at which the contract was deployed should be confirmed by Raiden.
    # Therefore, until that block is received.
    waiting.wait_for_block(
        raiden=app1.raiden,
        block_number=app1.raiden.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1,
        retry_timeout=retry_timeout,
    )

    api1 = RaidenAPI(app1.raiden)
    assert token_address not in api1.get_tokens_list(registry_address)

    api1.token_network_register(
        registry_address=registry_address,
        token_address=token_address,
        channel_participant_deposit_limit=UINT256_MAX,
        token_network_deposit_limit=UINT256_MAX,
    )
    exception = RuntimeError("Did not see the token registration within 30 seconds")
    with gevent.Timeout(seconds=30, exception=exception):
        wait_for_state_change(
            app1.raiden,
            ContractReceiveNewTokenNetwork,
            {"token_network": {"token_address": token_address}},
            retry_timeout,
        )
    assert token_address in api1.get_tokens_list(registry_address)

    # Exception if we try to reregister
    with pytest.raises(AlreadyRegisteredTokenAddress):
        api1.token_network_register(
            registry_address=registry_address,
            token_address=token_address,
            channel_participant_deposit_limit=UINT256_MAX,
            token_network_deposit_limit=UINT256_MAX,
        )
Ejemplo n.º 7
0
def test_register_token(raiden_network: List[RaidenService], retry_timeout,
                        unregistered_token):
    app1 = raiden_network[0]
    registry_address = app1.default_registry.address
    token_address = unregistered_token

    # Wait until Raiden can start using the token contract.
    # Here, the block at which the contract was deployed should be confirmed by Raiden.
    # Therefore, until that block is received.
    waiting.wait_for_block(
        raiden=app1,
        block_number=BlockNumber(app1.get_block_number() +
                                 DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1),
        retry_timeout=retry_timeout,
    )

    api1 = RaidenAPI(app1)
    assert token_address not in api1.get_tokens_list(registry_address)

    api1.token_network_register(
        registry_address=registry_address,
        token_address=token_address,
        channel_participant_deposit_limit=TokenAmount(UINT256_MAX),
        token_network_deposit_limit=TokenAmount(UINT256_MAX),
    )
    exception = RuntimeError(
        "Did not see the token registration within 30 seconds")
    with gevent.Timeout(seconds=30, exception=exception):
        wait_for_state_change(
            app1,
            ContractReceiveNewTokenNetwork,
            {"token_network": {
                "token_address": token_address
            }},
            retry_timeout,
        )
    assert token_address in api1.get_tokens_list(registry_address)

    # Exception if we try to reregister
    with pytest.raises(AlreadyRegisteredTokenAddress):
        api1.token_network_register(
            registry_address=registry_address,
            token_address=token_address,
            channel_participant_deposit_limit=TokenAmount(UINT256_MAX),
            token_network_deposit_limit=TokenAmount(UINT256_MAX),
        )
Ejemplo n.º 8
0
def test_register_token(raiden_network, token_amount, contract_manager, retry_timeout):
    app1 = raiden_network[0]

    registry_address = app1.raiden.default_registry.address

    token_address = deploy_contract_web3(
        contract_name=CONTRACT_HUMAN_STANDARD_TOKEN,
        deploy_client=app1.raiden.chain.client,
        contract_manager=contract_manager,
        constructor_arguments=(
            token_amount,
            2,
            'raiden',
            'Rd',
        ),
    )

    api1 = RaidenAPI(app1.raiden)
    assert token_address not in api1.get_tokens_list(registry_address)

    api1.token_network_register(registry_address, token_address)
    exception = RuntimeError('Did not see the token registration within 30 seconds')
    with gevent.Timeout(seconds=30, exception=exception):
        wait_for_state_change(
            app1.raiden,
            ContractReceiveNewTokenNetwork,
            {
                'token_network': {
                    'token_address': token_address,
                },
            },
            retry_timeout,
        )
    assert token_address in api1.get_tokens_list(registry_address)

    # Exception if we try to reregister
    with pytest.raises(AlreadyRegisteredTokenAddress):
        api1.token_network_register(registry_address, token_address)
Ejemplo n.º 9
0
def test_participant_deposit_amount_must_be_smaller_than_the_limit(
        raiden_network: List[App], contract_manager: ContractManager,
        retry_timeout: float) -> None:
    """The Python API must properly check the requested participant deposit
    will not exceed the smart contract limit.

    This is companion test for
    `test_deposit_amount_must_be_smaller_than_the_token_network_limit`. The
    participant deposit limit was introduced for the bug bounty with the PR
    https://github.com/raiden-network/raiden-contracts/pull/276/ , the limit is
    available since version 0.4.0 of the smart contract.
    """
    app1 = raiden_network[0]

    registry_address = app1.raiden.default_registry.address

    token_supply = 1_000_000
    token_address = TokenAddress(
        deploy_contract_web3(
            contract_name=CONTRACT_HUMAN_STANDARD_TOKEN,
            deploy_client=app1.raiden.rpc_client,
            contract_manager=contract_manager,
            constructor_arguments=(token_supply, 2, "raiden", "Rd"),
        ))

    api1 = RaidenAPI(app1.raiden)

    msg = "Token is not registered yet, it must not be in the token list."
    assert token_address not in api1.get_tokens_list(registry_address), msg

    # Wait until Raiden can start using the token contract.
    # Here, the block at which the contract was deployed should be confirmed by Raiden.
    # Therefore, until that block is received.
    waiting.wait_for_block(
        raiden=app1.raiden,
        block_number=BlockNumber(app1.raiden.get_block_number() +
                                 DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1),
        retry_timeout=retry_timeout,
    )

    token_network_participant_deposit_limit = TokenAmount(100)
    api1.token_network_register(
        registry_address=registry_address,
        token_address=token_address,
        channel_participant_deposit_limit=
        token_network_participant_deposit_limit,
        token_network_deposit_limit=TokenAmount(UINT256_MAX),
    )

    exception = RuntimeError(
        "Did not see the token registration within 30 seconds")
    with gevent.Timeout(seconds=30, exception=exception):
        wait_for_state_change(
            app1.raiden,
            ContractReceiveNewTokenNetwork,
            {"token_network": {
                "token_address": token_address
            }},
            retry_timeout,
        )

    msg = "Token has been registered, yet must be available in the token list."
    assert token_address in api1.get_tokens_list(registry_address), msg

    partner_address = make_address()
    api1.channel_open(
        registry_address=app1.raiden.default_registry.address,
        token_address=token_address,
        partner_address=partner_address,
    )

    with pytest.raises(DepositOverLimit):
        api1.set_total_channel_deposit(
            registry_address=app1.raiden.default_registry.address,
            token_address=token_address,
            partner_address=partner_address,
            total_deposit=TokenAmount(token_network_participant_deposit_limit +
                                      1),
        )

        pytest.fail(
            "The deposit must fail if the requested deposit exceeds the participant deposit limit."
        )
Ejemplo n.º 10
0
def test_token_registered_race(raiden_chain, retry_timeout,
                               unregistered_token):
    """If a token is registered it must appear on the token list.

    If two nodes register the same token one of the transactions will fail. The
    node that receives an error for "already registered token" must see the
    token in the token list. Issue: #784
    """
    app0, app1 = raiden_chain
    token_address = unregistered_token

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

    # Wait until Raiden can start using the token contract.
    # Here, the block at which the contract was deployed should be confirmed by Raiden.
    # Therefore, until that block is received.
    waiting.wait_for_block(
        raiden=app0.raiden,
        block_number=app0.raiden.get_block_number() +
        DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1,
        retry_timeout=retry_timeout,
    )
    waiting.wait_for_block(
        raiden=app1.raiden,
        block_number=app1.raiden.get_block_number() +
        DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1,
        retry_timeout=retry_timeout,
    )

    registry_address = app0.raiden.default_registry.address
    assert token_address not in api0.get_tokens_list(registry_address)
    assert token_address not in api1.get_tokens_list(registry_address)

    greenlets: set = {
        gevent.spawn(
            api0.token_network_register,
            registry_address=registry_address,
            token_address=token_address,
            channel_participant_deposit_limit=TokenAmount(UINT256_MAX),
            token_network_deposit_limit=TokenAmount(UINT256_MAX),
        ),
        gevent.spawn(
            api0.token_network_register,
            registry_address=registry_address,
            token_address=token_address,
            channel_participant_deposit_limit=TokenAmount(UINT256_MAX),
            token_network_deposit_limit=TokenAmount(UINT256_MAX),
        ),
    }

    # One of the nodes will lose the race
    with pytest.raises(RaidenRecoverableError):
        gevent.joinall(greenlets, raise_error=True)

    exception = RuntimeError(
        "Did not see the token registration within 30 seconds")
    with gevent.Timeout(seconds=30, exception=exception):
        wait_for_state_change(
            app0.raiden,
            ContractReceiveNewTokenNetwork,
            {"token_network": {
                "token_address": token_address
            }},
            retry_timeout,
        )
        wait_for_state_change(
            app1.raiden,
            ContractReceiveNewTokenNetwork,
            {"token_network": {
                "token_address": token_address
            }},
            retry_timeout,
        )

    assert token_address in api0.get_tokens_list(registry_address)
    assert token_address in api1.get_tokens_list(registry_address)

    for api in (api0, api1):
        with pytest.raises(AlreadyRegisteredTokenAddress):
            api.token_network_register(
                registry_address=registry_address,
                token_address=token_address,
                channel_participant_deposit_limit=TokenAmount(UINT256_MAX),
                token_network_deposit_limit=TokenAmount(UINT256_MAX),
            )
Ejemplo n.º 11
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,
        )
Ejemplo n.º 12
0
def test_different_view_of_last_bp_during_unlock(
        raiden_chain,
        number_of_nodes,
        token_addresses,
        deposit,
        network_wait,
        retry_timeout,
        # UDP does not seem to retry messages until processed
        # https://github.com/raiden-network/raiden/issues/3185
        skip_if_not_matrix,
):
    """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]
    payment_network_identifier = app0.raiden.default_registry.address
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(app0),
        payment_network_identifier,
        token_address,
    )
    token_proxy = app0.raiden.chain.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 = 1
    amount_path = 1
    mediated_transfer(
        app0,
        app2,
        token_network_identifier,
        amount_path,
        identifier_path,
        timeout=network_wait * number_of_nodes,
    )

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

    # wait for the nodes to sync
    gevent.sleep(0.2)

    assert_synced_channel_state(
        token_network_identifier,
        app0, deposit - amount_path, [],
        app1, deposit + amount_path, [],
    )
    assert_synced_channel_state(
        token_network_identifier,
        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 = 3
    amount_refund = 50
    async_result = app0.raiden.mediated_transfer_async(
        token_network_identifier,
        amount_refund,
        app2.raiden.address,
        identifier_refund,
    )
    assert async_result.wait() is False, 'there is no path with capacity, the transfer must fail'

    gevent.sleep(0.2)

    # A lock structure with the correct amount

    send_locked = raiden_events_must_contain_entry(
        app0.raiden,
        SendLockedTransfer,
        {'transfer': {'lock': {'amount': amount_refund}}},
    )
    assert send_locked
    secrethash = send_locked.transfer.lock.secrethash

    send_refund = raiden_events_must_contain_entry(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
    assert_synced_channel_state(
        token_network_identifier,
        app0, deposit - amount_path, [lockstate_from_lock(lock)],
        app1, deposit + amount_path, [lockstate_from_lock(refund_lock)],
    )
    assert_synced_channel_state(
        token_network_identifier,
        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.get()
        assert not app1.raiden

        # Wait for lock expiration so that app0 sends a LockExpired
        wait_for_block(
            raiden=app0.raiden,
            block_number=channel.get_sender_expiration_threshold(lock) + 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=payment_network_identifier,
            token_address=token_address,
            partner_address=app1.raiden.address,
        )

    count = 0
    original_update = app1.raiden.raiden_event_handler.handle_contract_send_channelupdate

    def patched_update(raiden, event):
        nonlocal count
        count += 1
        original_update(raiden, event)

    app1.raiden.raiden_event_handler.handle_contract_send_channelupdate = patched_update
    # 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_identifier).identifier

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

    with gevent.Timeout(10):
        unlock_app0 = wait_for_state_change(
            app0.raiden,
            ContractReceiveChannelBatchUnlock,
            {'participant': app0.raiden.address},
            retry_timeout,
        )
    assert unlock_app0.returned_tokens == 50
    with gevent.Timeout(10):
        unlock_app1 = wait_for_state_change(
            app1.raiden,
            ContractReceiveChannelBatchUnlock,
            {'participant': app1.raiden.address},
            retry_timeout,
        )
    assert unlock_app1.returned_tokens == 50
    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
Ejemplo n.º 13
0
def test_refund_transfer(
    raiden_chain,
    number_of_nodes,
    token_addresses,
    deposit,
    network_wait,
    retry_timeout,
    # UDP does not seem to retry messages until processed
    # https://github.com/raiden-network/raiden/issues/3185
    skip_if_not_matrix,
):
    """A failed transfer must send a refund back.

    TODO:
        - Unlock the token on refund #1091
        - Clear the merkletree and update the locked amount #193
        - Remove the refund message type #490"""
    # Topology:
    #
    #  0 -> 1 -> 2
    #
    app0, app1, app2 = raiden_chain
    token_address = token_addresses[0]
    payment_network_identifier = app0.raiden.default_registry.address
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(app0),
        payment_network_identifier,
        token_address,
    )

    # make a transfer to test the path app0 -> app1 -> app2
    identifier_path = 1
    amount_path = 1
    mediated_transfer(
        app0,
        app2,
        token_network_identifier,
        amount_path,
        identifier_path,
        timeout=network_wait * number_of_nodes,
    )

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

    # wait for the nodes to sync
    gevent.sleep(0.2)

    assert_synced_channel_state(
        token_network_identifier,
        app0,
        deposit - amount_path,
        [],
        app1,
        deposit + amount_path,
        [],
    )
    assert_synced_channel_state(
        token_network_identifier,
        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 = 3
    amount_refund = 50
    async_result = app0.raiden.mediated_transfer_async(
        token_network_identifier,
        amount_refund,
        app2.raiden.address,
        identifier_refund,
    )
    assert async_result.wait(
    ) is False, 'there is no path with capacity, the transfer must fail'

    gevent.sleep(0.2)

    # A lock structure with the correct amount

    send_locked = raiden_events_search_for_item(
        app0.raiden,
        SendLockedTransfer,
        {'transfer': {
            'lock': {
                'amount': amount_refund
            }
        }},
    )
    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
    assert_synced_channel_state(
        token_network_identifier,
        app0,
        deposit - amount_path,
        [lockstate_from_lock(lock)],
        app1,
        deposit + amount_path,
        [lockstate_from_lock(refund_lock)],
    )
    assert_synced_channel_state(
        token_network_identifier,
        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

    # Wait for lock lock expiration but make sure app0 never processes LockExpired
    with dont_handle_lock_expired_mock(app0):
        wait_for_block(
            raiden=app0.raiden,
            block_number=channel.get_sender_expiration_threshold(lock) + 1,
            retry_timeout=retry_timeout,
        )
        # make sure that app0 still has the payment task for the secrethash
        # https://github.com/raiden-network/raiden/issues/3183
        assert secrethash in state_from_raiden(
            app0.raiden).payment_mapping.secrethashes_to_task

        # make sure that app1 sent a lock expired message for the secrethash
        send_lock_expired = raiden_events_search_for_item(
            app1.raiden,
            SendLockExpired,
            {'secrethash': secrethash},
        )
        assert send_lock_expired
        # make sure that app0 never got it
        state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier(
            0, 'latest')
        assert not search_for_item(
            state_changes,
            ReceiveLockExpired,
            {'secrethash': secrethash},
        )

    # Out of the handicapped app0 transport.
    # Now wait till app0 receives and processes LockExpired
    receive_lock_expired = wait_for_state_change(
        app0.raiden,
        ReceiveLockExpired,
        {'secrethash': secrethash},
        retry_timeout,
    )
    # And also till app1 received the processed
    wait_for_state_change(
        app1.raiden,
        ReceiveProcessed,
        {'message_identifier': receive_lock_expired.message_identifier},
        retry_timeout,
    )

    # make sure app1 queue has cleared the SendLockExpired
    chain_state1 = views.state_from_app(app1)
    queues1 = views.get_all_messagequeues(chain_state=chain_state1)
    result = [(queue_id, queue) for queue_id, queue in queues1.items()
              if queue_id.recipient == app0.raiden.address and queue]
    assert not result

    # and now wait for 1 more block so that the payment task can be deleted
    wait_for_block(
        raiden=app0.raiden,
        block_number=app0.raiden.get_block_number() + 1,
        retry_timeout=retry_timeout,
    )

    # and since the lock expired message has been sent and processed then the
    # payment task should have been deleted from both nodes
    # https://github.com/raiden-network/raiden/issues/3183
    assert secrethash not in state_from_raiden(
        app0.raiden).payment_mapping.secrethashes_to_task
    assert secrethash not in state_from_raiden(
        app1.raiden).payment_mapping.secrethashes_to_task
Ejemplo n.º 14
0
def test_token_registered_race(raiden_chain, token_amount, retry_timeout,
                               contract_manager):
    """If a token is registered it must appear on the token list.

    If two nodes register the same token one of the transactions will fail. The
    node that receives an error for "already registered token" must see the
    token in the token list. Issue: #784
    """
    app0, app1 = raiden_chain

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

    # Recreate the race condition by making sure the non-registering app won't
    # register at all by watching for the TokenAdded blockchain event.
    event_listeners = app1.raiden.blockchain_events.event_listeners
    app1.raiden.blockchain_events.event_listeners = list()

    token_address = deploy_contract_web3(
        contract_name=CONTRACT_HUMAN_STANDARD_TOKEN,
        deploy_client=app1.raiden.chain.client,
        contract_manager=contract_manager,
        constructor_arguments=(
            token_amount,
            2,
            'raiden',
            'Rd',
        ),
    )

    gevent.sleep(1)

    registry_address = app0.raiden.default_registry.address
    assert token_address not in api0.get_tokens_list(registry_address)
    assert token_address not in api1.get_tokens_list(registry_address)

    api0.token_network_register(registry_address, token_address)
    exception = RuntimeError(
        'Did not see the token registration within 30 seconds')
    with gevent.Timeout(seconds=30, exception=exception):
        wait_for_state_change(
            app0.raiden,
            ContractReceiveNewTokenNetwork,
            {
                'token_network': {
                    'token_address': token_address,
                },
            },
            retry_timeout,
        )

    assert token_address in api0.get_tokens_list(registry_address)
    assert token_address not in api1.get_tokens_list(registry_address)

    # The next time when the event is polled, the token is registered
    app1.raiden.blockchain_events.event_listeners = event_listeners
    waiting.wait_for_block(
        app1.raiden,
        app1.raiden.get_block_number() + 1,
        retry_timeout,
    )

    assert token_address in api1.get_tokens_list(registry_address)
Ejemplo n.º 15
0
def test_raidenapi_channel_lifecycle(
    raiden_network: List[RaidenService],
    token_addresses,
    deposit,
    retry_timeout,
    settle_timeout_max,
):
    """Uses RaidenAPI to go through a complete channel lifecycle."""
    app1, app2 = raiden_network
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_raiden(app1), app1.default_registry.address,
        token_address)
    assert token_network_address

    api1 = RaidenAPI(app1)
    api2 = RaidenAPI(app2)

    registry_address = app1.default_registry.address

    # nodes don't have a channel, so they are not healthchecking
    assert api1.get_node_network_state(api2.address) == NetworkState.UNKNOWN
    assert api2.get_node_network_state(api1.address) == NetworkState.UNKNOWN
    assert not api1.get_channel_list(registry_address, token_address,
                                     api2.address)

    # Make sure invalid arguments to get_channel_list are caught
    with pytest.raises(UnknownTokenAddress):
        api1.get_channel_list(registry_address=registry_address,
                              token_address=None,
                              partner_address=api2.address)

    address_for_lowest_settle_timeout = make_address()
    lowest_valid_settle_timeout = app1.config.reveal_timeout * 2

    # Make sure a small settle timeout is not accepted when opening a channel
    with pytest.raises(InvalidSettleTimeout):
        api1.channel_open(
            registry_address=app1.default_registry.address,
            token_address=token_address,
            partner_address=address_for_lowest_settle_timeout,
            settle_timeout=BlockTimeout(lowest_valid_settle_timeout - 1),
        )

    # Make sure the smallest settle timeout is accepted
    api1.channel_open(
        registry_address=app1.default_registry.address,
        token_address=token_address,
        partner_address=address_for_lowest_settle_timeout,
        settle_timeout=BlockTimeout(lowest_valid_settle_timeout),
    )

    address_for_highest_settle_timeout = make_address()
    highest_valid_settle_timeout = settle_timeout_max

    # Make sure a large settle timeout is not accepted when opening a channel
    with pytest.raises(InvalidSettleTimeout):
        api1.channel_open(
            registry_address=app1.default_registry.address,
            token_address=token_address,
            partner_address=address_for_highest_settle_timeout,
            settle_timeout=highest_valid_settle_timeout + 1,
        )

    # Make sure the highest settle timeout is accepted
    api1.channel_open(
        registry_address=app1.default_registry.address,
        token_address=token_address,
        partner_address=address_for_highest_settle_timeout,
        settle_timeout=highest_valid_settle_timeout,
    )

    # open is a synchronous api
    api1.channel_open(app1.default_registry.address, token_address,
                      api2.address)
    channels = api1.get_channel_list(registry_address, token_address,
                                     api2.address)
    assert len(channels) == 1

    channel12 = get_channelstate(app1, app2, token_network_address)
    assert channel.get_status(channel12) == ChannelState.STATE_OPENED

    registry_address = api1.raiden.default_registry.address
    # Check that giving a 0 total deposit is not accepted
    with pytest.raises(DepositMismatch):
        api1.set_total_channel_deposit(
            registry_address=registry_address,
            token_address=token_address,
            partner_address=api2.address,
            total_deposit=TokenAmount(0),
        )
    # Load the new state with the deposit
    api1.set_total_channel_deposit(
        registry_address=registry_address,
        token_address=token_address,
        partner_address=api2.address,
        total_deposit=deposit,
    )

    # let's make sure it's idempotent. Same deposit should raise deposit mismatch limit
    with pytest.raises(DepositMismatch):
        api1.set_total_channel_deposit(registry_address, token_address,
                                       api2.address, deposit)

    channel12 = get_channelstate(app1, app2, token_network_address)

    assert channel.get_status(channel12) == ChannelState.STATE_OPENED
    assert channel.get_balance(channel12.our_state,
                               channel12.partner_state) == deposit
    assert channel12.our_state.contract_balance == deposit
    assert api1.get_channel_list(registry_address, token_address,
                                 api2.address) == [channel12]

    # there is a channel open, they must be healthchecking each other
    assert api1.get_node_network_state(api2.address) == NetworkState.REACHABLE
    assert api2.get_node_network_state(api1.address) == NetworkState.REACHABLE

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

    # Load the new state with the channel closed
    channel12 = get_channelstate(app1, app2, token_network_address)
    assert channel.get_status(channel12) == ChannelState.STATE_CLOSED

    with pytest.raises(UnexpectedChannelState):
        api1.set_total_channel_deposit(registry_address, token_address,
                                       api2.address, deposit + 100)

    assert wait_for_state_change(
        app1,
        ContractReceiveChannelSettled,
        {
            "canonical_identifier": {
                "token_network_address": token_network_address,
                "channel_identifier": channel12.identifier,
            }
        },
        retry_timeout,
    )
Ejemplo n.º 16
0
def run_test_raidenapi_channel_lifecycle(raiden_network, token_addresses,
                                         deposit, retry_timeout):
    node1, node2 = raiden_network
    token_address = token_addresses[0]
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(node1), node1.raiden.default_registry.address,
        token_address)

    api1 = RaidenAPI(node1.raiden)
    api2 = RaidenAPI(node2.raiden)

    registry_address = node1.raiden.default_registry.address

    # nodes don't have a channel, so they are not healthchecking
    assert api1.get_node_network_state(api2.address) == NODE_NETWORK_UNKNOWN
    assert api2.get_node_network_state(api1.address) == NODE_NETWORK_UNKNOWN
    assert not api1.get_channel_list(registry_address, token_address,
                                     api2.address)

    # Make sure invalid arguments to get_channel_list are caught
    with pytest.raises(UnknownTokenAddress):
        api1.get_channel_list(registry_address=registry_address,
                              token_address=None,
                              partner_address=api2.address)

    # open is a synchronous api
    api1.channel_open(node1.raiden.default_registry.address, token_address,
                      api2.address)
    channels = api1.get_channel_list(registry_address, token_address,
                                     api2.address)
    assert len(channels) == 1

    channel12 = get_channelstate(node1, node2, token_network_identifier)
    assert channel.get_status(channel12) == CHANNEL_STATE_OPENED

    channel_event_list1 = api1.get_blockchain_events_channel(
        token_address, channel12.partner_state.address)
    assert must_have_event(
        channel_event_list1,
        {
            "event": ChannelEvent.OPENED,
            "args": {
                "participant1": to_checksum_address(api1.address),
                "participant2": to_checksum_address(api2.address),
            },
        },
    )

    network_event_list1 = api1.get_blockchain_events_token_network(
        token_address)
    assert must_have_event(network_event_list1, {"event": ChannelEvent.OPENED})

    registry_address = api1.raiden.default_registry.address
    # Check that giving a 0 total deposit is not accepted
    with pytest.raises(DepositMismatch):
        api1.set_total_channel_deposit(
            registry_address=registry_address,
            token_address=token_address,
            partner_address=api2.address,
            total_deposit=0,
        )
    # Load the new state with the deposit
    api1.set_total_channel_deposit(
        registry_address=registry_address,
        token_address=token_address,
        partner_address=api2.address,
        total_deposit=deposit,
    )

    # let's make sure it's idempotent. Same deposit should raise deposit mismatch limit
    with pytest.raises(DepositMismatch):
        api1.set_total_channel_deposit(registry_address, token_address,
                                       api2.address, deposit)

    channel12 = get_channelstate(node1, node2, token_network_identifier)

    assert channel.get_status(channel12) == CHANNEL_STATE_OPENED
    assert channel.get_balance(channel12.our_state,
                               channel12.partner_state) == deposit
    assert channel12.our_state.contract_balance == deposit
    assert api1.get_channel_list(registry_address, token_address,
                                 api2.address) == [channel12]

    # there is a channel open, they must be healthchecking each other
    assert api1.get_node_network_state(api2.address) == NODE_NETWORK_REACHABLE
    assert api2.get_node_network_state(api1.address) == NODE_NETWORK_REACHABLE

    event_list2 = api1.get_blockchain_events_channel(
        token_address, channel12.partner_state.address)
    assert must_have_event(
        event_list2,
        {
            "event": ChannelEvent.DEPOSIT,
            "args": {
                "participant": to_checksum_address(api1.address),
                "total_deposit": deposit
            },
        },
    )

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

    # Load the new state with the channel closed
    channel12 = get_channelstate(node1, node2, token_network_identifier)

    event_list3 = api1.get_blockchain_events_channel(
        token_address, channel12.partner_state.address)
    assert len(event_list3) > len(event_list2)
    assert must_have_event(
        event_list3,
        {
            "event": ChannelEvent.CLOSED,
            "args": {
                "closing_participant": to_checksum_address(api1.address)
            },
        },
    )
    assert channel.get_status(channel12) == CHANNEL_STATE_CLOSED

    assert wait_for_state_change(
        node1.raiden,
        ContractReceiveChannelSettled,
        {
            "token_network_identifier": token_network_identifier,
            "channel_identifier": channel12.identifier,
        },
        retry_timeout,
    )
Ejemplo n.º 17
0
def run_test_locksroot_loading_during_channel_settle_handling(raiden_chain, token_addresses):
    app0, app1 = raiden_chain
    payment_network_id = app0.raiden.default_registry.address
    token_address = token_addresses[0]

    transfer(
        initiator_app=app0,
        target_app=app1,
        token_address=token_address,
        amount=10,
        identifier=1,
        transfer_state=TransferState.SECRET_NOT_REQUESTED,
    )
    transfer(
        initiator_app=app1,
        target_app=app0,
        token_address=token_address,
        amount=7,
        identifier=2,
        transfer_state=TransferState.SECRET_NOT_REQUESTED,
    )

    token_network_identifier = views.get_token_network_identifier_by_token_address(
        chain_state=views.state_from_raiden(app0.raiden),
        payment_network_id=payment_network_id,
        token_address=token_address,
    )
    channel_state = get_channelstate(
        app0=app0, app1=app1, token_network_identifier=token_network_identifier
    )

    channel = app0.raiden.chain.payment_channel(channel_state.canonical_identifier)
    balance_proof = channel_state.partner_state.balance_proof
    block_number = app0.raiden.chain.block_number()

    channel.close(
        nonce=balance_proof.nonce,
        balance_hash=balance_proof.balance_hash,
        additional_hash=balance_proof.message_hash,
        signature=balance_proof.signature,
        block_identifier=block_number,
    )

    app0.stop()

    waiting.wait_for_settle(
        raiden=app1.raiden,
        payment_network_id=payment_network_id,
        token_address=token_address,
        channel_ids=[channel_state.canonical_identifier.channel_identifier],
        retry_timeout=1,
    )

    # The private chain used for tests has a very low pruning setting
    pruned_after_blocks = 10
    close_event_pruned_at = app1.raiden.chain.get_block_number() + pruned_after_blocks
    waiting.wait_for_block(raiden=app1.raiden, block_number=close_event_pruned_at, retry_timeout=1)

    # make sure the block was pruned
    with pytest.raises(ValueError, match="pruned"):
        channel = app0.raiden.chain.payment_channel(channel_state.canonical_identifier)
        channel.detail(block_identifier=close_event_pruned_at)

    # This must not raise when the settle event is being raised and the
    # locksroot is being recover (#3856)
    app0.start()

    assert wait_for_state_change(
        raiden=app0.raiden,
        item_type=ContractReceiveChannelSettled,
        attributes={"canonical_identifier": channel_state.canonical_identifier},
        retry_timeout=1,
    )
Ejemplo n.º 18
0
def test_different_view_of_last_bp_during_unlock(
    raiden_chain,
    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)
    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 = 1
    amount_path = 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 = 2
    amount_drain = 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 = 3
    amount_refund = 50
    amount_refund_with_fees = amount_refund + calculate_fee_for_amount(50)
    payment_status = app0.raiden.mediated_transfer_async(
        token_network_address, amount_refund, 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.get()
        assert not app1.raiden

        # Wait for lock expiration so that app0 sends a LockExpired
        wait_for_block(
            raiden=app0.raiden,
            block_number=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)

    app1.raiden.raiden_event_handler.on_raiden_event = patched_on_raiden_event
    # 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.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.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
Ejemplo n.º 19
0
def test_locksroot_loading_during_channel_settle_handling(
    raiden_chain, deploy_client, token_addresses
):
    app0, app1 = raiden_chain
    token_network_registry_address = app0.raiden.default_registry.address
    token_address = token_addresses[0]

    transfer(
        initiator_app=app0,
        target_app=app1,
        token_address=token_address,
        amount=PaymentAmount(10),
        identifier=PaymentID(1),
        transfer_state=TransferState.SECRET_NOT_REQUESTED,
    )
    transfer(
        initiator_app=app1,
        target_app=app0,
        token_address=token_address,
        amount=PaymentAmount(7),
        identifier=PaymentID(2),
        transfer_state=TransferState.SECRET_NOT_REQUESTED,
    )

    token_network_address = views.get_token_network_address_by_token_address(
        chain_state=views.state_from_raiden(app0.raiden),
        token_network_registry_address=token_network_registry_address,
        token_address=token_address,
    )
    assert token_network_address
    channel_state = get_channelstate(
        app0=app0, app1=app1, token_network_address=token_network_address
    )

    channel = app0.raiden.proxy_manager.payment_channel(channel_state.canonical_identifier)
    balance_proof = channel_state.partner_state.balance_proof
    assert balance_proof
    balance_proof = cast(BalanceProofSignedState, balance_proof)
    block_number = app0.raiden.rpc_client.block_number()

    closing_data = pack_signed_balance_proof(
        msg_type=MessageTypeId.BALANCE_PROOF,
        nonce=balance_proof.nonce,
        balance_hash=balance_proof.balance_hash,
        additional_hash=balance_proof.message_hash,
        canonical_identifier=balance_proof.canonical_identifier,
        partner_signature=balance_proof.signature,
    )
    closing_signature = app0.raiden.signer.sign(data=closing_data)

    channel.close(
        nonce=balance_proof.nonce,
        balance_hash=balance_proof.balance_hash,
        additional_hash=balance_proof.message_hash,
        non_closing_signature=balance_proof.signature,
        closing_signature=closing_signature,
        block_identifier=block_number,
    )

    close_block = app0.raiden.rpc_client.block_number()

    app0.stop()

    waiting.wait_for_settle(
        raiden=app1.raiden,
        token_network_registry_address=token_network_registry_address,
        token_address=token_address,
        channel_ids=[channel_state.canonical_identifier.channel_identifier],
        retry_timeout=1,
    )

    contract_proxy, _ = deploy_rpc_test_contract(deploy_client, "RpcWithStorageTest")
    iterations = 1000

    def send_transaction():
        check_block = deploy_client.get_checking_block()
        startgas = contract_proxy.estimate_gas(check_block, "waste_storage", iterations)
        startgas = safe_gas_limit(startgas)
        transaction = contract_proxy.transact("waste_storage", startgas, iterations)
        return deploy_client.poll(transaction)

    for _ in range(10):
        send_transaction()

    # Wait until the target block has be prunned, it has to be larger than
    # pruning_history
    pruned_after_blocks = pruning_history * 1.5

    waiting.wait_for_block(
        raiden=app1.raiden, block_number=close_block + pruned_after_blocks, retry_timeout=1
    )

    channel = app0.raiden.proxy_manager.payment_channel(channel_state.canonical_identifier)

    # make sure the block was pruned
    with pytest.raises(ValueError):
        channel.detail(block_identifier=close_block)

    # This must not raise when the settle event is being raised and the
    # locksroot is being recover (#3856)
    app0.start()

    assert wait_for_state_change(
        raiden=app0.raiden,
        item_type=ContractReceiveChannelSettled,
        attributes={"canonical_identifier": channel_state.canonical_identifier},
        retry_timeout=1,
    )
Ejemplo n.º 20
0
def test_refund_transfer(raiden_chain, number_of_nodes, token_addresses,
                         deposit, network_wait, retry_timeout):
    """A failed transfer must send a refund back.

    TODO:
        - Unlock the token on refund #1091
        - Clear the pending locks and update the locked amount #193
        - Remove the refund message type #490"""
    # 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)

    # 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, 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

    # Wait for lock lock expiration but make sure app0 never processes LockExpired
    with dont_handle_lock_expired_mock(app0):
        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 still has the payment task for the secrethash
        # https://github.com/raiden-network/raiden/issues/3183
        assert secrethash in state_from_raiden(
            app0.raiden).payment_mapping.secrethashes_to_task

        # make sure that app1 sent a lock expired message for the secrethash
        send_lock_expired = raiden_events_search_for_item(
            app1.raiden, SendLockExpired, {"secrethash": secrethash})
        assert send_lock_expired
        # make sure that app0 never got it
        state_changes = app0.raiden.wal.storage.get_statechanges_by_range(
            RANGE_ALL_STATE_CHANGES)
        assert not search_for_item(state_changes, ReceiveLockExpired,
                                   {"secrethash": secrethash})

    # Out of the handicapped app0 transport.
    # Now wait till app0 receives and processes LockExpired
    receive_lock_expired = wait_for_state_change(app0.raiden,
                                                 ReceiveLockExpired,
                                                 {"secrethash": secrethash},
                                                 retry_timeout)
    # And also till app1 received the processed
    wait_for_state_change(
        app1.raiden,
        ReceiveProcessed,
        {"message_identifier": receive_lock_expired.message_identifier},
        retry_timeout,
    )

    # make sure app1 queue has cleared the SendLockExpired
    chain_state1 = views.state_from_app(app1)
    queues1 = views.get_all_messagequeues(chain_state=chain_state1)
    result = [(queue_id, queue) for queue_id, queue in queues1.items()
              if queue_id.recipient == app0.raiden.address and queue]
    assert not result

    # and now wait for 1 more block so that the payment task can be deleted
    wait_for_block(
        raiden=app0.raiden,
        block_number=app0.raiden.get_block_number() + 1,
        retry_timeout=retry_timeout,
    )

    # and since the lock expired message has been sent and processed then the
    # payment task should have been deleted from both nodes
    # https://github.com/raiden-network/raiden/issues/3183
    assert secrethash not in state_from_raiden(
        app0.raiden).payment_mapping.secrethashes_to_task
    assert secrethash not in state_from_raiden(
        app1.raiden).payment_mapping.secrethashes_to_task
Ejemplo n.º 21
0
def test_refund_transfer(
        raiden_chain,
        number_of_nodes,
        token_addresses,
        deposit,
        network_wait,
        retry_timeout,
        # UDP does not seem to retry messages until processed
        # https://github.com/raiden-network/raiden/issues/3185
        skip_if_not_matrix,
):
    """A failed transfer must send a refund back.

    TODO:
        - Unlock the token on refund #1091
        - Clear the merkletree and update the locked amount #193
        - Remove the refund message type #490"""
    # Topology:
    #
    #  0 -> 1 -> 2
    #
    app0, app1, app2 = raiden_chain
    token_address = token_addresses[0]
    payment_network_identifier = app0.raiden.default_registry.address
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(app0),
        payment_network_identifier,
        token_address,
    )

    # make a transfer to test the path app0 -> app1 -> app2
    identifier_path = 1
    amount_path = 1
    mediated_transfer(
        app0,
        app2,
        token_network_identifier,
        amount_path,
        identifier_path,
        timeout=network_wait * number_of_nodes,
    )

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

    # wait for the nodes to sync
    gevent.sleep(0.2)

    assert_synced_channel_state(
        token_network_identifier,
        app0, deposit - amount_path, [],
        app1, deposit + amount_path, [],
    )
    assert_synced_channel_state(
        token_network_identifier,
        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 = 3
    amount_refund = 50
    async_result = app0.raiden.mediated_transfer_async(
        token_network_identifier,
        amount_refund,
        app2.raiden.address,
        identifier_refund,
    )
    assert async_result.wait() is False, 'there is no path with capacity, the transfer must fail'

    gevent.sleep(0.2)

    # A lock structure with the correct amount

    send_locked = raiden_events_must_contain_entry(
        app0.raiden,
        SendLockedTransfer,
        {'transfer': {'lock': {'amount': amount_refund}}},
    )
    assert send_locked
    secrethash = send_locked.transfer.lock.secrethash

    send_refund = raiden_events_must_contain_entry(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
    assert_synced_channel_state(
        token_network_identifier,
        app0, deposit - amount_path, [lockstate_from_lock(lock)],
        app1, deposit + amount_path, [lockstate_from_lock(refund_lock)],
    )
    assert_synced_channel_state(
        token_network_identifier,
        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

    # Wait for lock lock expiration but make sure app0 never processes LockExpired
    with dont_handle_lock_expired_mock(app0):
        wait_for_block(
            raiden=app0.raiden,
            block_number=channel.get_sender_expiration_threshold(lock) + 1,
            retry_timeout=retry_timeout,
        )
        # make sure that app0 still has the payment task for the secrethash
        # https://github.com/raiden-network/raiden/issues/3183
        assert secrethash in state_from_raiden(app0.raiden).payment_mapping.secrethashes_to_task

        # make sure that app1 sent a lock expired message for the secrethash
        send_lock_expired = raiden_events_must_contain_entry(
            app1.raiden,
            SendLockExpired,
            {'secrethash': secrethash},
        )
        assert send_lock_expired
        # make sure that app0 never got it
        state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier(0, 'latest')
        assert not must_contain_entry(
            state_changes,
            ReceiveLockExpired,
            {'secrethash': secrethash},
        )

    # Out of the handicapped app0 transport.
    # Now wait till app0 receives and processes LockExpired
    receive_lock_expired = wait_for_state_change(
        app0.raiden,
        ReceiveLockExpired,
        {'secrethash': secrethash},
        retry_timeout,
    )
    # And also till app1 received the processed
    wait_for_state_change(
        app1.raiden,
        ReceiveProcessed,
        {'message_identifier': receive_lock_expired.message_identifier},
        retry_timeout,
    )

    # make sure app1 queue has cleared the SendLockExpired
    chain_state1 = views.state_from_app(app1)
    queues1 = views.get_all_messagequeues(chain_state=chain_state1)
    result = [
        (queue_id, queue)
        for queue_id, queue in queues1.items()
        if queue_id.recipient == app0.raiden.address and
        queue
    ]
    assert not result

    # and now wait for 1 more block so that the payment task can be deleted
    wait_for_block(
        raiden=app0.raiden,
        block_number=app0.raiden.get_block_number() + 1,
        retry_timeout=retry_timeout,
    )

    # and since the lock expired message has been sent and processed then the
    # payment task should have been deleted from both nodes
    # https://github.com/raiden-network/raiden/issues/3183
    assert secrethash not in state_from_raiden(app0.raiden).payment_mapping.secrethashes_to_task
    assert secrethash not in state_from_raiden(app1.raiden).payment_mapping.secrethashes_to_task
Ejemplo n.º 22
0
def test_deposit_amount_must_be_smaller_than_the_token_network_limit(
        raiden_network: List[App], contract_manager: ContractManager,
        retry_timeout: float) -> None:
    """The Python API must properly check the requested deposit will not exceed
    the token network deposit limit.

    This is a regression test for #3135.

    As of version `v0.18.1` (commit 786347b23), the proxy was not properly
    checking that the requested deposit amount was smaller than the smart
    contract deposit limit. This led to two errors:

    - The error message was vague and incorrect: "Deposit amount decreased"
    - The exception used was not handled and crashed the node.

    This test checks the limit is properly check from the REST API.
    """
    app1 = raiden_network[0]

    registry_address = app1.raiden.default_registry.address

    token_supply = 1_000_000
    token_address = TokenAddress(
        deploy_contract_web3(
            contract_name=CONTRACT_HUMAN_STANDARD_TOKEN,
            deploy_client=app1.raiden.rpc_client,
            contract_manager=contract_manager,
            constructor_arguments=(token_supply, 2, "raiden", "Rd"),
        ))

    # Wait until Raiden can start using the token contract.
    # Here, the block at which the contract was deployed should be confirmed by Raiden.
    # Therefore, until that block is received.
    waiting.wait_for_block(
        raiden=app1.raiden,
        block_number=BlockNumber(app1.raiden.get_block_number() +
                                 DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1),
        retry_timeout=retry_timeout,
    )

    api1 = RaidenAPI(app1.raiden)

    msg = "Token is not registered yet, it must not be in the token list."
    assert token_address not in api1.get_tokens_list(registry_address), msg

    token_network_deposit_limit = TokenAmount(100)
    api1.token_network_register(
        registry_address=registry_address,
        token_address=token_address,
        channel_participant_deposit_limit=token_network_deposit_limit,
        token_network_deposit_limit=token_network_deposit_limit,
    )

    exception = RuntimeError(
        "Did not see the token registration within 30 seconds")
    with gevent.Timeout(seconds=30, exception=exception):
        wait_for_state_change(
            app1.raiden,
            ContractReceiveNewTokenNetwork,
            {"token_network": {
                "token_address": token_address
            }},
            retry_timeout,
        )

    msg = "Token has been registered, yet must be available in the token list."
    assert token_address in api1.get_tokens_list(registry_address), msg

    partner_address = make_address()
    api1.channel_open(
        registry_address=app1.raiden.default_registry.address,
        token_address=token_address,
        partner_address=partner_address,
    )

    with pytest.raises(DepositOverLimit):
        api1.set_total_channel_deposit(
            registry_address=app1.raiden.default_registry.address,
            token_address=token_address,
            partner_address=partner_address,
            total_deposit=TokenAmount(token_network_deposit_limit + 1),
        )

        pytest.fail(
            "The deposit must fail if the requested deposit exceeds the token "
            "network deposit limit.")
Ejemplo n.º 23
0
def test_secret_revealed_on_chain(
    raiden_chain,
    deposit,
    settle_timeout,
    token_addresses,
    retry_interval,
):
    """ 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_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(app0),
        app0.raiden.default_registry.address,
        token_address,
    )

    amount = 10
    identifier = 1
    target = app2.raiden.address
    secret = sha3(target)
    secrethash = sha3(secret)

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

    app0.raiden.start_mediated_transfer_with_secret(
        token_network_identifier,
        amount,
        target,
        identifier,
        secret,
    )

    with gevent.Timeout(10):
        wait_for_state_change(
            app2.raiden,
            ReceiveSecretReveal,
            {'secrethash': secrethash},
            retry_interval,
        )

    channel_state2_1 = get_channelstate(app2, app1, token_network_identifier)
    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
    channel_close_event = ContractSendChannelClose(
        channel_identifier=channel_state2_1.identifier,
        token_address=channel_state2_1.token_address,
        token_network_identifier=token_network_identifier,
        balance_proof=channel_state2_1.partner_state.balance_proof,
        triggered_by_block_hash=app0.raiden.chain.block_hash(),
    )
    app2.raiden.raiden_event_handler.on_raiden_event(app2.raiden,
                                                     channel_close_event)

    settle_expiration = (app0.raiden.chain.block_number() + settle_timeout +
                         DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS)
    app0.raiden.chain.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_identifier,
        app0,
        deposit - amount,
        [],
        app1,
        deposit + amount,
        [],
    )

    with gevent.Timeout(10):
        wait_for_state_change(
            app2.raiden,
            ContractReceiveSecretReveal,
            {'secrethash': secrethash},
            retry_interval,
        )
Ejemplo n.º 24
0
def test_raidenapi_channel_lifecycle(raiden_network, token_addresses, deposit,
                                     retry_timeout, settle_timeout_max):
    """Uses RaidenAPI to go through a complete channel lifecycle."""
    node1, node2 = raiden_network
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(node1), node1.raiden.default_registry.address,
        token_address)
    assert token_network_address

    api1 = RaidenAPI(node1.raiden)
    api2 = RaidenAPI(node2.raiden)

    registry_address = node1.raiden.default_registry.address

    # nodes don't have a channel, so they are not healthchecking
    assert api1.get_node_network_state(api2.address) == NetworkState.UNKNOWN
    assert api2.get_node_network_state(api1.address) == NetworkState.UNKNOWN
    assert not api1.get_channel_list(registry_address, token_address,
                                     api2.address)

    # Make sure invalid arguments to get_channel_list are caught
    with pytest.raises(UnknownTokenAddress):
        api1.get_channel_list(registry_address=registry_address,
                              token_address=None,
                              partner_address=api2.address)

    address_for_lowest_settle_timeout = make_address()
    lowest_valid_settle_timeout = node1.raiden.config.reveal_timeout * 2

    # Make sure a small settle timeout is not accepted when opening a channel
    with pytest.raises(InvalidSettleTimeout):
        api1.channel_open(
            registry_address=node1.raiden.default_registry.address,
            token_address=token_address,
            partner_address=address_for_lowest_settle_timeout,
            settle_timeout=lowest_valid_settle_timeout - 1,
        )

    # Make sure the smallest settle timeout is accepted
    api1.channel_open(
        registry_address=node1.raiden.default_registry.address,
        token_address=token_address,
        partner_address=address_for_lowest_settle_timeout,
        settle_timeout=lowest_valid_settle_timeout,
    )

    address_for_highest_settle_timeout = make_address()
    highest_valid_settle_timeout = settle_timeout_max

    # Make sure a large settle timeout is not accepted when opening a channel
    with pytest.raises(InvalidSettleTimeout):
        api1.channel_open(
            registry_address=node1.raiden.default_registry.address,
            token_address=token_address,
            partner_address=address_for_highest_settle_timeout,
            settle_timeout=highest_valid_settle_timeout + 1,
        )

    # Make sure the highest settle timeout is accepted
    api1.channel_open(
        registry_address=node1.raiden.default_registry.address,
        token_address=token_address,
        partner_address=address_for_highest_settle_timeout,
        settle_timeout=highest_valid_settle_timeout,
    )

    # open is a synchronous api
    api1.channel_open(node1.raiden.default_registry.address, token_address,
                      api2.address)
    channels = api1.get_channel_list(registry_address, token_address,
                                     api2.address)
    assert len(channels) == 1

    channel12 = get_channelstate(node1, node2, token_network_address)
    assert channel.get_status(channel12) == ChannelState.STATE_OPENED

    channel_event_list1 = api1.get_blockchain_events_channel(
        token_address, channel12.partner_state.address)
    assert must_have_event(
        channel_event_list1,
        {
            "event": ChannelEvent.OPENED,
            "args": {
                "participant1": to_checksum_address(api1.address),
                "participant2": to_checksum_address(api2.address),
            },
        },
    )

    network_event_list1 = api1.get_blockchain_events_token_network(
        token_address)
    assert must_have_event(network_event_list1, {"event": ChannelEvent.OPENED})

    registry_address = api1.raiden.default_registry.address
    # Check that giving a 0 total deposit is not accepted
    with pytest.raises(DepositMismatch):
        api1.set_total_channel_deposit(
            registry_address=registry_address,
            token_address=token_address,
            partner_address=api2.address,
            total_deposit=TokenAmount(0),
        )
    # Load the new state with the deposit
    api1.set_total_channel_deposit(
        registry_address=registry_address,
        token_address=token_address,
        partner_address=api2.address,
        total_deposit=deposit,
    )

    # let's make sure it's idempotent. Same deposit should raise deposit mismatch limit
    with pytest.raises(DepositMismatch):
        api1.set_total_channel_deposit(registry_address, token_address,
                                       api2.address, deposit)

    channel12 = get_channelstate(node1, node2, token_network_address)

    assert channel.get_status(channel12) == ChannelState.STATE_OPENED
    assert channel.get_balance(channel12.our_state,
                               channel12.partner_state) == deposit
    assert channel12.our_state.contract_balance == deposit
    assert api1.get_channel_list(registry_address, token_address,
                                 api2.address) == [channel12]

    # there is a channel open, they must be healthchecking each other
    assert api1.get_node_network_state(api2.address) == NetworkState.REACHABLE
    assert api2.get_node_network_state(api1.address) == NetworkState.REACHABLE

    event_list2 = api1.get_blockchain_events_channel(
        token_address, channel12.partner_state.address)
    assert must_have_event(
        event_list2,
        {
            "event": ChannelEvent.DEPOSIT,
            "args": {
                "participant": to_checksum_address(api1.address),
                "total_deposit": deposit
            },
        },
    )

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

    # Load the new state with the channel closed
    channel12 = get_channelstate(node1, node2, token_network_address)

    event_list3 = api1.get_blockchain_events_channel(
        token_address, channel12.partner_state.address)
    assert len(event_list3) > len(event_list2)
    assert must_have_event(
        event_list3,
        {
            "event": ChannelEvent.CLOSED,
            "args": {
                "closing_participant": to_checksum_address(api1.address)
            },
        },
    )
    assert channel.get_status(channel12) == ChannelState.STATE_CLOSED

    with pytest.raises(UnexpectedChannelState):
        api1.set_total_channel_deposit(registry_address, token_address,
                                       api2.address, deposit + 100)

    assert wait_for_state_change(
        node1.raiden,
        ContractReceiveChannelSettled,
        {
            "canonical_identifier": {
                "token_network_address": token_network_address,
                "channel_identifier": channel12.identifier,
            }
        },
        retry_timeout,
    )
Ejemplo n.º 25
0
def test_token_registered_race(raiden_chain, token_amount, retry_timeout, contract_manager):
    """If a token is registered it must appear on the token list.

    If two nodes register the same token one of the transactions will fail. The
    node that receives an error for "already registered token" must see the
    token in the token list. Issue: #784
    """
    app0, app1 = raiden_chain

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

    # Recreate the race condition by making sure the non-registering app won't
    # register at all by watching for the TokenAdded blockchain event.
    event_listeners = app1.raiden.blockchain_events.event_listeners
    app1.raiden.blockchain_events.event_listeners = list()

    token_address = deploy_contract_web3(
        contract_name=CONTRACT_HUMAN_STANDARD_TOKEN,
        deploy_client=app1.raiden.chain.client,
        contract_manager=contract_manager,
        constructor_arguments=(
            token_amount,
            2,
            'raiden',
            'Rd',
        ),
    )

    gevent.sleep(1)

    registry_address = app0.raiden.default_registry.address
    assert token_address not in api0.get_tokens_list(registry_address)
    assert token_address not in api1.get_tokens_list(registry_address)

    api0.token_network_register(registry_address, token_address)
    exception = RuntimeError('Did not see the token registration within 30 seconds')
    with gevent.Timeout(seconds=30, exception=exception):
        wait_for_state_change(
            app0.raiden,
            ContractReceiveNewTokenNetwork,
            {
                'token_network': {
                    'token_address': token_address,
                },
            },
            retry_timeout,
        )

    assert token_address in api0.get_tokens_list(registry_address)
    assert token_address not in api1.get_tokens_list(registry_address)

    # The next time when the event is polled, the token is registered
    app1.raiden.blockchain_events.event_listeners = event_listeners
    waiting.wait_for_block(
        app1.raiden,
        app1.raiden.get_block_number() + 1,
        retry_timeout,
    )

    assert token_address in api1.get_tokens_list(registry_address)
Ejemplo n.º 26
0
def test_different_view_of_last_bp_during_unlock(
    raiden_chain,
    number_of_nodes,
    token_addresses,
    deposit,
    network_wait,
    retry_timeout,
    # UDP does not seem to retry messages until processed
    # https://github.com/raiden-network/raiden/issues/3185
    skip_if_not_matrix,
):
    """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]
    payment_network_identifier = app0.raiden.default_registry.address
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(app0),
        payment_network_identifier,
        token_address,
    )
    token_proxy = app0.raiden.chain.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 = 1
    amount_path = 1
    mediated_transfer(
        app0,
        app2,
        token_network_identifier,
        amount_path,
        identifier_path,
        timeout=network_wait * number_of_nodes,
    )

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

    # wait for the nodes to sync
    gevent.sleep(0.2)

    assert_synced_channel_state(
        token_network_identifier,
        app0,
        deposit - amount_path,
        [],
        app1,
        deposit + amount_path,
        [],
    )
    assert_synced_channel_state(
        token_network_identifier,
        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 = 3
    amount_refund = 50
    async_result = app0.raiden.mediated_transfer_async(
        token_network_identifier,
        amount_refund,
        app2.raiden.address,
        identifier_refund,
    )
    assert async_result.wait(
    ) is False, 'there is no path with capacity, the transfer must fail'

    gevent.sleep(0.2)

    # A lock structure with the correct amount

    send_locked = raiden_events_search_for_item(
        app0.raiden,
        SendLockedTransfer,
        {'transfer': {
            'lock': {
                'amount': amount_refund
            }
        }},
    )
    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
    assert_synced_channel_state(
        token_network_identifier,
        app0,
        deposit - amount_path,
        [lockstate_from_lock(lock)],
        app1,
        deposit + amount_path,
        [lockstate_from_lock(refund_lock)],
    )
    assert_synced_channel_state(
        token_network_identifier,
        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.get()
        assert not app1.raiden

        # Wait for lock expiration so that app0 sends a LockExpired
        wait_for_block(
            raiden=app0.raiden,
            block_number=channel.get_sender_expiration_threshold(lock) + 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=payment_network_identifier,
            token_address=token_address,
            partner_address=app1.raiden.address,
        )

    count = 0
    original_update = app1.raiden.raiden_event_handler.handle_contract_send_channelupdate

    def patched_update(raiden, event):
        nonlocal count
        count += 1
        original_update(raiden, event)

    app1.raiden.raiden_event_handler.handle_contract_send_channelupdate = patched_update
    # 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_identifier).identifier

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

    with gevent.Timeout(10):
        unlock_app0 = wait_for_state_change(
            app0.raiden,
            ContractReceiveChannelBatchUnlock,
            {'participant': app0.raiden.address},
            retry_timeout,
        )
    assert unlock_app0.returned_tokens == 50
    with gevent.Timeout(10):
        unlock_app1 = wait_for_state_change(
            app1.raiden,
            ContractReceiveChannelBatchUnlock,
            {'participant': app1.raiden.address},
            retry_timeout,
        )
    assert unlock_app1.returned_tokens == 50
    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
Ejemplo n.º 27
0
def test_different_view_of_last_bp_during_unlock(
    raiden_chain: List[RaidenService],
    restart_node,
    token_addresses,
    deposit,
    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.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_proxy = app0.proxy_manager.token(token_address, BLOCK_ID_LATEST)
    initial_balance0 = token_proxy.balance_of(app0.address)
    initial_balance1 = token_proxy.balance_of(app1.address)

    # make a transfer to test the path app0 -> app1 -> app2
    identifier_path = PaymentID(1)
    amount_path = PaymentAmount(1)
    with block_offset_timeout(app0):
        transfer(
            initiator_app=app0,
            target_app=app2,
            token_address=token_address,
            amount=amount_path,
            identifier=identifier_path,
            routes=[[app0.address, app1.address, app2.address]],
        )

    # drain the channel app1 -> app2
    identifier_drain = PaymentID(2)
    amount_drain = PaymentAmount(deposit * 8 // 10)
    with block_offset_timeout(app1):
        transfer(
            initiator_app=app1,
            target_app=app2,
            token_address=token_address,
            amount=amount_drain,
            identifier=identifier_drain,
            routes=[[app1.address, app2.address]],
        )
        wait_assert(
            assert_synced_channel_state,
            token_network_address,
            app0,
            deposit - amount_path,
            [],
            app1,
            deposit + amount_path,
            [],
        )
        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.mediated_transfer_async(
        token_network_address=token_network_address,
        amount=amount_refund,
        target=TargetAddress(app2.address),
        identifier=identifier_refund,
        route_states=[
            create_route_state_for_route(
                apps=raiden_chain,
                token_address=token_address,
                fee_estimate=FeeAmount(
                    round(INTERNAL_ROUTING_DEFAULT_FEE_PERC * amount_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,
        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, 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 block_offset_timeout(app0):
        wait_assert(
            assert_synced_channel_state,
            token_network_address,
            app0,
            deposit - amount_path,
            [lock],
            app1,
            deposit + amount_path,
            [refund_lock],
        )
        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).payment_mapping.secrethashes_to_task

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

        # Wait for lock expiration so that app0 sends a LockExpired
        wait_for_block(
            raiden=app0,
            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, SendLockExpired,
                              {"secrethash": secrethash}, retry_timeout)

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

    count = 0
    on_raiden_events_original = app1.raiden_event_handler.on_raiden_events

    def patched_on_raiden_events(raiden, chain_state, events):
        nonlocal count

        count += sum(1 for event in events
                     if type(event) == ContractSendChannelUpdateTransfer)

        on_raiden_events_original(raiden, chain_state, events)

    setattr(app1.raiden_event_handler, "on_raiden_events",
            patched_on_raiden_events)  # NOQA

    # and now app1 comes back online
    restart_node(app1)
    # 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,
        token_network_registry_address=token_network_registry_address,
        token_address=token_address,
        channel_ids=[channel_identifier],
        retry_timeout=app0.alarm.sleep_time,
    )

    timeout = 30 if blockchain_type == "parity" else 10
    with gevent.Timeout(timeout):
        unlock_app0 = wait_for_state_change(
            app0,
            ContractReceiveChannelBatchUnlock,
            {"receiver": app0.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,
            ContractReceiveChannelBatchUnlock,
            {"receiver": app1.address},
            retry_timeout,
        )
    assert unlock_app1
    assert unlock_app1.returned_tokens == amount_refund_with_fees
    final_balance0 = token_proxy.balance_of(app0.address)
    final_balance1 = token_proxy.balance_of(app1.address)

    assert final_balance0 - deposit - initial_balance0 == -1
    assert final_balance1 - deposit - initial_balance1 == 1
Ejemplo n.º 28
0
def test_secret_revealed_on_chain(
        raiden_chain,
        deposit,
        settle_timeout,
        token_addresses,
        retry_interval,
):
    """ 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_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(app0),
        app0.raiden.default_registry.address,
        token_address,
    )

    amount = 10
    identifier = 1
    target = app2.raiden.address
    secret = sha3(target)
    secrethash = sha3(secret)

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

    app0.raiden.start_mediated_transfer_with_secret(
        token_network_identifier,
        amount,
        target,
        identifier,
        secret,
    )

    with gevent.Timeout(10):
        wait_for_state_change(
            app2.raiden,
            ReceiveSecretReveal,
            {'secrethash': secrethash},
            retry_interval,
        )

    channel_state2_1 = get_channelstate(app2, app1, token_network_identifier)
    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
    channel_close_event = ContractSendChannelClose(
        channel_identifier=channel_state2_1.identifier,
        token_address=channel_state2_1.token_address,
        token_network_identifier=token_network_identifier,
        balance_proof=channel_state2_1.partner_state.balance_proof,
    )
    app2.raiden.raiden_event_handler.on_raiden_event(app2.raiden, channel_close_event)

    settle_expiration = (
        app0.raiden.chain.block_number() +
        settle_timeout +
        DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS
    )
    wait_until_block(app0.raiden.chain, 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_identifier,
        app0, deposit - amount, [],
        app1, deposit + amount, [],
    )

    with gevent.Timeout(10):
        wait_for_state_change(
            app2.raiden,
            ContractReceiveSecretReveal,
            {'secrethash': secrethash},
            retry_interval,
        )
Ejemplo n.º 29
0
def test_token_registered_race(raiden_chain, token_amount, retry_timeout, contract_manager):
    """If a token is registered it must appear on the token list.

    If two nodes register the same token one of the transactions will fail. The
    node that receives an error for "already registered token" must see the
    token in the token list. Issue: #784
    """
    app0, app1 = raiden_chain

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

    # Recreate the race condition by making sure the non-registering app won't
    # register at all by watching for the TokenAdded blockchain event.
    event_listeners = app1.raiden.blockchain_events.event_listeners
    app1.raiden.blockchain_events.event_listeners = list()

    token_address = deploy_contract_web3(
        contract_name=CONTRACT_HUMAN_STANDARD_TOKEN,
        deploy_client=app1.raiden.rpc_client,
        contract_manager=contract_manager,
        constructor_arguments=(token_amount, 2, "raiden", "Rd"),
    )

    # Wait until Raiden can start using the token contract.
    # Here, the block at which the contract was deployed should be confirmed by Raiden.
    # Therefore, until that block is received.
    waiting.wait_for_block(
        raiden=app0.raiden,
        block_number=app0.raiden.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1,
        retry_timeout=retry_timeout,
    )
    waiting.wait_for_block(
        raiden=app1.raiden,
        block_number=app1.raiden.get_block_number() + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS + 1,
        retry_timeout=retry_timeout,
    )

    registry_address = app0.raiden.default_registry.address
    assert token_address not in api0.get_tokens_list(registry_address)
    assert token_address not in api1.get_tokens_list(registry_address)

    api0.token_network_register(
        registry_address=registry_address,
        token_address=token_address,
        channel_participant_deposit_limit=UINT256_MAX,
        token_network_deposit_limit=UINT256_MAX,
    )
    exception = RuntimeError("Did not see the token registration within 30 seconds")
    with gevent.Timeout(seconds=30, exception=exception):
        wait_for_state_change(
            app0.raiden,
            ContractReceiveNewTokenNetwork,
            {"token_network": {"token_address": token_address}},
            retry_timeout,
        )

    assert token_address in api0.get_tokens_list(registry_address)
    assert token_address not in api1.get_tokens_list(registry_address)

    # The next time when the event is polled, the token is registered
    app1.raiden.blockchain_events.event_listeners = event_listeners
    waiting.wait_for_block(app1.raiden, app1.raiden.get_block_number() + 1, retry_timeout)

    assert token_address in api1.get_tokens_list(registry_address)