From 7f210b1b2150e1eba383e0b147ee6008be38143a Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Sat, 26 Oct 2024 19:32:02 -0400 Subject: [PATCH] Implement GRC::GetAvgNetworkWeight This separates out the calculation of network weight from nBits contained in GetActiveNetworkWeight and extends it to take a starting and ending index to compute the average over an interval. --- src/gridcoin/staking/difficulty.cpp | 56 +++++++++++++++++++++++++++++ src/gridcoin/staking/difficulty.h | 19 ++++++++++ src/gridcoin/voting/registry.cpp | 8 +---- 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/src/gridcoin/staking/difficulty.cpp b/src/gridcoin/staking/difficulty.cpp index b2cb8f097a..bbd980e35e 100644 --- a/src/gridcoin/staking/difficulty.cpp +++ b/src/gridcoin/staking/difficulty.cpp @@ -270,6 +270,62 @@ double GRC::GetEstimatedNetworkWeight(unsigned int nPoSInterval) return result; } +uint64_t GRC::GetAvgNetworkWeight(CBlockIndex* index_start, CBlockIndex* index_end) +{ + auto block_net_weight = [](CBlockIndex* index) + { + arith_uint256 target; + + target.SetCompact(index->nBits); + + return ~arith_uint256() / arith_uint256(450) / target * arith_uint256(COIN); + }; + + // These conditionals are ordered so that the no argument case quickly evaluates to the net weight of the current block. + if (index_end == nullptr) { + if (index_start == nullptr) { + return block_net_weight(pindexBest).GetLow64(); + } else { + return block_net_weight(index_start).GetLow64(); + } + } else { + if (index_start != nullptr) { + { + CBlockIndex* index; + arith_uint256 weight_sum; + unsigned int block_count; + + // If we are here, both index_start and index_end are not nullptrs. + + if (!index_start->IsInMainChain()) { + throw std::invalid_argument("Specified start index is not in main chain."); + } + + if (!index_end->IsInMainChain()) { + throw std::invalid_argument("Specified end index is not in main chain."); + } + + if (index_start->nHeight >= index_end-> nHeight) { + throw std::invalid_argument("End index if specified must be at a higher height than start index."); + } + + for (index = index_start, block_count = 0; index != index_end; index = index->pnext, ++block_count) + { + weight_sum += block_net_weight(index); + } + + // Get last block for inclusive interval + weight_sum += block_net_weight(index->pnext); + ++block_count; + + return (weight_sum / arith_uint256(block_count)).GetLow64(); + } + } else { + throw std::invalid_argument("End index was specified with start index = nullptr."); + } + } +} + double GRC::GetEstimatedTimetoStake(bool ignore_staking_status, double dDiff, double dConfidence) { /* diff --git a/src/gridcoin/staking/difficulty.h b/src/gridcoin/staking/difficulty.h index a002d8ed90..6ecbdd8337 100644 --- a/src/gridcoin/staking/difficulty.h +++ b/src/gridcoin/staking/difficulty.h @@ -6,6 +6,7 @@ #ifndef GRIDCOIN_STAKING_DIFFICULTY_H #define GRIDCOIN_STAKING_DIFFICULTY_H +#include class CBlockIndex; class CWallet; #include @@ -26,6 +27,24 @@ double GetSmoothedDifficulty(int64_t nStakeableBalance); uint64_t GetStakeWeight(const CWallet& wallet); double GetEstimatedNetworkWeight(unsigned int nPoSInterval = 40); + +//! +//! \brief This returns the precise average network weight in units of GRC as a 64 bit unsigned integer. The starting index and the +//! ending index are defaulted to nullptr if not provided. If neither is provided, the network weight for the current (best) block +//! will be returned. If only the starting index pointer is provided, the network weight of that block will be returned. If both +//! are provided, the network weight average will be returned over the interval of blocks inclusive of both start and end. Both +//! indexes, if specified, must be in the main chain. +//! +//! Please refer to https://gridcoin.us/assets/docs/grc-bluepaper-section-1.pdf equations 1 and 16 and footnote 5. +//! This method of computing net_weight is from first principles using the target from the nBits representation +//! recorded in the index, rather than the GetEstimatedNetworkWeight() function, which uses double fp arithmetic. +//! +//! \param index_start The CBlockIndex pointer to the starting index with which to take the average. Note that this is inclusive. +//! \param index_end The BClockIndex pointer to the ending index with which to take the average. Note that this is inclusive. +//! +//! \return uint64_t of the average network weight in Halford units. +//! +uint64_t GetAvgNetworkWeight(CBlockIndex* index_start = nullptr, CBlockIndex* index_end = nullptr); double GetEstimatedTimetoStake(bool ignore_staking_status = false, double dDiff = 0.0, double dConfidence = DEFAULT_ETTS_CONFIDENCE); } // namespace GRC diff --git a/src/gridcoin/voting/registry.cpp b/src/gridcoin/voting/registry.cpp index bbc873c501..66cf3a3336 100644 --- a/src/gridcoin/voting/registry.cpp +++ b/src/gridcoin/voting/registry.cpp @@ -657,13 +657,7 @@ std::optional PollReference::GetActiveVoteWeight(const PollResultOption } } - // Please refer to https://gridcoin.us/assets/docs/grc-bluepaper-section-1.pdf equations 1 and 16 and footnote 5. - // This method of computing net_weight is from first principles using the target from the nBits representation - // recorded in the index, rather than the GetEstimatedNetworkWeight() function, which uses double fp arithmetic. - arith_uint256 target; - target.SetCompact(pindex->nBits); - - arith_uint256 net_weight = ~arith_uint256() / arith_uint256(450) / target * arith_uint256(COIN); + arith_uint256 net_weight = GetAvgNetworkWeight(pindex); arith_uint256 money_supply = pindex->nMoneySupply;