Example #1
0
def handle_inittarget(state_change):
    """ Handles an ActionInitTarget state change. """
    from_transfer = state_change.from_transfer
    from_route = state_change.from_route
    block_number = state_change.block_number

    state = TargetState(
        state_change.our_address,
        from_route,
        from_transfer,
        block_number,
    )

    safe_to_wait = is_safe_to_wait(
        from_transfer,
        from_route.reveal_timeout,
        block_number,
    )

    # if there is not enough time to safely withdraw the token on-chain
    # silently let the transfer expire.
    if safe_to_wait:
        secret_request = SendSecretRequest(
            from_transfer.identifier,
            from_transfer.amount,
            from_transfer.hashlock,
            from_transfer.initiator,
        )

        iteration = TransitionResult(state, [secret_request])
    else:
        iteration = TransitionResult(state, list())

    return iteration
Example #2
0
def handle_inittarget(
    state_change,
    channel_state,
    pseudo_random_generator,
    block_number,
):
    """ Handles an ActionInitTarget state change. """
    transfer = state_change.transfer
    route = state_change.route

    target_state = TargetTransferState(
        route,
        transfer,
    )

    assert channel_state.identifier == transfer.balance_proof.channel_address
    is_valid, _, errormsg = channel.handle_receive_lockedtransfer(
        channel_state,
        transfer,
    )

    safe_to_wait = is_safe_to_wait(
        transfer.lock.expiration,
        channel_state.reveal_timeout,
        block_number,
    )

    # if there is not enough time to safely withdraw the token on-chain
    # silently let the transfer expire.
    if is_valid and safe_to_wait:
        message_identifier = message_identifier_from_prng(
            pseudo_random_generator)
        recipient = transfer.initiator
        queue_name = b'global'
        secret_request = SendSecretRequest(
            recipient,
            queue_name,
            message_identifier,
            transfer.payment_identifier,
            transfer.lock.amount,
            transfer.lock.secrethash,
        )

        iteration = TransitionResult(target_state, [secret_request])
    else:
        if not is_valid:
            failure_reason = errormsg
        elif not safe_to_wait:
            failure_reason = 'lock expiration is not safe'

        withdraw_failed = EventWithdrawFailed(
            identifier=transfer.payment_identifier,
            secrethash=transfer.lock.secrethash,
            reason=failure_reason,
        )
        iteration = TransitionResult(target_state, [withdraw_failed])

    return iteration
Example #3
0
def handle_inittarget(
    state_change,
    channel_state,
    pseudo_random_generator,
    block_number,
):
    """ Handles an ActionInitTarget state change. """
    transfer = state_change.transfer
    route = state_change.route

    target_state = TargetTransferState(
        route,
        transfer,
    )

    assert channel_state.identifier == transfer.balance_proof.channel_identifier
    is_valid, _, errormsg = channel.handle_receive_lockedtransfer(
        channel_state,
        transfer,
    )

    safe_to_wait, unsafe_msg = is_safe_to_wait(
        transfer.lock.expiration,
        channel_state.reveal_timeout,
        block_number,
    )

    # if there is not enough time to safely unlock the token on-chain
    # silently let the transfer expire.
    if is_valid and safe_to_wait:
        message_identifier = message_identifier_from_prng(
            pseudo_random_generator)
        recipient = transfer.initiator
        secret_request = SendSecretRequest(
            recipient=recipient,
            channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE,
            message_identifier=message_identifier,
            payment_identifier=transfer.payment_identifier,
            amount=transfer.lock.amount,
            expiration=transfer.lock.expiration,
            secrethash=transfer.lock.secrethash,
        )

        iteration = TransitionResult(target_state, [secret_request])
    else:
        if not is_valid:
            failure_reason = errormsg
        elif not safe_to_wait:
            failure_reason = unsafe_msg

        unlock_failed = EventUnlockClaimFailed(
            identifier=transfer.payment_identifier,
            secrethash=transfer.lock.secrethash,
            reason=failure_reason,
        )
        iteration = TransitionResult(target_state, [unlock_failed])

    return iteration
Example #4
0
def handle_inittarget(state_change, channel_state, block_number):
    """ Handles an ActionInitTarget state change. """
    transfer = state_change.transfer
    route = state_change.route

    target_state = TargetTransferState(
        route,
        transfer,
    )

    assert channel_state.identifier == transfer.balance_proof.channel_address
    is_valid, errormsg = channel.handle_receive_mediatedtransfer(
        channel_state,
        transfer,
    )

    safe_to_wait = is_safe_to_wait(
        transfer.lock.expiration,
        channel_state.reveal_timeout,
        block_number,
    )

    # if there is not enough time to safely withdraw the token on-chain
    # silently let the transfer expire.
    if is_valid and safe_to_wait:
        secret_request = SendSecretRequest(
            transfer.identifier,
            transfer.lock.amount,
            transfer.lock.hashlock,
            transfer.initiator,
        )

        iteration = TransitionResult(target_state, [secret_request])
    else:
        if not is_valid:
            failure_reason = errormsg
        elif not safe_to_wait:
            failure_reason = 'lock expiration is not safe'

        withdraw_failed = EventWithdrawFailed(
            identifier=transfer.identifier,
            hashlock=transfer.lock.hashlock,
            reason=failure_reason,
        )
        iteration = TransitionResult(target_state, [withdraw_failed])

    return iteration
Example #5
0
def handle_inittarget(
    state_change: ActionInitTarget,
    channel_state: NettingChannelState,
    pseudo_random_generator: random.Random,
    block_number: typing.BlockNumber,
):
    """ Handles an ActionInitTarget state change. """
    transfer = state_change.transfer
    route = state_change.route

    assert channel_state.identifier == transfer.balance_proof.channel_identifier
    is_valid, channel_events, errormsg = channel.handle_receive_lockedtransfer(
        channel_state,
        transfer,
    )

    if is_valid:
        # A valid balance proof does not mean the payment itself is still valid.
        # e.g. the lock may be near expiration or have expired. This is fine. The
        # message with an unusable lock must be handled to properly synchronize the
        # local view of the partner's channel state, allowing the next balance
        # proofs to be handled. This however, must only be done once, which is
        # enforced by the nonce increasing sequentially, which is verified by
        # the handler handle_receive_lockedtransfer.
        target_state = TargetTransferState(route, transfer)

        safe_to_wait, _ = is_safe_to_wait(
            transfer.lock.expiration,
            channel_state.reveal_timeout,
            block_number,
        )

        # If there is not enough time to safely unlock the lock on-chain
        # silently let the transfer expire. The target task must be created to
        # handle the ReceiveLockExpired state change, which will clear the
        # expired lock.
        if safe_to_wait:
            message_identifier = message_identifier_from_prng(
                pseudo_random_generator)
            recipient = transfer.initiator
            secret_request = SendSecretRequest(
                recipient=typing.Address(recipient),
                channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE,
                message_identifier=message_identifier,
                payment_identifier=transfer.payment_identifier,
                amount=transfer.lock.amount,
                expiration=transfer.lock.expiration,
                secrethash=transfer.lock.secrethash,
            )
            channel_events.append(secret_request)

        iteration = TransitionResult(target_state, channel_events)
    else:
        # If the balance proof is not valid, do *not* create a task. Otherwise it's
        # possible for an attacker to send multiple invalid transfers, and increase
        # the memory usage of this Node.
        unlock_failed = EventUnlockClaimFailed(
            identifier=transfer.payment_identifier,
            secrethash=transfer.lock.secrethash,
            reason=errormsg,
        )
        channel_events.append(unlock_failed)
        iteration = TransitionResult(None, channel_events)

    return iteration
Example #6
0
def handle_inittarget_light(
    state_change: ActionInitTargetLight,
    channel_state: NettingChannelState,
    pseudo_random_generator: random.Random,
    block_number: BlockNumber,
    storage
) -> TransitionResult[TargetTransferState]:
    """ Handles an ActionInitTarget state change. """
    transfer = state_change.transfer
    route = state_change.route

    assert channel_state.identifier == transfer.balance_proof.channel_identifier
    is_valid, channel_events, errormsg, handle_invoice_result = channel.handle_receive_lockedtransfer_light(
        channel_state, transfer, storage
    )

    if is_valid:
        # A valid balance proof does not mean the payment itself is still valid.
        # e.g. the lock may be near expiration or have expired. This is fine. The
        # message with an unusable lock must be handled to properly synchronize the
        # local view of the partner's channel state, allowing the next balance
        # proofs to be handled. This however, must only be done once, which is
        # enforced by the nonce increasing sequentially, which is verified by
        # the handler handle_receive_lockedtransfer.
        target_state = TargetTransferState(route, transfer)

        safe_to_wait, _ = is_safe_to_wait(
            transfer.lock.expiration, channel_state.reveal_timeout, block_number
        )

        # If there is not enough time to safely unlock the lock on-chain
        # silently let the transfer expire. The target task must be created to
        # handle the ReceiveLockExpired state change, which will clear the
        # expired lock.
        #
        # We add a new validation.
        # It is verified that if there was an invoice it was paid successfully,
        # if it was not, the payment is interrupted
        # by not generating an event send secret request
        if safe_to_wait and handle_invoice_result['is_valid']:
            payment = LightClientPayment(
                state_change.transfer.target, state_change.transfer.initiator,
                False,
                channel_state.token_network_identifier,
                transfer.lock.amount,
                str(date.today()),
                LightClientPaymentStatus.Pending,
                transfer.payment_identifier
            )

            payment_exists = LightClientService.get_light_client_payment(payment.payment_id, storage)
            if not payment_exists:
                LightClientMessageHandler.store_light_client_payment(payment, storage)

            message_identifier = message_identifier_from_prng(pseudo_random_generator)
            recipient = transfer.initiator
            secret_request = SendSecretRequest(
                recipient=Address(recipient),
                channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE,
                message_identifier=message_identifier,
                payment_identifier=transfer.payment_identifier,
                amount=transfer.lock.amount,
                expiration=transfer.lock.expiration,
                secrethash=transfer.lock.secrethash,
            )

            store_locked_transfer_event = StoreMessageEvent(transfer.message_identifier, transfer.payment_identifier, 1,
                                                            state_change.signed_lockedtransfer, True)

            secret_request_message = SecretRequest.from_event(secret_request)
            store_secret_request_event = StoreMessageEvent(message_identifier, transfer.payment_identifier, 5,
                                                           secret_request_message, False)
            channel_events.append(store_secret_request_event)
            channel_events.append(store_locked_transfer_event)

        iteration = TransitionResult(target_state, channel_events)
    else:
        # If the balance proof is not valid, do *not* create a task. Otherwise it's
        # possible for an attacker to send multiple invalid transfers, and increase
        # the memory usage of this Node.
        assert errormsg, "handle_receive_lockedtransfer should return error msg if not valid"
        unlock_failed = EventUnlockClaimFailed(
            identifier=transfer.payment_identifier,
            secrethash=transfer.lock.secrethash,
            reason=errormsg,
        )
        channel_events.append(unlock_failed)
        iteration = TransitionResult(None, channel_events)

    return iteration