예제 #1
0
def run_test_echo_node_response(token_addresses, raiden_chain, network_wait):
    app0, app1, app2, echo_app = raiden_chain
    address_to_app = {app.raiden.address: app for app in raiden_chain}
    token_address = token_addresses[0]
    echo_api = RaidenAPI(echo_app.raiden)

    echo_node = EchoNode(echo_api, token_address)
    echo_node.ready.wait(timeout=30)
    assert echo_node.ready.is_set()
    expected = list()

    # Create some transfers
    for num, app in enumerate([app0, app1, app2]):
        amount = 1 + num
        payment_status = RaidenAPI(app.raiden).transfer_async(
            app.raiden.default_registry.address,
            token_address,
            amount,
            echo_app.raiden.address,
            10 ** (num + 1),
        )
        payment_status.payment_done.wait(timeout=20)
        expected.append(amount)

    while echo_node.num_handled_transfers < len(expected):
        gevent.sleep(.5)

    # Check that all transfers were handled correctly
    def test_events(handled_transfer):
        app = address_to_app[handled_transfer.initiator]
        events = RaidenAPI(app.raiden).get_raiden_events_payment_history(
            token_address=token_address,
        )

        received = {
            event.identifier: event
            for event in events
            if type(event) == EventPaymentReceivedSuccess
        }

        if len(received) != 1:
            return None
        transfer = received.popitem()[1]

        is_not_valid = (
            transfer.initiator != echo_app.raiden.address or
            transfer.identifier != handled_transfer.identifier + transfer.amount
        )

        if is_not_valid:
            return None
        return transfer

    for handled_transfer in echo_node.seen_transfers:
        assert wait_until(lambda: test_events(handled_transfer), network_wait)

    echo_node.stop()
예제 #2
0
def test_echo_node_response(token_addresses, raiden_chain, network_wait):
    app0, app1, app2, echo_app = raiden_chain
    address_to_app = {app.raiden.address: app for app in raiden_chain}
    token_address = token_addresses[0]
    echo_api = RaidenAPI(echo_app.raiden)

    echo_node = EchoNode(echo_api, token_address)
    echo_node.ready.wait(timeout=30)
    assert echo_node.ready.is_set()
    expected = list()

    # Create some transfers
    for num, app in enumerate([app0, app1, app2]):
        amount = 1 + num
        transfer_event = RaidenAPI(app.raiden).transfer_async(
            app.raiden.default_registry.address,
            token_address,
            amount,
            echo_app.raiden.address,
            10 ** (num + 1),
        )
        transfer_event.wait(timeout=20)
        expected.append(amount)

    while echo_node.num_handled_transfers < len(expected):
        gevent.sleep(.5)

    # Check that all transfers were handled correctly
    def test_events(handled_transfer):
        app = address_to_app[handled_transfer.initiator]
        events = RaidenAPI(app.raiden).get_raiden_events_payment_history(
            token_address=token_address,
        )

        received = {
            event.identifier: event
            for event in events
            if type(event) == EventPaymentReceivedSuccess
        }

        if len(received) != 1:
            return
        transfer = received.popitem()[1]

        is_not_valid = (
            transfer.initiator != echo_app.raiden.address or
            transfer.identifier != handled_transfer.identifier + transfer.amount
        )

        if is_not_valid:
            return
        return transfer

    for handled_transfer in echo_node.seen_transfers:
        assert wait_until(lambda: test_events(handled_transfer), network_wait)

    echo_node.stop()
예제 #3
0
def test_echo_node_response(token_addresses, raiden_chain, network_wait):
    app0, app1, app2, echo_app = raiden_chain
    address_to_app = {app.raiden.address: app for app in raiden_chain}
    token_address = token_addresses[0]
    echo_api = RaidenAPI(echo_app.raiden)

    echo_node = EchoNode(echo_api, token_address)
    echo_node.ready.wait(timeout=30)
    assert echo_node.ready.is_set()
    expected = list()

    # Create some transfers
    for num, app in enumerate([app0, app1, app2]):
        amount = 1 + num
        transfer_event = RaidenAPI(app.raiden).transfer_async(
            app.raiden.default_registry.address,
            token_address,
            amount,
            echo_app.raiden.address,
            10**(num + 1),
        )
        transfer_event.wait(timeout=20)
        expected.append(amount)

    while echo_node.num_handled_transfers < len(expected):
        gevent.sleep(.5)

    # Check that all transfers were handled correctly
    def test_events(handled_transfer):
        app = address_to_app[handled_transfer['initiator']]
        events = get_channel_events_for_token(
            app,
            app.raiden.default_registry.address,
            token_address,
            0,
        )
        received = {
            event['identifier']: event
            for event in events
            if event['event'] == 'EventTransferReceivedSuccess'
        }
        if len(received) != 1:
            return
        transfer = received.popitem()[1]
        if (transfer['initiator'] != echo_app.raiden.address
                or transfer['identifier'] !=
                handled_transfer['identifier'] + transfer['amount']):
            return
        return transfer

    for handled_transfer in echo_node.seen_transfers:
        assert wait_until(lambda: test_events(handled_transfer), network_wait)

    echo_node.stop()
예제 #4
0
def test_echo_node_response(token_addresses, raiden_chain):
    app0, app1, app2, echo_app = raiden_chain
    address_to_app = {app.raiden.address: app for app in raiden_chain}
    token_address = token_addresses[0]
    echo_api = RaidenAPI(echo_app.raiden)

    echo_node = EchoNode(echo_api, token_address)
    echo_node.ready.wait(timeout=30)
    assert echo_node.ready.is_set()

    expected = list()

    # Create some transfers
    for num, app in enumerate([app0, app1, app2]):
        amount = 1 + num
        transfer_event = RaidenAPI(app.raiden).transfer_async(
            app.raiden.default_registry.address,
            token_address,
            amount,
            echo_app.raiden.address,
            10**(num + 1),
        )
        transfer_event.wait(timeout=20)
        expected.append(amount)

    while echo_node.num_handled_transfers < len(expected):
        gevent.sleep(.5)

    # Check that all transfers were handled correctly
    for handled_transfer in echo_node.seen_transfers:
        app = address_to_app[handled_transfer['initiator']]
        events = get_channel_events_for_token(
            app.raiden.default_registry.address,
            app,
            token_address,
            0,
        )
        received = {}

        for event in events:
            if event['event'] == 'EventTransferReceivedSuccess':
                received[repr(event)] = event

        assert len(received) == 1
        transfer = list(received.values())[0]
        assert transfer['initiator'] == echo_app.raiden.address
        assert transfer['identifier'] == (handled_transfer['identifier'] +
                                          transfer['amount'])

    echo_node.stop()
예제 #5
0
class EchoNodeRunner(NodeRunner):
    def __init__(self, options: Dict[str, Any], ctx, token_address: typing.TokenAddress):
        super().__init__(options, ctx)
        self._token_address = token_address
        self._echo_node = None

    @property
    def welcome_string(self):
        return '{} [ECHO NODE]'.format(super().welcome_string)

    def _startup_hook(self):
        self._echo_node = EchoNode(self._raiden_api, self._token_address)

    def _shutdown_hook(self):
        self._echo_node.stop()
예제 #6
0
class EchoNodeRunner(NodeRunner):
    def __init__(self, options: Dict[str, Any], ctx, token_address: typing.TokenAddress):
        super().__init__(options, ctx)
        self._token_address = token_address
        self._echo_node = None

    @property
    def welcome_string(self):
        return '{} [ECHO NODE]'.format(super().welcome_string)

    def _startup_hook(self):
        self._echo_node = EchoNode(self._raiden_api, self._token_address)

    def _shutdown_hook(self):
        self._echo_node.stop()
def test_echo_node_response(token_addresses, raiden_chain):
    app0, app1, app2, echo_app = raiden_chain
    address_to_app = {app.raiden.address: app for app in raiden_chain}
    token_address = token_addresses[0]
    echo_api = RaidenAPI(echo_app.raiden)

    echo_node = EchoNode(echo_api, token_address)
    echo_node.ready.wait(timeout=30)
    assert echo_node.ready.is_set()

    expected = list()

    # Create some transfers
    for num, app in enumerate([app0, app1, app2]):
        amount = 1 + num
        transfer_event = RaidenAPI(app.raiden).transfer_async(
            token_address,
            amount,
            echo_app.raiden.address,
            10 ** (num + 1)
        )
        transfer_event.wait(timeout=20)
        expected.append(amount)

    while echo_node.num_handled_transfers < len(expected):
        gevent.sleep(.5)

    # Check that all transfers were handled correctly
    for handled_transfer in echo_node.seen_transfers:
        app = address_to_app[handled_transfer['initiator']]
        events = get_channel_events_for_token(app, token_address, 0)
        received = {}

        for event in events:
            if event['_event_type'] == 'EventTransferReceivedSuccess':
                received[repr(event)] = event

        assert len(received) == 1
        transfer = list(received.values())[0]
        assert transfer['initiator'] == echo_app.raiden.address
        assert transfer['identifier'] == (
            handled_transfer['identifier'] + transfer['amount']
        )

    echo_node.stop()
예제 #8
0
class EchoNodeRunner(NodeRunner):
    def __init__(self, options: Dict[str, Any], ctx: Context, token_address: TokenAddress) -> None:
        super().__init__(options, ctx)
        self._token_address = token_address
        self._echo_node: Optional[EchoNode] = None

    def run(self) -> None:
        super().run()
        self._start_services()

    @property
    def welcome_string(self) -> str:
        return "{} [ECHO NODE]".format(super().welcome_string)

    def _startup_hook(self) -> None:
        if self.raiden_api is not None:
            self._echo_node = EchoNode(self.raiden_api, self._token_address)

    def _shutdown_hook(self) -> None:
        if self._echo_node:
            self._echo_node.stop()
예제 #9
0
def test_echo_node_response(token_addresses, raiden_chain, retry_timeout):
    app0, app1, echo_app = raiden_chain
    token_address = token_addresses[0]
    registry_address = echo_app.raiden.default_registry.address

    echo_api = RaidenAPI(echo_app.raiden)
    echo_node = EchoNode(echo_api, token_address)

    message_handler = WaitForMessage()
    echo_app.raiden.message_handler = message_handler

    echo_node.ready.wait(timeout=30)
    assert echo_node.ready.is_set()

    transfer_timeout = 10

    wait_for = list()
    for num, app in enumerate([app0, app1]):
        amount = PaymentAmount(1 + num)
        identifier = PaymentID(10 ** (num + 1))
        secret, secrethash = make_secret_with_hash()

        payment_status = RaidenAPI(app.raiden).transfer_async(
            registry_address=registry_address,
            token_address=token_address,
            amount=amount,
            target=echo_app.raiden.address,
            identifier=identifier,
            secret=secret,
            secrethash=secrethash,
        )

        wait = message_handler.wait_for_message(Unlock, {"secret": secret})
        wait_for.append((wait, app.raiden.address, amount, identifier))

        msg = (
            f"Transfer {identifier} from "
            f"{to_checksum_address(app.raiden.address)} to "
            f"{to_checksum_address(echo_app.raiden.address)} timed out after "
            f"{transfer_timeout}"
        )
        timeout = gevent.Timeout(transfer_timeout, exception=RuntimeError(msg))
        with watch_for_unlock_failures(*raiden_chain), timeout:
            payment_status.payment_done.wait()

        echo_identifier = PaymentID(identifier + amount)
        msg = (
            f"Response transfer {echo_identifier} from echo node "
            f"{to_checksum_address(echo_app.raiden.address)} to "
            f"{to_checksum_address(app.raiden.address)} timed out after "
            f"{transfer_timeout}"
        )
        with gevent.Timeout(transfer_timeout, exception=RuntimeError(msg)):
            result = wait_for_received_transfer_result(
                raiden=app.raiden,
                payment_identifier=echo_identifier,
                amount=amount,
                retry_timeout=retry_timeout,
                secrethash=secrethash,
            )
            assert result == TransferWaitResult.UNLOCKED

    for wait, sender, amount, ident in wait_for:
        wait.wait()
        assert search_for_item(
            echo_app.raiden.wal.storage.get_events(),
            EventPaymentReceivedSuccess,
            {
                "amount": amount,
                "identifier": ident,
                "initiator": sender,
                "token_network_registry_address": registry_address,
            },
        )

    echo_node.stop()
예제 #10
0
def test_echo_node_lottery(token_addresses, raiden_chain, network_wait):
    app0, app1, app2, app3, echo_app, app4, app5, app6 = raiden_chain
    address_to_app = {app.raiden.address: app for app in raiden_chain}
    token_address = token_addresses[0]
    echo_api = RaidenAPI(echo_app.raiden)

    echo_node = EchoNode(echo_api, token_address)
    echo_node.ready.wait(timeout=30)
    assert echo_node.ready.is_set()

    transfer_timeout = 10

    # Let 6 participants enter the pool
    amount = 7
    for num, app in enumerate([app0, app1, app2, app3, app4, app5]):
        identifier = 100 * num
        with watch_for_unlock_failures(*raiden_chain):
            transfer_and_await(
                app=app,
                token_address=token_address,
                target=echo_app.raiden.address,
                amount=amount,
                identifier=identifier,
                timeout=transfer_timeout,
            )

    # test duplicated identifier + amount is ignored
    with watch_for_unlock_failures(*raiden_chain):
        transfer_and_await(
            app=app5,
            token_address=token_address,
            target=echo_app.raiden.address,
            amount=amount,
            identifier=500,  # app5 used this identifier before
            timeout=transfer_timeout,
        )

    # test pool size querying
    pool_query_identifier = 77  # unused identifier different from previous one
    with watch_for_unlock_failures(*raiden_chain):
        transfer_and_await(
            app=app5,
            token_address=token_address,
            target=echo_app.raiden.address,
            amount=amount,
            identifier=pool_query_identifier,
            timeout=transfer_timeout,
        )

    # fill the pool
    with watch_for_unlock_failures(*raiden_chain):
        transfer_and_await(
            app=app6,
            token_address=token_address,
            target=echo_app.raiden.address,
            amount=amount,
            identifier=600,
            timeout=transfer_timeout,
        )

    def get_echoed_transfer(sent_transfer) -> Optional[EventPaymentReceivedSuccess]:
        """For a given transfer sent to echo node, get the corresponding echoed transfer"""
        app = address_to_app[sent_transfer.initiator]
        events = RaidenAPI(app.raiden).get_raiden_events_payment_history(
            token_address=token_address
        )
        for event in events:
            if not type(event) == EventPaymentReceivedSuccess:
                continue
            assert isinstance(event, EventPaymentReceivedSuccess), MYPY_ANNOTATION
            if not (
                event.initiator == echo_app.raiden.address
                and event.identifier == sent_transfer.identifier + event.amount
            ):
                continue

            return event

        return None

    def received_events_when_len(size: int) -> Optional[List[EventPaymentReceivedSuccess]]:
        """Return transfers received from echo_node when there's size transfers"""
        received_events = []
        # Check that payout was generated and pool_size_query answered
        for handled_transfer in echo_node.seen_transfers:
            event = get_echoed_transfer(handled_transfer)
            if not event:
                continue

            received_events.append(event)

        log.debug(
            "Checking number of received events",
            received_events=received_events,
            expected_size=size,
            actual_size=len(received_events),
            seen_transfers=echo_node.seen_transfers,
            received_transfers=received_events,
        )
        if len(received_events) == size:
            return received_events

        return None

    # wait for the expected echoed transfers to be handled
    received = wait_until(func=lambda: received_events_when_len(2), wait_for=network_wait)
    assert received

    received.sort(key=lambda transfer: transfer.amount)

    pool_query = received[0]
    assert pool_query.amount == 6
    assert pool_query.identifier == pool_query_identifier + 6

    winning_transfer = received[1]
    assert winning_transfer.initiator == echo_app.raiden.address
    assert winning_transfer.amount == 49
    assert (winning_transfer.identifier - 49) % 10 == 0

    echo_node.stop()
예제 #11
0
def test_echo_node_lottery(token_addresses, raiden_chain):
    app0, app1, app2, app3, echo_app, app4, app5, app6 = raiden_chain
    address_to_app = {app.raiden.address: app for app in raiden_chain}
    token_address = token_addresses[0]
    echo_api = RaidenAPI(echo_app.raiden)

    echo_node = EchoNode(echo_api, token_address)
    echo_node.ready.wait(timeout=30)
    assert echo_node.ready.is_set()

    expected = list()

    # Let 6 participants enter the pool
    amount = 7
    for num, app in enumerate([app0, app1, app2, app3, app4, app5]):
        transfer_event = RaidenAPI(app.raiden).transfer_async(
            token_address, amount, echo_app.raiden.address, 10**(num + 1))
        transfer_event.wait(timeout=20)
        expected.append(amount)

    # test duplicated identifier + amount is ignored
    transfer_event = RaidenAPI(app5.raiden).transfer_async(
        token_address,
        amount,  # same amount as before
        echo_app.raiden.address,
        10**6  # app5 used this identifier before
    ).wait(timeout=20)

    # test pool size querying
    pool_query_identifier = 77  # unused identifier different from previous one
    transfer_event = RaidenAPI(app5.raiden).transfer_async(
        token_address, amount, echo_app.raiden.address,
        pool_query_identifier).wait(timeout=20)
    expected.append(amount)

    # fill the pool
    transfer_event = RaidenAPI(app6.raiden).transfer_async(
        token_address, amount, echo_app.raiden.address, 10**7).wait(timeout=20)
    expected.append(amount)

    while echo_node.num_handled_transfers < len(expected):
        gevent.sleep(.5)

    received = {}
    # Check that payout was generated and pool_size_query answered
    for handled_transfer in echo_node.seen_transfers:
        app = address_to_app[handled_transfer['initiator']]
        events = get_channel_events_for_token(app, token_address, 0)

        for event in events:
            if event['_event_type'] == 'EventTransferReceivedSuccess':
                received[repr(event)] = event

    assert len(received) == 2

    received = sorted(received.values(),
                      key=lambda transfer: transfer['amount'])

    pool_query = received[0]
    assert pool_query['amount'] == 6
    assert pool_query['identifier'] == pool_query_identifier + 6

    winning_transfer = received[1]
    assert winning_transfer['initiator'] == echo_app.raiden.address
    assert winning_transfer['amount'] == 49
    assert (winning_transfer['identifier'] - 49) % 10 == 0

    echo_node.stop()
예제 #12
0
def run_test_echo_node_lottery(token_addresses, raiden_chain, network_wait):
    app0, app1, app2, app3, echo_app, app4, app5, app6 = raiden_chain
    address_to_app = {app.raiden.address: app for app in raiden_chain}
    token_address = token_addresses[0]
    echo_api = RaidenAPI(echo_app.raiden)

    echo_node = EchoNode(echo_api, token_address)
    echo_node.ready.wait(timeout=30)
    assert echo_node.ready.is_set()

    expected = list()

    # Let 6 participants enter the pool
    amount = 7
    for num, app in enumerate([app0, app1, app2, app3, app4, app5]):
        payment_status = RaidenAPI(app.raiden).transfer_async(
            app.raiden.default_registry.address,
            token_address,
            amount,
            echo_app.raiden.address,
            10 ** (num + 1),
        )
        payment_status.payment_done.wait(timeout=20)
        expected.append(amount)

    # test duplicated identifier + amount is ignored
    payment_status = RaidenAPI(app5.raiden).transfer_async(
        app.raiden.default_registry.address,
        token_address,
        amount,  # same amount as before
        echo_app.raiden.address,
        10 ** 6,  # app5 used this identifier before
    ).payment_done.wait(timeout=20)

    # test pool size querying
    pool_query_identifier = 77  # unused identifier different from previous one
    payment_status = RaidenAPI(app5.raiden).transfer_async(
        app.raiden.default_registry.address,
        token_address,
        amount,
        echo_app.raiden.address,
        pool_query_identifier,
    ).payment_done.wait(timeout=20)
    expected.append(amount)

    # fill the pool
    payment_status = RaidenAPI(app6.raiden).transfer_async(
        app.raiden.default_registry.address,
        token_address,
        amount,
        echo_app.raiden.address,
        10 ** 7,
    ).payment_done.wait(timeout=20)
    expected.append(amount)

    while echo_node.num_handled_transfers < len(expected):
        gevent.sleep(.5)

    def get_echoed_transfer(sent_transfer):
        """For a given transfer sent to echo node, get the corresponding echoed transfer"""
        app = address_to_app[sent_transfer.initiator]
        events = RaidenAPI(app.raiden).get_raiden_events_payment_history(
            token_address=token_address,
        )

        def is_valid(event):
            return (
                type(event) == EventPaymentReceivedSuccess and
                event.initiator == echo_app.raiden.address and
                event.identifier == sent_transfer.identifier + event.amount
            )

        received = {
            event.identifier: event
            for event in events
            if is_valid(event)
        }

        if len(received) != 1:
            return None
        return received.popitem()[1]

    def received_is_of_size(size):
        """Return transfers received from echo_node when there's size transfers"""
        received = {}
        # Check that payout was generated and pool_size_query answered
        for handled_transfer in echo_node.seen_transfers:
            event = get_echoed_transfer(handled_transfer)
            if not event:
                continue
            received[event.identifier] = event
        if len(received) == size:
            return received

        return None

    # wait for the expected echoed transfers to be handled
    received = wait_until(lambda: received_is_of_size(2), 2 * network_wait)
    assert received

    received = sorted(received.values(), key=lambda transfer: transfer.amount)

    pool_query = received[0]
    assert pool_query.amount == 6
    assert pool_query.identifier == pool_query_identifier + 6

    winning_transfer = received[1]
    assert winning_transfer.initiator == echo_app.raiden.address
    assert winning_transfer.amount == 49
    assert (winning_transfer.identifier - 49) % 10 == 0

    echo_node.stop()
예제 #13
0
def test_echo_node_lottery(token_addresses, raiden_chain, network_wait):
    app0, app1, app2, app3, echo_app, app4, app5, app6 = raiden_chain
    address_to_app = {app.raiden.address: app for app in raiden_chain}
    token_address = token_addresses[0]
    echo_api = RaidenAPI(echo_app.raiden)

    echo_node = EchoNode(echo_api, token_address)
    echo_node.ready.wait(timeout=30)
    assert echo_node.ready.is_set()

    expected = list()

    # Let 6 participants enter the pool
    amount = 7
    for num, app in enumerate([app0, app1, app2, app3, app4, app5]):
        transfer_event = RaidenAPI(app.raiden).transfer_async(
            app.raiden.default_registry.address,
            token_address,
            amount,
            echo_app.raiden.address,
            10 ** (num + 1),
        )
        transfer_event.wait(timeout=20)
        expected.append(amount)

    # test duplicated identifier + amount is ignored
    transfer_event = RaidenAPI(app5.raiden).transfer_async(
        app.raiden.default_registry.address,
        token_address,
        amount,  # same amount as before
        echo_app.raiden.address,
        10 ** 6,  # app5 used this identifier before
    ).wait(timeout=20)

    # test pool size querying
    pool_query_identifier = 77  # unused identifier different from previous one
    transfer_event = RaidenAPI(app5.raiden).transfer_async(
        app.raiden.default_registry.address,
        token_address,
        amount,
        echo_app.raiden.address,
        pool_query_identifier,
    ).wait(timeout=20)
    expected.append(amount)

    # fill the pool
    transfer_event = RaidenAPI(app6.raiden).transfer_async(
        app.raiden.default_registry.address,
        token_address,
        amount,
        echo_app.raiden.address,
        10 ** 7,
    ).wait(timeout=20)
    expected.append(amount)

    while echo_node.num_handled_transfers < len(expected):
        gevent.sleep(.5)

    def get_echoed_transfer(sent_transfer):
        """For a given transfer sent to echo node, get the corresponding echoed transfer"""
        app = address_to_app[sent_transfer.initiator]
        events = RaidenAPI(app.raiden).get_raiden_events_payment_history(
            token_address=token_address,
        )

        def is_valid(event):
            return (
                type(event) == EventPaymentReceivedSuccess and
                event.initiator == echo_app.raiden.address and
                event.identifier == sent_transfer.identifier + event.amount
            )

        received = {
            event.identifier: event
            for event in events
            if is_valid(event)
        }

        if len(received) != 1:
            return
        return received.popitem()[1]

    def received_is_of_size(size):
        """Return transfers received from echo_node when there's size transfers"""
        received = {}
        # Check that payout was generated and pool_size_query answered
        for handled_transfer in echo_node.seen_transfers:
            event = get_echoed_transfer(handled_transfer)
            if not event:
                continue
            received[event.identifier] = event
        if len(received) == size:
            return received

    # wait for the expected echoed transfers to be handled
    received = wait_until(lambda: received_is_of_size(2), 2 * network_wait)
    assert received

    received = sorted(received.values(), key=lambda transfer: transfer.amount)

    pool_query = received[0]
    assert pool_query.amount == 6
    assert pool_query.identifier == pool_query_identifier + 6

    winning_transfer = received[1]
    assert winning_transfer.initiator == echo_app.raiden.address
    assert winning_transfer.amount == 49
    assert (winning_transfer.identifier - 49) % 10 == 0

    echo_node.stop()
def test_echo_node_lottery(token_addresses, raiden_chain):
    app0, app1, app2, app3, echo_app, app4, app5, app6 = raiden_chain
    address_to_app = {app.raiden.address: app for app in raiden_chain}
    token_address = token_addresses[0]
    echo_api = RaidenAPI(echo_app.raiden)

    echo_node = EchoNode(echo_api, token_address)
    echo_node.ready.wait(timeout=30)
    assert echo_node.ready.is_set()

    expected = list()

    # Let 6 participants enter the pool
    amount = 7
    for num, app in enumerate([app0, app1, app2, app3, app4, app5]):
        transfer_event = RaidenAPI(app.raiden).transfer_async(
            token_address,
            amount,
            echo_app.raiden.address,
            10 ** (num + 1)
        )
        transfer_event.wait(timeout=20)
        expected.append(amount)

    # test duplicated identifier + amount is ignored
    transfer_event = RaidenAPI(app5.raiden).transfer_async(
        token_address,
        amount,  # same amount as before
        echo_app.raiden.address,
        10 ** 6  # app5 used this identifier before
    ).wait(timeout=20)

    # test pool size querying
    pool_query_identifier = 77  # unused identifier different from previous one
    transfer_event = RaidenAPI(app5.raiden).transfer_async(
        token_address,
        amount,
        echo_app.raiden.address,
        pool_query_identifier
    ).wait(timeout=20)
    expected.append(amount)

    # fill the pool
    transfer_event = RaidenAPI(app6.raiden).transfer_async(
        token_address,
        amount,
        echo_app.raiden.address,
        10 ** 7
    ).wait(timeout=20)
    expected.append(amount)

    while echo_node.num_handled_transfers < len(expected):
        gevent.sleep(.5)

    received = {}
    # Check that payout was generated and pool_size_query answered
    for handled_transfer in echo_node.seen_transfers:
        app = address_to_app[handled_transfer['initiator']]
        events = get_channel_events_for_token(app, token_address, 0)

        for event in events:
            if event['_event_type'] == 'EventTransferReceivedSuccess':
                received[repr(event)] = event

    assert len(received) == 2

    received = sorted(received.values(), key=lambda transfer: transfer['amount'])

    pool_query = received[0]
    assert pool_query['amount'] == 6
    assert pool_query['identifier'] == pool_query_identifier + 6

    winning_transfer = received[1]
    assert winning_transfer['initiator'] == echo_app.raiden.address
    assert winning_transfer['amount'] == 49
    assert (winning_transfer['identifier'] - 49) % 10 == 0

    echo_node.stop()