if (txout.IsEmpty() && !IsCoinBase() && !IsCoinStake())
return DoS(100, error("CTransaction::CheckTransaction() : txout empty for user transaction"));
- // ppcoin: enforce minimum output amount
- if ((!txout.IsEmpty()) && txout.nValue < MIN_TXOUT_AMOUNT)
+ // NovaCoin: enforce minimum output amount for user transactions
+ // (and for all transactions until 20 Sep 2013)
+ if ((!IsCoinBase() || nTime < CHAINCHECKS_SWITCH_TIME)
+ && (!txout.IsEmpty()) && txout.nValue < MIN_TXOUT_AMOUNT)
return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue below minimum"));
if (txout.nValue > MAX_MONEY)
if (IsCoinBase())
{
if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100)
- return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size"));
+ return DoS(100, error("CTransaction::CheckTransaction() : coinbase script size is invalid"));
}
else
{
}
int64 nSubsidy = bnUpperBound.getuint64();
+
nSubsidy = (nSubsidy / CENT) * CENT;
if (fDebug && GetBoolArg("-printcreation"))
printf("GetProofOfWorkReward() : create=%s nBits=0x%08x nSubsidy=%"PRI64d"\n", FormatMoney(nSubsidy).c_str(), nBits, nSubsidy);
if (vtx[i].IsCoinBase())
return DoS(100, error("CheckBlock() : more than one coinbase"));
- // ppcoin: only the second transaction can be the optional coinstake
- for (unsigned int i = 2; i < vtx.size(); i++)
- if (vtx[i].IsCoinStake())
- return DoS(100, error("CheckBlock() : coinstake in wrong position"));
-
- // ppcoin: coinbase output should be empty if proof-of-stake block
- if (IsProofOfStake() && (vtx[0].vout.size() != 1 || !vtx[0].vout[0].IsEmpty()))
- return error("CheckBlock() : coinbase output not empty for proof-of-stake block");
-
// Check coinbase timestamp
if (GetBlockTime() > (int64)vtx[0].nTime + nMaxClockDrift)
return DoS(50, error("CheckBlock() : coinbase timestamp is too early"));
- // Check coinstake timestamp
- if (IsProofOfStake() && !CheckCoinStakeTimestamp(GetBlockTime(), (int64)vtx[1].nTime))
- return DoS(50, error("CheckBlock() : coinstake timestamp violation nTimeBlock=%"PRI64d" nTimeTx=%u", GetBlockTime(), vtx[1].nTime));
+ if (IsProofOfStake())
+ {
+ // ppcoin: 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");
+
+ // Second transaction must be coinstake, the rest must not be
+ if (vtx.empty() || !vtx[1].IsCoinStake())
+ return DoS(100, error("CheckBlock() : second tx is not coinstake"));
+ for (unsigned int i = 2; i < vtx.size(); i++)
+ if (vtx[i].IsCoinStake())
+ return DoS(100, error("CheckBlock() : more than one coinstake"));
- // Check coinbase reward
- if (vtx[0].GetValueOut() > (IsProofOfWork()? (GetProofOfWorkReward(nBits) - vtx[0].GetMinFee() + MIN_TX_FEE) : 0))
- return DoS(50, error("CheckBlock() : coinbase reward exceeded %s > %s",
+ // Check coinstake timestamp
+ if (!CheckCoinStakeTimestamp(GetBlockTime(), (int64)vtx[1].nTime))
+ return DoS(50, error("CheckBlock() : coinstake timestamp violation nTimeBlock=%"PRI64d" nTimeTx=%u", GetBlockTime(), vtx[1].nTime));
+ }
+ else
+ {
+ // Coinbase fee paid until 20 Sep 2013
+ int64 nFee = GetBlockTime() < CHAINCHECKS_SWITCH_TIME ? vtx[0].GetMinFee() - MIN_TX_FEE : 0;
+
+ // 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(IsProofOfWork()? GetProofOfWorkReward(nBits) : 0).c_str()));
+ FormatMoney(GetProofOfWorkReward(nBits) - nFee).c_str()));
+ }
// Check transactions
BOOST_FOREACH(const CTransaction& tx, vtx)