// Check for negative or overflow output values
int64 nValueOut = 0;
- for (int i = (IsCoinStake()? 1 : 0); i < vout.size(); i++)
+ for (int i = 0; i < vout.size(); i++)
{
const CTxOut& txout = vout[i];
+ if (txout.IsEmpty() && (!IsCoinBase()) && (!IsCoinStake()))
+ return DoS(100, error("CTransaction::CheckTransaction() : txout empty for user transaction"));
if (txout.nValue < 0)
return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue negative"));
if (txout.nValue > MAX_MONEY)
// ppcoin: fees are not collected by miners as in bitcoin
// ppcoin: fees are destroyed to compensate the entire network
- if (vtx[0].GetValueOut() > GetProofOfWorkReward(nBits))
+ if (IsProofOfWork() && vtx[0].GetValueOut() > GetProofOfWorkReward(nBits))
return false;
if (fDebug && GetBoolArg("-printcreation"))
printf("ConnectBlock() : destroy=%s nFees=%"PRI64d"\n", FormatMoney(nFees).c_str(), nFees);
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[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"));
if (pwallet->CreateCoinStake(txNew.vout[0].scriptPubKey, pblock->nBits, txCoinStake))
{
pblock->vtx.push_back(txCoinStake);
+ pblock->vtx[0].vout[0].SetEmpty();
break;
}
}
return (nValue == -1);
}
- bool IsCoinStake() const
+ bool SetEmpty()
+ {
+ nValue = 0;
+ scriptPubKey.clear();
+ }
+
+ bool IsEmpty() const
{
return (nValue == 0 && scriptPubKey.empty());
}
std::string ToString() const
{
- if (IsCoinStake()) return "CTxOut(coinstake)";
+ if (IsEmpty()) return "CTxOut(empty)";
if (scriptPubKey.size() < 6)
return "CTxOut(error)";
return strprintf("CTxOut(nValue=%s, scriptPubKey=%s)", FormatMoney(nValue).c_str(), scriptPubKey.ToString().substr(0,30).c_str());
bool IsCoinStake() const
{
// ppcoin: the coin stake transaction is marked with the first output empty
- return (vout.size() == 2 && vout[0].IsCoinStake());
+ return ((!IsCoinBase()) && vout.size() == 2 && vout[0].IsEmpty());
}
int GetSigOpCount() const
std::string ToString() const
{
std::string str;
- str += strprintf("CTransaction(hash=%s, nTime=%d, ver=%d, vin.size=%d, vout.size=%d, nLockTime=%d)\n",
+ str += IsCoinBase()? "Coinbase" : (IsCoinStake()? "Coinstake" : "CTransaction");
+ str += strprintf("(hash=%s, nTime=%d, ver=%d, vin.size=%d, vout.size=%d, nLockTime=%d)\n",
GetHash().ToString().substr(0,10).c_str(),
nTime,
nVersion,
bool SignBlock(const CKeyStore& keystore)
{
std::vector<std::pair<opcodetype, valtype> > vSolution;
+ const CTxOut& txout = IsProofOfStake()? vtx[1].vout[1] : vtx[0].vout[0];
- if (!Solver(vtx[0].vout[0].scriptPubKey, vSolution))
+ if (!Solver(txout.scriptPubKey, vSolution))
return false;
BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{
return vchBlockSig.empty();
std::vector<std::pair<opcodetype, valtype> > vSolution;
+ const CTxOut& txout = IsProofOfStake()? vtx[1].vout[1] : vtx[0].vout[0];
- if (!Solver(vtx[0].vout[0].scriptPubKey, vSolution))
+ if (!Solver(txout.scriptPubKey, vSolution))
return false;
BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{