Exemplo n.º 1
0
def test_get_token_network_by_address():
    test_state = factories.make_chain_state(number_of_channels=3)
    assert (views.get_token_network_by_address(
        test_state.chain_state, test_state.token_network_address).address ==
            test_state.token_network_address)
    unknown_token_network_address = factories.make_address()
    assert (views.get_token_network_by_address(
        test_state.chain_state, unknown_token_network_address) is None)
Exemplo n.º 2
0
def get_contractreceivechannelnew_data_from_event(
        chain_state: ChainState,
        event: DecodedEvent) -> Optional[NewChannelDetails]:
    token_network_address = TokenNetworkAddress(event.originating_contract)
    data = event.event_data
    args = data["args"]
    participant1 = args["participant1"]
    participant2 = args["participant2"]

    our_address = chain_state.our_address

    if our_address == participant1:
        partner_address = participant2
    elif our_address == participant2:
        partner_address = participant1
    else:
        # Not a channel which this node is a participant
        return None

    token_network_registry = views.get_token_network_registry_by_token_network_address(
        chain_state, token_network_address)
    assert token_network_registry is not None, "Token network registry missing"

    token_network = views.get_token_network_by_address(
        chain_state=chain_state, token_network_address=token_network_address)
    assert token_network is not None, "Token network missing"

    return NewChannelDetails(
        chain_id=event.chain_id,
        token_network_registry_address=token_network_registry.address,
        token_address=token_network.token_address,
        token_network_address=token_network_address,
        our_address=our_address,
        partner_address=partner_address,
    )
Exemplo n.º 3
0
    def __init__(self, raiden: "RaidenService",
                 token_network_address: TokenNetworkAddress):
        self.raiden = raiden
        chain_state = views.state_from_raiden(raiden)
        token_network_state = views.get_token_network_by_address(
            chain_state, token_network_address)
        token_network_registry = views.get_token_network_registry_by_token_network_address(
            chain_state, token_network_address)

        msg = f"Token network for address {to_checksum_address(token_network_address)} not found."
        assert token_network_state, msg
        msg = (f"Token network registry for token network address "
               f"{to_checksum_address(token_network_address)} not found.")
        assert token_network_registry, msg

        # TODO:
        # - Add timeout for transaction polling, used to overwrite the RaidenAPI
        # defaults
        # - Add a proper selection strategy (#576)
        self.funds = 0
        self.initial_channel_target = 0
        self.joinable_funds_target = 0.0

        self.raiden = raiden
        self.registry_address = token_network_registry.address
        self.token_network_address = token_network_address
        self.token_address = token_network_state.token_address

        self.lock = Semaphore(
        )  #: protects self.funds and self.initial_channel_target
        self._retry_greenlet: Optional[Greenlet] = None
        self.api = RaidenAPI(raiden)
Exemplo n.º 4
0
def event_filter_for_payments(
    event: Event,
    chain_state: Optional[ChainState] = None,
    partner_address: Optional[Address] = None,
    token_address: Optional[TokenAddress] = None,
) -> bool:
    """Filters payment history related events depending on given arguments

    - If no other args are given, all payment related events match.
    - If a token network identifier is given then only payment events for that match.
    - If a partner is also given then if the event is a payment sent event and the
      target matches it's returned. If it's a payment received and the initiator matches.
      then it's returned.
    - If a token address is given then all events are filtered to be about that token.
    """
    sent_and_target_matches = isinstance(
        event, (EventPaymentSentFailed, EventPaymentSentSuccess)
    ) and (partner_address is None or event.target == TargetAddress(partner_address))
    received_and_initiator_matches = isinstance(event, EventPaymentReceivedSuccess) and (
        partner_address is None or event.initiator == InitiatorAddress(partner_address)
    )

    token_address_matches = True
    if token_address:
        assert chain_state, "Filtering for token_address without a chain state is an error"
        token_network = get_token_network_by_address(
            chain_state=chain_state,
            token_network_address=event.token_network_address,  # type: ignore
        )
        if not token_network:
            token_address_matches = False
        else:
            token_address_matches = token_address == token_network.token_address

    return token_address_matches and (sent_and_target_matches or received_and_initiator_matches)
Exemplo n.º 5
0
    def __init__(self, raiden: "RaidenService", token_network_address: TokenNetworkAddress):
        self.raiden = raiden
        chain_state = views.state_from_raiden(raiden)
        token_network_state = views.get_token_network_by_address(
            chain_state, token_network_address
        )
        token_network_registry = views.get_token_network_registry_by_token_network_address(
            chain_state, token_network_address
        )

        assert token_network_state
        assert token_network_registry

        # TODO:
        # - Add timeout for transaction polling, used to overwrite the RaidenAPI
        # defaults
        # - Add a proper selection strategy (#576)
        self.funds = 0
        self.initial_channel_target = 0
        self.joinable_funds_target = 0.0

        self.raiden = raiden
        self.registry_address = token_network_registry.address
        self.token_network_address = token_network_address
        self.token_address = token_network_state.token_address

        self.lock = Semaphore()  #: protects self.funds and self.initial_channel_target
        self.api = RaidenAPI(raiden)
Exemplo n.º 6
0
 def serialize(self, chain_state: ChainState, event: TimestampedEvent) -> Dict[str, Any]:
     serialized_event = self.dump(event)
     token_network = get_token_network_by_address(
         chain_state=chain_state,
         token_network_address=event.wrapped_event.token_network_address,
     )
     assert token_network, "Token network object should be registered if we got events with it"
     serialized_event["token_address"] = to_checksum_address(token_network.token_address)
     return serialized_event
Exemplo n.º 7
0
def is_channel_registered(node_app: App, partner_app: App,
                          canonical_identifier: CanonicalIdentifier) -> bool:
    """True if the `node_app` has a channel with `partner_app` in its state."""
    token_network = views.get_token_network_by_address(
        chain_state=views.state_from_app(node_app),
        token_network_address=canonical_identifier.token_network_address,
    )
    assert token_network

    is_in_channelid_map = (canonical_identifier.channel_identifier
                           in token_network.channelidentifiers_to_channels)
    is_in_partner_map = (
        canonical_identifier.channel_identifier
        in token_network.partneraddresses_to_channelidentifiers[
            partner_app.raiden.address])

    return is_in_channelid_map and is_in_partner_map
Exemplo n.º 8
0
def get_best_routes(
    chain_state: ChainState,
    token_network_address: TokenNetworkAddress,
    one_to_n_address: Optional[OneToNAddress],
    from_address: InitiatorAddress,
    to_address: TargetAddress,
    amount: PaymentAmount,
    previous_address: Optional[Address],
    pfs_config: Optional[PFSConfig],
    privkey: PrivateKey,
) -> Tuple[Optional[str], List[RouteState], Optional[UUID]]:

    token_network = views.get_token_network_by_address(chain_state,
                                                       token_network_address)
    assert token_network, "The token network must be validated and exist."

    # Always use a direct channel if available:
    # - There are no race conditions and the capacity is guaranteed to be
    #   available.
    # - There will be no mediation fees
    # - The transfer will be faster
    if Address(
            to_address
    ) in token_network.partneraddresses_to_channelidentifiers.keys():
        for channel_id in token_network.partneraddresses_to_channelidentifiers[
                Address(to_address)]:
            channel_state = token_network.channelidentifiers_to_channels[
                channel_id]

            # direct channels don't have fees
            payment_with_fee_amount = PaymentWithFeeAmount(amount)
            is_usable = channel.is_channel_usable_for_new_transfer(
                channel_state, payment_with_fee_amount, None)

            if is_usable is channel.ChannelUsability.USABLE:
                direct_route = RouteState(
                    route=[Address(from_address),
                           Address(to_address)],
                    estimated_fee=FeeAmount(0))
                return None, [direct_route], None

    if pfs_config is None or one_to_n_address is None:
        log.warning("Pathfinding Service could not be used.")
        return "Pathfinding Service could not be used.", list(), None

    # Does any channel have sufficient capacity for the payment?
    channels = [
        token_network.channelidentifiers_to_channels[channel_id]
        for channels_to_partner in
        token_network.partneraddresses_to_channelidentifiers.values()
        for channel_id in channels_to_partner
    ]
    for channel_state in channels:
        payment_with_fee_amount = PaymentWithFeeAmount(amount)
        is_usable = channel.is_channel_usable_for_new_transfer(
            channel_state, payment_with_fee_amount, None)
        if is_usable is channel.ChannelUsability.USABLE:
            break
    else:
        return ("You have no suitable channel to initiate this payment.",
                list(), None)

    # Make sure that the PFS knows about the last channel we opened
    latest_channel_opened_at = 0
    for channel_state in token_network.channelidentifiers_to_channels.values():
        latest_channel_opened_at = max(
            latest_channel_opened_at,
            channel_state.open_transaction.finished_block_number)

    pfs_error_msg, pfs_routes, pfs_feedback_token = get_best_routes_pfs(
        chain_state=chain_state,
        token_network_address=token_network_address,
        one_to_n_address=one_to_n_address,
        from_address=from_address,
        to_address=to_address,
        amount=amount,
        previous_address=previous_address,
        pfs_config=pfs_config,
        privkey=privkey,
        pfs_wait_for_block=BlockNumber(latest_channel_opened_at),
    )

    if pfs_error_msg:
        log.warning(
            "Request to Pathfinding Service was not successful. "
            "No routes to the target were found.",
            pfs_message=pfs_error_msg,
        )
        return pfs_error_msg, list(), None

    if not pfs_routes:
        # As of version 0.5 it is possible for the PFS to return an empty
        # list of routes without an error message.
        return "PFS could not find any routes", list(), None

    log.info("Received route(s) from PFS",
             routes=pfs_routes,
             feedback_token=pfs_feedback_token)
    return pfs_error_msg, pfs_routes, pfs_feedback_token
Exemplo n.º 9
0
def get_contractreceivechannelbatchunlock_data_from_event(
        chain_state: ChainState, storage: SerializedSQLiteStorage,
        event: DecodedEvent) -> Optional[CanonicalIdentifier]:
    token_network_address = TokenNetworkAddress(event.originating_contract)
    data = event.event_data
    args = data["args"]
    participant1 = args["receiver"]
    participant2 = args["sender"]
    locksroot = args["locksroot"]

    token_network_state = views.get_token_network_by_address(
        chain_state, token_network_address)
    msg = f"Could not find token network for address {to_checksum_address(token_network_address)}"
    assert token_network_state is not None, msg

    if participant1 == chain_state.our_address:
        partner = participant2
    elif participant2 == chain_state.our_address:
        partner = participant1
    else:
        return None

    channel_identifiers = token_network_state.partneraddresses_to_channelidentifiers[
        partner]
    canonical_identifier = None

    for channel_identifier in channel_identifiers:
        if partner == args["sender"]:
            state_change_record = get_state_change_with_balance_proof_by_locksroot(
                storage=storage,
                canonical_identifier=CanonicalIdentifier(
                    chain_identifier=chain_state.chain_id,
                    token_network_address=token_network_address,
                    channel_identifier=channel_identifier,
                ),
                locksroot=locksroot,
                sender=partner,
            )
            if state_change_record is not None:
                canonical_identifier = (
                    state_change_record.data.balance_proof.
                    canonical_identifier  # type: ignore
                )
                break
        elif partner == args["receiver"]:
            event_record = get_event_with_balance_proof_by_locksroot(
                storage=storage,
                canonical_identifier=CanonicalIdentifier(
                    chain_identifier=chain_state.chain_id,
                    token_network_address=token_network_address,
                    channel_identifier=channel_identifier,
                ),
                locksroot=locksroot,
                recipient=partner,
            )
            if event_record is not None:
                canonical_identifier = (
                    event_record.data.balance_proof.
                    canonical_identifier  # type: ignore
                )
                break

    msg = (
        f"Can not resolve channel_id for unlock with locksroot {to_hex(locksroot)} and "
        f"partner {to_checksum_address(partner)}.")
    if canonical_identifier is None:
        raise RaidenUnrecoverableError(msg)

    return canonical_identifier
Exemplo n.º 10
0
def test_clear_closed_queue(raiden_network: List[App], token_addresses,
                            network_wait):
    """ Closing a channel clears the respective message queue. """
    app0, app1 = raiden_network

    hold_event_handler = app1.raiden.raiden_event_handler
    assert isinstance(hold_event_handler, HoldRaidenEventHandler)

    registry_address = app0.raiden.default_registry.address
    token_address = token_addresses[0]
    chain_state0 = views.state_from_app(app0)
    token_network_address = views.get_token_network_address_by_token_address(
        chain_state0, app0.raiden.default_registry.address, token_address)
    assert token_network_address
    token_network = views.get_token_network_by_address(chain_state0,
                                                       token_network_address)
    assert token_network

    channel_identifier = get_channelstate(app0, app1,
                                          token_network_address).identifier

    assert (channel_identifier
            in token_network.partneraddresses_to_channelidentifiers[
                app1.raiden.address])

    target = app1.raiden.address
    secret = Secret(keccak(target))
    secrethash = sha256_secrethash(secret)
    hold_event_handler.hold_secretrequest_for(secrethash=secrethash)

    # make an unconfirmed transfer to ensure the nodes have communicated
    amount = PaymentAmount(10)
    payment_identifier = PaymentID(1337)
    app0.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=amount,
        target=TargetAddress(target),
        identifier=payment_identifier,
        secret=secret,
    )

    app1.raiden.transport.stop()
    app1.raiden.transport.greenlet.get()

    # make sure to wait until the queue is created
    def has_initiator_events():
        assert app0.raiden.wal, "raiden server must have been started"
        initiator_events = app0.raiden.wal.storage.get_events()
        return search_for_item(initiator_events, SendLockedTransfer, {})

    assert wait_until(has_initiator_events, network_wait)

    # assert the specific queue is present
    chain_state0 = views.state_from_app(app0)
    queues0 = views.get_all_messagequeues(chain_state=chain_state0)
    assert [
        (queue_id, queue) for queue_id, queue in queues0.items()
        if queue_id.recipient == app1.raiden.address and queue_id.
        canonical_identifier.channel_identifier == channel_identifier and queue
    ]

    # A ChannelClose event will be generated, this will be polled by both apps
    RaidenAPI(app0.raiden).channel_close(registry_address, token_address,
                                         app1.raiden.address)

    with block_offset_timeout(app0.raiden, "Could not get close event"):
        waiting.wait_for_close(
            app0.raiden,
            registry_address,
            token_address,
            [channel_identifier],
            app0.raiden.alarm.sleep_time,
        )

    # assert all queues with this partner are gone or empty
    chain_state0 = views.state_from_app(app0)
    queues0 = views.get_all_messagequeues(chain_state=chain_state0)
    assert not [(queue_id, queue) for queue_id, queue in queues0.items()
                if queue_id.recipient == app1.raiden.address and queue]

    chain_state1 = views.state_from_app(app1)
    queues1 = views.get_all_messagequeues(chain_state=chain_state1)
    assert not [(queue_id, queue) for queue_id, queue in queues1.items()
                if queue_id.recipient == app0.raiden.address and queue]
Exemplo n.º 11
0
def test_batch_unlock_after_restart(raiden_network, token_addresses, deposit):
    """Simulate the case where:
    - A sends B a transfer
    - B sends A a transfer
    - Secrets were never revealed
    - B closes channel
    - A crashes
    - Wait for settle
    - Wait for unlock from B
    - Restart A
    At this point, the current unlock logic will try to unlock
    iff the node gains from unlocking. Which means that the node will try to unlock
    either side. In the above scenario, each node will unlock its side.
    This test makes sure that we do NOT invalidate A's unlock transaction based
    on the ContractReceiveChannelBatchUnlock caused by B's unlock.
    """
    alice_app, bob_app = raiden_network
    registry_address = alice_app.raiden.default_registry.address
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        chain_state=views.state_from_app(alice_app),
        token_network_registry_address=alice_app.raiden.default_registry.address,
        token_address=token_address,
    )
    assert token_network_address
    timeout = 10

    token_network = views.get_token_network_by_address(
        chain_state=views.state_from_app(alice_app), token_network_address=token_network_address
    )
    assert token_network

    channel_identifier = get_channelstate(alice_app, bob_app, token_network_address).identifier

    assert (
        channel_identifier
        in token_network.partneraddresses_to_channelidentifiers[bob_app.raiden.address]
    )

    alice_to_bob_amount = 10
    identifier = 1

    alice_transfer_secret = Secret(sha3(alice_app.raiden.address))
    alice_transfer_secrethash = sha256_secrethash(alice_transfer_secret)

    bob_transfer_secret = Secret(sha3(bob_app.raiden.address))
    bob_transfer_secrethash = sha256_secrethash(bob_transfer_secret)

    alice_transfer_hold = bob_app.raiden.raiden_event_handler.hold_secretrequest_for(
        secrethash=alice_transfer_secrethash
    )
    bob_transfer_hold = alice_app.raiden.raiden_event_handler.hold_secretrequest_for(
        secrethash=bob_transfer_secrethash
    )

    alice_app.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=alice_to_bob_amount,
        target=bob_app.raiden.address,
        identifier=identifier,
        secret=alice_transfer_secret,
    )

    bob_app.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=alice_to_bob_amount,
        target=alice_app.raiden.address,
        identifier=identifier + 1,
        secret=bob_transfer_secret,
    )

    alice_transfer_hold.wait(timeout=timeout)
    bob_transfer_hold.wait(timeout=timeout)

    alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_address)
    alice_lock = channel.get_lock(alice_bob_channel_state.our_state, alice_transfer_secrethash)
    bob_lock = channel.get_lock(alice_bob_channel_state.partner_state, bob_transfer_secrethash)
    assert alice_lock
    assert bob_lock

    # This is the current state of protocol:
    #
    #    A -> B LockedTransfer
    #    - protocol didn't continue
    assert_synced_channel_state(
        token_network_address=token_network_address,
        app0=alice_app,
        balance0=deposit,
        pending_locks0=[alice_lock],
        app1=bob_app,
        balance1=deposit,
        pending_locks1=[bob_lock],
    )

    # A ChannelClose event will be generated, this will be polled by both apps
    # and each must start a task for calling settle
    RaidenAPI(bob_app.raiden).channel_close(
        registry_address=registry_address,
        token_address=token_address,
        partner_address=alice_app.raiden.address,
    )

    # wait for the close transaction to be mined, this is necessary to compute
    # the timeout for the settle
    with gevent.Timeout(timeout):
        waiting.wait_for_close(
            raiden=alice_app.raiden,
            token_network_registry_address=registry_address,
            token_address=token_address,
            channel_ids=[alice_bob_channel_state.identifier],
            retry_timeout=alice_app.raiden.alarm.sleep_time,
        )

    channel_closed = raiden_state_changes_search_for_item(
        bob_app.raiden,
        ContractReceiveChannelClosed,
        {
            "canonical_identifier": {
                "token_network_address": token_network_address,
                "channel_identifier": alice_bob_channel_state.identifier,
            }
        },
    )
    assert isinstance(channel_closed, ContractReceiveChannelClosed)
    settle_max_wait_block = BlockNumber(
        channel_closed.block_number + alice_bob_channel_state.settle_timeout * 2
    )

    settle_timeout = BlockTimeout(
        RuntimeError("settle did not happen"),
        bob_app.raiden,
        settle_max_wait_block,
        alice_app.raiden.alarm.sleep_time,
    )
    with settle_timeout:
        waiting.wait_for_settle(
            raiden=alice_app.raiden,
            token_network_registry_address=registry_address,
            token_address=token_address,
            channel_ids=[alice_bob_channel_state.identifier],
            retry_timeout=alice_app.raiden.alarm.sleep_time,
        )

    with gevent.Timeout(timeout):
        wait_for_batch_unlock(
            app=bob_app,
            token_network_address=token_network_address,
            receiver=alice_bob_channel_state.partner_state.address,
            sender=alice_bob_channel_state.our_state.address,
        )

    alice_app.start()

    with gevent.Timeout(timeout):
        wait_for_batch_unlock(
            app=alice_app,
            token_network_address=token_network_address,
            receiver=alice_bob_channel_state.partner_state.address,
            sender=alice_bob_channel_state.our_state.address,
        )
Exemplo n.º 12
0
def test_settle_is_automatically_called(raiden_network, token_addresses):
    """Settle is automatically called by one of the nodes."""
    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
    token_network = views.get_token_network_by_address(
        views.state_from_app(app0), token_network_address
    )
    assert token_network

    channel_identifier = get_channelstate(app0, app1, token_network_address).identifier

    assert (
        channel_identifier
        in token_network.partneraddresses_to_channelidentifiers[app1.raiden.address]
    )

    # A ChannelClose event will be generated, this will be polled by both apps
    # and each must start a task for calling settle
    RaidenAPI(app1.raiden).channel_close(registry_address, token_address, app0.raiden.address)

    waiting.wait_for_close(
        app0.raiden,
        registry_address,
        token_address,
        [channel_identifier],
        app0.raiden.alarm.sleep_time,
    )

    channel_state = views.get_channelstate_for(
        views.state_from_raiden(app0.raiden), registry_address, token_address, app1.raiden.address
    )
    assert channel_state
    assert channel_state.close_transaction
    assert channel_state.close_transaction.finished_block_number

    waiting.wait_for_settle(
        app0.raiden,
        registry_address,
        token_address,
        [channel_identifier],
        app0.raiden.alarm.sleep_time,
    )

    token_network = views.get_token_network_by_address(
        views.state_from_app(app0), token_network_address
    )
    assert token_network

    assert (
        channel_identifier
        not in token_network.partneraddresses_to_channelidentifiers[app1.raiden.address]
    )

    state_changes = app0.raiden.wal.storage.get_statechanges_by_range(RANGE_ALL_STATE_CHANGES)

    assert search_for_item(
        state_changes,
        ContractReceiveChannelClosed,
        {
            "token_network_address": token_network_address,
            "channel_identifier": channel_identifier,
            "transaction_from": app1.raiden.address,
            "block_number": channel_state.close_transaction.finished_block_number,
        },
    )

    assert search_for_item(
        state_changes,
        ContractReceiveChannelSettled,
        {"token_network_address": token_network_address, "channel_identifier": channel_identifier},
    )
Exemplo n.º 13
0
def test_mediator_clear_pairs_after_batch_unlock(chain_state,
                                                 token_network_state,
                                                 our_address,
                                                 channel_properties):
    """ Regression test for https://github.com/raiden-network/raiden/issues/2932
    The mediator must also clear the transfer pairs once a ReceiveBatchUnlock where
    he is a participant is received.
    """
    open_block_number = 10
    open_block_hash = factories.make_block_hash()

    pseudo_random_generator = random.Random()

    properties, pkey = channel_properties
    address = properties.partner_state.address
    channel_state = factories.create(properties)

    channel_new_state_change = ContractReceiveChannelNew(
        transaction_hash=factories.make_transaction_hash(),
        channel_state=channel_state,
        block_number=open_block_number,
        block_hash=open_block_hash,
    )

    channel_new_iteration = token_network.state_transition(
        token_network_state=token_network_state,
        state_change=channel_new_state_change,
        block_number=open_block_number,
        block_hash=open_block_hash,
        pseudo_random_generator=pseudo_random_generator,
    )

    lock_amount = 30
    lock_expiration = 20
    lock_secret = keccak(b"test_end_state")
    lock_secrethash = sha256(lock_secret).digest()
    lock = HashTimeLockState(lock_amount, lock_expiration, lock_secrethash)

    mediated_transfer = make_receive_transfer_mediated(
        channel_state=channel_state,
        privkey=pkey,
        nonce=1,
        transferred_amount=0,
        lock=lock)

    route_state = RouteState(
        route=[
            channel_state.our_state.address,
            channel_state.partner_state.address
        ],
        forward_channel_id=channel_state.canonical_identifier.
        channel_identifier,
    )
    from_hop = factories.make_hop_from_channel(channel_state)
    init_mediator = ActionInitMediator(
        route_states=[route_state],
        from_hop=from_hop,
        from_transfer=mediated_transfer,
        balance_proof=mediated_transfer.balance_proof,
        sender=mediated_transfer.balance_proof.sender,  # pylint: disable=no-member
    )

    node.state_transition(chain_state, init_mediator)

    closed_block_number = open_block_number + 10
    closed_block_hash = factories.make_block_hash()
    channel_close_state_change = ContractReceiveChannelClosed(
        transaction_hash=factories.make_transaction_hash(),
        transaction_from=channel_state.partner_state.address,
        canonical_identifier=channel_state.canonical_identifier,
        block_number=closed_block_number,
        block_hash=closed_block_hash,
    )

    channel_closed_iteration = token_network.state_transition(
        token_network_state=channel_new_iteration.new_state,
        state_change=channel_close_state_change,
        block_number=closed_block_number,
        block_hash=closed_block_hash,
        pseudo_random_generator=pseudo_random_generator,
    )

    settle_block_number = closed_block_number + channel_state.settle_timeout + 1
    channel_settled_state_change = ContractReceiveChannelSettled(
        transaction_hash=factories.make_transaction_hash(),
        canonical_identifier=channel_state.canonical_identifier,
        block_number=settle_block_number,
        block_hash=factories.make_block_hash(),
        our_onchain_locksroot=factories.make_32bytes(),
        partner_onchain_locksroot=LOCKSROOT_OF_NO_LOCKS,
    )

    channel_settled_iteration = token_network.state_transition(
        token_network_state=channel_closed_iteration.new_state,
        state_change=channel_settled_state_change,
        block_number=closed_block_number,
        block_hash=closed_block_hash,
        pseudo_random_generator=pseudo_random_generator,
    )

    token_network_state_after_settle = channel_settled_iteration.new_state
    ids_to_channels = token_network_state_after_settle.channelidentifiers_to_channels
    assert len(ids_to_channels) == 1
    assert channel_state.identifier in ids_to_channels

    block_number = closed_block_number + 1
    channel_batch_unlock_state_change = ContractReceiveChannelBatchUnlock(
        transaction_hash=factories.make_transaction_hash(),
        canonical_identifier=channel_state.canonical_identifier,
        receiver=address,
        sender=our_address,
        locksroot=compute_locksroot(PendingLocksState([bytes(lock.encoded)])),
        unlocked_amount=lock_amount,
        returned_tokens=0,
        block_number=block_number,
        block_hash=factories.make_block_hash(),
    )
    channel_unlock_iteration = node.state_transition(
        chain_state=chain_state,
        state_change=channel_batch_unlock_state_change)
    chain_state = channel_unlock_iteration.new_state
    token_network_state = views.get_token_network_by_address(
        chain_state=chain_state,
        token_network_address=token_network_state.address)
    ids_to_channels = token_network_state.channelidentifiers_to_channels
    assert len(ids_to_channels) == 0

    # Make sure that all is fine in the next block
    block = Block(block_number=block_number + 1,
                  gas_limit=1,
                  block_hash=factories.make_transaction_hash())
    iteration = node.state_transition(chain_state=chain_state,
                                      state_change=block)
    assert iteration.new_state

    # Make sure that mediator task was cleared during the next block processing
    # since the channel was removed
    mediator_task = chain_state.payment_mapping.secrethashes_to_task.get(
        lock_secrethash)
    assert not mediator_task
Exemplo n.º 14
0
def get_best_routes_internal(
    chain_state: ChainState,
    token_network_address: TokenNetworkAddress,
    from_address: InitiatorAddress,
    to_address: TargetAddress,
    amount: int,
    previous_address: Optional[Address],
) -> List[RouteState]:
    """ Returns a list of channels that can be used to make a transfer.

    This will filter out channels that are not open and don't have enough
    capacity.
    """
    # TODO: Route ranking.
    # Rate each route to optimize the fee price/quality of each route and add a
    # rate from in the range [0.0,1.0].

    available_routes = list()

    token_network = views.get_token_network_by_address(chain_state,
                                                       token_network_address)

    if not token_network:
        return list()

    neighbors_heap: List[Neighbour] = list()
    try:
        all_neighbors = networkx.all_neighbors(
            token_network.network_graph.network, from_address)
    except networkx.NetworkXError:
        # If `our_address` is not in the graph, no channels opened with the
        # address
        return list()

    for partner_address in all_neighbors:
        # don't send the message backwards
        if partner_address == previous_address:
            continue

        channel_state = views.get_channelstate_by_token_network_and_partner(
            chain_state, token_network_address, partner_address)

        if not channel_state:
            continue

        if channel.get_status(channel_state) != ChannelState.STATE_OPENED:
            log.info(
                "Channel is not opened, ignoring",
                from_address=to_checksum_address(from_address),
                partner_address=to_checksum_address(partner_address),
                routing_source="Internal Routing",
            )
            continue

        nonrefundable = amount > channel.get_distributable(
            channel_state.partner_state, channel_state.our_state)

        try:
            route = networkx.shortest_path(token_network.network_graph.network,
                                           partner_address, to_address)
            neighbour = Neighbour(
                length=len(route),
                nonrefundable=nonrefundable,
                partner_address=partner_address,
                channelid=channel_state.identifier,
                route=route,
            )
            heappush(neighbors_heap, neighbour)
        except (networkx.NetworkXNoPath, networkx.NodeNotFound):
            pass

    if not neighbors_heap:
        log.warning(
            "No routes available",
            from_address=to_checksum_address(from_address),
            to_address=to_checksum_address(to_address),
        )
        return list()

    while neighbors_heap:
        neighbour = heappop(neighbors_heap)
        # The complete route includes the initiator, add it to the beginning
        complete_route = [Address(from_address)] + neighbour.route

        # https://github.com/raiden-network/raiden/issues/4751
        # Internal routing doesn't know how much fees the initiator will be charged,
        # so it should set a percentage on top of the original amount
        # for the whole route.
        estimated_fee = FeeAmount(
            round(INTERNAL_ROUTING_DEFAULT_FEE_PERC * amount))
        if neighbour.length == 1:  # Target is our direct neighbour, pay no fees.
            estimated_fee = FeeAmount(0)

        available_routes.append(
            RouteState(
                route=complete_route,
                forward_channel_id=neighbour.channelid,
                estimated_fee=estimated_fee,
            ))

    return available_routes
Exemplo n.º 15
0
def test_clear_closed_queue(raiden_network, token_addresses, network_wait):
    """ Closing a channel clears the respective message queue. """
    app0, app1 = raiden_network

    hold_event_handler = app1.raiden.raiden_event_handler

    registry_address = app0.raiden.default_registry.address
    token_address = token_addresses[0]
    chain_state0 = views.state_from_app(app0)
    token_network_address = views.get_token_network_address_by_token_address(
        chain_state0, app0.raiden.default_registry.address, token_address)
    assert token_network_address
    token_network = views.get_token_network_by_address(chain_state0,
                                                       token_network_address)
    assert token_network

    channel_identifier = get_channelstate(app0, app1,
                                          token_network_address).identifier

    assert (channel_identifier
            in token_network.partneraddresses_to_channelidentifiers[
                app1.raiden.address])

    target = app1.raiden.address
    secret = sha3(target)
    secrethash = sha256(secret).digest()
    hold_event_handler.hold_secretrequest_for(secrethash=secrethash)

    # make an unconfirmed transfer to ensure the nodes have communicated
    amount = 10
    payment_identifier = 1337
    app0.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=amount,
        target=target,
        identifier=payment_identifier,
        secret=secret,
    )

    app1.raiden.transport.stop()
    app1.raiden.transport.get()

    # make sure to wait until the queue is created
    def has_initiator_events():
        initiator_events = app0.raiden.wal.storage.get_events()
        return search_for_item(initiator_events, SendLockedTransfer, {})

    assert wait_until(has_initiator_events, network_wait)

    # assert the specific queue is present
    chain_state0 = views.state_from_app(app0)
    queues0 = views.get_all_messagequeues(chain_state=chain_state0)
    assert [
        (queue_id, queue) for queue_id, queue in queues0.items()
        if queue_id.recipient == app1.raiden.address and queue_id.
        canonical_identifier.channel_identifier == channel_identifier and queue
    ]

    # A ChannelClose event will be generated, this will be polled by both apps
    RaidenAPI(app0.raiden).channel_close(registry_address, token_address,
                                         app1.raiden.address)

    exception = ValueError("Could not get close event")
    with gevent.Timeout(seconds=30, exception=exception):
        waiting.wait_for_close(
            app0.raiden,
            registry_address,
            token_address,
            [channel_identifier],
            app0.raiden.alarm.sleep_time,
        )

    # assert all queues with this partner are gone or empty
    chain_state0 = views.state_from_app(app0)
    queues0 = views.get_all_messagequeues(chain_state=chain_state0)
    assert not [(queue_id, queue) for queue_id, queue in queues0.items()
                if queue_id.recipient == app1.raiden.address and queue]

    chain_state1 = views.state_from_app(app1)
    queues1 = views.get_all_messagequeues(chain_state=chain_state1)
    assert not [(queue_id, queue) for queue_id, queue in queues1.items()
                if queue_id.recipient == app0.raiden.address and queue]
Exemplo n.º 16
0
def test_lock_expiry(raiden_network, token_addresses, deposit):
    """Test lock expiry and removal."""
    alice_app, bob_app = raiden_network
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(alice_app), alice_app.raiden.default_registry.address, token_address
    )
    assert token_network_address

    hold_event_handler = bob_app.raiden.raiden_event_handler
    wait_message_handler = bob_app.raiden.message_handler

    token_network = views.get_token_network_by_address(
        views.state_from_app(alice_app), token_network_address
    )
    assert token_network

    channel_state = get_channelstate(alice_app, bob_app, token_network_address)
    channel_identifier = channel_state.identifier

    assert (
        channel_identifier
        in token_network.partneraddresses_to_channelidentifiers[bob_app.raiden.address]
    )

    alice_to_bob_amount = 10
    identifier = 1
    target = bob_app.raiden.address
    transfer_1_secret = factories.make_secret(0)
    transfer_1_secrethash = sha256_secrethash(transfer_1_secret)
    transfer_2_secret = factories.make_secret(1)
    transfer_2_secrethash = sha256_secrethash(transfer_2_secret)

    hold_event_handler.hold_secretrequest_for(secrethash=transfer_1_secrethash)
    transfer1_received = wait_message_handler.wait_for_message(
        LockedTransfer, {"lock": {"secrethash": transfer_1_secrethash}}
    )
    transfer2_received = wait_message_handler.wait_for_message(
        LockedTransfer, {"lock": {"secrethash": transfer_2_secrethash}}
    )
    remove_expired_lock_received = wait_message_handler.wait_for_message(
        LockExpired, {"secrethash": transfer_1_secrethash}
    )

    alice_app.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=alice_to_bob_amount,
        target=target,
        identifier=identifier,
        secret=transfer_1_secret,
    )
    transfer1_received.wait()

    alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_address)
    lock = channel.get_lock(alice_bob_channel_state.our_state, transfer_1_secrethash)
    assert lock

    # This is the current state of the protocol:
    #
    #    A -> B LockedTransfer
    #    B -> A SecretRequest
    #    - protocol didn't continue
    assert_synced_channel_state(
        token_network_address, alice_app, deposit, [lock], bob_app, deposit, []
    )

    # Verify lock is registered in both channel states
    alice_channel_state = get_channelstate(alice_app, bob_app, token_network_address)
    assert transfer_1_secrethash in alice_channel_state.our_state.secrethashes_to_lockedlocks

    bob_channel_state = get_channelstate(bob_app, alice_app, token_network_address)
    assert transfer_1_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks

    alice_chain_state = views.state_from_raiden(alice_app.raiden)
    assert transfer_1_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task

    remove_expired_lock_received.wait()

    alice_channel_state = get_channelstate(alice_app, bob_app, token_network_address)
    assert transfer_1_secrethash not in alice_channel_state.our_state.secrethashes_to_lockedlocks

    # Verify Bob received the message and processed the LockExpired message
    bob_channel_state = get_channelstate(bob_app, alice_app, token_network_address)
    assert transfer_1_secrethash not in bob_channel_state.partner_state.secrethashes_to_lockedlocks

    alice_chain_state = views.state_from_raiden(alice_app.raiden)
    assert transfer_1_secrethash not in alice_chain_state.payment_mapping.secrethashes_to_task

    # Make another transfer
    alice_to_bob_amount = 10
    identifier = 2

    hold_event_handler.hold_secretrequest_for(secrethash=transfer_2_secrethash)

    alice_app.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=alice_to_bob_amount,
        target=target,
        identifier=identifier,
        secret=transfer_2_secret,
    )
    transfer2_received.wait()

    # Make sure the other transfer still exists
    alice_chain_state = views.state_from_raiden(alice_app.raiden)
    assert transfer_2_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task

    bob_channel_state = get_channelstate(bob_app, alice_app, token_network_address)
    assert transfer_2_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks
Exemplo n.º 17
0
def get_best_routes(
    chain_state: ChainState,
    token_network_address: TokenNetworkAddress,
    one_to_n_address: Optional[OneToNAddress],
    from_address: InitiatorAddress,
    to_address: TargetAddress,
    amount: PaymentAmount,
    previous_address: Optional[Address],
    pfs_config: Optional[PFSConfig],
    privkey: bytes,
) -> Tuple[Optional[str], List[RouteState], Optional[UUID]]:

    token_network = views.get_token_network_by_address(chain_state,
                                                       token_network_address)
    assert token_network, "The token network must be validated and exist."

    try:
        # networkx returns a generator, consume the result since it will be
        # iterated over multiple times.
        all_neighbors = list(
            networkx.all_neighbors(token_network.network_graph.network,
                                   from_address))
    except networkx.NetworkXError:
        # If `our_address` is not in the graph, no channels opened with the
        # address.
        log.debug(
            "Node does not have a channel in the requested token network.",
            source=to_checksum_address(from_address),
            target=to_checksum_address(to_address),
            amount=amount,
        )
        return ("Node does not have a channel in the requested token network.",
                list(), None)

    error_closed = 0
    error_no_route = 0
    error_no_capacity = 0
    error_not_online = 0
    error_direct = None
    shortest_routes: List[Neighbour] = list()

    # Always use a direct channel if available:
    # - There are no race conditions and the capacity is guaranteed to be
    #   available.
    # - There will be no mediation fees
    # - The transfer will be faster
    if to_address in all_neighbors:
        for channel_id in token_network.partneraddresses_to_channelidentifiers[
                Address(to_address)]:
            channel_state = token_network.channelidentifiers_to_channels[
                channel_id]

            # direct channels don't have fees
            payment_with_fee_amount = PaymentWithFeeAmount(amount)
            is_usable = channel.is_channel_usable_for_new_transfer(
                channel_state, payment_with_fee_amount, None)

            if is_usable is channel.ChannelUsability.USABLE:
                direct_route = RouteState(
                    route=[Address(from_address),
                           Address(to_address)],
                    forward_channel_id=channel_state.canonical_identifier.
                    channel_identifier,
                    estimated_fee=FeeAmount(0),
                )
                return (None, [direct_route], None)

            error_direct = is_usable

    latest_channel_opened_at = BlockNumber(0)
    for partner_address in all_neighbors:
        for channel_id in token_network.partneraddresses_to_channelidentifiers[
                partner_address]:
            channel_state = token_network.channelidentifiers_to_channels[
                channel_id]

            if channel.get_status(channel_state) != ChannelState.STATE_OPENED:
                error_closed += 1
                continue

            latest_channel_opened_at = max(
                latest_channel_opened_at,
                channel_state.open_transaction.finished_block_number)

            try:
                route = networkx.shortest_path(
                    token_network.network_graph.network, partner_address,
                    to_address)
            except (networkx.NetworkXNoPath, networkx.NodeNotFound):
                error_no_route += 1
            else:
                distributable = channel.get_distributable(
                    channel_state.our_state, channel_state.partner_state)

                network_status = views.get_node_network_status(
                    chain_state, channel_state.partner_state.address)

                if distributable < amount:
                    error_no_capacity += 1
                elif network_status != NetworkState.REACHABLE:
                    error_not_online += 1
                else:
                    nonrefundable = amount > channel.get_distributable(
                        channel_state.partner_state, channel_state.our_state)

                    # The complete route includes the initiator, add it to the beginning
                    complete_route = [Address(from_address)] + route
                    neighbour = Neighbour(
                        length=len(route),
                        nonrefundable=nonrefundable,
                        partner_address=partner_address,
                        channelid=channel_state.identifier,
                        route=complete_route,
                    )
                    heappush(shortest_routes, neighbour)

    if not shortest_routes:
        qty_channels = sum(
            len(token_network.
                partneraddresses_to_channelidentifiers[partner_address])
            for partner_address in all_neighbors)
        error_msg = (
            f"None of the existing channels could be used to complete the "
            f"transfer. From the {qty_channels} existing channels. "
            f"{error_closed} are closed. {error_not_online} are not online. "
            f"{error_no_route} don't have a route to the target in the given "
            f"token network. {error_no_capacity} don't have enough capacity for "
            f"the requested transfer.")
        if error_direct is not None:
            error_msg += f"direct channel {error_direct}."

        log.warning(
            "None of the existing channels could be used to complete the transfer",
            from_address=to_checksum_address(from_address),
            to_address=to_checksum_address(to_address),
            error_closed=error_closed,
            error_no_route=error_no_route,
            error_no_capacity=error_no_capacity,
            error_direct=error_direct,
            error_not_online=error_not_online,
        )
        return (error_msg, list(), None)

    if pfs_config is not None and one_to_n_address is not None:
        pfs_error_msg, pfs_routes, pfs_feedback_token = get_best_routes_pfs(
            chain_state=chain_state,
            token_network_address=token_network_address,
            one_to_n_address=one_to_n_address,
            from_address=from_address,
            to_address=to_address,
            amount=amount,
            previous_address=previous_address,
            pfs_config=pfs_config,
            privkey=privkey,
            pfs_wait_for_block=latest_channel_opened_at,
        )

        if not pfs_error_msg:
            # As of version 0.5 it is possible for the PFS to return an empty
            # list of routes without an error message.
            if not pfs_routes:
                return ("PFS could not find any routes", list(), None)

            log.info("Received route(s) from PFS",
                     routes=pfs_routes,
                     feedback_token=pfs_feedback_token)
            return (pfs_error_msg, pfs_routes, pfs_feedback_token)

        log.warning(
            "Request to Pathfinding Service was not successful. "
            "No routes to the target are found.",
            pfs_message=pfs_error_msg,
        )
        return (pfs_error_msg, list(), None)

    else:
        available_routes = list()

        while shortest_routes:
            neighbour = heappop(shortest_routes)

            # https://github.com/raiden-network/raiden/issues/4751
            # Internal routing doesn't know how much fees the initiator will be charged,
            # so it should set a percentage on top of the original amount
            # for the whole route.
            estimated_fee = FeeAmount(
                round(INTERNAL_ROUTING_DEFAULT_FEE_PERC * amount))
            if neighbour.length == 1:  # Target is our direct neighbour, pay no fees.
                estimated_fee = FeeAmount(0)

            available_routes.append(
                RouteState(
                    route=neighbour.route,
                    forward_channel_id=neighbour.channelid,
                    estimated_fee=estimated_fee,
                ))

        return (None, available_routes, None)
Exemplo n.º 18
0
def test_lock_expiry(
    raiden_network: List[RaidenService], token_addresses: List[TokenAddress], deposit: TokenAmount
) -> None:
    """Test lock expiry and removal."""
    alice_app, bob_app = raiden_network
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_raiden(alice_app),
        alice_app.default_registry.address,
        token_address,
    )
    assert token_network_address

    hold_event_handler = bob_app.raiden_event_handler
    wait_message_handler = bob_app.message_handler

    msg = "hold event handler necessary to control messages"
    assert isinstance(hold_event_handler, HoldRaidenEventHandler), msg
    assert isinstance(wait_message_handler, WaitForMessage), msg

    token_network = views.get_token_network_by_address(
        views.state_from_raiden(alice_app), token_network_address
    )
    assert token_network

    channel_state = get_channelstate(alice_app, bob_app, token_network_address)
    channel_identifier = channel_state.identifier

    assert (
        channel_identifier in token_network.partneraddresses_to_channelidentifiers[bob_app.address]
    )

    alice_to_bob_amount = PaymentAmount(10)
    identifier = factories.make_payment_id()
    target = TargetAddress(bob_app.address)
    transfer_1_secret = factories.make_secret(0)
    transfer_1_secrethash = sha256_secrethash(transfer_1_secret)
    transfer_2_secret = factories.make_secret(1)
    transfer_2_secrethash = sha256_secrethash(transfer_2_secret)

    hold_event_handler.hold_secretrequest_for(secrethash=transfer_1_secrethash)
    transfer1_received = wait_message_handler.wait_for_message(
        LockedTransfer, {"lock": {"secrethash": transfer_1_secrethash}}
    )
    transfer2_received = wait_message_handler.wait_for_message(
        LockedTransfer, {"lock": {"secrethash": transfer_2_secrethash}}
    )
    remove_expired_lock_received = wait_message_handler.wait_for_message(
        LockExpired, {"secrethash": transfer_1_secrethash}
    )

    alice_app.mediated_transfer_async(
        token_network_address=token_network_address,
        amount=alice_to_bob_amount,
        target=target,
        identifier=identifier,
        secret=transfer_1_secret,
    )
    transfer1_received.wait()

    alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_address)
    lock = channel.get_lock(alice_bob_channel_state.our_state, transfer_1_secrethash)
    assert lock

    # This is the current state of the protocol:
    #
    #    A -> B LockedTransfer
    #    B -> A SecretRequest
    #    - protocol didn't continue
    assert_synced_channel_state(
        token_network_address, alice_app, Balance(deposit), [lock], bob_app, Balance(deposit), []
    )

    # Verify lock is registered in both channel states
    alice_channel_state = get_channelstate(alice_app, bob_app, token_network_address)
    assert transfer_1_secrethash in alice_channel_state.our_state.secrethashes_to_lockedlocks

    bob_channel_state = get_channelstate(bob_app, alice_app, token_network_address)
    assert transfer_1_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks

    alice_chain_state = views.state_from_raiden(alice_app)
    assert transfer_1_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task

    remove_expired_lock_received.wait()

    alice_channel_state = get_channelstate(alice_app, bob_app, token_network_address)
    assert transfer_1_secrethash not in alice_channel_state.our_state.secrethashes_to_lockedlocks

    # Verify Bob received the message and processed the LockExpired message
    bob_channel_state = get_channelstate(bob_app, alice_app, token_network_address)
    assert transfer_1_secrethash not in bob_channel_state.partner_state.secrethashes_to_lockedlocks

    alice_chain_state = views.state_from_raiden(alice_app)
    assert transfer_1_secrethash not in alice_chain_state.payment_mapping.secrethashes_to_task

    # Make another transfer
    alice_to_bob_amount = PaymentAmount(10)
    identifier = factories.make_payment_id()

    hold_event_handler.hold_secretrequest_for(secrethash=transfer_2_secrethash)

    alice_app.mediated_transfer_async(
        token_network_address=token_network_address,
        amount=alice_to_bob_amount,
        target=target,
        identifier=identifier,
        secret=transfer_2_secret,
    )
    transfer2_received.wait()

    # Make sure the other transfer still exists
    alice_chain_state = views.state_from_raiden(alice_app)
    assert transfer_2_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task

    bob_channel_state = get_channelstate(bob_app, alice_app, token_network_address)
    assert transfer_2_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks