From 214a87885115296bf4e56fd820f5fbfdf4ee4453 Mon Sep 17 00:00:00 2001 From: Khushboo Mehta Date: Mon, 16 Feb 2026 23:14:26 +0100 Subject: [PATCH 1/2] feat: update apis to make it compatible with current Qt remote system --- CMakeLists.txt | 1 - flake.lock | 6 +- src/i_logos_blockchain_module.h | 18 ++-- src/known_addresses.h | 59 ------------- src/logos_blockchain_module.cpp | 149 +++++++++++++++++++++++++------- src/logos_blockchain_module.h | 27 +++++- 6 files changed, 154 insertions(+), 106 deletions(-) delete mode 100644 src/known_addresses.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 061f666..78c5401 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,7 +160,6 @@ target_sources(${PLUGIN_TARGET} PRIVATE set_property(TARGET ${PLUGIN_TARGET} PROPERTY PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/src/i_logos_blockchain_module.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/known_addresses.h ) target_include_directories(${PLUGIN_TARGET} PRIVATE diff --git a/flake.lock b/flake.lock index f244457..595e3d7 100644 --- a/flake.lock +++ b/flake.lock @@ -23,11 +23,11 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1771148003, - "narHash": "sha256-GhA2aeadEN24IMFYXnmCJxtJOx9ctuA8kTF7EWDqtY4=", + "lastModified": 1771418281, + "narHash": "sha256-9nATUijKs7OCEcepHKghuWdgHu+hq11JbJz2Lv4uyDU=", "owner": "logos-blockchain", "repo": "logos-blockchain", - "rev": "4c3738609e9fd4847db4f918e473da3c69b3366f", + "rev": "b862e6f640a79097b8a42c072e1f78bc430fa222", "type": "github" }, "original": { diff --git a/src/i_logos_blockchain_module.h b/src/i_logos_blockchain_module.h index 84caa46..d75332a 100644 --- a/src/i_logos_blockchain_module.h +++ b/src/i_logos_blockchain_module.h @@ -1,7 +1,8 @@ #ifndef I_LOGOS_BLOCKCHAIN_MODULE_API_H #define I_LOGOS_BLOCKCHAIN_MODULE_API_H -#include "known_addresses.h" +#include +#include #include class ILogosBlockchainModule { @@ -14,13 +15,14 @@ public: // Node virtual int start(const QString& config_path, const QString& deployment) = 0; virtual int stop() = 0; - virtual int wallet_get_balance( - const uint8_t* wallet_address, - const HeaderId* optional_tip, - BalanceResult* output_balance - ) = 0; - virtual int wallet_transfer_funds(const TransferFundsArguments* transfer_funds_arguments, Hash* output_hash) = 0; - virtual int wallet_get_known_addresses(lb::KnownAddresses* output) = 0; + virtual QString wallet_get_balance(const QString& addressHex) = 0; + virtual QString wallet_transfer_funds( + const QString& changePublicKey, + const QStringList& senderAddresses, + const QString& recipientAddress, + const QString& amount, + const QString& optionalTipHex) = 0; + virtual QStringList wallet_get_known_addresses() = 0; }; #define ILogosBlockchainModule_iid "org.logos.ilogosblockchainmodule" diff --git a/src/known_addresses.h b/src/known_addresses.h deleted file mode 100644 index f3f81ad..0000000 --- a/src/known_addresses.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif -#include -#ifdef __cplusplus -} -#endif - -namespace lb { - - class KnownAddresses { - public: - KnownAddresses() : data_(nullptr) {} - - explicit KnownAddresses(::KnownAddresses addresses) - : data_(new ::KnownAddresses(addresses), [](::KnownAddresses* ptr) { - if (ptr) { - free_known_addresses(*ptr); - delete ptr; - } - }) {} - - [[nodiscard]] size_t size() const { - return data_ ? data_->len : 0; - } - - [[nodiscard]] bool empty() const { - return size() == 0; - } - - [[nodiscard]] const uint8_t* at(size_t index) const { - if (!data_ || index >= data_->len) { - return nullptr; - } - return data_->addresses[index]; - } - - const uint8_t* operator[](size_t index) const { - return at(index); - } - - [[nodiscard]] bool valid() const { - return data_ != nullptr; - } - - explicit operator bool() const { - return valid(); - } - - private: - std::shared_ptr<::KnownAddresses> data_; - }; - -} diff --git a/src/logos_blockchain_module.cpp b/src/logos_blockchain_module.cpp index a799734..6133582 100644 --- a/src/logos_blockchain_module.cpp +++ b/src/logos_blockchain_module.cpp @@ -1,10 +1,30 @@ #include "logos_blockchain_module.h" #include "logos_api_client.h" +#include #include // Define static member LogosBlockchainModule* LogosBlockchainModule::s_instance = nullptr; +namespace { + // Use the C API type Hash (from logos_blockchain.h) to define address/hash byte size. + constexpr int kAddressBytes = static_cast(sizeof(Hash)); + constexpr int kAddressHexLen = kAddressBytes * 2; + + // Parses kAddressHexLen hex chars (optional 0x prefix) to kAddressBytes. Returns empty QByteArray on error. + QByteArray parseAddressHex(const QString& addressHex) { + QString hex = addressHex.trimmed(); + if (hex.startsWith(QStringLiteral("0x"), Qt::CaseInsensitive)) + hex = hex.mid(2); + if (hex.length() != kAddressHexLen) + return {}; + QByteArray bytes = QByteArray::fromHex(hex.toUtf8()); + if (bytes.size() != kAddressBytes) + return {}; + return bytes; + } +} + void LogosBlockchainModule::onNewBlockCallback(const char* block) { if (s_instance) { qInfo() << "Received new block: " << block; @@ -117,59 +137,126 @@ int LogosBlockchainModule::stop() { return 0; } -int LogosBlockchainModule::wallet_get_balance( - const uint8_t* wallet_address, - const HeaderId* optional_tip, - BalanceResult* output_balance -) { +QString LogosBlockchainModule::wallet_get_balance(const QString& addressHex) { + qDebug() << "wallet_get_balance: addressHex=" << addressHex; if (!node) { - qWarning() << "Could not execute the operation: The node is not running."; - return 1; + return QStringLiteral("Error: The node is not running."); } - auto [value, error] = get_balance(node, wallet_address, optional_tip); + QByteArray bytes = parseAddressHex(addressHex); + if (bytes.isEmpty() || bytes.size() != kAddressBytes) { + return QStringLiteral("Error: Address must be 64 hex characters (32 bytes)."); + } + + auto [value, error] = get_balance(node, + reinterpret_cast(bytes.constData()), nullptr); if (!is_ok(&error)) { - qCritical() << "Failed to get balance. Error:" << error; - return 1; + return QStringLiteral("Error: Failed to get balance: ") + QString::number(error); } - - output_balance->value = value; - return 0; + + return QString::number(value); } -int LogosBlockchainModule::wallet_transfer_funds( - const TransferFundsArguments* transfer_funds_arguments, - Hash* output_hash +QString LogosBlockchainModule::wallet_transfer_funds( + const QString& changePublicKey, + const QStringList& senderAddresses, + const QString& recipientAddress, + const QString& amount, + const QString& optionalTipHex ) { if (!node) { - qWarning() << "Could not execute the operation: The node is not running."; - return 1; + return QStringLiteral("Error: The node is not running."); } - auto [value, error] = transfer_funds(node, transfer_funds_arguments); + bool ok = false; + const quint64 amountVal = amount.trimmed().toULongLong(&ok); + if (!ok) { + return QStringLiteral("Error: Invalid amount (positive integer required)."); + } + + QByteArray changeBytes = parseAddressHex(changePublicKey); + if (changeBytes.isEmpty() || changeBytes.size() != kAddressBytes) { + return QStringLiteral("Error: Invalid changePublicKey (64 hex characters required)."); + } + QByteArray recipientBytes = parseAddressHex(recipientAddress); + if (recipientBytes.isEmpty() || recipientBytes.size() != kAddressBytes) { + return QStringLiteral("Error: Invalid recipientAddress (64 hex characters required)."); + } + if (senderAddresses.isEmpty()) { + return QStringLiteral("Error: At least one sender address required."); + } + QVector fundingBytes; + for (const QString& hex : senderAddresses) { + QByteArray b = parseAddressHex(hex); + if (b.isEmpty() || b.size() != kAddressBytes) { + return QStringLiteral("Error: Invalid sender address (64 hex characters required)."); + } + fundingBytes.append(b); + } + QVector fundingPtrs; + for (const QByteArray& b : fundingBytes) + fundingPtrs.append(reinterpret_cast(b.constData())); + + QByteArray tipBytes; + const HeaderId* optional_tip = nullptr; + if (!optionalTipHex.isEmpty()) { + tipBytes = parseAddressHex(optionalTipHex); + if (tipBytes.isEmpty() || tipBytes.size() != kAddressBytes) { + return QStringLiteral("Error: Invalid optional tip (64 hex characters or empty)."); + } + optional_tip = reinterpret_cast(tipBytes.constData()); + } + + TransferFundsArguments args{}; + args.optional_tip = optional_tip; + args.change_public_key = reinterpret_cast(changeBytes.constData()); + args.funding_public_keys = fundingPtrs.constData(); + args.funding_public_keys_len = static_cast(fundingPtrs.size()); + args.recipient_public_key = reinterpret_cast(recipientBytes.constData()); + args.amount = amountVal; + + auto [value, error] = transfer_funds(node, &args); if (!is_ok(&error)) { - qCritical() << "Failed to transfer funds. Error:" << error; - return 1; + return QStringLiteral("Error: Failed to transfer funds: ") + QString::number(static_cast(error)); } - - std::ranges::copy(value, *output_hash); - return 0; + // value is Hash (32 bytes); convert to hex string + QByteArray hashBytes(reinterpret_cast(&value), kAddressBytes); + return QString::fromUtf8(hashBytes.toHex()); } -int LogosBlockchainModule::wallet_get_known_addresses(lb::KnownAddresses* output) { +QString LogosBlockchainModule::wallet_transfer_funds( + const QString& changePublicKey, + const QString& senderAddress, + const QString& recipientAddress, + const QString& amount, + const QString& optionalTipHex) +{ + return wallet_transfer_funds(changePublicKey, QStringList{senderAddress}, recipientAddress, amount, optionalTipHex); +} + +QStringList LogosBlockchainModule::wallet_get_known_addresses() { + QStringList out; if (!node) { qWarning() << "Could not execute the operation: The node is not running."; - return 1; + return out; } - auto [value, error] = get_known_addresses(node); if (!is_ok(&error)) { qCritical() << "Failed to get known addresses. Error:" << error; - return 1; + return out; } - - *output = lb::KnownAddresses(value); - return 0; + // Each address is kAddressBytes (32) byte + for (size_t i = 0; i < value.len; ++i) { + const uint8_t* ptr = value.addresses[i]; + if (ptr) { + QByteArray addr(reinterpret_cast(ptr), kAddressBytes); + out.append(QString::fromUtf8(addr.toHex())); + } + } + free_known_addresses(value); + qDebug() << "blockchain lib: known addresses, count=" << out.size() + << "sample:" << (out.isEmpty() ? QLatin1String("(none)") : out.constFirst()); + return out; } void LogosBlockchainModule::emitEvent(const QString& eventName, const QVariantList& data) { diff --git a/src/logos_blockchain_module.h b/src/logos_blockchain_module.h index cab228c..7b95396 100644 --- a/src/logos_blockchain_module.h +++ b/src/logos_blockchain_module.h @@ -2,11 +2,19 @@ #include "i_logos_blockchain_module.h" #include #include +#ifdef __cplusplus +extern "C" { +#endif +#include +#ifdef __cplusplus +} +#endif +#include "i_logos_blockchain_module.h" class LogosBlockchainModule final : public QObject, public PluginInterface, public ILogosBlockchainModule { Q_OBJECT Q_PLUGIN_METADATA(IID ILogosBlockchainModule_iid FILE LOGOS_BLOCKCHAIN_MODULE_METADATA_FILE) - Q_INTERFACES(PluginInterface ILogosBlockchainModule) + Q_INTERFACES(PluginInterface) public: LogosBlockchainModule(); @@ -20,9 +28,20 @@ public: // Logos Blockchain Q_INVOKABLE int start(const QString& config_path, const QString& deployment) override; Q_INVOKABLE int stop() override; - Q_INVOKABLE int wallet_get_balance(const uint8_t*, const HeaderId*, BalanceResult*) override; - Q_INVOKABLE int wallet_transfer_funds(const TransferFundsArguments*, Hash*) override; - Q_INVOKABLE int wallet_get_known_addresses(lb::KnownAddresses*) override; + Q_INVOKABLE QString wallet_get_balance(const QString& addressHex) override; + Q_INVOKABLE QString wallet_transfer_funds( + const QString& changePublicKey, + const QStringList& senderAddresses, + const QString& recipientAddress, + const QString& amount, + const QString& optionalTipHex) override; + Q_INVOKABLE QString wallet_transfer_funds( + const QString& changePublicKey, + const QString& senderAddress, + const QString& recipientAddress, + const QString& amount, + const QString& optionalTipHex); + Q_INVOKABLE QStringList wallet_get_known_addresses() override; signals: void eventResponse(const QString& eventName, const QVariantList& data); From 08248235985e249bf781d73270acd263451b8928 Mon Sep 17 00:00:00 2001 From: danielSanchezQ <3danimanimal@gmail.com> Date: Wed, 18 Feb 2026 18:03:24 +0000 Subject: [PATCH 2/2] Fix double free --- flake.lock | 6 +++--- src/logos_blockchain_module.cpp | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 595e3d7..483ab55 100644 --- a/flake.lock +++ b/flake.lock @@ -23,11 +23,11 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1771418281, - "narHash": "sha256-9nATUijKs7OCEcepHKghuWdgHu+hq11JbJz2Lv4uyDU=", + "lastModified": 1771428592, + "narHash": "sha256-J0bJOaHNUh7yDXLw4UajReywSSvN36JiY+e6tPMvqwM=", "owner": "logos-blockchain", "repo": "logos-blockchain", - "rev": "b862e6f640a79097b8a42c072e1f78bc430fa222", + "rev": "7a15c6474a5f9b7c12a36f43e3858b8dcf27ee40", "type": "github" }, "original": { diff --git a/src/logos_blockchain_module.cpp b/src/logos_blockchain_module.cpp index 6133582..d46788b 100644 --- a/src/logos_blockchain_module.cpp +++ b/src/logos_blockchain_module.cpp @@ -31,7 +31,9 @@ void LogosBlockchainModule::onNewBlockCallback(const char* block) { QVariantList data; data.append(QString::fromUtf8(block)); s_instance->emitEvent("newBlock", data); - free_cstring(const_cast(block)); // Free Rust-allocated memory + // SAFETY: + // We are getting an owned pointer here which is freed after this callback is called, so there is not need to + // free the resrouce here as we are copying the data! } }