Пример #1
0
def test_regression_mediator_send_lock_expired_with_new_block():
    """The mediator must send the lock expired, but it must **not** clear
    itself if it has not **received** the corresponding message.
    """
    pseudo_random_generator = random.Random()

    channels = factories.mediator_make_channel_pair()
    payer_transfer = factories.make_signed_transfer_for(
        channels[0], LONG_EXPIRATION)

    init_iteration = mediator.state_transition(
        mediator_state=None,
        state_change=factories.mediator_make_init_action(
            channels, payer_transfer),
        channelidentifiers_to_channels=channels.channel_map,
        addresses_to_channel=channels.addresses_to_channel(),
        nodeaddresses_to_networkstates=channels.nodeaddresses_to_networkstates,
        pseudo_random_generator=pseudo_random_generator,
        block_number=5,
        block_hash=factories.make_block_hash(),
    )
    assert init_iteration.new_state is not None
    send_transfer = search_for_item(init_iteration.events, SendLockedTransfer,
                                    {})
    assert send_transfer

    transfer = send_transfer.transfer

    block_expiration_number = channel.get_sender_expiration_threshold(
        transfer.lock.expiration)
    block = Block(
        block_number=block_expiration_number,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    iteration = mediator.state_transition(
        mediator_state=init_iteration.new_state,
        state_change=block,
        channelidentifiers_to_channels=channels.channel_map,
        addresses_to_channel=channels.addresses_to_channel(),
        nodeaddresses_to_networkstates=channels.nodeaddresses_to_networkstates,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_expiration_number,
        block_hash=factories.make_block_hash(),
    )

    msg = ("The payer's lock has also expired, "
           "but it must not be removed locally (without an Expired lock)")
    assert transfer.lock.secrethash in channels[
        0].partner_state.secrethashes_to_lockedlocks, msg

    msg = "The payer has not yet sent an expired lock, the task can not be cleared yet"
    assert iteration.new_state is not None, msg

    assert search_for_item(iteration.events, SendLockExpired,
                           {"secrethash": transfer.lock.secrethash})
    assert transfer.lock.secrethash not in channels[
        1].our_state.secrethashes_to_lockedlocks
Пример #2
0
def test_regression_mediator_send_lock_expired_with_new_block():
    """ The mediator must send the lock expired, but it must **not** clear
    itself if it has not **received** the corresponding message.
    """
    pseudo_random_generator = random.Random()

    channels = factories.mediator_make_channel_pair()
    payer_transfer = factories.make_default_signed_transfer_for(
        channels[0],
        initiator=HOP1,
        expiration=30,
    )

    init_iteration = mediator.state_transition(
        mediator_state=None,
        state_change=factories.mediator_make_init_action(
            channels, payer_transfer),
        channelidentifiers_to_channels=channels.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=5,
    )
    assert init_iteration.new_state is not None
    send_transfer = must_contain_entry(init_iteration.events,
                                       SendLockedTransfer, {})
    assert send_transfer

    transfer = send_transfer.transfer

    block_expiration_number = transfer.lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2
    block = Block(
        block_number=block_expiration_number,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    iteration = mediator.state_transition(
        mediator_state=init_iteration.new_state,
        state_change=block,
        channelidentifiers_to_channels=channels.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_expiration_number,
    )

    msg = ("The payer's lock has also expired, "
           "but it must not be removed locally (without an Expired lock)")
    assert transfer.lock.secrethash in channels[
        0].partner_state.secrethashes_to_lockedlocks, msg

    msg = 'The payer has not yet sent an expired lock, the task can not be cleared yet'
    assert iteration.new_state is not None, msg

    assert must_contain_entry(iteration.events, SendLockExpired, {
        'secrethash': transfer.lock.secrethash,
    })
    assert transfer.lock.secrethash not in channels[
        1].our_state.secrethashes_to_lockedlocks
def test_regression_mediator_send_lock_expired_with_new_block():
    """ The mediator must send the lock expired, but it must **not** clear
    itself if it has not **received** the corresponding message.
    """
    pseudo_random_generator = random.Random()

    channels = factories.mediator_make_channel_pair()
    payer_transfer = factories.make_signed_transfer_for(channels[0], LONG_EXPIRATION)

    init_iteration = mediator.state_transition(
        mediator_state=None,
        state_change=factories.mediator_make_init_action(channels, payer_transfer),
        channelidentifiers_to_channels=channels.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=5,
    )
    assert init_iteration.new_state is not None
    send_transfer = must_contain_entry(init_iteration.events, SendLockedTransfer, {})
    assert send_transfer

    transfer = send_transfer.transfer

    block_expiration_number = channel.get_sender_expiration_threshold(transfer.lock)
    block = Block(
        block_number=block_expiration_number,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    iteration = mediator.state_transition(
        mediator_state=init_iteration.new_state,
        state_change=block,
        channelidentifiers_to_channels=channels.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_expiration_number,
    )

    msg = (
        "The payer's lock has also expired, "
        "but it must not be removed locally (without an Expired lock)"
    )
    assert transfer.lock.secrethash in channels[0].partner_state.secrethashes_to_lockedlocks, msg

    msg = 'The payer has not yet sent an expired lock, the task can not be cleared yet'
    assert iteration.new_state is not None, msg

    assert must_contain_entry(iteration.events, SendLockExpired, {
        'secrethash': transfer.lock.secrethash,
    })
    assert transfer.lock.secrethash not in channels[1].our_state.secrethashes_to_lockedlocks
def test_regression_unavailable_nodes_must_be_properly_filtered():
    """The list of available routes provided must be filtered based on the
    network status of the partner node.

    Regression test for: https://github.com/raiden-network/raiden/issues/3567
    """
    block_number = 5
    pseudo_random_generator = random.Random()

    channels = factories.mediator_make_channel_pair()
    payer_transfer = factories.make_signed_transfer_for(
        channels[0], LONG_EXPIRATION)

    all_nodes_offline = {
        channel.partner_state.address: NODE_NETWORK_UNREACHABLE
        for channel in channels.channels
    }

    initial_iteration = mediator.state_transition(
        mediator_state=None,
        state_change=factories.mediator_make_init_action(
            channels, payer_transfer),
        channelidentifiers_to_channels=channels.channel_map,
        nodeaddresses_to_networkstates=all_nodes_offline,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_number,
        block_hash=factories.make_block_hash(),
    )

    send_transfer = search_for_item(initial_iteration.events,
                                    SendLockedTransfer, {})
    msg = (
        'All available routes are with unavailable nodes, therefore no send '
        'should be produced')
    assert send_transfer is None, msg
Пример #5
0
def subdispatch_mediatortask(
    chain_state: ChainState,
    state_change: StateChange,
    token_network_identifier: TokenNetworkID,
    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)

    if not sub_task:
        is_valid_subtask = True
        mediator_state = None

    elif sub_task and isinstance(sub_task, MediatorTask):
        is_valid_subtask = (
            token_network_identifier == sub_task.token_network_identifier)
        mediator_state = sub_task.mediator_state
    else:
        is_valid_subtask = False

    events: List[Event] = list()
    if is_valid_subtask:
        token_network_state = get_token_network_by_address(
            chain_state,
            token_network_identifier,
        )

        if token_network_state:
            pseudo_random_generator = chain_state.pseudo_random_generator
            iteration = mediator.state_transition(
                mediator_state=mediator_state,
                state_change=state_change,
                channelidentifiers_to_channels=token_network_state.
                channelidentifiers_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 = iteration.events

            if iteration.new_state:
                sub_task = MediatorTask(
                    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)
Пример #6
0
def subdispatch_mediatortask(
        node_state,
        state_change,
        payment_network_identifier,
        token_address,
        secrethash):

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

    if not sub_task:
        is_valid_subtask = True
        mediator_state = None

    elif sub_task and isinstance(sub_task, PaymentMappingState.MediatorTask):
        is_valid_subtask = (
            payment_network_identifier == sub_task.payment_network_identifier and
            token_address == sub_task.token_address
        )
        mediator_state = sub_task.mediator_state
    else:
        is_valid_subtask = False

    events = list()
    if is_valid_subtask:
        token_network_state = get_token_network(
            node_state,
            payment_network_identifier,
            token_address,
        )

        pseudo_random_generator = node_state.pseudo_random_generator
        iteration = mediator.state_transition(
            mediator_state,
            state_change,
            token_network_state.channelidentifiers_to_channels,
            pseudo_random_generator,
            block_number,
        )
        events = iteration.events

        if iteration.new_state:
            sub_task = PaymentMappingState.MediatorTask(
                payment_network_identifier,
                token_address,
                iteration.new_state,
            )
            node_state.payment_mapping.secrethashes_to_task[secrethash] = sub_task

    return TransitionResult(node_state, events)
Пример #7
0
def subdispatch_mediatortask(
        chain_state: ChainState,
        state_change: StateChange,
        token_network_identifier: typing.TokenNetworkID,
        secrethash: typing.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
        mediator_state = None

    elif sub_task and isinstance(sub_task, MediatorTask):
        is_valid_subtask = (
            token_network_identifier == sub_task.token_network_identifier
        )
        mediator_state = sub_task.mediator_state
    else:
        is_valid_subtask = False

    events = list()
    if is_valid_subtask:
        token_network_state = views.get_token_network_by_identifier(
            chain_state,
            token_network_identifier,
        )

        pseudo_random_generator = chain_state.pseudo_random_generator
        iteration = mediator.state_transition(
            mediator_state,
            state_change,
            token_network_state.channelidentifiers_to_channels,
            pseudo_random_generator,
            block_number,
        )
        events = iteration.events

        if iteration.new_state:
            sub_task = MediatorTask(
                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)
Пример #8
0
def subdispatch_mediatortask(
        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
        mediator_state = None

    elif sub_task and isinstance(sub_task, MediatorTask):
        is_valid_subtask = (
            token_network_identifier == sub_task.token_network_identifier
        )
        mediator_state = sub_task.mediator_state
    else:
        is_valid_subtask = False

    events = list()
    if is_valid_subtask:
        token_network_state = views.get_token_network_by_identifier(
            chain_state,
            token_network_identifier,
        )

        pseudo_random_generator = chain_state.pseudo_random_generator
        iteration = mediator.state_transition(
            mediator_state,
            state_change,
            token_network_state.channelidentifiers_to_channels,
            pseudo_random_generator,
            block_number,
        )
        events = iteration.events

        if iteration.new_state:
            sub_task = MediatorTask(
                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)
Пример #9
0
def make_mediator_state(from_transfer,
                        from_route,
                        routes,
                        our_address=factories.ADDR):

    state_change = make_init_statechange(
        from_transfer,
        from_route,
        routes,
        our_address=our_address,
    )

    initial_state = None
    iteration = mediator.state_transition(initial_state, state_change)

    return iteration.new_state
def make_mediator_state(
        from_transfer,
        from_route,
        routes,
        our_address=factories.ADDR):

    state_change = make_init_statechange(
        from_transfer,
        from_route,
        routes,
        our_address=our_address,
    )

    initial_state = None
    iteration = mediator.state_transition(initial_state, state_change)

    return iteration.new_state
Пример #11
0
def subdispatch_mediatortask(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
        mediator_state = None

    elif sub_task and isinstance(sub_task, PaymentMappingState.MediatorTask):
        is_valid_subtask = (
            payment_network_identifier == sub_task.payment_network_identifier
            and token_network_identifier == sub_task.token_network_identifier)
        mediator_state = sub_task.mediator_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 = mediator.state_transition(
            mediator_state,
            state_change,
            token_network_state.channelidentifiers_to_channels,
            block_number,
        )
        events = iteration.events

        if iteration.new_state:
            sub_task = PaymentMappingState.MediatorTask(
                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_payer_enter_danger_zone_with_transfer_payed():
    """ A mediator may have paid the next hop (payee), and didn't get paid by
    the previous hop (payer).

    When this happens, an assertion must not be hit, because it means the
    transfer must be unlocked on-chain.

    Issue: https://github.com/raiden-network/raiden/issues/1013
    """
    amount = 10
    block_number = 5
    target = HOP2
    expiration = 30
    pseudo_random_generator = random.Random()

    payer_channel = factories.make_channel(
        partner_balance=amount,
        partner_address=UNIT_TRANSFER_SENDER,
        token_address=UNIT_TOKEN_ADDRESS,
    )

    payer_transfer = factories.make_signed_transfer_for(
        payer_channel,
        amount,
        HOP1,
        target,
        expiration,
        UNIT_SECRET,
    )

    channel1 = factories.make_channel(
        our_balance=amount,
        token_address=UNIT_TOKEN_ADDRESS,
    )
    channelmap = {
        channel1.identifier: channel1,
        payer_channel.identifier: payer_channel,
    }
    possible_routes = [factories.route_from_channel(channel1)]

    mediator_state = MediatorTransferState(UNIT_SECRETHASH)
    initial_iteration = mediator.mediate_transfer(
        mediator_state,
        possible_routes,
        payer_channel,
        channelmap,
        pseudo_random_generator,
        payer_transfer,
        block_number,
    )

    send_transfer = must_contain_entry(initial_iteration.events,
                                       SendLockedTransfer, {})
    assert send_transfer

    lock_expiration = send_transfer.transfer.lock.expiration

    new_state = initial_iteration.new_state
    for block_number in range(block_number, lock_expiration + 1):
        block_state_change = Block(block_number)

        block_iteration = mediator.handle_block(
            channelmap,
            new_state,
            block_state_change,
            block_number,
        )
        new_state = block_iteration.new_state

    # send the balance proof, transitioning the payee state to paid
    assert new_state.transfers_pair[0].payee_state == 'payee_pending'
    receive_secret = ReceiveSecretReveal(
        UNIT_SECRET,
        channel1.partner_state.address,
    )
    paid_iteration = mediator.state_transition(
        new_state,
        receive_secret,
        channelmap,
        pseudo_random_generator,
        block_number,
    )
    paid_state = paid_iteration.new_state
    assert paid_state.transfers_pair[0].payee_state == 'payee_balance_proof'

    # move to the block in which the payee lock expires. This must not raise an
    # assertion
    expired_block_number = lock_expiration + 1
    expired_block_state_change = Block(expired_block_number)
    block_iteration = mediator.handle_block(
        channelmap,
        paid_state,
        expired_block_state_change,
        expired_block_number,
    )
def test_regression_mediator_task_no_routes():
    """ The mediator must only be cleared after the waiting transfer's lock has
    been handled.

    If a node receives a transfer to mediate, but there is no route available
    (because there is no sufficient capacity or the partner nodes are offline),
    and a refund is not possible, the mediator task must not be cleared,
    otherwise followup remove expired lock messages wont be processed and the
    nodes will get out of sync.
    """
    pseudo_random_generator = random.Random()

    channels = make_channel_set([
        NettingChannelStateProperties(
            our_state=NettingChannelEndStateProperties(balance=0),
            partner_state=NettingChannelEndStateProperties(
                balance=10,
                address=HOP2,
                privatekey=HOP2_KEY,
            ),
        ),
    ])

    payer_transfer = factories.make_signed_transfer_for(
        channels[0],
        factories.LockedTransferSignedStateProperties(
            sender=HOP2,
            pkey=HOP2_KEY,
            transfer=factories.LockedTransferProperties(expiration=30),
        ))

    init_state_change = ActionInitMediator(
        channels.get_routes(),
        channels.get_route(0),
        payer_transfer,
    )
    init_iteration = mediator.state_transition(
        mediator_state=None,
        state_change=init_state_change,
        channelidentifiers_to_channels=channels.channel_map,
        nodeaddresses_to_networkstates=channels.nodeaddresses_to_networkstates,
        pseudo_random_generator=pseudo_random_generator,
        block_number=5,
        block_hash=factories.make_block_hash(),
    )

    msg = 'The task must not be cleared, even if there is no route to forward the transfer'
    assert init_iteration.new_state is not None, msg
    assert init_iteration.new_state.waiting_transfer.transfer == payer_transfer
    assert search_for_item(init_iteration.events, SendLockedTransfer,
                           {}) is None
    assert search_for_item(init_iteration.events, SendRefundTransfer,
                           {}) is None

    secrethash = UNIT_SECRETHASH
    lock = channels[0].partner_state.secrethashes_to_lockedlocks[secrethash]

    # Creates a transfer as it was from the *partner*
    send_lock_expired, _ = channel.create_sendexpiredlock(
        sender_end_state=channels[0].partner_state,
        locked_lock=lock,
        pseudo_random_generator=pseudo_random_generator,
        chain_id=channels[0].chain_id,
        token_network_identifier=channels[0].token_network_identifier,
        channel_identifier=channels[0].identifier,
        recipient=channels[0].our_state.address,
    )
    assert send_lock_expired
    lock_expired_message = message_from_sendevent(send_lock_expired, HOP1)
    lock_expired_message.sign(LocalSigner(channels.partner_privatekeys[0]))
    balance_proof = balanceproof_from_envelope(lock_expired_message)

    message_identifier = message_identifier_from_prng(pseudo_random_generator)

    # Regression: The mediator must still be able to process the block which
    # expires the lock
    expired_block_number = channel.get_sender_expiration_threshold(lock)
    block_hash = factories.make_block_hash()
    expire_block_iteration = mediator.state_transition(
        mediator_state=init_iteration.new_state,
        state_change=Block(
            block_number=expired_block_number,
            gas_limit=0,
            block_hash=block_hash,
        ),
        channelidentifiers_to_channels=channels.channel_map,
        nodeaddresses_to_networkstates=channels.nodeaddresses_to_networkstates,
        pseudo_random_generator=pseudo_random_generator,
        block_number=expired_block_number,
        block_hash=block_hash,
    )
    assert expire_block_iteration.new_state is not None

    receive_expired_iteration = mediator.state_transition(
        mediator_state=expire_block_iteration.new_state,
        state_change=ReceiveLockExpired(
            balance_proof=balance_proof,
            secrethash=secrethash,
            message_identifier=message_identifier,
        ),
        channelidentifiers_to_channels=channels.channel_map,
        nodeaddresses_to_networkstates=channels.nodeaddresses_to_networkstates,
        pseudo_random_generator=pseudo_random_generator,
        block_number=expired_block_number,
        block_hash=block_hash,
    )

    msg = 'The only used channel had the lock cleared, the task must be cleared'
    assert receive_expired_iteration.new_state is None, msg
    assert secrethash not in channels[
        0].partner_state.secrethashes_to_lockedlocks
def test_regression_mediator_not_update_payer_state_twice():
    """ Regression Test for https://github.com/raiden-network/raiden/issues/3086
    Make sure that after a lock expired the mediator doesn't update the pair
    twice causing EventUnlockClaimFailed to be generated at every block.
    """
    pseudo_random_generator = random.Random()

    pair = factories.mediator_make_channel_pair()
    payer_channel, payee_channel = pair.channels
    payer_route = factories.route_from_channel(payer_channel)
    payer_transfer = factories.make_signed_transfer_for(payer_channel, LONG_EXPIRATION)

    available_routes = [factories.route_from_channel(payee_channel)]
    init_state_change = ActionInitMediator(
        routes=available_routes,
        from_route=payer_route,
        from_transfer=payer_transfer,
    )
    iteration = mediator.state_transition(
        mediator_state=None,
        state_change=init_state_change,
        channelidentifiers_to_channels=pair.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=5,
    )
    assert iteration.new_state is not None

    current_state = iteration.new_state
    send_transfer = must_contain_entry(iteration.events, SendLockedTransfer, {})
    assert send_transfer

    transfer = send_transfer.transfer
    block_expiration_number = channel.get_sender_expiration_threshold(transfer.lock)

    block = Block(
        block_number=block_expiration_number,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    iteration = mediator.state_transition(
        mediator_state=current_state,
        state_change=block,
        channelidentifiers_to_channels=pair.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_expiration_number,
    )

    msg = 'At the expiration block we should get an EventUnlockClaimFailed'
    assert must_contain_entry(iteration.events, EventUnlockClaimFailed, {}), msg

    current_state = iteration.new_state
    next_block = Block(
        block_number=block_expiration_number + 1,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )

    # Initiator receives the secret reveal after the lock expired
    receive_secret = ReceiveSecretReveal(
        secret=UNIT_SECRET,
        sender=payee_channel.partner_state.address,
    )
    iteration = mediator.state_transition(
        mediator_state=current_state,
        state_change=receive_secret,
        channelidentifiers_to_channels=pair.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=next_block.block_number,
    )
    current_state = iteration.new_state
    lock = payer_transfer.lock
    secrethash = lock.secrethash
    assert secrethash in payer_channel.partner_state.secrethashes_to_lockedlocks
    assert current_state.transfers_pair[0].payee_state == 'payee_expired'
    assert not channel.is_secret_known(payer_channel.partner_state, secrethash)

    safe_to_wait, _ = mediator.is_safe_to_wait(
        lock_expiration=lock.expiration,
        reveal_timeout=payer_channel.reveal_timeout,
        block_number=lock.expiration + 10,
    )

    assert not safe_to_wait

    iteration = mediator.state_transition(
        mediator_state=current_state,
        state_change=next_block,
        channelidentifiers_to_channels=pair.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_expiration_number,
    )
    msg = 'At the next block we should not get the same event'
    assert not must_contain_entry(iteration.events, EventUnlockClaimFailed, {}), msg
Пример #15
0
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)
Пример #16
0
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)
Пример #17
0
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)
def test_regression_mediator_task_no_routes():
    """ The mediator must only be cleared after the waiting transfer's lock has
    been handled.

    If a node receives a transfer to mediate, but there is no route available
    (because there is no sufficient capacity or the partner nodes are offline),
    and a refund is not possible, the mediator task must not be cleared,
    otherwise followup remove expired lock messages wont be processed and the
    nodes will get out of sync.
    """
    pseudo_random_generator = random.Random()

    channels = make_channel_set([
        NettingChannelStateProperties(
            our_state=NettingChannelEndStateProperties(balance=0),
            partner_state=NettingChannelEndStateProperties(
                balance=10,
                address=HOP2,
                privatekey=HOP2_KEY,
            ),
        ),
    ])

    payer_transfer = factories.make_signed_transfer_for(
        channels[0],
        factories.LockedTransferSignedStateProperties(
            sender=HOP2,
            pkey=HOP2_KEY,
            transfer=factories.LockedTransferProperties(expiration=30),
        ))

    init_state_change = ActionInitMediator(
        channels.get_routes(),
        channels.get_route(0),
        payer_transfer,
    )
    init_iteration = mediator.state_transition(
        mediator_state=None,
        state_change=init_state_change,
        channelidentifiers_to_channels=channels.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=5,
    )

    msg = 'The task must not be cleared, even if there is no route to forward the transfer'
    assert init_iteration.new_state is not None, msg
    assert init_iteration.new_state.waiting_transfer.transfer == payer_transfer
    assert must_contain_entry(init_iteration.events, SendLockedTransfer, {}) is None
    assert must_contain_entry(init_iteration.events, SendRefundTransfer, {}) is None

    secrethash = UNIT_SECRETHASH
    lock = channels[0].partner_state.secrethashes_to_lockedlocks[secrethash]

    # Creates a transfer as it was from the *partner*
    send_lock_expired, _ = channel.create_sendexpiredlock(
        sender_end_state=channels[0].partner_state,
        locked_lock=lock,
        pseudo_random_generator=pseudo_random_generator,
        chain_id=channels[0].chain_id,
        token_network_identifier=channels[0].token_network_identifier,
        channel_identifier=channels[0].identifier,
        recipient=channels[0].our_state.address,
    )
    assert send_lock_expired
    lock_expired_message = message_from_sendevent(send_lock_expired, HOP1)
    lock_expired_message.sign(channels.partner_privatekeys[0])
    balance_proof = balanceproof_from_envelope(lock_expired_message)

    message_identifier = message_identifier_from_prng(pseudo_random_generator)

    # Regression: The mediator must still be able to process the block which
    # expires the lock
    expired_block_number = channel.get_sender_expiration_threshold(lock)
    expire_block_iteration = mediator.state_transition(
        mediator_state=init_iteration.new_state,
        state_change=Block(
            block_number=expired_block_number,
            gas_limit=0,
            block_hash=None,
        ),
        channelidentifiers_to_channels=channels.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=expired_block_number,
    )
    assert expire_block_iteration.new_state is not None

    receive_expired_iteration = mediator.state_transition(
        mediator_state=expire_block_iteration.new_state,
        state_change=ReceiveLockExpired(
            balance_proof=balance_proof,
            secrethash=secrethash,
            message_identifier=message_identifier,
        ),
        channelidentifiers_to_channels=channels.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=expired_block_number,
    )

    msg = 'The only used channel had the lock cleared, the task must be cleared'
    assert receive_expired_iteration.new_state is None, msg
    assert secrethash not in channels[0].partner_state.secrethashes_to_lockedlocks
def test_regression_onchain_secret_reveal_must_update_channel_state():
    """ If a secret is learned off-chain and then on-chain, the state of the
    lock must be updated in the channel.
    """
    pseudo_random_generator = random.Random()

    setup = factories.make_transfers_pair(2, block_number=10)

    mediator_state = MediatorTransferState(
        secrethash=UNIT_SECRETHASH,
        routes=setup.channels.get_routes(),
    )
    mediator_state.transfers_pair = setup.transfers_pair

    secret = UNIT_SECRET
    secrethash = UNIT_SECRETHASH
    payer_channel = mediator.get_payer_channel(setup.channel_map,
                                               setup.transfers_pair[0])
    payee_channel = mediator.get_payee_channel(setup.channel_map,
                                               setup.transfers_pair[0])
    lock = payer_channel.partner_state.secrethashes_to_lockedlocks[secrethash]

    mediator.state_transition(
        mediator_state=mediator_state,
        state_change=ReceiveSecretReveal(secret,
                                         payee_channel.partner_state.address),
        channelidentifiers_to_channels=setup.channel_map,
        nodeaddresses_to_networkstates=setup.channels.
        nodeaddresses_to_networkstates,
        pseudo_random_generator=pseudo_random_generator,
        block_number=setup.block_number,
        block_hash=setup.block_hash,
    )
    assert secrethash in payer_channel.partner_state.secrethashes_to_unlockedlocks

    secret_registry_address = factories.make_address()
    transaction_hash = factories.make_address()
    mediator.state_transition(
        mediator_state=mediator_state,
        state_change=ContractReceiveSecretReveal(
            transaction_hash=transaction_hash,
            secret_registry_address=secret_registry_address,
            secrethash=secrethash,
            secret=secret,
            block_number=setup.block_number,
            block_hash=setup.block_hash,
        ),
        channelidentifiers_to_channels=setup.channel_map,
        nodeaddresses_to_networkstates=setup.channels.
        nodeaddresses_to_networkstates,
        pseudo_random_generator=pseudo_random_generator,
        block_number=setup.block_number,
        block_hash=setup.block_hash,
    )
    assert secrethash in payer_channel.partner_state.secrethashes_to_onchain_unlockedlocks

    # Creates a transfer as it was from the *partner*
    send_lock_expired, _ = channel.create_sendexpiredlock(
        sender_end_state=payer_channel.partner_state,
        locked_lock=lock,
        pseudo_random_generator=pseudo_random_generator,
        chain_id=payer_channel.chain_id,
        token_network_identifier=payer_channel.token_network_identifier,
        channel_identifier=payer_channel.identifier,
        recipient=payer_channel.our_state.address,
    )
    assert send_lock_expired
    expired_message = message_from_sendevent(send_lock_expired,
                                             setup.channels.our_address(0))
    expired_message.sign(LocalSigner(setup.channels.partner_privatekeys[0]))
    balance_proof = balanceproof_from_envelope(expired_message)

    message_identifier = message_identifier_from_prng(pseudo_random_generator)
    expired_block_number = channel.get_sender_expiration_threshold(lock)
    mediator.state_transition(
        mediator_state=mediator_state,
        state_change=ReceiveLockExpired(
            balance_proof=balance_proof,
            secrethash=secrethash,
            message_identifier=message_identifier,
        ),
        channelidentifiers_to_channels=setup.channel_map,
        nodeaddresses_to_networkstates=setup.channels.
        nodeaddresses_to_networkstates,
        pseudo_random_generator=pseudo_random_generator,
        block_number=expired_block_number,
        block_hash=factories.make_block_hash(),
    )
    assert secrethash in payer_channel.partner_state.secrethashes_to_onchain_unlockedlocks
def test_payer_enter_danger_zone_with_transfer_payed():
    """ A mediator may have paid the next hop (payee), and didn't get paid by
    the previous hop (payer).

    When this happens, an assertion must not be hit, because it means the
    transfer must be unlocked on-chain.

    Issue: https://github.com/raiden-network/raiden/issues/1013
    """
    block_number = 5
    pseudo_random_generator = random.Random()

    channels = factories.mediator_make_channel_pair()
    payer_transfer = factories.make_signed_transfer_for(channels[0], LONG_EXPIRATION)

    initial_iteration = mediator.state_transition(
        mediator_state=None,
        state_change=factories.mediator_make_init_action(channels, payer_transfer),
        channelidentifiers_to_channels=channels.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_number,
    )

    send_transfer = must_contain_entry(initial_iteration.events, SendLockedTransfer, {})
    assert send_transfer

    lock_expiration = send_transfer.transfer.lock.expiration

    new_state = initial_iteration.new_state
    for block_number in range(block_number, lock_expiration - channels[1].reveal_timeout):
        block_state_change = Block(
            block_number=block_number,
            gas_limit=1,
            block_hash=factories.make_transaction_hash(),
        )

        block_iteration = mediator.handle_block(
            new_state,
            block_state_change,
            channels.channel_map,
            pseudo_random_generator,
        )
        new_state = block_iteration.new_state

    # send the balance proof, transitioning the payee state to paid
    assert new_state.transfers_pair[0].payee_state == 'payee_pending'
    receive_secret = ReceiveSecretReveal(
        UNIT_SECRET,
        channels[1].partner_state.address,
    )
    paid_iteration = mediator.state_transition(
        mediator_state=new_state,
        state_change=receive_secret,
        channelidentifiers_to_channels=channels.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_number,
    )
    paid_state = paid_iteration.new_state
    assert paid_state.transfers_pair[0].payee_state == 'payee_balance_proof'

    # move to the block in which the payee lock expires. This must not raise an
    # assertion
    expired_block_number = lock_expiration + 1
    expired_block_state_change = Block(
        block_number=expired_block_number,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    block_iteration = mediator.handle_block(
        mediator_state=paid_state,
        state_change=expired_block_state_change,
        channelidentifiers_to_channels=channels.channel_map,
        pseudo_random_generator=pseudo_random_generator,
    )
def test_regression_mediator_send_lock_expired_with_new_block():
    """ The mediator must send the lock expired, but it must **not** clear
    itself if it has not **received** the corresponding message.
    """
    amount = 10
    block_number = 5
    target = HOP2
    expiration = 30
    pseudo_random_generator = random.Random()

    payer_channel = factories.make_channel(
        partner_balance=amount,
        partner_address=UNIT_TRANSFER_SENDER,
        token_address=UNIT_TOKEN_ADDRESS,
    )
    payer_route = factories.route_from_channel(payer_channel)

    payer_transfer = factories.make_signed_transfer_for(
        payer_channel,
        amount,
        HOP1,
        target,
        expiration,
        UNIT_SECRET,
    )

    channel1 = factories.make_channel(
        our_balance=amount,
        token_address=UNIT_TOKEN_ADDRESS,
    )
    available_routes = [factories.route_from_channel(channel1)]
    channel_map = {
        channel1.identifier: channel1,
        payer_channel.identifier: payer_channel,
    }

    init_state_change = ActionInitMediator(
        available_routes,
        payer_route,
        payer_transfer,
    )
    initial_state = None
    init_iteration = mediator.state_transition(
        initial_state,
        init_state_change,
        channel_map,
        pseudo_random_generator,
        block_number,
    )
    assert init_iteration.new_state is not None
    send_transfer = must_contain_entry(init_iteration.events,
                                       SendLockedTransfer, {})
    assert send_transfer

    transfer = send_transfer.transfer

    block_expiration_number = transfer.lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2
    block = Block(
        block_number=block_expiration_number,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    iteration = mediator.state_transition(
        init_iteration.new_state,
        block,
        channel_map,
        pseudo_random_generator,
        block_expiration_number,
    )

    msg = ("The payer's lock has also expired, "
           "but it must not be removed locally (without an Expired lock)")
    assert transfer.lock.secrethash in payer_channel.partner_state.secrethashes_to_lockedlocks, msg

    msg = 'The payer has not yet sent an expired lock, the task can not be cleared yet'
    assert iteration.new_state is not None, msg

    assert must_contain_entry(iteration.events, SendLockExpired, {
        'secrethash': transfer.lock.secrethash,
    })
    assert transfer.lock.secrethash not in channel1.our_state.secrethashes_to_lockedlocks
Пример #22
0
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)
Пример #23
0
def test_regression_onchain_secret_reveal_must_update_channel_state():
    """ If a secret is learned off-chain and then on-chain, the state of the
    lock must be updated in the channel.
    """
    amount = 10
    block_number = 10
    pseudo_random_generator = random.Random()

    channel_map, transfers_pair = factories.make_transfers_pair(
        [HOP2_KEY, HOP3_KEY],
        amount,
        block_number,
    )

    mediator_state = MediatorTransferState(UNIT_SECRETHASH)
    mediator_state.transfers_pair = transfers_pair

    secret = UNIT_SECRET
    secrethash = UNIT_SECRETHASH
    payer_channelid = transfers_pair[
        0].payer_transfer.balance_proof.channel_identifier
    payee_channelid = transfers_pair[
        0].payee_transfer.balance_proof.channel_identifier
    payer_channel = channel_map[payer_channelid]
    payee_channel = channel_map[payee_channelid]
    lock = payer_channel.partner_state.secrethashes_to_lockedlocks[secrethash]

    mediator.state_transition(
        mediator_state=mediator_state,
        state_change=ReceiveSecretReveal(secret,
                                         payee_channel.partner_state.address),
        channelidentifiers_to_channels=channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_number,
    )
    assert secrethash in payer_channel.partner_state.secrethashes_to_unlockedlocks

    secret_registry_address = factories.make_address()
    transaction_hash = factories.make_address()
    mediator.state_transition(
        mediator_state=mediator_state,
        state_change=ContractReceiveSecretReveal(
            transaction_hash,
            secret_registry_address,
            secrethash,
            secret,
            block_number,
        ),
        channelidentifiers_to_channels=channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_number,
    )
    assert secrethash in payer_channel.partner_state.secrethashes_to_onchain_unlockedlocks

    # Creates a transfer as it was from the *partner*
    send_lock_expired, _ = channel.create_sendexpiredlock(
        sender_end_state=payer_channel.partner_state,
        locked_lock=lock,
        pseudo_random_generator=pseudo_random_generator,
        chain_id=payer_channel.chain_id,
        token_network_identifier=payer_channel.token_network_identifier,
        channel_identifier=payer_channel.identifier,
        recipient=payer_channel.our_state.address,
    )
    assert send_lock_expired
    lock_expired_message = message_from_sendevent(send_lock_expired, HOP1)
    lock_expired_message.sign(HOP2_KEY)
    balance_proof = balanceproof_from_envelope(lock_expired_message)

    message_identifier = message_identifier_from_prng(pseudo_random_generator)
    expired_block_number = lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2
    mediator.state_transition(
        mediator_state=mediator_state,
        state_change=ReceiveLockExpired(
            balance_proof=balance_proof,
            secrethash=secrethash,
            message_identifier=message_identifier,
        ),
        channelidentifiers_to_channels=channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=expired_block_number,
    )
    assert secrethash in payer_channel.partner_state.secrethashes_to_onchain_unlockedlocks
Пример #24
0
def test_regression_mediator_task_no_routes():
    """ The mediator must only be cleared after the waiting transfer's lock has
    been handled.

    If a node receives a transfer to mediate, but there is no route available
    (because there is no sufficient capacity or the partner nodes are offline),
    and a refund is not possible, the mediator task must not be cleared,
    otherwise followup remove expired lock messages wont be processed and the
    nodes will get out of sync.
    """
    pseudo_random_generator = random.Random()

    channels = factories.make_channel_set([
        {
            'our_state': {
                'balance': 0
            },
            'partner_state': {
                'balance': 10,
                'address': HOP2
            },
            'open_transaction':
            factories.make_transaction_execution_status(
                finished_block_number=10, ),
        },
    ])

    payer_transfer = factories.make_default_signed_transfer_for(
        channels[0],
        initiator=HOP1,
        expiration=30,
        pkey=HOP2_KEY,
        sender=HOP2,
    )

    init_state_change = ActionInitMediator(
        channels.get_routes(),
        channels.get_route(0),
        payer_transfer,
    )
    init_iteration = mediator.state_transition(
        mediator_state=None,
        state_change=init_state_change,
        channelidentifiers_to_channels=channels.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=5,
    )

    msg = 'The task must not be cleared, even if there is no route to forward the transfer'
    assert init_iteration.new_state is not None, msg
    assert init_iteration.new_state.waiting_transfer.transfer == payer_transfer
    assert must_contain_entry(init_iteration.events, SendLockedTransfer,
                              {}) is None
    assert must_contain_entry(init_iteration.events, SendRefundTransfer,
                              {}) is None

    secrethash = UNIT_SECRETHASH
    lock = channels[0].partner_state.secrethashes_to_lockedlocks[secrethash]

    # Creates a transfer as it was from the *partner*
    send_lock_expired, _ = channel.create_sendexpiredlock(
        sender_end_state=channels[0].partner_state,
        locked_lock=lock,
        pseudo_random_generator=pseudo_random_generator,
        chain_id=channels[0].chain_id,
        token_network_identifier=channels[0].token_network_identifier,
        channel_identifier=channels[0].identifier,
        recipient=channels[0].our_state.address,
    )
    assert send_lock_expired
    lock_expired_message = message_from_sendevent(send_lock_expired, HOP1)
    lock_expired_message.sign(HOP2_KEY)
    balance_proof = balanceproof_from_envelope(lock_expired_message)

    message_identifier = message_identifier_from_prng(pseudo_random_generator)
    expired_block_number = lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2

    # Regression: The mediator must still be able to process the block which
    # expires the lock
    expire_block_iteration = mediator.state_transition(
        mediator_state=init_iteration.new_state,
        state_change=Block(
            block_number=expired_block_number,
            gas_limit=0,
            block_hash=None,
        ),
        channelidentifiers_to_channels=channels.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=expired_block_number,
    )
    assert expire_block_iteration.new_state is not None

    receive_expired_iteration = mediator.state_transition(
        mediator_state=expire_block_iteration.new_state,
        state_change=ReceiveLockExpired(
            balance_proof=balance_proof,
            secrethash=secrethash,
            message_identifier=message_identifier,
        ),
        channelidentifiers_to_channels=channels.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=expired_block_number,
    )

    msg = 'The only used channel had the lock cleared, the task must be cleared'
    assert receive_expired_iteration.new_state is None, msg
    assert secrethash not in channels[
        0].partner_state.secrethashes_to_lockedlocks
def test_regression_mediator_not_update_payer_state_twice():
    """ Regression Test for https://github.com/raiden-network/raiden/issues/3086
    Make sure that after a lock expired the mediator doesn't update the pair
    twice causing EventUnlockClaimFailed to be generated at every block.
    """
    pseudo_random_generator = random.Random()

    pair = factories.mediator_make_channel_pair()
    payer_channel, payee_channel = pair.channels
    payer_route = factories.route_from_channel(payer_channel)
    payer_transfer = factories.make_signed_transfer_for(
        payer_channel, LONG_EXPIRATION)

    available_routes = [factories.route_from_channel(payee_channel)]
    init_state_change = ActionInitMediator(
        routes=available_routes,
        from_route=payer_route,
        from_transfer=payer_transfer,
    )
    iteration = mediator.state_transition(
        mediator_state=None,
        state_change=init_state_change,
        channelidentifiers_to_channels=pair.channel_map,
        nodeaddresses_to_networkstates=pair.nodeaddresses_to_networkstates,
        pseudo_random_generator=pseudo_random_generator,
        block_number=5,
        block_hash=factories.make_block_hash(),
    )
    assert iteration.new_state is not None

    current_state = iteration.new_state
    send_transfer = search_for_item(iteration.events, SendLockedTransfer, {})
    assert send_transfer

    transfer = send_transfer.transfer
    block_expiration_number = channel.get_sender_expiration_threshold(
        transfer.lock)

    block = Block(
        block_number=block_expiration_number,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    iteration = mediator.state_transition(
        mediator_state=current_state,
        state_change=block,
        channelidentifiers_to_channels=pair.channel_map,
        nodeaddresses_to_networkstates=pair.nodeaddresses_to_networkstates,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_expiration_number,
        block_hash=factories.make_block_hash(),
    )

    msg = 'At the expiration block we should get an EventUnlockClaimFailed'
    assert search_for_item(iteration.events, EventUnlockClaimFailed, {}), msg

    current_state = iteration.new_state
    next_block = Block(
        block_number=block_expiration_number + 1,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )

    # Initiator receives the secret reveal after the lock expired
    receive_secret = ReceiveSecretReveal(
        secret=UNIT_SECRET,
        sender=payee_channel.partner_state.address,
    )
    iteration = mediator.state_transition(
        mediator_state=current_state,
        state_change=receive_secret,
        channelidentifiers_to_channels=pair.channel_map,
        nodeaddresses_to_networkstates=pair.nodeaddresses_to_networkstates,
        pseudo_random_generator=pseudo_random_generator,
        block_number=next_block.block_number,
        block_hash=next_block.block_hash,
    )
    current_state = iteration.new_state
    lock = payer_transfer.lock
    secrethash = lock.secrethash
    assert secrethash in payer_channel.partner_state.secrethashes_to_lockedlocks
    assert current_state.transfers_pair[0].payee_state == 'payee_expired'
    assert not channel.is_secret_known(payer_channel.partner_state, secrethash)

    safe_to_wait, _ = mediator.is_safe_to_wait(
        lock_expiration=lock.expiration,
        reveal_timeout=payer_channel.reveal_timeout,
        block_number=lock.expiration + 10,
    )

    assert not safe_to_wait

    iteration = mediator.state_transition(
        mediator_state=current_state,
        state_change=next_block,
        channelidentifiers_to_channels=pair.channel_map,
        nodeaddresses_to_networkstates=pair.nodeaddresses_to_networkstates,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_expiration_number,
        block_hash=factories.make_block_hash(),
    )
    msg = 'At the next block we should not get the same event'
    assert not search_for_item(iteration.events, EventUnlockClaimFailed,
                               {}), msg
Пример #26
0
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)
def test_payer_enter_danger_zone_with_transfer_payed():
    """ A mediator may have paid the next hop (payee), and didn't get paid by
    the previous hop (payer).

    When this happens, an assertion must not be hit, because it means the
    transfer must be unlocked on-chain.

    Issue: https://github.com/raiden-network/raiden/issues/1013
    """
    block_number = 5
    pseudo_random_generator = random.Random()

    channels = factories.mediator_make_channel_pair()
    payer_transfer = factories.make_signed_transfer_for(
        channels[0], LONG_EXPIRATION)

    initial_iteration = mediator.state_transition(
        mediator_state=None,
        state_change=factories.mediator_make_init_action(
            channels, payer_transfer),
        channelidentifiers_to_channels=channels.channel_map,
        nodeaddresses_to_networkstates=channels.nodeaddresses_to_networkstates,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_number,
        block_hash=factories.make_block_hash(),
    )

    send_transfer = search_for_item(initial_iteration.events,
                                    SendLockedTransfer, {})
    assert send_transfer

    lock_expiration = send_transfer.transfer.lock.expiration

    new_state = initial_iteration.new_state
    for block_number in range(block_number,
                              lock_expiration - channels[1].reveal_timeout):
        block_state_change = Block(
            block_number=block_number,
            gas_limit=1,
            block_hash=factories.make_transaction_hash(),
        )

        block_iteration = mediator.handle_block(
            new_state,
            block_state_change,
            channels.channel_map,
            pseudo_random_generator,
        )
        new_state = block_iteration.new_state

    # send the balance proof, transitioning the payee state to paid
    assert new_state.transfers_pair[0].payee_state == 'payee_pending'
    receive_secret = ReceiveSecretReveal(
        UNIT_SECRET,
        channels[1].partner_state.address,
    )
    paid_iteration = mediator.state_transition(
        mediator_state=new_state,
        state_change=receive_secret,
        channelidentifiers_to_channels=channels.channel_map,
        nodeaddresses_to_networkstates=channels.nodeaddresses_to_networkstates,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_number,
        block_hash=factories.make_block_hash(),
    )
    paid_state = paid_iteration.new_state
    assert paid_state.transfers_pair[0].payee_state == 'payee_balance_proof'

    # move to the block in which the payee lock expires. This must not raise an
    # assertion
    expired_block_number = lock_expiration + 1
    expired_block_state_change = Block(
        block_number=expired_block_number,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    block_iteration = mediator.handle_block(
        mediator_state=paid_state,
        state_change=expired_block_state_change,
        channelidentifiers_to_channels=channels.channel_map,
        pseudo_random_generator=pseudo_random_generator,
    )
Пример #28
0
def test_regression_mediator_not_update_payer_state_twice():
    """ Regression Test for https://github.com/raiden-network/raiden/issues/3086
    Make sure that after a lock expired the mediator doesn't update the pair
    twice causing EventUnlockClaimFailed to be generated at every block.
    """
    amount = 10
    block_number = 5
    initiator = HOP1
    initiator_key = HOP1_KEY
    mediator_address = HOP2
    target = HOP3
    expiration = 30
    pseudo_random_generator = random.Random()

    payer_channel = factories.make_channel(
        partner_balance=amount,
        our_balance=amount,
        our_address=mediator_address,
        partner_address=initiator,
        token_address=UNIT_TOKEN_ADDRESS,
    )
    payer_route = factories.route_from_channel(payer_channel)

    payer_transfer = factories.make_signed_transfer_for(
        channel_state=payer_channel,
        amount=amount,
        initiator=initiator,
        target=target,
        expiration=expiration,
        secret=UNIT_SECRET,
        sender=initiator,
        pkey=initiator_key,
    )

    payee_channel = factories.make_channel(
        our_balance=amount,
        our_address=mediator_address,
        partner_address=target,
        token_address=UNIT_TOKEN_ADDRESS,
    )
    available_routes = [factories.route_from_channel(payee_channel)]
    channel_map = {
        payee_channel.identifier: payee_channel,
        payer_channel.identifier: payer_channel,
    }

    init_state_change = ActionInitMediator(
        routes=available_routes,
        from_route=payer_route,
        from_transfer=payer_transfer,
    )
    initial_state = None
    iteration = mediator.state_transition(
        mediator_state=initial_state,
        state_change=init_state_change,
        channelidentifiers_to_channels=channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_number,
    )
    assert iteration.new_state is not None

    current_state = iteration.new_state
    send_transfer = must_contain_entry(iteration.events, SendLockedTransfer,
                                       {})
    assert send_transfer

    transfer = send_transfer.transfer
    block_expiration_number = transfer.lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2

    block = Block(
        block_number=block_expiration_number,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    iteration = mediator.state_transition(
        mediator_state=current_state,
        state_change=block,
        channelidentifiers_to_channels=channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_expiration_number,
    )

    msg = 'At the expiration block we should get an EventUnlockClaimFailed'
    assert must_contain_entry(iteration.events, EventUnlockClaimFailed,
                              {}), msg

    current_state = iteration.new_state
    next_block = Block(
        block_number=block_expiration_number + 1,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )

    # Initiator receives the secret reveal after the lock expired
    receive_secret = ReceiveSecretReveal(
        secret=UNIT_SECRET,
        sender=payee_channel.partner_state.address,
    )
    iteration = mediator.state_transition(
        mediator_state=current_state,
        state_change=receive_secret,
        channelidentifiers_to_channels=channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=next_block.block_number,
    )
    current_state = iteration.new_state
    lock = payer_transfer.lock
    secrethash = lock.secrethash
    assert secrethash in payer_channel.partner_state.secrethashes_to_lockedlocks
    assert current_state.transfers_pair[0].payee_state == 'payee_expired'
    assert not channel.is_secret_known(payer_channel.partner_state, secrethash)

    safe_to_wait, _ = mediator.is_safe_to_wait(
        lock_expiration=lock.expiration,
        reveal_timeout=payer_channel.reveal_timeout,
        block_number=lock.expiration + 10,
    )

    assert not safe_to_wait

    iteration = mediator.state_transition(
        mediator_state=current_state,
        state_change=next_block,
        channelidentifiers_to_channels=channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=block_expiration_number,
    )
    msg = 'At the next block we should not get the same event'
    assert not must_contain_entry(iteration.events, EventUnlockClaimFailed,
                                  {}), msg
def test_regression_mediator_task_no_routes():
    """ The mediator must only be cleared after the waiting transfer's lock has
    been handled.

    If a node receives a transfer to mediate, but there is no route available
    (because there is no sufficient capacity or the partner nodes are offline),
    and a refund is not possible, the mediator task must not be cleared,
    otherwise followup remove expired lock messages wont be processed and the
    nodes will get out of sync.
    """

    amount = 10
    block_number = 5
    target = HOP2
    expiration = 30
    pseudo_random_generator = random.Random()

    payer_channel = factories.make_channel(
        partner_balance=amount,
        partner_address=HOP2,
        token_address=UNIT_TOKEN_ADDRESS,
    )
    payer_route = factories.route_from_channel(payer_channel)

    payer_transfer = factories.make_signed_transfer_for(
        payer_channel,
        amount,
        HOP1,
        target,
        expiration,
        UNIT_SECRET,
        pkey=HOP2_KEY,
        sender=HOP2,
    )

    available_routes = []
    channel_map = {
        payer_channel.identifier: payer_channel,
    }

    init_state_change = ActionInitMediator(
        available_routes,
        payer_route,
        payer_transfer,
    )
    initial_state = None
    init_iteration = mediator.state_transition(
        initial_state,
        init_state_change,
        channel_map,
        pseudo_random_generator,
        block_number,
    )
    msg = 'The task must not be cleared, even if there is no route to forward the transfer'
    assert init_iteration.new_state is not None, msg
    assert init_iteration.new_state.waiting_transfer.transfer == payer_transfer
    assert must_contain_entry(init_iteration.events, SendLockedTransfer,
                              {}) is None
    assert must_contain_entry(init_iteration.events, SendRefundTransfer,
                              {}) is None

    secrethash = UNIT_SECRETHASH
    lock = payer_channel.partner_state.secrethashes_to_lockedlocks[secrethash]

    # Creates a transfer as it was from the *partner*
    send_lock_expired, _ = channel.create_sendexpiredlock(
        sender_end_state=payer_channel.partner_state,
        locked_lock=lock,
        pseudo_random_generator=pseudo_random_generator,
        chain_id=payer_channel.chain_id,
        token_network_identifier=payer_channel.token_network_identifier,
        channel_identifier=payer_channel.identifier,
        recipient=payer_channel.our_state.address,
    )
    assert send_lock_expired
    lock_expired_message = message_from_sendevent(send_lock_expired, HOP1)
    lock_expired_message.sign(HOP2_KEY)
    balance_proof = balanceproof_from_envelope(lock_expired_message)

    message_identifier = message_identifier_from_prng(pseudo_random_generator)
    expired_block_number = lock.expiration + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS * 2

    # Regression: The mediator must still be able to process the block which
    # expires the lock
    expire_block_iteration = mediator.state_transition(
        init_iteration.new_state,
        Block(
            block_number=expired_block_number,
            gas_limit=0,
            block_hash=None,
        ),
        channel_map,
        pseudo_random_generator,
        expired_block_number,
    )
    assert expire_block_iteration.new_state is not None

    receive_expired_iteration = mediator.state_transition(
        expire_block_iteration.new_state,
        ReceiveLockExpired(
            sender=payer_channel.partner_state.address,
            balance_proof=balance_proof,
            secrethash=secrethash,
            message_identifier=message_identifier,
        ),
        channel_map,
        pseudo_random_generator,
        expired_block_number,
    )

    msg = 'The only used channel had the lock cleared, the task must be cleared'
    assert receive_expired_iteration.new_state is None, msg
    assert secrethash not in payer_channel.partner_state.secrethashes_to_lockedlocks
def test_regression_onchain_secret_reveal_must_update_channel_state():
    """ If a secret is learned off-chain and then on-chain, the state of the
    lock must be updated in the channel.
    """
    pseudo_random_generator = random.Random()

    setup = factories.make_transfers_pair(2, block_number=10)

    mediator_state = MediatorTransferState(UNIT_SECRETHASH)
    mediator_state.transfers_pair = setup.transfers_pair

    secret = UNIT_SECRET
    secrethash = UNIT_SECRETHASH
    payer_channel = mediator.get_payer_channel(setup.channel_map, setup.transfers_pair[0])
    payee_channel = mediator.get_payee_channel(setup.channel_map, setup.transfers_pair[0])
    lock = payer_channel.partner_state.secrethashes_to_lockedlocks[secrethash]

    mediator.state_transition(
        mediator_state=mediator_state,
        state_change=ReceiveSecretReveal(secret, payee_channel.partner_state.address),
        channelidentifiers_to_channels=setup.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=setup.block_number,
    )
    assert secrethash in payer_channel.partner_state.secrethashes_to_unlockedlocks

    secret_registry_address = factories.make_address()
    transaction_hash = factories.make_address()
    mediator.state_transition(
        mediator_state=mediator_state,
        state_change=ContractReceiveSecretReveal(
            transaction_hash,
            secret_registry_address,
            secrethash,
            secret,
            setup.block_number,
        ),
        channelidentifiers_to_channels=setup.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=setup.block_number,
    )
    assert secrethash in payer_channel.partner_state.secrethashes_to_onchain_unlockedlocks

    # Creates a transfer as it was from the *partner*
    send_lock_expired, _ = channel.create_sendexpiredlock(
        sender_end_state=payer_channel.partner_state,
        locked_lock=lock,
        pseudo_random_generator=pseudo_random_generator,
        chain_id=payer_channel.chain_id,
        token_network_identifier=payer_channel.token_network_identifier,
        channel_identifier=payer_channel.identifier,
        recipient=payer_channel.our_state.address,
    )
    assert send_lock_expired
    expired_message = message_from_sendevent(send_lock_expired, setup.channels.our_address(0))
    expired_message.sign(setup.channels.partner_privatekeys[0])
    balance_proof = balanceproof_from_envelope(expired_message)

    message_identifier = message_identifier_from_prng(pseudo_random_generator)
    expired_block_number = channel.get_sender_expiration_threshold(lock)
    mediator.state_transition(
        mediator_state=mediator_state,
        state_change=ReceiveLockExpired(
            balance_proof=balance_proof,
            secrethash=secrethash,
            message_identifier=message_identifier,
        ),
        channelidentifiers_to_channels=setup.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=expired_block_number,
    )
    assert secrethash in payer_channel.partner_state.secrethashes_to_onchain_unlockedlocks