示例#1
0
async def id_pubkey_correspondence(id_pubkey):
    client = ClientInstance().client
    # determine if id_pubkey is a pubkey
    checked_pubkey = is_pubkey_and_check(id_pubkey)
    if checked_pubkey:
        id_pubkey = checked_pubkey
        try:
            idty = await identity_of(id_pubkey)
            print(
                "{} public key corresponds to identity: {}".format(
                    display_pubkey_and_checksum(id_pubkey), idty["uid"]
                )
            )
        except:
            message_exit("No matching identity")
    # if not ; then it is a uid
    else:
        pubkeys = await wot_lookup(id_pubkey)
        print("Public keys found matching '{}':\n".format(id_pubkey))
        for pubkey in pubkeys:
            print("→", display_pubkey_and_checksum(pubkey["pubkey"]), end=" ")
            try:
                corresponding_id = await client(wot.identity_of, pubkey["pubkey"])
                print("↔ " + corresponding_id["uid"])
            except:
                print("")
    await client.close()
示例#2
0
async def cmd_amount(ctx, pubkeys):
    client = ClientInstance().client
    if not has_auth_method():
        if not pubkeys:
            message_exit("You should specify one or many pubkeys")
        pubkey_list = list()
        for pubkey in pubkeys:
            if check_pubkey_format(pubkey):
                pubkey_list.append(validate_checksum(pubkey))
            else:
                pubkey_list.append(pubkey)
        total = [0, 0]
        for pubkey in pubkey_list:
            inputs_balance = await get_amount_from_pubkey(pubkey)
            await show_amount_from_pubkey(pubkey, inputs_balance)
            total[0] += inputs_balance[0]
            total[1] += inputs_balance[1]
        if len(pubkey_list) > 1:
            await show_amount_from_pubkey("Total", total)
    else:
        key = auth_method()
        pubkey = key.pubkey
        await show_amount_from_pubkey(pubkey, await
                                      get_amount_from_pubkey(pubkey))
    await client.close()
示例#3
0
async def certification_confirmation(issuer, issuer_pubkey, pubkey_to_certify,
                                     idty_to_certify):
    cert = list()
    cert.append(
        ["Cert", "Issuer", "–>", "Recipient: Published: #block-hash date"])
    client = ClientInstance().client
    idty_timestamp = idty_to_certify["meta"]["timestamp"]
    block_uid_idty = block_uid(idty_timestamp)
    block = await client(bma.blockchain.block, block_uid_idty.number)
    block_uid_date = (": #" + idty_timestamp[:15] + "… " +
                      convert_time(block["time"], "all"))
    cert.append(
        ["ID", issuer["uid"], "–>", idty_to_certify["uid"] + block_uid_date])
    cert.append([
        "Pubkey",
        display_pubkey_and_checksum(issuer_pubkey),
        "–>",
        display_pubkey_and_checksum(pubkey_to_certify),
    ])
    params = await BlockchainParams().params
    cert_begins = convert_time(time(), "date")
    cert_ends = convert_time(time() + params["sigValidity"], "date")
    cert.append(["Valid", cert_begins, "—>", cert_ends])
    echo(tabulate(cert, tablefmt="fancy_grid"))
    if not confirm("Do you confirm sending this certification?"):
        await client.close()
        sys.exit(SUCCESS_EXIT_STATUS)
示例#4
0
async def argos_info():
    head_block = await HeadBlock().head_block
    print(await CurrencySymbol().symbol, "|")
    print("---")
    ep = EndPoint().ep
    endpoint_address = ep[best_endpoint_address(ep, False)]
    if ep["port"] == "443":
        href = "href=https://%s/" % (endpoint_address)
    else:
        href = "href=http://%s:%s/" % (endpoint_address, ep["port"])
    print(
        "Connected to node:",
        ep[best_endpoint_address(ep, False)],
        ep["port"],
        "|",
        href,
        "\nCurrent block number:",
        head_block["number"],
        "\nCurrency name:",
        await CurrencySymbol().symbol,
        "\nNumber of members:",
        head_block["membersCount"],
        "\nMinimal Proof-of-Work:",
        head_block["powMin"],
        "\nCurrent time:",
        convert_time(head_block["time"], "all"),
        "\nMedian time:",
        convert_time(head_block["medianTime"], "all"),
        "\nDifference time:",
        convert_time(head_block["time"] - head_block["medianTime"], "hour"),
    )
    client = ClientInstance().client
    await client.close()
示例#5
0
async def test_display_confirmation_table(
    patched_wot_requirements, monkeypatch, capsys
):
    monkeypatch.setattr(bma.wot, "requirements", patched_wot_requirements)
    monkeypatch.setattr(bma.blockchain, "parameters", patched_params)
    monkeypatch.setattr(bma.blockchain, "block", patched_block)

    client = ClientInstance().client
    identities_requirements = await client(bma.wot.requirements, pubkey)
    for identity_requirements in identities_requirements["identities"]:
        if identity_requirements["uid"] == identity_uid:
            membership_expires = identity_requirements["membershipExpiresIn"]
            pending_expires = identity_requirements["membershipPendingExpiresIn"]
            pending_memberships = identity_requirements["pendingMemberships"]
            break

    table = list()
    if membership_expires:
        expires = pendulum.now().add(seconds=membership_expires).diff_for_humans()
        table.append(["Expiration date of current membership", expires])

    if pending_memberships:
        line = [
            "Number of pending membership(s) in the mempool",
            len(pending_memberships),
        ]
        table.append(line)
        expiration = pendulum.now().add(seconds=pending_expires).diff_for_humans()
        table.append(["Pending membership documents will expire", expiration])

    table.append(["User Identifier (UID)", identity_uid])
    table.append(["Public Key", display_pubkey_and_checksum(pubkey)])

    table.append(["Block Identity", str(identity_timestamp)[:45] + "…"])

    block = await client(bma.blockchain.block, identity_timestamp.number)
    table.append(
        ["Identity published", pendulum.from_timestamp(block["time"]).format("LL")],
    )

    params = await BlockchainParams().params
    membership_validity = (
        pendulum.now().add(seconds=params["msValidity"]).diff_for_humans()
    )
    table.append(["Expiration date of new membership", membership_validity])

    membership_mempool = (
        pendulum.now().add(seconds=params["msPeriod"]).diff_for_humans()
    )
    table.append(
        ["Expiration date of new membership from the mempool", membership_mempool]
    )

    expected = tabulate(table, tablefmt="fancy_grid") + "\n"

    await membership.display_confirmation_table(
        identity_uid, pubkey, identity_timestamp
    )
    captured = capsys.readouterr()
    assert expected == captured.out
示例#6
0
async def display_confirmation_table(identity_uid, pubkey, identity_timestamp):
    """
    Check whether there is pending memberships already in the mempool
    Display their expiration date

    Actually, it works sending a membership document even if the time
    between two renewals is not awaited as for the certification
    """

    client = ClientInstance().client

    identities_requirements = await client(bma.wot.requirements, pubkey)
    for identity_requirements in identities_requirements["identities"]:
        if identity_requirements["uid"] == identity_uid:
            membership_expires = identity_requirements["membershipExpiresIn"]
            pending_expires = identity_requirements["membershipPendingExpiresIn"]
            pending_memberships = identity_requirements["pendingMemberships"]
            break

    table = list()
    if membership_expires:
        expires = pendulum.now().add(seconds=membership_expires).diff_for_humans()
        table.append(["Expiration date of current membership", expires])

    if pending_memberships:
        line = [
            "Number of pending membership(s) in the mempool",
            len(pending_memberships),
        ]
        table.append(line)

        expiration = pendulum.now().add(seconds=pending_expires).diff_for_humans()
        table.append(["Pending membership documents will expire", expiration])

    table.append(["User Identifier (UID)", identity_uid])
    table.append(["Public Key", display_pubkey_and_checksum(pubkey)])

    table.append(["Block Identity", str(identity_timestamp)[:45] + "…"])

    block = await client(bma.blockchain.block, identity_timestamp.number)
    table.append(
        ["Identity published", pendulum.from_timestamp(block["time"]).format("LL")]
    )

    params = await BlockchainParams().params
    membership_validity = (
        pendulum.now().add(seconds=params["msValidity"]).diff_for_humans()
    )
    table.append(["Expiration date of new membership", membership_validity])

    membership_mempool = (
        pendulum.now().add(seconds=params["msPeriod"]).diff_for_humans()
    )
    table.append(
        ["Expiration date of new membership from the mempool", membership_mempool]
    )

    click.echo(tabulate(table, tablefmt="fancy_grid"))
示例#7
0
文件: tx.py 项目: duniter/silkaj
async def send_transaction(amounts, amountsud, allsources, recipients, comment,
                           outputbackchange, yes):
    """
    Main function
    """
    if not (amounts or amountsud or allsources):
        message_exit("Error: amount, amountUD or allSources is not set.")
    if allsources and len(recipients) > 1:
        message_exit(
            "Error: the --allSources option can only be used with one recipient."
        )
    # compute amounts and amountsud
    if not allsources:
        tx_amounts = await transaction_amount(amounts, amountsud, recipients)

    key = auth_method()
    issuer_pubkey = key.pubkey

    pubkey_amount = await money.get_amount_from_pubkey(issuer_pubkey)
    if allsources:
        tx_amounts = [pubkey_amount[0]]

    recipients = list(recipients)
    outputbackchange = check_transaction_values(
        comment,
        recipients,
        outputbackchange,
        pubkey_amount[0] < sum(tx_amounts),
        issuer_pubkey,
    )

    if (yes or input(
            tabulate(
                await transaction_confirmation(
                    issuer_pubkey,
                    pubkey_amount[0],
                    tx_amounts,
                    recipients,
                    outputbackchange,
                    comment,
                ),
                tablefmt="fancy_grid",
            ) + "\nDo you confirm sending this transaction? [yes/no]: ")
            == "yes"):
        await handle_intermediaries_transactions(
            key,
            issuer_pubkey,
            tx_amounts,
            recipients,
            comment,
            outputbackchange,
        )
    else:
        client = ClientInstance().client
        await client.close()
示例#8
0
async def send_membership(dry_run):

    # Authentication
    key = auth.auth_method()

    # Get the identity information
    head_block = await HeadBlock().head_block
    membership_timestamp = BlockUID(head_block["number"], head_block["hash"])
    identity = (await wot.choose_identity(key.pubkey))[0]
    identity_uid = identity["uid"]
    identity_timestamp = block_uid(identity["meta"]["timestamp"])

    # Display license and ask for confirmation
    currency = head_block["currency"]
    if not dry_run:
        license_approval(currency)

    # Confirmation
    client = ClientInstance().client
    await display_confirmation_table(identity_uid, key.pubkey, identity_timestamp)
    if not dry_run:
        if not click.confirm(
            "Do you confirm sending a membership document for this identity?"
        ):
            await client.close()
            sys.exit(SUCCESS_EXIT_STATUS)

    membership = generate_membership_document(
        currency,
        key.pubkey,
        membership_timestamp,
        identity_uid,
        identity_timestamp,
    )

    # Sign document
    membership.sign([key])

    logging.debug(membership.signed_raw())

    if dry_run:
        await client.close()
        click.echo(membership.signed_raw())
        sys.exit(SUCCESS_EXIT_STATUS)

    # Send the membership signed raw document to the node
    response = await client(bma.blockchain.membership, membership.signed_raw())

    if response.status == 200:
        print("Membership successfully sent")
    else:
        print("Error while publishing membership: {0}".format(await response.text()))
    logging.debug(await response.text())
    await client.close()
示例#9
0
async def received_sent_certifications(uid_pubkey):
    """
    get searched id
    get id of received and sent certifications
    display in a table the result with the numbers
    """
    client = ClientInstance().client
    first_block = await client(blockchain.block, 1)
    time_first_block = first_block["time"]

    checked_pubkey = is_pubkey_and_check(uid_pubkey)
    if checked_pubkey:
        uid_pubkey = checked_pubkey

    identity, pubkey, signed = await choose_identity(uid_pubkey)
    certifications = OrderedDict()
    params = await BlockchainParams().params
    req = await client(wot.requirements, pubkey)
    req = req["identities"][0]
    certifications["received_expire"] = list()
    certifications["received"] = list()
    for cert in identity["others"]:
        certifications["received_expire"].append(
            expiration_date_from_block_id(
                cert["meta"]["block_number"], time_first_block, params
            )
        )
        certifications["received"].append(
            cert_written_in_the_blockchain(req["certifications"], cert)
        )
        (
            certifications["sent"],
            certifications["sent_expire"],
        ) = get_sent_certifications(signed, time_first_block, params)
    nbr_sent_certs = len(certifications["sent"]) if "sent" in certifications else 0
    print(
        "{0} ({1}) from block #{2}\nreceived {3} and sent {4}/{5} certifications:\n{6}\n{7}\n".format(
            identity["uid"],
            display_pubkey_and_checksum(pubkey, True),
            identity["meta"]["timestamp"][:15] + "…",
            len(certifications["received"]),
            nbr_sent_certs,
            params["sigStock"],
            tabulate(
                certifications,
                headers="keys",
                tablefmt="orgtbl",
                stralign="center",
            ),
            "✔: Certifications written into the blockchain",
        )
    )
    await membership_status(certifications, pubkey, req)
    await client.close()
示例#10
0
async def identity_of(pubkey_uid):
    """
    Only works for members
    Not able to get corresponding uid from a non-member identity
    Able to know if an identity is member or not
    """
    client = ClientInstance().client
    try:
        return await client(wot.identity_of, pubkey_uid)
    except DuniterError as e:
        raise DuniterError(e)
    except ValueError as e:
        pass
示例#11
0
async def wot_lookup(identifier):
    """
    :identifier: identity or pubkey in part or whole
    Return received and sent certifications lists of matching identities
    if one identity found
    """
    client = ClientInstance().client
    try:
        results = await client(wot.lookup, identifier)
        return results["results"]
    except DuniterError as e:
        message_exit(e.message)
    except ValueError as e:
        pass
示例#12
0
async def get_sources(pubkey):
    client = ClientInstance().client
    # Sources written into the blockchain
    sources = await client(tx.sources, pubkey)

    listinput = list()
    amount = 0
    for source in sources["sources"]:
        if source["conditions"] == "SIG(" + pubkey + ")":
            listinput.append(
                InputSource(
                    amount=source["amount"],
                    base=source["base"],
                    source=source["type"],
                    origin_id=source["identifier"],
                    index=source["noffset"],
                ))
            amount += amount_in_current_base(listinput[-1])

    # pending source
    history = await client(tx.pending, pubkey)
    history = history["history"]
    pendings = history["sending"] + history["receiving"] + history["pending"]

    # add pending output
    pending_sources = list()
    for pending in pendings:
        identifier = pending["hash"]
        for i, output in enumerate(pending["outputs"]):
            outputsplited = output.split(":")
            if outputsplited[2] == "SIG(" + pubkey + ")":
                inputgenerated = InputSource(
                    amount=int(outputsplited[0]),
                    base=int(outputsplited[1]),
                    source="T",
                    origin_id=identifier,
                    index=i,
                )
                if inputgenerated not in listinput:
                    listinput.append(inputgenerated)

        for input in pending["inputs"]:
            pending_sources.append(InputSource.from_inline(input))

    # remove input already used
    for input in pending_sources:
        if input in listinput:
            listinput.remove(input)

    return listinput, amount
示例#13
0
async def difficulties():
    client = ClientInstance().client
    try:
        ws = await client(bma.ws.block)
        while True:
            current = await ws.receive_json()
            jsonschema.validate(current, bma.ws.WS_BLOCK_SCHEMA)
            diffi = await client(bma.blockchain.difficulties)
            await display_diffi(current, diffi)
        await client.close()

    except (aiohttp.WSServerHandshakeError, ValueError) as e:
        print("Websocket block {0} : {1}".format(type(e).__name__, str(e)))
    except (aiohttp.ClientError, gaierror, TimeoutError) as e:
        print("{0} : {1}".format(str(e), BMAS_ENDPOINT))
    except jsonschema.ValidationError as e:
        print("{:}:{:}".format(str(e.__class__.__name__), str(e)))
示例#14
0
async def transaction_history(pubkey, uids):
    if check_pubkey_format(pubkey):
        pubkey = validate_checksum(pubkey)

    client = ClientInstance().client
    ud_value = await UDValue().ud_value
    currency_symbol = await CurrencySymbol().symbol

    header = await generate_header(pubkey, currency_symbol, ud_value)
    received_txs, sent_txs = list(), list()
    await get_transactions_history(client, pubkey, received_txs, sent_txs)
    remove_duplicate_txs(received_txs, sent_txs)
    txs_list = await generate_table(
        received_txs, sent_txs, pubkey, ud_value, currency_symbol, uids
    )
    table = Texttable(max_width=get_terminal_size()[0])
    table.add_rows(txs_list)
    await client.close()
    echo_via_pager(header + table.draw())
示例#15
0
文件: tx.py 项目: duniter/silkaj
async def generate_and_send_transaction(
    key,
    issuers,
    tx_amounts,
    listinput_and_amount,
    outputAddresses,
    Comment,
    OutputbackChange=None,
):
    """
    Display sent transaction
    Generate, sign, and send transaction document
    """
    intermediate_tx = listinput_and_amount[2]
    if intermediate_tx:
        print("Generate Change Transaction")
    else:
        print("Generate Transaction:")
    print("   - From:    " + display_pubkey_and_checksum(issuers))
    for tx_amount, outputAddress in zip(tx_amounts, outputAddresses):
        display_sent_tx(outputAddress, tx_amount)
    print("   - Total:   " + str(sum(tx_amounts) / 100))

    client = ClientInstance().client
    transaction = await generate_transaction_document(
        issuers,
        tx_amounts,
        listinput_and_amount,
        outputAddresses,
        Comment,
        OutputbackChange,
    )
    transaction.sign([key])
    response = await client(process, transaction.signed_raw())
    if response.status == 200:
        print("Transaction successfully sent.")
    else:
        message_exit("Error while publishing transaction: {0}".format(
            await response.text()))
示例#16
0
文件: tx.py 项目: duniter/silkaj
async def handle_intermediaries_transactions(
    key,
    issuers,
    tx_amounts,
    outputAddresses,
    Comment="",
    OutputbackChange=None,
):
    client = ClientInstance().client
    while True:
        listinput_and_amount = await get_list_input_for_transaction(
            issuers, sum(tx_amounts))
        intermediatetransaction = listinput_and_amount[2]

        if intermediatetransaction:
            totalAmountInput = listinput_and_amount[1]
            await generate_and_send_transaction(
                key,
                issuers,
                [totalAmountInput],
                listinput_and_amount,
                [issuers],
                "Change operation",
            )
            await sleep(1)  # wait 1 second before sending a new transaction

        else:
            await generate_and_send_transaction(
                key,
                issuers,
                tx_amounts,
                listinput_and_amount,
                outputAddresses,
                Comment,
                OutputbackChange,
            )
            await client.close()
            break
示例#17
0
async def currency_info():
    head_block = await HeadBlock().head_block
    ep = EndPoint().ep
    print(
        "Connected to node:",
        ep[best_endpoint_address(ep, False)],
        ep["port"],
        "\nCurrent block number:",
        head_block["number"],
        "\nCurrency name:",
        await CurrencySymbol().symbol,
        "\nNumber of members:",
        head_block["membersCount"],
        "\nMinimal Proof-of-Work:",
        head_block["powMin"],
        "\nCurrent time:",
        convert_time(head_block["time"], "all"),
        "\nMedian time:",
        convert_time(head_block["medianTime"], "all"),
        "\nDifference time:",
        convert_time(head_block["time"] - head_block["medianTime"], "hour"),
    )
    client = ClientInstance().client
    await client.close()
示例#18
0
async def send_certification(uid_pubkey_to_certify):
    client = ClientInstance().client

    checked_pubkey = is_pubkey_and_check(uid_pubkey_to_certify)
    if checked_pubkey:
        uid_pubkey_to_certify = checked_pubkey

    idty_to_certify, pubkey_to_certify, send_certs = await wot.choose_identity(
        uid_pubkey_to_certify)

    # Authentication
    key = auth_method()

    # Check whether current user is member
    issuer_pubkey = key.pubkey
    issuer = await wot.is_member(issuer_pubkey)
    if not issuer:
        message_exit("Current identity is not member.")

    if issuer_pubkey == pubkey_to_certify:
        message_exit("You can’t certify yourself!")

    # Check if the certification can be renewed
    req = await client(bma.wot.requirements, pubkey_to_certify)
    req = req["identities"][0]
    for cert in req["certifications"]:
        if cert["from"] == issuer_pubkey:
            params = await BlockchainParams().params
            # Ğ1: 0<–>2y - 2y + 2m
            # ĞT: 0<–>4.8m - 4.8m + 12.5d
            renewable = cert["expiresIn"] - params["sigValidity"] + params[
                "sigReplay"]
            if renewable > 0:
                renewable_date = convert_time(time() + renewable, "date")
                message_exit("Certification renewable the " + renewable_date)

    # Check if the certification is already in the pending certifications
    for pending_cert in req["pendingCerts"]:
        if pending_cert["from"] == issuer_pubkey:
            message_exit("Certification is currently been processed")

    # Display license and ask for confirmation
    head = await HeadBlock().head_block
    currency = head["currency"]
    license_approval(currency)

    # Certification confirmation
    await certification_confirmation(issuer, issuer_pubkey, pubkey_to_certify,
                                     idty_to_certify)

    identity = Identity(
        version=10,
        currency=currency,
        pubkey=pubkey_to_certify,
        uid=idty_to_certify["uid"],
        ts=block_uid(idty_to_certify["meta"]["timestamp"]),
        signature=idty_to_certify["self"],
    )

    certification = Certification(
        version=10,
        currency=currency,
        pubkey_from=issuer_pubkey,
        identity=identity,
        timestamp=BlockUID(head["number"], head["hash"]),
        signature="",
    )

    # Sign document
    certification.sign([key])

    # Send certification document
    response = await client(bma.wot.certify, certification.signed_raw())

    if response.status == 200:
        print("Certification successfully sent.")
    else:
        print("Error while publishing certification: {0}".format(
            await response.text()))

    await client.close()
示例#19
0
 async def get_head(self):
     client = ClientInstance().client
     return await client(blockchain.current)
示例#20
0
 async def get_params(self):
     client = ClientInstance().client
     return await client(blockchain.parameters)
示例#21
0
 async def get_ud_value(self):
     client = ClientInstance().client
     blockswithud = await client(blockchain.ud)
     NBlastUDblock = blockswithud["result"]["blocks"][-1]
     lastUDblock = await client(blockchain.block, NBlastUDblock)
     return lastUDblock["dividend"] * 10**lastUDblock["unitbase"]
示例#22
0
async def list_blocks(number, detailed):
    head_block = await HeadBlock().head_block
    current_nbr = head_block["number"]
    if number == 0:
        number = head_block["issuersFrame"]
    client = ClientInstance().client
    blocks = await client(bma.blockchain.blocks, number,
                          current_nbr - number + 1)
    issuers = list()
    issuers_dict = dict()
    for block in blocks:
        issuer = OrderedDict()
        issuer["pubkey"] = block["issuer"]
        if detailed or number <= 30:
            issuer["block"] = block["number"]
            issuer["gentime"] = convert_time(block["time"], "all")
            issuer["mediantime"] = convert_time(block["medianTime"], "all")
            issuer["hash"] = block["hash"][:10]
            issuer["powMin"] = block["powMin"]
        issuers_dict[issuer["pubkey"]] = issuer
        issuers.append(issuer)
    for pubkey in issuers_dict.keys():
        issuer = issuers_dict[pubkey]
        idty = await identity_of(issuer["pubkey"])
        for issuer2 in issuers:
            if (issuer2.get("pubkey") is not None
                    and issuer.get("pubkey") is not None
                    and issuer2["pubkey"] == issuer["pubkey"]):
                issuer2["uid"] = idty["uid"]
                issuer2.pop("pubkey")
        await sleep(ASYNC_SLEEP)
    await client.close()
    print(
        "Last {0} blocks from n°{1} to n°{2}".format(number,
                                                     current_nbr - number + 1,
                                                     current_nbr),
        end=" ",
    )
    if detailed or number <= 30:
        sorted_list = sorted(issuers, key=itemgetter("block"), reverse=True)
        print("\n" + tabulate(
            sorted_list, headers="keys", tablefmt="orgtbl", stralign="center"))
    else:
        list_issued = list()
        for issuer in issuers:
            found = False
            for issued in list_issued:
                if issued.get(
                        "uid") is not None and issued["uid"] == issuer["uid"]:
                    issued["blocks"] += 1
                    found = True
                    break
            if not found:
                issued = OrderedDict()
                issued["uid"] = issuer["uid"]
                issued["blocks"] = 1
                list_issued.append(issued)
        for issued in list_issued:
            issued["percent"] = issued["blocks"] / number * 100
        sorted_list = sorted(list_issued,
                             key=itemgetter("blocks"),
                             reverse=True)
        print("from {0} issuers\n{1}".format(
            len(list_issued),
            tabulate(
                sorted_list,
                headers="keys",
                tablefmt="orgtbl",
                floatfmt=".1f",
                stralign="center",
            ),
        ))