Jutarul (OP)
Donator
Legendary
Offline
Activity: 994
Merit: 1000
|
|
September 12, 2012, 11:52:34 PM |
|
I am currently digging through the ppcoin source code to understand the reward mechanism. Stake rewards are calculated based on the following equation (code below) CENT=10000; int64 nSubsidy = nCoinAge * 33 / (365 * 33 + * CENT;
Thus a CoinAge of 30000 (1000PPC at 30 days) provides a reward of about 0.8PPC (which corresponds to about 0.08% interest per month or about 1% per year) Questions: 1) what the purpose of the 33? 2) Is there another limit to the money generation I overlooked? Right now it looks like PPCoin is inflationary in nature (1% per year). 3) What is the rationale for the choice for rewards? Why 1% and not 0.5% return on stake per year? Thanks to whomever has answers. // ppcoin: miner's coin stake is rewarded based on coin age spent (coin-days) int64 GetProofOfStakeReward(int64 nCoinAge) { static int64 nRewardCoinYear = CENT; // creation amount per coin-year int64 nSubsidy = nCoinAge * 33 / (365 * 33 + 8) * nRewardCoinYear; if (fDebug && GetBoolArg("-printcreation")) printf("GetProofOfStakeReward(): create=%s nCoinAge=%"PRI64d"\n", FormatMoney(nSubsidy).c_str(), nCoinAge); return nSubsidy; }
|
|
|
|
Sunny King
Legendary
Offline
Activity: 1205
Merit: 1010
|
|
September 13, 2012, 12:28:52 AM |
|
I am currently digging through the ppcoin source code to understand the reward mechanism. Stake rewards are calculated based on the following equation (code below) CENT=10000; int64 nSubsidy = nCoinAge * 33 / (365 * 33 + * CENT;
Thus a CoinAge of 30000 (1000PPC at 30 days) provides a reward of about 0.8PPC (which corresponds to about 0.08% interest per month or about 1% per year) Questions: 1) what the purpose of the 33? 2) Is there another limit to the money generation I overlooked? Right now it looks like PPCoin is inflationary in nature (1% per year). 3) What is the rationale for the choice for rewards? Why 1% and not 0.5% return on stake per year? Thanks to whomever has answers. // ppcoin: miner's coin stake is rewarded based on coin age spent (coin-days) int64 GetProofOfStakeReward(int64 nCoinAge) { static int64 nRewardCoinYear = CENT; // creation amount per coin-year int64 nSubsidy = nCoinAge * 33 / (365 * 33 + 8) * nRewardCoinYear; if (fDebug && GetBoolArg("-printcreation")) printf("GetProofOfStakeReward(): create=%s nCoinAge=%"PRI64d"\n", FormatMoney(nSubsidy).c_str(), nCoinAge); return nSubsidy; }
Good to see people researching the code. 365+8/33 is an approximation of number of days in a year. 1% is chosen as it's a round number and low inflation rate. Not all coin age would generate block so the actual rate is likely lower than 1%. Following info is from our FAQ: Is there a cap on total money supply like Bitcoin's 21 million? There is no hard cap other than a 2 billion coin max put into the code for now. But that should not be interpreted as an approachable cap, as it might never get anywhere close to that. It should not be considered a hard cap either as it may get lifted but that's likely not needed in a very very long time. Due to the nature of the mint rate design it's not possible to predict a final limit as it depends heavily on market participation, as well as the influences between proof-of-stake minting and fee destruction (there may not even be a mathematical limit if minting continues to outpace fee destruction). What we do know is that the proof-of-work minting would slow down exponentially according to Moore's Law (we are aware that Moore's Law eventually would stop to apply), and proof-of-stake minting introduces at most 1% annual inflation. So generally speaking it is still a very low future-inflation design comparable to Bitcoin. In 0.2 release a 'moneysupply' stat is included in the getinfo output so everyone can see how many coins are in the market.
|
|
|
|
Jutarul (OP)
Donator
Legendary
Offline
Activity: 994
Merit: 1000
|
|
September 13, 2012, 12:44:58 AM |
|
Good to see people researching the code. 365+8/33 is an approximation of number of days in a year.
Ah. good. So you're accounting for the additional day every 4 years... 1% is chosen as it's a round number and low inflation rate. Not all coin age would generate block so the actual rate is likely lower than 1%.
Makes sense. So 1% seems to be the "worst" case. Following info is from our FAQ: Is there a cap on total money supply like Bitcoin's 21 million? ... There is no hard cap other than a 2 billion coin max put into the code for now. But that should not be interpreted as an approachable cap, ... (there may not even be a mathematical limit if minting continues to outpace fee destruction). ...
Thanks for pointing that out. So the transaction fee in ppcoin works different than in bitcoin? In bitcoin its voluntary and is redistributed to the miner as an incentive. Based on what you're suggesting is that ppcoin's transaction fees actually affect the money supply!
|
|
|
|
Sunny King
Legendary
Offline
Activity: 1205
Merit: 1010
|
|
September 13, 2012, 01:08:50 AM |
|
Thanks for pointing that out. So the transaction fee in ppcoin works different than in bitcoin? In bitcoin its voluntary and is redistributed to the miner as an incentive. Based on what you're suggesting is that ppcoin's transaction fees actually affect the money supply!
Yes. Transaction fees are destroyed and act as a deflationary force in ppcoin.
|
|
|
|
Jutarul (OP)
Donator
Legendary
Offline
Activity: 994
Merit: 1000
|
|
September 13, 2012, 01:36:50 AM |
|
Thanks for pointing that out. So the transaction fee in ppcoin works different than in bitcoin? In bitcoin its voluntary and is redistributed to the miner as an incentive. Based on what you're suggesting is that ppcoin's transaction fees actually affect the money supply!
Yes. Transaction fees are destroyed and act as a deflationary force in ppcoin. Wow. That gives it a totally different dynamic! Would be interesting to determine the half-time of the money.. that is the number of transactions necessary that it only has half of the nominal value.
|
|
|
|
Etlase2
|
|
September 13, 2012, 01:48:42 AM |
|
In all honesty, int64 nSubsidy = nCoinAge * 33 / (365 * 33 + 8) * nRewardCoinYear; this is some scary code. Is there something I am missing, or is compiler-dependent rounding part of your network protocol? This may work in C++ across all implementations, may, assuming they all adhere to the same standard, which is not a given. This may work in java or other implementations, but there is no guarantee. This may work in future programming languages. But all in all it is a not a good design decision. It has Y2K written all over it.
|
|
|
|
markm
Legendary
Offline
Activity: 3010
Merit: 1121
|
|
September 13, 2012, 02:17:52 AM |
|
In all honesty, int64 nSubsidy = nCoinAge * 33 / (365 * 33 + 8) * nRewardCoinYear; this is some scary code. Is there something I am missing, or is compiler-dependent rounding part of your network protocol? This may work in C++ across all implementations, may, assuming they all adhere to the same standard, which is not a given. This may work in java or other implementations, but there is no guarantee. This may work in future programming languages. But all in all it is a not a good design decision. It has Y2K written all over it. Since the variables are all presumably integers of a known number of bits, how is integer arithmetic compiler-dependent? That sounds like a really bad compiler design more than a code problem? tl;dr integers do not round, they truncate... -MarkM-
|
|
|
|
Jutarul (OP)
Donator
Legendary
Offline
Activity: 994
Merit: 1000
|
|
September 13, 2012, 02:22:01 AM |
|
In all honesty, int64 nSubsidy = nCoinAge * 33 / (365 * 33 + 8) * nRewardCoinYear; this is some scary code. Is there something I am missing, or is compiler-dependent rounding part of your network protocol? This may work in C++ across all implementations, may, assuming they all adhere to the same standard, which is not a given. This may work in java or other implementations, but there is no guarantee. This may work in future programming languages. But all in all it is a not a good design decision. It has Y2K written all over it. lol. good catch. As far as I understand C++, it is not doing any "rounding", because it never is converted to a different datatype. (as opposed to e.g. python) But what is problematic is the order by which the expression is evaluated. If the convention would be simply from right to left, then nSubsidy would always yield 0. proof: (365 * 33 + 8) * 10000 = 120530000 33/120530000 = 0 nCoinAge * 0 = 0 nSubsidy = 0 However, most compilers have operator associativity left to right, which yields the correct value IN THIS CASE.
|
|
|
|
markm
Legendary
Offline
Activity: 3010
Merit: 1121
|
|
September 13, 2012, 02:41:24 AM |
|
However, most compilers have operator associativity left to right, which yields the correct value IN THIS CASE.
Most compilers? That associativity is part of the language itself isn't it? So that a compiler that does not do it that way would be a different language's compiler. So again, back to it being a problem compiler rather than problem code. Could run into the problem though maybe if someone who does not bother to pay close attention to the associativity of the language they are porting from tries to port it though I suppose. -MarkM-
|
|
|
|
Jutarul (OP)
Donator
Legendary
Offline
Activity: 994
Merit: 1000
|
|
September 13, 2012, 03:05:43 AM |
|
Most compilers? That associativity is part of the language itself isn't it? So that a compiler that does not do it that way would be a different language's compiler. So again, back to it being a problem compiler rather than problem code.
Could run into the problem though maybe if someone who does not bother to pay close attention to the associativity of the language they are porting from tries to port it though I suppose.
-MarkM-
You're right. My bad. So problem will occur when somebody wants to port this or runs into a compiler bug. However, back to the original problem. I don't think the code works as INTENDED. E.g. CoinAge=365 -> nSubsidy= 0. CoinAge=366 -> nSubsidy= 10000. Which is due to operator associativity... I think the intent was: CoinAge=365 -> nSubsidy= 9993 CoinAge=366 -> nSubsidy= 10020 which translates into code: int64 nSubsidy = (nRewardCoinYear * nCoinAge * 33) / (365 * 33 + 8) ;
|
|
|
|
Etlase2
|
|
September 13, 2012, 04:36:26 AM Last edit: September 13, 2012, 05:33:22 AM by Etlase2 |
|
So again, back to it being a problem compiler rather than problem code. Not an associativity problem that I brought up, but indeed a rounding problem. When you get 1258.83752 or whatever there is no set standard across all implementations that says the number should be 1258 or 1259. C did not standardize this until many, many years after it was originally designed. If you're familiar with a company called Microsoft and a software called Visual Studio, you'll be perhaps not so surprised to know that not everybody complies with ANSI C standards with their compilers. And again, there is nothing that says this will be the same standard for other languages. edit: more derpage
|
|
|
|
markm
Legendary
Offline
Activity: 3010
Merit: 1121
|
|
September 13, 2012, 04:48:13 AM |
|
There is no rounding if all the variables are integers. There is nothing to round as there are no decimals in the first place.
In fact it is the processor hardware that does this I think, only some language that does not distinguish integers from reals could even get around it maybe. In C you'd have to cast to real somewhere in there or something like that.
Maybe you are imagining that the eight decimals you see displayed imply decimals exist in the code? The code uses integers, the display routines stick a decimal in before the last eight digits of the actual integer value used internally.
-MarkM-
|
|
|
|
Etlase2
|
|
September 13, 2012, 05:04:21 AM Last edit: September 13, 2012, 08:01:34 AM by Etlase2 |
|
There is no rounding if all the variables are integers. There is nothing to round as there are no decimals in the first place. You know what, I derped on this. This was a problem in the past if one of the operands was negative. The behavior could be truncate closest to zero, or be the smallest integer (e.g. -5.5 would be -6). This used to be implementation-specific behavior in C and does allude to there being more going on than just what the processor decides or that it is universally truncated. But in unsigned ints I don't believe it was ever an issue and I was mistaken there. Some old crusty nugget of misremembered information led me astray. The original formula is apt to lose precision (if it was correct) for no particular reason though.
|
|
|
|
AndyRossy
|
|
September 13, 2012, 09:02:15 AM |
|
// int64 nSubsidy = nCoinAge * 33 / (365 * 33 + 8) * nRewardCoinYear; int64 nCoEff = 0.00273790757487762; int64 nSubsidy = nCoinAge * nRewardCoinYear * nCoEff ;
Just calc the division yourself? Next.
|
|
|
|
Jutarul (OP)
Donator
Legendary
Offline
Activity: 994
Merit: 1000
|
|
September 13, 2012, 09:07:47 AM |
|
int64 nCoEff = 0.00273790757487762;
lol. I pretend I didn't see that
|
|
|
|
AndyRossy
|
|
September 13, 2012, 09:17:32 AM |
|
int64 nCoEff = 0.00273790757487762;
lol. I pretend I didn't see that oops xD even worse, my var name woooop good morning world.
|
|
|
|
|