def test_next_route():
    target = factories.HOP1
    routes = [
        factories.make_route(factories.HOP2, available_balance=factories.UNIT_TRANSFER_AMOUNT),
        factories.make_route(factories.HOP3, available_balance=factories.UNIT_TRANSFER_AMOUNT - 1),
        factories.make_route(factories.HOP4, available_balance=factories.UNIT_TRANSFER_AMOUNT),
    ]

    state = make_initiator_state(routes, target)

    assert state.route == routes[0], 'a initialized state must use the first valid route'

    assert state.routes.available_routes == routes[1:]
    assert not state.routes.ignored_routes
    assert not state.routes.refunded_routes
    assert not state.routes.canceled_routes

    with pytest.raises(AssertionError, message='cannot try a new route while one is in use'):
        initiator.try_new_route(state)

    state.routes.canceled_routes.append(state.route)
    state.route = None
    initiator.try_new_route(state)

    # HOP3 should be ignored because it doesnt have enough balance
    assert len(state.routes.ignored_routes) == 1

    assert not state.routes.available_routes
    assert not state.routes.refunded_routes
    assert state.routes.canceled_routes
Example #2
0
def handle_cancelroute(
        payment_state: InitiatorPaymentState,
        state_change: ActionCancelRoute,
        channelidentifiers_to_channels: initiator.ChannelMap,
        pseudo_random_generator: random.Random,
        block_number: typing.BlockNumber,
) -> TransitionResult:
    events = list()
    if can_cancel(payment_state):
        transfer_description = payment_state.initiator.transfer_description
        cancel_events = cancel_current_route(payment_state)

        msg = 'The previous transfer must be cancelled prior to trying a new route'
        assert payment_state.initiator is None, msg
        sub_iteration = initiator.try_new_route(
            channelidentifiers_to_channels,
            state_change.routes,
            transfer_description,
            pseudo_random_generator,
            block_number,
        )

        events.extend(cancel_events)
        events.extend(sub_iteration.events)

        if sub_iteration.new_state:
            payment_state.initiator = sub_iteration.new_state
        else:
            payment_state = None

    iteration = TransitionResult(payment_state, events)

    return iteration
Example #3
0
def handle_init(
        payment_state: InitiatorPaymentState,
        state_change: ActionInitInitiator,
        channelidentifiers_to_channels: ChannelMap,
        pseudo_random_generator: random.Random,
        block_number: BlockNumber,
) -> TransitionResult:
    events: List[Event]
    if payment_state is None:
        sub_iteration = initiator.try_new_route(
            old_initiator_state=None,
            channelidentifiers_to_channels=channelidentifiers_to_channels,
            available_routes=state_change.routes,
            transfer_description=state_change.transfer,
            pseudo_random_generator=pseudo_random_generator,
            block_number=block_number,
        )

        events = sub_iteration.events
        if sub_iteration.new_state:
            payment_state = InitiatorPaymentState(sub_iteration.new_state)
    else:
        events = list()

    iteration = TransitionResult(payment_state, events)
    return iteration
Example #4
0
def handle_init(
        payment_state: InitiatorPaymentState,
        state_change: ActionInitInitiator,
        channelidentifiers_to_channels: initiator.ChannelMap,
        pseudo_random_generator: random.Random,
        block_number: typing.BlockNumber,
) -> TransitionResult:
    if payment_state is None:
        sub_iteration = initiator.try_new_route(
            channelidentifiers_to_channels,
            state_change.routes,
            state_change.transfer,
            pseudo_random_generator,
            block_number,
        )

        events = sub_iteration.events
        if sub_iteration.new_state:
            payment_state = InitiatorPaymentState(sub_iteration.new_state)
    else:
        events = list()

    iteration = TransitionResult(payment_state, events)
    return iteration
Example #5
0
def handle_init(
    payment_state: InitiatorPaymentState,
    state_change: ActionInitInitiator,
    channelidentifiers_to_channels: initiator.ChannelMap,
    pseudo_random_generator: random.Random,
    block_number: typing.BlockNumber,
) -> TransitionResult:
    if payment_state is None:
        sub_iteration = initiator.try_new_route(
            channelidentifiers_to_channels,
            state_change.routes,
            state_change.transfer,
            pseudo_random_generator,
            block_number,
        )

        events = sub_iteration.events
        if sub_iteration.new_state:
            payment_state = InitiatorPaymentState(sub_iteration.new_state)
    else:
        events = list()

    iteration = TransitionResult(payment_state, events)
    return iteration
Example #6
0
def handle_transferreroute(
    payment_state: InitiatorPaymentState,
    state_change: ActionTransferReroute,
    channelidentifiers_to_channels: Dict[ChannelID, NettingChannelState],
    addresses_to_channel: Dict[Tuple[TokenNetworkAddress, Address],
                               NettingChannelState],
    nodeaddresses_to_networkstates: NodeNetworkStateMap,
    pseudo_random_generator: random.Random,
    block_number: BlockNumber,
) -> TransitionResult[InitiatorPaymentState]:

    try:
        initiator_state = payment_state.initiator_transfers[
            state_change.transfer.lock.secrethash]
        channel_identifier = initiator_state.channel_identifier
        channel_state = channelidentifiers_to_channels[channel_identifier]
    except KeyError:
        return TransitionResult(payment_state, list())

    refund_transfer = state_change.transfer
    original_transfer = initiator_state.transfer

    is_valid_lock = (
        refund_transfer.lock.secrethash == original_transfer.lock.secrethash
        and refund_transfer.lock.amount == original_transfer.lock.amount and
        refund_transfer.lock.expiration == original_transfer.lock.expiration)

    is_valid_refund = channel.refund_transfer_matches_transfer(
        refund_transfer, original_transfer)
    is_valid, channel_events, _ = channel.handle_receive_lockedtransfer(
        channel_state, refund_transfer)

    if not is_valid_lock or not is_valid_refund or not is_valid:
        return TransitionResult(payment_state, list())

    events: List[Event] = []
    events.extend(channel_events)

    old_description = initiator_state.transfer_description
    filtered_route_states = routes.filter_acceptable_routes(
        route_states=payment_state.routes,
        blacklisted_channel_ids=payment_state.cancelled_channels,
        addresses_to_channel=addresses_to_channel,
        token_network_address=old_description.token_network_address,
    )
    transfer_description = TransferDescriptionWithSecretState(
        token_network_registry_address=old_description.
        token_network_registry_address,
        payment_identifier=old_description.payment_identifier,
        amount=old_description.amount,
        token_network_address=old_description.token_network_address,
        initiator=old_description.initiator,
        target=old_description.target,
        secret=state_change.secret,
        secrethash=state_change.secrethash,
    )

    sub_iteration = initiator.try_new_route(
        addresses_to_channel=addresses_to_channel,
        nodeaddresses_to_networkstates=nodeaddresses_to_networkstates,
        candidate_route_states=filtered_route_states,
        transfer_description=transfer_description,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_number,
    )

    events.extend(sub_iteration.events)

    if sub_iteration.new_state is None:
        # Here we don't delete the initiator state, but instead let it live.
        # It will be deleted when the lock expires. We do that so that we
        # still have an initiator payment task around to process the
        # LockExpired message that our partner will send us.
        # https://github.com/raiden-network/raiden/issues/3146#issuecomment-447378046
        return TransitionResult(payment_state, events)

    new_transfer = sub_iteration.new_state.transfer
    payment_state.initiator_transfers[
        new_transfer.lock.secrethash] = sub_iteration.new_state

    return TransitionResult(payment_state, events)