Exemple #1
0
def next_channel_from_routes(
    available_routes: typing.List[RouteState],
    channelidentifiers_to_channels: typing.ChannelMap,
    transfer_amount: typing.TokenAmount,
) -> typing.Optional[NettingChannelState]:
    """ Returns the first channel that can be used to start the transfer.
    The routing service can race with local changes, so the recommended routes
    must be validated.
    """
    for route in available_routes:
        channel_identifier = route.channel_identifier
        channel_state = channelidentifiers_to_channels.get(channel_identifier)

        if not channel_state:
            continue

        if channel.get_status(channel_state) != CHANNEL_STATE_OPENED:
            continue

        pending_transfers = channel.get_number_of_pending_transfers(
            channel_state.our_state)
        if pending_transfers >= MAXIMUM_PENDING_TRANSFERS:
            continue

        distributable = channel.get_distributable(
            channel_state.our_state,
            channel_state.partner_state,
        )
        if transfer_amount > distributable:
            continue

        if channel.is_valid_amount(channel_state.our_state, transfer_amount):
            return channel_state

    return None
Exemple #2
0
def next_channel_from_routes(
        available_routes: typing.List[RouteState],
        channelidentifiers_to_channels: ChannelMap,
        transfer_amount: typing.TokenAmount,
) -> typing.Optional[NettingChannelState]:
    """ Returns the first channel that can be used to start the transfer.
    The routing service can race with local changes, so the recommended routes
    must be validated.
    """
    for route in available_routes:
        channel_identifier = route.channel_identifier
        channel_state = channelidentifiers_to_channels.get(channel_identifier)

        if not channel_state:
            continue

        if channel.get_status(channel_state) != CHANNEL_STATE_OPENED:
            continue

        distributable = channel.get_distributable(
            channel_state.our_state,
            channel_state.partner_state,
        )
        if transfer_amount > distributable:
            continue

        if channel.is_valid_amount(channel_state.our_state, transfer_amount):
            return channel_state

    return None
Exemple #3
0
def events_for_refund_transfer(
    refund_channel,
    refund_transfer,
    pseudo_random_generator,
    timeout_blocks,
    block_number,
):
    """ Refund the transfer.
    Args:
        refund_route (RouteState): The original route that sent the mediated
            transfer to this node.
        refund_transfer (LockedTransferSignedState): The original mediated transfer
            from the refund_route.
        timeout_blocks (int): The number of blocks available from the /latest
            transfer/ received by this node, this transfer might be the
            original mediated transfer (if no route was available) or a refund
            transfer from a down stream node.
        block_number (int): The current block number.
    Returns:
        An empty list if there are not enough blocks to safely create a refund,
        or a list with a refund event."""
    # A refund transfer works like a special SendLockedTransfer, so it must
    # follow the same rules and decrement reveal_timeout from the
    # payee_transfer.
    new_lock_timeout = timeout_blocks - refund_channel.reveal_timeout

    distributable = channel.get_distributable(
        refund_channel.our_state,
        refund_channel.partner_state,
    )

    is_valid = (new_lock_timeout > 0
                and refund_transfer.lock.amount <= distributable
                and channel.is_valid_amount(refund_channel.our_state,
                                            refund_transfer.lock.amount))

    if is_valid:
        new_lock_expiration = new_lock_timeout + block_number

        message_identifier = message_identifier_from_prng(
            pseudo_random_generator)
        refund_transfer = channel.send_refundtransfer(
            refund_channel,
            refund_transfer.initiator,
            refund_transfer.target,
            refund_transfer.lock.amount,
            message_identifier,
            refund_transfer.payment_identifier,
            new_lock_expiration,
            refund_transfer.lock.secrethash,
        )

        return [refund_transfer]

    # Can not create a refund lock with a safe expiration, so don't do anything
    # and wait for the received lock to expire.
    return list()
Exemple #4
0
def events_for_refund_transfer(
        refund_channel,
        refund_transfer,
        pseudo_random_generator,
        timeout_blocks,
        block_number,
):
    """ Refund the transfer.
    Args:
        refund_route (RouteState): The original route that sent the mediated
            transfer to this node.
        refund_transfer (LockedTransferSignedState): The original mediated transfer
            from the refund_route.
        timeout_blocks (int): The number of blocks available from the /latest
            transfer/ received by this node, this transfer might be the
            original mediated transfer (if no route was available) or a refund
            transfer from a down stream node.
        block_number (int): The current block number.
    Returns:
        An empty list if there are not enough blocks to safely create a refund,
        or a list with a refund event."""
    # A refund transfer works like a special SendLockedTransfer, so it must
    # follow the same rules and decrement reveal_timeout from the
    # payee_transfer.
    new_lock_timeout = timeout_blocks - refund_channel.reveal_timeout

    distributable = channel.get_distributable(
        refund_channel.our_state,
        refund_channel.partner_state,
    )

    is_valid = (
        new_lock_timeout > 0 and
        refund_transfer.lock.amount <= distributable and
        channel.is_valid_amount(refund_channel.our_state, refund_transfer.lock.amount)
    )

    if is_valid:
        new_lock_expiration = new_lock_timeout + block_number

        message_identifier = message_identifier_from_prng(pseudo_random_generator)
        refund_transfer = channel.send_refundtransfer(
            refund_channel,
            refund_transfer.initiator,
            refund_transfer.target,
            refund_transfer.lock.amount,
            message_identifier,
            refund_transfer.payment_identifier,
            new_lock_expiration,
            refund_transfer.lock.secrethash,
        )

        return [refund_transfer]

    # Can not create a refund lock with a safe expiration, so don't do anything
    # and wait for the received lock to expire.
    return list()
Exemple #5
0
def next_channel_from_routes(
    available_routes: List['RouteState'],
    channelidentifiers_to_channels: Dict,
    transfer_amount: int,
    timeout_blocks: int,
) -> NettingChannelState:
    """ Returns the first route that may be used to mediated the transfer.
    The routing service can race with local changes, so the recommended routes
    must be validated.
    Args:
        available_routes: Current available routes that may be used, it's
            assumed that the available_routes list is ordered from best to
            worst.
        channelidentifiers_to_channels: Mapping from channel identifier
            to NettingChannelState.
        transfer_amount: The amount of tokens that will be transferred
            through the given route.
        timeout_blocks: Base number of available blocks used to compute
            the lock timeout.
    Returns:
        The next route.
    """
    for route in available_routes:
        channel_identifier = route.channel_identifier
        channel_state = channelidentifiers_to_channels.get(channel_identifier)

        if not channel_state:
            continue

        if channel.get_status(channel_state) != CHANNEL_STATE_OPENED:
            continue

        pending_transfers = channel.get_number_of_pending_transfers(
            channel_state.our_state)
        if pending_transfers >= MAXIMUM_PENDING_TRANSFERS:
            continue

        distributable = channel.get_distributable(
            channel_state.our_state,
            channel_state.partner_state,
        )
        if transfer_amount > distributable:
            continue

        lock_timeout = timeout_blocks - channel_state.reveal_timeout
        if lock_timeout <= 0:
            continue

        if channel.is_valid_amount(channel_state.our_state, transfer_amount):
            return channel_state

    return None
Exemple #6
0
def is_channel_usable(candidate_channel_state, transfer_amount, lock_timeout):
    pending_transfers = channel.get_number_of_pending_transfers(
        candidate_channel_state.our_state)
    distributable = channel.get_distributable(
        candidate_channel_state.our_state,
        candidate_channel_state.partner_state,
    )

    return (lock_timeout > 0 and channel.get_status(candidate_channel_state)
            == CHANNEL_STATE_OPENED
            and candidate_channel_state.settle_timeout >= lock_timeout
            and candidate_channel_state.reveal_timeout < lock_timeout
            and pending_transfers < MAXIMUM_PENDING_TRANSFERS
            and transfer_amount <= distributable and channel.is_valid_amount(
                candidate_channel_state.our_state, transfer_amount))
Exemple #7
0
def next_channel_from_routes(
        available_routes: List['RouteState'],
        channelidentifiers_to_channels: Dict,
        transfer_amount: int,
        timeout_blocks: int,
) -> NettingChannelState:
    """ Returns the first route that may be used to mediated the transfer.
    The routing service can race with local changes, so the recommended routes
    must be validated.
    Args:
        available_routes: Current available routes that may be used, it's
            assumed that the available_routes list is ordered from best to
            worst.
        channelidentifiers_to_channels: Mapping from channel identifier
            to NettingChannelState.
        transfer_amount: The amount of tokens that will be transferred
            through the given route.
        timeout_blocks: Base number of available blocks used to compute
            the lock timeout.
    Returns:
        The next route.
    """
    for route in available_routes:
        channel_identifier = route.channel_identifier
        channel_state = channelidentifiers_to_channels.get(channel_identifier)

        if not channel_state:
            continue

        if channel.get_status(channel_state) != CHANNEL_STATE_OPENED:
            continue

        distributable = channel.get_distributable(
            channel_state.our_state,
            channel_state.partner_state,
        )
        if transfer_amount > distributable:
            continue

        lock_timeout = timeout_blocks - channel_state.reveal_timeout
        if lock_timeout <= 0:
            continue

        if channel.is_valid_amount(channel_state.our_state, transfer_amount):
            return channel_state

    return None