diff --git a/src/gridcoin/accrual/computer.h b/src/gridcoin/accrual/computer.h
index 4ea2d810a7..96818a2a6c 100644
--- a/src/gridcoin/accrual/computer.h
+++ b/src/gridcoin/accrual/computer.h
@@ -71,6 +71,12 @@ class IAccrualComputer
//!
virtual CAmount PaymentPerDayLimit() const = 0;
+ //!
+ //! \brief Return an accrual value that is nearing the limit based on accrual rate.
+ //! \return Value of near limit in CAmount units.
+ //!
+ virtual CAmount NearRewardLimit() const = 0;
+
//!
//! \brief Determine whether the account exceeded the daily payment limit.
//!
diff --git a/src/gridcoin/accrual/newbie.h b/src/gridcoin/accrual/newbie.h
index bfe1646d53..dd46733228 100644
--- a/src/gridcoin/accrual/newbie.h
+++ b/src/gridcoin/accrual/newbie.h
@@ -84,6 +84,16 @@ class NewbieAccrualComputer : public IAccrualComputer
return MaxReward();
}
+ CAmount NearRewardLimit() const override
+ {
+ // This returns MaxReward() - 2 * ExpectedDaily() or 1/2 of MaxReward(), whichever
+ // is greater
+
+ CAmount threshold = std::max(MaxReward() / 2, MaxReward() - 2 * ExpectedDaily());
+
+ return threshold;
+ }
+
bool ExceededRecentPayments() const override
{
return RawAccrual() > PaymentPerDayLimit();
diff --git a/src/gridcoin/accrual/null.h b/src/gridcoin/accrual/null.h
index 58eaa91540..960cec45a9 100644
--- a/src/gridcoin/accrual/null.h
+++ b/src/gridcoin/accrual/null.h
@@ -57,6 +57,11 @@ class NullAccrualComputer : public IAccrualComputer
return 0;
}
+ CAmount NearRewardLimit() const override
+ {
+ return 0;
+ }
+
bool ExceededRecentPayments() const override
{
return false;
diff --git a/src/gridcoin/accrual/research_age.h b/src/gridcoin/accrual/research_age.h
index 9fc7c84916..8018db0fb1 100644
--- a/src/gridcoin/accrual/research_age.h
+++ b/src/gridcoin/accrual/research_age.h
@@ -165,6 +165,16 @@ class ResearchAgeComputer : public IAccrualComputer
return m_account.AverageLifetimeMagnitude() * m_magnitude_unit * COIN * 5;
}
+ CAmount NearRewardLimit() const override
+ {
+ // This returns MaxReward() - 2 * ExpectedDaily() or 1/2 of MaxReward(), whichever
+ // is greater
+
+ CAmount threshold = std::max(MaxReward() / 2, MaxReward() - 2 * ExpectedDaily());
+
+ return threshold;
+ }
+
//!
//! \brief Determine whether the account exceeded the daily payment limit.
//!
diff --git a/src/gridcoin/accrual/snapshot.h b/src/gridcoin/accrual/snapshot.h
index 5b7ad3fe4a..1bd009e811 100644
--- a/src/gridcoin/accrual/snapshot.h
+++ b/src/gridcoin/accrual/snapshot.h
@@ -361,6 +361,16 @@ class SnapshotAccrualComputer : public IAccrualComputer, SnapshotCalculator
return MaxReward();
}
+ CAmount NearRewardLimit() const override
+ {
+ // This returns MaxReward() - 2 * ExpectedDaily() or 1/2 of MaxReward(), whichever
+ // is greater
+
+ CAmount threshold = std::max(MaxReward() / 2, MaxReward() - 2 * ExpectedDaily());
+
+ return threshold;
+ }
+
bool ExceededRecentPayments() const override
{
return RawAccrual() > PaymentPerDayLimit();
diff --git a/src/gridcoin/researcher.cpp b/src/gridcoin/researcher.cpp
index 7537b183dc..c4b57ad034 100644
--- a/src/gridcoin/researcher.cpp
+++ b/src/gridcoin/researcher.cpp
@@ -1329,6 +1329,21 @@ CAmount Researcher::Accrual() const
return Tally::GetAccrual(*cpid, now, pindexBest);
}
+CAmount Researcher::AccrualNearLimit() const
+{
+ const CpidOption cpid = m_mining_id.TryCpid();
+
+ if (!cpid || !pindexBest) {
+ return false;
+ }
+
+ const int64_t now = OutOfSyncByAge() ? pindexBest->nTime : GetAdjustedTime();
+
+ LOCK(cs_main);
+
+ return Tally::AccrualNearLimit(*cpid, now, pindexBest);
+}
+
ResearcherStatus Researcher::Status() const
{
if (Eligible()) {
diff --git a/src/gridcoin/researcher.h b/src/gridcoin/researcher.h
index 3ad03d197d..325f4f94fc 100644
--- a/src/gridcoin/researcher.h
+++ b/src/gridcoin/researcher.h
@@ -550,6 +550,12 @@ class Researcher
//!
CAmount Accrual() const;
+ //!
+ //! \brief Value of account accrual that is near MaxReward() based on accrual rate..
+ //! \return CAmount value. This is implemented in IAccrualComputer::NearRewardLimit().
+ //!
+ CAmount AccrualNearLimit() const;
+
//!
//! \brief Get a value that indicates how the wallet participates in the
//! research reward protocol.
diff --git a/src/gridcoin/tally.cpp b/src/gridcoin/tally.cpp
index 46e965dc09..73929b9bc5 100644
--- a/src/gridcoin/tally.cpp
+++ b/src/gridcoin/tally.cpp
@@ -1090,6 +1090,14 @@ CAmount Tally::GetAccrual(
return GetComputer(cpid, payment_time, last_block_ptr)->Accrual();
}
+CAmount Tally::AccrualNearLimit(
+ const Cpid cpid,
+ const int64_t payment_time,
+ const CBlockIndex* const last_block_ptr)
+{
+ return (GetComputer(cpid, payment_time, last_block_ptr)->NearRewardLimit()) ;
+}
+
//!
//! \brief Compute "catch-up" accrual to correct for newbie accrual bug.
//!
diff --git a/src/gridcoin/tally.h b/src/gridcoin/tally.h
index 6fa4f8228c..ed4b6c6b0a 100644
--- a/src/gridcoin/tally.h
+++ b/src/gridcoin/tally.h
@@ -133,6 +133,22 @@ class Tally
const int64_t payment_time,
const CBlockIndex* const last_block_ptr);
+ //!
+ //! \brief A value of the accrual that is near the MaxReward for the accrual computer in context based on
+ //! the rate of accrual. This is defined in the implementation of the virtual method NearRewardLimit()
+ //! in IAccrualComputer.
+ //!
+ //! \param cpid CPID to calculate research accrual for.
+ //! \param payment_time Time of payment to calculate rewards at.
+ //! \param last_block_ptr Refers to the block for the reward.
+ //!
+ //! \return CAmount of account accrual that is near the MaxReward.
+ //!
+ static CAmount AccrualNearLimit(
+ const Cpid cpid,
+ const int64_t payment_time,
+ const CBlockIndex* const last_block_ptr);
+
//!
//! \brief Compute "catch-up" accrual to correct for newbie accrual bug.
//!
diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui
index 7827a69310..6e925557b6 100644
--- a/src/qt/forms/overviewpage.ui
+++ b/src/qt/forms/overviewpage.ui
@@ -7,7 +7,7 @@
0
0
948
- 635
+ 755
@@ -788,10 +788,10 @@
12
- -
-
+
-
+
- Status:
+ Magnitude:
true
@@ -817,18 +817,24 @@
- -
-
+
-
+
+
+
+ 0
+ 0
+
+
- Magnitude:
+
-
- true
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse
- -
-
+
-
+
0
@@ -843,6 +849,16 @@
+ -
+
+
+ Status:
+
+
+ true
+
+
+
-
@@ -853,19 +869,25 @@
- -
-
-
-
- 0
- 0
-
+
-
+
+
+
+ 16777215
+ 16777215
+
+
+
+ You are approaching the accrual limit of 16384 GRC. If you have a relatively low balance, you should request payment via MRC so that you do not lose earned rewards.
-
+
-
- Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse
+
+ :/icons/warning
+
+
+ true
@@ -1108,6 +1130,8 @@
1
-
+
+
+
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index cadc72d084..0a0ac45872 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -153,6 +153,10 @@ OverviewPage::OverviewPage(QWidget *parent) :
ui->stakingGridLayout->setVerticalSpacing(verticalSpacing);
ui->researcherGridLayout->setVerticalSpacing(verticalSpacing);
+ // scale warning icon
+ int warning_icon_size = GRC::ScalePx(this, 21);
+ ui->accrualLimitWarningIconlabel->setMaximumSize(QSize(warning_icon_size, warning_icon_size));
+
// Recent Transactions
ui->listTransactions->setItemDelegate(txdelegate);
ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false);
@@ -285,6 +289,7 @@ void OverviewPage::setBalance(qint64 balance, qint64 stake, qint64 unconfirmedBa
bool showImmature = immatureBalance != 0;
ui->immatureLabel->setVisible(showImmature);
ui->immatureTextLabel->setVisible(showImmature);
+
}
void OverviewPage::setHeight(int height, int height_of_peers, bool in_sync)
@@ -501,7 +506,14 @@ void OverviewPage::updatePendingAccrual()
unit = walletModel->getOptionsModel()->getDisplayUnit();
}
- ui->accrualLabel->setText(researcherModel->formatAccrual(unit));
+ bool near_limit = false;
+
+ ui->accrualLabel->setText(researcherModel->formatAccrual(unit, near_limit));
+ if (near_limit) {
+ ui->accrualLimitWarningIconlabel->show();
+ } else {
+ ui->accrualLimitWarningIconlabel->hide();
+ }
}
void OverviewPage::updateResearcherAlert()
diff --git a/src/qt/researcher/researchermodel.cpp b/src/qt/researcher/researchermodel.cpp
index 9074e3e316..032892c9c1 100644
--- a/src/qt/researcher/researchermodel.cpp
+++ b/src/qt/researcher/researchermodel.cpp
@@ -317,6 +317,11 @@ bool ResearcherModel::needsBeaconAuth() const
return m_beacon->m_public_key != m_pending_beacon->m_public_key;
}
+CAmount ResearcherModel::accrualNearLimit() const
+{
+ return m_researcher->AccrualNearLimit();
+}
+
CAmount ResearcherModel::getAccrual() const
{
return m_researcher->Accrual();
@@ -353,16 +358,23 @@ QString ResearcherModel::formatMagnitude() const
return text;
}
-QString ResearcherModel::formatAccrual(const int display_unit) const
+QString ResearcherModel::formatAccrual(const int display_unit, bool& near_limit) const
{
QString text;
+ // We only do the actual accrual calculation once. The AccrualNearLimit() is lighter.
+ CAmount accrual = m_researcher->Accrual();
+
+ near_limit = (accrual >= m_researcher->AccrualNearLimit());
+
if (outOfSync()) {
text = "...";
} else {
- text = BitcoinUnits::formatWithPrivacy(display_unit, m_researcher->Accrual(), m_privacy_enabled);
+ text = BitcoinUnits::formatWithPrivacy(display_unit, accrual, m_privacy_enabled);
}
+
+
return text;
}
diff --git a/src/qt/researcher/researchermodel.h b/src/qt/researcher/researchermodel.h
index 480fac6ee2..9e3ac12ea4 100644
--- a/src/qt/researcher/researchermodel.h
+++ b/src/qt/researcher/researchermodel.h
@@ -101,12 +101,13 @@ class ResearcherModel : public QObject
bool hasSplitCpid() const;
bool needsBeaconAuth() const;
+ CAmount accrualNearLimit() const;
CAmount getAccrual() const;
QString email() const;
QString formatCpid() const;
QString formatMagnitude() const;
- QString formatAccrual(const int display_unit) const;
+ QString formatAccrual(const int display_unit, bool& near_limit) const;
QString formatStatus() const;
QString formatBoincPath() const;
diff --git a/src/qt/researcher/researcherwizardsummarypage.cpp b/src/qt/researcher/researcherwizardsummarypage.cpp
index 8d99ac4dac..6e5bd24ab6 100644
--- a/src/qt/researcher/researcherwizardsummarypage.cpp
+++ b/src/qt/researcher/researcherwizardsummarypage.cpp
@@ -94,7 +94,9 @@ void ResearcherWizardSummaryPage::refreshSummary()
ui->cpidLabel->setText(m_researcher_model->formatCpid());
ui->statusLabel->setText(m_researcher_model->formatStatus());
ui->magnitudeLabel->setText(m_researcher_model->formatMagnitude());
- ui->accrualLabel->setText(m_researcher_model->formatAccrual(unit));
+
+ bool near_limit = false;
+ ui->accrualLabel->setText(m_researcher_model->formatAccrual(unit, near_limit));
ui->reviewBeaconAuthButton->setVisible(m_researcher_model->needsBeaconAuth());
ui->beaconDetailsIconLabel->setPixmap(