Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
d9beeec
qt: switch RPCConsole and leftover MasternodeList code to feed
kwvg Feb 18, 2026
960666b
qt: switch ProposalList to consume masternode list feed
kwvg Feb 21, 2026
b524eef
qt: precompute mappings to avoid expensive searches
kwvg Feb 18, 2026
dfec7d8
fix(qt): align headers in debug window's information tab
kwvg Jan 26, 2026
0a64bab
refactor(qt): move debug window stats to separate information widget
kwvg Feb 20, 2026
918cba1
refactor(qt): move Dash-specific reporting to network widget
kwvg Feb 20, 2026
6bb3e6b
chore(qt): update header and label descriptions based on capability
kwvg Feb 19, 2026
d1f61f5
refactor: drop now-unused cached masternode list routine
kwvg Feb 21, 2026
ba406f5
interfaces: introduce UI signal `NotifyInstantSendChanged`
kwvg Feb 16, 2026
654724d
qt: register instantsend information as a feed, replace polling approach
kwvg Feb 19, 2026
ab8d6d2
qt: register chainlocks information as a feed, treat UI notif as trigger
kwvg Feb 19, 2026
a4e9fbc
qt: report chainlock time to maintain parity with block fields
kwvg Feb 18, 2026
b9a14cc
qt: show more instantsend counters (pending, waiting, unprotected) in UI
kwvg Feb 21, 2026
26ed211
feat(qt): report credit pool statistics in network widget
kwvg Feb 21, 2026
12dc7fe
feat(qt): report quorum statistics in network widget
kwvg Feb 22, 2026
dff26d6
refactor(qt): use horizontal layout with vertical grids, reorder data
kwvg Feb 21, 2026
8a721c2
refactor(qt): move "Chainlocks" outside hlayout due to value width
kwvg Feb 19, 2026
7839115
feat(qt): add tooltip for quorum statistics with rotation, expiry, age
kwvg Feb 20, 2026
f85a459
refactor(qt): move debug log action from General widget to File menu
kwvg Feb 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/Makefile.qt.include
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ QT_FORMS_UI = \
qt/forms/descriptiondialog.ui \
qt/forms/editaddressdialog.ui \
qt/forms/helpmessagedialog.ui \
qt/forms/informationwidget.ui \
qt/forms/intro.ui \
qt/forms/masternodelist.ui \
qt/forms/mnemonicverificationdialog.ui \
qt/forms/modaloverlay.ui \
qt/forms/networkwidget.ui \
qt/forms/openuridialog.ui \
qt/forms/optionsdialog.ui \
qt/forms/overviewpage.ui \
Expand Down Expand Up @@ -62,6 +64,7 @@ QT_MOC_CPP = \
qt/moc_descriptiondialog.cpp \
qt/moc_editaddressdialog.cpp \
qt/moc_guiutil.cpp \
qt/moc_informationwidget.cpp \
qt/moc_initexecutor.cpp \
qt/moc_intro.cpp \
qt/moc_macdockiconhandler.cpp \
Expand All @@ -70,6 +73,7 @@ QT_MOC_CPP = \
qt/moc_masternodemodel.cpp \
qt/moc_mnemonicverificationdialog.cpp \
qt/moc_modaloverlay.cpp \
qt/moc_networkwidget.cpp \
qt/moc_notificator.cpp \
qt/moc_openuridialog.cpp \
qt/moc_optionsdialog.cpp \
Expand Down Expand Up @@ -145,6 +149,7 @@ BITCOIN_QT_H = \
qt/guiconstants.h \
qt/guiutil_font.h \
qt/guiutil.h \
qt/informationwidget.h \
qt/initexecutor.h \
qt/intro.h \
qt/macdockiconhandler.h \
Expand All @@ -155,6 +160,7 @@ BITCOIN_QT_H = \
qt/mnemonicverificationdialog.h \
qt/modaloverlay.h \
qt/networkstyle.h \
qt/networkwidget.h \
qt/notificator.h \
qt/openuridialog.h \
qt/optionsdialog.h \
Expand Down Expand Up @@ -189,6 +195,7 @@ BITCOIN_QT_H = \
qt/transactionrecord.h \
qt/transactiontablemodel.h \
qt/transactionview.h \
qt/util.h \
qt/utilitydialog.h \
qt/walletcontroller.h \
qt/walletframe.h \
Expand Down Expand Up @@ -254,10 +261,12 @@ BITCOIN_QT_BASE_CPP = \
qt/csvmodelwriter.cpp \
qt/guiutil.cpp \
qt/guiutil_font.cpp \
qt/informationwidget.cpp \
qt/initexecutor.cpp \
qt/intro.cpp \
qt/modaloverlay.cpp \
qt/networkstyle.cpp \
qt/networkwidget.cpp \
qt/notificator.cpp \
qt/optionsdialog.cpp \
qt/optionsmodel.cpp \
Expand Down
2 changes: 2 additions & 0 deletions src/instantsend/net_instantsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <instantsend/net_instantsend.h>

#include <bls/bls_batchverifier.h>
#include <node/interface_ui.h>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix clang-format issue flagged by CI.

The pipeline reports a clang-format difference in this file. The include ordering likely needs adjustment — <node/interface_ui.h> appears before <cxxtimer.hpp>, but the project's clang-format rules may expect a different sort order.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/instantsend/net_instantsend.cpp` at line 8, The CI clang-format failure
is caused by incorrect include ordering: move or reorder the include lines so
they follow the project's sorted include convention (put <cxxtimer.hpp> before
<node/interface_ui.h>, or run the repository's clang-format configuration on
src/instantsend/net_instantsend.cpp) so the header ordering matches the
project's style.

#include <cxxtimer.hpp>
#include <instantsend/instantsend.h>
#include <llmq/commitment.h>
Expand Down Expand Up @@ -307,6 +308,7 @@ void NetInstantSend::ProcessPendingISLocks(std::vector<instantsend::PendingISLoc
// Now check against the previous active set and perform banning if this fails
ProcessPendingInstantSendLocks(llmq_params, dkgInterval, /*ban=*/true, still_pending);
}
uiInterface.NotifyInstantSendChanged();
}

void NetInstantSend::WorkThreadMain()
Expand Down
10 changes: 4 additions & 6 deletions src/interfaces/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,19 +115,13 @@ class MnList
virtual uint256 getBlockHash() const = 0;

virtual void forEachMN(bool only_valid, std::function<void(const MnEntryCPtr&)> cb) const = 0;
virtual MnEntryCPtr getMN(const uint256& hash) const = 0;
virtual MnEntryCPtr getMNByService(const CService& service) const = 0;
virtual MnEntryCPtr getValidMN(const uint256& hash) const = 0;
virtual std::vector<MnEntryCPtr> getProjectedMNPayees(const CBlockIndex* pindex) const = 0;

virtual void copyContextTo(MnList& mn_list) const = 0;
virtual void setContext(node::NodeContext* context) = 0;
};

using MnListPtr = std::shared_ptr<MnList>;

MnListPtr MakeMNList(const CDeterministicMNList& mn_list);

//! Interface for the src/evo part of a dash node (dashd process).
class EVO
{
Expand Down Expand Up @@ -517,6 +511,10 @@ class Node
std::function<void(SynchronizationState, interfaces::BlockTip tip, double verification_progress)>;
virtual std::unique_ptr<Handler> handleNotifyHeaderTip(NotifyHeaderTipFn fn) = 0;

//! Register handler for InstantSend data messages.
using NotifyInstantSendChangedFn = std::function<void()>;
virtual std::unique_ptr<Handler> handleNotifyInstantSendChanged(NotifyInstantSendChangedFn fn) = 0;

//! Register handler for governance data messages.
using NotifyGovernanceChangedFn = std::function<void()>;
virtual std::unique_ptr<Handler> handleNotifyGovernanceChanged(NotifyGovernanceChangedFn fn) = 0;
Expand Down
3 changes: 3 additions & 0 deletions src/node/interface_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct UISignals {
boost::signals2::signal<CClientUIInterface::NotifyChainLockSig> NotifyChainLock;
boost::signals2::signal<CClientUIInterface::NotifyHeaderTipSig> NotifyHeaderTip;
boost::signals2::signal<CClientUIInterface::NotifyGovernanceChangedSig> NotifyGovernanceChanged;
boost::signals2::signal<CClientUIInterface::NotifyInstantSendChangedSig> NotifyInstantSendChanged;
boost::signals2::signal<CClientUIInterface::NotifyMasternodeListChangedSig> NotifyMasternodeListChanged;
boost::signals2::signal<CClientUIInterface::NotifyAdditionalDataSyncProgressChangedSig> NotifyAdditionalDataSyncProgressChanged;
boost::signals2::signal<CClientUIInterface::BannedListChangedSig> BannedListChanged;
Expand All @@ -48,6 +49,7 @@ ADD_SIGNALS_IMPL_WRAPPER(NotifyBlockTip);
ADD_SIGNALS_IMPL_WRAPPER(NotifyChainLock);
ADD_SIGNALS_IMPL_WRAPPER(NotifyHeaderTip);
ADD_SIGNALS_IMPL_WRAPPER(NotifyGovernanceChanged);
ADD_SIGNALS_IMPL_WRAPPER(NotifyInstantSendChanged);
ADD_SIGNALS_IMPL_WRAPPER(NotifyMasternodeListChanged);
ADD_SIGNALS_IMPL_WRAPPER(NotifyAdditionalDataSyncProgressChanged);
ADD_SIGNALS_IMPL_WRAPPER(BannedListChanged);
Expand All @@ -64,6 +66,7 @@ void CClientUIInterface::NotifyBlockTip(SynchronizationState s, const CBlockInde
void CClientUIInterface::NotifyChainLock(const std::string& bestChainLockHash, int bestChainLockHeight) { return g_ui_signals.NotifyChainLock(bestChainLockHash, bestChainLockHeight); }
void CClientUIInterface::NotifyHeaderTip(SynchronizationState s, const CBlockIndex* i) { return g_ui_signals.NotifyHeaderTip(s, i); }
void CClientUIInterface::NotifyGovernanceChanged() { return g_ui_signals.NotifyGovernanceChanged(); }
void CClientUIInterface::NotifyInstantSendChanged() { return g_ui_signals.NotifyInstantSendChanged(); }
void CClientUIInterface::NotifyMasternodeListChanged(const CDeterministicMNList& list, const CBlockIndex* i) { return g_ui_signals.NotifyMasternodeListChanged(list, i); }
void CClientUIInterface::NotifyAdditionalDataSyncProgressChanged(double nSyncProgress) { return g_ui_signals.NotifyAdditionalDataSyncProgressChanged(nSyncProgress); }
void CClientUIInterface::BannedListChanged() { return g_ui_signals.BannedListChanged(); }
Expand Down
3 changes: 3 additions & 0 deletions src/node/interface_ui.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ class CClientUIInterface
/** Masternode list has changed */
ADD_SIGNALS_DECL_WRAPPER(NotifyMasternodeListChanged, void, const CDeterministicMNList&, const CBlockIndex*);

/** InstantSend data changed */
ADD_SIGNALS_DECL_WRAPPER(NotifyInstantSendChanged, void);

/** Governance data changed */
ADD_SIGNALS_DECL_WRAPPER(NotifyGovernanceChanged, void);

Expand Down
25 changes: 4 additions & 21 deletions src/node/interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,21 +164,6 @@ class MnListImpl : public MnList
cb(std::make_shared<const MnEntryImpl>(dmn));
});
}
MnEntryCPtr getMN(const uint256& hash) const override
{
const auto dmn{m_list.GetMN(hash)};
return dmn ? std::make_shared<const MnEntryImpl>(dmn) : nullptr;
}
MnEntryCPtr getMNByService(const CService& service) const override
{
const auto dmn{m_list.GetMNByService(service)};
return dmn ? std::make_shared<const MnEntryImpl>(dmn) : nullptr;
}
MnEntryCPtr getValidMN(const uint256& hash) const override
{
const auto dmn{m_list.GetValidMN(hash)};
return dmn ? std::make_shared<const MnEntryImpl>(dmn) : nullptr;
}
std::vector<MnEntryCPtr> getProjectedMNPayees(const CBlockIndex* pindex) const override
{
std::vector<MnEntryCPtr> ret;
Expand All @@ -188,11 +173,6 @@ class MnListImpl : public MnList
return ret;
}

void copyContextTo(MnList& mn_list) const override
{
if (!m_context) return;
mn_list.setContext(m_context);
}
void setContext(NodeContext* context) override
{
m_context = context;
Expand Down Expand Up @@ -1023,6 +1003,10 @@ class NodeImpl : public Node
/* verification progress is unused when a header was received */ 0);
}));
}
std::unique_ptr<Handler> handleNotifyInstantSendChanged(NotifyInstantSendChangedFn fn) override
{
return MakeHandler(::uiInterface.NotifyInstantSendChanged_connect(fn));
}
std::unique_ptr<Handler> handleNotifyGovernanceChanged(NotifyGovernanceChangedFn fn) override
{
return MakeHandler(::uiInterface.NotifyGovernanceChanged_connect(fn));
Expand Down Expand Up @@ -1503,5 +1487,4 @@ class ChainImpl : public Chain
namespace interfaces {
std::unique_ptr<Node> MakeNode(node::NodeContext& context) { return std::make_unique<node::NodeImpl>(context); }
std::unique_ptr<Chain> MakeChain(node::NodeContext& node) { return std::make_unique<node::ChainImpl>(node); }
MnListPtr MakeMNList(const CDeterministicMNList& mn_list) { return std::make_shared<node::MnListImpl>(mn_list); }
} // namespace interfaces
16 changes: 11 additions & 5 deletions src/qt/bitcoingui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,8 @@ void BitcoinGUI::createActions()
openPeersAction->setStatusTip(tr("Show peers info"));
openRepairAction = new QAction(tr("Wallet &Repair"), this);
openRepairAction->setStatusTip(tr("Show wallet repair options"));
openDebugLogAction = new QAction(tr("Open &debug log file"), this);
openDebugLogAction->setStatusTip(tr("Open the debug log file from the current data directory"));
openConfEditorAction = new QAction(tr("Open &wallet configuration file"), this);
openConfEditorAction->setStatusTip(tr("Open configuration file"));
// override TextHeuristicRole set by default which confuses this action with application settings
Expand Down Expand Up @@ -517,7 +519,8 @@ void BitcoinGUI::createActions()
connect(openPeersAction, &QAction::triggered, this, &BitcoinGUI::showPeers);
connect(openRepairAction, &QAction::triggered, this, &BitcoinGUI::showRepair);

// Open configs and backup folder from menu
// Open logs, configs, and backup folder from menu
connect(openDebugLogAction, &QAction::triggered, GUIUtil::openDebugLogfile);
connect(openConfEditorAction, &QAction::triggered, this, &BitcoinGUI::showConfEditor);
connect(showBackupsAction, &QAction::triggered, this, &BitcoinGUI::showBackups);

Expand Down Expand Up @@ -640,6 +643,7 @@ void BitcoinGUI::createMenuBar()
file->addAction(m_load_psbt_clipboard_action);
file->addSeparator();
}
file->addAction(openDebugLogAction);
file->addAction(openConfEditorAction);
if(walletFrame) {
file->addAction(showBackupsAction);
Expand Down Expand Up @@ -1142,6 +1146,7 @@ void BitcoinGUI::createIconMenu(QMenu *pmenu)
repair_action = pmenu->addAction(openRepairAction->text(), openRepairAction, &QAction::trigger);
}
pmenu->addSeparator();
QAction* debuglog_action = pmenu->addAction(openDebugLogAction->text(), openDebugLogAction, &QAction::trigger);
QAction* conf_action = pmenu->addAction(openConfEditorAction->text(), openConfEditorAction, &QAction::trigger);
QAction* backups_action{nullptr};
if (enableWallet) {
Expand All @@ -1158,7 +1163,7 @@ void BitcoinGUI::createIconMenu(QMenu *pmenu)
// Using QSystemTrayIcon::Context is not reliable.
// See https://bugreports.qt.io/browse/QTBUG-91697
pmenu, &QMenu::aboutToShow,
[this, show_hide_action, send_action, cj_send_action, receive_action, sign_action, verify_action, options_action, node_window_action, quit_action, repair_action, backups_action, info_action, graph_action, peer_action, conf_action] {
[this, show_hide_action, send_action, cj_send_action, receive_action, sign_action, verify_action, options_action, node_window_action, quit_action, repair_action, backups_action, info_action, graph_action, peer_action, debuglog_action, conf_action] {
if (m_node.shutdownRequested()) return; // nothing to do, node is shutting down.

if (show_hide_action) show_hide_action->setText(
Expand All @@ -1185,6 +1190,7 @@ void BitcoinGUI::createIconMenu(QMenu *pmenu)
node_window_action->setEnabled(openRPCConsoleAction->isEnabled());
graph_action->setEnabled(openGraphAction->isEnabled());
peer_action->setEnabled(openPeersAction->isEnabled());
debuglog_action->setEnabled(openDebugLogAction->isEnabled());
conf_action->setEnabled(openConfEditorAction->isEnabled());
if (quit_action) quit_action->setEnabled(true);
}
Expand Down Expand Up @@ -1809,20 +1815,20 @@ void BitcoinGUI::updateGovernanceCycleIcon()

const auto gov_info{m_node.gov().getGovernanceInfo()};
const auto remaining_blocks{std::max<int>(0, gov_info.nextsuperblock - current_height)};
const auto days{static_cast<int>(static_cast<int64_t>(remaining_blocks) * gov_info.targetSpacing / (24*60*60))};
const auto remaining_str{GUIUtil::formatBlockDuration(remaining_blocks, gov_info.targetSpacing)};
const bool awaiting_superblock{current_height % gov_info.superblockcycle >= gov_info.superblockcycle - gov_info.superblockmaturitywindow};

QString tooltip1{};
if (awaiting_superblock) {
labelGovernanceCycleIcon->setPixmap(m_gov_cycle_pixmaps.at({ToUnderlying(GUIUtil::ThemedColor::BLUE), 0}));
tooltip1 = tr("~%n day(s) (%1 blocks) left for superblock", "", days).arg(remaining_blocks);
tooltip1 = tr("~%1 (%2 blocks) left for superblock").arg(remaining_str).arg(remaining_blocks);
} else {
const auto cycle_blocks{gov_info.superblockcycle - gov_info.superblockmaturitywindow};
const auto blocks_elapsed{gov_info.superblockcycle - remaining_blocks - gov_info.superblockmaturitywindow};
const auto progress{static_cast<double>(std::max(0, blocks_elapsed)) / static_cast<double>(std::max(1, cycle_blocks))};
const auto frame{std::clamp<int>(static_cast<int>(progress * (GOV_CYCLE_FRAME_COUNT - 1)), 0, GOV_CYCLE_FRAME_COUNT - 2) + 1};
labelGovernanceCycleIcon->setPixmap(m_gov_cycle_pixmaps.at({ToUnderlying(GUIUtil::ThemedColor::GREEN), frame}));
tooltip1 = tr("~%n day(s) (%1 blocks) left for voting", "", days).arg(remaining_blocks);
tooltip1 = tr("~%1 (%2 blocks) left for voting").arg(remaining_str).arg(remaining_blocks);
}

const auto allocated_budget{m_node.gov().getFundableProposalHashes().allocated};
Expand Down
1 change: 1 addition & 0 deletions src/qt/bitcoingui.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ class BitcoinGUI : public QMainWindow
QAction* openGraphAction = nullptr;
QAction* openPeersAction = nullptr;
QAction* openRepairAction = nullptr;
QAction* openDebugLogAction = nullptr;
QAction* openConfEditorAction = nullptr;
QAction* showBackupsAction = nullptr;
QAction* openAction = nullptr;
Expand Down
Loading
Loading