-
+ 1C71304D64FBEC2036D0189F0F2395148F5F56A49374F48E0305EF7D47DD87263FF30EEC38400B4B2A657490ECA59E73C80AFB455E558263F65A4024E850A15C
bitcoin/src/wallet.cpp
(0 . 0)(1 . 1446)
26669 // /****************************\
26670 // * EXPERIMENTAL BRANCH. *
26671 // * FOR LABORATORY USE ONLY. *
26672 // ********************************
26673 // ************
26674 // **************
26675 // ****************
26676 // **** **** ****
26677 // *** *** ***
26678 // *** *** ***
26679 // *** * * **
26680 // ******** ********
26681 // ******* ******
26682 // *** **
26683 // * ******* **
26684 // ** * * * * *
26685 // ** * * ***
26686 // **** * * * * ****
26687 // **** *** * * ** ***
26688 // **** ********* ******
26689 // ******* ***** *******
26690 // ********* ****** **
26691 // ** ****** ******
26692 // ** ******* **
26693 // ** ******* ***
26694 // **** ******** ************
26695 // ************ ************
26696 // ******** *******
26697 // ****** ****
26698 // *** ***
26699 // ********************************
26700 // Copyright (c) 2009-2010 Satoshi Nakamoto
26701 // Copyright (c) 2011 The Bitcoin developers
26702 // Distributed under the MIT/X11 software license, see the accompanying
26703 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
26704
26705 #include "headers.h"
26706 #include "db.h"
26707 #include "crypter.h"
26708
26709 using namespace std;
26710
26711
26712 //////////////////////////////////////////////////////////////////////////////
26713 //
26714 // mapWallet
26715 //
26716
26717 bool CWallet::AddKey(const CKey& key)
26718 {
26719 if (!CCryptoKeyStore::AddKey(key))
26720 return false;
26721 if (!fFileBacked)
26722 return true;
26723 if (!IsCrypted())
26724 return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey());
26725 return true;
26726 }
26727
26728 bool CWallet::AddCryptedKey(const vector<unsigned char> &vchPubKey, const vector<unsigned char> &vchCryptedSecret)
26729 {
26730 if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
26731 return false;
26732 if (!fFileBacked)
26733 return true;
26734 CRITICAL_BLOCK(cs_wallet)
26735 {
26736 if (pwalletdbEncryption)
26737 return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret);
26738 else
26739 return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret);
26740 }
26741 return false;
26742 }
26743
26744 bool CWallet::Unlock(const SecureString& strWalletPassphrase)
26745 {
26746 if (!IsLocked())
26747 return false;
26748
26749 CCrypter crypter;
26750 CKeyingMaterial vMasterKey;
26751
26752 CRITICAL_BLOCK(cs_wallet)
26753 BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
26754 {
26755 if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
26756 return false;
26757 if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
26758 return false;
26759 if (CCryptoKeyStore::Unlock(vMasterKey))
26760 return true;
26761 }
26762 return false;
26763 }
26764
26765 bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
26766 {
26767 bool fWasLocked = IsLocked();
26768
26769 CRITICAL_BLOCK(cs_wallet)
26770 {
26771 Lock();
26772
26773 CCrypter crypter;
26774 CKeyingMaterial vMasterKey;
26775 BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
26776 {
26777 if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
26778 return false;
26779 if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
26780 return false;
26781 if (CCryptoKeyStore::Unlock(vMasterKey))
26782 {
26783 int64 nStartTime = GetTimeMillis();
26784 crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
26785 pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
26786
26787 nStartTime = GetTimeMillis();
26788 crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
26789 pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
26790
26791 if (pMasterKey.second.nDeriveIterations < 25000)
26792 pMasterKey.second.nDeriveIterations = 25000;
26793
26794 printf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
26795
26796 if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
26797 return false;
26798 if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey))
26799 return false;
26800 CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second);
26801 if (fWasLocked)
26802 Lock();
26803 return true;
26804 }
26805 }
26806 }
26807
26808 return false;
26809 }
26810
26811
26812 // This class implements an addrIncoming entry that causes pre-0.4
26813 // clients to crash on startup if reading a private-key-encrypted wallet.
26814 class CCorruptAddress
26815 {
26816 public:
26817 IMPLEMENT_SERIALIZE
26818 (
26819 if (nType & SER_DISK)
26820 READWRITE(nVersion);
26821 )
26822 };
26823
26824 bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
26825 {
26826 if (IsCrypted())
26827 return false;
26828
26829 CKeyingMaterial vMasterKey;
26830 RandAddSeedPerfmon();
26831
26832 vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
26833 RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
26834
26835 CMasterKey kMasterKey;
26836
26837 RandAddSeedPerfmon();
26838 kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
26839 RAND_bytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
26840
26841 CCrypter crypter;
26842 int64 nStartTime = GetTimeMillis();
26843 crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
26844 kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
26845
26846 nStartTime = GetTimeMillis();
26847 crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
26848 kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
26849
26850 if (kMasterKey.nDeriveIterations < 25000)
26851 kMasterKey.nDeriveIterations = 25000;
26852
26853 printf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
26854
26855 if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
26856 return false;
26857 if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
26858 return false;
26859
26860 CRITICAL_BLOCK(cs_wallet)
26861 {
26862 mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
26863 if (fFileBacked)
26864 {
26865 pwalletdbEncryption = new CWalletDB(strWalletFile);
26866 pwalletdbEncryption->TxnBegin();
26867 pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
26868 }
26869
26870 if (!EncryptKeys(vMasterKey))
26871 {
26872 if (fFileBacked)
26873 pwalletdbEncryption->TxnAbort();
26874 exit(1); //We now probably have half of our keys encrypted in memory, and half not...die and let the user reload their unencrypted wallet.
26875 }
26876
26877 if (fFileBacked)
26878 {
26879 CCorruptAddress corruptAddress;
26880 pwalletdbEncryption->WriteSetting("addrIncoming", corruptAddress);
26881 if (!pwalletdbEncryption->TxnCommit())
26882 exit(1); //We now have keys encrypted in memory, but no on disk...die to avoid confusion and let the user reload their unencrypted wallet.
26883
26884 delete pwalletdbEncryption;
26885 pwalletdbEncryption = NULL;
26886 }
26887
26888 Lock();
26889 Unlock(strWalletPassphrase);
26890 NewKeyPool();
26891 Lock();
26892
26893 // Need to completely rewrite the wallet file; if we don't, bdb might keep
26894 // bits of the unencrypted private key in slack space in the database file.
26895 CDB::Rewrite(strWalletFile);
26896 }
26897
26898 return true;
26899 }
26900
26901 void CWallet::WalletUpdateSpent(const CTransaction &tx)
26902 {
26903 // Anytime a signature is successfully verified, it's proof the outpoint is spent.
26904 // Update the wallet spent flag if it doesn't know due to wallet.dat being
26905 // restored from backup or the user making copies of wallet.dat.
26906 CRITICAL_BLOCK(cs_wallet)
26907 {
26908 BOOST_FOREACH(const CTxIn& txin, tx.vin)
26909 {
26910 map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash);
26911 if (mi != mapWallet.end())
26912 {
26913 CWalletTx& wtx = (*mi).second;
26914 if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n]))
26915 {
26916 printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
26917 wtx.MarkSpent(txin.prevout.n);
26918 wtx.WriteToDisk();
26919 vWalletUpdated.push_back(txin.prevout.hash);
26920 }
26921 }
26922 }
26923 }
26924 }
26925
26926 bool CWallet::AddToWallet(const CWalletTx& wtxIn)
26927 {
26928 uint256 hash = wtxIn.GetHash();
26929 CRITICAL_BLOCK(cs_wallet)
26930 {
26931 // Inserts only if not already there, returns tx inserted or tx found
26932 pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
26933 CWalletTx& wtx = (*ret.first).second;
26934 wtx.pwallet = this;
26935 bool fInsertedNew = ret.second;
26936 if (fInsertedNew)
26937 wtx.nTimeReceived = GetAdjustedTime();
26938
26939 bool fUpdated = false;
26940 if (!fInsertedNew)
26941 {
26942 // Merge
26943 if (wtxIn.hashBlock != 0 && wtxIn.hashBlock != wtx.hashBlock)
26944 {
26945 wtx.hashBlock = wtxIn.hashBlock;
26946 fUpdated = true;
26947 }
26948 if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex))
26949 {
26950 wtx.vMerkleBranch = wtxIn.vMerkleBranch;
26951 wtx.nIndex = wtxIn.nIndex;
26952 fUpdated = true;
26953 }
26954 if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
26955 {
26956 wtx.fFromMe = wtxIn.fFromMe;
26957 fUpdated = true;
26958 }
26959 fUpdated |= wtx.UpdateSpent(wtxIn.vfSpent);
26960 }
26961
26962 //// debug print
26963 printf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString().substr(0,10).c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
26964
26965 // Write to disk
26966 if (fInsertedNew || fUpdated)
26967 if (!wtx.WriteToDisk())
26968 return false;
26969 #ifndef QT_GUI
26970 // If default receiving address gets used, replace it with a new one
26971 CScript scriptDefaultKey;
26972 scriptDefaultKey.SetBitcoinAddress(vchDefaultKey);
26973 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
26974 {
26975 if (txout.scriptPubKey == scriptDefaultKey)
26976 {
26977 std::vector<unsigned char> newDefaultKey;
26978 if (GetKeyFromPool(newDefaultKey, false))
26979 {
26980 SetDefaultKey(newDefaultKey);
26981 SetAddressBookName(CBitcoinAddress(vchDefaultKey), "");
26982 }
26983 }
26984 }
26985 #endif
26986 // Notify UI
26987 vWalletUpdated.push_back(hash);
26988
26989 // since AddToWallet is called directly for self-originating transactions, check for consumption of own coins
26990 WalletUpdateSpent(wtx);
26991 }
26992
26993 // Refresh UI
26994 MainFrameRepaint();
26995 return true;
26996 }
26997
26998 // Add a transaction to the wallet, or update it.
26999 // pblock is optional, but should be provided if the transaction is known to be in a block.
27000 // If fUpdate is true, existing transactions will be updated.
27001 bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
27002 {
27003 uint256 hash = tx.GetHash();
27004 CRITICAL_BLOCK(cs_wallet)
27005 {
27006 bool fExisted = mapWallet.count(hash);
27007 if (fExisted && !fUpdate) return false;
27008 if (fExisted || IsMine(tx) || IsFromMe(tx))
27009 {
27010 CWalletTx wtx(this,tx);
27011 // Get merkle branch if transaction was found in a block
27012 if (pblock)
27013 wtx.SetMerkleBranch(pblock);
27014 return AddToWallet(wtx);
27015 }
27016 else
27017 WalletUpdateSpent(tx);
27018 }
27019 return false;
27020 }
27021
27022 bool CWallet::EraseFromWallet(uint256 hash)
27023 {
27024 if (!fFileBacked)
27025 return false;
27026 CRITICAL_BLOCK(cs_wallet)
27027 {
27028 if (mapWallet.erase(hash))
27029 CWalletDB(strWalletFile).EraseTx(hash);
27030 }
27031 return true;
27032 }
27033
27034
27035 bool CWallet::IsMine(const CTxIn &txin) const
27036 {
27037 CRITICAL_BLOCK(cs_wallet)
27038 {
27039 map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
27040 if (mi != mapWallet.end())
27041 {
27042 const CWalletTx& prev = (*mi).second;
27043 if (txin.prevout.n < prev.vout.size())
27044 if (IsMine(prev.vout[txin.prevout.n]))
27045 return true;
27046 }
27047 }
27048 return false;
27049 }
27050
27051 int64 CWallet::GetDebit(const CTxIn &txin) const
27052 {
27053 CRITICAL_BLOCK(cs_wallet)
27054 {
27055 map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
27056 if (mi != mapWallet.end())
27057 {
27058 const CWalletTx& prev = (*mi).second;
27059 if (txin.prevout.n < prev.vout.size())
27060 if (IsMine(prev.vout[txin.prevout.n]))
27061 return prev.vout[txin.prevout.n].nValue;
27062 }
27063 }
27064 return 0;
27065 }
27066
27067 int64 CWalletTx::GetTxTime() const
27068 {
27069 return nTimeReceived;
27070 }
27071
27072 int CWalletTx::GetRequestCount() const
27073 {
27074 // Returns -1 if it wasn't being tracked
27075 int nRequests = -1;
27076 CRITICAL_BLOCK(pwallet->cs_wallet)
27077 {
27078 if (IsCoinBase())
27079 {
27080 // Generated block
27081 if (hashBlock != 0)
27082 {
27083 map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
27084 if (mi != pwallet->mapRequestCount.end())
27085 nRequests = (*mi).second;
27086 }
27087 }
27088 else
27089 {
27090 // Did anyone request this transaction?
27091 map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
27092 if (mi != pwallet->mapRequestCount.end())
27093 {
27094 nRequests = (*mi).second;
27095
27096 // How about the block it's in?
27097 if (nRequests == 0 && hashBlock != 0)
27098 {
27099 map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
27100 if (mi != pwallet->mapRequestCount.end())
27101 nRequests = (*mi).second;
27102 else
27103 nRequests = 1; // If it's in someone else's block it must have got out
27104 }
27105 }
27106 }
27107 }
27108 return nRequests;
27109 }
27110
27111 void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list<pair<CBitcoinAddress, int64> >& listReceived,
27112 list<pair<CBitcoinAddress, int64> >& listSent, int64& nFee, string& strSentAccount) const
27113 {
27114 nGeneratedImmature = nGeneratedMature = nFee = 0;
27115 listReceived.clear();
27116 listSent.clear();
27117 strSentAccount = strFromAccount;
27118
27119 if (IsCoinBase())
27120 {
27121 if (GetBlocksToMaturity() > 0)
27122 nGeneratedImmature = pwallet->GetCredit(*this);
27123 else
27124 nGeneratedMature = GetCredit();
27125 return;
27126 }
27127
27128 // Compute fee:
27129 int64 nDebit = GetDebit();
27130 if (nDebit > 0) // debit>0 means we signed/sent this transaction
27131 {
27132 int64 nValueOut = GetValueOut();
27133 nFee = nDebit - nValueOut;
27134 }
27135
27136 // Sent/received. Standard client will never generate a send-to-multiple-recipients,
27137 // but non-standard clients might (so return a list of address/amount pairs)
27138 BOOST_FOREACH(const CTxOut& txout, vout)
27139 {
27140 CBitcoinAddress address;
27141 vector<unsigned char> vchPubKey;
27142 if (!ExtractAddress(txout.scriptPubKey, NULL, address))
27143 {
27144 printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
27145 this->GetHash().ToString().c_str());
27146 address = " unknown ";
27147 }
27148
27149 // Don't report 'change' txouts
27150 if (nDebit > 0 && pwallet->IsChange(txout))
27151 continue;
27152
27153 if (nDebit > 0)
27154 listSent.push_back(make_pair(address, txout.nValue));
27155
27156 if (pwallet->IsMine(txout))
27157 listReceived.push_back(make_pair(address, txout.nValue));
27158 }
27159
27160 }
27161
27162 void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived,
27163 int64& nSent, int64& nFee) const
27164 {
27165 nGenerated = nReceived = nSent = nFee = 0;
27166
27167 int64 allGeneratedImmature, allGeneratedMature, allFee;
27168 allGeneratedImmature = allGeneratedMature = allFee = 0;
27169 string strSentAccount;
27170 list<pair<CBitcoinAddress, int64> > listReceived;
27171 list<pair<CBitcoinAddress, int64> > listSent;
27172 GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
27173
27174 if (strAccount == "")
27175 nGenerated = allGeneratedMature;
27176 if (strAccount == strSentAccount)
27177 {
27178 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& s, listSent)
27179 nSent += s.second;
27180 nFee = allFee;
27181 }
27182 CRITICAL_BLOCK(pwallet->cs_wallet)
27183 {
27184 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
27185 {
27186 if (pwallet->mapAddressBook.count(r.first))
27187 {
27188 map<CBitcoinAddress, string>::const_iterator mi = pwallet->mapAddressBook.find(r.first);
27189 if (mi != pwallet->mapAddressBook.end() && (*mi).second == strAccount)
27190 nReceived += r.second;
27191 }
27192 else if (strAccount.empty())
27193 {
27194 nReceived += r.second;
27195 }
27196 }
27197 }
27198 }
27199
27200 void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
27201 {
27202 vtxPrev.clear();
27203
27204 const int COPY_DEPTH = 3;
27205 if (SetMerkleBranch() < COPY_DEPTH)
27206 {
27207 vector<uint256> vWorkQueue;
27208 BOOST_FOREACH(const CTxIn& txin, vin)
27209 vWorkQueue.push_back(txin.prevout.hash);
27210
27211 // This critsect is OK because txdb is already open
27212 CRITICAL_BLOCK(pwallet->cs_wallet)
27213 {
27214 map<uint256, const CMerkleTx*> mapWalletPrev;
27215 set<uint256> setAlreadyDone;
27216 for (int i = 0; i < vWorkQueue.size(); i++)
27217 {
27218 uint256 hash = vWorkQueue[i];
27219 if (setAlreadyDone.count(hash))
27220 continue;
27221 setAlreadyDone.insert(hash);
27222
27223 CMerkleTx tx;
27224 map<uint256, CWalletTx>::const_iterator mi = pwallet->mapWallet.find(hash);
27225 if (mi != pwallet->mapWallet.end())
27226 {
27227 tx = (*mi).second;
27228 BOOST_FOREACH(const CMerkleTx& txWalletPrev, (*mi).second.vtxPrev)
27229 mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
27230 }
27231 else if (mapWalletPrev.count(hash))
27232 {
27233 tx = *mapWalletPrev[hash];
27234 }
27235 else if (!fClient && txdb.ReadDiskTx(hash, tx))
27236 {
27237 ;
27238 }
27239 else
27240 {
27241 printf("ERROR: AddSupportingTransactions() : unsupported transaction\n");
27242 continue;
27243 }
27244
27245 int nDepth = tx.SetMerkleBranch();
27246 vtxPrev.push_back(tx);
27247
27248 if (nDepth < COPY_DEPTH)
27249 BOOST_FOREACH(const CTxIn& txin, tx.vin)
27250 vWorkQueue.push_back(txin.prevout.hash);
27251 }
27252 }
27253 }
27254
27255 reverse(vtxPrev.begin(), vtxPrev.end());
27256 }
27257
27258 bool CWalletTx::WriteToDisk()
27259 {
27260 return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this);
27261 }
27262
27263 // Scan the block chain (starting in pindexStart) for transactions
27264 // from or to us. If fUpdate is true, found transactions that already
27265 // exist in the wallet will be updated.
27266 int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
27267 {
27268 int ret = 0;
27269
27270 CBlockIndex* pindex = pindexStart;
27271 CRITICAL_BLOCK(cs_wallet)
27272 {
27273 while (pindex)
27274 {
27275 CBlock block;
27276 block.ReadFromDisk(pindex, true);
27277 BOOST_FOREACH(CTransaction& tx, block.vtx)
27278 {
27279 if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
27280 ret++;
27281 }
27282 pindex = pindex->pnext;
27283 }
27284 }
27285 return ret;
27286 }
27287
27288 void CWallet::ReacceptWalletTransactions()
27289 {
27290 CTxDB txdb("r");
27291 bool fRepeat = true;
27292 while (fRepeat) CRITICAL_BLOCK(cs_wallet)
27293 {
27294 fRepeat = false;
27295 vector<CDiskTxPos> vMissingTx;
27296 BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
27297 {
27298 CWalletTx& wtx = item.second;
27299 if (wtx.IsCoinBase() && wtx.IsSpent(0))
27300 continue;
27301
27302 CTxIndex txindex;
27303 bool fUpdated = false;
27304 if (txdb.ReadTxIndex(wtx.GetHash(), txindex))
27305 {
27306 // Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
27307 if (txindex.vSpent.size() != wtx.vout.size())
27308 {
27309 printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size());
27310 continue;
27311 }
27312 for (int i = 0; i < txindex.vSpent.size(); i++)
27313 {
27314 if (wtx.IsSpent(i))
27315 continue;
27316 if (!txindex.vSpent[i].IsNull() && IsMine(wtx.vout[i]))
27317 {
27318 wtx.MarkSpent(i);
27319 fUpdated = true;
27320 vMissingTx.push_back(txindex.vSpent[i]);
27321 }
27322 }
27323 if (fUpdated)
27324 {
27325 printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
27326 wtx.MarkDirty();
27327 wtx.WriteToDisk();
27328 }
27329 }
27330 else
27331 {
27332 // Reaccept any txes of ours that aren't already in a block
27333 if (!wtx.IsCoinBase())
27334 wtx.AcceptWalletTransaction(txdb, false);
27335 }
27336 }
27337 if (!vMissingTx.empty())
27338 {
27339 // TODO: optimize this to scan just part of the block chain?
27340 if (ScanForWalletTransactions(pindexGenesisBlock))
27341 fRepeat = true; // Found missing transactions: re-do Reaccept.
27342 }
27343 }
27344 }
27345
27346 void CWalletTx::RelayWalletTransaction(CTxDB& txdb)
27347 {
27348 BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
27349 {
27350 if (!tx.IsCoinBase())
27351 {
27352 uint256 hash = tx.GetHash();
27353 if (!txdb.ContainsTx(hash))
27354 RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
27355 }
27356 }
27357 if (!IsCoinBase())
27358 {
27359 uint256 hash = GetHash();
27360 if (!txdb.ContainsTx(hash))
27361 {
27362 printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
27363 RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
27364 }
27365 }
27366 }
27367
27368 void CWalletTx::RelayWalletTransaction()
27369 {
27370 CTxDB txdb("r");
27371 RelayWalletTransaction(txdb);
27372 }
27373
27374 void CWallet::ResendWalletTransactions()
27375 {
27376 // Do this infrequently and randomly to avoid giving away
27377 // that these are our transactions.
27378 static int64 nNextTime;
27379 if (GetTime() < nNextTime)
27380 return;
27381 bool fFirst = (nNextTime == 0);
27382 nNextTime = GetTime() + GetRand(30 * 60);
27383 if (fFirst)
27384 return;
27385
27386 // Only do it if there's been a new block since last time
27387 static int64 nLastTime;
27388 if (nTimeBestReceived < nLastTime)
27389 return;
27390 nLastTime = GetTime();
27391
27392 // Rebroadcast any of our txes that aren't in a block yet
27393 printf("ResendWalletTransactions()\n");
27394 CTxDB txdb("r");
27395 CRITICAL_BLOCK(cs_wallet)
27396 {
27397 // Sort them in chronological order
27398 multimap<unsigned int, CWalletTx*> mapSorted;
27399 BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
27400 {
27401 CWalletTx& wtx = item.second;
27402 // Don't rebroadcast until it's had plenty of time that
27403 // it should have gotten in already by now.
27404 if (nTimeBestReceived - (int64)wtx.nTimeReceived > 5 * 60)
27405 mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
27406 }
27407 BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
27408 {
27409 CWalletTx& wtx = *item.second;
27410 wtx.RelayWalletTransaction(txdb);
27411 }
27412 }
27413 }
27414
27415
27416
27417
27418
27419
27420 //////////////////////////////////////////////////////////////////////////////
27421 //
27422 // Actions
27423 //
27424
27425
27426 int64 CWallet::GetBalance() const
27427 {
27428 int64 nTotal = 0;
27429 CRITICAL_BLOCK(cs_wallet)
27430 {
27431 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
27432 {
27433 const CWalletTx* pcoin = &(*it).second;
27434 if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
27435 continue;
27436 nTotal += pcoin->GetAvailableCredit();
27437 }
27438 }
27439
27440 return nTotal;
27441 }
27442
27443 int64 CWallet::GetUnconfirmedBalance() const
27444 {
27445 int64 nTotal = 0;
27446 CRITICAL_BLOCK(cs_wallet)
27447 {
27448 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
27449 {
27450 const CWalletTx* pcoin = &(*it).second;
27451 if (pcoin->IsFinal() && pcoin->IsConfirmed())
27452 continue;
27453 nTotal += pcoin->GetAvailableCredit();
27454 }
27455 }
27456 return nTotal;
27457 }
27458
27459 bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
27460 {
27461 setCoinsRet.clear();
27462 nValueRet = 0;
27463
27464 // List of values less than target
27465 pair<int64, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
27466 coinLowestLarger.first = INT64_MAX;
27467 coinLowestLarger.second.first = NULL;
27468 vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue;
27469 int64 nTotalLower = 0;
27470
27471 CRITICAL_BLOCK(cs_wallet)
27472 {
27473 vector<const CWalletTx*> vCoins;
27474 vCoins.reserve(mapWallet.size());
27475 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
27476 vCoins.push_back(&(*it).second);
27477 random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
27478
27479 BOOST_FOREACH(const CWalletTx* pcoin, vCoins)
27480 {
27481 if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
27482 continue;
27483
27484 if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
27485 continue;
27486
27487 int nDepth = pcoin->GetDepthInMainChain();
27488 if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
27489 continue;
27490
27491 for (int i = 0; i < pcoin->vout.size(); i++)
27492 {
27493 if (pcoin->IsSpent(i) || !IsMine(pcoin->vout[i]))
27494 continue;
27495
27496 int64 n = pcoin->vout[i].nValue;
27497
27498 if (n <= 0)
27499 continue;
27500
27501 pair<int64,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin,i));
27502
27503 if (n == nTargetValue)
27504 {
27505 setCoinsRet.insert(coin.second);
27506 nValueRet += coin.first;
27507 return true;
27508 }
27509 else if (n < nTargetValue + CENT)
27510 {
27511 vValue.push_back(coin);
27512 nTotalLower += n;
27513 }
27514 else if (n < coinLowestLarger.first)
27515 {
27516 coinLowestLarger = coin;
27517 }
27518 }
27519 }
27520 }
27521
27522 if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT)
27523 {
27524 for (int i = 0; i < vValue.size(); ++i)
27525 {
27526 setCoinsRet.insert(vValue[i].second);
27527 nValueRet += vValue[i].first;
27528 }
27529 return true;
27530 }
27531
27532 if (nTotalLower < nTargetValue + (coinLowestLarger.second.first ? CENT : 0))
27533 {
27534 if (coinLowestLarger.second.first == NULL)
27535 return false;
27536 setCoinsRet.insert(coinLowestLarger.second);
27537 nValueRet += coinLowestLarger.first;
27538 return true;
27539 }
27540
27541 if (nTotalLower >= nTargetValue + CENT)
27542 nTargetValue += CENT;
27543
27544 // Solve subset sum by stochastic approximation
27545 sort(vValue.rbegin(), vValue.rend());
27546 vector<char> vfIncluded;
27547 vector<char> vfBest(vValue.size(), true);
27548 int64 nBest = nTotalLower;
27549
27550 for (int nRep = 0; nRep < 1000 && nBest != nTargetValue; nRep++)
27551 {
27552 vfIncluded.assign(vValue.size(), false);
27553 int64 nTotal = 0;
27554 bool fReachedTarget = false;
27555 for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
27556 {
27557 for (int i = 0; i < vValue.size(); i++)
27558 {
27559 if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
27560 {
27561 nTotal += vValue[i].first;
27562 vfIncluded[i] = true;
27563 if (nTotal >= nTargetValue)
27564 {
27565 fReachedTarget = true;
27566 if (nTotal < nBest)
27567 {
27568 nBest = nTotal;
27569 vfBest = vfIncluded;
27570 }
27571 nTotal -= vValue[i].first;
27572 vfIncluded[i] = false;
27573 }
27574 }
27575 }
27576 }
27577 }
27578
27579 // If the next larger is still closer, return it
27580 if (coinLowestLarger.second.first && coinLowestLarger.first - nTargetValue <= nBest - nTargetValue)
27581 {
27582 setCoinsRet.insert(coinLowestLarger.second);
27583 nValueRet += coinLowestLarger.first;
27584 }
27585 else {
27586 for (int i = 0; i < vValue.size(); i++)
27587 if (vfBest[i])
27588 {
27589 setCoinsRet.insert(vValue[i].second);
27590 nValueRet += vValue[i].first;
27591 }
27592
27593 //// debug print
27594 printf("SelectCoins() best subset: ");
27595 for (int i = 0; i < vValue.size(); i++)
27596 if (vfBest[i])
27597 printf("%s ", FormatMoney(vValue[i].first).c_str());
27598 printf("total %s\n", FormatMoney(nBest).c_str());
27599 }
27600
27601 return true;
27602 }
27603
27604 bool CWallet::SelectCoins(int64 nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
27605 {
27606 return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) ||
27607 SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) ||
27608 SelectCoinsMinConf(nTargetValue, 0, 1, setCoinsRet, nValueRet));
27609 }
27610
27611
27612
27613
27614 bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
27615 {
27616 int64 nValue = 0;
27617 BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
27618 {
27619 if (nValue < 0)
27620 return false;
27621 nValue += s.second;
27622 }
27623 if (vecSend.empty() || nValue < 0)
27624 return false;
27625
27626 wtxNew.pwallet = this;
27627
27628 CRITICAL_BLOCK(cs_main)
27629 CRITICAL_BLOCK(cs_wallet)
27630 {
27631 // txdb must be opened before the mapWallet lock
27632 CTxDB txdb("r");
27633 {
27634 nFeeRet = nTransactionFee;
27635 loop
27636 {
27637 wtxNew.vin.clear();
27638 wtxNew.vout.clear();
27639 wtxNew.fFromMe = true;
27640
27641 int64 nTotalValue = nValue + nFeeRet;
27642 double dPriority = 0;
27643 // vouts to the payees
27644 BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
27645 wtxNew.vout.push_back(CTxOut(s.second, s.first));
27646
27647 // Choose coins to use
27648 set<pair<const CWalletTx*,unsigned int> > setCoins;
27649 int64 nValueIn = 0;
27650 if (!SelectCoins(nTotalValue, setCoins, nValueIn))
27651 return false;
27652 BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
27653 {
27654 int64 nCredit = pcoin.first->vout[pcoin.second].nValue;
27655 dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain();
27656 }
27657
27658 int64 nChange = nValueIn - nValue - nFeeRet;
27659 // if sub-cent change is required, the fee must be raised to at least MIN_TX_FEE
27660 // or until nChange becomes zero
27661 if (nFeeRet < MIN_TX_FEE && nChange > 0 && nChange < CENT)
27662 {
27663 int64 nMoveToFee = min(nChange, MIN_TX_FEE - nFeeRet);
27664 nChange -= nMoveToFee;
27665 nFeeRet += nMoveToFee;
27666 }
27667
27668 if (nChange > 0)
27669 {
27670 // Note: We use a new key here to keep it from being obvious which side is the change.
27671 // The drawback is that by not reusing a previous key, the change may be lost if a
27672 // backup is restored, if the backup doesn't have the new private key for the change.
27673 // If we reused the old key, it would be possible to add code to look for and
27674 // rediscover unknown transactions that were written with keys of ours to recover
27675 // post-backup change.
27676
27677 // Reserve a new key pair from key pool
27678 vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
27679 // assert(mapKeys.count(vchPubKey));
27680
27681 // Fill a vout to ourself, using same address type as the payment
27682 CScript scriptChange;
27683 if (vecSend[0].first.GetBitcoinAddress().IsValid())
27684 scriptChange.SetBitcoinAddress(vchPubKey);
27685 else
27686 scriptChange << vchPubKey << OP_CHECKSIG;
27687
27688 // Insert change txn at random position:
27689 vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
27690 wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));
27691 }
27692 else
27693 reservekey.ReturnKey();
27694
27695 // Fill vin
27696 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
27697 wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
27698
27699 // Sign
27700 int nIn = 0;
27701 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
27702 if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
27703 return false;
27704
27705 // Limit size
27706 unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK);
27707 if (nBytes >= MAX_BLOCK_SIZE_GEN/5)
27708 return false;
27709 dPriority /= nBytes;
27710
27711 // Check that enough fee is included
27712 int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
27713 bool fAllowFree = CTransaction::AllowFree(dPriority);
27714 int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree);
27715 if (nFeeRet < max(nPayFee, nMinFee))
27716 {
27717 nFeeRet = max(nPayFee, nMinFee);
27718 continue;
27719 }
27720
27721 // Fill vtxPrev by copying from previous transactions vtxPrev
27722 wtxNew.AddSupportingTransactions(txdb);
27723 wtxNew.fTimeReceivedIsTxTime = true;
27724
27725 break;
27726 }
27727 }
27728 }
27729 return true;
27730 }
27731
27732 bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
27733 {
27734 vector< pair<CScript, int64> > vecSend;
27735 vecSend.push_back(make_pair(scriptPubKey, nValue));
27736 return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet);
27737 }
27738
27739 // Call after CreateTransaction unless you want to abort
27740 bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
27741 {
27742 CRITICAL_BLOCK(cs_main)
27743 CRITICAL_BLOCK(cs_wallet)
27744 {
27745 printf("CommitTransaction:\n%s", wtxNew.ToString().c_str());
27746 {
27747 // This is only to keep the database open to defeat the auto-flush for the
27748 // duration of this scope. This is the only place where this optimization
27749 // maybe makes sense; please don't do it anywhere else.
27750 CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r") : NULL;
27751
27752 // Take key pair from key pool so it won't be used again
27753 reservekey.KeepKey();
27754
27755 // Add tx to wallet, because if it has change it's also ours,
27756 // otherwise just for transaction history.
27757 AddToWallet(wtxNew);
27758
27759 // Mark old coins as spent
27760 set<CWalletTx*> setCoins;
27761 BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
27762 {
27763 CWalletTx &coin = mapWallet[txin.prevout.hash];
27764 coin.pwallet = this;
27765 coin.MarkSpent(txin.prevout.n);
27766 coin.WriteToDisk();
27767 vWalletUpdated.push_back(coin.GetHash());
27768 }
27769
27770 if (fFileBacked)
27771 delete pwalletdb;
27772 }
27773
27774 // Track how many getdata requests our transaction gets
27775 mapRequestCount[wtxNew.GetHash()] = 0;
27776
27777 // Broadcast
27778 if (!wtxNew.AcceptToMemoryPool())
27779 {
27780 // This must not fail. The transaction has already been signed and recorded.
27781 printf("CommitTransaction() : Error: Transaction not valid");
27782 return false;
27783 }
27784 wtxNew.RelayWalletTransaction();
27785 }
27786 MainFrameRepaint();
27787 return true;
27788 }
27789
27790
27791
27792
27793 string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
27794 {
27795 CReserveKey reservekey(this);
27796 int64 nFeeRequired;
27797
27798 if (IsLocked())
27799 {
27800 string strError = _("Error: Wallet locked, unable to create transaction ");
27801 printf("SendMoney() : %s", strError.c_str());
27802 return strError;
27803 }
27804 if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
27805 {
27806 string strError;
27807 if (nValue + nFeeRequired > GetBalance())
27808 strError = strprintf(_("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds "), FormatMoney(nFeeRequired).c_str());
27809 else
27810 strError = _("Error: Transaction creation failed ");
27811 printf("SendMoney() : %s", strError.c_str());
27812 return strError;
27813 }
27814
27815 if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
27816 return "ABORTED";
27817
27818 if (!CommitTransaction(wtxNew, reservekey))
27819 return _("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
27820
27821 MainFrameRepaint();
27822 return "";
27823 }
27824
27825
27826
27827 string CWallet::SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
27828 {
27829 // Check amount
27830 if (nValue <= 0)
27831 return _("Invalid amount");
27832 if (nValue + nTransactionFee > GetBalance())
27833 return _("Insufficient funds");
27834
27835 // Parse bitcoin address
27836 CScript scriptPubKey;
27837 scriptPubKey.SetBitcoinAddress(address);
27838
27839 return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee);
27840 }
27841
27842
27843
27844
27845 int CWallet::LoadWallet(bool& fFirstRunRet)
27846 {
27847 if (!fFileBacked)
27848 return false;
27849 fFirstRunRet = false;
27850 int nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
27851 if (nLoadWalletRet == DB_NEED_REWRITE)
27852 {
27853 if (CDB::Rewrite(strWalletFile, "\x04pool"))
27854 {
27855 setKeyPool.clear();
27856 // Note: can't top-up keypool here, because wallet is locked.
27857 // User will be prompted to unlock wallet the next operation
27858 // the requires a new key.
27859 }
27860 nLoadWalletRet = DB_NEED_REWRITE;
27861 }
27862
27863 if (nLoadWalletRet != DB_LOAD_OK)
27864 return nLoadWalletRet;
27865 fFirstRunRet = vchDefaultKey.empty();
27866
27867 if (!HaveKey(Hash160(vchDefaultKey)))
27868 {
27869 // Create new keyUser and set as default key
27870 RandAddSeedPerfmon();
27871
27872 std::vector<unsigned char> newDefaultKey;
27873 if (!GetKeyFromPool(newDefaultKey, false))
27874 return DB_LOAD_FAIL;
27875 SetDefaultKey(newDefaultKey);
27876 if (!SetAddressBookName(CBitcoinAddress(vchDefaultKey), ""))
27877 return DB_LOAD_FAIL;
27878 }
27879
27880 CreateThread(ThreadFlushWalletDB, &strWalletFile);
27881 return DB_LOAD_OK;
27882 }
27883
27884
27885 bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& strName)
27886 {
27887 mapAddressBook[address] = strName;
27888 if (!fFileBacked)
27889 return false;
27890 return CWalletDB(strWalletFile).WriteName(address.ToString(), strName);
27891 }
27892
27893 bool CWallet::DelAddressBookName(const CBitcoinAddress& address)
27894 {
27895 mapAddressBook.erase(address);
27896 if (!fFileBacked)
27897 return false;
27898 return CWalletDB(strWalletFile).EraseName(address.ToString());
27899 }
27900
27901
27902 void CWallet::PrintWallet(const CBlock& block)
27903 {
27904 CRITICAL_BLOCK(cs_wallet)
27905 {
27906 if (mapWallet.count(block.vtx[0].GetHash()))
27907 {
27908 CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()];
27909 printf(" mine: %d %d %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit());
27910 }
27911 }
27912 printf("\n");
27913 }
27914
27915 bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx)
27916 {
27917 CRITICAL_BLOCK(cs_wallet)
27918 {
27919 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hashTx);
27920 if (mi != mapWallet.end())
27921 {
27922 wtx = (*mi).second;
27923 return true;
27924 }
27925 }
27926 return false;
27927 }
27928
27929 bool CWallet::SetDefaultKey(const std::vector<unsigned char> &vchPubKey)
27930 {
27931 if (fFileBacked)
27932 {
27933 if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey))
27934 return false;
27935 }
27936 vchDefaultKey = vchPubKey;
27937 return true;
27938 }
27939
27940 bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut)
27941 {
27942 if (!pwallet->fFileBacked)
27943 return false;
27944 strWalletFileOut = pwallet->strWalletFile;
27945 return true;
27946 }
27947
27948 //
27949 // Mark old keypool keys as used,
27950 // and generate all new keys
27951 //
27952 bool CWallet::NewKeyPool()
27953 {
27954 CRITICAL_BLOCK(cs_wallet)
27955 {
27956 CWalletDB walletdb(strWalletFile);
27957 BOOST_FOREACH(int64 nIndex, setKeyPool)
27958 walletdb.ErasePool(nIndex);
27959 setKeyPool.clear();
27960
27961 if (IsLocked())
27962 return false;
27963
27964 int64 nKeys = max(GetArg("-keypool", 100), (int64)0);
27965 for (int i = 0; i < nKeys; i++)
27966 {
27967 int64 nIndex = i+1;
27968 walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey()));
27969 setKeyPool.insert(nIndex);
27970 }
27971 printf("CWallet::NewKeyPool wrote %"PRI64d" new keys\n", nKeys);
27972 }
27973 return true;
27974 }
27975
27976 bool CWallet::TopUpKeyPool()
27977 {
27978 CRITICAL_BLOCK(cs_wallet)
27979 {
27980 if (IsLocked())
27981 return false;
27982
27983 CWalletDB walletdb(strWalletFile);
27984
27985 // Top up key pool
27986 int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0);
27987 while (setKeyPool.size() < nTargetSize+1)
27988 {
27989 int64 nEnd = 1;
27990 if (!setKeyPool.empty())
27991 nEnd = *(--setKeyPool.end()) + 1;
27992 if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
27993 throw runtime_error("TopUpKeyPool() : writing generated key failed");
27994 setKeyPool.insert(nEnd);
27995 printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size());
27996 }
27997 }
27998 return true;
27999 }
28000
28001 void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
28002 {
28003 nIndex = -1;
28004 keypool.vchPubKey.clear();
28005 CRITICAL_BLOCK(cs_wallet)
28006 {
28007 if (!IsLocked())
28008 TopUpKeyPool();
28009
28010 // Get the oldest key
28011 if(setKeyPool.empty())
28012 return;
28013
28014 CWalletDB walletdb(strWalletFile);
28015
28016 nIndex = *(setKeyPool.begin());
28017 setKeyPool.erase(setKeyPool.begin());
28018 if (!walletdb.ReadPool(nIndex, keypool))
28019 throw runtime_error("ReserveKeyFromKeyPool() : read failed");
28020 if (!HaveKey(Hash160(keypool.vchPubKey)))
28021 throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
28022 assert(!keypool.vchPubKey.empty());
28023 printf("keypool reserve %"PRI64d"\n", nIndex);
28024 }
28025 }
28026
28027 void CWallet::KeepKey(int64 nIndex)
28028 {
28029 // Remove from key pool
28030 if (fFileBacked)
28031 {
28032 CWalletDB walletdb(strWalletFile);
28033 walletdb.ErasePool(nIndex);
28034 }
28035 printf("keypool keep %"PRI64d"\n", nIndex);
28036 }
28037
28038 void CWallet::ReturnKey(int64 nIndex)
28039 {
28040 // Return to key pool
28041 CRITICAL_BLOCK(cs_wallet)
28042 setKeyPool.insert(nIndex);
28043 printf("keypool return %"PRI64d"\n", nIndex);
28044 }
28045
28046 bool CWallet::GetKeyFromPool(vector<unsigned char>& result, bool fAllowReuse)
28047 {
28048 int64 nIndex = 0;
28049 CKeyPool keypool;
28050 CRITICAL_BLOCK(cs_wallet)
28051 {
28052 ReserveKeyFromKeyPool(nIndex, keypool);
28053 if (nIndex == -1)
28054 {
28055 if (fAllowReuse && !vchDefaultKey.empty())
28056 {
28057 result = vchDefaultKey;
28058 return true;
28059 }
28060 if (IsLocked()) return false;
28061 result = GenerateNewKey();
28062 return true;
28063 }
28064 KeepKey(nIndex);
28065 result = keypool.vchPubKey;
28066 }
28067 return true;
28068 }
28069
28070 int64 CWallet::GetOldestKeyPoolTime()
28071 {
28072 int64 nIndex = 0;
28073 CKeyPool keypool;
28074 ReserveKeyFromKeyPool(nIndex, keypool);
28075 if (nIndex == -1)
28076 return GetTime();
28077 ReturnKey(nIndex);
28078 return keypool.nTime;
28079 }
28080
28081 vector<unsigned char> CReserveKey::GetReservedKey()
28082 {
28083 if (nIndex == -1)
28084 {
28085 CKeyPool keypool;
28086 pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
28087 if (nIndex != -1)
28088 vchPubKey = keypool.vchPubKey;
28089 else
28090 {
28091 printf("CReserveKey::GetReservedKey(): Warning: using default key instead of a new key, top up your keypool.");
28092 vchPubKey = pwallet->vchDefaultKey;
28093 }
28094 }
28095 assert(!vchPubKey.empty());
28096 return vchPubKey;
28097 }
28098
28099 void CReserveKey::KeepKey()
28100 {
28101 if (nIndex != -1)
28102 pwallet->KeepKey(nIndex);
28103 nIndex = -1;
28104 vchPubKey.clear();
28105 }
28106
28107 void CReserveKey::ReturnKey()
28108 {
28109 if (nIndex != -1)
28110 pwallet->ReturnKey(nIndex);
28111 nIndex = -1;
28112 vchPubKey.clear();
28113 }
28114