2016-09-03 09:39:45 -07:00
|
|
|
// Copyright (c) 2016 The Zcash developers
|
|
|
|
// Distributed under the MIT software license, see the accompanying
|
2019-07-18 07:16:09 -07:00
|
|
|
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
|
2016-09-03 09:39:45 -07:00
|
|
|
|
|
|
|
#include "metrics.h"
|
|
|
|
|
|
|
|
#include "chainparams.h"
|
2017-06-26 16:16:08 -07:00
|
|
|
#include "checkpoints.h"
|
2016-10-30 14:36:36 -07:00
|
|
|
#include "main.h"
|
2019-07-31 14:16:25 -07:00
|
|
|
#include "timedata.h"
|
2016-09-03 10:51:54 -07:00
|
|
|
#include "ui_interface.h"
|
2016-09-03 09:39:45 -07:00
|
|
|
#include "util.h"
|
|
|
|
#include "utiltime.h"
|
2016-10-30 14:36:36 -07:00
|
|
|
#include "utilmoneystr.h"
|
2017-05-10 20:35:57 -07:00
|
|
|
#include "utilstrencodings.h"
|
2016-09-03 09:39:45 -07:00
|
|
|
|
|
|
|
#include <boost/thread.hpp>
|
2016-09-03 10:51:54 -07:00
|
|
|
#include <boost/thread/synchronized_value.hpp>
|
|
|
|
#include <string>
|
2018-04-13 22:17:52 -07:00
|
|
|
#ifdef WIN32
|
|
|
|
#include <io.h>
|
|
|
|
#else
|
2016-09-03 20:40:28 -07:00
|
|
|
#include <sys/ioctl.h>
|
2018-04-13 22:17:52 -07:00
|
|
|
#endif
|
2016-10-23 19:23:56 -07:00
|
|
|
#include <unistd.h>
|
2016-09-03 09:39:45 -07:00
|
|
|
|
2017-03-22 16:35:44 -07:00
|
|
|
void AtomicTimer::start()
|
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> lock(mtx);
|
|
|
|
if (threads < 1) {
|
|
|
|
start_time = GetTime();
|
|
|
|
}
|
|
|
|
++threads;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AtomicTimer::stop()
|
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> lock(mtx);
|
|
|
|
// Ignore excess calls to stop()
|
|
|
|
if (threads > 0) {
|
|
|
|
--threads;
|
|
|
|
if (threads < 1) {
|
|
|
|
int64_t time_span = GetTime() - start_time;
|
|
|
|
total_time += time_span;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AtomicTimer::running()
|
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> lock(mtx);
|
|
|
|
return threads > 0;
|
|
|
|
}
|
|
|
|
|
2017-02-14 14:06:35 -08:00
|
|
|
uint64_t AtomicTimer::threadCount()
|
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> lock(mtx);
|
|
|
|
return threads;
|
|
|
|
}
|
|
|
|
|
2017-03-22 16:35:44 -07:00
|
|
|
double AtomicTimer::rate(const AtomicCounter& count)
|
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> lock(mtx);
|
|
|
|
int64_t duration = total_time;
|
|
|
|
if (threads > 0) {
|
|
|
|
// Timer is running, so get the latest count
|
|
|
|
duration += GetTime() - start_time;
|
|
|
|
}
|
|
|
|
return duration > 0 ? (double)count.get() / duration : 0;
|
|
|
|
}
|
|
|
|
|
2018-01-14 08:23:05 -08:00
|
|
|
static CCriticalSection cs_metrics;
|
2016-11-01 09:59:40 -07:00
|
|
|
|
2018-01-14 08:23:05 -08:00
|
|
|
static boost::synchronized_value<int64_t> nNodeStartTime;
|
|
|
|
static boost::synchronized_value<int64_t> nNextRefresh;
|
2016-09-03 09:39:45 -07:00
|
|
|
AtomicCounter transactionsValidated;
|
|
|
|
AtomicCounter ehSolverRuns;
|
2016-09-04 15:54:15 -07:00
|
|
|
AtomicCounter solutionTargetChecks;
|
2018-01-14 08:23:05 -08:00
|
|
|
static AtomicCounter minedBlocks;
|
2017-03-22 16:37:22 -07:00
|
|
|
AtomicTimer miningTimer;
|
2016-09-03 09:39:45 -07:00
|
|
|
|
2018-01-14 08:23:05 -08:00
|
|
|
static boost::synchronized_value<std::list<uint256>> trackedBlocks;
|
2016-10-30 14:36:36 -07:00
|
|
|
|
2018-01-14 08:23:05 -08:00
|
|
|
static boost::synchronized_value<std::list<std::string>> messageBox;
|
|
|
|
static boost::synchronized_value<std::string> initMessage;
|
|
|
|
static bool loaded = false;
|
2016-09-03 10:51:54 -07:00
|
|
|
|
2016-10-30 15:25:40 -07:00
|
|
|
extern int64_t GetNetworkHashPS(int lookup, int height);
|
|
|
|
|
2016-10-30 14:36:36 -07:00
|
|
|
void TrackMinedBlock(uint256 hash)
|
|
|
|
{
|
2016-11-01 09:59:40 -07:00
|
|
|
LOCK(cs_metrics);
|
2016-10-30 14:36:36 -07:00
|
|
|
minedBlocks.increment();
|
|
|
|
trackedBlocks->push_back(hash);
|
|
|
|
}
|
|
|
|
|
2016-10-25 13:11:41 -07:00
|
|
|
void MarkStartTime()
|
|
|
|
{
|
|
|
|
*nNodeStartTime = GetTime();
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t GetUptime()
|
|
|
|
{
|
|
|
|
return GetTime() - *nNodeStartTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
double GetLocalSolPS()
|
|
|
|
{
|
2017-03-22 16:37:22 -07:00
|
|
|
return miningTimer.rate(solutionTargetChecks);
|
2016-10-25 13:11:41 -07:00
|
|
|
}
|
|
|
|
|
2019-01-05 05:19:20 -08:00
|
|
|
std::string WhichNetwork()
|
|
|
|
{
|
|
|
|
if (GetBoolArg("-regtest", false))
|
2019-09-18 11:16:11 -07:00
|
|
|
return "regtest";
|
2019-01-05 05:19:20 -08:00
|
|
|
if (GetBoolArg("-testnet", false))
|
2019-09-18 11:16:11 -07:00
|
|
|
return "testnet";
|
|
|
|
return "mainnet";
|
2019-01-05 05:19:20 -08:00
|
|
|
}
|
|
|
|
|
2019-08-05 13:20:25 -07:00
|
|
|
int EstimateNetHeight(const Consensus::Params& params, int currentHeadersHeight, int64_t currentHeadersTime)
|
2017-06-26 16:16:08 -07:00
|
|
|
{
|
2020-02-05 08:49:48 -08:00
|
|
|
int64_t now = GetTime();
|
2019-08-05 13:20:25 -07:00
|
|
|
if (currentHeadersTime >= now) {
|
|
|
|
return currentHeadersHeight;
|
2019-08-02 21:51:21 -07:00
|
|
|
}
|
2017-06-26 16:16:08 -07:00
|
|
|
|
2019-08-05 13:20:25 -07:00
|
|
|
int estimatedHeight = currentHeadersHeight + (now - currentHeadersTime) / params.PoWTargetSpacing(currentHeadersHeight);
|
2019-07-31 14:16:25 -07:00
|
|
|
|
|
|
|
int blossomActivationHeight = params.vUpgrades[Consensus::UPGRADE_BLOSSOM].nActivationHeight;
|
2019-08-05 13:20:25 -07:00
|
|
|
if (currentHeadersHeight >= blossomActivationHeight || estimatedHeight <= blossomActivationHeight) {
|
2019-08-06 08:45:17 -07:00
|
|
|
return ((estimatedHeight + 5) / 10) * 10;
|
2019-07-31 14:16:25 -07:00
|
|
|
}
|
|
|
|
|
2019-08-05 13:20:25 -07:00
|
|
|
int numPreBlossomBlocks = blossomActivationHeight - currentHeadersHeight;
|
2019-07-31 14:16:25 -07:00
|
|
|
int64_t preBlossomTime = numPreBlossomBlocks * params.PoWTargetSpacing(blossomActivationHeight - 1);
|
2019-08-05 13:20:25 -07:00
|
|
|
int64_t blossomActivationTime = currentHeadersTime + preBlossomTime;
|
2019-08-02 21:51:21 -07:00
|
|
|
if (blossomActivationTime >= now) {
|
|
|
|
return blossomActivationHeight;
|
|
|
|
}
|
2019-07-31 14:16:25 -07:00
|
|
|
|
2019-08-05 13:20:25 -07:00
|
|
|
int netheight = blossomActivationHeight + (now - blossomActivationTime) / params.PoWTargetSpacing(blossomActivationHeight);
|
|
|
|
return ((netheight + 5) / 10) * 10;
|
2017-06-26 16:16:08 -07:00
|
|
|
}
|
|
|
|
|
2017-01-03 01:21:00 -08:00
|
|
|
void TriggerRefresh()
|
|
|
|
{
|
|
|
|
*nNextRefresh = GetTime();
|
|
|
|
// Ensure that the refresh has started before we return
|
|
|
|
MilliSleep(200);
|
|
|
|
}
|
|
|
|
|
2016-09-03 10:51:54 -07:00
|
|
|
static bool metrics_ThreadSafeMessageBox(const std::string& message,
|
|
|
|
const std::string& caption,
|
|
|
|
unsigned int style)
|
|
|
|
{
|
2017-01-03 01:26:49 -08:00
|
|
|
// The SECURE flag has no effect in the metrics UI.
|
|
|
|
style &= ~CClientUIInterface::SECURE;
|
|
|
|
|
2016-09-03 10:51:54 -07:00
|
|
|
std::string strCaption;
|
|
|
|
// Check for usage of predefined caption
|
|
|
|
switch (style) {
|
|
|
|
case CClientUIInterface::MSG_ERROR:
|
|
|
|
strCaption += _("Error");
|
|
|
|
break;
|
|
|
|
case CClientUIInterface::MSG_WARNING:
|
|
|
|
strCaption += _("Warning");
|
|
|
|
break;
|
|
|
|
case CClientUIInterface::MSG_INFORMATION:
|
|
|
|
strCaption += _("Information");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
strCaption += caption; // Use supplied caption (can be empty)
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::strict_lock_ptr<std::list<std::string>> u = messageBox.synchronize();
|
|
|
|
u->push_back(strCaption + ": " + message);
|
|
|
|
if (u->size() > 5) {
|
|
|
|
u->pop_back();
|
|
|
|
}
|
2017-01-03 01:21:00 -08:00
|
|
|
|
|
|
|
TriggerRefresh();
|
|
|
|
return false;
|
2016-09-03 10:51:54 -07:00
|
|
|
}
|
|
|
|
|
2017-02-23 04:55:14 -08:00
|
|
|
static bool metrics_ThreadSafeQuestion(const std::string& /* ignored interactive message */, const std::string& message, const std::string& caption, unsigned int style)
|
|
|
|
{
|
|
|
|
return metrics_ThreadSafeMessageBox(message, caption, style);
|
|
|
|
}
|
|
|
|
|
2016-09-03 10:51:54 -07:00
|
|
|
static void metrics_InitMessage(const std::string& message)
|
|
|
|
{
|
|
|
|
*initMessage = message;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ConnectMetricsScreen()
|
|
|
|
{
|
|
|
|
uiInterface.ThreadSafeMessageBox.disconnect_all_slots();
|
|
|
|
uiInterface.ThreadSafeMessageBox.connect(metrics_ThreadSafeMessageBox);
|
2017-02-23 04:55:14 -08:00
|
|
|
uiInterface.ThreadSafeQuestion.disconnect_all_slots();
|
|
|
|
uiInterface.ThreadSafeQuestion.connect(metrics_ThreadSafeQuestion);
|
2016-09-03 10:51:54 -07:00
|
|
|
uiInterface.InitMessage.disconnect_all_slots();
|
|
|
|
uiInterface.InitMessage.connect(metrics_InitMessage);
|
|
|
|
}
|
|
|
|
|
2019-11-03 03:35:10 -08:00
|
|
|
std::string DisplayDuration(int64_t time, DurationFormat format)
|
2019-10-30 11:19:22 -07:00
|
|
|
{
|
|
|
|
int days = time / (24 * 60 * 60);
|
|
|
|
int hours = (time - (days * 24 * 60 * 60)) / (60 * 60);
|
|
|
|
int minutes = (time - (((days * 24) + hours) * 60 * 60)) / 60;
|
|
|
|
int seconds = time - (((((days * 24) + hours) * 60) + minutes) * 60);
|
|
|
|
|
2019-11-03 03:35:10 -08:00
|
|
|
std::string strDuration;
|
|
|
|
if (format == DurationFormat::REDUCED) {
|
2019-10-30 11:19:22 -07:00
|
|
|
if (days > 0) {
|
2019-11-03 03:35:10 -08:00
|
|
|
strDuration = strprintf(_("%d days"), days);
|
2019-10-30 11:19:22 -07:00
|
|
|
} else if (hours > 0) {
|
2019-11-03 03:35:10 -08:00
|
|
|
strDuration = strprintf(_("%d hours"), hours);
|
2019-10-30 11:19:22 -07:00
|
|
|
} else if (minutes > 0) {
|
2019-11-03 03:35:10 -08:00
|
|
|
strDuration = strprintf(_("%d minutes"), minutes);
|
2019-10-30 11:19:22 -07:00
|
|
|
} else {
|
2019-11-03 03:35:10 -08:00
|
|
|
strDuration = strprintf(_("%d seconds"), seconds);
|
2019-10-30 11:19:22 -07:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (days > 0) {
|
2019-11-03 03:35:10 -08:00
|
|
|
strDuration = strprintf(_("%d days, %d hours, %d minutes, %d seconds"), days, hours, minutes, seconds);
|
2019-10-30 11:19:22 -07:00
|
|
|
} else if (hours > 0) {
|
2019-11-03 03:35:10 -08:00
|
|
|
strDuration = strprintf(_("%d hours, %d minutes, %d seconds"), hours, minutes, seconds);
|
2019-10-30 11:19:22 -07:00
|
|
|
} else if (minutes > 0) {
|
2019-11-03 03:35:10 -08:00
|
|
|
strDuration = strprintf(_("%d minutes, %d seconds"), minutes, seconds);
|
2019-10-30 11:19:22 -07:00
|
|
|
} else {
|
2019-11-03 03:35:10 -08:00
|
|
|
strDuration = strprintf(_("%d seconds"), seconds);
|
2019-10-30 11:19:22 -07:00
|
|
|
}
|
|
|
|
}
|
2019-11-03 03:35:10 -08:00
|
|
|
return strDuration;
|
2019-10-30 11:19:22 -07:00
|
|
|
}
|
|
|
|
|
2020-03-05 05:26:07 -08:00
|
|
|
std::string DisplaySize(size_t value)
|
|
|
|
{
|
|
|
|
double coef = 1.0;
|
|
|
|
if (value < 1024.0 * coef)
|
|
|
|
return strprintf(_("%d Bytes"), value);
|
|
|
|
coef *= 1024.0;
|
|
|
|
if (value < 1024.0 * coef)
|
|
|
|
return strprintf(_("%.2f KiB"), value / coef);
|
|
|
|
coef *= 1024.0;
|
|
|
|
if (value < 1024.0 * coef)
|
|
|
|
return strprintf(_("%.2f MiB"), value / coef);
|
|
|
|
coef *= 1024.0;
|
|
|
|
if (value < 1024.0 * coef)
|
|
|
|
return strprintf(_("%.2f GiB"), value / coef);
|
|
|
|
coef *= 1024.0;
|
|
|
|
return strprintf(_("%.2f TiB"), value / coef);
|
|
|
|
}
|
|
|
|
|
2019-11-03 03:35:10 -08:00
|
|
|
boost::optional<int64_t> SecondsLeftToNextEpoch(const Consensus::Params& params, int currentHeight)
|
2019-11-02 14:37:45 -07:00
|
|
|
{
|
2019-11-03 03:35:10 -08:00
|
|
|
auto nextHeight = NextActivationHeight(currentHeight, params);
|
|
|
|
if (nextHeight) {
|
|
|
|
return (nextHeight.get() - currentHeight) * params.PoWTargetSpacing(nextHeight.get() - 1);
|
|
|
|
} else {
|
2019-11-02 14:37:45 -07:00
|
|
|
return boost::none;
|
2019-11-03 03:35:10 -08:00
|
|
|
}
|
2019-11-02 14:37:45 -07:00
|
|
|
}
|
|
|
|
|
2017-03-22 18:04:12 -07:00
|
|
|
int printStats(bool mining)
|
2016-10-30 15:25:40 -07:00
|
|
|
{
|
2017-03-22 18:04:12 -07:00
|
|
|
// Number of lines that are always displayed
|
2019-10-30 11:19:22 -07:00
|
|
|
int lines = 5;
|
2017-03-22 18:04:12 -07:00
|
|
|
|
|
|
|
int height;
|
2019-08-05 13:20:25 -07:00
|
|
|
int64_t currentHeadersHeight;
|
|
|
|
int64_t currentHeadersTime;
|
2017-03-22 18:04:12 -07:00
|
|
|
size_t connections;
|
|
|
|
int64_t netsolps;
|
2019-11-02 14:37:45 -07:00
|
|
|
const Consensus::Params& params = Params().GetConsensus();
|
2017-03-22 18:04:12 -07:00
|
|
|
{
|
|
|
|
LOCK2(cs_main, cs_vNodes);
|
|
|
|
height = chainActive.Height();
|
2019-08-06 08:45:17 -07:00
|
|
|
currentHeadersHeight = pindexBestHeader ? pindexBestHeader->nHeight: -1;
|
|
|
|
currentHeadersTime = pindexBestHeader ? pindexBestHeader->nTime : 0;
|
2017-03-22 18:04:12 -07:00
|
|
|
connections = vNodes.size();
|
|
|
|
netsolps = GetNetworkHashPS(120, -1);
|
|
|
|
}
|
|
|
|
auto localsolps = GetLocalSolPS();
|
2016-10-30 15:25:40 -07:00
|
|
|
|
2019-04-01 18:30:33 -07:00
|
|
|
if (IsInitialBlockDownload(Params())) {
|
2020-02-20 07:40:46 -08:00
|
|
|
if (fReindex) {
|
|
|
|
int downloadPercent = nSizeReindexed * 100 / nFullSizeToReindex;
|
2020-03-05 05:26:07 -08:00
|
|
|
std::cout << " " << _("Reindexing blocks") << " | " << DisplaySize(nSizeReindexed) << " / " << DisplaySize(nFullSizeToReindex) << " (" << downloadPercent << "%, " << height << " " << _("blocks") << ")" << std::endl;
|
2020-02-20 07:40:46 -08:00
|
|
|
} else {
|
|
|
|
int netheight = currentHeadersHeight == -1 || currentHeadersTime == 0 ?
|
|
|
|
0 : EstimateNetHeight(params, currentHeadersHeight, currentHeadersTime);
|
|
|
|
int downloadPercent = height * 100 / netheight;
|
|
|
|
std::cout << " " << _("Downloading blocks") << " | " << height << " / ~" << netheight << " (" << downloadPercent << "%)" << std::endl;
|
|
|
|
}
|
2017-06-26 16:16:08 -07:00
|
|
|
} else {
|
|
|
|
std::cout << " " << _("Block height") << " | " << height << std::endl;
|
|
|
|
}
|
2019-10-30 11:19:22 -07:00
|
|
|
|
2019-11-03 03:35:10 -08:00
|
|
|
auto secondsLeft = SecondsLeftToNextEpoch(params, height);
|
2019-10-30 11:19:22 -07:00
|
|
|
std::string strUpgradeTime;
|
2019-11-04 08:31:00 -08:00
|
|
|
if (secondsLeft) {
|
|
|
|
auto nextHeight = NextActivationHeight(height, params).value();
|
|
|
|
auto nextBranch = NextEpoch(height, params).value();
|
2019-11-02 14:37:45 -07:00
|
|
|
strUpgradeTime = strprintf(_("%s at block height %d, in around %s"),
|
2019-11-03 03:35:10 -08:00
|
|
|
NetworkUpgradeInfo[nextBranch].strName, nextHeight, DisplayDuration(secondsLeft.value(), DurationFormat::REDUCED));
|
|
|
|
}
|
2019-11-04 08:31:00 -08:00
|
|
|
else {
|
|
|
|
strUpgradeTime = "Unknown";
|
|
|
|
}
|
2019-10-30 11:19:22 -07:00
|
|
|
std::cout << " " << _("Next upgrade") << " | " << strUpgradeTime << std::endl;
|
2017-03-22 18:04:12 -07:00
|
|
|
std::cout << " " << _("Connections") << " | " << connections << std::endl;
|
|
|
|
std::cout << " " << _("Network solution rate") << " | " << netsolps << " Sol/s" << std::endl;
|
|
|
|
if (mining && miningTimer.running()) {
|
|
|
|
std::cout << " " << _("Local solution rate") << " | " << strprintf("%.4f Sol/s", localsolps) << std::endl;
|
|
|
|
lines++;
|
|
|
|
}
|
2016-10-30 15:25:40 -07:00
|
|
|
std::cout << std::endl;
|
|
|
|
|
2017-03-22 18:04:12 -07:00
|
|
|
return lines;
|
2016-10-30 15:25:40 -07:00
|
|
|
}
|
|
|
|
|
2016-10-30 14:37:20 -07:00
|
|
|
int printMiningStatus(bool mining)
|
2016-09-03 20:18:44 -07:00
|
|
|
{
|
2016-11-06 11:40:34 -08:00
|
|
|
#ifdef ENABLE_MINING
|
2016-10-30 14:37:20 -07:00
|
|
|
// Number of lines that are always displayed
|
|
|
|
int lines = 1;
|
|
|
|
|
2016-09-03 20:18:44 -07:00
|
|
|
if (mining) {
|
2017-02-14 14:06:35 -08:00
|
|
|
auto nThreads = miningTimer.threadCount();
|
|
|
|
if (nThreads > 0) {
|
2017-03-22 18:05:00 -07:00
|
|
|
std::cout << strprintf(_("You are mining with the %s solver on %d threads."),
|
|
|
|
GetArg("-equihashsolver", "default"), nThreads) << std::endl;
|
|
|
|
} else {
|
2017-03-22 19:16:04 -07:00
|
|
|
bool fvNodesEmpty;
|
|
|
|
{
|
|
|
|
LOCK(cs_vNodes);
|
|
|
|
fvNodesEmpty = vNodes.empty();
|
|
|
|
}
|
|
|
|
if (fvNodesEmpty) {
|
|
|
|
std::cout << _("Mining is paused while waiting for connections.") << std::endl;
|
2019-04-01 18:30:33 -07:00
|
|
|
} else if (IsInitialBlockDownload(Params())) {
|
2017-03-22 19:16:04 -07:00
|
|
|
std::cout << _("Mining is paused while downloading blocks.") << std::endl;
|
|
|
|
} else {
|
|
|
|
std::cout << _("Mining is paused (a JoinSplit may be in progress).") << std::endl;
|
|
|
|
}
|
2017-03-22 18:05:00 -07:00
|
|
|
}
|
2016-10-30 14:37:20 -07:00
|
|
|
lines++;
|
2016-09-03 20:18:44 -07:00
|
|
|
} else {
|
2016-09-03 20:31:50 -07:00
|
|
|
std::cout << _("You are currently not mining.") << std::endl;
|
|
|
|
std::cout << _("To enable mining, add 'gen=1' to your zcash.conf and restart.") << std::endl;
|
2016-10-30 14:37:20 -07:00
|
|
|
lines += 2;
|
2016-09-03 20:18:44 -07:00
|
|
|
}
|
|
|
|
std::cout << std::endl;
|
2016-10-30 14:37:20 -07:00
|
|
|
|
|
|
|
return lines;
|
2016-11-06 11:40:34 -08:00
|
|
|
#else // ENABLE_MINING
|
|
|
|
return 0;
|
|
|
|
#endif // !ENABLE_MINING
|
2016-09-03 20:18:44 -07:00
|
|
|
}
|
|
|
|
|
2016-10-25 13:11:41 -07:00
|
|
|
int printMetrics(size_t cols, bool mining)
|
2016-09-03 20:18:44 -07:00
|
|
|
{
|
|
|
|
// Number of lines that are always displayed
|
|
|
|
int lines = 3;
|
|
|
|
|
2019-10-30 11:19:22 -07:00
|
|
|
// Calculate and display uptime
|
2019-11-03 03:35:10 -08:00
|
|
|
std::string duration = DisplayDuration(GetUptime(), DurationFormat::FULL);
|
2019-10-30 11:19:22 -07:00
|
|
|
|
2016-09-03 20:40:28 -07:00
|
|
|
std::string strDuration = strprintf(_("Since starting this node %s ago:"), duration);
|
|
|
|
std::cout << strDuration << std::endl;
|
|
|
|
lines += (strDuration.size() / cols);
|
2016-09-03 20:18:44 -07:00
|
|
|
|
2016-11-30 18:34:57 -08:00
|
|
|
int validatedCount = transactionsValidated.get();
|
2016-10-28 10:14:13 -07:00
|
|
|
if (validatedCount > 1) {
|
|
|
|
std::cout << "- " << strprintf(_("You have validated %d transactions!"), validatedCount) << std::endl;
|
|
|
|
} else if (validatedCount == 1) {
|
2016-11-30 18:34:57 -08:00
|
|
|
std::cout << "- " << _("You have validated a transaction!") << std::endl;
|
2016-10-28 10:14:13 -07:00
|
|
|
} else {
|
2016-11-30 18:34:57 -08:00
|
|
|
std::cout << "- " << _("You have validated no transactions.") << std::endl;
|
2016-10-28 10:14:13 -07:00
|
|
|
}
|
2016-09-03 20:18:44 -07:00
|
|
|
|
2016-10-30 16:54:05 -07:00
|
|
|
if (mining && loaded) {
|
2016-09-03 20:31:50 -07:00
|
|
|
std::cout << "- " << strprintf(_("You have completed %d Equihash solver runs."), ehSolverRuns.get()) << std::endl;
|
2017-03-22 18:04:12 -07:00
|
|
|
lines++;
|
2016-09-03 20:18:44 -07:00
|
|
|
|
2016-11-01 09:59:40 -07:00
|
|
|
int mined = 0;
|
|
|
|
int orphaned = 0;
|
2016-11-01 18:37:59 -07:00
|
|
|
CAmount immature {0};
|
|
|
|
CAmount mature {0};
|
2016-11-01 09:59:40 -07:00
|
|
|
{
|
|
|
|
LOCK2(cs_main, cs_metrics);
|
2016-10-30 14:36:36 -07:00
|
|
|
boost::strict_lock_ptr<std::list<uint256>> u = trackedBlocks.synchronize();
|
|
|
|
auto consensusParams = Params().GetConsensus();
|
|
|
|
auto tipHeight = chainActive.Height();
|
|
|
|
|
|
|
|
// Update orphans and calculate subsidies
|
2016-11-02 07:20:35 -07:00
|
|
|
std::list<uint256>::iterator it = u->begin();
|
|
|
|
while (it != u->end()) {
|
2016-10-30 14:36:36 -07:00
|
|
|
auto hash = *it;
|
|
|
|
if (mapBlockIndex.count(hash) > 0 &&
|
|
|
|
chainActive.Contains(mapBlockIndex[hash])) {
|
|
|
|
int height = mapBlockIndex[hash]->nHeight;
|
|
|
|
CAmount subsidy = GetBlockSubsidy(height, consensusParams);
|
2019-07-29 12:44:53 -07:00
|
|
|
if ((height > 0) && (height <= consensusParams.GetLastFoundersRewardBlockHeight(height))) {
|
2016-10-30 14:36:36 -07:00
|
|
|
subsidy -= subsidy/5;
|
|
|
|
}
|
|
|
|
if (std::max(0, COINBASE_MATURITY - (tipHeight - height)) > 0) {
|
|
|
|
immature += subsidy;
|
|
|
|
} else {
|
|
|
|
mature += subsidy;
|
|
|
|
}
|
2016-11-02 07:20:35 -07:00
|
|
|
it++;
|
2016-10-30 14:36:36 -07:00
|
|
|
} else {
|
|
|
|
it = u->erase(it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-01 09:59:40 -07:00
|
|
|
mined = minedBlocks.get();
|
|
|
|
orphaned = mined - u->size();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mined > 0) {
|
2016-11-01 18:37:59 -07:00
|
|
|
std::string units = Params().CurrencyUnits();
|
2016-09-03 20:31:50 -07:00
|
|
|
std::cout << "- " << strprintf(_("You have mined %d blocks!"), mined) << std::endl;
|
2016-10-30 14:36:36 -07:00
|
|
|
std::cout << " "
|
|
|
|
<< strprintf(_("Orphaned: %d blocks, Immature: %u %s, Mature: %u %s"),
|
|
|
|
orphaned,
|
|
|
|
FormatMoney(immature), units,
|
|
|
|
FormatMoney(mature), units)
|
|
|
|
<< std::endl;
|
|
|
|
lines += 2;
|
2016-09-03 20:18:44 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
|
|
|
return lines;
|
|
|
|
}
|
|
|
|
|
2016-09-03 20:40:28 -07:00
|
|
|
int printMessageBox(size_t cols)
|
2016-09-03 10:51:54 -07:00
|
|
|
{
|
|
|
|
boost::strict_lock_ptr<std::list<std::string>> u = messageBox.synchronize();
|
|
|
|
|
|
|
|
if (u->size() == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-09-03 20:40:28 -07:00
|
|
|
int lines = 2 + u->size();
|
2016-09-03 20:31:50 -07:00
|
|
|
std::cout << _("Messages:") << std::endl;
|
2016-09-03 10:51:54 -07:00
|
|
|
for (auto it = u->cbegin(); it != u->cend(); ++it) {
|
2017-05-10 20:35:57 -07:00
|
|
|
auto msg = FormatParagraph(*it, cols, 2);
|
|
|
|
std::cout << "- " << msg << std::endl;
|
2017-01-04 23:38:35 -08:00
|
|
|
// Handle newlines and wrapped lines
|
|
|
|
size_t i = 0;
|
|
|
|
size_t j = 0;
|
2017-05-10 20:35:57 -07:00
|
|
|
while (j < msg.size()) {
|
|
|
|
i = msg.find('\n', j);
|
2017-01-04 23:38:35 -08:00
|
|
|
if (i == std::string::npos) {
|
2017-05-10 20:35:57 -07:00
|
|
|
i = msg.size();
|
2017-01-04 23:38:35 -08:00
|
|
|
} else {
|
|
|
|
// Newline
|
|
|
|
lines++;
|
|
|
|
}
|
|
|
|
j = i + 1;
|
|
|
|
}
|
2016-09-03 10:51:54 -07:00
|
|
|
}
|
2016-09-03 20:18:44 -07:00
|
|
|
std::cout << std::endl;
|
2016-09-03 20:40:28 -07:00
|
|
|
return lines;
|
2016-09-03 10:51:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
int printInitMessage()
|
|
|
|
{
|
|
|
|
if (loaded) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string msg = *initMessage;
|
2016-09-03 20:31:50 -07:00
|
|
|
std::cout << _("Init message:") << " " << msg << std::endl;
|
2016-09-03 20:18:44 -07:00
|
|
|
std::cout << std::endl;
|
2016-09-03 10:51:54 -07:00
|
|
|
|
2016-09-03 20:31:50 -07:00
|
|
|
if (msg == _("Done loading")) {
|
2016-09-03 10:51:54 -07:00
|
|
|
loaded = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
2018-04-17 18:57:58 -07:00
|
|
|
#ifdef WIN32
|
|
|
|
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
|
|
|
|
|
|
|
bool enableVTMode()
|
|
|
|
{
|
|
|
|
// Set output mode to handle virtual terminal sequences
|
|
|
|
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
|
if (hOut == INVALID_HANDLE_VALUE) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD dwMode = 0;
|
|
|
|
if (!GetConsoleMode(hOut, &dwMode)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
|
|
|
if (!SetConsoleMode(hOut, dwMode)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-09-03 09:39:45 -07:00
|
|
|
void ThreadShowMetricsScreen()
|
|
|
|
{
|
|
|
|
// Make this thread recognisable as the metrics screen thread
|
|
|
|
RenameThread("zcash-metrics-screen");
|
|
|
|
|
2016-11-17 19:17:09 -08:00
|
|
|
// Determine whether we should render a persistent UI or rolling metrics
|
2016-11-17 19:32:21 -08:00
|
|
|
bool isTTY = isatty(STDOUT_FILENO);
|
|
|
|
bool isScreen = GetBoolArg("-metricsui", isTTY);
|
|
|
|
int64_t nRefresh = GetArg("-metricsrefreshtime", isTTY ? 1 : 600);
|
2016-09-03 09:39:45 -07:00
|
|
|
|
2016-11-17 19:17:09 -08:00
|
|
|
if (isScreen) {
|
2018-04-17 18:57:58 -07:00
|
|
|
#ifdef WIN32
|
|
|
|
enableVTMode();
|
|
|
|
#endif
|
|
|
|
|
2016-11-17 19:17:09 -08:00
|
|
|
// Clear screen
|
|
|
|
std::cout << "\e[2J";
|
2016-09-03 09:39:45 -07:00
|
|
|
|
2016-11-17 19:17:09 -08:00
|
|
|
// Print art
|
|
|
|
std::cout << METRICS_ART << std::endl;
|
|
|
|
std::cout << std::endl;
|
|
|
|
|
|
|
|
// Thank you text
|
2019-10-29 10:44:27 -07:00
|
|
|
std::cout << strprintf(_("Thank you for running a %s zcashd v%s node!"), WhichNetwork(), FormatVersion(CLIENT_VERSION)) << std::endl;
|
2016-11-17 19:17:09 -08:00
|
|
|
std::cout << _("You're helping to strengthen the network and contributing to a social good :)") << std::endl;
|
2017-03-23 18:13:37 -07:00
|
|
|
|
2017-03-25 18:08:29 -07:00
|
|
|
// Privacy notice text
|
|
|
|
std::cout << PrivacyInfo();
|
2016-11-17 19:17:09 -08:00
|
|
|
std::cout << std::endl;
|
|
|
|
}
|
2016-09-03 09:39:45 -07:00
|
|
|
|
|
|
|
while (true) {
|
2016-09-03 10:51:54 -07:00
|
|
|
// Number of lines that are always displayed
|
2016-09-03 20:18:44 -07:00
|
|
|
int lines = 1;
|
2016-10-23 08:54:50 -07:00
|
|
|
int cols = 80;
|
2016-09-03 09:39:45 -07:00
|
|
|
|
2016-09-03 20:40:28 -07:00
|
|
|
// Get current window size
|
2016-11-17 19:32:21 -08:00
|
|
|
if (isTTY) {
|
2018-04-13 22:17:52 -07:00
|
|
|
#ifdef WIN32
|
|
|
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
2018-08-21 08:54:40 -07:00
|
|
|
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi) != 0) {
|
|
|
|
cols = csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
|
|
|
}
|
2018-04-13 22:17:52 -07:00
|
|
|
#else
|
2016-10-23 19:23:56 -07:00
|
|
|
struct winsize w;
|
|
|
|
w.ws_col = 0;
|
|
|
|
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1 && w.ws_col != 0) {
|
|
|
|
cols = w.ws_col;
|
|
|
|
}
|
2018-04-13 22:17:52 -07:00
|
|
|
#endif
|
2016-10-23 08:54:50 -07:00
|
|
|
}
|
2016-09-03 20:40:28 -07:00
|
|
|
|
2016-11-17 19:17:09 -08:00
|
|
|
if (isScreen) {
|
|
|
|
// Erase below current position
|
|
|
|
std::cout << "\e[J";
|
|
|
|
}
|
2016-09-03 09:39:45 -07:00
|
|
|
|
2016-10-30 14:37:20 -07:00
|
|
|
// Miner status
|
2016-11-06 11:40:34 -08:00
|
|
|
#ifdef ENABLE_MINING
|
2016-10-30 14:37:20 -07:00
|
|
|
bool mining = GetBoolArg("-gen", false);
|
2016-11-06 11:40:34 -08:00
|
|
|
#else
|
|
|
|
bool mining = false;
|
|
|
|
#endif
|
2016-10-30 14:37:20 -07:00
|
|
|
|
2016-10-30 15:25:40 -07:00
|
|
|
if (loaded) {
|
2017-03-22 18:04:12 -07:00
|
|
|
lines += printStats(mining);
|
2017-03-22 18:05:00 -07:00
|
|
|
lines += printMiningStatus(mining);
|
2016-10-30 15:25:40 -07:00
|
|
|
}
|
2016-10-25 13:11:41 -07:00
|
|
|
lines += printMetrics(cols, mining);
|
2016-10-23 08:54:50 -07:00
|
|
|
lines += printMessageBox(cols);
|
2016-09-03 10:51:54 -07:00
|
|
|
lines += printInitMessage();
|
|
|
|
|
2016-11-17 19:17:09 -08:00
|
|
|
if (isScreen) {
|
|
|
|
// Explain how to exit
|
2018-04-17 19:46:43 -07:00
|
|
|
std::cout << "[";
|
|
|
|
#ifdef WIN32
|
|
|
|
std::cout << _("'zcash-cli.exe stop' to exit");
|
|
|
|
#else
|
|
|
|
std::cout << _("Press Ctrl+C to exit");
|
|
|
|
#endif
|
|
|
|
std::cout << "] [" << _("Set 'showmetrics=0' to hide") << "]" << std::endl;
|
2016-11-17 19:17:09 -08:00
|
|
|
} else {
|
|
|
|
// Print delineator
|
2016-11-28 21:17:28 -08:00
|
|
|
std::cout << "----------------------------------------" << std::endl;
|
2016-11-17 19:17:09 -08:00
|
|
|
}
|
2016-09-03 09:39:45 -07:00
|
|
|
|
2017-01-03 01:21:00 -08:00
|
|
|
*nNextRefresh = GetTime() + nRefresh;
|
|
|
|
while (GetTime() < *nNextRefresh) {
|
2016-11-17 19:32:21 -08:00
|
|
|
boost::this_thread::interruption_point();
|
|
|
|
MilliSleep(200);
|
|
|
|
}
|
2016-09-03 09:39:45 -07:00
|
|
|
|
2016-11-17 19:17:09 -08:00
|
|
|
if (isScreen) {
|
|
|
|
// Return to the top of the updating section
|
|
|
|
std::cout << "\e[" << lines << "A";
|
|
|
|
}
|
2016-09-03 09:39:45 -07:00
|
|
|
}
|
|
|
|
}
|