When uint64 nCoinAge becomes too large, it can cause int64 nSubsidy to overflow into a negative value, then because negative rewards are generally not accepteed, this prevents that input from ever staking.
(nCoinAge being unsigned, and nSubsidy being signed)
the basic, and truncated, code in question is
bool CTransaction::GetCoinAge(CTxDB& txdb, uint64_t& nCoinAge) const
{
CBigNum bnCentSecond = 0; // coin age in the unit of cent-seconds
nCoinAge = 0;
int64_t nValueIn = txPrev.vout[txin.prevout.n].nValue;
bnCentSecond += CBigNum(nValueIn) * (nTime-txPrev.nTime) / CENT;
CBigNum bnCoinDay = bnCentSecond * CENT / COIN / (24 * 60 * 60);
nCoinAge = bnCoinDay.getuint64();
}
static const int64_t COIN_YEAR_REWARD = 1000 * CENT;
int64_t GetProofOfStakeReward(int nHeight, int64_t nCoinAge, int64_t nFees)
{
int64_t nSubsidy = nCoinAge * COIN_YEAR_REWARD * 33 / (365 * 33 + 8);
return nSubsidy + nFees;
}
I'm pondering different options to "fix" this.
1. modify nCoinAge
- it were based on CoinYear rather than CoinDay, the possibility would be diminished but would still exist.
- if it were given an upper limit then it would be possible for nSubsidy to never exceed upper limit of being int64.
2. modify nSubsidy
- ignoring the -ve and getting absolute value as is , not sure of correct usage but something along lines of
int64_t nSubsidy = abs(nCoinAge * COIN_YEAR_REWARD * 33 / (365 * 33 + 8));
- does it even need to be uint64? give it more bits? eg converting to CBigNum which is 256 bit?
.
another variable of interest in this is MAX_MONEY, as it defines maximum possible size of input, it then sets some idea where nCoinAge becomes an issue
maximum value of int64 / MAX_MONEY = age at which larges possible input will cause problems
static const int64_t MAX_MONEY = 700000000 * COIN;
.
other possibilities include auto splitting the input if it is obviously an issue.
when nCoinAge of the input exceeds some value, then split it.
this would be interesting because it's only a client update, where the others seem to requiring forks.