Skip to content

Commit

Permalink
Implement protocol entry changeable magnitude unit
Browse files Browse the repository at this point in the history
The magnitude unit has been fixed at 1/4 since Fern. This commit
allows the magnitude unit to be changed via a protocol entry for block
V13+.
  • Loading branch information
jamescowens committed Dec 16, 2024
1 parent ca935a3 commit 6c47db9
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 37 deletions.
87 changes: 77 additions & 10 deletions src/gridcoin/accrual/snapshot.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
#include "gridcoin/accrual/computer.h"
#include "gridcoin/beacon.h"
#include "gridcoin/cpid.h"
#include "gridcoin/protocol.h"
#include "gridcoin/sidestake.h"
#include "gridcoin/superblock.h"
#include "gridcoin/support/block_finder.h"
#include "gridcoin/support/filehash.h"
#include "node/blockstorage.h"
#include "serialize.h"
Expand All @@ -29,6 +32,7 @@ namespace {
using namespace GRC;
using LogFlags = BCLog::LogFlags;

/*
//!
//! \brief Numerator of the static magnitude unit coefficient for snapshot
//! accrual (block version 11 and greater).
Expand All @@ -40,6 +44,7 @@ constexpr int64_t MAG_UNIT_NUMERATOR = 1;
//! accrual (block version 11 and greater).
//!
constexpr int64_t MAG_UNIT_DENOMINATOR = 4;
*/

//!
//! \brief Calculates the current accrual for a CPID by adding the snapshot of
Expand All @@ -61,6 +66,66 @@ class SnapshotCalculator
{
}

//!
//! \brief Returns the current magnitude unit allocation fraction as of the provided superblock. Prior to block v13 this is
//! fixed at 1/4.
//!
//! The magnitude unit here will only change along superblock boundaries. Whatever the active value of the magnitude unit is
//! at the superblock provided will be used for accruals.
//!
//! \return Allocation Fraction representing Magnitude Unit.
//!
Allocation GetMagnitudeUnit() const
{
Allocation magnitude_unit = Params().GetConsensus().DefaultMagnitudeUnit;

// Before V13 magnitude unit is 1/4.
if (!IsV13Enabled(m_superblock.m_height)) {
return Allocation(1, 4);
}

// Find the current protocol entry value for Magnitude Weight Factor, if it exists.
ProtocolEntryOption protocol_entry = GetProtocolRegistry().TryLastBeforeTimestamp("magnitudeunit", m_superblock.m_timestamp);

// If their is an entry prior or equal in timestamp to the superblock and it is active then set the magnitude unit
// to that value. If the last entry is not active (i.e. deleted), then leave at the default.
if (protocol_entry != nullptr && protocol_entry->m_status == ProtocolEntryStatus::ACTIVE) {
magnitude_unit = Fraction().FromString(protocol_entry->m_value);
}

return magnitude_unit;
}

//!
//! \brief Static version of GetMagnitudeUnit used in Tally class.
//!
//! \param index for which to return the current magnitude unit.
//!
//! \return Allocation fraction representing magnitude unit.
//!
static Allocation GetMagnitudeUnit(CBlockIndex* index)
{
CBlockIndex* sb_index = BlockFinder::FindLatestSuperblock(index);

Allocation magnitude_unit = Params().GetConsensus().DefaultMagnitudeUnit;

// Before V13 magnitude unit is 1/4.
if (!IsV13Enabled(sb_index->nHeight)) {
return Allocation(1, 4);
}

// Find the current protocol entry value for Magnitude Weight Factor, if it exists.
ProtocolEntryOption protocol_entry = GetProtocolRegistry().TryLastBeforeTimestamp("magnitudeunit", sb_index->GetBlockTime());

// If their is an entry prior or equal in timestamp to the superblock and it is active then set the magnitude unit
// to that value. If the last entry is not active (i.e. deleted), then leave at the default.
if (protocol_entry != nullptr && protocol_entry->m_status == ProtocolEntryStatus::ACTIVE) {
magnitude_unit = Fraction().FromString(protocol_entry->m_value);
}

return magnitude_unit;
}

//!
//! \brief Get the magnitude unit factored into the reward calculation.
//!
Expand All @@ -72,15 +137,15 @@ class SnapshotCalculator
//!
//! \return Amount paid per unit of magnitude per day in units of GRC.
//!
static double MagnitudeUnit()
double MagnitudeUnit() const
{
// Superblock-based accrual calculations do not rely on the rolling
// two-week network payment average. Instead, we calculate research
// rewards using the magnitude unit that represents the equilibrium
// quantity of the formula used to determine the magnitude unit for
// the legacy research age accrual calculations.
//
// Where...
// Where (prior to block v13) ...
//
// blocks_per_day = 960
// grc_per_block = 50
Expand All @@ -95,7 +160,8 @@ class SnapshotCalculator
//
// ...rounded-up to 0.25:
//
return static_cast<double>(MAG_UNIT_NUMERATOR) / MAG_UNIT_DENOMINATOR;
// V13+, the magnitude unit can be set by protocol entry.
return GetMagnitudeUnit().ToDouble();
}

//!
Expand Down Expand Up @@ -142,7 +208,7 @@ class SnapshotCalculator
//
const uint64_t base_accrual = accrual_timespan
* CurrentMagnitude(cpid).Scaled()
* MAG_UNIT_NUMERATOR;
* GetMagnitudeUnit().GetNumerator();

// If the accrual calculation will overflow a 64-bit integer, we need
// more bits. Arithmetic with the big integer type is much slower and
Expand All @@ -155,15 +221,15 @@ class SnapshotCalculator
accrual_bn *= COIN;
accrual_bn /= 86400;
accrual_bn /= Magnitude::SCALE_FACTOR;
accrual_bn /= MAG_UNIT_DENOMINATOR;
accrual_bn /= GetMagnitudeUnit().GetDenominator();

accrual = accrual_bn.GetLow64();
} else {
accrual = base_accrual
* COIN
/ 86400
/ Magnitude::SCALE_FACTOR
/ MAG_UNIT_DENOMINATOR;
/ GetMagnitudeUnit().GetDenominator();
}

LogPrint(BCLog::LogFlags::ACCRUAL, "INFO %s: CPID = %s, LastRewardHeight() = %u, accrual_timespan = %" PRId64 ", "
Expand Down Expand Up @@ -263,7 +329,7 @@ class SnapshotAccrualComputer : public IAccrualComputer, SnapshotCalculator
// the amount of accrual that a CPID can collect over two days when the
// CPID achieves the maximum magnitude value supported in a superblock.
//
// Where...
// Where... (for block versions below V13)
//
// max_magnitude = 32767
// magnitude_unit = 0.25
Expand All @@ -272,9 +338,10 @@ class SnapshotAccrualComputer : public IAccrualComputer, SnapshotCalculator
//
// max_magnitude * magnitude_unit * 2 = max_accrual = 16383.5
//
// ...rounded-up to:
// ...rounded-up to 16384.
//
return 16384 * COIN;
// For V13+, the magnitude unit can be set by protocol entry.
return (GetMagnitudeUnit() * 32768 * 2 * COIN).ToCAmount();
}

//!
Expand All @@ -290,7 +357,7 @@ class SnapshotAccrualComputer : public IAccrualComputer, SnapshotCalculator
//!
double MagnitudeUnit() const override
{
return SnapshotCalculator::MagnitudeUnit();
return GetMagnitudeUnit().ToDouble();
}

int64_t AccrualAge() const override
Expand Down
26 changes: 24 additions & 2 deletions src/gridcoin/support/block_finder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,13 @@ CBlockIndex* BlockFinder::FindByMinTime(int64_t time)
}

// The arguments are passed by value on purpose.
CBlockIndex* BlockFinder::FindByMinTimeFromGivenIndex(int64_t time, CBlockIndex* index)
CBlockIndex* BlockFinder::FindByMinTimeFromGivenIndex(int64_t time, CBlockIndex* const index_in)
{
CBlockIndex* index = index_in;

// If no starting index is provided (i.e. second parameter is omitted or nullptr is passed in,
// then start at the Genesis Block. This is in general expensive and should be avoided.
if (!index) {
if (index == nullptr) {
index = pindexGenesisBlock;
}

Expand All @@ -71,3 +73,23 @@ CBlockIndex* BlockFinder::FindByMinTimeFromGivenIndex(int64_t time, CBlockIndex*

return index;
}

CBlockIndex* BlockFinder::FindLatestSuperblock(CBlockIndex* const index_in)
{
CBlockIndex* index = index_in;

// If no input index is provided, start at the head of the chain.
if (index == nullptr) {
index = pindexBest;
}

while (index && index->pprev) {
if (index->IsSuperblock()) {
break;
}

index = index->pprev;
}

return index;
}
9 changes: 8 additions & 1 deletion src/gridcoin/support/block_finder.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,14 @@ class BlockFinder
//! \return CBlockIndex pointing to the youngest block which is not older than \p time, or
//! the head of the chain if it is older than \p time.
//!
static CBlockIndex* FindByMinTimeFromGivenIndex(int64_t time, CBlockIndex* index = nullptr);
static CBlockIndex* FindByMinTimeFromGivenIndex(int64_t time, CBlockIndex* const index_in = nullptr);

//!
//! \brief Find the last superblock at or before the provided index.
//! \param CBlockIndex from where to start.
//! \return CBlockIndex pointing to the block containing the last superblock contract.
//!
static CBlockIndex* FindLatestSuperblock(CBlockIndex * const index_in = nullptr);
};
} // namespace GRC

Expand Down
24 changes: 14 additions & 10 deletions src/gridcoin/tally.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1063,10 +1063,10 @@ CAmount Tally::MaxEmission(const int64_t payment_time)
return NetworkTally::MaxEmission(payment_time) * COIN;
}

double Tally::GetMagnitudeUnit(const CBlockIndex* const pindex)
double Tally::GetMagnitudeUnit(CBlockIndex* const pindex)
{
if (pindex->nVersion >= 11) {
return SnapshotCalculator::MagnitudeUnit();
return SnapshotCalculator::GetMagnitudeUnit(pindex).ToDouble();
}

return g_network_tally.GetMagnitudeUnit(pindex->nTime);
Expand Down Expand Up @@ -1158,7 +1158,9 @@ CAmount Tally::GetNewbieSuperblockAccrualCorrection(const Cpid& cpid, const Supe
const auto tally_accrual_period = [&](
const int64_t low_time,
const int64_t high_time,
const GRC::Magnitude magnitude)
const GRC::Magnitude magnitude,
const Allocation magnitude_unit,
CAmount max_reward)
{
int64_t time_interval = high_time - low_time;

Expand All @@ -1175,7 +1177,7 @@ CAmount Tally::GetNewbieSuperblockAccrualCorrection(const Cpid& cpid, const Supe
// correctly in the bignumber calculations.
const uint64_t base_accrual = abs_time_interval
* magnitude.Scaled()
* MAG_UNIT_NUMERATOR;
* magnitude_unit.GetNumerator();

int64_t period = 0;

Expand All @@ -1184,7 +1186,7 @@ CAmount Tally::GetNewbieSuperblockAccrualCorrection(const Cpid& cpid, const Supe
accrual_bn *= COIN;
accrual_bn /= 86400;
accrual_bn /= Magnitude::SCALE_FACTOR;
accrual_bn /= MAG_UNIT_DENOMINATOR;
accrual_bn /= magnitude_unit.GetDenominator();

period = accrual_bn.GetLow64() * (int64_t) sign;
}
Expand All @@ -1194,14 +1196,11 @@ CAmount Tally::GetNewbieSuperblockAccrualCorrection(const Cpid& cpid, const Supe
* COIN
/ 86400
/ Magnitude::SCALE_FACTOR
/ MAG_UNIT_DENOMINATOR;
/ magnitude_unit.GetDenominator();
}

accrual += period;

// TODO: Change this to refer to MaxReward() from the snapshot computer.
int64_t max_reward = 16384 * COIN;

if (accrual > max_reward)
{
int64_t overage = accrual - max_reward;
Expand Down Expand Up @@ -1267,7 +1266,12 @@ CAmount Tally::GetNewbieSuperblockAccrualCorrection(const Cpid& cpid, const Supe
// Stop the accrual when we get to a superblock that is before the beacon advertisement.
if (pindex->nTime < beacon_ptr->m_timestamp) break;

CAmount period = tally_accrual_period(pindex->nTime, pindex_high->nTime, magnitude);
// We are only going to use the accrual computer here for the magnitude unit and max_reward.
AccrualComputer computer = GetSnapshotComputer(cpid, pindex->GetBlockTime(), pindex);

int64_t max_reward = computer->MaxReward();

CAmount period = tally_accrual_period(pindex->nTime, pindex_high->nTime, magnitude, computer->MagnitudeUnit(), max_reward);

LogPrint(BCLog::LogFlags::ACCRUAL, "INFO %s: period_num = %u, "
"low height = %i, high height = %u, magnitude at low height SB = %f, "
Expand Down
2 changes: 1 addition & 1 deletion src/gridcoin/tally.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class Tally
//!
//! \return Current magnitude unit adjusted for the specified block.
//!
static double GetMagnitudeUnit(const CBlockIndex* const pindex);
static double GetMagnitudeUnit(CBlockIndex * const pindex);

//!
//! \brief Get a traversable object for the research accounts stored in
Expand Down
4 changes: 2 additions & 2 deletions src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ UniValue MRCToJson(const GRC::MRC& mrc) {
return json;
}

UniValue ClaimToJson(const GRC::Claim& claim, const CBlockIndex* const pindex)
UniValue ClaimToJson(const GRC::Claim& claim, CBlockIndex* pindex)
{
UniValue json(UniValue::VOBJ);

Expand Down Expand Up @@ -155,7 +155,7 @@ UniValue SuperblockToJson(const GRC::SuperblockPtr& superblock)
return SuperblockToJson(*superblock);
}

UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
UniValue blockToJSON(const CBlock& block, CBlockIndex* blockindex, bool fPrintTransactionDetail)
{
UniValue result(UniValue::VOBJ);

Expand Down
Loading

0 comments on commit 6c47db9

Please sign in to comment.