[Qt] Add option to pause/resume block downloads #9502

Open
wants to merge 8 commits into
from
View
@@ -60,6 +60,8 @@ static std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUAR
static const uint64_t RANDOMIZER_ID_ADDRESS_RELAY = 0x3cac0035b5866b90ULL; // SHA256("main address relay")[0:8]
+static std::atomic<bool> fAutoRequestBlocks(DEFAULT_AUTOMATIC_BLOCK_REQUESTS);
+
// Internal stuff
namespace {
/** Number of nodes with fSyncStarted. */
@@ -105,6 +107,7 @@ namespace {
std::unique_ptr<PartiallyDownloadedBlock> partialBlock; //!< Optional, used for CMPCTBLOCK downloads
};
std::map<uint256, std::pair<NodeId, std::list<QueuedBlock>::iterator> > mapBlocksInFlight;
+ std::atomic<unsigned int> nBlocksInFlight; //!< lock free counter on how many block are in flight
/** Stack of nodes which we have set to announce using compact blocks */
std::list<NodeId> lNodesAnnouncingHeaderAndIDs;
@@ -291,6 +294,7 @@ void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
for (const QueuedBlock& entry : state->vBlocksInFlight) {
mapBlocksInFlight.erase(entry.hash);
}
+ nBlocksInFlight = mapBlocksInFlight.size();
EraseOrphansFor(nodeid);
nPreferredDownload -= state->fPreferredDownload;
nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0);
@@ -327,6 +331,7 @@ bool MarkBlockAsReceived(const uint256& hash) {
state->nBlocksInFlight--;
state->nStallingSince = 0;
mapBlocksInFlight.erase(itInFlight);
+ nBlocksInFlight = mapBlocksInFlight.size();
return true;
}
return false;
@@ -363,6 +368,7 @@ bool MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const CBlockIndex*
nPeersWithValidatedDownloads++;
}
itInFlight = mapBlocksInFlight.insert(std::make_pair(hash, std::make_pair(nodeid, it))).first;
+ nBlocksInFlight = mapBlocksInFlight.size();
if (pit)
*pit = &itInFlight->second.second;
return true;
@@ -465,6 +471,10 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<con
// Make sure pindexBestKnownBlock is up to date, we'll need it.
ProcessBlockAvailability(nodeid);
+ if (!fAutoRequestBlocks) {
+ return;
+ }
+
if (state->pindexBestKnownBlock == NULL || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < UintToArith256(consensusParams.nMinimumChainWork)) {
// This peer has nothing interesting.
return;
@@ -3301,6 +3311,18 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
return true;
}
+void SetAutoRequestBlocks(bool state) {
+ fAutoRequestBlocks = state;
+}
+
+bool isAutoRequestingBlocks() {
+ return fAutoRequestBlocks;
+}
+
+unsigned int getAmountOfBlocksInFlight() {
+ return nBlocksInFlight;
+}
+
class CNetProcessingCleanup
{
public:
View
@@ -27,6 +27,9 @@ void RegisterNodeSignals(CNodeSignals& nodeSignals);
/** Unregister a network node */
void UnregisterNodeSignals(CNodeSignals& nodeSignals);
+/** if disabled, blocks will not be requested automatically, useful for low-resources-available mode */
+static const bool DEFAULT_AUTOMATIC_BLOCK_REQUESTS = true;
+
class PeerLogicValidation : public CValidationInterface {
private:
CConnman* connman;
@@ -64,4 +67,10 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman, const std::atomic<bool>& i
*/
bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interrupt);
+void SetAutoRequestBlocks(bool);
+bool isAutoRequestingBlocks();
+
+/** retruns the amount of blocks in flight (in total) */
+unsigned int getAmountOfBlocksInFlight();
+
#endif // BITCOIN_NET_PROCESSING_H
View
@@ -479,6 +479,10 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel)
connect(_clientModel, SIGNAL(networkActiveChanged(bool)), this, SLOT(setNetworkActive(bool)));
modalOverlay->setKnownBestHeight(_clientModel->getHeaderTipHeight(), QDateTime::fromTime_t(_clientModel->getHeaderTipTime()));
+ modalOverlay->setPauseResumeState(!_clientModel->isAutoRequestingBlocks());
+ connect(modalOverlay, SIGNAL(requestVerificationPauseOrResume()), _clientModel, SLOT(toggleAutoRequestBlocks()));
+ connect(_clientModel, SIGNAL(verificationProgressPauseStateHasChanged(bool)), modalOverlay, SLOT(setPauseResumeState(bool)));
+
setNumBlocks(_clientModel->getNumBlocks(), _clientModel->getLastBlockDate(), _clientModel->getVerificationProgress(NULL), false);
connect(_clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double,bool)), this, SLOT(setNumBlocks(int,QDateTime,double,bool)));
@@ -506,6 +510,7 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel)
// initialize the disable state of the tray icon with the current value in the model.
setTrayIconVisible(optionsModel->getHideTrayIcon());
}
+
} else {
// Disable possibility to show main window via action
toggleHideAction->setEnabled(false);
View
@@ -15,6 +15,7 @@
#include "clientversion.h"
#include "validation.h"
#include "net.h"
+#include "net_processing.h"
#include "txmempool.h"
#include "ui_interface.h"
#include "util.h"
@@ -245,6 +246,22 @@ QString ClientModel::dataDir() const
return GUIUtil::boostPathToQString(GetDataDir());
}
+bool ClientModel::isAutoRequestingBlocks() const
+{
+ return ::isAutoRequestingBlocks();
+}
+
+void ClientModel::setAutoRequestBlocks(bool state)
+{
+ ::SetAutoRequestBlocks(state);
+ Q_EMIT verificationProgressPauseStateHasChanged(!::isAutoRequestingBlocks());
+}
+
+void ClientModel::toggleAutoRequestBlocks()
+{
+ setAutoRequestBlocks(!::isAutoRequestingBlocks());
+}
+
void ClientModel::updateBanlist()
{
banTableModel->refresh();
View
@@ -84,6 +84,10 @@ class ClientModel : public QObject
mutable std::atomic<int> cachedBestHeaderHeight;
mutable std::atomic<int64_t> cachedBestHeaderTime;
+ // get/set state about autorequesting-blocks during IBD
+ bool isAutoRequestingBlocks() const;
+ void setAutoRequestBlocks(bool state);
+
private:
OptionsModel *optionsModel;
PeerTableModel *peerTableModel;
@@ -108,12 +112,15 @@ class ClientModel : public QObject
// Show progress dialog e.g. for verifychain
void showProgress(const QString &title, int nProgress);
+ void verificationProgressPauseStateHasChanged(bool pauseActive);
+
public Q_SLOTS:
void updateTimer();
void updateNumConnections(int numConnections);
void updateNetworkActive(bool networkActive);
void updateAlert();
void updateBanlist();
+ void toggleAutoRequestBlocks();
};
#endif // BITCOIN_QT_CLIENTMODEL_H
@@ -224,6 +224,26 @@ QLabel { color: rgb(40,40,40); }</string>
</widget>
</item>
<item row="1" column="0">
+ <widget class="QLabel" name="labelNumberBlocksRequested">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>Blocks requested from peers</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="numberBlocksRequested">
+ <property name="text">
+ <string>Unknown...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
<widget class="QLabel" name="labelLastBlockTime">
<property name="font">
<font>
@@ -236,7 +256,7 @@ QLabel { color: rgb(40,40,40); }</string>
</property>
</widget>
</item>
- <item row="1" column="1">
+ <item row="2" column="1">
<widget class="QLabel" name="newestBlockDate">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
@@ -249,7 +269,7 @@ QLabel { color: rgb(40,40,40); }</string>
</property>
</widget>
</item>
- <item row="2" column="0">
+ <item row="3" column="0">
<widget class="QLabel" name="labelSyncDone">
<property name="font">
<font>
@@ -262,7 +282,7 @@ QLabel { color: rgb(40,40,40); }</string>
</property>
</widget>
</item>
- <item row="2" column="1">
+ <item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayoutSync" stretch="0,1">
<item>
<widget class="QLabel" name="percentageProgress">
@@ -283,7 +303,7 @@ QLabel { color: rgb(40,40,40); }</string>
</item>
</layout>
</item>
- <item row="4" column="0">
+ <item row="5" column="0">
<widget class="QLabel" name="labelProgressIncrease">
<property name="font">
<font>
@@ -296,14 +316,14 @@ QLabel { color: rgb(40,40,40); }</string>
</property>
</widget>
</item>
- <item row="4" column="1">
+ <item row="5" column="1">
<widget class="QLabel" name="progressIncreasePerH">
<property name="text">
<string>calculating...</string>
</property>
</widget>
</item>
- <item row="5" column="0">
+ <item row="6" column="0">
<widget class="QLabel" name="labelEstimatedTimeLeft">
<property name="font">
<font>
@@ -316,7 +336,7 @@ QLabel { color: rgb(40,40,40); }</string>
</property>
</widget>
</item>
- <item row="5" column="1">
+ <item row="6" column="1">
<widget class="QLabel" name="expectedTimeLeft">
<property name="text">
<string>calculating...</string>
@@ -334,6 +354,33 @@ QLabel { color: rgb(40,40,40); }</string>
<number>10</number>
</property>
<item>
@promag

promag Jul 17, 2017

Contributor

Nit, can't comment there, but remove leftMargin above to be consistent.

+ <widget class="QPushButton" name="pauseResumeVerification">
@promag

promag Jul 17, 2017

Contributor

Nit, rename toggleDownloadButton.

+ <property name="text">
+ <string>Pause downloading blocks</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="infoLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
View
@@ -8,6 +8,7 @@
#include "guiutil.h"
#include "chainparams.h"
+#include "net_processing.h"
#include <QResizeEvent>
#include <QPropertyAnimation>
@@ -18,10 +19,12 @@ ui(new Ui::ModalOverlay),
bestHeaderHeight(0),
bestHeaderDate(QDateTime()),
layerIsVisible(false),
-userClosed(false)
+userClosed(false),
+verificationPauseActive(false)
{
ui->setupUi(this);
connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(closeClicked()));
+ connect(ui->pauseResumeVerification, SIGNAL(clicked()), this, SLOT(pauseClicked()));
if (parent) {
parent->installEventFilter(this);
raise();
@@ -71,6 +74,7 @@ void ModalOverlay::setKnownBestHeight(int count, const QDateTime& blockDate)
if (count > bestHeaderHeight) {
bestHeaderHeight = count;
bestHeaderDate = blockDate;
+ eventuallyShowHeaderSyncing(count);
}
}
@@ -125,15 +129,30 @@ void ModalOverlay::tipUpdate(int count, const QDateTime& blockDate, double nVeri
// not syncing
return;
+ // show remaining number of blocks
+ ui->numberOfBlocksLeft->setText(QString::number(bestHeaderHeight - count));
+
+ // show already requested blocks (in total)
+ ui->numberBlocksRequested->setText(QString::number(getAmountOfBlocksInFlight()));
+ eventuallyShowHeaderSyncing(count);
+ updatePauseState(verificationPauseActive);
+
+ // disable pause button when we we can fetch directly
+ // avoid using the core-layer's existing CanFetchDirectly()
+ bool canFetchDirecly = (blockDate.toTime_t() > GetAdjustedTime() - Params().GetConsensus().nPowTargetSpacing * 20);
+ ui->pauseResumeVerification->setEnabled(!canFetchDirecly);
+ ui->infoLabel->setVisible(!canFetchDirecly);
+}
+
+void ModalOverlay::eventuallyShowHeaderSyncing(int count)
+{
// estimate the number of headers left based on nPowTargetSpacing
// and check if the gui is not aware of the best header (happens rarely)
- int estimateNumHeadersLeft = bestHeaderDate.secsTo(currentDate) / Params().GetConsensus().nPowTargetSpacing;
+ int estimateNumHeadersLeft = bestHeaderDate.secsTo(QDateTime::currentDateTime()) / Params().GetConsensus().nPowTargetSpacing;
bool hasBestHeader = bestHeaderHeight >= count;
- // show remaining number of blocks
- if (estimateNumHeadersLeft < HEADER_HEIGHT_DELTA_SYNC && hasBestHeader) {
- ui->numberOfBlocksLeft->setText(QString::number(bestHeaderHeight - count));
- } else {
+ // show headers-syncing progress if we still sync headers
+ if (estimateNumHeadersLeft >= HEADER_HEIGHT_DELTA_SYNC || !hasBestHeader) {
ui->numberOfBlocksLeft->setText(tr("Unknown. Syncing Headers (%1)...").arg(bestHeaderHeight));
ui->expectedTimeLeft->setText(tr("Unknown..."));
}
@@ -170,3 +189,21 @@ void ModalOverlay::closeClicked()
showHide(true);
userClosed = true;
}
+
+void ModalOverlay::pauseClicked()
+{
+ Q_EMIT requestVerificationPauseOrResume();
+}
+
+void ModalOverlay::setPauseResumeState(bool pauseActive)
+{
+ verificationPauseActive = pauseActive;
+ updatePauseState(pauseActive);
+}
+
+void ModalOverlay::updatePauseState(bool pauseActive)
+{
+ ui->labelNumberBlocksRequested->setText((pauseActive ? "Finish downloading blocks": "Blocks requested from peers"));
@promag

promag Jul 17, 2017

Contributor

Don't see the need to change label, maybe a generic Downloading: %d blocks?

+ ui->pauseResumeVerification->setText((pauseActive ? "Resume downloading blocks ": "Pause downloading blocks"));
+ ui->infoLabel->setText((pauseActive && getAmountOfBlocksInFlight() > 0 ? "Wait to finish current downloads...": ""));
@promag

promag Jul 17, 2017

Contributor

I don't know if you plan to show other messages for this label, but if not then toggle visibility like above?

@promag

promag Jul 17, 2017

Contributor

Also, when paused, nBlocksInFlight doesn't always decrease to zero.

+}
Oops, something went wrong.