aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.qt.include5
-rw-r--r--src/net_processing.cpp38
-rw-r--r--src/net_processing.h5
-rw-r--r--src/qt/forms/addpeerdialog.ui73
-rw-r--r--src/qt/forms/debugwindow.ui95
-rw-r--r--src/qt/forms/testpeerdialog.ui73
-rw-r--r--src/qt/guiutil.cpp53
-rw-r--r--src/qt/guiutil.h4
-rw-r--r--src/qt/locale/bitcoin_fr_CA.ts16
-rw-r--r--src/qt/macdockiconhandler.mm38
-rw-r--r--src/qt/peerdialog.cpp176
-rw-r--r--src/qt/peerdialog.h62
-rw-r--r--src/qt/peertablemodel.cpp11
-rw-r--r--src/qt/peertablemodel.h5
-rw-r--r--src/qt/rpcconsole.cpp61
-rw-r--r--src/qt/rpcconsole.h8
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>&amp;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>&amp;Label</source>
- <translation>Record</translation>
+ <translation>Étiquette</translation>
</message>
<message>
<source>&amp;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();
};