예제 #1
0
def test_lock_expiry_updates_balance_proof():
    setup = setup_initiator_tests(amount=UNIT_TRANSFER_AMOUNT * 2, block_number=10)

    transfer = setup.current_state.initiator.transfer
    assert transfer.lock.secrethash in setup.channel.our_state.secrethashes_to_lockedlocks

    nonce_before_lock_expiry = setup.channel.our_state.balance_proof.nonce

    # Trigger lock expiry
    state_change = Block(
        block_number=channel.get_sender_expiration_threshold(transfer.lock),
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )

    initiator_manager.state_transition(
        setup.current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        setup.block_number,
    )

    balance_proof = setup.channel.our_state.balance_proof
    assert balance_proof.nonce == nonce_before_lock_expiry + 1
    assert balance_proof.transferred_amount == 0
    assert balance_proof.locked_amount == 0
예제 #2
0
def test_init_with_maximum_pending_transfers_exceeded():
    channel1 = factories.make_channel(
        our_balance=2 * MAXIMUM_PENDING_TRANSFERS * UNIT_TRANSFER_AMOUNT,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    channel_map = {channel1.identifier: channel1}
    available_routes = [factories.route_from_channel(channel1)]
    pseudo_random_generator = random.Random()

    transitions = list()
    block_number = 1
    for _ in range(MAXIMUM_PENDING_TRANSFERS + 1):
        init_state_change = ActionInitInitiator(make_transfer_description(), available_routes)
        transitions.append(initiator_manager.state_transition(
            None,
            init_state_change,
            channel_map,
            pseudo_random_generator,
            block_number,
        ))

    failed_transition = transitions.pop()
    assert all(
        isinstance(transition.new_state, InitiatorPaymentState)
        for transition in transitions
    )

    assert failed_transition.new_state is None
    assert len(failed_transition.events) == 1
    assert isinstance(failed_transition.events[0], EventPaymentSentFailed)
예제 #3
0
def test_state_wait_unlock_invalid():
    setup = setup_initiator_tests()
    identifier = setup.channel.identifier
    target_address = factories.HOP2

    # setup the state for the wait unlock
    setup.current_state.initiator.revealsecret = SendSecretReveal(
        recipient=target_address,
        channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE,
        message_identifier=identifier,
        secret=UNIT_SECRET,
    )

    before_state = deepcopy(setup.current_state)

    state_change = ReceiveSecretReveal(
        secret=UNIT_SECRET,
        sender=factories.ADDR,
    )
    iteration = initiator_manager.state_transition(
        setup.current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        setup.block_number,
    )

    assert not iteration.events
    assert iteration.new_state == before_state
예제 #4
0
def test_state_wait_unlock_valid():
    setup = setup_initiator_tests()

    # setup the state for the wait unlock
    setup.current_state.initiator.revealsecret = SendSecretReveal(
        recipient=UNIT_TRANSFER_TARGET,
        channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE,
        message_identifier=UNIT_TRANSFER_IDENTIFIER,
        secret=UNIT_SECRET,
    )

    state_change = ReceiveSecretReveal(
        secret=UNIT_SECRET,
        sender=setup.channel.partner_state.address,
    )
    iteration = initiator_manager.state_transition(
        setup.current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        setup.block_number,
    )

    assert len(iteration.events) == 3
    assert any(isinstance(e, SendBalanceProof) for e in iteration.events)
    assert any(isinstance(e, EventPaymentSentSuccess) for e in iteration.events)
    assert any(isinstance(e, EventUnlockSuccess) for e in iteration.events)

    balance_proof = next(e for e in iteration.events if isinstance(e, SendBalanceProof))
    complete = next(e for e in iteration.events if isinstance(e, EventPaymentSentSuccess))

    assert balance_proof.recipient == setup.channel.partner_state.address
    assert complete.identifier == UNIT_TRANSFER_IDENTIFIER
    assert iteration.new_state is None, 'state must be cleaned'
예제 #5
0
def test_invalid_cancelpayment():
    """ A payment can *NOT* be cancelled if a secret for any transfer has been
    revealed.
    """
    setup = setup_initiator_tests(
        amount=2 * MAXIMUM_PENDING_TRANSFERS * UNIT_TRANSFER_AMOUNT,
    )
    receive_secret_request = ReceiveSecretRequest(
        UNIT_TRANSFER_IDENTIFIER,
        setup.lock.amount,
        setup.lock.expiration,
        setup.lock.secrethash,
        UNIT_TRANSFER_TARGET,
    )
    secret_transition = initiator_manager.state_transition(
        payment_state=setup.current_state,
        state_change=receive_secret_request,
        channelidentifiers_to_channels=setup.channel_map,
        pseudo_random_generator=setup.prng,
        block_number=1,
    )

    iteration = initiator_manager.handle_cancelpayment(
        payment_state=secret_transition.new_state,
        channel_state=setup.channel,
    )
    msg = 'The secret *has* been revealed, the payment must not be cancelled'
    assert iteration.new_state is not None, msg
    assert not iteration.events, msg
예제 #6
0
def test_next_route():
    amount = UNIT_TRANSFER_AMOUNT
    channel1 = factories.make_channel(
        our_balance=amount,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    channel2 = factories.make_channel(
        our_balance=0,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    channel3 = factories.make_channel(
        our_balance=amount,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    pseudo_random_generator = random.Random()

    channel_map = {
        channel1.identifier: channel1,
        channel2.identifier: channel2,
        channel3.identifier: channel3,
    }

    available_routes = [
        factories.route_from_channel(channel1),
        factories.route_from_channel(channel2),
        factories.route_from_channel(channel3),
    ]

    block_number = 10
    state = make_initiator_manager_state(
        available_routes,
        factories.UNIT_TRANSFER_DESCRIPTION,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    msg = 'an initialized state must use the first valid route'
    assert state.initiator.channel_identifier == channel1.identifier, msg
    assert not state.cancelled_channels

    state_change = ActionCancelRoute(
        UNIT_REGISTRY_IDENTIFIER,
        channel1.identifier,
        available_routes,
    )
    iteration = initiator_manager.state_transition(
        state,
        state_change,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    # HOP3 should be ignored because it doesnt have enough balance
    assert iteration.new_state.cancelled_channels == [channel1.identifier]
예제 #7
0
def test_state_wait_secretrequest_invalid_amount_and_sender():
    setup = setup_initiator_tests()

    state_change = ReceiveSecretRequest(
        UNIT_TRANSFER_IDENTIFIER,
        setup.lock.amount + 1,
        setup.lock.expiration,
        setup.lock.secrethash,
        UNIT_TRANSFER_INITIATOR,
    )

    iteration = initiator_manager.state_transition(
        setup.current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        setup.block_number,
    )

    assert len(iteration.events) == 0
    assert iteration.new_state.initiator.received_secret_request is False

    # Now the proper target sends the message, this should be applied
    state_change_2 = ReceiveSecretRequest(
        UNIT_TRANSFER_IDENTIFIER,
        setup.lock.amount,
        setup.lock.expiration,
        setup.lock.secrethash,
        UNIT_TRANSFER_TARGET,
    )

    iteration2 = initiator_manager.state_transition(
        iteration.new_state,
        state_change_2,
        setup.channel_map,
        setup.prng,
        setup.block_number,
    )

    assert iteration2.new_state.initiator.received_secret_request is True
    assert isinstance(iteration2.events[0], SendSecretReveal)
예제 #8
0
def test_state_wait_secretrequest_invalid_amount():
    setup = setup_initiator_tests()

    state_change = ReceiveSecretRequest(
        UNIT_TRANSFER_IDENTIFIER,
        setup.lock.amount + 1,
        setup.lock.expiration,
        setup.lock.secrethash,
        UNIT_TRANSFER_TARGET,
    )

    iteration = initiator_manager.state_transition(
        setup.current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        setup.block_number,
    )

    assert len(iteration.events) == 1
    assert isinstance(iteration.events[0], EventPaymentSentFailed)
    assert iteration.new_state.initiator.received_secret_request is True

    state_change_2 = ReceiveSecretRequest(
        UNIT_TRANSFER_IDENTIFIER,
        setup.lock.amount,
        setup.lock.expiration,
        setup.lock.secrethash,
        UNIT_TRANSFER_TARGET,
    )

    iteration2 = initiator_manager.state_transition(
        iteration.new_state,
        state_change_2,
        setup.channel_map,
        setup.prng,
        setup.block_number,
    )

    assert len(iteration2.events) == 0
예제 #9
0
파일: node.py 프로젝트: hackaugusto/raiden
def subdispatch_initiatortask(
        chain_state: ChainState,
        state_change: StateChange,
        token_network_identifier: TokenNetworkID,
        secrethash: SecretHash,
) -> TransitionResult:

    block_number = chain_state.block_number
    sub_task = chain_state.payment_mapping.secrethashes_to_task.get(secrethash)

    if not sub_task:
        is_valid_subtask = True
        manager_state = None

    elif sub_task and isinstance(sub_task, InitiatorTask):
        is_valid_subtask = (
            token_network_identifier == sub_task.token_network_identifier
        )
        manager_state = sub_task.manager_state
    else:
        is_valid_subtask = False

    events = list()
    if is_valid_subtask:
        pseudo_random_generator = chain_state.pseudo_random_generator

        token_network_state = views.get_token_network_by_identifier(
            chain_state,
            token_network_identifier,
        )
        iteration = initiator_manager.state_transition(
            manager_state,
            state_change,
            token_network_state.channelidentifiers_to_channels,
            pseudo_random_generator,
            block_number,
        )
        events = iteration.events

        if iteration.new_state:
            sub_task = InitiatorTask(
                token_network_identifier,
                iteration.new_state,
            )
            chain_state.payment_mapping.secrethashes_to_task[secrethash] = sub_task
        elif secrethash in chain_state.payment_mapping.secrethashes_to_task:
            del chain_state.payment_mapping.secrethashes_to_task[secrethash]

    return TransitionResult(chain_state, events)
예제 #10
0
def test_refund_transfer_no_more_routes():
    amount = UNIT_TRANSFER_AMOUNT
    refund_pkey, refund_address = factories.make_privkey_address()
    setup = setup_initiator_tests(
        amount=amount,
        partner_balance=amount,
        our_address=UNIT_TRANSFER_INITIATOR,
        partner_address=refund_address,
    )

    original_transfer = setup.current_state.initiator.transfer
    refund_transfer = factories.make_signed_transfer(
        amount,
        original_transfer.initiator,
        original_transfer.target,
        original_transfer.lock.expiration,
        UNIT_SECRET,
        payment_identifier=original_transfer.payment_identifier,
        channel_identifier=setup.channel.identifier,
        pkey=refund_pkey,
        sender=refund_address,
    )

    state_change = ReceiveTransferRefundCancelRoute(
        routes=setup.available_routes,
        transfer=refund_transfer,
        secret=random_secret(),
    )

    iteration = initiator_manager.state_transition(
        setup.current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        setup.block_number,
    )
    assert iteration.new_state is None

    unlocked_failed = next(e for e in iteration.events if isinstance(e, EventUnlockFailed))
    sent_failed = next(e for e in iteration.events if isinstance(e, EventPaymentSentFailed))

    assert unlocked_failed
    assert sent_failed
예제 #11
0
파일: node.py 프로젝트: ycaihua/raiden
def subdispatch_initiatortask(node_state, state_change,
                              payment_network_identifier,
                              token_network_identifier, hashlock):

    block_number = node_state.block_number
    sub_task = node_state.payment_mapping.hashlocks_to_task.get(hashlock)

    if not sub_task:
        is_valid_subtask = True
        manager_state = None

    elif sub_task and isinstance(sub_task, PaymentMappingState.InitiatorTask):
        is_valid_subtask = (
            payment_network_identifier == sub_task.payment_network_identifier
            and token_network_identifier == sub_task.token_network_identifier)
        manager_state = sub_task.manager_state
    else:
        is_valid_subtask = False

    events = list()
    if is_valid_subtask:
        token_network_state = get_token_network(
            node_state,
            payment_network_identifier,
            token_network_identifier,
        )
        iteration = initiator_manager.state_transition(
            manager_state,
            state_change,
            token_network_state.channelidentifiers_to_channels,
            block_number,
        )
        events = iteration.events

        if iteration.new_state:
            sub_task = PaymentMappingState.InitiatorTask(
                payment_network_identifier,
                token_network_identifier,
                iteration.new_state,
            )
            node_state.payment_mapping.hashlocks_to_task[hashlock] = sub_task

    return TransitionResult(node_state, events)
예제 #12
0
def test_state_wait_secretrequest_valid():
    amount = UNIT_TRANSFER_AMOUNT
    block_number = 1
    pseudo_random_generator = random.Random()

    channel1 = factories.make_channel(
        our_balance=amount,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    channel_map = {channel1.identifier: channel1}
    available_routes = [factories.route_from_channel(channel1)]
    current_state = make_initiator_manager_state(
        available_routes,
        factories.UNIT_TRANSFER_DESCRIPTION,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    lock = channel.get_lock(
        channel1.our_state,
        current_state.initiator.transfer_description.secrethash,
    )

    state_change = ReceiveSecretRequest(
        UNIT_TRANSFER_IDENTIFIER,
        lock.amount,
        lock.expiration,
        lock.secrethash,
        UNIT_TRANSFER_TARGET,
    )

    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    assert len(iteration.events) == 1
    assert isinstance(iteration.events[0], SendSecretReveal)
예제 #13
0
def test_next_route():
    amount = UNIT_TRANSFER_AMOUNT
    channel1 = factories.make_channel(our_balance=amount, token_address=UNIT_TOKEN_ADDRESS)
    channel2 = factories.make_channel(our_balance=0, token_address=UNIT_TOKEN_ADDRESS)
    channel3 = factories.make_channel(our_balance=amount, token_address=UNIT_TOKEN_ADDRESS)

    channelmap = {
        channel1.identifier: channel1,
        channel2.identifier: channel2,
        channel3.identifier: channel3,
    }

    available_routes = [
        factories.route_from_channel(channel1),
        factories.route_from_channel(channel2),
        factories.route_from_channel(channel3),
    ]

    block_number = 10
    state = make_initiator_state(
        available_routes,
        factories.UNIT_TRANSFER_DESCRIPTION,
        channelmap,
        block_number,
    )

    msg = 'an initialized state must use the first valid route'
    assert state.initiator.channel_identifier == channel1.identifier, msg
    assert not state.cancelled_channels

    state_change = ActionCancelRoute(
        channel1.identifier,
        available_routes,
    )
    iteration = initiator_manager.state_transition(
        state,
        state_change,
        channelmap,
        block_number,
    )

    # HOP3 should be ignored because it doesnt have enough balance
    assert iteration.new_state.cancelled_channels == [channel1.identifier]
예제 #14
0
def test_init_with_usable_routes():
    channel1 = factories.make_channel(
        our_balance=UNIT_TRANSFER_AMOUNT,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    channel_map = {channel1.identifier: channel1}
    available_routes = [factories.route_from_channel(channel1)]
    pseudo_random_generator = random.Random()

    init_state_change = ActionInitInitiator(
        factories.UNIT_TRANSFER_DESCRIPTION,
        available_routes,
    )

    block_number = 1
    transition = initiator_manager.state_transition(
        None,
        init_state_change,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    assert isinstance(transition.new_state, InitiatorPaymentState)
    assert transition.events, 'we have a valid route, the mediated transfer event must be emitted'

    payment_state = transition.new_state
    assert payment_state.initiator.transfer_description == factories.UNIT_TRANSFER_DESCRIPTION

    mediated_transfers = [e for e in transition.events if isinstance(e, SendLockedTransfer)]
    assert len(mediated_transfers) == 1, 'mediated_transfer should /not/ split the transfer'

    send_mediated_transfer = mediated_transfers[0]
    transfer = send_mediated_transfer.transfer
    expiration = initiator.get_initial_lock_expiration(block_number, channel1.reveal_timeout)

    assert transfer.balance_proof.token_network_identifier == channel1.token_network_identifier
    assert transfer.lock.amount == factories.UNIT_TRANSFER_DESCRIPTION.amount
    assert transfer.lock.expiration == expiration
    assert transfer.lock.secrethash == factories.UNIT_TRANSFER_DESCRIPTION.secrethash
    assert send_mediated_transfer.recipient == channel1.partner_state.address
예제 #15
0
def test_cancel_transfer():
    amount = UNIT_TRANSFER_AMOUNT
    block_number = 1
    pseudo_random_generator = random.Random()

    channel1 = factories.make_channel(
        our_balance=amount,
        our_address=UNIT_TRANSFER_INITIATOR,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    channelmap = {channel1.identifier: channel1}
    available_routes = [factories.route_from_channel(channel1)]

    current_state = make_initiator_state(
        available_routes,
        factories.UNIT_TRANSFER_DESCRIPTION,
        channelmap,
        pseudo_random_generator,
        block_number,
    )

    state_change = ActionCancelPayment(
        payment_identifier=UNIT_TRANSFER_IDENTIFIER, )

    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        channelmap,
        pseudo_random_generator,
        block_number,
    )
    assert iteration.new_state is None
    assert len(iteration.events) == 2

    unlocked_failed = next(e for e in iteration.events
                           if isinstance(e, EventUnlockFailed))
    sent_failed = next(e for e in iteration.events
                       if isinstance(e, EventTransferSentFailed))

    assert unlocked_failed
    assert sent_failed
예제 #16
0
def test_state_wait_unlock_invalid():
    identifier = identifier = 1
    block_number = 1
    target_address = factories.HOP2
    token = factories.UNIT_TOKEN_ADDRESS

    channel1 = factories.make_channel(
        our_balance=UNIT_TRANSFER_AMOUNT,
        token_address=UNIT_TOKEN_ADDRESS,
    )
    channelmap = {channel1.identifier: channel1}
    available_routes = [factories.route_from_channel(channel1)]
    current_state = make_initiator_state(
        available_routes,
        factories.UNIT_TRANSFER_DESCRIPTION,
        channelmap,
        block_number,
    )

    # setup the state for the wait unlock
    current_state.initiator.revealsecret = SendRevealSecret(
        identifier,
        UNIT_SECRET,
        token,
        target_address,
    )

    before_state = deepcopy(current_state)

    state_change = ReceiveSecretReveal(
        secret=UNIT_SECRET,
        sender=factories.ADDR,
    )
    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        channelmap,
        block_number,
    )

    assert not iteration.events
    assert iteration.new_state == before_state
예제 #17
0
def test_init_with_usable_routes():
    channel1 = factories.make_channel(
        our_balance=UNIT_TRANSFER_AMOUNT,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    channel_map = {channel1.identifier: channel1}
    available_routes = [factories.route_from_channel(channel1)]
    pseudo_random_generator = random.Random()

    init_state_change = ActionInitInitiator(
        factories.UNIT_TRANSFER_DESCRIPTION,
        available_routes,
    )

    block_number = 1
    transition = initiator_manager.state_transition(
        None,
        init_state_change,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    assert isinstance(transition.new_state, InitiatorPaymentState)
    assert transition.events, 'we have a valid route, the mediated transfer event must be emitted'

    payment_state = transition.new_state
    assert payment_state.initiator.transfer_description == factories.UNIT_TRANSFER_DESCRIPTION

    mediated_transfers = [e for e in transition.events if isinstance(e, SendLockedTransfer)]
    assert len(mediated_transfers) == 1, 'mediated_transfer should /not/ split the transfer'

    send_mediated_transfer = mediated_transfers[0]
    transfer = send_mediated_transfer.transfer
    expiration = initiator.get_initial_lock_expiration(block_number, channel1.reveal_timeout)

    assert transfer.balance_proof.token_network_identifier == channel1.token_network_identifier
    assert transfer.lock.amount == factories.UNIT_TRANSFER_DESCRIPTION.amount
    assert transfer.lock.expiration == expiration
    assert transfer.lock.secrethash == factories.UNIT_TRANSFER_DESCRIPTION.secrethash
    assert send_mediated_transfer.recipient == channel1.partner_state.address
예제 #18
0
def test_cancel_transfer():
    setup = setup_initiator_tests()
    state_change = ActionCancelPayment(
        payment_identifier=UNIT_TRANSFER_IDENTIFIER,
    )

    iteration = initiator_manager.state_transition(
        setup.current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        setup.block_number,
    )
    assert iteration.new_state is None
    assert len(iteration.events) == 2

    unlocked_failed = next(e for e in iteration.events if isinstance(e, EventUnlockFailed))
    sent_failed = next(e for e in iteration.events if isinstance(e, EventPaymentSentFailed))

    assert unlocked_failed
    assert sent_failed
예제 #19
0
def test_cancel_transfer():
    setup = setup_initiator_tests()
    state_change = ActionCancelPayment(
        payment_identifier=UNIT_TRANSFER_IDENTIFIER,
    )

    iteration = initiator_manager.state_transition(
        setup.current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        setup.block_number,
    )
    assert iteration.new_state is None
    assert len(iteration.events) == 2

    unlocked_failed = next(e for e in iteration.events if isinstance(e, EventUnlockFailed))
    sent_failed = next(e for e in iteration.events if isinstance(e, EventPaymentSentFailed))

    assert unlocked_failed
    assert sent_failed
예제 #20
0
def test_initiator_lock_expired_must_not_be_sent_if_channel_is_closed():
    """ If the channel is closed there is no rason to send balance proofs
    off-chain, so a remove expired lock must not be sent when the channel is
    closed.
    """
    block_number = 10
    setup = setup_initiator_tests(amount=UNIT_TRANSFER_AMOUNT * 2,
                                  block_number=block_number)

    channel_closed = ContractReceiveChannelClosed(
        transaction_hash=factories.make_transaction_hash(),
        transaction_from=factories.make_address(),
        token_network_identifier=setup.channel.token_network_identifier,
        channel_identifier=setup.channel.identifier,
        block_number=block_number,
    )
    channel_close_transition = channel.state_transition(
        channel_state=setup.channel,
        state_change=channel_closed,
        pseudo_random_generator=setup.prng,
        block_number=block_number,
    )
    channel_state = channel_close_transition.new_state

    expiration_block_number = setup.lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2
    block = Block(
        block_number=expiration_block_number,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    channel_map = {channel_state.identifier: channel_state}
    iteration = initiator_manager.state_transition(
        setup.current_state,
        block,
        channel_map,
        setup.prng,
        expiration_block_number,
    )
    assert events.must_contain_entry(iteration.events, SendLockExpired,
                                     {}) is None
예제 #21
0
파일: node.py 프로젝트: sekmet/raiden
def subdispatch_initiatortask(
    chain_state: ChainState,
    state_change: StateChange,
    token_network_address: TokenNetworkAddress,
    secrethash: SecretHash,
) -> TransitionResult[ChainState]:
    token_network_state = get_token_network_by_address(chain_state, token_network_address)
    if not token_network_state:
        return TransitionResult(chain_state, [])

    sub_task = chain_state.payment_mapping.secrethashes_to_task.get(secrethash)
    if not sub_task:
        manager_state = None
    else:
        if (
            not isinstance(sub_task, InitiatorTask)
            or token_network_address != sub_task.token_network_address
        ):
            return TransitionResult(chain_state, [])
        manager_state = sub_task.manager_state

    iteration = initiator_manager.state_transition(
        payment_state=manager_state,
        state_change=state_change,
        channelidentifiers_to_channels=token_network_state.channelidentifiers_to_channels,
        addresses_to_channel=chain_state.addresses_to_channel,
        nodeaddresses_to_networkstates=chain_state.nodeaddresses_to_networkstates,
        pseudo_random_generator=chain_state.pseudo_random_generator,
        block_number=chain_state.block_number,
    )
    events: List[Event] = iteration.events

    if iteration.new_state:
        chain_state.payment_mapping.secrethashes_to_task[secrethash] = InitiatorTask(
            token_network_address, iteration.new_state
        )
    elif secrethash in chain_state.payment_mapping.secrethashes_to_task:
        del chain_state.payment_mapping.secrethashes_to_task[secrethash]

    return TransitionResult(chain_state, events)
예제 #22
0
def test_initiator_lock_expired_must_not_be_sent_if_channel_is_closed():
    """ If the channel is closed there is no rason to send balance proofs
    off-chain, so a remove expired lock must not be sent when the channel is
    closed.
    """
    block_number = 10
    setup = setup_initiator_tests(amount=UNIT_TRANSFER_AMOUNT * 2, block_number=block_number)

    channel_closed = ContractReceiveChannelClosed(
        transaction_hash=factories.make_transaction_hash(),
        transaction_from=factories.make_address(),
        token_network_identifier=setup.channel.token_network_identifier,
        channel_identifier=setup.channel.identifier,
        block_number=block_number,
    )
    channel_close_transition = channel.state_transition(
        channel_state=setup.channel,
        state_change=channel_closed,
        pseudo_random_generator=setup.prng,
        block_number=block_number,
    )
    channel_state = channel_close_transition.new_state

    expiration_block_number = channel.get_sender_expiration_threshold(setup.lock)
    block = Block(
        block_number=expiration_block_number,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    channel_map = {channel_state.identifier: channel_state}
    iteration = initiator_manager.state_transition(
        setup.current_state,
        block,
        channel_map,
        setup.prng,
        expiration_block_number,
    )
    assert events.must_contain_entry(iteration.events, SendLockExpired, {}) is None
예제 #23
0
def make_initiator_manager_state(
        routes,
        transfer_description,
        channel_map,
        pseudo_random_generator,
        block_number,
):

    init_state_change = ActionInitInitiator(
        transfer_description,
        routes,
    )

    inital_state = None
    iteration = initiator_manager.state_transition(
        inital_state,
        init_state_change,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    return iteration.new_state
예제 #24
0
def test_init_without_routes():
    block_number = 1
    routes = []
    payment_network_identifier = factories.make_address()
    init_state_change = ActionInitInitiator(
        payment_network_identifier,
        factories.UNIT_TRANSFER_DESCRIPTION,
        routes,
    )

    channelmap = dict()
    iteration = initiator_manager.state_transition(
        None,
        init_state_change,
        channelmap,
        block_number,
    )

    assert iteration.new_state is None

    assert len(iteration.events) == 1
    assert isinstance(iteration.events[0], EventTransferSentFailed)
    assert iteration.new_state is None
예제 #25
0
def make_initiator_manager_state(
        routes,
        transfer_description,
        channel_map,
        pseudo_random_generator,
        block_number,
):

    init_state_change = ActionInitInitiator(
        transfer_description,
        routes,
    )

    inital_state = None
    iteration = initiator_manager.state_transition(
        inital_state,
        init_state_change,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    return iteration.new_state
def test_state_wait_unlock_valid():
    setup = setup_initiator_tests()

    # setup the state for the wait unlock
    setup.current_state.initiator.revealsecret = SendSecretReveal(
        recipient=UNIT_TRANSFER_TARGET,
        channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE,
        message_identifier=UNIT_TRANSFER_IDENTIFIER,
        secret=UNIT_SECRET,
    )

    state_change = ReceiveSecretReveal(
        secret=UNIT_SECRET,
        sender=setup.channel.partner_state.address,
    )
    iteration = initiator_manager.state_transition(
        setup.current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        setup.block_number,
    )

    assert len(iteration.events) == 3
    assert any(isinstance(e, SendBalanceProof) for e in iteration.events)
    assert any(
        isinstance(e, EventPaymentSentSuccess) for e in iteration.events)
    assert any(isinstance(e, EventUnlockSuccess) for e in iteration.events)

    balance_proof = next(e for e in iteration.events
                         if isinstance(e, SendBalanceProof))
    complete = next(e for e in iteration.events
                    if isinstance(e, EventPaymentSentSuccess))

    assert balance_proof.recipient == setup.channel.partner_state.address
    assert complete.identifier == UNIT_TRANSFER_IDENTIFIER
    assert iteration.new_state is None, 'state must be cleaned'
예제 #27
0
def test_init_without_routes():
    block_number = 1
    routes = []
    pseudo_random_generator = random.Random()

    init_state_change = ActionInitInitiator(
        factories.UNIT_TRANSFER_DESCRIPTION,
        routes,
    )

    channel_map = dict()
    iteration = initiator_manager.state_transition(
        None,
        init_state_change,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    assert iteration.new_state is None

    assert len(iteration.events) == 1
    assert isinstance(iteration.events[0], EventPaymentSentFailed)
    assert iteration.new_state is None
예제 #28
0
def make_initiator_state(routes,
                         transfer_description,
                         channelmap,
                         block_number,
                         payment_network_identifier=None):

    if payment_network_identifier is None:
        payment_network_identifier = factories.make_address()

    init_state_change = ActionInitInitiator(
        payment_network_identifier,
        transfer_description,
        routes,
    )

    inital_state = None
    iteration = initiator_manager.state_transition(
        inital_state,
        init_state_change,
        channelmap,
        block_number,
    )

    return iteration.new_state
예제 #29
0
def test_init_without_routes():
    block_number = 1
    routes = []
    pseudo_random_generator = random.Random()

    init_state_change = ActionInitInitiator(
        factories.UNIT_TRANSFER_DESCRIPTION,
        routes,
    )

    channelmap = dict()
    iteration = initiator_manager.state_transition(
        None,
        init_state_change,
        channelmap,
        pseudo_random_generator,
        block_number,
    )

    assert iteration.new_state is None

    assert len(iteration.events) == 1
    assert isinstance(iteration.events[0], EventTransferSentFailed)
    assert iteration.new_state is None
예제 #30
0
파일: node.py 프로젝트: hwlsniper/raiden
def subdispatch_to_paymenttask(node_state, state_change, secrethash):
    block_number = node_state.block_number
    sub_task = node_state.payment_mapping.secrethashes_to_task.get(secrethash)
    events = list()
    sub_iteration = None

    if sub_task:
        pseudo_random_generator = node_state.pseudo_random_generator

        if isinstance(sub_task, PaymentMappingState.InitiatorTask):
            token_network_identifier = sub_task.token_network_identifier
            token_network_state = views.get_token_network_by_identifier(
                node_state,
                token_network_identifier,
            )

            if token_network_state:
                sub_iteration = initiator_manager.state_transition(
                    sub_task.manager_state,
                    state_change,
                    token_network_state.channelidentifiers_to_channels,
                    pseudo_random_generator,
                    block_number,
                )
                events = sub_iteration.events

        elif isinstance(sub_task, PaymentMappingState.MediatorTask):
            token_network_identifier = sub_task.token_network_identifier
            token_network_state = views.get_token_network_by_identifier(
                node_state,
                token_network_identifier,
            )

            if token_network_state:
                sub_iteration = mediator.state_transition(
                    sub_task.mediator_state,
                    state_change,
                    token_network_state.channelidentifiers_to_channels,
                    pseudo_random_generator,
                    block_number,
                )
                events = sub_iteration.events

        elif isinstance(sub_task, PaymentMappingState.TargetTask):
            token_network_identifier = sub_task.token_network_identifier
            channel_identifier = sub_task.channel_identifier
            token_network_state = views.get_token_network_by_identifier(
                node_state,
                token_network_identifier,
            )

            channel_state = views.get_channelstate_by_token_network_identifier(
                node_state,
                token_network_identifier,
                channel_identifier,
            )

            if channel_state:
                sub_iteration = target.state_transition(
                    sub_task.target_state,
                    state_change,
                    channel_state,
                    pseudo_random_generator,
                    block_number,
                )
                events = sub_iteration.events

        if sub_iteration and sub_iteration.new_state is None:
            del node_state.payment_mapping.secrethashes_to_task[secrethash]

    return TransitionResult(node_state, events)
예제 #31
0
def test_initiator_lock_expired():
    amount = UNIT_TRANSFER_AMOUNT * 2
    block_number = 1
    refund_pkey, refund_address = factories.make_privkey_address()
    pseudo_random_generator = random.Random()

    channel1 = factories.make_channel(
        our_balance=amount,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    channel2 = factories.make_channel(
        our_balance=0,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    pseudo_random_generator = random.Random()

    channel_map = {
        channel1.identifier: channel1,
        channel2.identifier: channel2,
    }

    available_routes = [
        factories.route_from_channel(channel1),
        factories.route_from_channel(channel2),
    ]

    block_number = 10
    current_state = make_initiator_manager_state(
        available_routes,
        factories.UNIT_TRANSFER_DESCRIPTION,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    transfer = current_state.initiator.transfer

    assert transfer.lock.secrethash in channel1.our_state.secrethashes_to_lockedlocks

    # Trigger lock expiry
    state_change = Block(
        block_number=transfer.lock.expiration + DEFAULT_NUMBER_OF_CONFIRMATIONS_BLOCK,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )

    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    assert events.must_contain_entry(iteration.events, SendLockExpired, {
        'balance_proof': {
            'nonce': 2,
            'transferred_amount': 0,
            'locked_amount': 0,
        },
        'secrethash': transfer.lock.secrethash,
        'recipient': channel1.partner_state.address,
    })

    assert transfer.lock.secrethash not in channel1.our_state.secrethashes_to_lockedlocks

    # Create 2 other transfers
    transfer2_state = make_initiator_manager_state(
        available_routes,
        make_transfer_description('transfer2'),
        channel_map,
        pseudo_random_generator,
        30,
    )
    transfer2_lock = transfer2_state.initiator.transfer.lock

    transfer3_state = make_initiator_manager_state(
        available_routes,
        make_transfer_description('transfer3'),
        channel_map,
        pseudo_random_generator,
        32,
    )

    transfer3_lock = transfer3_state.initiator.transfer.lock

    assert len(channel1.our_state.secrethashes_to_lockedlocks) == 2

    assert transfer2_lock.secrethash in channel1.our_state.secrethashes_to_lockedlocks

    expiration_block_number = transfer2_lock.expiration + DEFAULT_NUMBER_OF_CONFIRMATIONS_BLOCK

    block = Block(
        block_number=expiration_block_number,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    iteration = initiator_manager.state_transition(
        transfer2_state,
        block,
        channel_map,
        pseudo_random_generator,
        expiration_block_number,
    )

    # Transfer 2 expired
    assert transfer2_lock.secrethash not in channel1.our_state.secrethashes_to_lockedlocks

    # Transfer 3 is still there
    assert transfer3_lock.secrethash in channel1.our_state.secrethashes_to_lockedlocks
예제 #32
0
파일: node.py 프로젝트: realflash7/raiden
def subdispatch_to_paymenttask(
    chain_state: ChainState,
    state_change: StateChange,
    secrethash: SecretHash,
) -> TransitionResult[ChainState]:
    block_number = chain_state.block_number
    sub_task = chain_state.payment_mapping.secrethashes_to_task.get(secrethash)
    events: List[Event] = list()
    sub_iteration = None

    if sub_task:
        pseudo_random_generator = chain_state.pseudo_random_generator

        if isinstance(sub_task, InitiatorTask):
            token_network_identifier = sub_task.token_network_identifier
            token_network_state = views.get_token_network_by_identifier(
                chain_state,
                token_network_identifier,
            )
            if token_network_state:
                sub_iteration = initiator_manager.state_transition(
                    sub_task.manager_state,
                    state_change,
                    token_network_state.channelidentifiers_to_channels,
                    pseudo_random_generator,
                    block_number,
                )
                events = sub_iteration.events

        elif isinstance(sub_task, MediatorTask):
            token_network_identifier = sub_task.token_network_identifier
            token_network_state = views.get_token_network_by_identifier(
                chain_state,
                token_network_identifier,
            )

            if token_network_state:
                sub_iteration = mediator.state_transition(
                    sub_task.mediator_state,
                    state_change,
                    token_network_state.channelidentifiers_to_channels,
                    chain_state.nodeaddresses_to_networkstates,
                    pseudo_random_generator,
                    block_number,
                )
                events = sub_iteration.events

        elif isinstance(sub_task, TargetTask):
            token_network_identifier = sub_task.token_network_identifier
            channel_identifier = sub_task.channel_identifier

            channel_state = views.get_channelstate_by_token_network_identifier(
                chain_state,
                token_network_identifier,
                channel_identifier,
            )

            if channel_state:
                sub_iteration = target.state_transition(
                    sub_task.target_state,
                    state_change,
                    channel_state,
                    pseudo_random_generator,
                    block_number,
                )
                events = sub_iteration.events

        if sub_iteration and sub_iteration.new_state is None:
            del chain_state.payment_mapping.secrethashes_to_task[secrethash]

    return TransitionResult(chain_state, events)
예제 #33
0
파일: node.py 프로젝트: Huaida/raiden
def subdispatch_to_paymenttask(node_state, state_change, secrethash):
    block_number = node_state.block_number
    sub_task = node_state.payment_mapping.secrethashes_to_task.get(secrethash)
    events = list()

    if sub_task:
        if isinstance(sub_task, PaymentMappingState.InitiatorTask):
            payment_network_identifier = sub_task.payment_network_identifier
            token_address = sub_task.token_address

            token_network_state = get_token_network(
                node_state,
                payment_network_identifier,
                token_address,
            )

            if token_network_state:
                sub_iteration = initiator_manager.state_transition(
                    sub_task.manager_state,
                    state_change,
                    token_network_state.channelidentifiers_to_channels,
                    block_number,
                )
                events = sub_iteration.events

        elif isinstance(sub_task, PaymentMappingState.MediatorTask):
            payment_network_identifier = sub_task.payment_network_identifier
            token_address = sub_task.token_address

            token_network_state = get_token_network(
                node_state,
                payment_network_identifier,
                token_address,
            )

            if token_network_state:
                sub_iteration = mediator.state_transition(
                    sub_task.mediator_state,
                    state_change,
                    token_network_state.channelidentifiers_to_channels,
                    block_number,
                )
                events = sub_iteration.events

        elif isinstance(sub_task, PaymentMappingState.TargetTask):
            payment_network_identifier = sub_task.payment_network_identifier
            token_address = sub_task.token_address
            channel_identifier = sub_task.channel_identifier

            channel_state = views.get_channelstate_by_tokenaddress(
                node_state,
                payment_network_identifier,
                token_address,
                channel_identifier,
            )

            if channel_state:
                sub_iteration = target.state_transition(
                    sub_task.target_state,
                    state_change,
                    channel_state,
                    block_number,
                )
                events = sub_iteration.events

    return TransitionResult(node_state, events)
예제 #34
0
파일: node.py 프로젝트: hackaugusto/raiden
def subdispatch_to_paymenttask(
        chain_state: ChainState,
        state_change: StateChange,
        secrethash: SecretHash,
) -> TransitionResult:
    block_number = chain_state.block_number
    sub_task = chain_state.payment_mapping.secrethashes_to_task.get(secrethash)
    events = list()
    sub_iteration = None

    if sub_task:
        pseudo_random_generator = chain_state.pseudo_random_generator

        if isinstance(sub_task, InitiatorTask):
            token_network_identifier = sub_task.token_network_identifier
            token_network_state = views.get_token_network_by_identifier(
                chain_state,
                token_network_identifier,
            )
            if token_network_state:
                sub_iteration = initiator_manager.state_transition(
                    sub_task.manager_state,
                    state_change,
                    token_network_state.channelidentifiers_to_channels,
                    pseudo_random_generator,
                    block_number,
                )
                events = sub_iteration.events

        elif isinstance(sub_task, MediatorTask):
            token_network_identifier = sub_task.token_network_identifier
            token_network_state = views.get_token_network_by_identifier(
                chain_state,
                token_network_identifier,
            )

            if token_network_state:
                sub_iteration = mediator.state_transition(
                    sub_task.mediator_state,
                    state_change,
                    token_network_state.channelidentifiers_to_channels,
                    pseudo_random_generator,
                    block_number,
                )
                events = sub_iteration.events

        elif isinstance(sub_task, TargetTask):
            token_network_identifier = sub_task.token_network_identifier
            channel_identifier = sub_task.channel_identifier

            channel_state = views.get_channelstate_by_token_network_identifier(
                chain_state,
                token_network_identifier,
                channel_identifier,
            )

            if channel_state:
                sub_iteration = target.state_transition(
                    sub_task.target_state,
                    state_change,
                    channel_state,
                    pseudo_random_generator,
                    block_number,
                )
                events = sub_iteration.events

        if sub_iteration and sub_iteration.new_state is None:
            del chain_state.payment_mapping.secrethashes_to_task[secrethash]

    return TransitionResult(chain_state, events)
예제 #35
0
def test_refund_transfer_no_more_routes():
    amount = UNIT_TRANSFER_AMOUNT
    refund_pkey, refund_address = factories.make_privkey_address()
    setup = setup_initiator_tests(
        amount=amount,
        partner_balance=amount,
        our_address=UNIT_TRANSFER_INITIATOR,
        partner_address=refund_address,
    )

    original_transfer = setup.current_state.initiator.transfer
    refund_transfer = factories.make_signed_transfer(
        amount,
        original_transfer.initiator,
        original_transfer.target,
        original_transfer.lock.expiration,
        UNIT_SECRET,
        payment_identifier=original_transfer.payment_identifier,
        channel_identifier=setup.channel.identifier,
        pkey=refund_pkey,
        sender=refund_address,
    )

    state_change = ReceiveTransferRefundCancelRoute(
        routes=setup.available_routes,
        transfer=refund_transfer,
        secret=random_secret(),
    )

    iteration = initiator_manager.state_transition(
        setup.current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        setup.block_number,
    )
    current_state = iteration.new_state
    # As per the description of the issue here:
    # https://github.com/raiden-network/raiden/issues/3146#issuecomment-447378046
    # We can fail the payment but can't delete the payment task if there are no
    # more routes, but we have to wait for the lock expiration
    assert iteration.new_state is not None

    unlocked_failed = next(e for e in iteration.events if isinstance(e, EventUnlockFailed))
    sent_failed = next(e for e in iteration.events if isinstance(e, EventPaymentSentFailed))

    assert unlocked_failed
    assert sent_failed

    invalid_balance_proof = factories.make_signed_balance_proof(
        nonce=2,
        transferred_amount=original_transfer.balance_proof.transferred_amount,
        locked_amount=0,
        token_network_address=original_transfer.balance_proof.token_network_identifier,
        channel_identifier=setup.channel.identifier,
        locksroot=EMPTY_MERKLE_ROOT,
        extra_hash=original_transfer.lock.secrethash,
        sender_address=refund_address,
    )
    balance_proof = factories.make_signed_balance_proof(
        nonce=2,
        transferred_amount=original_transfer.balance_proof.transferred_amount,
        locked_amount=0,
        token_network_address=original_transfer.balance_proof.token_network_identifier,
        channel_identifier=setup.channel.identifier,
        locksroot=EMPTY_MERKLE_ROOT,
        extra_hash=original_transfer.lock.secrethash,
        sender_address=refund_address,
        private_key=refund_pkey,
    )
    invalid_lock_expired_state_change = ReceiveLockExpired(
        invalid_balance_proof,
        secrethash=original_transfer.lock.secrethash,
        message_identifier=5,
    )
    lock_expired_state_change = ReceiveLockExpired(
        balance_proof,
        secrethash=original_transfer.lock.secrethash,
        message_identifier=5,
    )
    before_expiry_block = original_transfer.lock.expiration - 1
    expiry_block = channel.get_sender_expiration_threshold(original_transfer.lock)

    # a block before lock expiration, no events should be emitted
    current_state = iteration.new_state
    state_change = Block(
        block_number=before_expiry_block,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        expiry_block,
    )
    assert not iteration.events
    assert iteration.new_state, 'payment task should not be deleted at this block'

    # process an invalid lock expired message before lock expiration
    current_state = iteration.new_state
    iteration = initiator_manager.state_transition(
        current_state,
        invalid_lock_expired_state_change,
        setup.channel_map,
        setup.prng,
        before_expiry_block,
    )
    assert iteration.new_state, 'payment task should not be deleted at this lock expired'
    # should not be accepted
    assert not events.must_contain_entry(iteration.events, SendProcessed, {})
    assert events.must_contain_entry(iteration.events, EventInvalidReceivedLockExpired, {})

    # process a valid lock expired message before lock expiration
    current_state = iteration.new_state
    iteration = initiator_manager.state_transition(
        current_state,
        lock_expired_state_change,
        setup.channel_map,
        setup.prng,
        before_expiry_block,
    )
    assert iteration.new_state, 'payment task should not be deleted at this lock expired'
    # should not be accepted
    assert not events.must_contain_entry(iteration.events, SendProcessed, {})

    # now we get to the lock expiration block
    current_state = iteration.new_state
    state_change = Block(
        block_number=expiry_block,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        expiry_block,
    )
    assert events.must_contain_entry(iteration.events, SendLockExpired, {})
    # Since there was a refund transfer the payment task must not have been deleted
    assert iteration.new_state is not None

    # process the lock expired message after lock expiration
    current_state = iteration.new_state
    iteration = initiator_manager.state_transition(
        current_state,
        lock_expired_state_change,
        setup.channel_map,
        setup.prng,
        expiry_block,
    )
    # should be accepted
    assert events.must_contain_entry(iteration.events, SendProcessed, {})
    assert iteration.new_state, 'payment task should be there waiting for next block'

    # process the the block after lock expiration
    current_state = iteration.new_state
    state_change = Block(
        block_number=expiry_block + 1,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        expiry_block + 1,
    )
    assert iteration.new_state is None, 'from this point on the payment task should go'
예제 #36
0
def test_initiator_lock_expired():
    amount = UNIT_TRANSFER_AMOUNT * 2

    channel1 = factories.make_channel(
        our_balance=amount,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    channel2 = factories.make_channel(
        our_balance=0,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    pseudo_random_generator = random.Random()

    channel_map = {
        channel1.identifier: channel1,
        channel2.identifier: channel2,
    }

    available_routes = [
        factories.route_from_channel(channel1),
        factories.route_from_channel(channel2),
    ]

    block_number = 10
    transfer_description = factories.make_transfer_description(
        secret=UNIT_SECRET,
        payment_network_identifier=channel1.payment_network_identifier,
    )
    current_state = make_initiator_manager_state(
        available_routes,
        transfer_description,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    transfer = current_state.initiator.transfer

    assert transfer.lock.secrethash in channel1.our_state.secrethashes_to_lockedlocks

    # Trigger lock expiry
    state_change = Block(
        block_number=channel.get_sender_expiration_threshold(transfer.lock),
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )

    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    assert events.must_contain_entry(iteration.events, SendLockExpired, {
        'balance_proof': {
            'nonce': 2,
            'transferred_amount': 0,
            'locked_amount': 0,
        },
        'secrethash': transfer.lock.secrethash,
        'recipient': channel1.partner_state.address,
    })
    # Since the lock expired make sure we also get the payment sent failed event
    assert events.must_contain_entry(iteration.events, EventPaymentSentFailed, {
        'payment_network_identifier': channel1.payment_network_identifier,
        'token_network_identifier': channel1.token_network_identifier,
        'identifier': UNIT_TRANSFER_IDENTIFIER,
        'target': transfer.target,
        'reason': "transfer's lock has expired",
    })

    assert transfer.lock.secrethash not in channel1.our_state.secrethashes_to_lockedlocks
    msg = 'the initiator payment task must be deleted at block of the lock expiration'
    assert not iteration.new_state, msg

    # Create 2 other transfers
    transfer2_state = make_initiator_manager_state(
        available_routes,
        make_transfer_description('transfer2'),
        channel_map,
        pseudo_random_generator,
        30,
    )
    transfer2_lock = transfer2_state.initiator.transfer.lock

    transfer3_state = make_initiator_manager_state(
        available_routes,
        make_transfer_description('transfer3'),
        channel_map,
        pseudo_random_generator,
        32,
    )

    transfer3_lock = transfer3_state.initiator.transfer.lock

    assert len(channel1.our_state.secrethashes_to_lockedlocks) == 2

    assert transfer2_lock.secrethash in channel1.our_state.secrethashes_to_lockedlocks

    expiration_block_number = channel.get_sender_expiration_threshold(transfer2_lock)

    block = Block(
        block_number=expiration_block_number,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    iteration = initiator_manager.state_transition(
        transfer2_state,
        block,
        channel_map,
        pseudo_random_generator,
        expiration_block_number,
    )

    # Transfer 2 expired
    assert transfer2_lock.secrethash not in channel1.our_state.secrethashes_to_lockedlocks

    # Transfer 3 is still there
    assert transfer3_lock.secrethash in channel1.our_state.secrethashes_to_lockedlocks
예제 #37
0
def test_refund_transfer_no_more_routes():
    amount = UNIT_TRANSFER_AMOUNT
    block_number = 1
    refund_pkey, refund_address = factories.make_privkey_address()
    pseudo_random_generator = random.Random()

    channel1 = factories.make_channel(
        our_balance=amount,
        partner_balance=amount,
        our_address=UNIT_TRANSFER_INITIATOR,
        partner_address=refund_address,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    channelmap = {channel1.identifier: channel1}
    available_routes = [factories.route_from_channel(channel1)]

    current_state = make_initiator_state(
        available_routes,
        factories.UNIT_TRANSFER_DESCRIPTION,
        channelmap,
        pseudo_random_generator,
        block_number,
    )

    original_transfer = current_state.initiator.transfer
    channel_identifier = current_state.initiator.channel_identifier
    channel_state = channelmap[channel_identifier]

    expiration = original_transfer.lock.expiration - channel_state.reveal_timeout - TRANSIT_BLOCKS
    refund_transfer = factories.make_signed_transfer(
        amount,
        original_transfer.initiator,
        original_transfer.target,
        expiration,
        UNIT_SECRET,
        payment_identifier=original_transfer.payment_identifier,
        channel_identifier=channel1.identifier,
        pkey=refund_pkey,
        sender=refund_address,
    )

    state_change = ReceiveTransferRefundCancelRoute(
        sender=channel_state.partner_state.address,
        routes=available_routes,
        transfer=refund_transfer,
        secret=random_secret(),
    )

    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        channelmap,
        pseudo_random_generator,
        block_number,
    )
    assert iteration.new_state is None

    unlocked_failed = next(e for e in iteration.events
                           if isinstance(e, EventUnlockFailed))
    sent_failed = next(e for e in iteration.events
                       if isinstance(e, EventTransferSentFailed))

    assert unlocked_failed
    assert sent_failed
def test_initiator_lock_expired():
    amount = UNIT_TRANSFER_AMOUNT * 2

    channel1 = factories.make_channel(
        our_balance=amount,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    channel2 = factories.make_channel(
        our_balance=0,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    pseudo_random_generator = random.Random()

    channel_map = {
        channel1.identifier: channel1,
        channel2.identifier: channel2,
    }

    available_routes = [
        factories.route_from_channel(channel1),
        factories.route_from_channel(channel2),
    ]

    block_number = 10
    transfer_description = factories.make_transfer_description(
        secret=UNIT_SECRET,
        payment_network_identifier=channel1.payment_network_identifier,
    )
    current_state = make_initiator_manager_state(
        available_routes,
        transfer_description,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    transfer = current_state.initiator.transfer

    assert transfer.lock.secrethash in channel1.our_state.secrethashes_to_lockedlocks

    # Trigger lock expiry
    state_change = Block(
        block_number=transfer.lock.expiration +
        DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )

    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    assert events.must_contain_entry(
        iteration.events, SendLockExpired, {
            'balance_proof': {
                'nonce': 2,
                'transferred_amount': 0,
                'locked_amount': 0,
            },
            'secrethash': transfer.lock.secrethash,
            'recipient': channel1.partner_state.address,
        })
    # Since the lock expired make sure we also get the payment sent failed event
    assert events.must_contain_entry(
        iteration.events, EventPaymentSentFailed, {
            'payment_network_identifier': channel1.payment_network_identifier,
            'token_network_identifier': channel1.token_network_identifier,
            'identifier': UNIT_TRANSFER_IDENTIFIER,
            'target': transfer.target,
            'reason': "transfer's lock has expired",
        })

    assert transfer.lock.secrethash not in channel1.our_state.secrethashes_to_lockedlocks
    msg = 'the initiator payment task must be deleted at block of the lock expiration'
    assert not iteration.new_state, msg

    # Create 2 other transfers
    transfer2_state = make_initiator_manager_state(
        available_routes,
        make_transfer_description('transfer2'),
        channel_map,
        pseudo_random_generator,
        30,
    )
    transfer2_lock = transfer2_state.initiator.transfer.lock

    transfer3_state = make_initiator_manager_state(
        available_routes,
        make_transfer_description('transfer3'),
        channel_map,
        pseudo_random_generator,
        32,
    )

    transfer3_lock = transfer3_state.initiator.transfer.lock

    assert len(channel1.our_state.secrethashes_to_lockedlocks) == 2

    assert transfer2_lock.secrethash in channel1.our_state.secrethashes_to_lockedlocks

    expiration_block_number = transfer2_lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2

    block = Block(
        block_number=expiration_block_number,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    iteration = initiator_manager.state_transition(
        transfer2_state,
        block,
        channel_map,
        pseudo_random_generator,
        expiration_block_number,
    )

    # Transfer 2 expired
    assert transfer2_lock.secrethash not in channel1.our_state.secrethashes_to_lockedlocks

    # Transfer 3 is still there
    assert transfer3_lock.secrethash in channel1.our_state.secrethashes_to_lockedlocks
def test_refund_transfer_no_more_routes():
    amount = UNIT_TRANSFER_AMOUNT
    refund_pkey, refund_address = factories.make_privkey_address()
    setup = setup_initiator_tests(
        amount=amount,
        partner_balance=amount,
        our_address=UNIT_TRANSFER_INITIATOR,
        partner_address=refund_address,
    )

    original_transfer = setup.current_state.initiator.transfer
    refund_transfer = factories.make_signed_transfer(
        amount,
        original_transfer.initiator,
        original_transfer.target,
        original_transfer.lock.expiration,
        UNIT_SECRET,
        payment_identifier=original_transfer.payment_identifier,
        channel_identifier=setup.channel.identifier,
        pkey=refund_pkey,
        sender=refund_address,
    )

    state_change = ReceiveTransferRefundCancelRoute(
        routes=setup.available_routes,
        transfer=refund_transfer,
        secret=random_secret(),
    )

    iteration = initiator_manager.state_transition(
        setup.current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        setup.block_number,
    )
    current_state = iteration.new_state
    # As per the description of the issue here:
    # https://github.com/raiden-network/raiden/issues/3146#issuecomment-447378046
    # We can fail the payment but can't delete the payment task if there are no
    # more routes, but we have to wait for the lock expiration
    assert iteration.new_state is not None

    unlocked_failed = next(e for e in iteration.events
                           if isinstance(e, EventUnlockFailed))
    sent_failed = next(e for e in iteration.events
                       if isinstance(e, EventPaymentSentFailed))

    assert unlocked_failed
    assert sent_failed

    invalid_balance_proof = factories.make_signed_balance_proof(
        nonce=2,
        transferred_amount=original_transfer.balance_proof.transferred_amount,
        locked_amount=0,
        token_network_address=original_transfer.balance_proof.
        token_network_identifier,
        channel_identifier=setup.channel.identifier,
        locksroot=EMPTY_MERKLE_ROOT,
        extra_hash=original_transfer.lock.secrethash,
        sender_address=refund_address,
    )
    balance_proof = factories.make_signed_balance_proof(
        nonce=2,
        transferred_amount=original_transfer.balance_proof.transferred_amount,
        locked_amount=0,
        token_network_address=original_transfer.balance_proof.
        token_network_identifier,
        channel_identifier=setup.channel.identifier,
        locksroot=EMPTY_MERKLE_ROOT,
        extra_hash=original_transfer.lock.secrethash,
        sender_address=refund_address,
        private_key=refund_pkey,
    )
    invalid_lock_expired_state_change = ReceiveLockExpired(
        invalid_balance_proof,
        secrethash=original_transfer.lock.secrethash,
        message_identifier=5,
    )
    lock_expired_state_change = ReceiveLockExpired(
        balance_proof,
        secrethash=original_transfer.lock.secrethash,
        message_identifier=5,
    )
    before_expiry_block = original_transfer.lock.expiration - 1
    expiry_block = original_transfer.lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2

    # a block before lock expiration, no events should be emitted
    current_state = iteration.new_state
    state_change = Block(
        block_number=before_expiry_block,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        expiry_block,
    )
    assert not iteration.events
    assert iteration.new_state, 'payment task should not be deleted at this block'

    # process an invalid lock expired message before lock expiration
    current_state = iteration.new_state
    iteration = initiator_manager.state_transition(
        current_state,
        invalid_lock_expired_state_change,
        setup.channel_map,
        setup.prng,
        before_expiry_block,
    )
    assert iteration.new_state, 'payment task should not be deleted at this lock expired'
    # should not be accepted
    assert not events.must_contain_entry(iteration.events, SendProcessed, {})
    assert events.must_contain_entry(iteration.events,
                                     EventInvalidReceivedLockExpired, {})

    # process a valid lock expired message before lock expiration
    current_state = iteration.new_state
    iteration = initiator_manager.state_transition(
        current_state,
        lock_expired_state_change,
        setup.channel_map,
        setup.prng,
        before_expiry_block,
    )
    assert iteration.new_state, 'payment task should not be deleted at this lock expired'
    # should not be accepted
    assert not events.must_contain_entry(iteration.events, SendProcessed, {})

    # now we get to the lock expiration block
    current_state = iteration.new_state
    state_change = Block(
        block_number=expiry_block,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        expiry_block,
    )
    assert events.must_contain_entry(iteration.events, SendLockExpired, {})
    # Since there was a refund transfer the payment task must not have been deleted
    assert iteration.new_state is not None

    # process the lock expired message after lock expiration
    current_state = iteration.new_state
    iteration = initiator_manager.state_transition(
        current_state,
        lock_expired_state_change,
        setup.channel_map,
        setup.prng,
        expiry_block,
    )
    # should be accepted
    assert events.must_contain_entry(iteration.events, SendProcessed, {})
    assert iteration.new_state, 'payment task should be there waiting for next block'

    # process the the block after lock expiration
    current_state = iteration.new_state
    state_change = Block(
        block_number=expiry_block + 1,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        expiry_block + 1,
    )
    assert iteration.new_state is None, 'from this point on the payment task should go'
예제 #40
0
def test_refund_transfer_next_route():
    amount = UNIT_TRANSFER_AMOUNT
    our_address = factories.ADDR
    refund_pkey, refund_address = factories.make_privkey_address()
    pseudo_random_generator = random.Random()

    channel1 = factories.make_channel(
        our_balance=amount,
        partner_balance=amount,
        our_address=our_address,
        partner_address=refund_address,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    channel2 = factories.make_channel(
        our_balance=0,
        our_address=our_address,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    channel3 = factories.make_channel(
        our_balance=amount,
        our_address=our_address,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )

    channelmap = {
        channel1.identifier: channel1,
        channel2.identifier: channel2,
        channel3.identifier: channel3,
    }

    available_routes = [
        factories.route_from_channel(channel1),
        factories.route_from_channel(channel2),
        factories.route_from_channel(channel3),
    ]

    block_number = 10
    current_state = make_initiator_state(
        available_routes,
        factories.UNIT_TRANSFER_DESCRIPTION,
        channelmap,
        pseudo_random_generator,
        block_number,
    )

    original_transfer = current_state.initiator.transfer
    channel_identifier = current_state.initiator.channel_identifier
    channel_state = channelmap[channel_identifier]

    expiration = original_transfer.lock.expiration - channel_state.reveal_timeout - TRANSIT_BLOCKS
    refund_transfer = factories.make_signed_transfer(
        amount,
        our_address,
        original_transfer.target,
        expiration,
        UNIT_SECRET,
        payment_identifier=original_transfer.payment_identifier,
        channel_identifier=channel1.identifier,
        pkey=refund_pkey,
        sender=refund_address,
    )
    assert channel_state.partner_state.address == refund_address

    state_change = ReceiveTransferRefundCancelRoute(
        sender=refund_address,
        routes=available_routes,
        transfer=refund_transfer,
        secret=random_secret(),
    )

    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        channelmap,
        pseudo_random_generator,
        block_number,
    )
    assert iteration.new_state is not None

    route_cancelled = next(e for e in iteration.events
                           if isinstance(e, EventUnlockFailed))
    new_transfer = next(e for e in iteration.events
                        if isinstance(e, SendLockedTransfer))

    assert route_cancelled, 'The previous transfer must be cancelled'
    assert new_transfer, 'No mediated transfer event emitted, should have tried a new route'
    msg = 'the new transfer must use a new secret / secrethash'
    assert new_transfer.transfer.lock.secrethash != refund_transfer.lock.secrethash, msg
    assert iteration.new_state.initiator is not None
예제 #41
0
파일: node.py 프로젝트: gasparmedina/lumino
def subdispatch_to_paymenttask(
        chain_state: ChainState, state_change: StateChange,
        secrethash: SecretHash) -> TransitionResult[ChainState]:
    block_number = chain_state.block_number
    block_hash = chain_state.block_hash
    sub_task = chain_state.payment_mapping.secrethashes_to_task.get(secrethash)
    events: List[Event] = list()

    if sub_task:
        pseudo_random_generator = chain_state.pseudo_random_generator
        sub_iteration: Union[TransitionResult[InitiatorPaymentState],
                             TransitionResult[MediatorTransferState],
                             TransitionResult[TargetTransferState], ]

        if isinstance(sub_task, InitiatorTask):
            token_network_identifier = sub_task.token_network_identifier
            token_network_state = get_token_network_by_address(
                chain_state, token_network_identifier)
            if token_network_state:
                sub_iteration = initiator_manager.state_transition(
                    sub_task.manager_state,
                    state_change,
                    token_network_state.channelidentifiers_to_channels,
                    pseudo_random_generator,
                    block_number,
                )
                events = sub_iteration.events

                if sub_iteration.new_state is None:
                    del chain_state.payment_mapping.secrethashes_to_task[
                        secrethash]

        elif isinstance(sub_task, MediatorTask):
            token_network_identifier = sub_task.token_network_identifier
            token_network_state = get_token_network_by_address(
                chain_state, token_network_identifier)

            if token_network_state:
                channelids_to_channels = token_network_state.channelidentifiers_to_channels
                sub_iteration = mediator.state_transition(
                    mediator_state=sub_task.mediator_state,
                    state_change=state_change,
                    channelidentifiers_to_channels=channelids_to_channels,
                    nodeaddresses_to_networkstates=chain_state.
                    nodeaddresses_to_networkstates,
                    pseudo_random_generator=pseudo_random_generator,
                    block_number=block_number,
                    block_hash=block_hash,
                )
                events = sub_iteration.events

                if sub_iteration.new_state is None:
                    del chain_state.payment_mapping.secrethashes_to_task[
                        secrethash]

        elif isinstance(sub_task, TargetTask):
            token_network_identifier = sub_task.token_network_identifier
            channel_identifier = sub_task.channel_identifier

            channel_state = views.get_channelstate_by_canonical_identifier(
                chain_state=chain_state,
                canonical_identifier=CanonicalIdentifier(
                    chain_identifier=chain_state.chain_id,
                    token_network_address=token_network_identifier,
                    channel_identifier=channel_identifier,
                ),
            )

            if channel_state:
                sub_iteration = target.state_transition(
                    target_state=sub_task.target_state,
                    state_change=state_change,
                    channel_state=channel_state,
                    pseudo_random_generator=pseudo_random_generator,
                    block_number=block_number,
                )
                events = sub_iteration.events

                if sub_iteration.new_state is None:
                    del chain_state.payment_mapping.secrethashes_to_task[
                        secrethash]

    return TransitionResult(chain_state, events)
예제 #42
0
def test_state_wait_secretrequest_invalid_amount_and_sender():
    amount = UNIT_TRANSFER_AMOUNT
    block_number = 1
    pseudo_random_generator = random.Random()

    channel1 = factories.make_channel(
        our_balance=amount,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    channel_map = {channel1.identifier: channel1}
    available_routes = [factories.route_from_channel(channel1)]
    current_state = make_initiator_manager_state(
        available_routes,
        factories.UNIT_TRANSFER_DESCRIPTION,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    lock = channel.get_lock(
        channel1.our_state,
        current_state.initiator.transfer_description.secrethash,
    )

    state_change = ReceiveSecretRequest(
        UNIT_TRANSFER_IDENTIFIER,
        lock.amount + 1,
        lock.expiration,
        lock.secrethash,
        UNIT_TRANSFER_INITIATOR,
    )

    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    assert len(iteration.events) == 0
    assert iteration.new_state.initiator.received_secret_request is False

    # Now the proper target sends the message, this should be applied
    state_change_2 = ReceiveSecretRequest(
        UNIT_TRANSFER_IDENTIFIER,
        lock.amount,
        lock.expiration,
        lock.secrethash,
        UNIT_TRANSFER_TARGET,
    )

    iteration2 = initiator_manager.state_transition(
        iteration.new_state,
        state_change_2,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    assert iteration2.new_state.initiator.received_secret_request is True
    assert isinstance(iteration2.events[0], SendSecretReveal)
예제 #43
0
def test_refund_transfer_next_route():
    amount = UNIT_TRANSFER_AMOUNT
    our_address = factories.ADDR
    refund_pkey, refund_address = factories.make_privkey_address()
    pseudo_random_generator = random.Random()

    channel1 = factories.make_channel(
        our_balance=amount,
        partner_balance=amount,
        our_address=our_address,
        partner_address=refund_address,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    channel2 = factories.make_channel(
        our_balance=0,
        our_address=our_address,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )
    channel3 = factories.make_channel(
        our_balance=amount,
        our_address=our_address,
        token_address=UNIT_TOKEN_ADDRESS,
        token_network_identifier=UNIT_TOKEN_NETWORK_ADDRESS,
    )

    channel_map = {
        channel1.identifier: channel1,
        channel2.identifier: channel2,
        channel3.identifier: channel3,
    }

    available_routes = [
        factories.route_from_channel(channel1),
        factories.route_from_channel(channel2),
        factories.route_from_channel(channel3),
    ]

    block_number = 10
    current_state = make_initiator_manager_state(
        available_routes,
        factories.UNIT_TRANSFER_DESCRIPTION,
        channel_map,
        pseudo_random_generator,
        block_number,
    )

    original_transfer = current_state.initiator.transfer

    refund_transfer = factories.make_signed_transfer(
        amount,
        our_address,
        original_transfer.target,
        original_transfer.lock.expiration,
        UNIT_SECRET,
        payment_identifier=original_transfer.payment_identifier,
        channel_identifier=channel1.identifier,
        pkey=refund_pkey,
        sender=refund_address,
    )
    assert channel1.partner_state.address == refund_address

    state_change = ReceiveTransferRefundCancelRoute(
        routes=available_routes,
        transfer=refund_transfer,
        secret=random_secret(),
    )

    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        channel_map,
        pseudo_random_generator,
        block_number,
    )
    assert iteration.new_state is not None

    route_cancelled = next(e for e in iteration.events if isinstance(e, EventUnlockFailed))
    new_transfer = next(e for e in iteration.events if isinstance(e, SendLockedTransfer))

    assert route_cancelled, 'The previous transfer must be cancelled'
    assert new_transfer, 'No mediated transfer event emitted, should have tried a new route'
    msg = 'the new transfer must use a new secret / secrethash'
    assert new_transfer.transfer.lock.secrethash != refund_transfer.lock.secrethash, msg
    assert iteration.new_state.initiator is not None