Пример #1
0
def handle_secretrequest(
    initiator_state: InitiatorTransferState,
    state_change: ReceiveSecretRequest,
    channel_state: NettingChannelState,
    pseudo_random_generator: random.Random,
) -> TransitionResult[InitiatorTransferState]:
    is_message_from_target = (
        state_change.sender == initiator_state.transfer_description.target
        and state_change.secrethash == initiator_state.transfer_description.secrethash
        and state_change.payment_identifier
        == initiator_state.transfer_description.payment_identifier
    )

    lock = channel.get_lock(
        channel_state.our_state, initiator_state.transfer_description.secrethash
    )

    # This should not ever happen. This task clears itself when the lock is
    # removed.
    assert lock is not None, "channel is does not have the transfer's lock"

    already_received_secret_request = initiator_state.received_secret_request

    # lock.amount includes the fees, transfer_description.amount is the actual
    # payment amount, for the transfer to be valid and the unlock allowed the
    # target must receive an amount between these values.
    is_valid_secretrequest = (
        state_change.amount <= lock.amount
        and state_change.amount >= initiator_state.transfer_description.amount
        and state_change.expiration == lock.expiration
        ## and initiator_state.transfer_description.secret != EMPTY_SECRET
    )

    if already_received_secret_request and is_message_from_target:
        # A secret request was received earlier, all subsequent are ignored
        # as it might be an attack
        iteration = TransitionResult(initiator_state, list())

    elif is_valid_secretrequest and is_message_from_target:
        # Reveal the secret to the target node and wait for its confirmation.
        # At this point the transfer is not cancellable anymore as either the lock
        # timeouts or a secret reveal is received.
        #
        # Note: The target might be the first hop
        #
        message_identifier = message_identifier_from_prng(pseudo_random_generator)
        transfer_description = initiator_state.transfer_description
        recipient = transfer_description.target
        secret = transfer_description.secret
        revealsecret = SendSecretReveal(
            recipient=Address(recipient),
            channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE,
            message_identifier=message_identifier,
            secret=secret,
        )

        initiator_state.revealsecret = revealsecret
        initiator_state.received_secret_request = True
        iteration = TransitionResult(initiator_state, [revealsecret])

    elif not is_valid_secretrequest and is_message_from_target:
        initiator_state.received_secret_request = True
        iteration = TransitionResult(initiator_state, list())

    else:
        iteration = TransitionResult(initiator_state, list())

    return iteration
Пример #2
0
def handle_secretrequest(
    initiator_state: InitiatorTransferState,
    state_change: ReceiveSecretRequest,
    channel_state: NettingChannelState,
    pseudo_random_generator: random.Random,
) -> TransitionResult[InitiatorTransferState]:

    is_message_from_target = (
        state_change.sender == Address(
            initiator_state.transfer_description.target)
        and state_change.secrethash
        == initiator_state.transfer_description.secrethash
        and state_change.payment_identifier
        == initiator_state.transfer_description.payment_identifier)
    if not is_message_from_target:
        return TransitionResult(initiator_state, list())

    lock = channel.get_lock(channel_state.our_state,
                            initiator_state.transfer_description.secrethash)

    # This should not ever happen. This task clears itself when the lock is
    # removed.
    assert lock is not None, "channel is does not have the transfer's lock"

    if initiator_state.received_secret_request:
        # A secret request was received earlier, all subsequent are ignored
        # as it might be an attack.
        return TransitionResult(initiator_state, list())

    # transfer_description.amount is the actual payment amount without fees.
    # For the transfer to be valid and the unlock allowed the target must
    # receive at least that amount.
    is_valid_secretrequest = (
        state_change.amount >= initiator_state.transfer_description.amount
        and state_change.expiration == lock.expiration
        and initiator_state.transfer_description.secret != ABSENT_SECRET)

    if is_valid_secretrequest:
        # Reveal the secret to the target node and wait for its confirmation.
        # At this point the transfer is not cancellable anymore as either the lock
        # timeouts or a secret reveal is received.
        #
        # Note: The target might be the first hop
        #
        message_identifier = message_identifier_from_prng(
            pseudo_random_generator)
        transfer_description = initiator_state.transfer_description
        recipient = transfer_description.target
        revealsecret = SendSecretReveal(
            recipient=Address(recipient),
            message_identifier=message_identifier,
            secret=transfer_description.secret,
            canonical_identifier=CANONICAL_IDENTIFIER_UNORDERED_QUEUE,
        )

        initiator_state.transfer_state = "transfer_secret_revealed"
        initiator_state.received_secret_request = True
        return TransitionResult(initiator_state, [revealsecret])
    else:
        initiator_state.received_secret_request = True
        invalid_request = EventInvalidSecretRequest(
            payment_identifier=state_change.payment_identifier,
            intended_amount=initiator_state.transfer_description.amount,
            actual_amount=state_change.amount,
        )
        return TransitionResult(initiator_state, [invalid_request])
Пример #3
0
def handle_secretrequest(
    initiator_state: InitiatorTransferState,
    state_change: ReceiveSecretRequest,
    channel_state: NettingChannelState,
    pseudo_random_generator: random.Random,
) -> TransitionResult:

    is_message_from_target = (
        state_change.sender == initiator_state.transfer_description.target
        and state_change.secrethash
        == initiator_state.transfer_description.secrethash
        and state_change.payment_identifier
        == initiator_state.transfer_description.payment_identifier)

    lock = channel.get_lock(
        channel_state.our_state,
        initiator_state.transfer_description.secrethash,
    )

    already_received_secret_request = initiator_state.received_secret_request

    is_valid_secretrequest = (state_change.amount
                              == initiator_state.transfer_description.amount
                              and state_change.expiration == lock.expiration)

    if already_received_secret_request and is_message_from_target:
        # A secret request was received earlier, all subsequent are ignored
        # as it might be an attack
        iteration = TransitionResult(initiator_state, list())

    elif is_valid_secretrequest and is_message_from_target:
        # Reveal the secret to the target node and wait for its confirmation.
        # At this point the transfer is not cancellable anymore as either the lock
        # timeouts or a secret reveal is received.
        #
        # Note: The target might be the first hop
        #
        message_identifier = message_identifier_from_prng(
            pseudo_random_generator)
        transfer_description = initiator_state.transfer_description
        recipient = transfer_description.target
        revealsecret = SendSecretReveal(
            recipient=typing.Address(recipient),
            channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE,
            message_identifier=message_identifier,
            secret=transfer_description.secret,
        )

        initiator_state.revealsecret = revealsecret
        initiator_state.received_secret_request = True
        iteration = TransitionResult(initiator_state, [revealsecret])

    elif not is_valid_secretrequest and is_message_from_target:
        cancel = EventPaymentSentFailed(
            payment_network_identifier=channel_state.
            payment_network_identifier,
            token_network_identifier=channel_state.token_network_identifier,
            identifier=initiator_state.transfer_description.payment_identifier,
            target=initiator_state.transfer_description.target,
            reason='bad secret request message from target',
        )

        initiator_state.received_secret_request = True
        iteration = TransitionResult(initiator_state, [cancel])

    else:
        iteration = TransitionResult(initiator_state, list())

    return iteration
Пример #4
0
def handle_offchain_secretreveal_light(
    target_state: TargetTransferState,
    state_change: ReceiveSecretRevealLight,
    channel_state: NettingChannelState,
    pseudo_random_generator: random.Random,
    block_number: BlockNumber,
) -> TransitionResult[TargetTransferState]:
    """ Validates and handles a ReceiveSecretReveal state change. """
    valid_secret = is_valid_secret_reveal(
        state_change=state_change,
        transfer_secrethash=target_state.transfer.lock.secrethash,
        secret=state_change.secret,
    )
    has_transfer_expired = channel.is_transfer_expired(
        transfer=target_state.transfer, affected_channel=channel_state, block_number=block_number
    )

    if valid_secret and not has_transfer_expired:
        # TODO mmarcosmartinez7 this cannot be done without LC interaction
        # channel.register_offchain_secret(
        #     channel_state=channel_state,
        #     secret=state_change.secret,
        #     secrethash=state_change.secrethash,
        # )

        route = target_state.route
        message_identifier = message_identifier_from_prng(pseudo_random_generator)
        target_state.state = TargetTransferState.OFFCHAIN_SECRET_REVEAL
        target_state.secret = state_change.secret
        recipient = route.node_address

        # Store reveal secret 7, create reveal secret 9 and store it for LC signing.

        received_reveal_secret = state_change.secret_reveal_message
        reveal_secret_to_send_event = SendSecretReveal(
            recipient=recipient,
            channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE,
            message_identifier=message_identifier,
            secret=target_state.secret,
        )
        reveal_secret_to_send_msg = message_from_sendevent(reveal_secret_to_send_event)

        store_received_reveal = StoreMessageEvent(
            received_reveal_secret.message_identifier,
            target_state.transfer.payment_identifier,
            7,
            received_reveal_secret,
            True
        )

        store_reveal_to_send = StoreMessageEvent(
            message_identifier,
            target_state.transfer.payment_identifier,
            9,
            reveal_secret_to_send_msg,
            False
        )

        iteration = TransitionResult(target_state, [store_received_reveal, store_reveal_to_send])

    else:
        # TODO: event for byzantine behavior
        iteration = TransitionResult(target_state, list())

    return iteration