Examples » Get Mempool Contents

This module submits a transaction, reads the contents of the mempool, and then waits for the mempool to empty:

#include <chrono>
#include <thread>
#include <vector>

#include <cardano/address.hpp>
#include <cardano/crypto.hpp>
#include <cardano/encodings.hpp>
#include <cardano/ledger.hpp>
#include <cardano/transaction.hpp>
#include <ogmios/client.hpp>
#include <spdlog/spdlog.h>

using namespace std::chrono_literals;

namespace utils
{

auto get_mempool_transactions(ogmios::Client& client) -> std::vector<json>
{
    if (client.acquireMempool().wait_for(2s) != std::future_status::ready)
    {
        throw std::runtime_error("Unable to acquire the mempool!");
    }

    auto mempool_txs = std::vector<json>();
    while (true)
    {
        auto result = client.nextTransaction().get()["result"];
        if (result["transaction"] == nullptr)
        {
            break;
        }
        mempool_txs.push_back(result);
    }

    if (client.releaseMempool().wait_for(2s) != std::future_status::ready)
    {
        throw std::runtime_error("Unable to release the mempool!");
    }

    return mempool_txs;
}

auto wait_for_empty_mempool(ogmios::Client& client, int timeout_s = 60) -> void
{
    auto start = std::chrono::steady_clock::now();
    while (true)
    {
        if (client.acquireMempool().wait_for(2s) != std::future_status::ready)
        {
            throw std::runtime_error("Unable to acquire the mempool!");
        }

        auto future_result = client.nextTransaction();
        if (future_result.wait_for(2s) != std::future_status::ready)
        {
            throw std::runtime_error("Unable to query the mempool!");
        }

        if (client.releaseMempool().wait_for(2s) != std::future_status::ready)
        {
            throw std::runtime_error("Unable to release the mempool!");
        }

        auto result = future_result.get()["result"];
        if (result["transaction"] == nullptr)
        {
            break;
        }

        auto end = std::chrono::steady_clock::now();
        auto elapsed_s =
            std::chrono::duration_cast<std::chrono::seconds>(end - start)
                .count();

        if (elapsed_s >= timeout_s)
        {
            throw std::runtime_error(
                "Mempool did not empty within the timeout period!"
            );
        }

        spdlog::info("Mempool is not empty, waiting...");
        std::this_thread::sleep_for(1s);
    }
}

}  // namespace utils

auto submit_transaction(ogmios::Client& client) -> void
{
    // Get the signing key from the test seed phrase.
    constexpr auto seed_phrase =
        "firm useless gym escape dad game acid ready ocean hotel broccoli "
        "drift attack little depth prosper cliff forum hole unhappy split "
        "remove among model";
    auto mn = cardano::Mnemonic(seed_phrase, cardano::BIP39Language::English);
    auto root_xsk = cardano::BIP32PrivateKey::fromMnemonic(mn);

    auto payment_xsk = root_xsk.deriveChild(cardano::HardenIndex(1852))
                           .deriveChild(cardano::HardenIndex(1815))
                           .deriveChild(cardano::HardenIndex(0))
                           .deriveChild(0)
                           .deriveChild(0);

    auto stake_xsk = root_xsk.deriveChild(cardano::HardenIndex(1852))
                         .deriveChild(cardano::HardenIndex(1815))
                         .deriveChild(cardano::HardenIndex(0))
                         .deriveChild(2)
                         .deriveChild(0);

    // Create a base address from the corresponding payment and stake keys. This
    // is the address that will be used to send funds.
    auto from_addr = cardano::BaseAddress::fromKeys(
        cardano::NetworkID::testnet,
        payment_xsk.toPublic(),
        stake_xsk.toPublic()
    );

    // Query the UTxOs under the from address.
    auto params = json({{"addresses", {from_addr.toBech32("addr_test")}}});
    auto utxos = client.queryUtxo(params).get()["result"];
    if (utxos.empty()) throw std::runtime_error("No utxos found");

    // Find a UTxO for the transaction to consume.
    auto utxo = utxos[1];  // <- add logic here to select the UTxO.
    auto tx_input_id = utxo["transaction"]["id"].get<std::string>();
    auto tx_input_index = utxo["index"].get<uint32_t>();
    auto tx_input_value = utxo["value"]["ada"]["lovelace"].get<uint64_t>();

    // The addres to send the funds to.
    auto to_addr = cardano::EnterpriseAddress::fromBech32(
        "addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x"
    );

    auto tx_fee = 173861UL;
    auto tx_send = 1500000UL;
    if (tx_input_value < tx_fee + tx_send)
    {
        throw std::runtime_error("Insufficient funds");
    }

    // Get the current chain tip.
    auto tip = client.queryNetworkTip().get()["result"]["slot"].get<size_t>();

    auto tx_builder = cardano::TransactionBuilder();
    tx_builder.addInput(cardano::BASE16::decode(tx_input_id), tx_input_index)
        .addOutput(from_addr, tx_input_value - tx_fee - tx_send)
        .addOutput(to_addr, tx_send)
        .setFee(tx_fee)
        .setTtl(tip + 1000)
        .sign(payment_xsk);

    auto cborHex = cardano::BASE16::encode(tx_builder.serialize());
    spdlog::info("Transaction CBOR: {}", cborHex);

    // Submit the transaction to the Ogmios server.
    client.submitTransactionCbor(cborHex).get();
}

auto get_mempool_contents(ogmios::Client& client) -> void
{
    auto mempool_txs = utils::get_mempool_transactions(client);

    if (mempool_txs.empty())
    {
        spdlog::info("Mempool is empty!");
        return;
    }

    spdlog::info("Mempool has {} transactions:", mempool_txs.size());
    for (const auto& tx : mempool_txs)
    {
        spdlog::info("  {}", tx["transaction"]["id"].get<std::string>());
    }

    spdlog::info("Waiting for mempool to be empty...");
    utils::wait_for_empty_mempool(client);
    spdlog::info("Mempool is empty!");
}

auto main() -> int
{
    // Create a client to manage the Ogmios server connection.
    // The URL defaults to ws://localhost:1337
    auto client = ogmios::Client();

    // Setup the logging callback to print information to stdout.
    spdlog::set_level(spdlog::level::debug);  // Set global log level
    client.setLoggerCallback(
        [](int level, const std::string& msg)
        { spdlog::log(static_cast<spdlog::level::level_enum>(level), msg); }
    );

    submit_transaction(client);
    get_mempool_contents(client);

    return 0;
}  // main

Example output:

Image
Get Mempool Contents Example Output

Open Example on Gitlab