]> Nutra Git (v2) - gamesguru/feather.git/commitdiff
lint/warning fixes
authorgg <chown_tee@proton.me>
Tue, 20 Jan 2026 03:03:12 +0000 (22:03 -0500)
committergg <chown_tee@proton.me>
Tue, 20 Jan 2026 07:07:13 +0000 (02:07 -0500)
src/HistoryWidget.cpp
src/MainWindow.cpp
src/SendWidget.cpp
src/WindowManager.cpp
src/dialog/SyncRangeDialog.cpp
src/dialog/TxImportDialog.cpp
src/libwalletqt/Wallet.cpp
src/libwalletqt/Wallet.h
src/main.cpp
src/utils/Utils.cpp

index 09aa843b326ad1a89c777806e3004585779a82e3..1791fc8cbe282ebe9638f889a0737b2f3147f749 100644 (file)
@@ -213,14 +213,14 @@ void HistoryWidget::copy(copyField field) {
             case copyField::JSON: {
                 QJsonObject obj;
                 obj.insert("txid", tx.hash);
-                obj.insert("amount", static_cast<double>(tx.amount));
-                obj.insert("fee", static_cast<double>(tx.fee));
-                obj.insert("height", static_cast<double>(tx.blockHeight));
+                obj.insert("amount", QString::number(tx.amount));
+                obj.insert("fee", QString::number(tx.fee));
+                obj.insert("height", static_cast<qint64>(tx.blockHeight));
                 obj.insert("timestamp", tx.timestamp.toSecsSinceEpoch());
                 obj.insert("direction", tx.direction == TransactionRow::Direction_In ? "in" : "out");
                 obj.insert("payment_id", tx.paymentId);
                 obj.insert("description", tx.description);
-                obj.insert("confirmations", static_cast<double>(tx.confirmations));
+                obj.insert("confirmations", static_cast<qint64>(tx.confirmations));
                 obj.insert("failed", tx.failed);
                 obj.insert("pending", tx.pending);
                 obj.insert("coinbase", tx.coinbase);
index d7bf5dc17c86ed92cbc6b74937707c83a9de1674..df8170188d7dc7be3592cc3bcc771ed5bb229025 100644 (file)
@@ -444,7 +444,6 @@ void MainWindow::initWidgets() {
     connect(m_walletUnlockWidget, &WalletUnlockWidget::closeWallet, this, &MainWindow::close);
     connect(m_walletUnlockWidget, &WalletUnlockWidget::unlockWallet, this, &MainWindow::unlockWallet);
 
-    ui->tabWidget->setCurrentIndex(0);
     ui->tabWidget->setCurrentIndex(0);
     ui->stackedWidget->setCurrentIndex(0);
 
index de34fae7f96ac509680b7e9bc79d0c6da5b0df17..f869fb841423d8cada5ccf1b0a5626b23223f81b 100644 (file)
@@ -146,7 +146,9 @@ void SendWidget::scanClicked() {
 }
 
 void SendWidget::sendClicked() {
-    if (conf()->get(Config::syncPaused).toBool()) {
+    bool syncPaused = conf()->get(Config::syncPaused).toBool();
+
+    if (syncPaused) {
         QMessageBox msgBox(this);
         msgBox.setIcon(QMessageBox::Warning);
         msgBox.setWindowTitle("Are you sure? Create transaction?");
@@ -167,14 +169,14 @@ void SendWidget::sendClicked() {
         }
     }
 
-    if (!m_wallet->isConnected() && !conf()->get(Config::syncPaused).toBool()) {
+    if (!m_wallet->isConnected() && !syncPaused) {
         Utils::showError(this, "Unable to create transaction", "Wallet is not connected to a node.",
                          {"Wait for the wallet to automatically connect to a node.", "Go to File -> Settings -> Network -> Node to manually connect to a node."},
                          "nodes");
         return;
     }
 
-    if (!m_wallet->isSynchronized() && !conf()->get(Config::syncPaused).toBool()) {
+    if (!m_wallet->isSynchronized() && !syncPaused) {
         Utils::showError(this, "Unable to create transaction", "Wallet is not synchronized", {"Wait for wallet synchronization to complete"}, "synchronization");
         return;
     }
index 9fab17e559e3419a524d7a875c3ffd0dc1c74f06..07e0f36d1b040ef74293a618122a81b5cf20fcef 100644 (file)
@@ -117,12 +117,12 @@ void WindowManager::close() {
     }
     m_closing = true;
 
-
-    // Stop all threads before application shutdown to avoid QThreadStorage warnings
-    if (m_cleanupThread && m_cleanupThread->isRunning()) {
-        m_cleanupThread->quit();
-        m_cleanupThread->wait();
-        qDebug() << "WindowManager: cleanup thread stopped in close()";
+    // Force save all wallets before attempting to close
+    // This ensures that even if the cleanup thread hangs and we _Exit(1), data is saved.
+    for (const auto &window : m_windows) {
+        if (window->m_wallet) {
+            window->m_wallet->store();
+        }
     }
 
     // Close all windows first to ensure they cancel their tasks/connections
@@ -132,6 +132,13 @@ void WindowManager::close() {
         window->close();
     }
 
+    // Stop all threads before application shutdown to avoid QThreadStorage warnings
+    if (m_cleanupThread && m_cleanupThread->isRunning()) {
+        m_cleanupThread->quit();
+        m_cleanupThread->wait();
+        qDebug() << "WindowManager: cleanup thread stopped in close()";
+    }
+
     // Stop Tor manager threads
     torManager()->stop();
 
index 793d46c9d691b41d3856d56b9bc310808fec83c9..885f649fbb3bfe9f1d57d2fded4abb287d1334ea 100644 (file)
@@ -11,6 +11,7 @@
 #include <QDateEdit>
 #include <QLabel>
 #include <QDialogButtonBox>
+#include <QSignalBlocker>
 
 #include "utils/Utils.h"
 #include "utils/RestoreHeightLookup.h"
@@ -144,11 +145,13 @@ void SyncRangeDialog::updateInfo() {
 }
 
 void SyncRangeDialog::updateFromDate() {
+    const QSignalBlocker blocker(m_fromDateEdit);
     m_fromDateEdit->setDate(m_toDateEdit->date().addDays(-m_daysSpinBox->value()));
     updateInfo();
 }
 
 void SyncRangeDialog::updateToDate() {
+    const QSignalBlocker blocker(m_toDateEdit);
     m_toDateEdit->setDate(m_fromDateEdit->date().addDays(m_daysSpinBox->value()));
     updateInfo();
 }
index 842337bfedea87e7d113c4d21e02a4a82fa229b2..d09dc7383cc9b01b285836d0fb9b74e5d57888fc 100644 (file)
@@ -46,6 +46,12 @@ void TxImportDialog::onImport() {
     QString txid = ui->line_txid->text().trimmed();
     if (txid.isEmpty()) return;
 
+    static const QRegularExpression hexMatcher("^[0-9a-fA-F]{64}$");
+    if (!hexMatcher.match(txid).hasMatch()) {
+        Utils::showError(this, "Invalid TXID", "Transaction ID must be a 64-character hexadecimal string.");
+        return;
+    }
+
     if (m_wallet->haveTransaction(txid)) {
         Utils::showWarning(this, "Transaction already exists in wallet", "If you can't find it in your history, "
                                                                        "check if it belongs to a different account (Wallet -> Account)");
@@ -56,22 +62,22 @@ void TxImportDialog::onImport() {
     ui->btn_import->setEnabled(false);
     ui->btn_import->setText("Checking...");
 
-    QNetworkAccessManager* nam = getNetwork(); // Use global network manager
     QString url = m_nodes->connection().toURL() + "/get_transactions";
-    
+    QNetworkAccessManager* nam = getNetwork(url); // Use global network manager
+
     QJsonObject req;
     req["txs_hashes"] = QJsonArray({txid});
-    
+
     QNetworkRequest request(url);
     request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
 
     QNetworkReply* reply = nam->post(request, QJsonDocument(req).toJson());
-    
+
     connect(reply, &QNetworkReply::finished, this, [this, reply, txid]() {
         reply->deleteLater();
         ui->btn_import->setEnabled(true);
         ui->btn_import->setText("Import");
-        
+
         if (reply->error() != QNetworkReply::NoError) {
              Utils::showError(this, "Connection error", reply->errorString());
              return;
@@ -96,9 +102,22 @@ void TxImportDialog::onImport() {
                      this->accept();
                      return;
                 }
-                
+
                 quint64 height = tx.value("block_height").toVariant().toULongLong();
                 if (height > 0) {
+                     if (height > std::numeric_limits<quint64>::max() - 10) {
+                         Utils::showError(this, "Invalid Block Height", "Block height is too large.");
+                         return;
+                     }
+
+                     // Validate against daemon height
+                     quint64 daemonHeight = m_wallet->daemonBlockChainHeight();
+                     if (daemonHeight > 0 && height > daemonHeight + 100) {
+                         Utils::showError(this, "Invalid Block Height",
+                             QString("The node returned a block height significantly in the future (%1). Daemon height: %2.").arg(height).arg(daemonHeight));
+                         return;
+                     }
+
                      // Check if wallet is far behind (fresh restore?)
                      quint64 currentHeight = m_wallet->blockChainHeight();
 
index b4a517efe379f3681b554294ced09ba32344ecaa..a10d503acd2494fdcfd5c77e053a045e743f1d45 100644 (file)
@@ -61,6 +61,7 @@ Wallet::Wallet(Monero::Wallet *wallet, QObject *parent)
         , m_coins(new Coins(this, wallet->getWallet(), this))
         , m_storeTimer(new QTimer(this))
         , m_lastRefreshTime(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now().time_since_epoch()).count())
+        , m_lastSyncTime(0)
 {
     m_walletListener = new WalletListenerImpl(this);
     m_walletImpl->setListener(m_walletListener);
@@ -104,7 +105,7 @@ Wallet::Wallet(Monero::Wallet *wallet, QObject *parent)
     if (!lastSyncStr.isEmpty()) {
         qint64 lastSync = lastSyncStr.toLongLong();
         if (lastSync > 0) {
-            m_lastSyncTime = QDateTime::fromSecsSinceEpoch(lastSync);
+            m_lastSyncTime = lastSync * 1000;
         }
     }
 }
@@ -451,7 +452,7 @@ void Wallet::initAsync(const QString &daemonAddress, bool trustedDaemon, quint64
                      safeAddress.prepend("http://");
                  }
             }
-            qCritical() << "Refresher: Initializing wallet with daemon address:" << safeAddress;
+            qInfo() << "Refresher: Initializing wallet with daemon address:" << safeAddress;
             qDebug() << "InitAsync: connecting to" << safeAddress;
             m_wallet2->set_offline(false);
             success = m_walletImpl->init(safeAddress.toStdString(), upperTransactionLimit, m_daemonUsername.toStdString(), m_daemonPassword.toStdString(), m_useSSL, false, proxyAddress.toStdString());
@@ -662,7 +663,7 @@ void Wallet::onHeightsRefreshed(bool success, quint64 daemonHeight, quint64 targ
     }
 
     if (success) {
-        m_lastSyncTime = QDateTime::currentDateTime();
+        m_lastSyncTime = QDateTime::currentDateTime().toMSecsSinceEpoch();
     }
 }
 
@@ -726,7 +727,9 @@ void Wallet::setScanMempoolWhenPaused(bool enabled) {
 }
 
 QDateTime Wallet::lastSyncTime() const {
-    return m_lastSyncTime;
+    if (m_lastSyncTime == 0)
+        return QDateTime();
+    return QDateTime::fromMSecsSinceEpoch(m_lastSyncTime);
 }
 
 void Wallet::setRefreshInterval(int seconds) {
@@ -746,7 +749,7 @@ void Wallet::skipToTip() {
     m_stopHeight = target;
     m_rangeSyncActive = true;
     m_wallet2->set_refresh_from_block_height(target);
-    m_lastSyncTime = QDateTime::currentDateTime();
+    m_lastSyncTime = QDateTime::currentDateTime().toMSecsSinceEpoch();
 
     setConnectionStatus(ConnectionStatus_Synchronized);
     startRefresh(true);
@@ -831,7 +834,7 @@ void Wallet::startSmartSync(quint64 requestedTarget) {
     m_stopHeight = target;
     m_rangeSyncActive = true;
     m_pauseAfterSync = true;
-    m_lastSyncTime = QDateTime::currentDateTime();
+    m_lastSyncTime = QDateTime::currentDateTime().toMSecsSinceEpoch();
 
     setConnectionStatus(ConnectionStatus_Synchronizing);
     startRefresh(true);
@@ -1865,23 +1868,25 @@ void Wallet::getTxPoolStatsAsync() {
 }
 
 void Wallet::scanMempool() {
-    QMutexLocker locker(&m_asyncMutex);
-    try {
-        std::vector<std::tuple<cryptonote::transaction, crypto::hash, bool>> process_txs;
-        m_wallet2->update_pool_state(process_txs, false, false);
-        // Refresh models so the UI picks up the new transaction(s)
-        // We invoke this on the main thread to ensure signals (beginResetModel) are processed synchronously
-        // with the data update, preventing race conditions or ignored updates in the view.
-        QMetaObject::invokeMethod(this, [this]{
-            if (m_history) m_history->refresh();
-            if (m_coins) m_coins->refresh();
-            if (m_subaddress) m_subaddress->refresh();
-        }, Qt::QueuedConnection);
-        
-        emit updated();
-    } catch (const std::exception &e) {
-        qWarning() << "Failed to scan mempool:" << e.what();
+    {
+        QMutexLocker locker(&m_asyncMutex);
+        try {
+            std::vector<std::tuple<cryptonote::transaction, crypto::hash, bool>> process_txs;
+            m_wallet2->update_pool_state(process_txs, false, false);
+            // Refresh models so the UI picks up the new transaction(s)
+            // We invoke this on the main thread to ensure signals (beginResetModel) are processed synchronously
+            // with the data update, preventing race conditions or ignored updates in the view.
+            QMetaObject::invokeMethod(this, [this]{
+                if (m_history) m_history->refresh();
+                if (m_coins) m_coins->refresh();
+                if (m_subaddress) m_subaddress->refresh();
+            }, Qt::QueuedConnection);
+
+        } catch (const std::exception &e) {
+            qWarning() << "Failed to scan mempool:" << e.what();
+        }
     }
+    emit updated();
 }
 
 Wallet::~Wallet()
index 1c85d9b3248fad8213db5902765b753abc2292ef..d1beccf5f25737673821a79a5644e1c17706305d 100644 (file)
@@ -516,9 +516,9 @@ private:
     AddressBook *m_addressBook;
     AddressBookModel *m_addressBookModel;
 
-    quint64 m_daemonBlockChainHeight;
-    quint64 m_daemonBlockChainTargetHeight;
-    QDateTime m_lastSyncTime;
+    std::atomic<quint64> m_daemonBlockChainHeight;
+    std::atomic<quint64> m_daemonBlockChainTargetHeight;
+    std::atomic<qint64> m_lastSyncTime;
 
     ConnectionStatus m_connectionStatus;
 
@@ -553,7 +553,7 @@ private:
     std::atomic<quint64> m_stopHeight{0};
     std::atomic<bool> m_rangeSyncActive{false};
     std::atomic<bool> m_syncPaused{false};
-    std::atomic<bool> m_lastRefreshTime{0};
+    std::atomic<quint64> m_lastRefreshTime{0};
     std::atomic<bool> m_pauseAfterSync{false};
     std::atomic<bool> m_refreshThreadStarted{false};
     std::atomic<bool> m_scanMempoolWhenPaused{false};
index 4b57478ec969c358c89f17ed5658eb7e225f8c4e..6d058396e30d0d575e436137a5bcea17c7e849df 100644 (file)
@@ -212,7 +212,7 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) {
 
     conf()->set(Config::restartRequired, false);
 
-    if (!quiet && !conf()->get(Config::disableLogging).toBool()) {
+    if (!quiet && !conf()->get(Config::disableLoggingStdout).toBool()) {
         QList<QPair<QString, QString>> info;
         info.emplace_back("Feather", FEATHER_VERSION);
         info.emplace_back("Monero", MONERO_VERSION);
index d9e42776f4893f2994c133420d912e2ec2ce2da2..c80ac2a440e132f8c1a8d8ee5300040162d3be29 100644 (file)
@@ -761,11 +761,13 @@ QString formatSyncTimeEstimate(quint64 blocks) {
     quint64 minutes = blocks * 2;
     quint64 days = minutes / (60 * 24);
 
+    quint64 hours = minutes / 60;
+
     QString timeStr;
     if (days > 0) {
-        timeStr = QObject::tr("~%1 days").arg(days);
+        timeStr = QObject::tr("~%1 day%2").arg(days).arg(days == 1 ? "" : "s");
     } else if (minutes >= 60) {
-        timeStr = QObject::tr("~%1 hours").arg(minutes / 60);
+        timeStr = QObject::tr("~%1 hour%2").arg(hours).arg(hours == 1 ? "" : "s");
     } else {
         timeStr = QObject::tr("< 1 hour");
     }