From 4ffa5951a45683c8609deca0f69fdabfc86697df Mon Sep 17 00:00:00 2001 From: Sunny King Date: Fri, 24 Aug 2012 20:14:01 +0100 Subject: [PATCH] PPCoin: Allow multiple outputs for coinbase and coinstake Upgrade requirements: upgrade with deadline, possible fork --- src/main.cpp | 4 ++-- src/main.h | 4 ++-- src/wallet.cpp | 42 ++++++++++++++++++++++++++++++------------ 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 2be1fef..2b0bef8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1232,7 +1232,7 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, MapPrevTx inputs, 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)) + if (nStakeReward > GetProofOfStakeReward(nCoinAge) - GetMinFee() + MIN_TX_FEE) return DoS(100, error("ConnectInputs() : %s stake reward exceeded", GetHash().ToString().substr(0,10).c_str())); } else @@ -1908,7 +1908,7 @@ bool CBlock::CheckBlock() const return DoS(50, error("CheckBlock() : coinstake timestamp is too early")); // Check coinbase reward - if (vtx[0].GetValueOut() > (IsProofOfWork()? GetProofOfWorkReward(nBits) : 0)) + if (vtx[0].GetValueOut() > (IsProofOfWork()? (GetProofOfWorkReward(nBits) - vtx[0].GetMinFee() + MIN_TX_FEE) : 0)) return DoS(50, error("CheckBlock() : coinbase reward exceeded %s > %s", FormatMoney(vtx[0].GetValueOut()).c_str(), FormatMoney(IsProofOfWork()? GetProofOfWorkReward(nBits) : 0).c_str())); diff --git a/src/main.h b/src/main.h index 43a8b70..5232a93 100644 --- a/src/main.h +++ b/src/main.h @@ -502,13 +502,13 @@ public: bool IsCoinBase() const { - return (vin.size() == 1 && vin[0].prevout.IsNull() && vout.size() == 1); + return (vin.size() == 1 && vin[0].prevout.IsNull() && vout.size() >= 1); } bool IsCoinStake() const { // ppcoin: the coin stake transaction is marked with the first output empty - return (vin.size() > 0 && vout.size() == 2 && vout[0].IsEmpty()); + return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].IsEmpty()); } /** Check for standard transaction types diff --git a/src/wallet.cpp b/src/wallet.cpp index 6cc679b..b740c8a 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1288,21 +1288,39 @@ bool CWallet::CreateCoinStake(unsigned int nBits, CTransaction& txNew) return error("CreateCoinStake : failed to calculate coin age"); nCredit += GetProofOfStakeReward(nCoinAge); } - // Set output amount - txNew.vout[1].nValue = nCredit; - // Sign - int nIn = 0; - BOOST_FOREACH(const CWalletTx* pcoin, vwtxPrev) + int64 nMinFee = 0; + loop { - if (!SignSignature(*this, *pcoin, txNew, nIn++)) - return error("CreateCoinStake : failed to sign coinstake"); - } + // Set output amount + txNew.vout[1].nValue = nCredit - nMinFee; - // Limit size - unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION); - if (nBytes >= MAX_BLOCK_SIZE_GEN/5) - return false; + // Sign + int nIn = 0; + BOOST_FOREACH(const CWalletTx* pcoin, vwtxPrev) + { + if (!SignSignature(*this, *pcoin, txNew, nIn++)) + return error("CreateCoinStake : failed to sign coinstake"); + } + + // Limit size + unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION); + if (nBytes >= MAX_BLOCK_SIZE_GEN/5) + return false; + + // Check enough fee is paid + if (nMinFee < txNew.GetMinFee() - MIN_TX_FEE) + { + nMinFee = txNew.GetMinFee() - MIN_TX_FEE; + continue; // try signing again + } + else + { + if (fDebug && GetBoolArg("-printfee")) + printf("CreateCoinStake : fee for coinstake %s\n", FormatMoney(nMinFee).c_str()); + break; + } + } // Successfully generated coinstake return true; -- 1.7.1