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: