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
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
Example #3
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,
            },
        })
Example #4
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
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
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
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