def test_regression_send_refund():
    """Regression test for discarded refund transfer.

    The handle_refundtransfer used to discard events from the channel state
    machine, which led to the state being updated but the message to the
    partner was never sent.

    Also, for issue: https://github.com/raiden-network/raiden/issues/3170
    It was noticed that when receiving the same refund transfer twice, the mediator
    would detect an invalid refund and clear the mediator state. So the test also
    checks that mediator rejects the duplicate transfer and keeps the mediator
    state unchanged.
    """
    pseudo_random_generator = random.Random()
    setup = factories.make_transfers_pair(3)

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

    last_pair = setup.transfers_pair[-1]
    channel_identifier = last_pair.payee_transfer.balance_proof.channel_identifier
    lock_expiration = last_pair.payee_transfer.lock.expiration

    received_transfer = factories.make_signed_transfer_state(
        amount=UNIT_TRANSFER_AMOUNT,
        initiator=UNIT_TRANSFER_INITIATOR,
        target=UNIT_TRANSFER_TARGET,
        expiration=lock_expiration,
        secret=UNIT_SECRET,
        payment_identifier=UNIT_TRANSFER_IDENTIFIER,
        channel_identifier=channel_identifier,
        pkey=setup.channels.partner_privatekeys[2],
        sender=setup.channels.partner_address(2),
    )

    # All three channels have been used
    routes = []

    refund_state_change = ReceiveTransferRefund(
        transfer=received_transfer,
        routes=routes,
    )

    iteration = mediator.handle_refundtransfer(
        mediator_state=mediator_state,
        mediator_state_change=refund_state_change,
        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,
    )

    first_pair = setup.transfers_pair[0]
    first_payer_transfer = first_pair.payer_transfer
    payer_channel = mediator.get_payer_channel(setup.channel_map, first_pair)
    lock = channel.get_lock(
        end_state=payer_channel.partner_state,
        secrethash=UNIT_SECRETHASH,
    )
    token_network_identifier = first_payer_transfer.balance_proof.token_network_identifier
    assert search_for_item(
        iteration.events, SendRefundTransfer, {
            'recipient': setup.channels.partner_address(0),
            'queue_identifier': {
                'recipient':
                setup.channels.partner_address(0),
                'channel_identifier':
                first_payer_transfer.balance_proof.channel_identifier,
            },
            'transfer': {
                'payment_identifier': UNIT_TRANSFER_IDENTIFIER,
                'token': UNIT_TOKEN_ADDRESS,
                'balance_proof': {
                    'transferred_amount': 0,
                    'locked_amount': 10,
                    'locksroot': lock.lockhash,
                    'token_network_identifier': token_network_identifier,
                    'channel_identifier':
                    first_payer_transfer.balance_proof.channel_identifier,
                    'chain_id': first_payer_transfer.balance_proof.chain_id,
                },
                'lock': {
                    'amount': lock.amount,
                    'expiration': lock.expiration,
                    'secrethash': lock.secrethash,
                },
                'initiator': UNIT_TRANSFER_INITIATOR,
                'target': UNIT_TRANSFER_TARGET,
            },
        })

    duplicate_iteration = mediator.handle_refundtransfer(
        mediator_state=iteration.new_state,
        mediator_state_change=refund_state_change,
        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,
    )

    assert search_for_item(duplicate_iteration.events, SendRefundTransfer,
                           {}) is None

    assert duplicate_iteration.new_state is not None
    assert duplicate_iteration.new_state == iteration.new_state
Esempio n. 2
0
def test_regression_send_refund():
    """Regression test for discarded refund transfer.

    The handle_refundtransfer used to discard events from the channel state
    machine, which led to the state being updated but the message to the
    partner was never sent.
    """
    pseudo_random_generator = random.Random()
    setup = factories.make_transfers_pair(3)

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

    last_pair = setup.transfers_pair[-1]
    channel_identifier = last_pair.payee_transfer.balance_proof.channel_identifier
    lock_expiration = last_pair.payee_transfer.lock.expiration

    received_transfer = factories.make_signed_transfer(
        amount=UNIT_TRANSFER_AMOUNT,
        initiator=UNIT_TRANSFER_INITIATOR,
        target=UNIT_TRANSFER_TARGET,
        expiration=lock_expiration,
        secret=UNIT_SECRET,
        payment_identifier=UNIT_TRANSFER_IDENTIFIER,
        channel_identifier=channel_identifier,
        pkey=setup.channels.partner_privatekeys[2],
        sender=setup.channels.partner_address(2),
    )

    # All three channels have been used
    routes = []

    refund_state_change = ReceiveTransferRefund(
        transfer=received_transfer,
        routes=routes,
    )

    iteration = mediator.handle_refundtransfer(
        mediator_state=mediator_state,
        mediator_state_change=refund_state_change,
        channelidentifiers_to_channels=setup.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=setup.block_number,
    )

    first_pair = setup.transfers_pair[0]
    first_payer_transfer = first_pair.payer_transfer
    payer_channel = mediator.get_payer_channel(setup.channel_map, first_pair)
    lock = channel.get_lock(
        end_state=payer_channel.partner_state,
        secrethash=UNIT_SECRETHASH,
    )
    token_network_identifier = first_payer_transfer.balance_proof.token_network_identifier
    assert must_contain_entry(
        iteration.events, SendRefundTransfer, {
            'recipient': setup.channels.partner_address(0),
            'queue_identifier': {
                'recipient':
                setup.channels.partner_address(0),
                'channel_identifier':
                first_payer_transfer.balance_proof.channel_identifier,
            },
            'transfer': {
                'payment_identifier': UNIT_TRANSFER_IDENTIFIER,
                'token': UNIT_TOKEN_ADDRESS,
                'balance_proof': {
                    'transferred_amount': 0,
                    'locked_amount': 10,
                    'locksroot': lock.lockhash,
                    'token_network_identifier': token_network_identifier,
                    'channel_identifier':
                    first_payer_transfer.balance_proof.channel_identifier,
                    'chain_id': first_payer_transfer.balance_proof.chain_id,
                },
                'lock': {
                    'amount': lock.amount,
                    'expiration': lock.expiration,
                    'secrethash': lock.secrethash,
                },
                'initiator': UNIT_TRANSFER_INITIATOR,
                'target': UNIT_TRANSFER_TARGET,
            },
        })
def test_regression_send_refund():
    """Regression test for discarded refund transfer.

    The handle_refundtransfer used to discard events from the channel state
    machine, which led to the state being updated but the message to the
    partner was never sent.

    Also, for issue: https://github.com/raiden-network/raiden/issues/3170
    It was noticed that when receiving the same refund transfer twice, the mediator
    would detect an invalid refund and clear the mediator state. So the test also
    checks that mediator rejects the duplicate transfer and keeps the mediator
    state unchanged.
    """
    pseudo_random_generator = random.Random()
    setup = factories.make_transfers_pair(3)

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

    last_pair = setup.transfers_pair[-1]
    channel_identifier = last_pair.payee_transfer.balance_proof.channel_identifier
    lock_expiration = last_pair.payee_transfer.lock.expiration

    received_transfer = factories.make_signed_transfer(
        amount=UNIT_TRANSFER_AMOUNT,
        initiator=UNIT_TRANSFER_INITIATOR,
        target=UNIT_TRANSFER_TARGET,
        expiration=lock_expiration,
        secret=UNIT_SECRET,
        payment_identifier=UNIT_TRANSFER_IDENTIFIER,
        channel_identifier=channel_identifier,
        pkey=setup.channels.partner_privatekeys[2],
        sender=setup.channels.partner_address(2),
    )

    # All three channels have been used
    routes = []

    refund_state_change = ReceiveTransferRefund(
        transfer=received_transfer,
        routes=routes,
    )

    iteration = mediator.handle_refundtransfer(
        mediator_state=mediator_state,
        mediator_state_change=refund_state_change,
        channelidentifiers_to_channels=setup.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=setup.block_number,
    )

    first_pair = setup.transfers_pair[0]
    first_payer_transfer = first_pair.payer_transfer
    payer_channel = mediator.get_payer_channel(setup.channel_map, first_pair)
    lock = channel.get_lock(
        end_state=payer_channel.partner_state,
        secrethash=UNIT_SECRETHASH,
    )
    token_network_identifier = first_payer_transfer.balance_proof.token_network_identifier
    assert must_contain_entry(iteration.events, SendRefundTransfer, {
        'recipient': setup.channels.partner_address(0),
        'queue_identifier': {
            'recipient': setup.channels.partner_address(0),
            'channel_identifier': first_payer_transfer.balance_proof.channel_identifier,
        },
        'transfer': {
            'payment_identifier': UNIT_TRANSFER_IDENTIFIER,
            'token': UNIT_TOKEN_ADDRESS,
            'balance_proof': {
                'transferred_amount': 0,
                'locked_amount': 10,
                'locksroot': lock.lockhash,
                'token_network_identifier': token_network_identifier,
                'channel_identifier': first_payer_transfer.balance_proof.channel_identifier,
                'chain_id': first_payer_transfer.balance_proof.chain_id,
            },
            'lock': {
                'amount': lock.amount,
                'expiration': lock.expiration,
                'secrethash': lock.secrethash,
            },
            'initiator': UNIT_TRANSFER_INITIATOR,
            'target': UNIT_TRANSFER_TARGET,
        },
    })

    duplicate_iteration = mediator.handle_refundtransfer(
        mediator_state=iteration.new_state,
        mediator_state_change=refund_state_change,
        channelidentifiers_to_channels=setup.channel_map,
        pseudo_random_generator=pseudo_random_generator,
        block_number=setup.block_number,
    )

    assert must_contain_entry(duplicate_iteration.events, SendRefundTransfer, {}) is None

    assert duplicate_iteration.new_state is not None
    assert duplicate_iteration.new_state == iteration.new_state
Esempio n. 4
0
def test_mediator_skips_used_routes():
    prng = random.Random()
    block_number = 3
    defaults = factories.NettingChannelStateProperties(
        our_state=factories.NettingChannelEndStateProperties.OUR_STATE,
        partner_state=factories.NettingChannelEndStateProperties(
            balance=UNIT_TRANSFER_AMOUNT),
        open_transaction=factories.TransactionExecutionStatusProperties(
            started_block_number=1, finished_block_number=2, result="success"),
    )
    properties = [
        factories.NettingChannelStateProperties(
            partner_state=factories.NettingChannelEndStateProperties(
                privatekey=factories.HOP1_KEY, address=factories.HOP1)),
        factories.NettingChannelStateProperties(
            partner_state=factories.NettingChannelEndStateProperties(
                privatekey=factories.HOP2_KEY, address=factories.HOP2)),
        factories.NettingChannelStateProperties(
            partner_state=factories.NettingChannelEndStateProperties(
                privatekey=factories.HOP3_KEY, address=factories.HOP3)),
    ]
    channels = factories.make_channel_set(properties=properties,
                                          number_of_channels=3,
                                          defaults=defaults)
    bob = channels.channels[1].partner_state.address
    charlie = channels.channels[2].partner_state.address
    dave = factories.make_address()
    eric = factories.make_address()
    locked_transfer = factories.create(
        factories.LockedTransferSignedStateProperties(
            expiration=10,
            routes=[
                [
                    factories.UNIT_OUR_ADDRESS, bob, dave,
                    factories.UNIT_TRANSFER_TARGET
                ],
                [
                    factories.UNIT_OUR_ADDRESS, bob, eric,
                    factories.UNIT_TRANSFER_TARGET
                ],
                [
                    factories.UNIT_OUR_ADDRESS, charlie, eric,
                    factories.UNIT_TRANSFER_TARGET
                ],
            ],
            canonical_identifier=channels.channels[0].canonical_identifier,
            pkey=factories.HOP1_KEY,
            sender=factories.HOP1,
        ))
    init_action = factories.mediator_make_init_action(channels=channels,
                                                      transfer=locked_transfer)
    nodeaddresses_to_networkstates = {
        channel.partner_state.address: NetworkState.REACHABLE
        for channel in channels.channels
    }

    transition_result = mediator.handle_init(
        state_change=init_action,
        channelidentifiers_to_channels=channels.channel_map,
        nodeaddresses_to_networkstates=nodeaddresses_to_networkstates,
        pseudo_random_generator=prng,
        block_number=block_number,
    )
    mediator_state = transition_result.new_state
    events = transition_result.events
    assert mediator_state is not None
    assert events

    assert len(mediator_state.routes) == 3
    assert mediator_state.routes[0].route[1] == bob
    assert mediator_state.routes[1].route[1] == bob
    assert mediator_state.routes[2].route[1] == charlie
    # now we receive a refund from whoever we forwarded to (should be HOP2)
    assert isinstance(events[-1], SendLockedTransfer)
    assert events[-1].recipient == factories.HOP2

    last_pair = mediator_state.transfers_pair[-1]
    canonical_identifier = last_pair.payee_transfer.balance_proof.canonical_identifier
    lock_expiration = last_pair.payee_transfer.lock.expiration
    payment_identifier = last_pair.payee_transfer.payment_identifier

    received_transfer = factories.create(
        factories.LockedTransferSignedStateProperties(
            expiration=lock_expiration,
            payment_identifier=payment_identifier,
            canonical_identifier=canonical_identifier,
            sender=factories.HOP2,
            pkey=factories.HOP2_KEY,
            message_identifier=factories.make_message_identifier(),
        ))

    refund_state_change = ReceiveTransferRefund(
        transfer=received_transfer,
        balance_proof=received_transfer.balance_proof,
        sender=received_transfer.balance_proof.sender,  # pylint: disable=no-member
    )
    transition_result = mediator.handle_refundtransfer(
        mediator_state=mediator_state,
        mediator_state_change=refund_state_change,
        channelidentifiers_to_channels=channels.channel_map,
        nodeaddresses_to_networkstates=nodeaddresses_to_networkstates,
        pseudo_random_generator=prng,
        block_number=block_number,
    )

    mediator_state = transition_result.new_state
    events = transition_result.events
    assert mediator_state is not None
    assert events
    assert mediator_state.transfers_pair[-1].payee_address == charlie

    # now we should have a forward transfer to HOP3
    assert isinstance(events[-1], SendLockedTransfer)
    assert events[-1].recipient == factories.HOP3

    # now we will receive a refund from HOP3

    last_pair = mediator_state.transfers_pair[-1]
    canonical_identifier = last_pair.payee_transfer.balance_proof.canonical_identifier
    lock_expiration = last_pair.payee_transfer.lock.expiration
    payment_identifier = last_pair.payee_transfer.payment_identifier

    received_transfer = factories.create(
        factories.LockedTransferSignedStateProperties(
            expiration=lock_expiration,
            payment_identifier=payment_identifier,
            canonical_identifier=canonical_identifier,
            sender=factories.HOP3,
            pkey=factories.HOP3_KEY,
            message_identifier=factories.make_message_identifier(),
        ))

    refund_state_change = ReceiveTransferRefund(
        transfer=received_transfer,
        balance_proof=received_transfer.balance_proof,
        sender=received_transfer.balance_proof.sender,  # pylint: disable=no-member
    )

    transition_result = mediator.handle_refundtransfer(
        mediator_state=mediator_state,
        mediator_state_change=refund_state_change,
        channelidentifiers_to_channels=channels.channel_map,
        nodeaddresses_to_networkstates=nodeaddresses_to_networkstates,
        pseudo_random_generator=prng,
        block_number=block_number,
    )

    mediator_state = transition_result.new_state
    events = transition_result.events
    assert mediator_state is not None
    assert events

    # no other routes available, so refund HOP1
    assert isinstance(events[-1], SendRefundTransfer)
    assert events[-1].recipient == factories.HOP1
def test_regression_send_refund():
    """Regression test for discarded refund transfer.

    The handle_refundtransfer used to discard events from the channel state
    machine, which led to the state being updated but the message to the
    partner was never sent.

    Also, for issue: https://github.com/raiden-network/raiden/issues/3170
    It was noticed that when receiving the same refund transfer twice, the mediator
    would detect an invalid refund and clear the mediator state. So the test also
    checks that mediator rejects the duplicate transfer and keeps the mediator
    state unchanged.
    """
    pseudo_random_generator = random.Random()
    setup = factories.make_transfers_pair(3)

    mediator_state = MediatorTransferState(secrethash=UNIT_SECRETHASH,
                                           routes=[])
    mediator_state.transfers_pair = setup.transfers_pair

    last_pair = setup.transfers_pair[-1]
    canonical_identifier = last_pair.payee_transfer.balance_proof.canonical_identifier
    lock_expiration = last_pair.payee_transfer.lock.expiration

    received_transfer = factories.create(
        factories.LockedTransferSignedStateProperties(
            expiration=lock_expiration,
            payment_identifier=UNIT_TRANSFER_IDENTIFIER,
            canonical_identifier=canonical_identifier,
            sender=setup.channels.partner_address(2),
            pkey=setup.channels.partner_privatekeys[2],
            message_identifier=factories.make_message_identifier(),
        ))

    # All three channels have been used
    refund_state_change = ReceiveTransferRefund(
        transfer=received_transfer,
        balance_proof=received_transfer.balance_proof,
        sender=received_transfer.balance_proof.sender,  # pylint: disable=no-member
    )

    iteration = mediator.handle_refundtransfer(
        mediator_state=mediator_state,
        mediator_state_change=refund_state_change,
        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,
    )

    first_pair = setup.transfers_pair[0]
    first_payer_transfer = first_pair.payer_transfer
    payer_channel = mediator.get_payer_channel(setup.channel_map, first_pair)
    lock = channel.get_lock(end_state=payer_channel.partner_state,
                            secrethash=UNIT_SECRETHASH)
    token_network_address = first_payer_transfer.balance_proof.token_network_address
    assert search_for_item(
        iteration.events,
        SendRefundTransfer,
        {
            "recipient": setup.channels.partner_address(0),
            "queue_identifier": {
                "recipient": setup.channels.partner_address(0),
                "canonical_identifier": {
                    "chain_identifier":
                    first_payer_transfer.balance_proof.chain_id,
                    "token_network_address":
                    token_network_address,
                    "channel_identifier":
                    first_payer_transfer.balance_proof.channel_identifier,
                },
            },
            "transfer": {
                "payment_identifier": UNIT_TRANSFER_IDENTIFIER,
                "token": UNIT_TOKEN_ADDRESS,
                "balance_proof": {
                    "transferred_amount": 0,
                    "locked_amount": UNIT_TRANSFER_AMOUNT,
                    "locksroot": keccak(lock.encoded),
                    "token_network_address": token_network_address,
                    "channel_identifier":
                    first_payer_transfer.balance_proof.channel_identifier,
                    "chain_id": first_payer_transfer.balance_proof.chain_id,
                },
                "lock": {
                    "amount": lock.amount,
                    "expiration": lock.expiration,
                    "secrethash": lock.secrethash,
                },
                "initiator": UNIT_TRANSFER_INITIATOR,
                "target": UNIT_TRANSFER_TARGET,
            },
        },
    )

    duplicate_iteration = mediator.handle_refundtransfer(
        mediator_state=iteration.new_state,
        mediator_state_change=refund_state_change,
        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,
    )

    assert search_for_item(duplicate_iteration.events, SendRefundTransfer,
                           {}) is None

    assert duplicate_iteration.new_state is not None
    assert duplicate_iteration.new_state == iteration.new_state