async def main(start_port: int,
               show_timing: bool = False,
               routing: bool = False):

    genesis = await default_genesis_txns()
    if not genesis:
        print("Error retrieving ledger genesis transactions")
        sys.exit(1)

    alice = None
    faber = None
    alice_router = None
    run_timer = log_timer("Total runtime:")
    run_timer.start()

    try:
        alice = AliceAgent(start_port,
                           genesis_data=genesis,
                           timing=show_timing)
        await alice.listen_webhooks(start_port + 2)

        faber = FaberAgent(start_port + 3,
                           genesis_data=genesis,
                           timing=show_timing)
        await faber.listen_webhooks(start_port + 5)
        await faber.register_did()

        if routing:
            alice_router = RoutingAgent(start_port + 6,
                                        genesis_data=genesis,
                                        timing=show_timing)
            await alice_router.listen_webhooks(start_port + 8)
            await alice_router.register_did()

        with log_timer("Startup duration:"):
            if alice_router:
                await alice_router.start_process()
            await alice.start_process()
            await faber.start_process()

        with log_timer("Publish duration:"):
            await faber.publish_defs()

        with log_timer("Connect duration:"):
            if routing:
                router_invite = await alice_router.get_invite()
                alice_router_conn_id = await alice.receive_invite(router_invite
                                                                  )
                await asyncio.wait_for(alice.detect_connection(), 30)

            invite = await faber.get_invite()

            if routing:
                conn_id = await alice.receive_invite(invite, accept="manual")
                await alice.establish_inbound(conn_id, alice_router_conn_id)
                await alice.accept_invite(conn_id)
                await asyncio.wait_for(alice.detect_connection(), 30)
            else:
                await alice.receive_invite(invite)

            await asyncio.wait_for(faber.detect_connection(), 30)

        if show_timing:
            await alice.reset_timing()
            await faber.reset_timing()
            if routing:
                await alice_router.reset_timing()

        issue_count = 300
        batch_size = 100

        semaphore = asyncio.Semaphore(10)

        async def send():
            await semaphore.acquire()
            asyncio.ensure_future(faber.send_credential()).add_done_callback(
                lambda fut: semaphore.release())

        recv_timer = alice.log_timer(f"Received {issue_count} credentials in ")
        recv_timer.start()
        batch_timer = faber.log_timer(
            f"Started {batch_size} credential exchanges in ")
        batch_timer.start()

        async def check_received(agent, issue_count, pb):
            reported = 0
            iter_pb = iter(pb) if pb else None
            while True:
                pending, total = agent.check_received_creds()
                if iter_pb and total > reported:
                    try:
                        while next(iter_pb) < total:
                            pass
                    except StopIteration:
                        iter_pb = None
                reported = total
                if total == issue_count and not pending:
                    break
                await asyncio.wait_for(agent.update_creds(), 30)

        with progress() as pb:
            receive_task = None
            try:
                issue_pg = pb(range(issue_count), label="Issuing credentials")
                receive_pg = pb(range(issue_count),
                                label="Receiving credentials")
                issue_task = asyncio.ensure_future(
                    check_received(faber, issue_count, issue_pg))
                receive_task = asyncio.ensure_future(
                    check_received(alice, issue_count, receive_pg))
                with faber.log_timer(
                        f"Done starting {issue_count} credential exchanges in "
                ):
                    for idx in range(0, issue_count):
                        await send()
                        if not (idx +
                                1) % batch_size and idx < issue_count - 1:
                            batch_timer.reset()

                await issue_task
                await receive_task
            except KeyboardInterrupt:
                if receive_task:
                    receive_task.cancel()
                print("Canceled")

        recv_timer.stop()
        avg = recv_timer.duration / issue_count
        alice.log(f"Average time per credential: {avg:.2f}s ({1/avg:.2f}/s)")

        if show_timing:
            timing = await alice.fetch_timing()
            if timing:
                for line in alice.format_timing(timing):
                    alice.log(line)

            timing = await faber.fetch_timing()
            if timing:
                for line in faber.format_timing(timing):
                    faber.log(line)
            if routing:
                timing = await alice_router.fetch_timing()
                if timing:
                    for line in alice_router.format_timing(timing):
                        alice_router.log(line)

    finally:
        terminated = True
        try:
            if alice:
                await alice.terminate()
        except Exception:
            LOGGER.exception("Error terminating agent:")
            terminated = False
        try:
            if faber:
                await faber.terminate()
        except Exception:
            LOGGER.exception("Error terminating agent:")
            terminated = False
        try:
            if alice_router:
                await alice_router.terminate()
        except Exception:
            LOGGER.exception("Error terminating agent:")
            terminated = False

    run_timer.stop()
    await asyncio.sleep(0.1)

    if not terminated:
        os._exit(1)
Exemple #2
0
async def main(
    start_port: int,
    threads: int = 20,
    ping_only: bool = False,
    show_timing: bool = False,
    routing: bool = False,
    issue_count: int = 300,
):

    genesis = await default_genesis_txns()
    if not genesis:
        print("Error retrieving ledger genesis transactions")
        sys.exit(1)

    alice = None
    faber = None
    alice_router = None
    run_timer = log_timer("Total runtime:")
    run_timer.start()

    try:
        alice = AliceAgent(start_port,
                           genesis_data=genesis,
                           timing=show_timing)
        await alice.listen_webhooks(start_port + 2)

        faber = FaberAgent(start_port + 3,
                           genesis_data=genesis,
                           timing=show_timing)
        await faber.listen_webhooks(start_port + 5)
        await faber.register_did()

        if routing:
            alice_router = RoutingAgent(start_port + 6,
                                        genesis_data=genesis,
                                        timing=show_timing)
            await alice_router.listen_webhooks(start_port + 8)
            await alice_router.register_did()

        with log_timer("Startup duration:"):
            if alice_router:
                await alice_router.start_process()
            await alice.start_process()
            await faber.start_process()

        if not ping_only:
            with log_timer("Publish duration:"):
                await faber.publish_defs()
                # await alice.set_tag_policy(faber.credential_definition_id, ["name"])

        with log_timer("Connect duration:"):
            if routing:
                router_invite = await alice_router.get_invite()
                alice_router_conn_id = await alice.receive_invite(router_invite
                                                                  )
                await asyncio.wait_for(alice.detect_connection(), 30)

            invite = await faber.get_invite()

            if routing:
                conn_id = await alice.receive_invite(invite, accept="manual")
                await alice.establish_inbound(conn_id, alice_router_conn_id)
                await alice.accept_invite(conn_id)
                await asyncio.wait_for(alice.detect_connection(), 30)
            else:
                await alice.receive_invite(invite)

            await asyncio.wait_for(faber.detect_connection(), 30)

        if show_timing:
            await alice.reset_timing()
            await faber.reset_timing()
            if routing:
                await alice_router.reset_timing()

        batch_size = 100

        semaphore = asyncio.Semaphore(threads)

        def done_send(fut: asyncio.Task):
            semaphore.release()
            faber.check_task_exception(fut)

        async def send_credential(index: int):
            await semaphore.acquire()
            comment = f"issue test credential {index}"
            attributes = {
                "name": "Alice Smith",
                "date": "2018-05-28",
                "degree": "Maths",
                "age": "24",
            }
            asyncio.ensure_future(faber.send_credential(
                attributes, comment)).add_done_callback(done_send)

        async def check_received_creds(agent, issue_count, pb):
            reported = 0
            iter_pb = iter(pb) if pb else None
            while True:
                pending, total = await agent.check_received_creds()
                complete = total - pending
                if reported == complete:
                    await asyncio.wait_for(agent.update_creds(), 30)
                    continue
                if iter_pb and complete > reported:
                    try:
                        while next(iter_pb) < complete:
                            pass
                    except StopIteration:
                        iter_pb = None
                reported = complete
                if reported == issue_count:
                    break

        async def send_ping(index: int):
            await semaphore.acquire()
            asyncio.ensure_future(faber.send_ping(
                str(index))).add_done_callback(done_send)

        async def check_received_pings(agent, issue_count, pb):
            reported = 0
            iter_pb = iter(pb) if pb else None
            while True:
                pings = await agent.check_received_pings()
                complete = sum(len(tids) for tids in pings.values())
                if complete == reported:
                    await asyncio.wait_for(agent.update_pings(), 30)
                    continue
                if iter_pb and complete > reported:
                    try:
                        while next(iter_pb) < complete:
                            pass
                    except StopIteration:
                        iter_pb = None
                reported = complete
                if reported >= issue_count:
                    break

        if ping_only:
            recv_timer = faber.log_timer(
                f"Completed {issue_count} ping exchanges in")
            batch_timer = faber.log_timer(
                f"Started {batch_size} ping exchanges in")
        else:
            recv_timer = faber.log_timer(
                f"Completed {issue_count} credential exchanges in")
            batch_timer = faber.log_timer(
                f"Started {batch_size} credential exchanges in")
        recv_timer.start()
        batch_timer.start()

        with progress() as pb:
            receive_task = None
            try:
                if ping_only:
                    issue_pg = pb(range(issue_count), label="Sending pings")
                    receive_pg = pb(range(issue_count),
                                    label="Responding pings")
                    check_received = check_received_pings
                    send = send_ping
                    completed = f"Done sending {issue_count} pings in"
                else:
                    issue_pg = pb(range(issue_count),
                                  label="Issuing credentials")
                    receive_pg = pb(range(issue_count),
                                    label="Receiving credentials")
                    check_received = check_received_creds
                    send = send_credential
                    completed = f"Done starting {issue_count} credential exchanges in"

                issue_task = asyncio.ensure_future(
                    check_received(faber, issue_count, issue_pg))
                issue_task.add_done_callback(faber.check_task_exception)
                receive_task = asyncio.ensure_future(
                    check_received(alice, issue_count, receive_pg))
                receive_task.add_done_callback(alice.check_task_exception)
                with faber.log_timer(completed):
                    for idx in range(0, issue_count):
                        await send(idx + 1)
                        if not (idx +
                                1) % batch_size and idx < issue_count - 1:
                            batch_timer.reset()

                await issue_task
                await receive_task
            except KeyboardInterrupt:
                if receive_task:
                    receive_task.cancel()
                print("Canceled")

        recv_timer.stop()
        avg = recv_timer.duration / issue_count
        item_short = "ping" if ping_only else "cred"
        item_long = "ping exchange" if ping_only else "credential"
        faber.log(f"Average time per {item_long}: {avg:.2f}s ({1/avg:.2f}/s)")

        if alice.postgres:
            await alice.collect_postgres_stats(f"{issue_count} {item_short}s")
            for line in alice.format_postgres_stats():
                alice.log(line)
        if faber.postgres:
            await faber.collect_postgres_stats(f"{issue_count} {item_short}s")
            for line in faber.format_postgres_stats():
                faber.log(line)

        if show_timing:
            timing = await alice.fetch_timing()
            if timing:
                for line in alice.format_timing(timing):
                    alice.log(line)

            timing = await faber.fetch_timing()
            if timing:
                for line in faber.format_timing(timing):
                    faber.log(line)
            if routing:
                timing = await alice_router.fetch_timing()
                if timing:
                    for line in alice_router.format_timing(timing):
                        alice_router.log(line)

    finally:
        terminated = True
        try:
            if alice:
                await alice.terminate()
        except Exception:
            LOGGER.exception("Error terminating agent:")
            terminated = False
        try:
            if faber:
                await faber.terminate()
        except Exception:
            LOGGER.exception("Error terminating agent:")
            terminated = False
        try:
            if alice_router:
                await alice_router.terminate()
        except Exception:
            LOGGER.exception("Error terminating agent:")
            terminated = False

    run_timer.stop()
    await asyncio.sleep(0.1)

    if not terminated:
        os._exit(1)
async def main(
    start_port: int,
    threads: int = 20,
    action: str = None,
    show_timing: bool = False,
    multitenant: bool = False,
    mediation: bool = False,
    use_did_exchange: bool = False,
    revocation: bool = False,
    tails_server_base_url: str = None,
    issue_count: int = 300,
    wallet_type: str = None,
):

    genesis = await default_genesis_txns()
    if not genesis:
        print("Error retrieving ledger genesis transactions")
        sys.exit(1)

    alice = None
    faber = None
    alice_mediator_agent = None
    faber_mediator_agent = None
    run_timer = log_timer("Total runtime:")
    run_timer.start()

    try:
        alice = AliceAgent(
            start_port,
            genesis_data=genesis,
            timing=show_timing,
            multitenant=multitenant,
            mediation=mediation,
            wallet_type=wallet_type,
        )
        await alice.listen_webhooks(start_port + 2)

        faber = FaberAgent(
            start_port + 3,
            genesis_data=genesis,
            timing=show_timing,
            tails_server_base_url=tails_server_base_url,
            multitenant=multitenant,
            mediation=mediation,
            wallet_type=wallet_type,
        )
        await faber.listen_webhooks(start_port + 5)
        await faber.register_did()

        with log_timer("Startup duration:"):
            await alice.start_process()
            await faber.start_process()

            if mediation:
                alice_mediator_agent = await start_mediator_agent(
                    start_port + 8, genesis)
                if not alice_mediator_agent:
                    raise Exception("Mediator agent returns None :-(")
                faber_mediator_agent = await start_mediator_agent(
                    start_port + 11, genesis)
                if not faber_mediator_agent:
                    raise Exception("Mediator agent returns None :-(")
            else:
                alice_mediator_agent = None
                faber_mediator_agent = None

        with log_timer("Connect duration:"):
            if multitenant:
                # create an initial managed sub-wallet (also mediated)
                await alice.register_or_switch_wallet(
                    "Alice.initial",
                    webhook_port=None,
                    mediator_agent=alice_mediator_agent,
                )
                await faber.register_or_switch_wallet(
                    "Faber.initial",
                    public_did=True,
                    webhook_port=None,
                    mediator_agent=faber_mediator_agent,
                )
            elif mediation:
                # we need to pre-connect the agent(s) to their mediator (use the same
                # mediator for both)
                if not await connect_wallet_to_mediator(
                        alice, alice_mediator_agent):
                    log_msg("Mediation setup FAILED :-(")
                    raise Exception("Mediation setup FAILED :-(")
                if not await connect_wallet_to_mediator(
                        faber, faber_mediator_agent):
                    log_msg("Mediation setup FAILED :-(")
                    raise Exception("Mediation setup FAILED :-(")

            invite = await faber.get_invite(use_did_exchange)
            await alice.receive_invite(invite["invitation"])
            await asyncio.wait_for(faber.detect_connection(), 30)

        if action != "ping":
            with log_timer("Publish duration:"):
                await faber.publish_defs(revocation)
            # cache the credential definition
            await alice.fetch_credential_definition(
                faber.credential_definition_id)

        if show_timing:
            await alice.reset_timing()
            await faber.reset_timing()
            if mediation:
                await alice_mediator_agent.reset_timing()
                await faber_mediator_agent.reset_timing()

        batch_size = 100

        semaphore = asyncio.Semaphore(threads)

        def done_propose(fut: asyncio.Task):
            semaphore.release()
            alice.check_task_exception(fut)

        def done_send(fut: asyncio.Task):
            semaphore.release()
            faber.check_task_exception(fut)

        def test_cred(index: int) -> dict:
            return {
                "name": "Alice Smith",
                "date": f"{2020+index}-05-28",
                "degree": "Maths",
                "age": "24",
            }

        async def propose_credential(index: int):
            await semaphore.acquire()
            comment = f"propose test credential {index}"
            attributes = test_cred(index)
            asyncio.ensure_future(
                alice.propose_credential(
                    attributes, faber.credential_definition_id, comment,
                    not revocation)).add_done_callback(done_propose)

        async def send_credential(index: int):
            await semaphore.acquire()
            comment = f"issue test credential {index}"
            attributes = test_cred(index)
            asyncio.ensure_future(
                faber.send_credential(
                    attributes, comment,
                    not revocation)).add_done_callback(done_send)

        async def check_received_creds(agent, issue_count, pb):
            reported = 0
            iter_pb = iter(pb) if pb else None
            while True:
                pending, total = await agent.check_received_creds()
                complete = total - pending
                if reported == complete:
                    await asyncio.wait_for(agent.update_creds(), 30)
                    continue
                if iter_pb and complete > reported:
                    try:
                        while next(iter_pb) < complete:
                            pass
                    except StopIteration:
                        iter_pb = None
                reported = complete
                if reported == issue_count:
                    break

        async def send_ping(index: int):
            await semaphore.acquire()
            asyncio.ensure_future(faber.send_ping(
                str(index))).add_done_callback(done_send)

        async def check_received_pings(agent, issue_count, pb):
            reported = 0
            iter_pb = iter(pb) if pb else None
            while True:
                pings = await agent.check_received_pings()
                complete = sum(len(tids) for tids in pings.values())
                if complete == reported:
                    await asyncio.wait_for(agent.update_pings(), 30)
                    continue
                if iter_pb and complete > reported:
                    try:
                        while next(iter_pb) < complete:
                            pass
                    except StopIteration:
                        iter_pb = None
                reported = complete
                if reported >= issue_count:
                    break

        if action == "ping":
            recv_timer = faber.log_timer(
                f"Completed {issue_count} ping exchanges in")
            batch_timer = faber.log_timer(
                f"Started {batch_size} ping exchanges in")
        else:
            recv_timer = faber.log_timer(
                f"Completed {issue_count} credential exchanges in")
            batch_timer = faber.log_timer(
                f"Started {batch_size} credential exchanges in")
        recv_timer.start()
        batch_timer.start()

        with progress() as pb:
            receive_task = None
            try:
                if action == "ping":
                    issue_pg = pb(range(issue_count), label="Sending pings")
                    receive_pg = pb(range(issue_count),
                                    label="Responding pings")
                    check_received = check_received_pings
                    send = send_ping
                    completed = f"Done sending {issue_count} pings in"
                else:
                    issue_pg = pb(range(issue_count),
                                  label="Issuing credentials")
                    receive_pg = pb(range(issue_count),
                                    label="Receiving credentials")
                    check_received = check_received_creds
                    if action == "propose":
                        send = propose_credential
                    else:
                        send = send_credential
                    completed = f"Done starting {issue_count} credential exchanges in"

                issue_task = asyncio.ensure_future(
                    check_received(faber, issue_count, issue_pg))
                issue_task.add_done_callback(faber.check_task_exception)
                receive_task = asyncio.ensure_future(
                    check_received(alice, issue_count, receive_pg))
                receive_task.add_done_callback(alice.check_task_exception)
                with faber.log_timer(completed):
                    for idx in range(0, issue_count):
                        await send(idx + 1)
                        if not (idx +
                                1) % batch_size and idx < issue_count - 1:
                            batch_timer.reset()

                await issue_task
                await receive_task
            except KeyboardInterrupt:
                if receive_task:
                    receive_task.cancel()
                print("Cancelled")

        recv_timer.stop()
        avg = recv_timer.duration / issue_count
        item_short = "ping" if action == "ping" else "cred"
        item_long = "ping exchange" if action == "ping" else "credential"
        faber.log(f"Average time per {item_long}: {avg:.2f}s ({1/avg:.2f}/s)")

        if alice.postgres:
            await alice.collect_postgres_stats(f"{issue_count} {item_short}s")
            for line in alice.format_postgres_stats():
                alice.log(line)
        if faber.postgres:
            await faber.collect_postgres_stats(f"{issue_count} {item_short}s")
            for line in faber.format_postgres_stats():
                faber.log(line)

        if revocation and faber.revocations:
            (rev_reg_id, cred_rev_id) = next(iter(faber.revocations))
            print(f"Revoking and publishing cred rev id {cred_rev_id} "
                  f"from rev reg id {rev_reg_id}")

        if show_timing:
            timing = await alice.fetch_timing()
            if timing:
                for line in alice.format_timing(timing):
                    alice.log(line)

            timing = await faber.fetch_timing()
            if timing:
                for line in faber.format_timing(timing):
                    faber.log(line)
            if mediation:
                timing = await alice_mediator_agent.fetch_timing()
                if timing:
                    for line in alice_mediator_agent.format_timing(timing):
                        alice_mediator_agent.log(line)
                timing = await faber_mediator_agent.fetch_timing()
                if timing:
                    for line in faber_mediator_agent.format_timing(timing):
                        faber_mediator_agent.log(line)

    finally:
        terminated = True
        try:
            if alice:
                await alice.terminate()
        except Exception:
            LOGGER.exception("Error terminating agent:")
            terminated = False
        try:
            if faber:
                await faber.terminate()
        except Exception:
            LOGGER.exception("Error terminating agent:")
            terminated = False
        try:
            if alice_mediator_agent:
                await alice_mediator_agent.terminate()
            if faber_mediator_agent:
                await faber_mediator_agent.terminate()
        except Exception:
            LOGGER.exception("Error terminating agent:")
            terminated = False

    run_timer.stop()
    await asyncio.sleep(0.1)

    if not terminated:
        os._exit(1)