Example #1
0
def test_refund_transfer_matches_received():
    amount = 30
    expiration = 50

    transfer = factories.make_transfer(
        amount,
        UNIT_TRANSFER_INITIATOR,
        UNIT_TRANSFER_TARGET,
        expiration,
        UNIT_SECRET,
    )

    refund_lower_expiration = factories.make_signed_transfer(
        amount,
        UNIT_TRANSFER_INITIATOR,
        UNIT_TRANSFER_TARGET,
        expiration - 1,
        UNIT_SECRET,
    )

    assert channel.refund_transfer_matches_received(refund_lower_expiration, transfer) is True

    refund_same_expiration = factories.make_signed_transfer(
        amount,
        UNIT_TRANSFER_INITIATOR,
        UNIT_TRANSFER_TARGET,
        expiration,
        UNIT_SECRET,
    )
    assert channel.refund_transfer_matches_received(refund_same_expiration, transfer) is False
Example #2
0
def make_signed_transfer_from_counter(counter):
    lock = Lock(
        amount=next(counter),
        expiration=next(counter),
        secrethash=sha3(factories.make_secret(next(counter))),
    )

    signed_transfer = factories.make_signed_transfer(
        amount=next(counter),
        initiator=factories.make_address(),
        target=factories.make_address(),
        expiration=next(counter),
        secret=factories.make_secret(next(counter)),
        payment_identifier=next(counter),
        message_identifier=next(counter),
        nonce=next(counter),
        transferred_amount=next(counter),
        locked_amount=next(counter),
        locksroot=sha3(lock.as_bytes),
        recipient=factories.make_address(),
        channel_identifier=next(counter),
        token_network_address=factories.make_address(),
        token=factories.make_address(),
        pkey=factories.HOP1_KEY,
        sender=factories.HOP1,
    )

    return signed_transfer
Example #3
0
def test_refund_transfer_no_more_routes():
    amount = UNIT_TRANSFER_AMOUNT
    block_number = 1
    refund_pkey, refund_address = factories.make_privkey_address()

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

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

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

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

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

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

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

    assert unlocked_failed
    assert sent_failed
Example #4
0
def make_signed_transfer_from_counter(counter):
    lock = Lock(
        amount=next(counter),
        expiration=next(counter),
        secrethash=sha3(factories.make_secret(next(counter))),
    )

    signed_transfer = factories.make_signed_transfer(
        amount=next(counter),
        initiator=factories.make_address(),
        target=factories.make_address(),
        expiration=next(counter),
        secret=factories.make_secret(next(counter)),
        payment_identifier=next(counter),
        message_identifier=next(counter),
        nonce=next(counter),
        transferred_amount=next(counter),
        locked_amount=next(counter),
        locksroot=sha3(lock.as_bytes),
        recipient=factories.make_address(),
        channel_identifier=next(counter),
        token_network_address=factories.make_address(),
        token=factories.make_address(),
        pkey=factories.HOP1_KEY,
        sender=factories.HOP1,
    )

    return signed_transfer
def test_locked_transfer_secret_registered_onchain(
        raiden_network,
        token_addresses,
        secret_registry_address,
):
    app0 = raiden_network[0]
    token_address = token_addresses[0]
    chain_state = views.state_from_app(app0)
    payment_network_id = app0.raiden.default_registry.address
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        chain_state,
        payment_network_id,
        token_address,
    )

    amount = 1
    target = UNIT_TRANSFER_INITIATOR
    identifier = 1
    transfer_secret = sha3(target + b'1')

    secret_registry_proxy = app0.raiden.chain.secret_registry(
        secret_registry_address,
    )
    secret_registry_proxy.register_secret(transfer_secret)

    # Test that sending a transfer with a secret already registered on-chain fails
    with pytest.raises(RaidenUnrecoverableError):
        app0.raiden.start_mediated_transfer_with_secret(
            token_network_identifier,
            amount,
            target,
            identifier,
            transfer_secret,
        )

    expiration = 9999
    transfer = make_signed_transfer(
        amount,
        UNIT_TRANSFER_INITIATOR,
        app0.raiden.address,
        expiration,
        transfer_secret,
    )

    message_handler = MessageHandler()
    message_handler.handle_message_lockedtransfer(
        app0.raiden,
        transfer,
    )

    state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier(0, 'latest')
    transfer_statechange_dispatched = (
        must_contain_entry(state_changes, ActionInitMediator, {}) or
        must_contain_entry(state_changes, ActionInitTarget, {})
    )
    assert not transfer_statechange_dispatched
def test_locked_transfer_secret_registered_onchain(
        raiden_network,
        token_addresses,
        secret_registry_address,
):
    app0 = raiden_network[0]
    token_address = token_addresses[0]
    chain_state = views.state_from_app(app0)
    payment_network_id = app0.raiden.default_registry.address
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        chain_state,
        payment_network_id,
        token_address,
    )

    amount = 1
    target = UNIT_TRANSFER_INITIATOR
    identifier = 1
    transfer_secret = sha3(target + b'1')

    secret_registry_proxy = app0.raiden.chain.secret_registry(
        secret_registry_address,
    )
    secret_registry_proxy.register_secret(transfer_secret)

    # Test that sending a transfer with a secret already registered on-chain fails
    with pytest.raises(RaidenUnrecoverableError):
        app0.raiden.start_mediated_transfer_with_secret(
            token_network_identifier,
            amount,
            target,
            identifier,
            transfer_secret,
        )

    expiration = 9999
    transfer = make_signed_transfer(
        amount,
        UNIT_TRANSFER_INITIATOR,
        app0.raiden.address,
        expiration,
        transfer_secret,
    )

    message_handler = MessageHandler()
    message_handler.handle_message_lockedtransfer(
        app0.raiden,
        transfer,
    )

    state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier(0, 'latest')
    transfer_statechange_dispatched = (
        must_contain_entry(state_changes, ActionInitMediator, {}) or
        must_contain_entry(state_changes, ActionInitTarget, {})
    )
    assert not transfer_statechange_dispatched
Example #7
0
def test_refund_transfer_invalid_sender():
    amount = UNIT_TRANSFER_AMOUNT
    block_number = 1
    pseudo_random_generator = random.Random()

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

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

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

    expiration = original_transfer.lock.expiration - channel_state.reveal_timeout - TRANSIT_BLOCKS
    refund_transfer = factories.make_signed_transfer(
        amount,
        original_transfer.initiator,
        original_transfer.target,
        expiration,
        UNIT_SECRET,
    )

    wrong_sender_address = factories.HOP3
    state_change = ReceiveTransferRefundCancelRoute(
        sender=wrong_sender_address,
        routes=available_routes,
        transfer=refund_transfer,
        secret=random_secret(),
    )

    before_state = deepcopy(current_state)
    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        channelmap,
        pseudo_random_generator,
        block_number,
    )
    assert iteration.new_state is not None
    assert not iteration.events
    assert iteration.new_state == before_state
Example #8
0
def run_test_mediated_transfer_calls_pfs(raiden_network, token_addresses):
    app0, = raiden_network
    token_address = token_addresses[0]
    chain_state = views.state_from_app(app0)
    payment_network_id = app0.raiden.default_registry.address
    token_network_id = views.get_token_network_identifier_by_token_address(
        chain_state,
        payment_network_id,
        token_address,
    )

    with patch('raiden.routing.query_paths', return_value=[]) as patched:

        app0.raiden.start_mediated_transfer_with_secret(
            token_network_identifier=token_network_id,
            amount=10,
            fee=0,
            target=factories.HOP1,
            identifier=1,
            secret=b'1' * 32,
        )
        assert not patched.called

        config_patch = dict(
            pathfinding_service_address='mock-address',
            pathfinding_eth_address=factories.make_checksum_address(),
        )

        with patch.dict(app0.raiden.config['services'], config_patch):
            app0.raiden.start_mediated_transfer_with_secret(
                token_network_identifier=token_network_id,
                amount=11,
                fee=0,
                target=factories.HOP2,
                identifier=2,
                secret=b'2' * 32,
            )
            assert patched.call_count == 1

            locked_transfer = factories.make_signed_transfer(
                amount=5,
                initiator=factories.HOP1,
                target=factories.HOP2,
                sender=factories.HOP1,
                pkey=factories.HOP1_KEY,
                token_network_address=token_network_id,
                token=token_address,
            )
            app0.raiden.mediate_mediated_transfer(locked_transfer)
            assert patched.call_count == 2
def test_handle_inittarget():
    """ Init transfer must send a secret request if the expiration is valid. """
    amount = 3
    block_number = 1
    initiator = factories.HOP1
    target_address = UNIT_TRANSFER_TARGET
    payment_network_identifier = factories.make_address()
    pseudo_random_generator = random.Random()

    from_channel = factories.make_channel(
        our_address=target_address,
        partner_address=UNIT_TRANSFER_SENDER,
        partner_balance=amount,
    )
    from_route = factories.route_from_channel(from_channel)

    expiration = from_channel.reveal_timeout + block_number + 1
    from_transfer = factories.make_signed_transfer(
        amount,
        initiator,
        target_address,
        expiration,
        UNIT_SECRET,
        channel_identifier=from_channel.identifier,
    )

    state_change = ActionInitTarget(
        payment_network_identifier,
        from_route,
        from_transfer,
    )

    iteration = target.handle_inittarget(
        state_change,
        from_channel,
        pseudo_random_generator,
        block_number,
    )

    events = iteration.events
    assert events
    assert isinstance(events[0], SendSecretRequest)

    assert events[0].payment_identifier == from_transfer.payment_identifier
    assert events[0].amount == from_transfer.lock.amount
    assert events[0].secrethash == from_transfer.lock.secrethash
    assert events[0].recipient == initiator
Example #10
0
def test_handle_inittarget():
    """ Init transfer must send a secret request if the expiration is valid. """
    amount = 3
    block_number = 1
    initiator = factories.HOP1
    target_address = UNIT_TRANSFER_TARGET
    pseudo_random_generator = random.Random()

    from_channel = factories.make_channel(
        our_address=target_address,
        partner_address=UNIT_TRANSFER_SENDER,
        partner_balance=amount,
    )
    from_route = factories.route_from_channel(from_channel)

    expiration = from_channel.reveal_timeout + block_number + 1
    from_transfer = factories.make_signed_transfer(
        amount,
        initiator,
        target_address,
        expiration,
        UNIT_SECRET,
        channel_identifier=from_channel.identifier,
        token_network_address=from_channel.token_network_identifier,
    )

    state_change = ActionInitTarget(
        from_route,
        from_transfer,
    )

    iteration = target.handle_inittarget(
        state_change,
        from_channel,
        pseudo_random_generator,
        block_number,
    )

    assert must_contain_entry(
        iteration.events, SendSecretRequest, {
            'payment_identifier': from_transfer.payment_identifier,
            'amount': from_transfer.lock.amount,
            'secrethash': from_transfer.lock.secrethash,
            'recipient': initiator,
        })
    assert must_contain_entry(iteration.events, SendProcessed, {})
Example #11
0
def test_handle_inittarget():
    """ Init transfer must send a secret request if the expiration is valid. """
    amount = 3
    block_number = 1
    initiator = factories.HOP1
    target_address = UNIT_TRANSFER_TARGET
    pseudo_random_generator = random.Random()

    from_channel = factories.make_channel(
        our_address=target_address,
        partner_address=UNIT_TRANSFER_SENDER,
        partner_balance=amount,
    )
    from_route = factories.route_from_channel(from_channel)

    expiration = from_channel.reveal_timeout + block_number + 1
    from_transfer = factories.make_signed_transfer(
        amount,
        initiator,
        target_address,
        expiration,
        UNIT_SECRET,
        channel_identifier=from_channel.identifier,
    )

    state_change = ActionInitTarget(
        from_route,
        from_transfer,
    )

    iteration = target.handle_inittarget(
        state_change,
        from_channel,
        pseudo_random_generator,
        block_number,
    )

    events = iteration.events
    assert events
    assert isinstance(events[0], SendSecretRequest)

    assert events[0].payment_identifier == from_transfer.payment_identifier
    assert events[0].amount == from_transfer.lock.amount
    assert events[0].secrethash == from_transfer.lock.secrethash
    assert events[0].recipient == initiator
Example #12
0
def test_refund_transfer_no_more_routes():
    amount = UNIT_TRANSFER_AMOUNT
    refund_pkey, refund_address = factories.make_privkey_address()
    setup = setup_initiator_tests(
        amount=amount,
        partner_balance=amount,
        our_address=UNIT_TRANSFER_INITIATOR,
        partner_address=refund_address,
    )

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

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

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

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

    assert unlocked_failed
    assert sent_failed
Example #13
0
def test_refund_transfer_does_not_match_received():
    amount = 30
    expiration = 50
    target = UNIT_TRANSFER_SENDER
    transfer = factories.make_transfer(
        amount,
        UNIT_TRANSFER_INITIATOR,
        target,
        expiration,
        UNIT_SECRET,
    )

    refund_from_target = factories.make_signed_transfer(
        amount,
        UNIT_TRANSFER_INITIATOR,
        UNIT_TRANSFER_TARGET,
        expiration - 1,
        UNIT_SECRET,
    )
    # target cannot refund
    assert not channel.refund_transfer_matches_received(refund_from_target, transfer)
Example #14
0
def test_refund_transfer_next_route():
    amount = UNIT_TRANSFER_AMOUNT
    our_address = factories.ADDR
    refund_pkey, refund_address = factories.make_privkey_address()
    pseudo_random_generator = random.Random()

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

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

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

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

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

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

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

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

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

    assert route_cancelled, 'The previous transfer must be cancelled'
    assert new_transfer, 'No mediated transfer event emitted, should have tried a new route'
    msg = 'the new transfer must use a new secret / secrethash'
    assert new_transfer.transfer.lock.secrethash != refund_transfer.lock.secrethash, msg
    assert iteration.new_state.initiator is not None
Example #15
0
def test_refund_transfer_no_more_routes():
    amount = UNIT_TRANSFER_AMOUNT
    refund_pkey, refund_address = factories.make_privkey_address()
    setup = setup_initiator_tests(
        amount=amount,
        partner_balance=amount,
        our_address=UNIT_TRANSFER_INITIATOR,
        partner_address=refund_address,
    )

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

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

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

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

    assert unlocked_failed
    assert sent_failed

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

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

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

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

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

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

    # process the the block after lock expiration
    current_state = iteration.new_state
    state_change = Block(
        block_number=expiry_block + 1,
        gas_limit=1,
        block_hash=factories.make_transaction_hash(),
    )
    iteration = initiator_manager.state_transition(
        current_state,
        state_change,
        setup.channel_map,
        setup.prng,
        expiry_block + 1,
    )
    assert iteration.new_state is None, 'from this point on the payment task should go'
Example #16
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 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,
        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_refund_transfer_no_more_routes():
    amount = UNIT_TRANSFER_AMOUNT
    refund_pkey, refund_address = factories.make_privkey_address()
    setup = setup_initiator_tests(
        amount=amount,
        partner_balance=amount,
        our_address=UNIT_TRANSFER_INITIATOR,
        partner_address=refund_address,
    )

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

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

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

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

    assert unlocked_failed
    assert sent_failed

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

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

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

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

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

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

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

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

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

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

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

    original_transfer = current_state.initiator.transfer

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

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

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

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

    assert route_cancelled, 'The previous transfer must be cancelled'
    assert new_transfer, 'No mediated transfer event emitted, should have tried a new route'
    msg = 'the new transfer must use a new secret / secrethash'
    assert new_transfer.transfer.lock.secrethash != refund_transfer.lock.secrethash, msg
    assert iteration.new_state.initiator is not None
Example #20
0
def run_test_locked_transfer_secret_registered_onchain(
    raiden_network,
    token_addresses,
    secret_registry_address,
    retry_timeout,
):
    app0 = raiden_network[0]
    token_address = token_addresses[0]
    chain_state = views.state_from_app(app0)
    payment_network_id = app0.raiden.default_registry.address
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        chain_state,
        payment_network_id,
        token_address,
    )

    amount = 1
    target = factories.UNIT_TRANSFER_INITIATOR
    identifier = 1
    transfer_secret = sha3(target + b'1')

    secret_registry_proxy = app0.raiden.chain.secret_registry(
        secret_registry_address, )
    secret_registry_proxy.register_secret(secret=transfer_secret,
                                          given_block_identifier='latest')

    # Wait until our node has processed the block that the secret registration was mined at
    block_number = app0.raiden.get_block_number()
    wait_for_block(
        raiden=app0.raiden,
        block_number=block_number + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS,
        retry_timeout=retry_timeout,
    )

    # Test that sending a transfer with a secret already registered on-chain fails
    with pytest.raises(RaidenUnrecoverableError):
        app0.raiden.start_mediated_transfer_with_secret(
            token_network_identifier=token_network_identifier,
            amount=amount,
            fee=0,
            target=target,
            identifier=identifier,
            secret=transfer_secret,
        )

    # Test that receiving a transfer with a secret already registered on chain fails
    expiration = 9999
    locked_transfer = factories.make_signed_transfer(
        amount,
        factories.UNIT_TRANSFER_INITIATOR,
        app0.raiden.address,
        expiration,
        transfer_secret,
    )

    message_handler = MessageHandler()
    message_handler.handle_message_lockedtransfer(
        app0.raiden,
        locked_transfer,
    )

    state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier(
        0, 'latest')
    transfer_statechange_dispatched = (
        search_for_item(state_changes, ActionInitMediator, {})
        or search_for_item(state_changes, ActionInitTarget, {}))
    assert not transfer_statechange_dispatched
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