diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.qt.include | 5 | ||||
| -rw-r--r-- | src/net_processing.cpp | 38 | ||||
| -rw-r--r-- | src/net_processing.h | 5 | ||||
| -rw-r--r-- | src/qt/forms/addpeerdialog.ui | 73 | ||||
| -rw-r--r-- | src/qt/forms/debugwindow.ui | 95 | ||||
| -rw-r--r-- | src/qt/forms/testpeerdialog.ui | 73 | ||||
| -rw-r--r-- | src/qt/guiutil.cpp | 53 | ||||
| -rw-r--r-- | src/qt/guiutil.h | 4 | ||||
| -rw-r--r-- | src/qt/locale/bitcoin_fr_CA.ts | 16 | ||||
| -rw-r--r-- | src/qt/macdockiconhandler.mm | 38 | ||||
| -rw-r--r-- | src/qt/peerdialog.cpp | 176 | ||||
| -rw-r--r-- | src/qt/peerdialog.h | 62 | ||||
| -rw-r--r-- | src/qt/peertablemodel.cpp | 11 | ||||
| -rw-r--r-- | src/qt/peertablemodel.h | 5 | ||||
| -rw-r--r-- | src/qt/rpcconsole.cpp | 61 | ||||
| -rw-r--r-- | src/qt/rpcconsole.h | 8 |
16 files changed, 678 insertions, 45 deletions
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 3997ae0ec..c73ff66ad 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -110,6 +110,8 @@ QT_FORMS_UI = \ qt/forms/receivecoinsdialog.ui \ qt/forms/receiverequestdialog.ui \ qt/forms/debugwindow.ui \ + qt/forms/addpeerdialog.ui \ + qt/forms/testpeerdialog.ui \ qt/forms/sendcoinsdialog.ui \ qt/forms/sendcoinsentry.ui \ qt/forms/signverifymessagedialog.ui \ @@ -159,6 +161,7 @@ QT_MOC_CPP = \ qt/moc_transactiontablemodel.cpp \ qt/moc_transactionview.cpp \ qt/moc_utilitydialog.cpp \ + qt/moc_peerdialog.cpp \ qt/moc_verticallabel.cpp \ qt/moc_walletframe.cpp \ qt/moc_walletmodel.cpp \ @@ -234,6 +237,7 @@ BITCOIN_QT_H = \ qt/transactiontablemodel.h \ qt/transactionview.h \ qt/utilitydialog.h \ + qt/peerdialog.h \ qt/verticallabel.h \ qt/walletframe.h \ qt/walletmodel.h \ @@ -324,6 +328,7 @@ BITCOIN_QT_BASE_CPP = \ qt/splashscreen.cpp \ qt/trafficgraphwidget.cpp \ qt/utilitydialog.cpp \ + qt/peerdialog.cpp \ qt/verticallabel.cpp BITCOIN_QT_WINDOWS_CPP = qt/winshutdownmonitor.cpp diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 1b33d529b..5c595a891 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -169,6 +169,8 @@ struct CNodeState { int nUnconnectingHeaders; //! Whether we've started headers synchronization with this peer. bool fSyncStarted; + //! When to potentially disconnect peer for stalling headers download + int64_t nHeadersSyncTimeout; //! Since when we're stalling block download progress (in microseconds), or 0. int64_t nStallingSince; std::list<QueuedBlock> vBlocksInFlight; @@ -208,6 +210,7 @@ struct CNodeState { pindexBestHeaderSent = NULL; nUnconnectingHeaders = 0; fSyncStarted = false; + nHeadersSyncTimeout = 0; nStallingSince = 0; nDownloadingSince = 0; nBlocksInFlight = 0; @@ -2899,6 +2902,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr // Only actively request headers from a single peer, unless we're close to today. if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) { state.fSyncStarted = true; + state.nHeadersSyncTimeout = GetTimeMicros() + HEADERS_DOWNLOAD_TIMEOUT_BASE + HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER * (GetAdjustedTime() - pindexBestHeader->GetBlockTime())/(consensusParams.nPowTargetSpacing); nSyncStarted++; const CBlockIndex *pindexStart = pindexBestHeader; /* If possible, start at the block preceding the currently @@ -3197,7 +3201,6 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr } if (!vInv.empty()) connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); - // Detect whether we're stalling nNow = GetTimeMicros(); if (state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) { @@ -3222,7 +3225,38 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr return true; } } - + // Check for headers sync timeouts + if (state.fSyncStarted && state.nHeadersSyncTimeout < std::numeric_limits<int64_t>::max()) { + // Detect whether this is a stalling initial-headers-sync peer + if (pindexBestHeader->GetBlockTime() <= GetAdjustedTime() - 24*60*60) { + if (nNow > state.nHeadersSyncTimeout && nSyncStarted == 1 && (nPreferredDownload - state.fPreferredDownload >= 1)) { + // Disconnect a (non-whitelisted) peer if it is our only sync peer, + // and we have others we could be using instead. + // Note: If all our peers are inbound, then we won't + // disconnect our sync peer for stalling; we have bigger + // problems if we can't get any outbound peers. + if (!pto->fWhitelisted) { + LogPrintf("Timeout downloading headers from peer=%d, disconnecting\n", pto->GetId()); + pto->fDisconnect = true; + return true; + } else { + LogPrintf("Timeout downloading headers from whitelisted peer=%d, not disconnecting\n", pto->GetId()); + // Reset the headers sync state so that we have a + // chance to try downloading from a different peer. + // Note: this will also result in at least one more + // getheaders message to be sent to + // this peer (eventually). + state.fSyncStarted = false; + nSyncStarted--; + state.nHeadersSyncTimeout = 0; + } + } + } else { + // After we've caught up once, reset the timeout so we can't trigger + // disconnect later. + state.nHeadersSyncTimeout = std::numeric_limits<int64_t>::max(); + } + } // // Message: getdata (blocks) // diff --git a/src/net_processing.h b/src/net_processing.h index 9e3f1b715..53ca5e393 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -17,7 +17,10 @@ static const int64_t ORPHAN_TX_EXPIRE_TIME = 20 * 60; static const int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60; /** Default number of orphan+recently-replaced txn to keep around for block reconstruction */ static const unsigned int DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN = 100; - +/** Headers download timeout expressed in microseconds + * Timeout = base + per_header * (expected number of headers) */ +static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_BASE = 15 * 60 * 1000000; // 15 minutes +static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1000; // 1ms/header /** Register with a network node to receive its signals */ void RegisterNodeSignals(CNodeSignals& nodeSignals); /** Unregister a network node */ diff --git a/src/qt/forms/addpeerdialog.ui b/src/qt/forms/addpeerdialog.ui new file mode 100644 index 000000000..7cb09dea3 --- /dev/null +++ b/src/qt/forms/addpeerdialog.ui @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>AddPeerDialog</class> + <widget class="QWidget" name="AddPeerDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>466</width> + <height>186</height> + </rect> + </property> + <property name="windowTitle"> + <string>Add Peer</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLabel" name="label"> + <property name="font"> + <font> + <pointsize>11</pointsize> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Enter the peer details below.</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Be careful! Do not blindly trust anyone that tells you to add their node.</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLineEdit" name="peerAddress"> + <property name="placeholderText"> + <string>Enter the peer's address</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="peerPort"> + <property name="placeholderText"> + <string>Enter the peer's port</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QPushButton" name="pushButton"> + <property name="text"> + <string>Add!</string> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index 8be4a955b..6eb838c91 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -165,17 +165,17 @@ </widget> </item> <item row="6" column="0"> - <widget class="QLabel" name="labelNetwork"> - <property name="font"> - <font> - <weight>75</weight> - <bold>true</bold> - </font> - </property> - <property name="text"> - <string>Network</string> - </property> - </widget> + <widget class="QLabel" name="labelNetwork"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Network</string> + </property> + </widget> </item> <item row="7" column="0"> <widget class="QLabel" name="label_8"> @@ -433,12 +433,12 @@ <height>24</height> </size> </property> - <property name="text"> - <string/> - </property> <property name="toolTip"> <string>Decrease font size</string> </property> + <property name="text"> + <string/> + </property> <property name="icon"> <iconset resource="../bitcoin.qrc"> <normaloff>:/icons/fontsmaller</normaloff>:/icons/fontsmaller</iconset> @@ -855,6 +855,33 @@ <number>0</number> </property> <item> + <widget class="QLabel" name="peerlistHeading"> + <property name="minimumSize"> + <size> + <width>300</width> + <height>32</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>32</height> + </size> + </property> + <property name="font"> + <font> + <pointsize>12</pointsize> + </font> + </property> + <property name="cursor"> + <cursorShape>IBeamCursor</cursorShape> + </property> + <property name="text"> + <string>Connected peers</string> + </property> + </widget> + </item> + <item> <widget class="QTableView" name="peerWidget"> <property name="horizontalScrollBarPolicy"> <enum>Qt::ScrollBarAsNeeded</enum> @@ -871,6 +898,46 @@ </widget> </item> <item> + <layout class="QHBoxLayout" name="horizontalLayout_6"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <item> + <widget class="QPushButton" name="peerAdd"> + <property name="cursor"> + <cursorShape>PointingHandCursor</cursorShape> + </property> + <property name="text"> + <string>Add new peer</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="peerRemove"> + <property name="cursor"> + <cursorShape>PointingHandCursor</cursorShape> + </property> + <property name="text"> + <string>Remove peer</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="peerTest"> + <property name="cursor"> + <cursorShape>PointingHandCursor</cursorShape> + </property> + <property name="text"> + <string>One try peer</string> + </property> + </widget> + </item> + </layout> + </item> + <item> <widget class="QLabel" name="banHeading"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> diff --git a/src/qt/forms/testpeerdialog.ui b/src/qt/forms/testpeerdialog.ui new file mode 100644 index 000000000..471860529 --- /dev/null +++ b/src/qt/forms/testpeerdialog.ui @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>TestPeerDialog</class> + <widget class="QWidget" name="TestPeerDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>466</width> + <height>186</height> + </rect> + </property> + <property name="windowTitle"> + <string>Test Peer</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLabel" name="label"> + <property name="font"> + <font> + <pointsize>11</pointsize> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Enter the peer details below.</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Be careful! Do not blindly trust anyone that tells you to add their node.</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLineEdit" name="peerAddress"> + <property name="placeholderText"> + <string>Enter the peer's address</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="peerPort"> + <property name="placeholderText"> + <string>Enter the peer's port</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QPushButton" name="pushButton"> + <property name="text"> + <string>Test!</string> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 6912b9312..71fe49ae5 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers +// Copyright (c) 2021 The Dogecoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -79,6 +80,9 @@ extern double NSAppKitVersionNumber; #if !defined(NSAppKitVersionNumber10_9) #define NSAppKitVersionNumber10_9 1265 #endif +#include <QProcess> + +void ForceActivation(); #endif namespace GUIUtil { @@ -404,6 +408,23 @@ bool isObscured(QWidget *w) && checkPoint(QPoint(w->width() / 2, w->height() / 2), w)); } +void bringToFront(QWidget* w) +{ + #ifdef Q_OS_MAC + ForceActivation(); + #endif + if (w) { + // activateWindow() (sometimes) helps with keyboard focus on Windows + if (w->isMinimized()) { + w->showNormal(); + } else { + w->show(); + } + w->activateWindow(); + w->raise(); + } +} + void openDebugLogfile() { boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; @@ -941,6 +962,38 @@ QString formatPingTime(double dPingTime) return (dPingTime == std::numeric_limits<int64_t>::max()/1e6 || dPingTime == 0) ? QObject::tr("N/A") : QString(QObject::tr("%1 ms")).arg(QString::number((int)(dPingTime * 1000), 10)); } +QString formatDataSizeValue(uint64_t uValue) +{ + // Why handle these comparisons directly, instead of a clever algorithm? + // This is likely to be called in a tight loop, so avoid the overhead of + // setting up a constant list and walking an iterator. + static const uint64_t TERABYTE_SIZE = UINT64_C(1024*1024*1024*1024); + static const uint64_t GIGABYTE_SIZE = UINT64_C(1024*1024*1024); + static const uint64_t MEGABYTE_SIZE = UINT64_C(1024*1024); + static const uint64_t KILOBYTE_SIZE = UINT64_C(1024); + + QString unitFormat = QObject::tr("%1 B"); + + if (uValue == std::numeric_limits<int64_t>::max()/1e6 || uValue == 0) + return QObject::tr("N/A"); + + if (uValue > TERABYTE_SIZE) { + unitFormat = QObject::tr("%1 TB"); + uValue /= TERABYTE_SIZE; + } else if (uValue > GIGABYTE_SIZE) { + unitFormat = QObject::tr("%1 GB"); + uValue /= GIGABYTE_SIZE; + } else if (uValue > MEGABYTE_SIZE) { + unitFormat = QObject::tr("%1 MB"); + uValue /= MEGABYTE_SIZE; + } else if (uValue > KILOBYTE_SIZE) { + unitFormat = QObject::tr("%1 KB"); + uValue /= KILOBYTE_SIZE; + } + + return QString(unitFormat).arg(QString::number(uValue), 10); +} + QString formatTimeOffset(int64_t nTimeOffset) { return QString(QObject::tr("%1 s")).arg(QString::number((int)nTimeOffset, 10)); diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 913aa5e24..5ac303125 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -1,4 +1,5 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers +// Copyright (c) 2021 The Dogecoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -197,6 +198,9 @@ namespace GUIUtil /* Format a CNodeCombinedStats.dPingTime into a user-readable string or display N/A, if 0*/ QString formatPingTime(double dPingTime); + /* Format a uint64_t into a user-readable data size string (KB, MB, GB, TB) or display N/A, if 0*/ + QString formatDataSizeValue(uint64_t uValue); + /* Format a CNodeCombinedStats.nTimeOffset into a user-readable string. */ QString formatTimeOffset(int64_t nTimeOffset); diff --git a/src/qt/locale/bitcoin_fr_CA.ts b/src/qt/locale/bitcoin_fr_CA.ts index 2affdf310..bb1842758 100644 --- a/src/qt/locale/bitcoin_fr_CA.ts +++ b/src/qt/locale/bitcoin_fr_CA.ts @@ -7,7 +7,7 @@ </message> <message> <source>Copy the currently selected address to the system clipboard</source> - <translation>Copier l'adresse surligné a votre presse-papier</translation> + <translation>Copier l'adresse surlignée à votre presse-papier</translation> </message> <message> <source>&Delete</source> @@ -21,15 +21,15 @@ <name>AskPassphraseDialog</name> <message> <source>Enter passphrase</source> - <translation>Entrer Mot de Passe</translation> + <translation>Entrer le mot de passe</translation> </message> <message> <source>New passphrase</source> - <translation>Nouveau Mot de passe</translation> + <translation>Nouveau mot de passe</translation> </message> <message> <source>Repeat new passphrase</source> - <translation>Répéter Mot de Passe</translation> + <translation>Répéter le nouveau mot de passe</translation> </message> </context> <context> @@ -42,18 +42,18 @@ <name>CoinControlDialog</name> <message> <source>(un)select all</source> - <translation>Toute sélectionner </translation> + <translation>Tout (dé)sélectionner</translation> </message> </context> <context> <name>EditAddressDialog</name> <message> <source>&Label</source> - <translation>Record</translation> + <translation>Étiquette</translation> </message> <message> <source>&Address</source> - <translation>Addresse</translation> + <translation>Adresse</translation> </message> </context> <context> @@ -66,7 +66,7 @@ <name>Intro</name> <message> <source>Welcome</source> - <translation>Bienvenue </translation> + <translation>Bienvenue</translation> </message> </context> <context> diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm index a41d39d51..15f44927d 100644 --- a/src/qt/macdockiconhandler.mm +++ b/src/qt/macdockiconhandler.mm @@ -9,10 +9,9 @@ #include <QBuffer> #include <QWidget> -#undef slots #include <Cocoa/Cocoa.h> -#include <objc/objc.h> -#include <objc/message.h> +#include <AppKit/AppKit.h> +#include <objc/runtime.h> #if QT_VERSION < 0x050000 extern void qt_mac_set_dock_menu(QMenu *); @@ -23,26 +22,20 @@ static MacDockIconHandler *s_instance = NULL; bool dockClickHandler(id self,SEL _cmd,...) { Q_UNUSED(self) Q_UNUSED(_cmd) - + s_instance->handleDockIconClickEvent(); - + // Return NO (false) to suppress the default OS X actions return false; } void setupDockClickHandler() { - Class cls = objc_getClass("NSApplication"); - id appInst = objc_msgSend((id)cls, sel_registerName("sharedApplication")); - - if (appInst != NULL) { - id delegate = objc_msgSend(appInst, sel_registerName("delegate")); - Class delClass = (Class)objc_msgSend(delegate, sel_registerName("class")); - SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:"); - if (class_getInstanceMethod(delClass, shouldHandle)) - class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:"); - else - class_addMethod(delClass, shouldHandle, (IMP)dockClickHandler,"B@:"); - } + Class delClass = (Class)[[[NSApplication sharedApplication] delegate] class]; + SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:"); + if (class_getInstanceMethod(delClass, shouldHandle)) + class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:"); + else + class_addMethod(delClass, shouldHandle, (IMP)dockClickHandler,"B@:"); } @@ -132,3 +125,14 @@ void MacDockIconHandler::handleDockIconClickEvent() Q_EMIT this->dockIconClicked(); } + +/** + * Force application activation on macOS. With Qt 5.5.1 this is required when + * an action in the Dock menu is triggered. + * TODO: Define a Qt version where it's no-longer necessary. + */ +void ForceActivation() +{ + [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; +} + diff --git a/src/qt/peerdialog.cpp b/src/qt/peerdialog.cpp new file mode 100644 index 000000000..3c35c686f --- /dev/null +++ b/src/qt/peerdialog.cpp @@ -0,0 +1,176 @@ +// Copyright (c) 2011-2016 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 "guiutil.h" +#if defined(HAVE_CONFIG_H) +#include "config/bitcoin-config.h" +#endif + +#include <iostream> +#include <string> + +#include "peerdialog.h" + +#include "ui_addpeerdialog.h" +#include "ui_testpeerdialog.h" + +#include "net.h" +#include "net_processing.h" +#include "netbase.h" +#include "protocol.h" +#include "chainparams.h" +#include "util.h" + +#include <stdio.h> + +#include <QMessageBox> +#include <QHostAddress> +#include <QAbstractSocket> +#include <QUrl> + +/** Function to manage peers */ +QString PeerTools::ManagePeer(QString type, QString peer) +{ + std::string peerAddress = peer.toStdString(); + + if(!g_connman) + return "Error: Peer-to-peer functionality missing or disabled"; + + if (type == "onetry") + { + CAddress addr; + g_connman->OpenNetworkConnection(addr, false, NULL, peerAddress.c_str()); + return "Attempted to one try node."; + } + + if (type == "add") + { + if(!g_connman->AddNode(peerAddress)) + return "Error: Node already added"; + } + else if(type == "remove") + { + if(!g_connman->RemoveAddedNode(peerAddress)) + { + if(!g_connman->DisconnectNode(peerAddress)) + return "Node not found in connected nodes"; + + return "Disconnected the node: " + peer; + } + else + { + if(!g_connman->DisconnectNode(peerAddress)) + return "Node not found in connected nodes"; + } + } + + return "Returned OK."; +} + +/** Check if Peer is valid */ +bool PeerTools::CheckPeerAddress(QString address) +{ + CNetAddr addr; + return LookupHost(address.toStdString().c_str(), addr, true); +} + +/** Get port based on current chain */ +QString PeerTools::GetPort() +{ + return QString::number(Params().GetDefaultPort()); +} + +/** Add Peer Dialog */ +AddPeerDialog::AddPeerDialog(QWidget *parent) : + QWidget(parent), + ui(new Ui::AddPeerDialog) +{ + ui->setupUi(this); + + ui->peerPort->setValidator( new QIntValidator(1, 65535, this) ); + + connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(on_addPeer_clicked())); +} + +AddPeerDialog::~AddPeerDialog() +{ + delete ui; +} + +void AddPeerDialog::on_addPeer_clicked() +{ + QString address = ui->peerAddress->text(); + QString port = ui->peerPort->text(); + QString data = ""; + + if(address.isEmpty()) + { + QMessageBox::critical(this, "Add Peer", "Please enter an address.", QMessageBox::Ok, QMessageBox::Ok); + return; + } + + if(port.isEmpty()) + { + port = PeerTools::GetPort(); + ui->peerPort->setText(port); + } + + if(!PeerTools::CheckPeerAddress(address)) + { + QMessageBox::critical(this, "Add Peer", "Please enter a vaild peer address.", QMessageBox::Ok, QMessageBox::Ok); + return; + } + + data = address + ":" + port; + + if(QMessageBox::Ok == QMessageBox::information(this, "Add Peer", PeerTools::ManagePeer("add", data), QMessageBox::Ok, QMessageBox::Ok)) + this->close(); +} + +/** Add Test Peer Dialog */ +TestPeerDialog::TestPeerDialog(QWidget *parent) : + QWidget(parent), + ui(new Ui::TestPeerDialog) +{ + ui->setupUi(this); + + ui->peerPort->setValidator( new QIntValidator(1, 65535, this) ); + + connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(on_testPeer_clicked())); +} + +TestPeerDialog::~TestPeerDialog() +{ + delete ui; +} + +void TestPeerDialog::on_testPeer_clicked() +{ + QString address = ui->peerAddress->text(); + QString port = ui->peerPort->text(); + QString data = ""; + + if(address.isEmpty()) + { + QMessageBox::critical(this, "Test Peer", "Please enter an address.", QMessageBox::Ok, QMessageBox::Ok); + return; + } + + if(port.isEmpty()) + { + port = PeerTools::GetPort(); + ui->peerPort->setText(port); + } + + if(!PeerTools::CheckPeerAddress(address)) + { + QMessageBox::critical(this, "Test Peer", "Please enter a vaild peer address.", QMessageBox::Ok, QMessageBox::Ok); + return; + } + + data = address + ":" + port; + + if(QMessageBox::Ok == QMessageBox::information(this, "Try Peer", PeerTools::ManagePeer("onetry", data), QMessageBox::Ok, QMessageBox::Ok)) + this->close(); +} diff --git a/src/qt/peerdialog.h b/src/qt/peerdialog.h new file mode 100644 index 000000000..45d3215c4 --- /dev/null +++ b/src/qt/peerdialog.h @@ -0,0 +1,62 @@ +// Copyright (c) 2011-2016 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_PEERDIALOG_H +#define BITCOIN_QT_PEERDIALOG_H + +#include <QObject> +#include <QWidget> +#include <string> +#include "guiutil.h" + +class PeerTools; + +namespace Ui { + class AddPeerDialog; + class RemovePeerDialog; + class TestPeerDialog; +} + +/** Class to manage peers */ +class PeerTools : public QObject +{ + Q_OBJECT + +public: + static QString ManagePeer(QString type, QString peer); + static bool CheckPeerAddress(QString address); + static bool CheckIPAddress(QString ip); + static bool CheckDNS(QString dns); + static QString GetPort(); +}; + +/** "Add peer" dialog box */ +class AddPeerDialog : public QWidget +{ + Q_OBJECT + +public: + explicit AddPeerDialog(QWidget *parent); + ~AddPeerDialog(); +private: + Ui::AddPeerDialog *ui; +private Q_SLOTS: + void on_addPeer_clicked(); +}; + +/** "Test peer" dialog box */ +class TestPeerDialog : public QWidget +{ + Q_OBJECT + +public: + explicit TestPeerDialog(QWidget *parent); + ~TestPeerDialog(); +private: + Ui::TestPeerDialog *ui; +private Q_SLOTS: + void on_testPeer_clicked(); +}; + +#endif diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp index fff072fd4..f55564890 100644 --- a/src/qt/peertablemodel.cpp +++ b/src/qt/peertablemodel.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers +// Copyright (c) 2021 The Dogecoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -33,6 +34,10 @@ bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombine return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0; case PeerTableModel::Ping: return pLeft->dMinPing < pRight->dMinPing; + case PeerTableModel::BytesSent: + return pLeft->nSendBytes < pRight->nSendBytes; + case PeerTableModel::BytesReceived: + return pLeft->nRecvBytes < pRight->nRecvBytes; } return false; @@ -114,7 +119,7 @@ PeerTableModel::PeerTableModel(ClientModel *parent) : clientModel(parent), timer(0) { - columns << tr("NodeId") << tr("Node/Service") << tr("User Agent") << tr("Ping"); + columns << tr("NodeId") << tr("Node/Service") << tr("User Agent") << tr("Ping") << tr("Bytes Sent") << tr("Bytes Received"); priv.reset(new PeerTablePriv()); // default to unsorted priv->sortColumn = -1; @@ -173,6 +178,10 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const return QString::fromStdString(rec->nodeStats.cleanSubVer); case Ping: return GUIUtil::formatPingTime(rec->nodeStats.dMinPing); + case BytesSent: + return GUIUtil::formatDataSizeValue(rec->nodeStats.nSendBytes); + case BytesReceived: + return GUIUtil::formatDataSizeValue(rec->nodeStats.nRecvBytes); } } else if (role == Qt::TextAlignmentRole) { if (index.column() == Ping) diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h index cc47b67ec..85502527b 100644 --- a/src/qt/peertablemodel.h +++ b/src/qt/peertablemodel.h @@ -1,4 +1,5 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers +// Copyright (c) 2021 The Dogecoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -56,7 +57,9 @@ public: NetNodeId = 0, Address = 1, Subversion = 2, - Ping = 3 + Ping = 3, + BytesSent = 4, + BytesReceived = 5 }; /** @name Methods overridden from QAbstractTableModel diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 7bf01c906..dacbeacdf 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -2,11 +2,13 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "bitcoingui.h" #if defined(HAVE_CONFIG_H) #include "config/bitcoin-config.h" #endif #include "rpcconsole.h" +#include "peerdialog.h" #include "ui_debugwindow.h" #include "bantablemodel.h" @@ -14,6 +16,7 @@ #include "guiutil.h" #include "platformstyle.h" #include "bantablemodel.h" +#include "utilitydialog.h" #include "chainparams.h" #include "netbase.h" @@ -39,6 +42,7 @@ #include <QTime> #include <QTimer> #include <QStringList> +#include <QThread> #if QT_VERSION < 0x050000 #include <QUrl> @@ -441,6 +445,15 @@ RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) : connect(ui->fontSmallerButton, SIGNAL(clicked()), this, SLOT(fontSmaller())); connect(ui->btnClearTrafficGraph, SIGNAL(clicked()), ui->trafficGraph, SLOT(clear())); + // Allow user to add new peer + connect(ui->peerAdd, SIGNAL(clicked()), this, SLOT(on_addPeer_clicked())); + + // Allow user to remove peer + connect(ui->peerRemove, SIGNAL(clicked()), this, SLOT(on_removePeer_clicked())); + + // Allow user to test peer + connect(ui->peerTest, SIGNAL(clicked()), this, SLOT(on_testPeer_clicked())); + // set library version labels #ifdef ENABLE_WALLET ui->berkeleyDBVersion->setText(DbEnv::version(0, 0, 0)); @@ -910,6 +923,54 @@ void RPCConsole::on_openDebugLogfileButton_clicked() GUIUtil::openDebugLogfile(); } +void RPCConsole::on_addPeer_clicked() +{ + + QWidget *win = new AddPeerDialog(0); + + win->showNormal(); + win->show(); + win->raise(); + win->activateWindow(); + + /** Center window */ + const QPoint global = ui->tabWidget->mapToGlobal(ui->tabWidget->rect().center()); + win->move(global.x() - win->width() / 2, global.y() - win->height() / 2); +} + +void RPCConsole::on_removePeer_clicked() +{ + QList<QModelIndex> ips = GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::Address); + + if(ips.size() != 0) + { + QString address = ips[0].data().toString(); + + if(QMessageBox::Yes == QMessageBox::question(this, "Remove Peer", "Are you sure you want to remove the peer: " + address + "?", QMessageBox::Yes | QMessageBox::No)) + { + QMessageBox::information(this, "Remove Peer", PeerTools::ManagePeer("remove", address), QMessageBox::Ok, QMessageBox::Ok); + } + + } else + { + QMessageBox::information(this, "Remove Peer", "No peer was selected.", QMessageBox::Ok, QMessageBox::Ok); + } +} + +void RPCConsole::on_testPeer_clicked() +{ + QWidget *win = new TestPeerDialog(0); + + win->showNormal(); + win->show(); + win->raise(); + win->activateWindow(); + + /** Center window */ + const QPoint global = ui->tabWidget->mapToGlobal(ui->tabWidget->rect().center()); + win->move(global.x() - win->width() / 2, global.y() - win->height() / 2); +} + void RPCConsole::scrollToEnd() { QScrollBar *scrollbar = ui->messagesWidget->verticalScrollBar(); diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index ec531c99c..4176e2acf 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -17,6 +17,7 @@ class ClientModel; class PlatformStyle; class RPCTimerInterface; +class RPCExecutor; namespace Ui { class RPCConsole; @@ -67,6 +68,12 @@ private Q_SLOTS: void on_tabWidget_currentChanged(int index); /** open the debug.log from the current datadir */ void on_openDebugLogfileButton_clicked(); + /** open dialog to add new peer */ + void on_addPeer_clicked(); + /** open dialog to remove peer */ + void on_removePeer_clicked(); + /** open dialog to test peer */ + void on_testPeer_clicked(); /** change the time range of the network traffic graph */ void on_sldGraphRange_valueChanged(int value); /** update traffic statistics */ @@ -152,7 +159,6 @@ private: int consoleFontSize; QCompleter *autoCompleter; QThread thread; - /** Update UI with latest network info from model. */ void updateNetworkState(); }; |