Exemplo n.º 1
0
    def handle_contract_send_channelunlock(
            self,
            raiden: RaidenService,
            channel_unlock_event: ContractSendChannelBatchUnlock,
    ):
        token_network_identifier = channel_unlock_event.token_network_identifier
        channel_identifier = channel_unlock_event.channel_identifier
        participant = channel_unlock_event.participant
        token_address = channel_unlock_event.token_address

        payment_channel: PaymentChannel = raiden.chain.payment_channel(
            token_network_address=token_network_identifier,
            channel_id=channel_identifier,
        )
        token_network: TokenNetwork = payment_channel.token_network

        participants_details = token_network.detail_participants(
            participant1=raiden.address,
            participant2=participant,
            channel_identifier=channel_identifier,
        )

        our_details = participants_details.our_details
        our_locksroot = our_details.locksroot

        partner_details = participants_details.partner_details
        partner_locksroot = partner_details.locksroot

        is_partner_unlock = (
            partner_details.address == participant and
            partner_locksroot != EMPTY_HASH
        )
        is_our_unlock = (
            our_details.address == participant and
            our_locksroot != EMPTY_HASH
        )

        if is_partner_unlock:
            state_change_record = get_state_change_with_balance_proof(
                storage=raiden.wal.storage,
                chain_id=raiden.chain.network_id,
                token_network_identifier=token_network_identifier,
                channel_identifier=channel_identifier,
                balance_hash=partner_details.balance_hash,
                sender=participants_details.partner_details.address,
            )
            state_change_identifier = state_change_record.state_change_identifier
        elif is_our_unlock:
            event_record = get_event_with_balance_proof(
                storage=raiden.wal.storage,
                chain_id=raiden.chain.network_id,
                token_network_identifier=token_network_identifier,
                channel_identifier=channel_identifier,
                balance_hash=our_details.balance_hash,
            )
            state_change_identifier = event_record.state_change_identifier
        else:
            state_change_identifier = 0

        if not state_change_identifier:
            raise RaidenUnrecoverableError(
                f'Failed to find state/event that match current channel locksroots. '
                f'token:{to_checksum_address(token_address)} '
                f'token_network:{to_checksum_address(token_network_identifier)} '
                f'channel:{channel_identifier} '
                f'participant:{to_checksum_address(participant)} '
                f'our_locksroot:{to_hex(our_locksroot)} '
                f'partner_locksroot:{to_hex(partner_locksroot)} ',
            )

        # Replay state changes until a channel state is reached where
        # this channel state has the participants balance hash.
        restored_channel_state = channel_state_until_state_change(
            raiden=raiden,
            payment_network_identifier=raiden.default_registry.address,
            token_address=token_address,
            channel_identifier=channel_identifier,
            state_change_identifier=state_change_identifier,
        )

        our_state = restored_channel_state.our_state
        partner_state = restored_channel_state.partner_state
        if partner_state.address == participant:
            merkle_tree_leaves = get_batch_unlock(partner_state)
        elif our_state.address == participant:
            merkle_tree_leaves = get_batch_unlock(our_state)

        try:
            payment_channel.unlock(merkle_tree_leaves)
        except ChannelOutdatedError as e:
            log.error(
                str(e),
                node=pex(raiden.address),
            )
Exemplo n.º 2
0
    def handle_contract_send_channelunlock(
        self,
        raiden: RaidenService,
        channel_unlock_event: ContractSendChannelBatchUnlock,
    ):
        payment_channel: PaymentChannel = raiden.chain.payment_channel(
            channel_unlock_event.token_network_identifier,
            channel_unlock_event.channel_identifier,
        )
        token_network: TokenNetwork = payment_channel.token_network

        # Fetch on-chain balance hashes for both participants
        participants_details = token_network.detail_participants(
            raiden.address,
            channel_unlock_event.participant,
            channel_unlock_event.channel_identifier,
        )

        our_details = participants_details.our_details
        our_locksroot = our_details.locksroot

        partner_details = participants_details.partner_details
        partner_locksroot = partner_details.locksroot

        is_partner_unlock = (partner_details.address
                             == channel_unlock_event.participant
                             and partner_locksroot != EMPTY_HASH)
        is_our_unlock = (our_details.address
                         == channel_unlock_event.participant
                         and our_locksroot != EMPTY_HASH)

        if is_partner_unlock:
            record = raiden.wal.storage.get_latest_state_change_by_data_field({
                'balance_proof.chain_id':
                raiden.chain.network_id,
                'balance_proof.token_network_identifier':
                to_checksum_address(
                    channel_unlock_event.token_network_identifier, ),
                'balance_proof.channel_identifier':
                channel_unlock_event.channel_identifier,
                'balance_proof.sender':
                to_checksum_address(
                    participants_details.partner_details.address, ),
                'balance_proof.locksroot':
                serialize_bytes(partner_locksroot),
            })
        elif is_our_unlock:
            record = raiden.wal.storage.get_latest_event_by_data_field({
                'balance_proof.chain_id':
                raiden.chain.network_id,
                'balance_proof.token_network_identifier':
                to_checksum_address(
                    channel_unlock_event.token_network_identifier, ),
                'balance_proof.locksroot':
                serialize_bytes(our_locksroot),
                'channel_identifier':
                channel_unlock_event.channel_identifier,
            })
        else:
            raise RaidenUnrecoverableError(
                'Failed to find state/event that match current channel locksroots',
            )

        # Replay state changes until a channel state is reached where
        # this channel state has the participants balance hash.
        restored_channel_state = channel_state_until_state_change(
            raiden=raiden,
            payment_network_identifier=raiden.default_registry.address,
            token_address=channel_unlock_event.token_address,
            channel_identifier=channel_unlock_event.channel_identifier,
            state_change_identifier=record.state_change_identifier,
        )

        # Compute merkle tree leaves from partner state
        our_state = restored_channel_state.our_state
        partner_state = restored_channel_state.partner_state
        if partner_state.address == channel_unlock_event.participant:  # Partner account
            merkle_tree_leaves = get_batch_unlock(partner_state)
        elif our_state.address == channel_unlock_event.participant:  # Our account
            merkle_tree_leaves = get_batch_unlock(our_state)

        try:
            payment_channel.unlock(merkle_tree_leaves)
        except ChannelOutdatedError as e:
            log.error(
                str(e),
                node=pex(raiden.address),
            )
Exemplo n.º 3
0
    def handle_contract_send_channelunlock(
        raiden: "RaidenService",
        chain_state: ChainState,
        channel_unlock_event: ContractSendChannelBatchUnlock,
    ):
        assert raiden.wal, "The Raiden Service must be initialize to handle events"

        canonical_identifier = channel_unlock_event.canonical_identifier
        token_network_identifier = canonical_identifier.token_network_address
        channel_identifier = canonical_identifier.channel_identifier
        participant = channel_unlock_event.participant

        payment_channel: PaymentChannel = raiden.chain.payment_channel(
            canonical_identifier=canonical_identifier
        )

        channel_state = get_channelstate_by_token_network_and_partner(
            chain_state=chain_state,
            token_network_id=TokenNetworkID(token_network_identifier),
            partner_address=participant,
        )

        if not channel_state:
            # channel was cleaned up already due to an unlock
            raise RaidenUnrecoverableError(
                f"Failed to find channel state with partner:"
                f"{to_checksum_address(participant)}, token_network:pex(token_network_identifier)"
            )

        our_address = channel_state.our_state.address
        our_locksroot = channel_state.our_state.onchain_locksroot

        partner_address = channel_state.partner_state.address
        partner_locksroot = channel_state.partner_state.onchain_locksroot

        # we want to unlock because there are on-chain unlocked locks
        search_events = our_locksroot != EMPTY_HASH
        # we want to unlock, because there are unlocked/unclaimed locks
        search_state_changes = partner_locksroot != EMPTY_HASH

        if not search_events and not search_state_changes:
            # In the case that someone else sent the unlock we do nothing
            # Check https://github.com/raiden-network/raiden/issues/3152
            # for more details
            log.warning(
                "Onchain unlock already mined",
                canonical_identifier=canonical_identifier,
                channel_identifier=canonical_identifier.channel_identifier,
                participant=to_checksum_address(participant),
            )
            return

        if search_state_changes:
            state_change_record = get_state_change_with_balance_proof_by_locksroot(
                storage=raiden.wal.storage,
                canonical_identifier=canonical_identifier,
                locksroot=partner_locksroot,
                sender=partner_address,
            )
            state_change_identifier = state_change_record.state_change_identifier

            if not state_change_identifier:
                raise RaidenUnrecoverableError(
                    f"Failed to find state that matches the current channel locksroots. "
                    f"chain_id:{raiden.chain.network_id} "
                    f"token_network:{to_checksum_address(token_network_identifier)} "
                    f"channel:{channel_identifier} "
                    f"participant:{to_checksum_address(participant)} "
                    f"our_locksroot:{to_hex(our_locksroot)} "
                    f"partner_locksroot:{to_hex(partner_locksroot)} "
                )

            restored_channel_state = channel_state_until_state_change(
                raiden=raiden,
                canonical_identifier=canonical_identifier,
                state_change_identifier=state_change_identifier,
            )
            assert restored_channel_state is not None

            gain = get_batch_unlock_gain(restored_channel_state)

            skip_unlock = (
                restored_channel_state.partner_state.address == participant
                and gain.from_partner_locks == 0
            )
            if not skip_unlock:
                unlock(
                    raiden=raiden,
                    payment_channel=payment_channel,
                    end_state=restored_channel_state.partner_state,
                    participant=our_address,
                    partner=partner_address,
                )

        if search_events:
            event_record = get_event_with_balance_proof_by_locksroot(
                storage=raiden.wal.storage,
                canonical_identifier=canonical_identifier,
                locksroot=our_locksroot,
                recipient=partner_address,
            )
            state_change_identifier = event_record.state_change_identifier

            if not state_change_identifier:
                raise RaidenUnrecoverableError(
                    f"Failed to find event that match current channel locksroots. "
                    f"chain_id:{raiden.chain.network_id} "
                    f"token_network:{to_checksum_address(token_network_identifier)} "
                    f"channel:{channel_identifier} "
                    f"participant:{to_checksum_address(participant)} "
                    f"our_locksroot:{to_hex(our_locksroot)} "
                    f"partner_locksroot:{to_hex(partner_locksroot)} "
                )

            restored_channel_state = channel_state_until_state_change(
                raiden=raiden,
                canonical_identifier=canonical_identifier,
                state_change_identifier=state_change_identifier,
            )
            assert restored_channel_state is not None

            gain = get_batch_unlock_gain(restored_channel_state)

            skip_unlock = (
                restored_channel_state.our_state.address == participant
                and gain.from_our_locks == 0
            )
            if not skip_unlock:
                unlock(
                    raiden=raiden,
                    payment_channel=payment_channel,
                    end_state=restored_channel_state.our_state,
                    participant=partner_address,
                    partner=our_address,
                )
Exemplo n.º 4
0
def test_batch_unlock(raiden_network, token_addresses, secret_registry_address,
                      deposit):
    """Batch unlock can be called after the channel is settled."""
    alice_app, bob_app = raiden_network
    registry_address = alice_app.raiden.default_registry.address
    token_address = token_addresses[0]
    token_proxy = alice_app.raiden.chain.token(token_address)
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(alice_app),
        alice_app.raiden.default_registry.address,
        token_address,
    )

    # Take a snapshot early on
    alice_app.raiden.wal.snapshot()

    token_network = views.get_token_network_by_identifier(
        views.state_from_app(alice_app),
        token_network_identifier,
    )

    channel_identifier = get_channelstate(alice_app, bob_app,
                                          token_network_identifier).identifier

    assert channel_identifier in token_network.partneraddresses_to_channels[
        bob_app.raiden.address]

    alice_initial_balance = token_proxy.balance_of(alice_app.raiden.address)
    bob_initial_balance = token_proxy.balance_of(bob_app.raiden.address)

    # Take snapshot before transfer
    alice_app.raiden.wal.snapshot()

    alice_to_bob_amount = 10
    identifier = 1
    secret = pending_mediated_transfer(
        raiden_network,
        token_network_identifier,
        alice_to_bob_amount,
        identifier,
    )

    secrethash = sha3(secret)

    alice_bob_channel_state = get_channelstate(alice_app, bob_app,
                                               token_network_identifier)
    lock = channel.get_lock(alice_bob_channel_state.our_state, secrethash)

    # This is the current state of the protocol:
    #
    #    A -> B LockedTransfer
    #    B -> A SecretRequest
    #    - protocol didn't continue
    assert_synced_channel_state(
        token_network_identifier,
        alice_app,
        deposit,
        [lock],
        bob_app,
        deposit,
        [],
    )

    # Take a snapshot early on
    alice_app.raiden.wal.snapshot()

    our_balance_proof = alice_bob_channel_state.our_state.balance_proof

    # Test WAL restore to return the latest channel state
    restored_channel_state = channel_state_until_state_change(
        raiden=alice_app.raiden,
        payment_network_identifier=alice_app.raiden.default_registry.address,
        token_address=token_address,
        channel_identifier=alice_bob_channel_state.identifier,
        state_change_identifier='latest',
    )

    our_restored_balance_proof = restored_channel_state.our_state.balance_proof
    assert our_balance_proof == our_restored_balance_proof

    # A ChannelClose event will be generated, this will be polled by both apps
    # and each must start a task for calling settle
    RaidenAPI(bob_app.raiden).channel_close(
        registry_address,
        token_address,
        alice_app.raiden.address,
    )

    secret_registry_proxy = alice_app.raiden.chain.secret_registry(
        secret_registry_address, )
    secret_registry_proxy.register_secret(secret)

    assert lock, 'the lock must still be part of the node state'
    msg = 'the secret must be registered before the lock expires'
    assert lock.expiration > alice_app.raiden.get_block_number(), msg
    assert lock.secrethash == sha3(secret)

    waiting.wait_for_settle(
        alice_app.raiden,
        registry_address,
        token_address,
        [alice_bob_channel_state.identifier],
        alice_app.raiden.alarm.sleep_time,
    )

    token_network = views.get_token_network_by_identifier(
        views.state_from_app(bob_app),
        token_network_identifier,
    )

    assert channel_identifier in token_network.partneraddresses_to_channels[
        alice_app.raiden.address]

    # wait for the node to call batch unlock
    with gevent.Timeout(10):
        wait_for_batch_unlock(
            bob_app,
            token_network_identifier,
            alice_bob_channel_state.partner_state.address,
            alice_bob_channel_state.our_state.address,
        )

    token_network = views.get_token_network_by_identifier(
        views.state_from_app(bob_app),
        token_network_identifier,
    )

    assert channel_identifier not in token_network.partneraddresses_to_channels[
        alice_app.raiden.address]

    alice_new_balance = alice_initial_balance + deposit - alice_to_bob_amount
    bob_new_balance = bob_initial_balance + deposit + alice_to_bob_amount

    assert token_proxy.balance_of(
        alice_app.raiden.address) == alice_new_balance
    assert token_proxy.balance_of(bob_app.raiden.address) == bob_new_balance
Exemplo n.º 5
0
def test_batch_unlock(raiden_network, token_addresses, secret_registry_address, deposit):
    """Tests that batch unlock is properly called.

    This test will start a single incomplete transfer, the secret will be
    revealed *on-chain*. The node that receives the tokens has to call unlock,
    the node that doesn't gain anything does nothing.
    """
    alice_app, bob_app = raiden_network
    alice_address = alice_app.raiden.address
    bob_address = bob_app.raiden.address

    token_network_registry_address = alice_app.raiden.default_registry.address
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(alice_app), token_network_registry_address, token_address
    )
    assert token_network_address

    hold_event_handler = bob_app.raiden.raiden_event_handler

    # Take a snapshot early on
    alice_app.raiden.wal.snapshot()

    canonical_identifier = get_channelstate(
        alice_app, bob_app, token_network_address
    ).canonical_identifier

    assert is_channel_registered(alice_app, bob_app, canonical_identifier)
    assert is_channel_registered(bob_app, alice_app, canonical_identifier)

    token_proxy = alice_app.raiden.proxy_manager.token(token_address)
    alice_initial_balance = token_proxy.balance_of(alice_app.raiden.address)
    bob_initial_balance = token_proxy.balance_of(bob_app.raiden.address)

    # Take snapshot before transfer
    alice_app.raiden.wal.snapshot()

    alice_to_bob_amount = 10
    identifier = 1
    secret = Secret(sha3(bob_address))
    secrethash = sha256_secrethash(secret)

    secret_request_event = hold_event_handler.hold_secretrequest_for(secrethash=secrethash)

    alice_app.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=alice_to_bob_amount,
        target=bob_address,
        identifier=identifier,
        secret=secret,
    )

    secret_request_event.get()  # wait for the messages to be exchanged

    alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_address)
    lock = channel.get_lock(alice_bob_channel_state.our_state, secrethash)
    assert lock

    # This is the current state of the protocol:
    #
    #    A -> B LockedTransfer
    #    B -> A SecretRequest
    #    - protocol didn't continue
    assert_synced_channel_state(
        token_network_address, alice_app, deposit, [lock], bob_app, deposit, []
    )

    # Test WAL restore to return the latest channel state
    alice_app.raiden.wal.snapshot()
    our_balance_proof = alice_bob_channel_state.our_state.balance_proof
    restored_channel_state = channel_state_until_state_change(
        raiden=alice_app.raiden,
        canonical_identifier=alice_bob_channel_state.canonical_identifier,
        state_change_identifier=HIGH_STATECHANGE_ULID,
    )
    assert restored_channel_state
    our_restored_balance_proof = restored_channel_state.our_state.balance_proof
    assert our_balance_proof == our_restored_balance_proof

    # Close the channel before revealing the secret off-chain. This will leave
    # a pending lock in the channel which has to be unlocked on-chain.
    #
    # The token network will emit a ChannelClose event, this will be polled by
    # both apps and each must start a task for calling settle.
    RaidenAPI(bob_app.raiden).channel_close(
        token_network_registry_address, token_address, alice_app.raiden.address
    )

    # The secret has to be registered manually because Bob never learned the
    # secret. The test is holding the SecretRequest to ensure the off-chain
    # unlock will not happen and the channel is closed with a pending lock.
    #
    # Alternatives would be to hold the unlock messages, or to stop and restart
    # the apps after the channel is closed.
    secret_registry_proxy = alice_app.raiden.proxy_manager.secret_registry(secret_registry_address)
    secret_registry_proxy.register_secret(secret=secret)

    msg = (
        "The lock must still be part of the node state for the test to proceed, "
        "otherwise there is not unlock to be done."
    )
    assert lock, msg

    msg = (
        "The secret must be registered before the lock expires, in order for "
        "the unlock to happen on-chain. Otherwise the test will fail on the "
        "expected balances."
    )
    assert lock.expiration > alice_app.raiden.get_block_number(), msg
    assert lock.secrethash == sha256_secrethash(secret)

    waiting.wait_for_settle(
        alice_app.raiden,
        token_network_registry_address,
        token_address,
        [alice_bob_channel_state.identifier],
        alice_app.raiden.alarm.sleep_time,
    )

    msg = "The channel_state must not have been cleared, one of the ends has pending locks to do."
    assert is_channel_registered(alice_app, bob_app, canonical_identifier), msg
    assert is_channel_registered(bob_app, alice_app, canonical_identifier), msg

    msg = (
        "Timeout while waiting for the unlock to be mined. This may happen if "
        "transaction is rejected, not mined, or the node's alarm task is "
        "not running."
    )
    with gevent.Timeout(seconds=30, exception=AssertionError(msg)):
        # Wait for both nodes (Bob and Alice) to see the on-chain unlock
        wait_for_batch_unlock(
            app=alice_app,
            token_network_address=token_network_address,
            receiver=bob_address,
            sender=alice_address,
        )
        wait_for_batch_unlock(
            app=bob_app,
            token_network_address=token_network_address,
            receiver=bob_address,
            sender=alice_address,
        )

    msg = (
        "The nodes have done the unlock, and both ends have seen it, now the "
        "channel must be cleared"
    )
    assert not is_channel_registered(alice_app, bob_app, canonical_identifier), msg
    assert not is_channel_registered(bob_app, alice_app, canonical_identifier), msg

    alice_new_balance = alice_initial_balance + deposit - alice_to_bob_amount
    bob_new_balance = bob_initial_balance + deposit + alice_to_bob_amount

    msg = "Unexpected end balance after channel settlement with batch unlock."
    assert token_proxy.balance_of(alice_app.raiden.address) == alice_new_balance, msg
    assert token_proxy.balance_of(bob_app.raiden.address) == bob_new_balance, msg
Exemplo n.º 6
0
def test_batch_unlock(raiden_network, token_addresses, secret_registry_address, deposit):
    """Batch unlock can be called after the channel is settled."""
    alice_app, bob_app = raiden_network
    registry_address = alice_app.raiden.default_registry.address
    token_address = token_addresses[0]
    token_proxy = alice_app.raiden.chain.token(token_address)
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(alice_app),
        alice_app.raiden.default_registry.address,
        token_address,
    )

    hold_event_handler = HoldOffChainSecretRequest()
    bob_app.raiden.raiden_event_handler = hold_event_handler

    # Take a snapshot early on
    alice_app.raiden.wal.snapshot()

    token_network = views.get_token_network_by_identifier(
        views.state_from_app(alice_app),
        token_network_identifier,
    )

    channel_identifier = get_channelstate(alice_app, bob_app, token_network_identifier).identifier

    assert channel_identifier in token_network.partneraddresses_to_channelidentifiers[
        bob_app.raiden.address
    ]

    alice_initial_balance = token_proxy.balance_of(alice_app.raiden.address)
    bob_initial_balance = token_proxy.balance_of(bob_app.raiden.address)

    # Take snapshot before transfer
    alice_app.raiden.wal.snapshot()

    alice_to_bob_amount = 10
    identifier = 1
    target = bob_app.raiden.address
    secret = sha3(target)
    secrethash = sha3(secret)

    hold_event_handler.hold_secretrequest_for(secrethash=secrethash)

    alice_app.raiden.start_mediated_transfer_with_secret(
        token_network_identifier,
        alice_to_bob_amount,
        target,
        identifier,
        secret,
    )

    gevent.sleep(1)  # wait for the messages to be exchanged

    alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_identifier)
    lock = channel.get_lock(alice_bob_channel_state.our_state, secrethash)

    # This is the current state of the protocol:
    #
    #    A -> B LockedTransfer
    #    B -> A SecretRequest
    #    - protocol didn't continue
    assert_synced_channel_state(
        token_network_identifier,
        alice_app, deposit, [lock],
        bob_app, deposit, [],
    )

    # Take a snapshot early on
    alice_app.raiden.wal.snapshot()

    our_balance_proof = alice_bob_channel_state.our_state.balance_proof

    # Test WAL restore to return the latest channel state
    restored_channel_state = channel_state_until_state_change(
        raiden=alice_app.raiden,
        payment_network_identifier=alice_app.raiden.default_registry.address,
        token_address=token_address,
        channel_identifier=alice_bob_channel_state.identifier,
        state_change_identifier='latest',
    )

    our_restored_balance_proof = restored_channel_state.our_state.balance_proof
    assert our_balance_proof == our_restored_balance_proof

    # A ChannelClose event will be generated, this will be polled by both apps
    # and each must start a task for calling settle
    RaidenAPI(bob_app.raiden).channel_close(
        registry_address,
        token_address,
        alice_app.raiden.address,
    )

    secret_registry_proxy = alice_app.raiden.chain.secret_registry(
        secret_registry_address,
    )
    secret_registry_proxy.register_secret(secret)

    assert lock, 'the lock must still be part of the node state'
    msg = 'the secret must be registered before the lock expires'
    assert lock.expiration > alice_app.raiden.get_block_number(), msg
    assert lock.secrethash == sha3(secret)

    waiting.wait_for_settle(
        alice_app.raiden,
        registry_address,
        token_address,
        [alice_bob_channel_state.identifier],
        alice_app.raiden.alarm.sleep_time,
    )

    token_network = views.get_token_network_by_identifier(
        views.state_from_app(bob_app),
        token_network_identifier,
    )

    assert channel_identifier in token_network.partneraddresses_to_channelidentifiers[
        alice_app.raiden.address
    ]

    # wait for the node to call batch unlock
    with gevent.Timeout(10):
        wait_for_batch_unlock(
            bob_app,
            token_network_identifier,
            alice_bob_channel_state.partner_state.address,
            alice_bob_channel_state.our_state.address,
        )

    token_network = views.get_token_network_by_identifier(
        views.state_from_app(bob_app),
        token_network_identifier,
    )

    assert channel_identifier not in token_network.partneraddresses_to_channelidentifiers[
        alice_app.raiden.address
    ]

    alice_new_balance = alice_initial_balance + deposit - alice_to_bob_amount
    bob_new_balance = bob_initial_balance + deposit + alice_to_bob_amount

    assert token_proxy.balance_of(alice_app.raiden.address) == alice_new_balance
    assert token_proxy.balance_of(bob_app.raiden.address) == bob_new_balance
Exemplo n.º 7
0
def run_test_batch_unlock(raiden_network, token_addresses,
                          secret_registry_address, deposit, blockchain_type):
    """Batch unlock can be called after the channel is settled."""
    alice_app, bob_app = raiden_network
    registry_address = alice_app.raiden.default_registry.address
    token_address = token_addresses[0]
    token_proxy = alice_app.raiden.chain.token(token_address)
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(alice_app),
        alice_app.raiden.default_registry.address, token_address)

    hold_event_handler = HoldOffChainSecretRequest()
    bob_app.raiden.raiden_event_handler = hold_event_handler

    # Take a snapshot early on
    alice_app.raiden.wal.snapshot()

    token_network = views.get_token_network_by_identifier(
        views.state_from_app(alice_app), token_network_identifier)

    channel_identifier = get_channelstate(alice_app, bob_app,
                                          token_network_identifier).identifier

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

    alice_initial_balance = token_proxy.balance_of(alice_app.raiden.address)
    bob_initial_balance = token_proxy.balance_of(bob_app.raiden.address)

    # Take snapshot before transfer
    alice_app.raiden.wal.snapshot()

    alice_to_bob_amount = 10
    identifier = 1
    target = bob_app.raiden.address
    secret = sha3(target)
    secrethash = sha3(secret)

    hold_event_handler.hold_secretrequest_for(secrethash=secrethash)

    alice_app.raiden.start_mediated_transfer_with_secret(
        token_network_identifier=token_network_identifier,
        amount=alice_to_bob_amount,
        fee=0,
        target=target,
        identifier=identifier,
        secret=secret,
    )

    gevent.sleep(1)  # wait for the messages to be exchanged

    alice_bob_channel_state = get_channelstate(alice_app, bob_app,
                                               token_network_identifier)
    lock = channel.get_lock(alice_bob_channel_state.our_state, secrethash)

    # This is the current state of the protocol:
    #
    #    A -> B LockedTransfer
    #    B -> A SecretRequest
    #    - protocol didn't continue
    assert_synced_channel_state(token_network_identifier, alice_app, deposit,
                                [lock], bob_app, deposit, [])

    # Take a snapshot early on
    alice_app.raiden.wal.snapshot()

    our_balance_proof = alice_bob_channel_state.our_state.balance_proof

    # Test WAL restore to return the latest channel state
    restored_channel_state = channel_state_until_state_change(
        raiden=alice_app.raiden,
        canonical_identifier=alice_bob_channel_state.canonical_identifier,
        state_change_identifier="latest",
    )

    our_restored_balance_proof = restored_channel_state.our_state.balance_proof
    assert our_balance_proof == our_restored_balance_proof

    # A ChannelClose event will be generated, this will be polled by both apps
    # and each must start a task for calling settle
    RaidenAPI(bob_app.raiden).channel_close(registry_address, token_address,
                                            alice_app.raiden.address)

    secret_registry_proxy = alice_app.raiden.chain.secret_registry(
        secret_registry_address)
    secret_registry_proxy.register_secret(secret=secret)

    assert lock, "the lock must still be part of the node state"
    msg = "the secret must be registered before the lock expires"
    assert lock.expiration > alice_app.raiden.get_block_number(), msg
    assert lock.secrethash == sha3(secret)

    waiting.wait_for_settle(
        alice_app.raiden,
        registry_address,
        token_address,
        [alice_bob_channel_state.identifier],
        alice_app.raiden.alarm.sleep_time,
    )

    token_network = views.get_token_network_by_identifier(
        views.state_from_app(bob_app), token_network_identifier)

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

    # wait for the node to call batch unlock
    timeout = 30 if blockchain_type == "parity" else 10
    with gevent.Timeout(timeout):
        wait_for_batch_unlock(
            bob_app,
            token_network_identifier,
            alice_bob_channel_state.partner_state.address,
            alice_bob_channel_state.our_state.address,
        )

    token_network = views.get_token_network_by_identifier(
        views.state_from_app(bob_app), token_network_identifier)

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

    alice_new_balance = alice_initial_balance + deposit - alice_to_bob_amount
    bob_new_balance = bob_initial_balance + deposit + alice_to_bob_amount

    assert token_proxy.balance_of(
        alice_app.raiden.address) == alice_new_balance
    assert token_proxy.balance_of(bob_app.raiden.address) == bob_new_balance
Exemplo n.º 8
0
    def handle_contract_send_channelunlock(
        self,
        raiden: RaidenService,
        channel_unlock_event: ContractSendChannelBatchUnlock,
    ):
        token_network_identifier = channel_unlock_event.token_network_identifier
        channel_identifier = channel_unlock_event.channel_identifier
        participant = channel_unlock_event.participant
        token_address = channel_unlock_event.token_address

        payment_channel: PaymentChannel = raiden.chain.payment_channel(
            token_network_address=token_network_identifier,
            channel_id=channel_identifier,
        )
        token_network: TokenNetwork = payment_channel.token_network

        participants_details = token_network.detail_participants(
            participant1=raiden.address,
            participant2=participant,
            channel_identifier=channel_identifier,
        )

        our_details = participants_details.our_details
        our_locksroot = our_details.locksroot

        partner_details = participants_details.partner_details
        partner_locksroot = partner_details.locksroot

        is_partner_unlock = (partner_details.address == participant
                             and partner_locksroot != EMPTY_HASH)
        is_our_unlock = (our_details.address == participant
                         and our_locksroot != EMPTY_HASH)

        if not is_partner_unlock and not is_our_unlock:
            # In the case that someone else sent the unlock we do nothing
            # Check https://github.com/raiden-network/raiden/issues/3152
            # for more details
            log.warning(
                'Onchain unlock already mined',
                token_address=token_address,
                channel_identifier=channel_identifier,
                participant=participant,
            )
            return

        record = get_state_change_or_event_with_balance_proof(
            storage=raiden.wal.storage,
            chain_id=raiden.chain.network_id,
            token_network_identifier=token_network_identifier,
            channel_identifier=channel_identifier,
            is_our_unlock=is_our_unlock,
            is_partner_unlock=is_partner_unlock,
            our_balance_hash=our_details.balance_hash,
            partner_balance_hash=partner_details.balance_hash,
            sender=participants_details.partner_details.address,
        )

        if not record.state_change_identifier:
            log.warning(
                f'Unlock not done. '
                f'Failed to find state/event that match current channel locksroots. '
                f'token:{to_checksum_address(token_address)} '
                f'token_network:{to_checksum_address(token_network_identifier)} '
                f'channel:{channel_identifier} '
                f'participant:{to_checksum_address(participant)} '
                f'our_locksroot:{to_hex(our_locksroot)} '
                f'partner_locksroot:{to_hex(partner_locksroot)} ', )
            return

        # Replay state changes until a channel state is reached where
        # this channel state has the participants balance hash.
        restored_channel_state = channel_state_until_state_change(
            raiden=raiden,
            payment_network_identifier=raiden.default_registry.address,
            token_address=token_address,
            channel_identifier=channel_identifier,
            state_change_identifier=record.state_change_identifier,
        )

        our_state = restored_channel_state.our_state
        partner_state = restored_channel_state.partner_state
        if partner_state.address == participant:
            merkle_tree_leaves = get_batch_unlock(partner_state)
        elif our_state.address == participant:
            merkle_tree_leaves = get_batch_unlock(our_state)

        try:
            payment_channel.unlock(merkle_tree_leaves)
        except ChannelOutdatedError as e:
            log.error(
                str(e),
                node=pex(raiden.address),
            )
Exemplo n.º 9
0
    def handle_contract_send_channelunlock(
        raiden: "RaidenService",
        chain_state: ChainState,
        channel_unlock_event: ContractSendChannelBatchUnlock,
    ) -> None:
        assert raiden.wal, "The Raiden Service must be initialize to handle events"

        canonical_identifier = channel_unlock_event.canonical_identifier
        token_network_address = canonical_identifier.token_network_address
        channel_identifier = canonical_identifier.channel_identifier
        participant = channel_unlock_event.sender

        channel_state = get_channelstate_by_canonical_identifier(
            chain_state=state_from_raiden(raiden),
            canonical_identifier=canonical_identifier)
        if channel_state is None:
            raise RaidenUnrecoverableError(
                "ContractSendChannelBatchUnlock for inexesting channel.")

        confirmed_block_identifier = state_from_raiden(raiden).block_hash
        payment_channel: PaymentChannel = raiden.proxy_manager.payment_channel(
            channel_state=channel_state,
            block_identifier=confirmed_block_identifier)

        channel_state = get_channelstate_by_token_network_and_partner(
            chain_state=chain_state,
            token_network_address=token_network_address,
            partner_address=participant,
        )

        if not channel_state:
            # channel was cleaned up already due to an unlock
            raise RaidenUnrecoverableError(
                f"Failed to find channel state with partner:"
                f"{to_checksum_address(participant)}, "
                f"token_network:{to_checksum_address(token_network_address)}")

        our_address = channel_state.our_state.address
        our_locksroot = channel_state.our_state.onchain_locksroot

        partner_address = channel_state.partner_state.address
        partner_locksroot = channel_state.partner_state.onchain_locksroot

        # we want to unlock because there are on-chain unlocked locks
        search_events = our_locksroot != LOCKSROOT_OF_NO_LOCKS
        # we want to unlock, because there are unlocked/unclaimed locks
        search_state_changes = partner_locksroot != LOCKSROOT_OF_NO_LOCKS

        if not search_events and not search_state_changes:
            # In the case that someone else sent the unlock we do nothing
            # Check https://github.com/raiden-network/raiden/issues/3152
            # for more details
            log.warning(
                "Onchain unlock already mined",
                canonical_identifier=canonical_identifier,
                channel_identifier=canonical_identifier.channel_identifier,
                participant=to_checksum_address(participant),
            )
            return

        if search_state_changes:
            state_change_record = get_state_change_with_balance_proof_by_locksroot(
                storage=raiden.wal.storage,
                canonical_identifier=canonical_identifier,
                locksroot=partner_locksroot,
                sender=partner_address,
            )

            if state_change_record is None:
                raise RaidenUnrecoverableError(
                    f"Failed to find state that matches the current channel locksroots. "
                    f"chain_id:{raiden.rpc_client.chain_id} "
                    f"token_network:{to_checksum_address(token_network_address)} "
                    f"channel:{channel_identifier} "
                    f"participant:{to_checksum_address(participant)} "
                    f"our_locksroot:{to_hex(our_locksroot)} "
                    f"partner_locksroot:{to_hex(partner_locksroot)} ")

            state_change_identifier = state_change_record.state_change_identifier
            restored_channel_state = channel_state_until_state_change(
                raiden=raiden,
                canonical_identifier=canonical_identifier,
                state_change_identifier=state_change_identifier,
            )

            gain = get_batch_unlock_gain(restored_channel_state)

            skip_unlock = (restored_channel_state.partner_state.address
                           == participant and gain.from_partner_locks == 0)
            if not skip_unlock:
                unlock(
                    payment_channel=payment_channel,
                    end_state=restored_channel_state.partner_state,
                    sender=partner_address,
                    receiver=our_address,
                    given_block_identifier=channel_unlock_event.
                    triggered_by_block_hash,
                )

        if search_events:
            event_record = get_event_with_balance_proof_by_locksroot(
                storage=raiden.wal.storage,
                canonical_identifier=canonical_identifier,
                locksroot=our_locksroot,
                recipient=partner_address,
            )

            if event_record is None:
                raise RaidenUnrecoverableError(
                    f"Failed to find event that match current channel locksroots. "
                    f"chain_id:{raiden.rpc_client.chain_id} "
                    f"token_network:{to_checksum_address(token_network_address)} "
                    f"channel:{channel_identifier} "
                    f"participant:{to_checksum_address(participant)} "
                    f"our_locksroot:{to_hex(our_locksroot)} "
                    f"partner_locksroot:{to_hex(partner_locksroot)} ")

            state_change_identifier = event_record.state_change_identifier
            restored_channel_state = channel_state_until_state_change(
                raiden=raiden,
                canonical_identifier=canonical_identifier,
                state_change_identifier=state_change_identifier,
            )

            gain = get_batch_unlock_gain(restored_channel_state)

            skip_unlock = (restored_channel_state.our_state.address
                           == participant and gain.from_our_locks == 0)
            if not skip_unlock:
                try:
                    unlock(
                        payment_channel=payment_channel,
                        end_state=restored_channel_state.our_state,
                        sender=our_address,
                        receiver=partner_address,
                        given_block_identifier=channel_unlock_event.
                        triggered_by_block_hash,
                    )
                except InsufficientEth as e:
                    raise RaidenUnrecoverableError(str(e)) from e
Exemplo n.º 10
0
    def handle_contract_send_channelunlock(
            self,
            raiden: RaidenService,
            channel_unlock_event: ContractSendChannelBatchUnlock,
    ):
        token_network_identifier = channel_unlock_event.token_network_identifier
        channel_identifier = channel_unlock_event.channel_identifier
        participant = channel_unlock_event.participant
        token_address = channel_unlock_event.token_address

        payment_channel: PaymentChannel = raiden.chain.payment_channel(
            token_network_address=token_network_identifier,
            channel_id=channel_identifier,
        )
        token_network: TokenNetwork = payment_channel.token_network

        participants_details = token_network.detail_participants(
            participant1=raiden.address,
            participant2=participant,
            channel_identifier=channel_identifier,
        )

        our_details = participants_details.our_details
        our_locksroot = our_details.locksroot

        partner_details = participants_details.partner_details
        partner_locksroot = partner_details.locksroot

        is_partner_unlock = (
            partner_details.address == participant and
            partner_locksroot != EMPTY_HASH
        )
        is_our_unlock = (
            our_details.address == participant and
            our_locksroot != EMPTY_HASH
        )

        if is_partner_unlock:
            state_change_record = get_state_change_with_balance_proof_by_locksroot(
                storage=raiden.wal.storage,
                chain_id=raiden.chain.network_id,
                token_network_identifier=token_network_identifier,
                channel_identifier=channel_identifier,
                locksroot=partner_locksroot,
                sender=participants_details.partner_details.address,
            )
            state_change_identifier = state_change_record.state_change_identifier
        elif is_our_unlock:
            event_record = get_event_with_balance_proof_by_locksroot(
                storage=raiden.wal.storage,
                chain_id=raiden.chain.network_id,
                token_network_identifier=token_network_identifier,
                channel_identifier=channel_identifier,
                locksroot=our_locksroot.balance_hash,
            )
            state_change_identifier = event_record.state_change_identifier
        else:
            # In the case that someone else sent the unlock we do nothing
            # Check https://github.com/raiden-network/raiden/issues/3152
            # for more details
            log.warning(
                'Onchain unlock already mined',
                token_address=token_address,
                channel_identifier=channel_identifier,
                participant=participant,
            )
            return

        if not state_change_identifier:
            raise RaidenUnrecoverableError(
                f'Failed to find state/event that match current channel locksroots. '
                f'chain_id:{raiden.chain.network_id} '
                f'token:{to_checksum_address(token_address)} '
                f'token_network:{to_checksum_address(token_network_identifier)} '
                f'channel:{channel_identifier} '
                f'participant:{to_checksum_address(participant)} '
                f'our_locksroot:{to_hex(our_locksroot)} '
                f'our_balance_hash:{to_hex(our_details.balance_hash)} '
                f'partner_locksroot:{to_hex(partner_locksroot)} '
                f'partner_balancehash:{to_hex(partner_details.balance_hash)} ',
            )

        # Replay state changes until a channel state is reached where
        # this channel state has the participants balance hash.
        restored_channel_state = channel_state_until_state_change(
            raiden=raiden,
            payment_network_identifier=raiden.default_registry.address,
            token_address=token_address,
            channel_identifier=channel_identifier,
            state_change_identifier=state_change_identifier,
        )

        our_state = restored_channel_state.our_state
        partner_state = restored_channel_state.partner_state
        if partner_state.address == participant:
            merkle_tree_leaves = get_batch_unlock(partner_state)
        elif our_state.address == participant:
            merkle_tree_leaves = get_batch_unlock(our_state)

        try:
            payment_channel.unlock(merkle_tree_leaves)
        except ChannelOutdatedError as e:
            log.error(
                str(e),
                node=pex(raiden.address),
            )
Exemplo n.º 11
0
    def handle_contract_send_channelunlock(
        raiden: 'RaidenService',
        channel_unlock_event: ContractSendChannelBatchUnlock,
    ):
        token_network_identifier = channel_unlock_event.token_network_identifier
        channel_identifier = channel_unlock_event.channel_identifier
        canonical_identifier = CanonicalIdentifier(
            chain_identifier=raiden.chain.network_id,
            token_network_address=token_network_identifier,
            channel_identifier=channel_identifier,
        )
        participant = channel_unlock_event.participant
        token_address = channel_unlock_event.token_address

        payment_channel: PaymentChannel = raiden.chain.payment_channel(
            canonical_identifier=canonical_identifier, )

        channel_state = get_channelstate_by_token_network_and_partner(
            chain_state=state_from_raiden(raiden),
            token_network_id=token_network_identifier,
            partner_address=participant,
        )

        if not channel_state:
            # channel was cleaned up already due to an unlock
            raise RaidenUnrecoverableError(
                f'Failed to find channel state with partner '
                f'{participant}, token_network:pex(token_network_identifier)',
            )

        our_address = channel_state.our_state.address
        our_locksroot = channel_state.our_state.onchain_locksroot

        partner_address = channel_state.partner_state.address
        partner_locksroot = channel_state.partner_state.onchain_locksroot

        # we want to unlock because there are on-chain unlocked locks
        search_events = our_locksroot != EMPTY_HASH
        # we want to unlock, because there are unlocked/unclaimed locks
        search_state_changes = partner_locksroot != EMPTY_HASH

        if not search_events and not search_state_changes:
            # In the case that someone else sent the unlock we do nothing
            # Check https://github.com/raiden-network/raiden/issues/3152
            # for more details
            log.warning(
                'Onchain unlock already mined',
                token_address=token_address,
                channel_identifier=canonical_identifier.channel_identifier,
                participant=participant,
            )
            return

        if search_state_changes:
            state_change_record = get_state_change_with_balance_proof_by_locksroot(
                storage=raiden.wal.storage,
                canonical_identifier=canonical_identifier,
                locksroot=partner_locksroot,
                sender=partner_address,
            )
            state_change_identifier = state_change_record.state_change_identifier

            if not state_change_identifier:
                raise RaidenUnrecoverableError(
                    f'Failed to find state that matches the current channel locksroots. '
                    f'chain_id:{raiden.chain.network_id} '
                    f'token:{to_checksum_address(token_address)} '
                    f'token_network:{to_checksum_address(token_network_identifier)} '
                    f'channel:{channel_identifier} '
                    f'participant:{to_checksum_address(participant)} '
                    f'our_locksroot:{to_hex(our_locksroot)} '
                    f'partner_locksroot:{to_hex(partner_locksroot)} ', )

            restored_channel_state = channel_state_until_state_change(
                raiden=raiden,
                payment_network_identifier=raiden.default_registry.address,
                token_address=token_address,
                channel_identifier=channel_identifier,
                state_change_identifier=state_change_identifier,
            )

            gain = get_batch_unlock_gain(restored_channel_state, )

            skip_unlock = (restored_channel_state.partner_state.address
                           == participant and gain.from_partner_locks == 0)
            if not skip_unlock:
                unlock(
                    raiden=raiden,
                    payment_channel=payment_channel,
                    end_state=restored_channel_state.partner_state,
                    participant=our_address,
                    partner=partner_address,
                )

        if search_events:
            event_record = get_event_with_balance_proof_by_locksroot(
                storage=raiden.wal.storage,
                canonical_identifier=canonical_identifier,
                locksroot=our_locksroot,
                recipient=partner_address,
            )
            state_change_identifier = event_record.state_change_identifier

            if not state_change_identifier:
                raise RaidenUnrecoverableError(
                    f'Failed to find event that match current channel locksroots. '
                    f'chain_id:{raiden.chain.network_id} '
                    f'token:{to_checksum_address(token_address)} '
                    f'token_network:{to_checksum_address(token_network_identifier)} '
                    f'channel:{channel_identifier} '
                    f'participant:{to_checksum_address(participant)} '
                    f'our_locksroot:{to_hex(our_locksroot)} '
                    f'partner_locksroot:{to_hex(partner_locksroot)} ', )

            restored_channel_state = channel_state_until_state_change(
                raiden=raiden,
                payment_network_identifier=raiden.default_registry.address,
                token_address=token_address,
                channel_identifier=canonical_identifier.channel_identifier,
                state_change_identifier=state_change_identifier,
            )

            gain = get_batch_unlock_gain(restored_channel_state, )

            skip_unlock = (restored_channel_state.our_state.address
                           == participant and gain.from_our_locks == 0)
            if not skip_unlock:
                unlock(
                    raiden=raiden,
                    payment_channel=payment_channel,
                    end_state=restored_channel_state.our_state,
                    participant=partner_address,
                    partner=our_address,
                )