X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fwallet.cpp;h=c245f8478308c6fce5287431d595b85479900d94;hb=b92fd202e243bf3cbb6902833d991296213b8c2f;hp=564362b2e9018077bb98afa5027136b298a58623;hpb=c7bf973604a7cfca15dc70d647ce1016881d624b;p=novacoin.git diff --git a/src/wallet.cpp b/src/wallet.cpp index 564362b..c245f84 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -7,6 +7,7 @@ #include "headers.h" #include "db.h" #include "crypter.h" +#include "checkpoints.h" using namespace std; @@ -771,13 +772,29 @@ int64 CWallet::GetStake() const for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; - if ((pcoin->IsCoinBase() || pcoin->IsCoinStake()) && pcoin->GetBlocksToMaturity() > 0 && pcoin->GetDepthInMainChain() > 0) + if (pcoin->IsCoinStake() && pcoin->GetBlocksToMaturity() > 0 && pcoin->GetDepthInMainChain() > 0) nTotal += CWallet::GetCredit(*pcoin); } } return nTotal; } +int64 CWallet::GetNewMint() const +{ + int64 nTotal = 0; + CRITICAL_BLOCK(cs_wallet) + { + for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + const CWalletTx* pcoin = &(*it).second; + if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0 && pcoin->GetDepthInMainChain() > 0) + nTotal += CWallet::GetCredit(*pcoin); + } + } + return nTotal; +} + + bool CWallet::SelectCoinsMinConf(int64 nTargetValue, unsigned int nSpendTime, int nConfMine, int nConfTheirs, set >& setCoinsRet, int64& nValueRet) const { setCoinsRet.clear(); @@ -1061,8 +1078,11 @@ bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& w } // ppcoin: create coin stake transaction -bool CWallet::CreateCoinStake(CScript scriptPubKey, CTransaction& txNew) +bool CWallet::CreateCoinStake(unsigned int nBits, CTransaction& txNew) { + CBigNum bnTargetPerCoinDay; + bnTargetPerCoinDay.SetCompact(nBits); + CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_wallet) { @@ -1077,6 +1097,7 @@ bool CWallet::CreateCoinStake(CScript scriptPubKey, CTransaction& txNew) if (nBalance <= nBalanceReserve) return false; set > setCoins; + vector vwtxPrev; int64 nValueIn = 0; if (!SelectCoins(nBalance - nBalanceReserve, txNew.nTime, setCoins, nValueIn)) return false; @@ -1085,39 +1106,63 @@ bool CWallet::CreateCoinStake(CScript scriptPubKey, CTransaction& txNew) int64 nCredit = 0; BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins) { - nCredit += pcoin.first->vout[pcoin.second].nValue; - // Only spend one tx for now - break; + CTxDB txdb("r"); + CTxIndex txindex; + if (!txdb.ReadTxIndex(pcoin.first->GetHash(), txindex)) + continue; + + // Read block header + CBlock block; + if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) + continue; + if (block.GetBlockTime() + AUTO_CHECKPOINT_TRUST_SPAN > txNew.nTime) + continue; // only count coins from at least one week ago + + int64 nValueIn = pcoin.first->vout[pcoin.second].nValue; + CBigNum bnCoinDay = CBigNum(nValueIn) * (txNew.nTime-pcoin.first->nTime) / COIN / (24 * 60 * 60); + // Calculate hash + CDataStream ss(SER_GETHASH, VERSION); + ss << nBits << block.nTime << (txindex.pos.nTxPos - txindex.pos.nBlockPos) << pcoin.first->nTime << pcoin.second << txNew.nTime; + if (CBigNum(Hash(ss.begin(), ss.end())) <= bnCoinDay * bnTargetPerCoinDay) + { + txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second)); + nCredit += pcoin.first->vout[pcoin.second].nValue; + vwtxPrev.push_back(pcoin.first); + // Set output scriptPubKey + txNew.vout.push_back(CTxOut(0, pcoin.first->vout[pcoin.second].scriptPubKey)); + break; + } } - if (nCredit > nBalance - nBalanceReserve) + if (nCredit == 0 || nCredit > nBalance - nBalanceReserve) return false; - // Fill vin - BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) + BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins) { - txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second)); - // Only spend one tx for now - break; + if (pcoin.first->vout[pcoin.second].scriptPubKey == txNew.vout[1].scriptPubKey && pcoin.first->GetHash() != txNew.vin[0].prevout.hash) + { + if (nCredit + pcoin.first->vout[pcoin.second].nValue > nBalance - nBalanceReserve) + break; + txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second)); + nCredit += pcoin.first->vout[pcoin.second].nValue; + vwtxPrev.push_back(pcoin.first); + } } // Calculate coin age reward { uint64 nCoinAge; CTxDB txdb("r"); if (!txNew.GetCoinAge(txdb, nCoinAge)) - return false; + return error("CreateCoinStake : failed to calculate coin age"); nCredit += GetProofOfStakeReward(nCoinAge); } - // Fill vout - txNew.vout.push_back(CTxOut(nCredit, scriptPubKey)); - + // Set output amount + txNew.vout[1].nValue = nCredit; // Sign int nIn = 0; - BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) + BOOST_FOREACH(const CWalletTx* pcoin, vwtxPrev) { - if (!SignSignature(*this, *coin.first, txNew, nIn++)) - return false; - // Only spend one tx for now - break; + if (!SignSignature(*this, *pcoin, txNew, nIn++)) + return error("CreateCoinStake : failed to sign coinstake"); } } return true; @@ -1471,6 +1516,110 @@ int64 CWallet::GetOldestKeyPoolTime() return keypool.nTime; } +// ppcoin: check 'spent' consistency between wallet and txindex +bool CWallet::CheckSpentCoins(int& nMismatchFound, int64& nBalanceInQuestion) +{ + nMismatchFound = 0; + nBalanceInQuestion = 0; + CRITICAL_BLOCK(cs_wallet) + { + vector vCoins; + vCoins.reserve(mapWallet.size()); + for (map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + vCoins.push_back(&(*it).second); + + CTxDB txdb("r"); + BOOST_FOREACH(const CWalletTx* pcoin, vCoins) + { + // Find the corresponding transaction index + CTxIndex txindex; + if (!txdb.ReadTxIndex(pcoin->GetHash(), txindex)) + continue; + for (int n=0; n < pcoin->vout.size(); n++) + { + if (pcoin->IsSpent(n) && (txindex.vSpent.size() <= n || txindex.vSpent[n].IsNull())) + { + printf("CheckSpentCoins found lost coin %sppc %s[%d]\n", FormatMoney(pcoin->GetCredit()).c_str(), pcoin->GetHash().ToString().c_str(), n); + nMismatchFound++; + nBalanceInQuestion += pcoin->vout[n].nValue; + } + else if (!pcoin->IsSpent(n) && (txindex.vSpent.size() > n && !txindex.vSpent[n].IsNull())) + { + printf("CheckSpentCoins found spent coin %sppc %s[%d]\n", FormatMoney(pcoin->GetCredit()).c_str(), pcoin->GetHash().ToString().c_str(), n); + nMismatchFound++; + nBalanceInQuestion += pcoin->vout[n].nValue; + } + } + } + } + return (nMismatchFound == 0); +} + +// ppcoin: fix wallet spent state according to txindex +void CWallet::FixSpentCoins(int& nMismatchFound, int64& nBalanceInQuestion) +{ + nMismatchFound = 0; + nBalanceInQuestion = 0; + CRITICAL_BLOCK(cs_wallet) + { + vector vCoins; + vCoins.reserve(mapWallet.size()); + for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + vCoins.push_back(&(*it).second); + + CTxDB txdb("r"); + BOOST_FOREACH(CWalletTx* pcoin, vCoins) + { + // Find the corresponding transaction index + CTxIndex txindex; + if (!txdb.ReadTxIndex(pcoin->GetHash(), txindex)) + continue; + for (int n=0; n < pcoin->vout.size(); n++) + { + if (pcoin->IsSpent(n) && (txindex.vSpent.size() <= n || txindex.vSpent[n].IsNull())) + { + printf("FixSpentCoins found lost coin %sppc %s[%d]\n", FormatMoney(pcoin->GetCredit()).c_str(), pcoin->GetHash().ToString().c_str(), n); + nMismatchFound++; + nBalanceInQuestion += pcoin->vout[n].nValue; + pcoin->MarkUnspent(n); + pcoin->WriteToDisk(); + } + else if (!pcoin->IsSpent(n) && (txindex.vSpent.size() > n && !txindex.vSpent[n].IsNull())) + { + printf("FixSpentCoins found spent coin %sppc %s[%d]\n", FormatMoney(pcoin->GetCredit()).c_str(), pcoin->GetHash().ToString().c_str(), n); + nMismatchFound++; + nBalanceInQuestion += pcoin->vout[n].nValue; + pcoin->MarkSpent(n); + pcoin->WriteToDisk(); + } + } + } + } +} + +// ppcoin: disable transaction (only for coinstake) +void CWallet::DisableTransaction(const CTransaction &tx) +{ + if (!tx.IsCoinStake() || !IsFromMe(tx)) + return; // only disconnecting coinstake requires marking input unspent + CRITICAL_BLOCK(cs_wallet) + { + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + map::iterator mi = mapWallet.find(txin.prevout.hash); + if (mi != mapWallet.end()) + { + CWalletTx& prev = (*mi).second; + if (txin.prevout.n < prev.vout.size() && IsMine(prev.vout[txin.prevout.n])) + { + prev.MarkUnspent(txin.prevout.n); + prev.WriteToDisk(); + } + } + } + } +} + vector CReserveKey::GetReservedKey() { if (nIndex == -1)