// miner's coin stake reward based on nBits and coin age spent (coin-days)
int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTime, bool bCoinYearOnly)
{
- int64 nRewardCoinYear, nSubsidy;
+ int64 nRewardCoinYear, nSubsidy, nSubsidyLimit = 10 * COIN;
if(fTestNet || nTime > STAKE_SWITCH_TIME)
{
// Human readable form: nRewardCoinYear = 1 / (posdiff ^ 1/6)
//
- bnMidPart = bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnTargetLimit;
- bnRewardPart = bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnTarget;
+ bnMidPart = bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue;
+ bnRewardPart = bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit;
}
else
{
// Human readable form: nRewardCoinYear = 1 / (posdiff ^ 1/3)
//
- bnMidPart = bnMidValue * bnMidValue * bnMidValue * bnTargetLimit;
- bnRewardPart = bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnTarget;
+ bnMidPart = bnMidValue * bnMidValue * bnMidValue;
+ bnRewardPart = bnRewardCoinYearLimit * bnRewardCoinYearLimit * bnRewardCoinYearLimit;
}
- if (bnMidPart > bnRewardPart)
+ if (bnMidPart * bnTargetLimit > bnRewardPart * bnTarget)
bnUpperBound = bnMidValue;
else
bnLowerBound = bnMidValue;
else
nSubsidy = nCoinAge * nRewardCoinYear * 33 / (365 * 33 + 8);
+ // Set reasonable reward limit for large inputs since 20 Oct 2013
+ //
+ // This will stimulate large holders to use smaller inputs, that's good for the network protection
+ if(fTestNet || STAKECURVE_SWITCH_TIME < nTime)
+ {
+ if (fDebug && GetBoolArg("-printcreation") && nSubsidyLimit < nSubsidy)
+ printf("GetProofOfStakeReward(): %s is greater than %s, coinstake reward will be truncated\n", FormatMoney(nSubsidy).c_str(), FormatMoney(nSubsidyLimit).c_str());
+
+ nSubsidy = min(nSubsidy, nSubsidyLimit);
+ }
+
if (fDebug && GetBoolArg("-printcreation"))
printf("GetProofOfStakeReward(): create=%s nCoinAge=%"PRI64d" nBits=%d\n", FormatMoney(nSubsidy).c_str(), nCoinAge, nBits);
return nSubsidy;
uint64 nCoinAge;
if (!GetCoinAge(txdb, nCoinAge))
return error("ConnectInputs() : %s unable to get coin age for coinstake", GetHash().ToString().substr(0,10).c_str());
+
int64 nStakeReward = GetValueOut() - nValueIn;
- if (nStakeReward > GetProofOfStakeReward(nCoinAge, pindexBlock->nBits, nTime) - GetMinFee() + MIN_TX_FEE)
- return DoS(100, error("ConnectInputs() : %s stake reward exceeded", GetHash().ToString().substr(0,10).c_str()));
+ int64 nCalculatedStakeReward = GetProofOfStakeReward(nCoinAge, pindexBlock->nBits, nTime) - GetMinFee() + MIN_TX_FEE;
+
+ if (nStakeReward > nCalculatedStakeReward)
+ return DoS(100, error("ConnectInputs() : coinstake pays too much(actual=%"PRI64d" vs calculated=%"PRI64d")", nStakeReward, nCalculatedStakeReward));
}
else
{
if (IsProofOfStake())
{
- // ppcoin: coinbase output should be empty if proof-of-stake block
+ // Coinbase output should be empty if proof-of-stake block
if (vtx[0].vout.size() != 1 || !vtx[0].vout[0].IsEmpty())
- return error("CheckBlock() : coinbase output not empty for proof-of-stake block");
+ return DoS(100, error("CheckBlock() : coinbase output not empty for proof-of-stake block"));
// Second transaction must be coinstake, the rest must not be
if (vtx.empty() || !vtx[1].IsCoinStake())
// Check coinbase reward
if (vtx[0].GetValueOut() > (GetProofOfWorkReward(nBits) - nFee))
- return DoS(50, error("CheckBlock() : coinbase reward exceeded %s > %s",
- FormatMoney(vtx[0].GetValueOut()).c_str(),
- FormatMoney(GetProofOfWorkReward(nBits) - nFee).c_str()));
+ return DoS(50, error("CheckBlock() : coinbase reward exceeded (actual=%"PRI64d" vs calculated=%"PRI64d")",
+ vtx[0].GetValueOut(),
+ GetProofOfWorkReward(nBits) - nFee));
}
// Check transactions
}
}
- // Reject block.nVersion < 3 blocks since 95% threshold on mainNet and always on testNet:
- if (nVersion < 3 && ((!fTestNet && nHeight > 14060) || (fTestNet && nHeight > 0)))
- return error("CheckBlock() : rejected nVersion < 3 block");
-
// Enforce rule that the coinbase starts with serialized block height
CScript expect = CScript() << nHeight;
if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin()))