コード例 #1
0
def make_receive_expired_lock(
    channel_state: NettingChannelState,
    privkey: bytes,
    nonce: Nonce,
    transferred_amount: TokenAmount,
    lock: HashTimeLockState,
    locked_amount: LockedAmount,
    pending_locks: PendingLocksState = None,
    chain_id: ChainID = None,
) -> ReceiveLockExpired:

    typecheck(lock, HashTimeLockState)

    signer = LocalSigner(privkey)
    address = signer.address
    if address not in (channel_state.our_state.address,
                       channel_state.partner_state.address):
        raise ValueError("Private key does not match any of the participants.")

    if pending_locks is None:
        pending_locks = make_empty_pending_locks_state()
    else:
        assert lock.encoded not in pending_locks.locks

    locksroot = compute_locksroot(pending_locks)

    chain_id = chain_id or channel_state.chain_id
    lock_expired_msg = LockExpired(
        chain_id=chain_id,
        nonce=nonce,
        message_identifier=make_message_identifier(),
        transferred_amount=transferred_amount,
        locked_amount=TokenAmount(locked_amount),
        locksroot=locksroot,
        channel_identifier=channel_state.identifier,
        token_network_address=channel_state.token_network_address,
        recipient=channel_state.partner_state.address,
        secrethash=lock.secrethash,
        signature=EMPTY_SIGNATURE,
    )
    lock_expired_msg.sign(signer)

    balance_proof = balanceproof_from_envelope(lock_expired_msg)

    receive_lockedtransfer = ReceiveLockExpired(
        balance_proof=balance_proof,
        secrethash=lock.secrethash,
        message_identifier=make_message_identifier(),
        sender=balance_proof.sender,
    )

    return receive_lockedtransfer
コード例 #2
0
def test_receive_lockedtransfer_invalidnonce(raiden_network, number_of_nodes,
                                             deposit, token_addresses,
                                             reveal_timeout, network_wait):
    app0, app1, app2 = raiden_network
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(app0), app0.raiden.default_registry.address,
        token_address)
    assert token_network_address
    channel0 = get_channelstate(app0, app1, token_network_address)

    amount = 10
    payment_identifier = PaymentID(1)
    secrethash = transfer(
        initiator_app=app0,
        target_app=app2,
        token_address=token_address,
        amount=PaymentAmount(10),
        identifier=payment_identifier,
        timeout=network_wait * number_of_nodes,
    )

    repeated_nonce = Nonce(1)
    expiration = reveal_timeout * 2
    mediated_transfer_message = LockedTransfer(
        chain_id=UNIT_CHAIN_ID,
        message_identifier=make_message_identifier(),
        payment_identifier=payment_identifier,
        nonce=repeated_nonce,
        token_network_address=token_network_address,
        token=token_address,
        channel_identifier=channel0.identifier,
        transferred_amount=TokenAmount(amount),
        locked_amount=TokenAmount(amount),
        recipient=app1.raiden.address,
        locksroot=make_locksroot(),
        lock=Lock(amount=PaymentWithFeeAmount(amount),
                  expiration=expiration,
                  secrethash=UNIT_SECRETHASH),
        target=app2.raiden.address,
        initiator=app0.raiden.address,
        signature=EMPTY_SIGNATURE,
        metadata=Metadata(routes=[
            RouteMetadata(route=[app1.raiden.address, app2.raiden.address])
        ]),
    )

    sign_and_inject(mediated_transfer_message, app0.raiden.signer, app1)

    with block_timeout_for_transfer_by_secrethash(app1.raiden, secrethash):
        wait_assert(
            assert_synced_channel_state,
            token_network_address,
            app0,
            deposit - amount,
            [],
            app1,
            deposit + amount,
            [],
        )
コード例 #3
0
def test_restore_queueids_to_queues(chain_state, netting_channel_state):
    """Test that withdraw messages are restorable if they exist in
    chain_state.queueids_to_queues.
    """
    recipient = netting_channel_state.partner_state.address

    queue_identifier = QueueIdentifier(
        recipient=recipient,
        canonical_identifier=netting_channel_state.canonical_identifier)

    msg_args = dict(
        recipient=recipient,
        canonical_identifier=netting_channel_state.canonical_identifier,
        message_identifier=factories.make_message_identifier(),
        total_withdraw=WithdrawAmount(1),
        participant=recipient,
        expiration=BlockExpiration(10),
        nonce=Nonce(15),
    )
    messages = [
        SendWithdrawRequest(**msg_args),
        SendWithdrawConfirmation(**msg_args),
        SendWithdrawExpired(**msg_args),
    ]

    chain_state.queueids_to_queues[queue_identifier] = messages

    serialized_chain_state = JSONSerializer.serialize(chain_state)

    deserialized_chain_state = JSONSerializer.deserialize(
        serialized_chain_state)

    assert chain_state == deserialized_chain_state
コード例 #4
0
def test_events_loaded_from_storage_should_deserialize(tmp_path):
    filename = f"{tmp_path}/v{RAIDEN_DB_VERSION}_log.db"
    storage = SerializedSQLiteStorage(filename, serializer=JSONSerializer())

    # Satisfy the foreign-key constraint for state change ID
    ids = storage.write_state_changes([
        ActionInitChain(
            pseudo_random_generator=random.Random(),
            block_number=1,
            block_hash=b"",
            our_address=factories.make_address(),
            chain_id=1,
        )
    ])

    canonical_identifier = factories.make_canonical_identifier()
    recipient = factories.make_address()
    participant = factories.make_address()
    event = SendWithdrawRequest(
        recipient=recipient,
        canonical_identifier=canonical_identifier,
        message_identifier=factories.make_message_identifier(),
        total_withdraw=1,
        participant=participant,
        expiration=10,
        nonce=15,
    )
    storage.write_events([(ids[0], event)])

    stored_events = storage.get_events()
    assert stored_events[0] == event
コード例 #5
0
def test_regression_revealsecret_after_secret(
        raiden_network: List[App],
        token_addresses: List[TokenAddress]) -> None:
    """ A RevealSecret message received after a Unlock message must be cleanly
    handled.
    """
    app0, app1, app2 = raiden_network
    token = token_addresses[0]
    identifier = PaymentID(1)
    token_network_registry_address = app0.raiden.default_registry.address
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(app0), token_network_registry_address, token)
    assert token_network_address, "The fixtures must register the token"

    payment_status = app0.raiden.mediated_transfer_async(
        token_network_address,
        amount=PaymentAmount(1),
        target=TargetAddress(app2.raiden.address),
        identifier=identifier,
    )
    with watch_for_unlock_failures(*raiden_network):
        assert payment_status.payment_done.wait()

    assert app1.raiden.wal, "The fixtures must start the app."
    event = raiden_events_search_for_item(app1.raiden, SendSecretReveal, {})
    assert event

    reveal_secret = RevealSecret(
        message_identifier=make_message_identifier(),
        secret=event.secret,
        signature=EMPTY_SIGNATURE,
    )
    app2.raiden.sign(reveal_secret)
    app1.raiden.on_messages([reveal_secret])
コード例 #6
0
def test_events_loaded_from_storage_should_deserialize(tmp_path):
    filename = Path(f"{tmp_path}/v{RAIDEN_DB_VERSION}_log.db")
    storage = SerializedSQLiteStorage(filename, serializer=JSONSerializer())

    # Satisfy the foreign-key constraint for state change ID
    ids = storage.write_state_changes([
        Block(
            block_number=BlockNumber(1),
            gas_limit=BlockGasLimit(1),
            block_hash=factories.make_block_hash(),
        )
    ])

    canonical_identifier = factories.make_canonical_identifier()
    recipient = factories.make_address()
    participant = factories.make_address()
    event = SendWithdrawRequest(
        recipient=recipient,
        canonical_identifier=canonical_identifier,
        message_identifier=factories.make_message_identifier(),
        total_withdraw=WithdrawAmount(1),
        participant=participant,
        expiration=BlockExpiration(10),
        nonce=Nonce(15),
    )
    storage.write_events([(ids[0], event)])

    stored_events = storage.get_events()
    assert stored_events[0] == event
コード例 #7
0
def test_regression_revealsecret_after_secret(raiden_network, token_addresses,
                                              transport_protocol):
    """ A RevealSecret message received after a Unlock message must be cleanly
    handled.
    """
    app0, app1, app2 = raiden_network
    token = token_addresses[0]

    identifier = 1
    token_network_registry_address = app0.raiden.default_registry.address
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(app0), token_network_registry_address, token)
    payment_status = app0.raiden.mediated_transfer_async(
        token_network_address,
        amount=1,
        target=app2.raiden.address,
        identifier=identifier)
    with watch_for_unlock_failures(*raiden_network):
        assert payment_status.payment_done.wait()

    event = search_for_item(app1.raiden.wal.storage.get_events(),
                            SendSecretReveal, {})
    assert event

    reveal_secret = RevealSecret(
        message_identifier=make_message_identifier(),
        secret=event.secret,
        signature=EMPTY_SIGNATURE,
    )
    app2.raiden.sign(reveal_secret)

    if transport_protocol is TransportProtocol.MATRIX:
        app1.raiden.transport._receive_message(reveal_secret)  # pylint: disable=protected-access
    else:
        raise TypeError("Unknown TransportProtocol")
コード例 #8
0
def test_subdispatch_to_paymenttask_target(chain_state, netting_channel_state):
    target_state = TargetTransferState(
        from_hop=HopState(
            node_address=netting_channel_state.partner_state.address,
            channel_identifier=netting_channel_state.canonical_identifier.
            channel_identifier,
        ),
        transfer=factories.create(
            factories.LockedTransferSignedStateProperties()),
        secret=UNIT_SECRET,
    )
    subtask = TargetTask(
        canonical_identifier=netting_channel_state.canonical_identifier,
        target_state=target_state)
    chain_state.payment_mapping.secrethashes_to_task[UNIT_SECRETHASH] = subtask

    lock = factories.HashTimeLockState(amount=0,
                                       expiration=2,
                                       secrethash=UNIT_SECRETHASH)

    netting_channel_state.partner_state.secrethashes_to_lockedlocks[
        UNIT_SECRETHASH] = lock
    netting_channel_state.partner_state.pending_locks = PendingLocksState(
        [bytes(lock.encoded)])
    state_change = Block(
        block_number=chain_state.block_number,
        gas_limit=GAS_LIMIT,
        block_hash=chain_state.block_hash,
    )
    transition_result = subdispatch_to_paymenttask(chain_state=chain_state,
                                                   state_change=state_change,
                                                   secrethash=UNIT_SECRETHASH)
    assert transition_result.events == []
    assert transition_result.new_state == chain_state

    chain_state.block_number = 20

    balance_proof: BalanceProofSignedState = factories.create(
        factories.BalanceProofSignedStateProperties(
            canonical_identifier=netting_channel_state.canonical_identifier,
            sender=netting_channel_state.partner_state.address,
            transferred_amount=0,
            pkey=factories.UNIT_TRANSFER_PKEY,
            locksroot=LOCKSROOT_OF_NO_LOCKS,
        ))
    state_change = ReceiveLockExpired(
        balance_proof=balance_proof,
        sender=netting_channel_state.partner_state.address,
        secrethash=UNIT_SECRETHASH,
        message_identifier=factories.make_message_identifier(),
    )
    transition_result = subdispatch_to_paymenttask(chain_state=chain_state,
                                                   state_change=state_change,
                                                   secrethash=UNIT_SECRETHASH)
    msg = "ReceiveLockExpired should have cleared the task"
    assert UNIT_SECRETHASH not in chain_state.payment_mapping.secrethashes_to_task, msg
    assert len(
        transition_result.events), "ReceiveLockExpired should generate events"
    assert transition_result.new_state == chain_state
コード例 #9
0
def make_message(sign: bool = True) -> Message:
    message = SecretRequest(
        message_identifier=make_message_identifier(),
        payment_identifier=PaymentID(1),
        secrethash=factories.UNIT_SECRETHASH,
        amount=PaymentAmount(1),
        expiration=BlockExpiration(10),
        signature=EMPTY_SIGNATURE,
    )
    if sign:
        message.sign(LocalSigner(factories.HOP1_KEY))
    return message
コード例 #10
0
def test_received_lockedtransfer_closedchannel(raiden_network, reveal_timeout,
                                               token_addresses, deposit):
    app0, app1 = raiden_network
    registry_address = app0.raiden.default_registry.address
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(app0), app0.raiden.default_registry.address,
        token_address)
    assert token_network_address
    channel0 = get_channelstate(app0, app1, token_network_address)

    RaidenAPI(app1.raiden).channel_close(registry_address, token_address,
                                         app0.raiden.address)

    app0.raiden.proxy_manager.wait_until_block(
        target_block_number=app0.raiden.rpc_client.block_number() + 1)

    # Now receive one mediated transfer for the closed channel
    lock_amount = TokenAmount(10)
    payment_identifier = PaymentID(1)
    expiration = reveal_timeout * 2
    mediated_transfer_message = LockedTransfer(
        chain_id=UNIT_CHAIN_ID,
        message_identifier=make_message_identifier(),
        payment_identifier=payment_identifier,
        nonce=Nonce(1),
        token_network_address=token_network_address,
        token=token_address,
        channel_identifier=channel0.identifier,
        transferred_amount=TokenAmount(0),
        locked_amount=lock_amount,
        recipient=app1.raiden.address,
        locksroot=make_locksroot(),
        lock=Lock(
            amount=PaymentWithFeeAmount(lock_amount),
            expiration=expiration,
            secrethash=UNIT_SECRETHASH,
        ),
        target=app1.raiden.address,
        initiator=app0.raiden.address,
        signature=EMPTY_SIGNATURE,
        metadata=Metadata(routes=[RouteMetadata(route=[app1.raiden.address])]),
    )

    sign_and_inject(mediated_transfer_message, app0.raiden.signer, app1)

    # The local state must not change since the channel is already closed
    assert_synced_channel_state(token_network_address, app0, deposit, [], app1,
                                deposit, [])
コード例 #11
0
def test_inplace_delete_message_queue(chain_state):
    sender = factories.make_address()
    canonical_identifier = factories.make_canonical_identifier()
    message_id = factories.make_message_identifier()
    delivered_state_change = ReceiveDelivered(sender=sender,
                                              message_identifier=message_id)
    processed_state_change = ReceiveProcessed(sender=sender,
                                              message_identifier=message_id)

    global_identifier = QueueIdentifier(
        recipient=sender,
        canonical_identifier=CANONICAL_IDENTIFIER_GLOBAL_QUEUE)

    chain_state.queueids_to_queues[global_identifier] = None
    assert global_identifier in chain_state.queueids_to_queues, "queue mapping insertion failed"
    inplace_delete_message_queue(chain_state=chain_state,
                                 state_change=delivered_state_change,
                                 queueid=global_identifier)
    assert global_identifier not in chain_state.queueids_to_queues, "did not clear queue"

    chain_state.queueids_to_queues[global_identifier] = [
        SendMessageEvent(
            recipient=sender,
            canonical_identifier=canonical_identifier,
            message_identifier=message_id,
        )
    ]
    assert global_identifier in chain_state.queueids_to_queues, "queue mapping insertion failed"
    handle_receive_delivered(chain_state=chain_state,
                             state_change=delivered_state_change)
    assert global_identifier not in chain_state.queueids_to_queues, "did not clear queue"

    queue_identifier = QueueIdentifier(
        recipient=sender, canonical_identifier=canonical_identifier)
    assert queue_identifier not in chain_state.queueids_to_queues, "queue not empty"
    chain_state.queueids_to_queues[queue_identifier] = [
        SendMessageEvent(
            recipient=sender,
            canonical_identifier=canonical_identifier,
            message_identifier=message_id,
        )
    ]
    assert queue_identifier in chain_state.queueids_to_queues, "queue mapping not mutable"
    handle_receive_processed(chain_state=chain_state,
                             state_change=processed_state_change)
    assert queue_identifier not in chain_state.queueids_to_queues, "queue did not clear"
コード例 #12
0
def test_receive_lockedtransfer_invalidrecipient(raiden_network,
                                                 token_addresses,
                                                 reveal_timeout, deposit):
    app0, app1 = raiden_network
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(app0), app0.raiden.default_registry.address,
        token_address)
    assert token_network_address
    channel0 = get_channelstate(app0, app1, token_network_address)

    payment_identifier = PaymentID(1)
    invalid_recipient = make_address()
    lock_amount = TokenAmount(10)
    expiration = reveal_timeout * 2
    mediated_transfer_message = LockedTransfer(
        chain_id=UNIT_CHAIN_ID,
        message_identifier=make_message_identifier(),
        payment_identifier=payment_identifier,
        nonce=Nonce(1),
        token_network_address=token_network_address,
        token=token_address,
        channel_identifier=channel0.identifier,
        transferred_amount=TokenAmount(0),
        locked_amount=lock_amount,
        recipient=invalid_recipient,
        locksroot=make_locksroot(),
        lock=Lock(
            amount=PaymentWithFeeAmount(lock_amount),
            expiration=expiration,
            secrethash=UNIT_SECRETHASH,
        ),
        target=app1.raiden.address,
        initiator=app0.raiden.address,
        signature=EMPTY_SIGNATURE,
        metadata=Metadata(routes=[RouteMetadata(route=[app1.raiden.address])]),
    )

    sign_and_inject(mediated_transfer_message, app0.raiden.signer, app1)

    assert_synced_channel_state(token_network_address, app0, deposit, [], app1,
                                deposit, [])
コード例 #13
0
def test_receive_lockedtransfer_invalidsender(
    raiden_network: List[RaidenService], token_addresses, deposit, reveal_timeout
):
    app0, app1 = raiden_network
    token_address = token_addresses[0]
    other_key, other_address = make_privkey_address()

    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_raiden(app0), app0.default_registry.address, token_address
    )
    assert token_network_address
    channel0 = get_channelstate(app0, app1, token_network_address)
    lock_amount = LockedAmount(10)
    expiration = reveal_timeout * 2
    mediated_transfer_message = LockedTransfer(
        chain_id=UNIT_CHAIN_ID,
        message_identifier=make_message_identifier(),
        payment_identifier=PaymentID(1),
        nonce=Nonce(1),
        token_network_address=token_network_address,
        token=token_address,
        channel_identifier=channel0.identifier,
        transferred_amount=TokenAmount(0),
        locked_amount=lock_amount,
        recipient=app0.address,
        locksroot=make_locksroot(),
        lock=Lock(
            amount=PaymentWithFeeAmount(lock_amount),
            expiration=expiration,
            secrethash=UNIT_SECRETHASH,
        ),
        target=TargetAddress(app0.address),
        initiator=InitiatorAddress(other_address),
        signature=EMPTY_SIGNATURE,
        metadata=Metadata(routes=[RouteMetadata(route=[app0.address])]),
    )

    sign_and_inject(mediated_transfer_message, LocalSigner(other_key), app0)

    assert_synced_channel_state(token_network_address, app0, deposit, [], app1, deposit, [])
コード例 #14
0
def action_init_initiator_to_action_init_target(
    action: ActionInitInitiator,
    channel: NettingChannelState,
    block_number: BlockNumber,
    route_state: RouteState,
    address: Address,
    private_key: PrivateKey,
) -> ActionInitTarget:
    transfer = signed_transfer_from_description(
        private_key=private_key,
        description=action.transfer,
        channel=channel,
        message_id=factories.make_message_identifier(),
        block_number=block_number,
        route_state=route_state,
        route_states=action.routes,
    )
    from_hop = HopState(node_address=address,
                        channel_identifier=channel.identifier)
    return ActionInitTarget(from_hop=from_hop,
                            transfer=transfer,
                            sender=address,
                            balance_proof=transfer.balance_proof)
コード例 #15
0
# messages that don't depend on randomness for that test. But right now, we
# don't have that.
random.seed(1)

message_factories = (
    factories.LockedTransferProperties(),
    factories.RefundTransferProperties(),
    factories.LockExpiredProperties(),
    factories.UnlockProperties(),
)
messages = [factories.create(factory) for factory in message_factories]

# TODO Handle these with factories once #5091 is implemented
messages.append(
    Delivered(
        delivered_message_identifier=factories.make_message_identifier(),
        signature=factories.make_signature(),
    )
)
messages.append(
    Processed(
        message_identifier=factories.make_message_identifier(),
        signature=factories.make_signature(),
    )
)
messages.append(
    RevealSecret(
        message_identifier=factories.make_message_identifier(),
        secret=factories.make_secret(),
        signature=factories.make_signature(),
    )
コード例 #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.

    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]
    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
    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
コード例 #17
0
def test_regression_multiple_revealsecret(
        raiden_network: List[App],
        token_addresses: List[TokenAddress]) -> None:
    """ Multiple RevealSecret messages arriving at the same time must be
    handled properly.

    Unlock handling followed these steps:

        The Unlock message arrives
        The secret is registered
        The channel is updated and the correspoding lock is removed
        * A balance proof for the new channel state is created and sent to the
          payer
        The channel is unregistered for the given secrethash

    The step marked with an asterisk above introduced a context-switch. This
    allowed a second Reveal Unlock message to be handled before the channel was
    unregistered. And because the channel was already updated an exception was raised
    for an unknown secret.
    """
    app0, app1 = raiden_network
    token = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(app0), app0.raiden.default_registry.address,
        token)
    assert token_network_address
    channelstate_0_1 = get_channelstate(app0, app1, token_network_address)

    payment_identifier = PaymentID(1)
    secret, secrethash = make_secret_with_hash()
    expiration = BlockExpiration(app0.raiden.get_block_number() + 100)
    lock_amount = PaymentWithFeeAmount(10)
    lock = Lock(amount=lock_amount,
                expiration=expiration,
                secrethash=secrethash)

    nonce = Nonce(1)
    transferred_amount = TokenAmount(0)
    mediated_transfer = LockedTransfer(
        chain_id=UNIT_CHAIN_ID,
        message_identifier=make_message_identifier(),
        payment_identifier=payment_identifier,
        nonce=nonce,
        token_network_address=token_network_address,
        token=token,
        channel_identifier=channelstate_0_1.identifier,
        transferred_amount=transferred_amount,
        locked_amount=LockedAmount(lock_amount),
        recipient=app1.raiden.address,
        locksroot=Locksroot(lock.lockhash),
        lock=lock,
        target=TargetAddress(app1.raiden.address),
        initiator=InitiatorAddress(app0.raiden.address),
        signature=EMPTY_SIGNATURE,
        metadata=Metadata(routes=[
            RouteMetadata(route=[app0.raiden.address, app1.raiden.address])
        ]),
    )
    app0.raiden.sign(mediated_transfer)
    app1.raiden.on_messages([mediated_transfer])

    reveal_secret = RevealSecret(message_identifier=make_message_identifier(),
                                 secret=secret,
                                 signature=EMPTY_SIGNATURE)
    app0.raiden.sign(reveal_secret)

    token_network_address = channelstate_0_1.token_network_address
    unlock = Unlock(
        chain_id=UNIT_CHAIN_ID,
        message_identifier=make_message_identifier(),
        payment_identifier=payment_identifier,
        nonce=Nonce(mediated_transfer.nonce + 1),
        token_network_address=token_network_address,
        channel_identifier=channelstate_0_1.identifier,
        transferred_amount=TokenAmount(lock_amount),
        locked_amount=LockedAmount(0),
        locksroot=LOCKSROOT_OF_NO_LOCKS,
        secret=secret,
        signature=EMPTY_SIGNATURE,
    )
    app0.raiden.sign(unlock)

    messages = [unlock, reveal_secret]
    receive_method = app1.raiden.on_messages
    wait = set(
        gevent.spawn_later(0.1, receive_method, [data]) for data in messages)

    gevent.joinall(wait, raise_error=True)
コード例 #18
0
def test_receive_secrethashtransfer_unknown(
        raiden_network: List[RaidenService], token_addresses):
    app0 = raiden_network[0]
    token_address = token_addresses[0]

    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_raiden(app0), app0.default_registry.address,
        token_address)
    assert token_network_address

    other_key = HOP1_KEY
    other_signer = LocalSigner(other_key)
    canonical_identifier = factories.make_canonical_identifier(
        token_network_address=token_network_address)

    amount = TokenAmount(10)
    locksroot = Locksroot(make_32bytes())
    refund_transfer_message = factories.create(
        factories.RefundTransferProperties(
            payment_identifier=PaymentID(1),
            nonce=Nonce(1),
            token=token_address,
            canonical_identifier=canonical_identifier,
            transferred_amount=amount,
            recipient=TargetAddress(app0.address),
            locksroot=locksroot,
            amount=amount,
            secret=UNIT_SECRET,
        ))
    sign_and_inject(refund_transfer_message, other_signer, app0)

    unlock = Unlock(
        chain_id=UNIT_CHAIN_ID,
        message_identifier=make_message_identifier(),
        payment_identifier=PaymentID(1),
        nonce=Nonce(1),
        channel_identifier=canonical_identifier.channel_identifier,
        token_network_address=token_network_address,
        transferred_amount=amount,
        locked_amount=LockedAmount(0),
        locksroot=locksroot,
        secret=UNIT_SECRET,
        signature=EMPTY_SIGNATURE,
    )
    sign_and_inject(unlock, other_signer, app0)

    secret_request_message = SecretRequest(
        message_identifier=make_message_identifier(),
        payment_identifier=PaymentID(1),
        secrethash=UNIT_SECRETHASH,
        amount=PaymentAmount(1),
        expiration=refund_transfer_message.lock.expiration,
        signature=EMPTY_SIGNATURE,
    )
    sign_and_inject(secret_request_message, other_signer, app0)

    reveal_secret_message = RevealSecret(
        message_identifier=make_message_identifier(),
        secret=UNIT_SECRET,
        signature=EMPTY_SIGNATURE)
    sign_and_inject(reveal_secret_message, other_signer, app0)
コード例 #19
0
def test_encoding_and_decoding():
    message_factories = (
        factories.LockedTransferProperties(),
        factories.RefundTransferProperties(),
        factories.LockExpiredProperties(),
        factories.UnlockProperties(),
    )
    messages = [factories.create(factory) for factory in message_factories]

    # TODO Handle these with factories once #5091 is implemented
    messages.append(
        Delivered(
            delivered_message_identifier=factories.make_message_identifier(),
            signature=factories.make_signature(),
        ))
    messages.append(
        Processed(
            message_identifier=factories.make_message_identifier(),
            signature=factories.make_signature(),
        ))
    messages.append(
        RevealSecret(
            message_identifier=factories.make_message_identifier(),
            secret=factories.make_secret(),
            signature=factories.make_signature(),
        ))
    messages.append(
        SecretRequest(
            message_identifier=factories.make_message_identifier(),
            payment_identifier=factories.make_payment_id(),
            secrethash=factories.make_secret_hash(),
            amount=factories.make_token_amount(),
            expiration=factories.make_block_number(),
            signature=factories.make_signature(),
        ))
    messages.append(
        WithdrawRequest(
            message_identifier=factories.make_message_identifier(),
            chain_id=factories.make_chain_id(),
            token_network_address=factories.make_token_network_address(),
            channel_identifier=factories.make_channel_identifier(),
            participant=factories.make_address(),
            total_withdraw=factories.make_token_amount(),
            nonce=factories.make_nonce(),
            expiration=factories.make_block_number(),
            signature=factories.make_signature(),
        ))
    messages.append(
        WithdrawConfirmation(
            message_identifier=factories.make_message_identifier(),
            chain_id=factories.make_chain_id(),
            token_network_address=factories.make_token_network_address(),
            channel_identifier=factories.make_channel_identifier(),
            participant=factories.make_address(),
            total_withdraw=factories.make_token_amount(),
            nonce=factories.make_nonce(),
            expiration=factories.make_block_number(),
            signature=factories.make_signature(),
        ))
    messages.append(
        WithdrawExpired(
            message_identifier=factories.make_message_identifier(),
            chain_id=factories.make_chain_id(),
            token_network_address=factories.make_token_network_address(),
            channel_identifier=factories.make_channel_identifier(),
            participant=factories.make_address(),
            total_withdraw=factories.make_token_amount(),
            nonce=factories.make_nonce(),
            expiration=factories.make_block_number(),
            signature=factories.make_signature(),
        ))
    messages.append(
        PFSCapacityUpdate(
            canonical_identifier=factories.make_canonical_identifier(),
            updating_participant=factories.make_address(),
            other_participant=factories.make_address(),
            updating_nonce=factories.make_nonce(),
            other_nonce=factories.make_nonce(),
            updating_capacity=factories.make_token_amount(),
            other_capacity=factories.make_token_amount(),
            reveal_timeout=factories.make_uint64(),
            signature=factories.make_signature(),
        ))
    messages.append(
        PFSFeeUpdate(
            canonical_identifier=factories.make_canonical_identifier(),
            updating_participant=factories.make_address(),
            fee_schedule=factories.create(
                factories.FeeScheduleStateProperties()),
            timestamp=datetime.now(),
            signature=factories.make_signature(),
        ))
    messages.append(
        RequestMonitoring(
            reward_amount=factories.make_token_amount(),
            balance_proof=SignedBlindedBalanceProof.
            from_balance_proof_signed_state(
                factories.create(
                    factories.BalanceProofSignedStateProperties())),
            monitoring_service_contract_address=factories.make_address(),
            non_closing_participant=factories.make_address(),
            non_closing_signature=factories.make_signature(),
            signature=factories.make_signature(),
        ))

    for message in messages:
        serialized = MessageSerializer.serialize(message)
        deserialized = MessageSerializer.deserialize(serialized)
        assert deserialized == message
コード例 #20
0
def make_receive_transfer_mediated(
    channel_state: NettingChannelState,
    privkey: bytes,
    nonce: Nonce,
    transferred_amount: TokenAmount,
    lock: HashTimeLockState,
    pending_locks: PendingLocksState = None,
    locked_amount: Optional[PaymentWithFeeAmount] = None,
    chain_id: Optional[ChainID] = None,
) -> LockedTransferSignedState:

    typecheck(lock, HashTimeLockState)

    signer = LocalSigner(privkey)
    address = signer.address
    if address not in (channel_state.our_state.address,
                       channel_state.partner_state.address):
        raise ValueError("Private key does not match any of the participants.")

    if pending_locks is None:
        locks = make_empty_pending_locks_state()
        locks.locks.append(lock.encoded)
    else:
        assert bytes(lock.encoded) in pending_locks.locks
        locks = pending_locks

    if locked_amount is None:
        locked_amount = lock.amount

    assert locked_amount >= lock.amount

    locksroot = compute_locksroot(locks)

    payment_identifier = PaymentID(nonce)
    transfer_target = make_target_address()
    transfer_initiator = make_initiator_address()
    chain_id = chain_id or channel_state.chain_id

    transfer_metadata = Metadata(routes=[
        RouteMetadata(
            route=[channel_state.our_state.address,
                   Address(transfer_target)])
    ])

    mediated_transfer_msg = LockedTransfer(
        chain_id=chain_id,
        message_identifier=make_message_identifier(),
        payment_identifier=payment_identifier,
        nonce=nonce,
        token_network_address=channel_state.token_network_address,
        token=channel_state.token_address,
        channel_identifier=channel_state.identifier,
        transferred_amount=transferred_amount,
        locked_amount=TokenAmount(locked_amount),
        recipient=channel_state.partner_state.address,
        locksroot=locksroot,
        lock=Lock(amount=lock.amount,
                  expiration=lock.expiration,
                  secrethash=lock.secrethash),
        target=transfer_target,
        initiator=transfer_initiator,
        signature=EMPTY_SIGNATURE,
        fee=0,
        metadata=transfer_metadata,
    )
    mediated_transfer_msg.sign(signer)

    receive_lockedtransfer = LockedTransferSignedState(
        payment_identifier=payment_identifier,
        token=channel_state.token_address,
        lock=lock,
        initiator=transfer_initiator,
        target=transfer_target,
        message_identifier=make_message_identifier(),
        balance_proof=balanceproof_from_envelope(mediated_transfer_msg),
        routes=[
            route_metadata.route for route_metadata in transfer_metadata.routes
        ],
    )

    return receive_lockedtransfer
コード例 #21
0
def test_initiator_skips_used_routes():
    defaults = factories.NettingChannelStateProperties(
        our_state=factories.NettingChannelEndStateProperties.OUR_STATE,
        partner_state=factories.NettingChannelEndStateProperties(balance=10),
        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))
    ]
    test_chain_state = factories.make_chain_state(number_of_channels=1,
                                                  properties=properties,
                                                  defaults=defaults)
    channels = test_chain_state.channel_set

    bob = channels.channels[0].partner_state.address

    routes = [[
        factories.UNIT_OUR_ADDRESS, bob, factories.UNIT_TRANSFER_TARGET
    ]]

    transfer = factories.create(
        factories.TransferDescriptionProperties(
            initiator=factories.UNIT_OUR_ADDRESS,
            target=factories.UNIT_TRANSFER_TARGET))
    init_action = factories.initiator_make_init_action(
        channels=channels,
        routes=routes,
        transfer=transfer,
        estimated_fee=FeeAmount(0))
    transition_result = handle_action_init_initiator(
        chain_state=test_chain_state.chain_state, state_change=init_action)

    chain_state = transition_result.new_state

    assert transfer.secrethash in chain_state.payment_mapping.secrethashes_to_task

    initiator_task = chain_state.payment_mapping.secrethashes_to_task[
        transfer.secrethash]
    initiator_state = initiator_task.manager_state

    assert len(initiator_state.routes) == 1, "Should have one route"
    assert len(
        initiator_state.routes[0].route) == 3, "Route should not be pruned"
    assert initiator_state.routes[0].route == routes[
        0], "Should have test route"

    events = transition_result.events

    assert isinstance(events[-1], SendLockedTransfer)

    locked_transfer = initiator_state.initiator_transfers[
        transfer.secrethash].transfer

    received_transfer = factories.create(
        factories.LockedTransferSignedStateProperties(
            expiration=locked_transfer.lock.expiration,
            payment_identifier=locked_transfer.payment_identifier,
            canonical_identifier=locked_transfer.balance_proof.
            canonical_identifier,
            initiator=factories.UNIT_OUR_ADDRESS,
            sender=bob,
            pkey=factories.HOP1_KEY,
            message_identifier=factories.make_message_identifier(),
            routes=[],
            secret=transfer.secret,
        ))

    role = views.get_transfer_role(chain_state=chain_state,
                                   secrethash=locked_transfer.lock.secrethash)

    assert role == "initiator", "Should keep initiator role"

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

    state_transition(chain_state=chain_state,
                     state_change=failed_route_state_change)

    reroute_state_change = ActionTransferReroute(
        transfer=received_transfer,
        balance_proof=received_transfer.balance_proof,
        sender=received_transfer.balance_proof.sender,  # pylint: disable=no-member
        secret=factories.make_secret(),
    )

    iteration = state_transition(chain_state=chain_state,
                                 state_change=reroute_state_change)

    assert search_for_item(iteration.events, SendLockedTransfer, {}) is None
コード例 #22
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