Skip to content

Commit a5fc22b

Browse files
committed
Improve Staking Icon
Improvements have been made to the miner code to use scoped enums for the miner status rather than a concatenated string. (The string is also retained for legacy purposes for now.) The old staking icon/tooltip conflated two different states together: "unable to stake" because the wallet is locked or the reserve is set so that no coins can be used for staking, etc. vs. "currently not staking, but able to stake", which is all of the coins currently on cooldown (such as for a new wallet that just received it's first "deposit", or a one UTXO wallet where the UTXO just staked and is on cooldown. I have introduced a new staking icon, a red down arrow, which indicates "unable to stake", with an appropriate tooltip description. The gray down arrow is now used for "currently not staking" status, where staking will occur without any further operator action (i.e. coins maturing). The green up arrow is used for currently staking status as before. Some minor improvements were also made, such as minor style cleanups of the code where I was working, along with some lock optimizations.
1 parent 80aee2c commit a5fc22b

File tree

13 files changed

+365
-117
lines changed

13 files changed

+365
-117
lines changed

src/Makefile.qt.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ RES_ICONS = \
270270
qt/res/icons/rsz_chat.png \
271271
qt/res/icons/staking_off.svg \
272272
qt/res/icons/staking_on.svg \
273+
qt/res/icons/staking_unable.svg \
273274
qt/res/icons/statistics.png \
274275
qt/res/icons/toolbar.png \
275276
qt/res/icons/transaction_conflicted.png \

src/main.cpp

Lines changed: 68 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -377,9 +377,19 @@ double GetEstimatedTimetoStake(bool ignore_staking_status, double dDiff, double
377377
return result;
378378
}
379379

380-
bool staking = MinerStatus.nLastCoinStakeSearchInterval && MinerStatus.WeightSum;
381-
// Get out early if not staking and ignore_staking_status is false and set return value of 0.
382-
if (!staking && !ignore_staking_status)
380+
bool staking;
381+
bool able_to_stake;
382+
383+
{
384+
LOCK(MinerStatus.lock);
385+
386+
staking = MinerStatus.nLastCoinStakeSearchInterval && MinerStatus.WeightSum;
387+
388+
able_to_stake = MinerStatus.able_to_stake;
389+
}
390+
391+
// Get out early if not staking, ignore_staking_status is false, and not able_to_stake and set return value of 0.
392+
if (!ignore_staking_status && !staking && !able_to_stake)
383393
{
384394
if (fDebug10) LogPrintf("GetEstimatedTimetoStake debug: Not staking: ETTS = %f", result);
385395
return result;
@@ -447,11 +457,9 @@ double GetEstimatedTimetoStake(bool ignore_staking_status, double dDiff, double
447457
{
448458
CTxIndex txindex;
449459
CBlock CoinBlock; //Block which contains CoinTx
450-
if (!txdb.ReadTxIndex(out.tx->GetHash(), txindex))
451-
continue; //error?
460+
if (!txdb.ReadTxIndex(out.tx->GetHash(), txindex)) continue; //Ignore transactions that can't be read.
452461

453-
if (!CoinBlock.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
454-
continue;
462+
if (!CoinBlock.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) continue;
455463

456464
// We are going to store as an event the time that the UTXO matures (is available for staking again.)
457465
nTime = (CoinBlock.GetBlockTime() & ~ETTS_TIMESTAMP_MASK) + nStakeMinAge;
@@ -462,14 +470,14 @@ double GetEstimatedTimetoStake(bool ignore_staking_status, double dDiff, double
462470
// subtracting the reserve. Each UTXO also has to be greater than 1/80 GRC to result in a weight greater than zero in the CreateCoinStake loop,
463471
// so eliminate UTXO's with less than 0.0125 GRC balances right here. The test with Satoshi units for that is
464472
// nValue >= 1250000.
465-
if(BalanceAvailForStaking >= nValue && nValue >= 1250000)
473+
if (BalanceAvailForStaking >= nValue && nValue >= 1250000)
466474
{
467475
vUTXO.push_back(std::pair<int64_t, int64_t>( nTime, nValue));
468476
if (fDebug10) LogPrintf("GetEstimatedTimetoStake debug: pair (relative to current time: <%i, %i>", nTime - nCurrentTime, nValue);
469477

470478
// Only record a time below if it is after nCurrentTime, because UTXO's that have matured already are already stakeable and can be grouped (will be found)
471479
// by the nCurrentTime record that was already injected above.
472-
if(nTime > nCurrentTime) UniqueUTXOTimes.insert(nTime);
480+
if (nTime > nCurrentTime) UniqueUTXOTimes.insert(nTime);
473481
}
474482
}
475483

@@ -485,13 +493,13 @@ double GetEstimatedTimetoStake(bool ignore_staking_status, double dDiff, double
485493
// become significant. The CDF of a compound geometric distribution as you do tosses with different probabilities follows the
486494
// recursion relation... CDF.i = 1 - (1 - CDF.i-1)(1 - p.i). If all probabilities are the same, this reduces to the familiar
487495
// CDF.k = 1 - (1 - p)^k where ^ is exponentiation.
488-
for(const auto& itertime : UniqueUTXOTimes)
496+
for (const auto& itertime : UniqueUTXOTimes)
489497
{
490498

491499
nTime = itertime;
492500
dProbAccumulator = 0;
493501

494-
for( auto& iterUTXO : vUTXO)
502+
for (auto& iterUTXO : vUTXO)
495503
{
496504

497505
if (fDebug10) LogPrintf("GetEstimatedTimetoStake debug: Unique UTXO Time: %u, vector pair <%u, %u>", nTime, iterUTXO.first, iterUTXO.second);
@@ -515,8 +523,7 @@ double GetEstimatedTimetoStake(bool ignore_staking_status, double dDiff, double
515523
dCumulativeProbability = 1 - ((1 - dCumulativeProbability) * pow((1 - dProbAccumulator), nThrows));
516524
if (fDebug10) LogPrintf("GetEstimatedTimetoStake debug: dCumulativeProbability = %e", dCumulativeProbability);
517525

518-
if(dCumulativeProbability >= dConfidence)
519-
break;
526+
if (dCumulativeProbability >= dConfidence) break;
520527

521528
nTimePrev = nTime;
522529
}
@@ -549,16 +556,6 @@ double GetEstimatedTimetoStake(bool ignore_staking_status, double dDiff, double
549556
result = nDeltaTime + nTime - nCurrentTime;
550557
if (fDebug10) LogPrintf("GetEstimatedTimetoStake debug: ETTS at %d confidence = %i", dConfidence, result);
551558

552-
// The old calculation for comparative purposes, only done if fDebug10 set. Note that this is the "fixed" old
553-
// calculation, because the old network weight calculation was wrong too...
554-
if (fDebug10)
555-
{
556-
double oldETTS = 0;
557-
558-
oldETTS = GetTargetSpacing(nBestHeight) * GetEstimatedNetworkWeight(40) / MinerStatus.WeightSum;
559-
LogPrintf("GetEstimatedTimetoStake debug: oldETTS = %f", oldETTS);
560-
}
561-
562559
return result;
563560
}
564561

@@ -598,48 +595,57 @@ void GetGlobalStatus()
598595

599596
// It is necessary to assign a local variable for ETTS to avoid an occasional deadlock between the lock below,
600597
// the lock on cs_main in GetEstimateTimetoStake(), and the corresponding lock in the stakeminer.
601-
double dETTS = GetEstimatedTimetoStake()/86400.0;
598+
double dETTS = GetEstimatedTimetoStake() / 86400.0;
599+
602600
LOCK(GlobalStatusStruct.lock);
603-
{ LOCK(MinerStatus.lock);
604-
GlobalStatusStruct.blocks = ToString(nBestHeight);
605-
GlobalStatusStruct.difficulty = RoundToString(PORDiff,3);
606-
GlobalStatusStruct.netWeight = RoundToString(GetEstimatedNetworkWeight() / 80.0,2);
607-
//todo: use the real weight from miner status (requires scaling)
608-
GlobalStatusStruct.coinWeight = sWeight;
609-
GlobalStatusStruct.magnitude = RoundToString(boincmagnitude,2);
610-
GlobalStatusStruct.ETTS = RoundToString(dETTS,3);
611-
GlobalStatusStruct.ERRperday = RoundToString(boincmagnitude * NN::Tally::GetMagnitudeUnit(GetAdjustedTime()),2);
612-
GlobalStatusStruct.cpid = NN::GetPrimaryCpid();
613-
GlobalStatusStruct.poll = std::move(current_poll);
614-
615-
GlobalStatusStruct.status = msMiningErrors;
616-
617-
if(MinerStatus.WeightSum)
618-
GlobalStatusStruct.coinWeight = RoundToString(MinerStatus.WeightSum / 80.0,2);
619-
620-
GlobalStatusStruct.errors.clear();
621-
std::string Alerts = GetWarnings("statusbar");
622-
if(!Alerts.empty())
623-
GlobalStatusStruct.errors += _("Alert: ") + Alerts + "; ";
624-
625-
if (PORDiff < 0.1)
626-
GlobalStatusStruct.errors += _("Low difficulty!; ");
627-
628-
if(!MinerStatus.ReasonNotStaking.empty())
629-
GlobalStatusStruct.errors += _("Miner: ") + MinerStatus.ReasonNotStaking;
630-
631-
unsigned long stk_dropped = MinerStatus.KernelsFound - MinerStatus.AcceptedCnt;
632-
if(stk_dropped)
633-
GlobalStatusStruct.errors += "Rejected " + ToString(stk_dropped) + " stakes;";
634-
635-
if(!msMiningErrors6.empty())
636-
GlobalStatusStruct.errors +=msMiningErrors6 + "; ";
637-
if(!msMiningErrors7.empty())
638-
GlobalStatusStruct.errors += msMiningErrors7 + "; ";
639-
if(!msMiningErrors8.empty())
640-
GlobalStatusStruct.errors += msMiningErrors8 + "; ";
641601

602+
{
603+
GlobalStatusStruct.blocks = ToString(nBestHeight);
604+
GlobalStatusStruct.difficulty = RoundToString(PORDiff,3);
605+
GlobalStatusStruct.netWeight = RoundToString(GetEstimatedNetworkWeight() / 80.0,2);
606+
//todo: use the real weight from miner status (requires scaling)
607+
GlobalStatusStruct.coinWeight = sWeight;
608+
GlobalStatusStruct.magnitude = RoundToString(boincmagnitude,2);
609+
GlobalStatusStruct.ETTS = RoundToString(dETTS,3);
610+
GlobalStatusStruct.ERRperday = RoundToString(boincmagnitude * NN::Tally::GetMagnitudeUnit(GetAdjustedTime()),2);
611+
GlobalStatusStruct.cpid = NN::GetPrimaryCpid();
612+
GlobalStatusStruct.poll = std::move(current_poll);
613+
614+
GlobalStatusStruct.status = msMiningErrors;
615+
616+
unsigned long stk_dropped;
617+
618+
{
619+
LOCK(MinerStatus.lock);
620+
621+
if(MinerStatus.WeightSum)
622+
GlobalStatusStruct.coinWeight = RoundToString(MinerStatus.WeightSum / 80.0,2);
623+
624+
GlobalStatusStruct.errors.clear();
625+
std::string Alerts = GetWarnings("statusbar");
626+
if(!Alerts.empty())
627+
GlobalStatusStruct.errors += _("Alert: ") + Alerts + "; ";
628+
629+
if (PORDiff < 0.1)
630+
GlobalStatusStruct.errors += _("Low difficulty!; ");
631+
632+
if(!MinerStatus.ReasonNotStaking.empty())
633+
GlobalStatusStruct.errors += _("Miner: ") + MinerStatus.ReasonNotStaking;
634+
635+
stk_dropped = MinerStatus.KernelsFound - MinerStatus.AcceptedCnt;
636+
}
637+
638+
if (stk_dropped)
639+
GlobalStatusStruct.errors += "Rejected " + ToString(stk_dropped) + " stakes;";
640+
641+
if (!msMiningErrors6.empty())
642+
GlobalStatusStruct.errors +=msMiningErrors6 + "; ";
643+
if (!msMiningErrors7.empty())
644+
GlobalStatusStruct.errors += msMiningErrors7 + "; ";
645+
if (!msMiningErrors8.empty())
646+
GlobalStatusStruct.errors += msMiningErrors8 + "; ";
642647
}
648+
643649
return;
644650
}
645651
catch (std::exception& e)

src/miner.cpp

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,13 @@ class COrphan
6666
//!
6767
//! \return Always \false - suitable for returning from the call directly.
6868
//!
69-
bool ReturnMinerError(CMinerStatus& status, const std::string& message)
69+
bool ReturnMinerError(CMinerStatus& status, CMinerStatus::ReasonNotStakingCategory& not_staking_error)
7070
{
7171
LOCK(status.lock);
7272

7373
status.Clear();
74-
status.ReasonNotStaking += message;
75-
status.ReasonNotStaking += "; ";
74+
75+
status.SetReasonNotStaking(not_staking_error);
7676

7777
if (fDebug) {
7878
LogPrintf("CreateCoinStake: %s", MinerStatus.ReasonNotStaking);
@@ -131,7 +131,7 @@ bool SignClaim(NN::Claim& claim, const uint256& last_block_hash)
131131
CMinerStatus::CMinerStatus(void)
132132
{
133133
Clear();
134-
ReasonNotStaking= "";
134+
ClearReasonsNotStaking();
135135
CreatedCnt= AcceptedCnt= KernelsFound= 0;
136136
KernelDiffMax= 0;
137137
}
@@ -144,6 +144,35 @@ void CMinerStatus::Clear()
144144
nLastCoinStakeSearchInterval = 0;
145145
}
146146

147+
bool CMinerStatus::SetReasonNotStaking(ReasonNotStakingCategory not_staking_error)
148+
{
149+
bool inserted = false;
150+
151+
if (std::find(vReasonNotStaking.begin(), vReasonNotStaking.end(), not_staking_error) == vReasonNotStaking.end())
152+
{
153+
vReasonNotStaking.insert(vReasonNotStaking.end(), not_staking_error);
154+
155+
if (not_staking_error != NONE)
156+
{
157+
if (!ReasonNotStaking.empty()) ReasonNotStaking += "; ";
158+
ReasonNotStaking += vReasonNotStakingStrings[static_cast<int>(not_staking_error)];
159+
}
160+
161+
if (not_staking_error > NO_MATURE_COINS) able_to_stake = false;
162+
163+
inserted = true;
164+
}
165+
166+
return inserted;
167+
}
168+
169+
void CMinerStatus::ClearReasonsNotStaking()
170+
{
171+
vReasonNotStaking.clear();
172+
ReasonNotStaking.clear();
173+
able_to_stake = true;
174+
}
175+
147176
CMinerStatus MinerStatus;
148177

149178
// We want to sort transactions by priority and fee, so:
@@ -477,11 +506,11 @@ bool CreateCoinStake( CBlock &blocknew, CKey &key,
477506

478507
// Choose coins to use
479508
vector<pair<const CWalletTx*,unsigned int>> CoinsToStake;
480-
string sError = "";
509+
CMinerStatus::ReasonNotStakingCategory not_staking_error;
481510

482-
if (!wallet.SelectCoinsForStaking(txnew.nTime, CoinsToStake, sError, true))
511+
if (!wallet.SelectCoinsForStaking(txnew.nTime, CoinsToStake, not_staking_error, true))
483512
{
484-
ReturnMinerError(MinerStatus, sError);
513+
ReturnMinerError(MinerStatus, not_staking_error);
485514

486515
return false;
487516
}
@@ -1053,14 +1082,14 @@ bool IsMiningAllowed(CWallet *pwallet)
10531082
if(pwallet->IsLocked())
10541083
{
10551084
LOCK(MinerStatus.lock);
1056-
MinerStatus.ReasonNotStaking+=_("Wallet locked; ");
1085+
MinerStatus.SetReasonNotStaking(CMinerStatus::WALLET_LOCKED);
10571086
status=false;
10581087
}
10591088

10601089
if(fDevbuildCripple)
10611090
{
10621091
LOCK(MinerStatus.lock);
1063-
MinerStatus.ReasonNotStaking+="Testnet-only version; ";
1092+
MinerStatus.SetReasonNotStaking(CMinerStatus::TESTNET_ONLY);
10641093
status=false;
10651094
}
10661095

@@ -1069,7 +1098,7 @@ bool IsMiningAllowed(CWallet *pwallet)
10691098
)
10701099
{
10711100
LOCK(MinerStatus.lock);
1072-
MinerStatus.ReasonNotStaking+=_("Offline; ");
1101+
MinerStatus.SetReasonNotStaking(CMinerStatus::OFFLINE);
10731102
status=false;
10741103
}
10751104

@@ -1227,9 +1256,11 @@ void StakeMiner(CWallet *pwallet)
12271256
CBlockIndex* pindexPrev = pindexBest;
12281257
CBlock StakeBlock;
12291258

1230-
{ LOCK(MinerStatus.lock);
1259+
{
1260+
LOCK(MinerStatus.lock);
1261+
12311262
//clear miner messages
1232-
MinerStatus.ReasonNotStaking="";
1263+
MinerStatus.ClearReasonsNotStaking();
12331264

12341265
//New versions
12351266
if (IsV11Enabled(pindexPrev->nHeight + 1)) {
@@ -1240,11 +1271,15 @@ void StakeMiner(CWallet *pwallet)
12401271
}
12411272

12421273
MinerStatus.Version= StakeBlock.nVersion;
1274+
1275+
// This is needed due to early initialization of bitcoingui
1276+
miner_first_pass_complete = true;
12431277
}
12441278

12451279
if(!IsMiningAllowed(pwallet))
12461280
{
12471281
LOCK(MinerStatus.lock);
1282+
12481283
MinerStatus.Clear();
12491284
continue;
12501285
}
@@ -1294,7 +1329,9 @@ void StakeMiner(CWallet *pwallet)
12941329

12951330
LogPrintf("StakeMiner: signed boinchash, coinstake, wholeblock");
12961331

1297-
{ LOCK(MinerStatus.lock);
1332+
{
1333+
LOCK(MinerStatus.lock);
1334+
12981335
MinerStatus.CreatedCnt++;
12991336
}
13001337

@@ -1306,7 +1343,10 @@ void StakeMiner(CWallet *pwallet)
13061343
}
13071344

13081345
LogPrintf("StakeMiner: block processed");
1309-
{ LOCK(MinerStatus.lock);
1346+
1347+
{
1348+
LOCK(MinerStatus.lock);
1349+
13101350
MinerStatus.AcceptedCnt++;
13111351
}
13121352

src/miner.h

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,7 @@
99
#include "main.h"
1010
#include "wallet.h"
1111

12-
struct CMinerStatus
13-
{
14-
CCriticalSection lock;
15-
std::string ReasonNotStaking;
16-
uint64_t WeightSum,WeightMin,WeightMax;
17-
double ValueSum;
18-
int Version;
19-
uint64_t CreatedCnt;
20-
uint64_t AcceptedCnt;
21-
uint64_t KernelsFound;
22-
int64_t nLastCoinStakeSearchInterval;
23-
double KernelDiffMax;
24-
double KernelDiffSum;
25-
26-
void Clear();
27-
CMinerStatus();
28-
};
12+
// struct CMinerStatus is in wallet.h to prevent a circular header reference issue
2913

3014
typedef std::vector< std::pair<std::string, double> > SideStakeAlloc;
3115

src/qt/bitcoin.qrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
<file alias="notsynced">res/icons/notsynced.svg</file>
7272
<file alias="synced">res/icons/green_check.svg</file>
7373
<file alias="white_and_red_x">res/icons/white_and_red_x.svg</file>
74+
<file alias="staking_unable">res/icons/staking_unable.svg</file>
7475
</qresource>
7576
<qresource prefix="/images">
7677
<file alias="splash">res/images/splash3.png</file>

0 commit comments

Comments
 (0)