def test_initiator_log_directransfer_action(
        raiden_chain,
        token_addresses,
        deposit):
    """ The action that start a direct transfer must be logged in the WAL. """

    token_address = token_addresses[0]
    amount = int(deposit / 2.)
    identifier = 13

    app0, app1 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking
    direct_transfer(
        app0,
        app1,
        token_address,
        amount,
        identifier,
    )

    app0_state_changes = get_all_state_changes(app0.raiden.transaction_log)
    direct_transfers = [
        state_change
        for _, state_change in app0_state_changes
        if isinstance(state_change, ActionTransferDirect)
    ]
    assert direct_transfers[0] == ActionTransferDirect(
        identifier,
        amount,
        token_address,
        app1.raiden.address,
    )
예제 #2
0
    def direct_transfer_async(self, token_network_identifier, amount, target, identifier):
        """ Do a direct transfer with target.

        Direct transfers are non cancellable and non expirable, since these
        transfers are a signed balance proof with the transferred amount
        incremented.

        Because the transfer is non cancellable, there is a level of trust with
        the target. After the message is sent the target is effectively paid
        and then it is not possible to revert.

        The async result will be set to False iff there is no direct channel
        with the target or the payer does not have balance to complete the
        transfer, otherwise because the transfer is non expirable the async
        result *will never be set to False* and if the message is sent it will
        hang until the target node acknowledge the message.

        This transfer should be used as an optimization, since only two packets
        are required to complete the transfer (from the payers perspective),
        whereas the mediated transfer requires 6 messages.
        """

        self.start_health_check_for(target)

        if identifier is None:
            identifier = create_default_identifier()

        direct_transfer = ActionTransferDirect(
            token_network_identifier,
            target,
            identifier,
            amount,
        )

        self.handle_state_change(direct_transfer)
예제 #3
0
    def direct_transfer_async(self, token_network_identifier, amount, target,
                              identifier):
        """ Do a direct transfer with target.

        Direct transfers are non cancellable and non expirable, since these
        transfers are a signed balance proof with the transferred amount
        incremented.

        Because the transfer is non cancellable, there is a level of trust with
        the target. After the message is sent the target is effectively paid
        and then it is not possible to revert.

        The async result will be set to False iff there is no direct channel
        with the target or the payer does not have balance to complete the
        transfer, otherwise because the transfer is non expirable the async
        result *will never be set to False* and if the message is sent it will
        hang until the target node acknowledge the message.

        This transfer should be used as an optimization, since only two packets
        are required to complete the transfer (from the payers perspective),
        whereas the mediated transfer requires 6 messages.
        """

        self.start_health_check_for(target)

        if identifier is None:
            identifier = create_default_identifier()

        payment_status = self.targets_to_identifiers_to_statuses[target].get(
            identifier)
        if payment_status:
            if not payment_status.matches(PaymentType.DIRECT,
                                          token_network_identifier, amount):
                raise PaymentConflict(
                    'Another payment with the same id is in flight', )

            return payment_status.payment_done

        direct_transfer = ActionTransferDirect(
            token_network_identifier,
            target,
            identifier,
            amount,
        )

        payment_status = PaymentStatus(
            payment_type=PaymentType.DIRECT,
            payment_identifier=identifier,
            amount=amount,
            token_network_identifier=token_network_identifier,
            payment_done=AsyncResult(),
        )
        self.targets_to_identifiers_to_statuses[target][
            identifier] = payment_status

        self.handle_state_change(direct_transfer)

        return payment_status.payment_done
예제 #4
0
def test_transfer_statechange_operators():
    # pylint: disable=unneeded-not
    a = Block(2)
    b = Block(2)
    c = Block(3)

    assert a == b
    assert not a != b
    assert a != c
    assert not a == c

    a = ActionCancelPayment(2)
    b = ActionCancelPayment(2)
    c = ActionCancelPayment(3)

    assert a == b
    assert not a != b
    assert a != c
    assert not a == c

    token_network_identifier = factories.make_address()
    a = ActionTransferDirect(
        token_network_identifier,
        receiver_address=ADDRESS,
        payment_identifier=2,
        amount=2,
    )
    b = ActionTransferDirect(
        token_network_identifier,
        receiver_address=ADDRESS,
        payment_identifier=2,
        amount=2,
    )
    c = ActionTransferDirect(
        token_network_identifier,
        receiver_address=ADDRESS2,  # different recipient
        payment_identifier=2,
        amount=2,
    )

    assert a == b
    assert not a != b
    assert a != c
    assert not a == c
예제 #5
0
def make_direct_transfer_from_channel(
    payment_network_identifier,
    from_channel,
    partner_channel,
    amount,
    pkey,
):
    """ Helper to create and register a direct transfer from `from_channel` to
    `partner_channel`."""
    payment_identifier = channel.get_next_nonce(from_channel.our_state)
    pseudo_random_generator = random.Random()

    state_change = ActionTransferDirect(
        payment_network_identifier,
        from_channel.token_address,
        from_channel.partner_state.address,
        payment_identifier,
        amount,
    )

    iteration = channel.handle_send_directtransfer(
        from_channel,
        state_change,
        pseudo_random_generator,
    )
    assert isinstance(iteration.events[0], SendDirectTransfer)
    direct_transfer_message = DirectTransfer.from_event(iteration.events[0])

    address = privatekey_to_address(pkey)
    sign_key = PrivateKey(pkey)
    direct_transfer_message.sign(sign_key, address)

    # if this fails it's not the right key for the current `from_channel`
    assert direct_transfer_message.sender == from_channel.our_state.address

    balance_proof = balanceproof_from_envelope(direct_transfer_message)
    message_identifier = random.randint(0, UINT64_MAX)
    receive_direct = ReceiveTransferDirect(
        payment_network_identifier,
        from_channel.token_address,
        message_identifier,
        payment_identifier,
        balance_proof,
    )

    channel.handle_receive_directtransfer(
        partner_channel,
        receive_direct,
    )

    return direct_transfer_message
예제 #6
0
def test_transfer_statechange_operators():
    a = Block(2)
    b = Block(2)
    c = Block(3)

    assert a == b
    assert not a != b
    assert a != c
    assert not a == c

    a = ActionCancelTransfer(2)
    b = ActionCancelTransfer(2)
    c = ActionCancelTransfer(3)

    assert a == b
    assert not a != b
    assert a != c
    assert not a == c

    a = ActionTransferDirect(2, 2, ADDRESS, ADDRESS)
    b = ActionTransferDirect(2, 2, ADDRESS, ADDRESS)
    c = ActionTransferDirect(3, 4, ADDRESS, ADDRESS2)

    assert a == b
    assert not a != b
    assert a != c
    assert not a == c

    a = ReceiveTransferDirect(2, 2, ADDRESS, ADDRESS)
    b = ReceiveTransferDirect(2, 2, ADDRESS, ADDRESS)
    c = ReceiveTransferDirect(3, 4, ADDRESS, ADDRESS2)

    assert a == b
    assert not a != b
    assert a != c
    assert not a == c
예제 #7
0
    def direct_transfer_async(self, token_address, amount, target, identifier):
        """ Do a direct tranfer with target.

        Direct transfers are non cancellable and non expirable, since these
        transfers are a signed balance proof with the transferred amount
        incremented.

        Because the transfer is non cancellable, there is a level of trust with
        the target. After the message is sent the target is effectively paid
        and then it is not possible to revert.

        The async result will be set to False iff there is no direct channel
        with the target or the payer does not have balance to complete the
        transfer, otherwise because the transfer is non expirable the async
        result *will never be set to False* and if the message is sent it will
        hang until the target node acknowledge the message.

        This transfer should be used as an optimization, since only two packets
        are required to complete the transfer (from the payer's perspective),
        whereas the mediated transfer requires 6 messages.
        """
        graph = self.token_to_channelgraph[token_address]
        direct_channel = graph.partneraddress_to_channel.get(target)

        direct_channel_with_capacity = (direct_channel
                                        and direct_channel.can_transfer and
                                        amount <= direct_channel.distributable)

        if direct_channel_with_capacity:
            direct_transfer = direct_channel.create_directtransfer(
                amount, identifier)
            self.sign(direct_transfer)
            direct_channel.register_transfer(
                self.get_block_number(),
                direct_transfer,
            )

            direct_transfer_state_change = ActionTransferDirect(
                identifier,
                amount,
                token_address,
                direct_channel.partner_state.address,
            )
            # TODO: add the transfer sent event
            state_change_id = self.transaction_log.log(
                direct_transfer_state_change)

            # TODO: This should be set once the direct transfer is acknowledged
            transfer_success = EventTransferSentSuccess(
                identifier,
                amount,
                target,
            )
            self.transaction_log.log_events(state_change_id,
                                            [transfer_success],
                                            self.get_block_number())

            async_result = self.protocol.send_async(
                direct_channel.partner_state.address,
                direct_transfer,
            )

        else:
            async_result = AsyncResult()
            async_result.set(False)

        return async_result
예제 #8
0
    def _direct_or_mediated_transfer(self, token_address, amount, identifier, direct_channel):
        """ Check the direct channel and if possible use it, otherwise start a
        mediated transfer.
        """

        if not direct_channel.can_transfer:
            log.info(
                'DIRECT CHANNEL %s > %s is closed or has no funding',
                pex(direct_channel.our_state.address),
                pex(direct_channel.partner_state.address),
            )

            async_result = self._mediated_transfer(
                token_address,
                amount,
                identifier,
                direct_channel.partner_state.address,
            )

        elif amount > direct_channel.distributable:
            log.info(
                'DIRECT CHANNEL %s > %s doesnt have enough funds [%s]',
                pex(direct_channel.our_state.address),
                pex(direct_channel.partner_state.address),
                amount,
            )

            async_result = self._mediated_transfer(
                token_address,
                amount,
                identifier,
                direct_channel.partner_state.address,
            )

        else:
            direct_transfer = direct_channel.create_directtransfer(amount, identifier)
            self.sign(direct_transfer)
            direct_channel.register_transfer(
                self.get_block_number(),
                direct_transfer,
            )

            direct_transfer_state_change = ActionTransferDirect(
                identifier,
                amount,
                token_address,
                direct_channel.partner_state.address,
            )
            # TODO: add the transfer sent event
            state_change_id = self.transaction_log.log(direct_transfer_state_change)

            # TODO: This should be set once the direct transfer is acknowledged
            transfer_success = EventTransferSentSuccess(
                identifier,
            )
            self.transaction_log.log_events(
                state_change_id,
                [transfer_success],
                self.get_block_number()
            )

            async_result = self.protocol.send_async(
                direct_channel.partner_state.address,
                direct_transfer,
            )

        return async_result