Skip to content

Commit

Permalink
Redo global status for overview
Browse files Browse the repository at this point in the history
  • Loading branch information
jamescowens committed Dec 16, 2020
1 parent 0fd25a1 commit fc5672c
Show file tree
Hide file tree
Showing 13 changed files with 269 additions and 130 deletions.
74 changes: 44 additions & 30 deletions src/gridcoin/staking/difficulty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ double GRC::GetTargetDifficulty()
return GetBlockDifficulty(GetNextTargetRequired(pindexBest));
}

// This requires a lock on cs_main when called.
double GRC::GetAverageDifficulty(unsigned int nPoSInterval)
{
/*
Expand All @@ -154,8 +155,6 @@ double GRC::GetAverageDifficulty(unsigned int nPoSInterval)
unsigned int nStakesHandled = 0;
double result;

LOCK(cs_main);

CBlockIndex* pindex = pindexBest;

while (pindex && nStakesHandled < nPoSInterval)
Expand All @@ -181,6 +180,44 @@ double GRC::GetAverageDifficulty(unsigned int nPoSInterval)
return result;
}

// This requires a lock on cs_main when called.
double GRC::GetSmoothedDifficulty(int64_t nStakeableBalance)
{
// The smoothed difficulty is derived via a two step process. There is a coupling between the desired block
// span to compute difficulty and essentially the stakeable balance: If the balance is low, the ETTS is
// expected to be relatively long, so it is appropriate to use a longer span to compute the difficulty.
// Conversely, if the stakeable balance is high, it is appropriate to use a corresponding short span so that
// the staking estimate reflects appropriate network conditions compared to the expected staking interval.
// Since this is a coupled problem, the approach here, which works reasonably well, uses the last hour
// (40 block) diff to bootstrap a span estimate from using the thumbrule estimate of ETTS with that diff,
// and then re-computes the diff using the block span, with clamp of [40, BLOCKS_PER_DAY], since it is silly to
// allow difficulty to become more sensitive than one hour of change, and is of minimal value to long term
// projections to use more than a day's history of diff. (Difficulty patterns tend to repeat on a daily basis.
// Longer term historical variations of more than a day are due to extraneous variables of which history is of
// little predictive value.)

double dDiff = 1.0;

// First estimate the difficulty based on the last 40 blocks.
dDiff = GetAverageDifficulty(40);

// Compute an appropriate block span for the second iteration of dificulty computation based on the
// above diff calc. Clamp to no less than 40 (~1 hour) and no more than 960 (~1 day). Note that those
// familiar with the thumbrule for ETTS, ETTS = 10000 / Balance * Diff should recognize it in the below
// expression. Note that the actual constant is 9942.2056 (from the bluepaper, eq. 12), but it suffices to
// use the rounded thumbrule value here.
unsigned int nEstAppropriateDiffSpan = clamp<unsigned int>(10000.0 * BLOCKS_PER_DAY * COIN
/ nStakeableBalance * dDiff,
40, 960);

LogPrint(BCLog::LogFlags::NOISY, "GetSmoothedDifficulty debug: nStakeableBalance: %u", nStakeableBalance);
LogPrint(BCLog::LogFlags::NOISY, "GetSmoothedDifficulty debug: nEstAppropriateDiffSpan: %u", nEstAppropriateDiffSpan);

dDiff = GetAverageDifficulty(nEstAppropriateDiffSpan);

return dDiff;
}

uint64_t GRC::GetStakeWeight(const CWallet& wallet)
{
if (wallet.GetBalance() <= nReserveBalance) {
Expand Down Expand Up @@ -365,36 +402,13 @@ double GRC::GetEstimatedTimetoStake(bool ignore_staking_status, double dDiff, do
}

// If dDiff = 0 from supplied argument (which is also the default), then derive a smoothed difficulty, otherwise
// let the supplied argument dDiff stand. The smoothed difficulty is derived via a two step process. There is a
// coupling between the desired block span to compute difficulty and essentially the stakeable balance: If the
// balance is low, the ETTS is expected to be relatively long, so it is appropriate to use a longer span to
// compute the difficulty. Conversely, if the stakeable balance is high, it is appropriate to use a corresponding
// short span so that the staking estimate reflects appropriate network conditions compared to the expected
// staking interval. Since this is a coupled problem, the approach here, which works reasonably well, uses the
// last hour (40 block) diff to bootstrap a span estimate from using the thumbrule estimate of ETTS with that diff,
// and then re-computes the diff using the block span, with clamp of [40, BLOCKS_PER_DAY], since it is silly to
// allow difficulty to become more sensitive than one hour of change, and is of minimal value to long term
// projections to use more than a day's history of diff. (Difficulty patterns tend to repeat on a daily basis.
// Longer term historical variations of more than a day are due to extraneous variables of which history is of
// little predictive value.)
if (!dDiff)
// let the supplied argument dDiff stand.
if (dDiff == 0)
{
// First estimate the difficulty based on the last 40 blocks.
dDiff = GetAverageDifficulty(40);
LOCK(cs_main);

// Compute an appropriate block span for the second iteration of dificulty computation based on the
// above diff calc. Clamp to no less than 40 (~1 hour) and no more than 960 (~1 day). Note that those
// familiar with the thumbrule for ETTS, ETTS = 10000 / Balance * Diff should recognize it in the below
// expression. Note that the actual constant is 9942.2056 (from the bluepaper, eq. 12), but it suffices to
// use the rounded thumbrule value here.
unsigned int nEstAppropriateDiffSpan = clamp<unsigned int>(10000.0 * BLOCKS_PER_DAY * COIN
/ nStakeableBalance * dDiff,
40, 960);

LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: nStakeableBalance: %u", nStakeableBalance);
LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: nEstAppropriateDiffSpan: %u", nEstAppropriateDiffSpan);

dDiff = GetAverageDifficulty(nEstAppropriateDiffSpan);
// First estimate the difficulty based on the last 40 blocks.
dDiff = GetSmoothedDifficulty(nStakeableBalance);
}

LogPrint(BCLog::LogFlags::NOISY, "GetEstimatedTimetoStake debug: dDiff = %f", dDiff);
Expand Down
1 change: 1 addition & 0 deletions src/gridcoin/staking/difficulty.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ double GetBlockDifficulty(unsigned int nBits);
double GetCurrentDifficulty();
double GetTargetDifficulty();
double GetAverageDifficulty(unsigned int nPoSInterval = 40);
double GetSmoothedDifficulty(int64_t nStakeableBalance);

uint64_t GetStakeWeight(const CWallet& wallet);
double GetEstimatedNetworkWeight(unsigned int nPoSInterval = 40);
Expand Down
2 changes: 1 addition & 1 deletion src/logging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ const CLogCategoryDesc LogCategories[] =
{BCLog::REINDEX, "reindex"},
{BCLog::CMPCTBLOCK, "cmpctblock"},
{BCLog::RAND, "rand"},
{BCLog::PRUNE, "prune"},
{BCLog::MISC, "misc"},
{BCLog::PROXY, "proxy"},
{BCLog::MEMPOOLREJ, "mempoolrej"},
{BCLog::LIBEVENT, "libevent"},
Expand Down
2 changes: 1 addition & 1 deletion src/logging.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ namespace BCLog {
REINDEX = (1 << 11),
CMPCTBLOCK = (1 << 12),
RAND = (1 << 13),
PRUNE = (1 << 14),
MISC = (1 << 14),
PROXY = (1 << 15),
MEMPOOLREJ = (1 << 16),
LIBEVENT = (1 << 17),
Expand Down
149 changes: 105 additions & 44 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ int64_t nMinimumInputValue = 0;
bool fQtActive = false;
bool bGridcoinCoreInitComplete = false;

extern void GetGlobalStatus();
extern bool LessVerbose(int iMax1000);

// Mining status variables
Expand All @@ -130,7 +129,7 @@ int nNewIndex2 = 364500;
int64_t nGenesisSupply = 340569880;

// Stats for Main Screen:
globalStatusType GlobalStatusStruct;
GlobalStatus g_GlobalStatus;

bool fColdBoot = true;
bool fEnforceCanonical = true;
Expand All @@ -154,65 +153,121 @@ arith_uint256 GetChainTrust(const CBlockIndex* pindex)
return g_chain_trust.GetTrust(pindex);
}

void GetGlobalStatus()
void GlobalStatus::SetGlobalStatus(bool force)
{
//Populate overview

try
// Only update if the previous update is >= 4 seconds old or force is specified to avoid
// unnecessary calculations.
if (force || GetAdjustedTime() - update_time >= 4)
{
uint64_t nWeight = GRC::GetStakeWeight(*pwalletMain);
double weight = nWeight/COIN;
double PORDiff = GRC::GetCurrentDifficulty();
std::string sWeight = RoundToString((double)weight,0);

//9-6-2015 Add RSA fields to overview
if ((double)weight > 100000000000000)
// These are atomics and do not need a lock on cs_errors_lock to update. But the global variable
// and functions called need a lock on cs_main.
{
sWeight = sWeight.substr(0,13) + "E" + RoundToString((double)sWeight.length()-13,0);
}
LOCK(cs_main);

LOCK(GlobalStatusStruct.lock);
blocks = nBestHeight;
netWeight = GRC::GetEstimatedNetworkWeight() / 80.0;
difficulty = GRC::GetCurrentDifficulty();
etts = GRC::GetEstimatedTimetoStake();
}

GlobalStatusStruct.blocks = ToString(nBestHeight);
GlobalStatusStruct.difficulty = RoundToString(PORDiff,3);
GlobalStatusStruct.netWeight = RoundToString(GRC::GetEstimatedNetworkWeight() / 80.0,2);
//todo: use the real weight from miner status (requires scaling)
GlobalStatusStruct.coinWeight = sWeight;
// GetStakeWeight takes its own necessary locks.
coinWeight = static_cast<double>(GRC::GetStakeWeight(*pwalletMain)) / COIN;

unsigned long stk_dropped;
update_time = GetAdjustedTime();

try
{
LOCK(g_miner_status.lock);
unsigned long stk_dropped;

if(g_miner_status.WeightSum)
GlobalStatusStruct.coinWeight = RoundToString(g_miner_status.WeightSum / 80.0,2);
{
LOCK2(g_miner_status.lock, cs_errors_lock);

GlobalStatusStruct.errors.clear();
std::string Alerts = GetWarnings("statusbar");
if(!Alerts.empty())
GlobalStatusStruct.errors += _("Alert: ") + Alerts + "; ";
staking = g_miner_status.nLastCoinStakeSearchInterval && g_miner_status.WeightSum;

if (PORDiff < 0.1)
GlobalStatusStruct.errors += _("Low difficulty!; ");
coinWeight = g_miner_status.WeightSum / 80.0;

if(!g_miner_status.ReasonNotStaking.empty())
GlobalStatusStruct.errors += _("Miner: ") + g_miner_status.ReasonNotStaking;
able_to_stake = g_miner_status.able_to_stake;

stk_dropped = g_miner_status.KernelsFound - g_miner_status.AcceptedCnt;
}
ReasonNotStaking = g_miner_status.ReasonNotStaking;

if (stk_dropped)
GlobalStatusStruct.errors += "Rejected " + ToString(stk_dropped) + " stakes;";
errors.clear();

return;
std::string Alerts = GetWarnings("statusbar");

if (!Alerts.empty())
{
errors += _("Alert: ") + Alerts + "; ";
}

if (difficulty < 0.1)
{
errors += _("Low difficulty!; ");
}

if (!g_miner_status.ReasonNotStaking.empty())
{
errors += _("Miner: ") + g_miner_status.ReasonNotStaking;
}

stk_dropped = g_miner_status.KernelsFound - g_miner_status.AcceptedCnt;
}

if (stk_dropped)
{
errors += "Rejected " + ToString(stk_dropped) + " stakes;";
}

return;
}
catch (std::exception& e)
{
errors = _("Error obtaining status.");

LogPrintf("Error obtaining status");
return;
}
}
catch (std::exception& e)
}

const GlobalStatus::globalStatusType GlobalStatus::GetGlobalStatus()
{
globalStatusType globalStatus;

globalStatus.update_time = update_time;
globalStatus.blocks = blocks;
globalStatus.difficulty = difficulty;
globalStatus.netWeight = netWeight;
globalStatus.coinWeight = coinWeight;
globalStatus.etts = etts;

globalStatus.able_to_stake = able_to_stake;
globalStatus.staking = staking;

LOCK(cs_errors_lock);

globalStatus.ReasonNotStaking = ReasonNotStaking;
globalStatus.errors = errors;

return globalStatus;
}

const GlobalStatus::globalStatusStringType GlobalStatus::GetGlobalStatusStrings()
{
const globalStatusType& globalStatus = GetGlobalStatus();

globalStatusStringType globalStatusStrings;

if (update_time > 0)
{
GlobalStatusStruct.errors = _("Error obtaining status.");
globalStatusStrings.blocks = ToString(globalStatus.blocks);
globalStatusStrings.difficulty = RoundToString(globalStatus.difficulty, 3);
globalStatusStrings.netWeight = RoundToString(globalStatus.netWeight, 2);
globalStatusStrings.coinWeight = RoundToString(globalStatus.coinWeight, 2);

LogPrintf("Error obtaining status");
return;
globalStatusStrings.errors = globalStatus.errors;
}

return globalStatusStrings;
}

void RegisterWallet(CWallet* pwalletIn)
Expand Down Expand Up @@ -3068,10 +3123,16 @@ arith_uint256 CBlockIndex::GetBlockTrust() const

bool GridcoinServices()
{
//Dont do this on headless - SeP
// This is only necessary if the GUI is running. It is also really only necessary during
// rapid block influx during sync. SetGlobalStatus runs from the ClientModel timer with the force
// parameter set as well. Not sure any of this is necessary, since the overview page updateglobalstatus
// and UpdateBoincUtilization run a "hard" GlobalStatus update anyway, on a 5 second timer.
if (fQtActive && (nBestHeight % 125) == 0 && nBestHeight > 0)
{
GetGlobalStatus();
// Do a "soft" GlobalStatus update. In addition to the 125 block ladder above, the "soft" update
// will only actually update if more than 5 seconds has elapsed since the last call.
g_GlobalStatus.SetGlobalStatus();
// Emit the NotifyBlocksChanged signal. Note that this signal is not actually hooked up right now.
uiInterface.NotifyBlocksChanged();
}

Expand Down
Loading

0 comments on commit fc5672c

Please sign in to comment.