From f2090f1971bcd941acfb5ad0c740684a35f8b4ac Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 16 Feb 2019 23:59:16 +0000 Subject: [PATCH 01/11] Add signals for network local address added/removed --- src/interfaces/node.h | 4 ++++ src/net.cpp | 15 ++++++++++++--- src/node/interface_ui.cpp | 3 +++ src/node/interface_ui.h | 3 +++ src/node/interfaces.cpp | 4 ++++ src/qt/clientmodel.cpp | 5 +++++ src/qt/clientmodel.h | 2 ++ 7 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/interfaces/node.h b/src/interfaces/node.h index 3f8df57124..70c9bdcd8f 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -245,6 +245,10 @@ public: using NotifyNetworkActiveChangedFn = std::function; virtual std::unique_ptr handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn) = 0; + //! Register handler for network local changed messages. + using NotifyNetworkLocalChangedFn = std::function; + virtual std::unique_ptr handleNotifyNetworkLocalChanged(NotifyNetworkLocalChangedFn fn) = 0; + //! Register handler for notify alert messages. using NotifyAlertChangedFn = std::function; virtual std::unique_ptr handleNotifyAlertChanged(NotifyAlertChangedFn fn) = 0; diff --git a/src/net.cpp b/src/net.cpp index 5305e1148a..2531a57566 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -285,9 +285,11 @@ bool AddLocal(const CService& addr_, int nScore) LogPrintf("AddLocal(%s,%i)\n", addr.ToStringAddrPort(), nScore); + bool fAlready; { LOCK(g_maplocalhost_mutex); const auto [it, is_newly_added] = mapLocalHost.emplace(addr, LocalServiceInfo()); + fAlready = !is_newly_added; LocalServiceInfo &info = it->second; if (is_newly_added || nScore >= info.nScore) { info.nScore = nScore + (is_newly_added ? 0 : 1); @@ -295,6 +297,10 @@ bool AddLocal(const CService& addr_, int nScore) } } + if (!fAlready) { + uiInterface.NotifyNetworkLocalChanged(); + } + return true; } @@ -305,9 +311,12 @@ bool AddLocal(const CNetAddr &addr, int nScore) void RemoveLocal(const CService& addr) { - LOCK(g_maplocalhost_mutex); - LogPrintf("RemoveLocal(%s)\n", addr.ToStringAddrPort()); - mapLocalHost.erase(addr); + { + LOCK(g_maplocalhost_mutex); + LogPrintf("RemoveLocal(%s)\n", addr.ToStringAddrPort()); + mapLocalHost.erase(addr); + } + uiInterface.NotifyNetworkLocalChanged(); } /** vote for a local address */ diff --git a/src/node/interface_ui.cpp b/src/node/interface_ui.cpp index 9dd1e7d9cf..2de62f98c7 100644 --- a/src/node/interface_ui.cpp +++ b/src/node/interface_ui.cpp @@ -19,6 +19,7 @@ struct UISignals { boost::signals2::signal InitWallet; boost::signals2::signal NotifyNumConnectionsChanged; boost::signals2::signal NotifyNetworkActiveChanged; + boost::signals2::signal NotifyNetworkLocalChanged; boost::signals2::signal NotifyAlertChanged; boost::signals2::signal ShowProgress; boost::signals2::signal NotifyBlockTip; @@ -39,6 +40,7 @@ ADD_SIGNALS_IMPL_WRAPPER(InitMessage); ADD_SIGNALS_IMPL_WRAPPER(InitWallet); ADD_SIGNALS_IMPL_WRAPPER(NotifyNumConnectionsChanged); ADD_SIGNALS_IMPL_WRAPPER(NotifyNetworkActiveChanged); +ADD_SIGNALS_IMPL_WRAPPER(NotifyNetworkLocalChanged); ADD_SIGNALS_IMPL_WRAPPER(NotifyAlertChanged); ADD_SIGNALS_IMPL_WRAPPER(ShowProgress); ADD_SIGNALS_IMPL_WRAPPER(NotifyBlockTip); @@ -51,6 +53,7 @@ void CClientUIInterface::InitMessage(const std::string& message) { return g_ui_s void CClientUIInterface::InitWallet() { return g_ui_signals.InitWallet(); } void CClientUIInterface::NotifyNumConnectionsChanged(int newNumConnections) { return g_ui_signals.NotifyNumConnectionsChanged(newNumConnections); } void CClientUIInterface::NotifyNetworkActiveChanged(bool networkActive) { return g_ui_signals.NotifyNetworkActiveChanged(networkActive); } +void CClientUIInterface::NotifyNetworkLocalChanged() { return g_ui_signals.NotifyNetworkLocalChanged(); } void CClientUIInterface::NotifyAlertChanged() { return g_ui_signals.NotifyAlertChanged(); } void CClientUIInterface::ShowProgress(const std::string& title, int nProgress, bool resume_possible) { return g_ui_signals.ShowProgress(title, nProgress, resume_possible); } void CClientUIInterface::NotifyBlockTip(SynchronizationState s, const CBlockIndex* i) { return g_ui_signals.NotifyBlockTip(s, i); } diff --git a/src/node/interface_ui.h b/src/node/interface_ui.h index 22c241cb78..5799c075dd 100644 --- a/src/node/interface_ui.h +++ b/src/node/interface_ui.h @@ -90,6 +90,9 @@ public: /** Network activity state changed. */ ADD_SIGNALS_DECL_WRAPPER(NotifyNetworkActiveChanged, void, bool networkActive); + /** Network local addresses changed. */ + ADD_SIGNALS_DECL_WRAPPER(NotifyNetworkLocalChanged, void, ); + /** * Status bar alerts changed. */ diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index 4c2c4f79c4..b553d2d1a4 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -369,6 +369,10 @@ public: { return MakeSignalHandler(::uiInterface.NotifyNetworkActiveChanged_connect(fn)); } + std::unique_ptr handleNotifyNetworkLocalChanged(NotifyNetworkLocalChangedFn fn) override + { + return MakeSignalHandler(::uiInterface.NotifyNetworkLocalChanged_connect(fn)); + } std::unique_ptr handleNotifyAlertChanged(NotifyAlertChangedFn fn) override { return MakeSignalHandler(::uiInterface.NotifyAlertChanged_connect(fn)); diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 84fae2153a..ae959fcf09 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -251,6 +251,10 @@ void ClientModel::subscribeToCoreSignals() [this](bool network_active) { Q_EMIT networkActiveChanged(network_active); }); + m_handler_notify_network_local_changed = m_node.handleNotifyNetworkLocalChanged( + [this]() { + Q_EMIT networkLocalChanged(); + }); m_handler_notify_alert_changed = m_node.handleNotifyAlertChanged( [this]() { qDebug() << "ClientModel: NotifyAlertChanged"; @@ -278,6 +282,7 @@ void ClientModel::unsubscribeFromCoreSignals() m_handler_show_progress->disconnect(); m_handler_notify_num_connections_changed->disconnect(); m_handler_notify_network_active_changed->disconnect(); + m_handler_notify_network_local_changed->disconnect(); m_handler_notify_alert_changed->disconnect(); m_handler_banned_list_changed->disconnect(); m_handler_notify_block_tip->disconnect(); diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 2177b7e660..968f3ebd6f 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -101,6 +101,7 @@ private: std::unique_ptr m_handler_show_progress; std::unique_ptr m_handler_notify_num_connections_changed; std::unique_ptr m_handler_notify_network_active_changed; + std::unique_ptr m_handler_notify_network_local_changed; std::unique_ptr m_handler_notify_alert_changed; std::unique_ptr m_handler_banned_list_changed; std::unique_ptr m_handler_notify_block_tip; @@ -123,6 +124,7 @@ Q_SIGNALS: void numBlocksChanged(int count, const QDateTime& blockDate, double nVerificationProgress, SyncType header, SynchronizationState sync_state); void mempoolSizeChanged(long count, size_t mempoolSizeInBytes); void networkActiveChanged(bool networkActive); + void networkLocalChanged(); void alertsChanged(const QString &warnings); void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut); From 0e4f610a291d62d2d2f79a1791ac103ccb0dca9d Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sun, 17 Feb 2019 00:19:22 +0000 Subject: [PATCH 02/11] GUI: Add getTorInfo to ClientModel --- src/interfaces/node.h | 4 ++++ src/node/interfaces.cpp | 9 +++++++++ src/qt/clientmodel.cpp | 11 +++++++++++ src/qt/clientmodel.h | 1 + 4 files changed, 25 insertions(+) diff --git a/src/interfaces/node.h b/src/interfaces/node.h index 70c9bdcd8f..e8691c6144 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -24,6 +24,7 @@ class BanMan; class CFeeRate; +class CNetAddr; class CNodeStats; class Coin; class RPCTimerInterface; @@ -125,6 +126,9 @@ public: //! Get proxy. virtual bool getProxy(Network net, Proxy& proxy_info) = 0; + //! Get local network addresses. + virtual std::vector getNetLocalAddresses() = 0; + //! Get number of connections. virtual size_t getNodeCount(ConnectionDirection flags) = 0; diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index b553d2d1a4..e04af424a4 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -170,6 +170,15 @@ public: } void mapPort(bool use_upnp, bool use_natpmp) override { StartMapPort(use_upnp, use_natpmp); } bool getProxy(Network net, Proxy& proxy_info) override { return GetProxy(net, proxy_info); } + std::vector getNetLocalAddresses() override + { + std::vector ret; + LOCK(g_maplocalhost_mutex); + for (const std::pair &item : mapLocalHost) { + ret.emplace_back(item.first); + } + return ret; + } size_t getNodeCount(ConnectionDirection flags) override { return m_context->connman ? m_context->connman->GetNodeCount(flags) : 0; diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index ae959fcf09..35ad5b94e1 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -301,6 +301,17 @@ bool ClientModel::getProxyInfo(std::string& ip_port) const return false; } +bool ClientModel::getTorInfo(QString& out_onion) const +{ + for (const auto& addr : m_node.getNetLocalAddresses()) { + if (addr.IsTor()) { + out_onion = QString::fromStdString(addr.ToStringAddr()); + return true; + } + } + return false; +} + mempoolSamples_t ClientModel::getMempoolStatsInRange(QDateTime &from, QDateTime &to) { // get stats from the core stats model diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h index 968f3ebd6f..6922b7b902 100644 --- a/src/qt/clientmodel.h +++ b/src/qt/clientmodel.h @@ -85,6 +85,7 @@ public: QString blocksDir() const; bool getProxyInfo(std::string& ip_port) const; + bool getTorInfo(QString& out_onion) const; // caches for the best header: hash, number of blocks and block time mutable std::atomic cachedBestHeaderHeight; From 3df090f24d57e8f3fa84ef76ec45449c46111e60 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 16 Feb 2019 18:30:36 +0000 Subject: [PATCH 03/11] GUI: Add an extra stack to WalletFrame so non-wallet tabs are possible --- src/qt/walletframe.cpp | 8 +++++++- src/qt/walletframe.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 7a8a053900..825f5756d8 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -35,8 +35,10 @@ WalletFrame::WalletFrame(const PlatformStyle* _platformStyle, QWidget* parent) QHBoxLayout *walletFrameLayout = new QHBoxLayout(this); setContentsMargins(0,0,0,0); walletStack = new QStackedWidget(this); + m_global_stack = new QStackedWidget(this); + m_global_stack->addWidget(walletStack); walletFrameLayout->setContentsMargins(0,0,0,0); - walletFrameLayout->addWidget(walletStack); + walletFrameLayout->addWidget(m_global_stack); // hbox for no wallet QGroupBox* no_wallet_group = new QGroupBox(walletStack); @@ -153,6 +155,7 @@ void WalletFrame::gotoOverviewPage() QMap::const_iterator i; for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) i.value()->gotoOverviewPage(); + m_global_stack->setCurrentWidget(walletStack); } void WalletFrame::gotoHistoryPage() @@ -160,6 +163,7 @@ void WalletFrame::gotoHistoryPage() QMap::const_iterator i; for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) i.value()->gotoHistoryPage(); + m_global_stack->setCurrentWidget(walletStack); } void WalletFrame::gotoReceiveCoinsPage() @@ -167,6 +171,7 @@ void WalletFrame::gotoReceiveCoinsPage() QMap::const_iterator i; for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) i.value()->gotoReceiveCoinsPage(); + m_global_stack->setCurrentWidget(walletStack); } void WalletFrame::gotoSendCoinsPage(QString addr) @@ -174,6 +179,7 @@ void WalletFrame::gotoSendCoinsPage(QString addr) QMap::const_iterator i; for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) i.value()->gotoSendCoinsPage(addr); + m_global_stack->setCurrentWidget(walletStack); } void WalletFrame::gotoSignMessageTab(QString addr) diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index 60c97ff76a..d9c5b170c6 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -52,6 +52,7 @@ Q_SIGNALS: void currentWalletSet(); private: + QStackedWidget *m_global_stack; QStackedWidget *walletStack; ClientModel *clientModel; QMap mapWalletViews; From 0cb97fb471d35211c469fa32b2dbfd9e7ba5bb9e Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 16 Feb 2019 18:46:55 +0000 Subject: [PATCH 04/11] GUI: Add a new tab for pairing --- src/Makefile.qt.include | 3 +++ src/qt/bitcoingui.cpp | 17 ++++++++++++++++- src/qt/bitcoingui.h | 3 +++ src/qt/pairingpage.cpp | 10 ++++++++++ src/qt/pairingpage.h | 19 +++++++++++++++++++ src/qt/walletframe.cpp | 9 +++++++++ src/qt/walletframe.h | 5 +++++ 7 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/qt/pairingpage.cpp create mode 100644 src/qt/pairingpage.h diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index cc6307bf9e..ad51305b34 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -64,6 +64,7 @@ QT_MOC_CPP = \ qt/moc_optionsdialog.cpp \ qt/moc_optionsmodel.cpp \ qt/moc_overviewpage.cpp \ + qt/moc_pairingpage.cpp \ qt/moc_peertablemodel.cpp \ qt/moc_peertablesortproxy.cpp \ qt/moc_paymentserver.cpp \ @@ -140,6 +141,7 @@ BITCOIN_QT_H = \ qt/optionsdialog.h \ qt/optionsmodel.h \ qt/overviewpage.h \ + qt/pairingpage.h \ qt/paymentserver.h \ qt/peertablemodel.h \ qt/peertablesortproxy.h \ @@ -265,6 +267,7 @@ BITCOIN_QT_WALLET_CPP = \ qt/editaddressdialog.cpp \ qt/openuridialog.cpp \ qt/overviewpage.cpp \ + qt/pairingpage.cpp \ qt/paymentserver.cpp \ qt/psbtoperationsdialog.cpp \ qt/qrimagewidget.cpp \ diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index eb8e9bdfeb..3dc66a100f 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -278,6 +278,13 @@ void BitcoinGUI::createActions() historyAction->setShortcut(QKeySequence(QStringLiteral("Alt+4"))); tabGroup->addAction(historyAction); + m_action_pairing = new QAction(platformStyle->SingleColorIcon(":/icons/connect_1"), tr("&Pairing"), this); + m_action_pairing->setStatusTip(tr("Pair other software or devices with your node")); + m_action_pairing->setToolTip(m_action_pairing->statusTip()); + m_action_pairing->setCheckable(true); + m_action_pairing->setShortcut(QKeySequence(QStringLiteral("Alt+5"))); + tabGroup->addAction(m_action_pairing); + #ifdef ENABLE_WALLET // These showNormalIfMinimized are needed because Send Coins and Receive Coins // can be triggered from the tray menu, and need to show the GUI to be useful. @@ -289,6 +296,8 @@ void BitcoinGUI::createActions() connect(receiveCoinsAction, &QAction::triggered, this, &BitcoinGUI::gotoReceiveCoinsPage); connect(historyAction, &QAction::triggered, [this]{ showNormalIfMinimized(); }); connect(historyAction, &QAction::triggered, this, &BitcoinGUI::gotoHistoryPage); + connect(m_action_pairing, &QAction::triggered, this, [this]{ showNormalIfMinimized(); }); + connect(m_action_pairing, &QAction::triggered, this, &BitcoinGUI::gotoPairingPage); #endif // ENABLE_WALLET quitAction = new QAction(tr("E&xit"), this); @@ -592,6 +601,7 @@ void BitcoinGUI::createToolBars() toolbar->addAction(sendCoinsAction); toolbar->addAction(receiveCoinsAction); toolbar->addAction(historyAction); + toolbar->addAction(m_action_pairing); overviewAction->setChecked(true); #ifdef ENABLE_WALLET @@ -813,7 +823,6 @@ void BitcoinGUI::removeAllWallets() void BitcoinGUI::setWalletActionsEnabled(bool enabled) { - overviewAction->setEnabled(enabled); sendCoinsAction->setEnabled(enabled); receiveCoinsAction->setEnabled(enabled); historyAction->setEnabled(enabled); @@ -997,6 +1006,12 @@ void BitcoinGUI::gotoOverviewPage() if (walletFrame) walletFrame->gotoOverviewPage(); } +void BitcoinGUI::gotoPairingPage() +{ + m_action_pairing->setChecked(true); + if (walletFrame) walletFrame->gotoPairingPage(); +} + void BitcoinGUI::gotoHistoryPage() { historyAction->setChecked(true); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index c23f871cc5..c3ea4316df 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -137,6 +137,7 @@ private: QMenuBar* appMenuBar = nullptr; QToolBar* appToolBar = nullptr; QAction* overviewAction = nullptr; + QAction* m_action_pairing = nullptr; QAction* historyAction = nullptr; QAction* quitAction = nullptr; QAction* sendCoinsAction = nullptr; @@ -285,6 +286,8 @@ public Q_SLOTS: #ifdef ENABLE_WALLET /** Switch to overview (home) page */ void gotoOverviewPage(); + /** Switch to pairing page */ + void gotoPairingPage(); /** Switch to history (transactions) page */ void gotoHistoryPage(); /** Switch to receive coins page */ diff --git a/src/qt/pairingpage.cpp b/src/qt/pairingpage.cpp new file mode 100644 index 0000000000..bedc5d32e5 --- /dev/null +++ b/src/qt/pairingpage.cpp @@ -0,0 +1,10 @@ +// Copyright (c) 2018 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +PairingPage::PairingPage(QWidget *parent) : + QWidget(parent) +{ +} diff --git a/src/qt/pairingpage.h b/src/qt/pairingpage.h new file mode 100644 index 0000000000..189143c205 --- /dev/null +++ b/src/qt/pairingpage.h @@ -0,0 +1,19 @@ +// Copyright (c) 2018 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_QT_PAIRINGPAGE_H +#define BITCOIN_QT_PAIRINGPAGE_H + +#include + +class PairingPage : public QWidget +{ + Q_OBJECT + +public: + explicit PairingPage(QWidget *parent = nullptr); + ~PairingPage() {} +}; + +#endif // BITCOIN_QT_PAIRINGPAGE_H diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 825f5756d8..4e217482c6 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include @@ -55,6 +56,9 @@ WalletFrame::WalletFrame(const PlatformStyle* _platformStyle, QWidget* parent) no_wallet_group->setLayout(no_wallet_layout); walletStack->addWidget(no_wallet_group); + + m_page_pairing = new PairingPage(this); + m_global_stack->addWidget(m_page_pairing); } WalletFrame::~WalletFrame() = default; @@ -158,6 +162,11 @@ void WalletFrame::gotoOverviewPage() m_global_stack->setCurrentWidget(walletStack); } +void WalletFrame::gotoPairingPage() +{ + m_global_stack->setCurrentWidget(m_page_pairing); +} + void WalletFrame::gotoHistoryPage() { QMap::const_iterator i; diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h index d9c5b170c6..2760714cd4 100644 --- a/src/qt/walletframe.h +++ b/src/qt/walletframe.h @@ -9,6 +9,7 @@ #include class ClientModel; +class PairingPage; class PlatformStyle; class SendCoinsRecipient; class WalletModel; @@ -57,6 +58,8 @@ private: ClientModel *clientModel; QMap mapWalletViews; + PairingPage *m_page_pairing; + bool bOutOfSync; const PlatformStyle *platformStyle; @@ -70,6 +73,8 @@ public: public Q_SLOTS: /** Switch to overview (home) page */ void gotoOverviewPage(); + /** Switch to pairing page */ + void gotoPairingPage(); /** Switch to history (transactions) page */ void gotoHistoryPage(); /** Switch to receive coins page */ From b1dc47e164875fae7e59938de24673b5d8e8450b Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sun, 17 Feb 2019 01:49:20 +0000 Subject: [PATCH 05/11] GUI: Show onion address as text & QR code in Pairing tab --- src/qt/pairingpage.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++ src/qt/pairingpage.h | 17 +++++++++++++ src/qt/walletframe.cpp | 2 ++ 3 files changed, 74 insertions(+) diff --git a/src/qt/pairingpage.cpp b/src/qt/pairingpage.cpp index bedc5d32e5..bdcede56c2 100644 --- a/src/qt/pairingpage.cpp +++ b/src/qt/pairingpage.cpp @@ -2,9 +2,64 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include #include +#include + +#include +#include +#include +#include PairingPage::PairingPage(QWidget *parent) : QWidget(parent) { + QVBoxLayout *layout = new QVBoxLayout(this); + + QLabel *label_summary = new QLabel(this); + label_summary->setText(tr("Below you will find information to pair other software or devices with this node:")); + layout->addWidget(label_summary); + + QFormLayout *form_layout = new QFormLayout(this); + m_onion_address = new QLineEdit(this); + m_onion_address->setReadOnly(true); + form_layout->addRow(tr("Onion address: "), m_onion_address); + + layout->addLayout(form_layout); + + m_qrcode = new QRImageWidget(this); +#ifdef USE_QRCODE + layout->addWidget(m_qrcode); +#endif + + layout->addStretch(); + + refresh(); +} + +void PairingPage::setClientModel(ClientModel *client_model) +{ + m_client_model = client_model; + connect(client_model, &ClientModel::networkLocalChanged, this, &PairingPage::refresh); + refresh(); +} + +void PairingPage::refresh() +{ + QString onion; + if (m_client_model && m_client_model->getTorInfo(onion)) { + m_onion_address->setText(onion); + m_onion_address->setEnabled(true); + QString uri = QString("bitcoin-p2p://") + onion; + m_qrcode->setQR(uri); + m_qrcode->setVisible(true); + } else { + m_onion_address->setText(tr("(not connected)")); + m_onion_address->setEnabled(false); + m_qrcode->setVisible(false); + } } diff --git a/src/qt/pairingpage.h b/src/qt/pairingpage.h index 189143c205..e37e91fc99 100644 --- a/src/qt/pairingpage.h +++ b/src/qt/pairingpage.h @@ -7,6 +7,13 @@ #include +class ClientModel; +class QRImageWidget; + +QT_BEGIN_NAMESPACE +class QLineEdit; +QT_END_NAMESPACE + class PairingPage : public QWidget { Q_OBJECT @@ -14,6 +21,16 @@ class PairingPage : public QWidget public: explicit PairingPage(QWidget *parent = nullptr); ~PairingPage() {} + + void setClientModel(ClientModel *); + +public Q_SLOTS: + void refresh(); + +private: + ClientModel *m_client_model{nullptr}; + QLineEdit *m_onion_address{nullptr}; + QRImageWidget *m_qrcode{nullptr}; }; #endif // BITCOIN_QT_PAIRINGPAGE_H diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp index 4e217482c6..952b0651a8 100644 --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -67,6 +67,8 @@ void WalletFrame::setClientModel(ClientModel *_clientModel) { this->clientModel = _clientModel; + m_page_pairing->setClientModel(_clientModel); + for (auto i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) { i.value()->setClientModel(_clientModel); } From cb29a8fa417b22105a39412f6c48a3efc86600f5 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 30 Apr 2019 23:27:51 +0000 Subject: [PATCH 06/11] GUI: Make RPCConsole tabs more flexible at runtime --- src/qt/rpcconsole.cpp | 30 ++++++++++++++++++++++++++++-- src/qt/rpcconsole.h | 3 ++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index ceaa3ac46b..ce7032b963 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -471,6 +471,12 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty platformStyle(_platformStyle) { ui->setupUi(this); + + // Default tabs are identified by their UI index + for (int i = ui->tabWidget->count(); i--; ) { + m_tabs[TabTypes(i)] = ui->tabWidget->widget(i); + } + QSettings settings; #ifdef ENABLE_WALLET if (WalletModel::isWalletEnabled()) { @@ -1360,14 +1366,34 @@ void RPCConsole::showOrHideBanTableIfRequired() ui->banHeading->setVisible(visible); } +std::vector RPCConsole::tabs() const +{ + std::vector ret; + ret.reserve(m_tabs.size()); + + std::map tabtype_map; + for (const auto& tab : m_tabs) { + tabtype_map[tab.second] = tab.first; + } + + for (int i = 0; i < ui->tabWidget->count(); ++i) { + auto tabtype = tabtype_map.find(ui->tabWidget->widget(i)); + if (tabtype != tabtype_map.end()) { + ret.push_back(tabtype->second); + } + } + return ret; +} + void RPCConsole::setTabFocus(enum TabTypes tabType) { - ui->tabWidget->setCurrentIndex(int(tabType)); + ui->tabWidget->setCurrentWidget(m_tabs[tabType]); } QString RPCConsole::tabTitle(TabTypes tab_type) const { - return ui->tabWidget->tabText(int(tab_type)); + const int tab_index = ui->tabWidget->indexOf(m_tabs.at(tab_type)); + return ui->tabWidget->tabText(tab_index); } QKeySequence RPCConsole::tabShortcut(TabTypes tab_type) const diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 344297ca97..c63341a038 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -76,7 +76,7 @@ public: PEERS }; - std::vector tabs() const { return {TabTypes::INFO, TabTypes::CONSOLE, TabTypes::GRAPH, TabTypes::PEERS}; } + std::vector tabs() const; QString tabTitle(TabTypes tab_type) const; QKeySequence tabShortcut(TabTypes tab_type) const; @@ -164,6 +164,7 @@ private: interfaces::Node& m_node; Ui::RPCConsole* const ui; ClientModel *clientModel = nullptr; + std::map m_tabs; GuiNetWatch *netwatch = nullptr; QStringList history; int historyPtr = 0; From f749b77c15eb52e4729e7f86f3bb7150fcf0df00 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 30 Apr 2019 23:31:17 +0000 Subject: [PATCH 07/11] GUI: Add Pairing tab to disablewallet mode --- src/Makefile.qt.include | 4 ++-- src/qt/bitcoingui.cpp | 1 + src/qt/rpcconsole.cpp | 12 ++++++++++++ src/qt/rpcconsole.h | 6 +++++- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index ad51305b34..d31484577c 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -245,9 +245,11 @@ BITCOIN_QT_BASE_CPP = \ qt/notificator.cpp \ qt/optionsdialog.cpp \ qt/optionsmodel.cpp \ + qt/pairingpage.cpp \ qt/peertablemodel.cpp \ qt/peertablesortproxy.cpp \ qt/platformstyle.cpp \ + qt/qrimagewidget.cpp \ qt/qvalidatedlineedit.cpp \ qt/qvaluecombobox.cpp \ qt/rpcconsole.cpp \ @@ -267,10 +269,8 @@ BITCOIN_QT_WALLET_CPP = \ qt/editaddressdialog.cpp \ qt/openuridialog.cpp \ qt/overviewpage.cpp \ - qt/pairingpage.cpp \ qt/paymentserver.cpp \ qt/psbtoperationsdialog.cpp \ - qt/qrimagewidget.cpp \ qt/receivecoinsdialog.cpp \ qt/receiverequestdialog.cpp \ qt/recentrequeststablemodel.cpp \ diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 3dc66a100f..43ba80f368 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -123,6 +123,7 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty /* When compiled without wallet or -disablewallet is provided, * the central widget is the rpc console. */ + rpcConsole->addPairingTab(); setCentralWidget(rpcConsole); Q_EMIT consoleShown(rpcConsole); } diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index ce7032b963..dacacfc863 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -671,6 +672,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ } ui->trafficGraph->setClientModel(model); + if (m_tab_pairing) m_tab_pairing->setClientModel(model); if (model && clientModel->getPeerTableModel() && clientModel->getBanTableModel()) { // Keep up to date with client setNumConnections(model->getNumConnections()); @@ -790,6 +792,15 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_ } } +void RPCConsole::addPairingTab() +{ + assert(!m_tab_pairing); + m_tab_pairing = new PairingPage(this); + ui->tabWidget->insertTab(1, m_tab_pairing, tr("&Pairing")); + m_tabs[TabTypes::PAIRING] = m_tab_pairing; + if (clientModel) m_tab_pairing->setClientModel(clientModel); +} + #ifdef ENABLE_WALLET void RPCConsole::addWallet(WalletModel * const walletModel) { @@ -1402,6 +1413,7 @@ QKeySequence RPCConsole::tabShortcut(TabTypes tab_type) const case TabTypes::INFO: return QKeySequence(tr("Ctrl+I")); case TabTypes::CONSOLE: return QKeySequence(tr("Ctrl+T")); case TabTypes::GRAPH: return QKeySequence(tr("Ctrl+N")); + case TabTypes::PAIRING: return QKeySequence(QStringLiteral("Alt+5")); // Only used in disablewallet mode - matches wallet GUI's pairing shortcut case TabTypes::PEERS: return QKeySequence(tr("Ctrl+P")); } // no default case, so the compiler can warn about missing cases diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index c63341a038..f849dacbcf 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -21,6 +21,7 @@ #include class GuiNetWatch; +class PairingPage; class PlatformStyle; class RPCExecutor; class RPCTimerInterface; @@ -55,6 +56,7 @@ public: } void setClientModel(ClientModel *model = nullptr, int bestblock_height = 0, int64_t bestblock_date = 0, double verification_progress = 0.0); + void addPairingTab(); #ifdef ENABLE_WALLET void addWallet(WalletModel* const walletModel); @@ -73,7 +75,8 @@ public: INFO, CONSOLE, GRAPH, - PEERS + PEERS, + PAIRING, }; std::vector tabs() const; @@ -165,6 +168,7 @@ private: Ui::RPCConsole* const ui; ClientModel *clientModel = nullptr; std::map m_tabs; + PairingPage *m_tab_pairing{nullptr}; GuiNetWatch *netwatch = nullptr; QStringList history; int historyPtr = 0; From aed244489f1d763e70c16688925d38d240438bc7 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 1 May 2019 03:21:05 +0000 Subject: [PATCH 08/11] GUI: Add experimental-status warning to Pairing page --- src/qt/pairingpage.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/qt/pairingpage.cpp b/src/qt/pairingpage.cpp index bdcede56c2..f277cd0159 100644 --- a/src/qt/pairingpage.cpp +++ b/src/qt/pairingpage.cpp @@ -20,6 +20,14 @@ PairingPage::PairingPage(QWidget *parent) : { QVBoxLayout *layout = new QVBoxLayout(this); + QLabel *label_experimental = new QLabel(this); + label_experimental->setStyleSheet("QLabel { background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000; }"); + label_experimental->setMargin(3); + label_experimental->setTextInteractionFlags(Qt::TextSelectableByMouse); + label_experimental->setWordWrap(true); + label_experimental->setText(tr("Pairing is an experimental feature that currently only works when Tor is enabled. It is expected that the pairing address below will change with future updates, and you may need to re-pair after upgrading.")); + layout->addWidget(label_experimental); + QLabel *label_summary = new QLabel(this); label_summary->setText(tr("Below you will find information to pair other software or devices with this node:")); layout->addWidget(label_summary); From 353d950f7933dced4441b94a49febe884f7cd247 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 8 Jul 2021 06:34:59 +0000 Subject: [PATCH 09/11] Bugfix: GUI: Pairing: Don't try to add layout to the wrong parent even temporarily --- src/qt/pairingpage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/pairingpage.cpp b/src/qt/pairingpage.cpp index f277cd0159..5c2d25d76f 100644 --- a/src/qt/pairingpage.cpp +++ b/src/qt/pairingpage.cpp @@ -32,7 +32,7 @@ PairingPage::PairingPage(QWidget *parent) : label_summary->setText(tr("Below you will find information to pair other software or devices with this node:")); layout->addWidget(label_summary); - QFormLayout *form_layout = new QFormLayout(this); + QFormLayout *form_layout = new QFormLayout(); m_onion_address = new QLineEdit(this); m_onion_address->setReadOnly(true); form_layout->addRow(tr("Onion address: "), m_onion_address); From 9ed9aa9836d8b3f2887d6f52f375dc0827a3a52a Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 8 Jul 2021 06:35:42 +0000 Subject: [PATCH 10/11] Bugfix: GUI: Pairing: Only attach to non-null client model signals --- src/qt/pairingpage.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/qt/pairingpage.cpp b/src/qt/pairingpage.cpp index 5c2d25d76f..593a49bf2c 100644 --- a/src/qt/pairingpage.cpp +++ b/src/qt/pairingpage.cpp @@ -51,8 +51,13 @@ PairingPage::PairingPage(QWidget *parent) : void PairingPage::setClientModel(ClientModel *client_model) { + if (m_client_model) { + disconnect(m_client_model, &ClientModel::networkLocalChanged, this, &PairingPage::refresh); + } m_client_model = client_model; - connect(client_model, &ClientModel::networkLocalChanged, this, &PairingPage::refresh); + if (client_model) { + connect(client_model, &ClientModel::networkLocalChanged, this, &PairingPage::refresh); + } refresh(); } From 08245ef1d680843d6e38b89c5c59bc03196a4fe5 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 10 Oct 2023 02:00:33 +0000 Subject: [PATCH 11/11] node: Optimise getNetLocalAddresses slightly --- src/node/interfaces.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index e04af424a4..700d8804c9 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -174,6 +174,7 @@ public: { std::vector ret; LOCK(g_maplocalhost_mutex); + ret.reserve(mapLocalHost.size()); for (const std::pair &item : mapLocalHost) { ret.emplace_back(item.first); }