aboutsummaryrefslogtreecommitdiff
path: root/src/wallet.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet.h')
-rw-r--r--src/wallet.h611
1 files changed, 611 insertions, 0 deletions
diff --git a/src/wallet.h b/src/wallet.h
new file mode 100644
index 0000000000..69110a4afa
--- /dev/null
+++ b/src/wallet.h
@@ -0,0 +1,611 @@
+// Copyright (c) 2009-2011 Satoshi Nakamoto & Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file license.txt or http://www.opensource.org/licenses/mit-license.php.
+#ifndef BITCOIN_WALLET_H
+#define BITCOIN_WALLET_H
+
+#include "bignum.h"
+#include "key.h"
+#include "script.h"
+
+class CWalletTx;
+class CReserveKey;
+class CWalletDB;
+
+class CWallet : public CKeyStore
+{
+private:
+ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
+ bool SelectCoins(int64 nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
+
+
+public:
+ bool fFileBacked;
+ std::string strWalletFile;
+
+ std::set<int64> setKeyPool;
+ CCriticalSection cs_setKeyPool;
+
+ CWallet()
+ {
+ fFileBacked = false;
+ }
+ CWallet(std::string strWalletFileIn)
+ {
+ strWalletFile = strWalletFileIn;
+ fFileBacked = true;
+ }
+
+ mutable CCriticalSection cs_mapWallet;
+ std::map<uint256, CWalletTx> mapWallet;
+ std::vector<uint256> vWalletUpdated;
+
+ std::map<uint256, int> mapRequestCount;
+ mutable CCriticalSection cs_mapRequestCount;
+
+ std::map<std::string, std::string> mapAddressBook;
+ mutable CCriticalSection cs_mapAddressBook;
+
+ std::vector<unsigned char> vchDefaultKey;
+
+ bool AddKey(const CKey& key);
+ bool AddToWallet(const CWalletTx& wtxIn);
+ bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false);
+ bool EraseFromWallet(uint256 hash);
+ void WalletUpdateSpent(const CTransaction& prevout);
+ int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
+ void ReacceptWalletTransactions();
+ void ResendWalletTransactions();
+ int64 GetBalance() const;
+ bool CreateTransaction(const std::vector<std::pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet);
+ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet);
+ bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
+ bool BroadcastTransaction(CWalletTx& wtxNew);
+ std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
+ std::string SendMoneyToBitcoinAddress(std::string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
+
+ void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool);
+ void KeepKey(int64 nIndex);
+ void ReturnKey(int64 nIndex);
+ std::vector<unsigned char> GetKeyFromKeyPool();
+ int64 GetOldestKeyPoolTime();
+
+ bool IsMine(const CTxIn& txin) const;
+ int64 GetDebit(const CTxIn& txin) const;
+ bool IsMine(const CTxOut& txout) const
+ {
+ return ::IsMine(*this, txout.scriptPubKey);
+ }
+ int64 GetCredit(const CTxOut& txout) const
+ {
+ if (!MoneyRange(txout.nValue))
+ throw std::runtime_error("CWallet::GetCredit() : value out of range");
+ return (IsMine(txout) ? txout.nValue : 0);
+ }
+ bool IsChange(const CTxOut& txout) const
+ {
+ std::vector<unsigned char> vchPubKey;
+ if (ExtractPubKey(txout.scriptPubKey, this, vchPubKey))
+ CRITICAL_BLOCK(cs_mapAddressBook)
+ if (!mapAddressBook.count(PubKeyToAddress(vchPubKey)))
+ return true;
+ return false;
+ }
+ int64 GetChange(const CTxOut& txout) const
+ {
+ if (!MoneyRange(txout.nValue))
+ throw std::runtime_error("CWallet::GetChange() : value out of range");
+ return (IsChange(txout) ? txout.nValue : 0);
+ }
+ bool IsMine(const CTransaction& tx) const
+ {
+ BOOST_FOREACH(const CTxOut& txout, tx.vout)
+ if (IsMine(txout))
+ return true;
+ return false;
+ }
+ bool IsFromMe(const CTransaction& tx) const
+ {
+ return (GetDebit(tx) > 0);
+ }
+ int64 GetDebit(const CTransaction& tx) const
+ {
+ int64 nDebit = 0;
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ {
+ nDebit += GetDebit(txin);
+ if (!MoneyRange(nDebit))
+ throw std::runtime_error("CWallet::GetDebit() : value out of range");
+ }
+ return nDebit;
+ }
+ int64 GetCredit(const CTransaction& tx) const
+ {
+ int64 nCredit = 0;
+ BOOST_FOREACH(const CTxOut& txout, tx.vout)
+ {
+ nCredit += GetCredit(txout);
+ if (!MoneyRange(nCredit))
+ throw std::runtime_error("CWallet::GetCredit() : value out of range");
+ }
+ return nCredit;
+ }
+ int64 GetChange(const CTransaction& tx) const
+ {
+ int64 nChange = 0;
+ BOOST_FOREACH(const CTxOut& txout, tx.vout)
+ {
+ nChange += GetChange(txout);
+ if (!MoneyRange(nChange))
+ throw std::runtime_error("CWallet::GetChange() : value out of range");
+ }
+ return nChange;
+ }
+ void SetBestChain(const CBlockLocator& loc)
+ {
+ CWalletDB walletdb(strWalletFile);
+ walletdb.WriteBestBlock(loc);
+ }
+
+ bool LoadWallet(bool& fFirstRunRet);
+// bool BackupWallet(const std::string& strDest);
+ bool SetAddressBookName(const std::string& strAddress, const std::string& strName);
+ bool EraseAddressBookName(const std::string& strAddress);
+ std::string GetDefaultAddress();
+ bool SetDefaultAddress(const std::string& strAddress);
+
+ void UpdatedTransaction(const uint256 &hashTx)
+ {
+ CRITICAL_BLOCK(cs_mapWallet)
+ vWalletUpdated.push_back(hashTx);
+ }
+
+ void PrintWallet(const CBlock& block);
+
+ void Inventory(const uint256 &hash)
+ {
+ CRITICAL_BLOCK(cs_mapRequestCount)
+ {
+ std::map<uint256, int>::iterator mi = mapRequestCount.find(hash);
+ if (mi != mapRequestCount.end())
+ (*mi).second++;
+ }
+ }
+
+ bool GetTransaction(const uint256 &hashTx, CWalletTx& wtx);
+
+};
+
+
+class CReserveKey
+{
+protected:
+ CWallet* pwallet;
+ int64 nIndex;
+ std::vector<unsigned char> vchPubKey;
+public:
+ CReserveKey(CWallet* pwalletIn)
+ {
+ nIndex = -1;
+ pwallet = pwalletIn;
+ }
+
+ ~CReserveKey()
+ {
+ if (!fShutdown)
+ ReturnKey();
+ }
+
+ void ReturnKey();
+ std::vector<unsigned char> GetReservedKey();
+ void KeepKey();
+};
+
+
+//
+// A transaction with a bunch of additional info that only the owner cares
+// about. It includes any unrecorded transactions needed to link it back
+// to the block chain.
+//
+class CWalletTx : public CMerkleTx
+{
+public:
+ const CWallet* pwallet;
+
+ std::vector<CMerkleTx> vtxPrev;
+ std::map<std::string, std::string> mapValue;
+ std::vector<std::pair<std::string, std::string> > vOrderForm;
+ unsigned int fTimeReceivedIsTxTime;
+ unsigned int nTimeReceived; // time received by this node
+ char fFromMe;
+ std::string strFromAccount;
+ std::vector<char> vfSpent;
+
+ // memory only
+ mutable char fDebitCached;
+ mutable char fCreditCached;
+ mutable char fAvailableCreditCached;
+ mutable char fChangeCached;
+ mutable int64 nDebitCached;
+ mutable int64 nCreditCached;
+ mutable int64 nAvailableCreditCached;
+ mutable int64 nChangeCached;
+
+ // memory only UI hints
+ mutable unsigned int nTimeDisplayed;
+ mutable int nLinesDisplayed;
+ mutable char fConfirmedDisplayed;
+
+ CWalletTx()
+ {
+ Init(NULL);
+ }
+
+ CWalletTx(const CWallet* pwalletIn)
+ {
+ Init(pwalletIn);
+ }
+
+ CWalletTx(const CWallet* pwalletIn, const CMerkleTx& txIn) : CMerkleTx(txIn)
+ {
+ Init(pwalletIn);
+ }
+
+ CWalletTx(const CWallet* pwalletIn, const CTransaction& txIn) : CMerkleTx(txIn)
+ {
+ Init(pwalletIn);
+ }
+
+ void Init(const CWallet* pwalletIn)
+ {
+ pwallet = pwalletIn;
+ vtxPrev.clear();
+ mapValue.clear();
+ vOrderForm.clear();
+ fTimeReceivedIsTxTime = false;
+ nTimeReceived = 0;
+ fFromMe = false;
+ strFromAccount.clear();
+ vfSpent.clear();
+ fDebitCached = false;
+ fCreditCached = false;
+ fAvailableCreditCached = false;
+ fChangeCached = false;
+ nDebitCached = 0;
+ nCreditCached = 0;
+ nAvailableCreditCached = 0;
+ nChangeCached = 0;
+ nTimeDisplayed = 0;
+ nLinesDisplayed = 0;
+ fConfirmedDisplayed = false;
+ }
+
+ IMPLEMENT_SERIALIZE
+ (
+ CWalletTx* pthis = const_cast<CWalletTx*>(this);
+ if (fRead)
+ pthis->Init(NULL);
+ char fSpent = false;
+
+ if (!fRead)
+ {
+ pthis->mapValue["fromaccount"] = pthis->strFromAccount;
+
+ std::string str;
+ BOOST_FOREACH(char f, vfSpent)
+ {
+ str += (f ? '1' : '0');
+ if (f)
+ fSpent = true;
+ }
+ pthis->mapValue["spent"] = str;
+ }
+
+ nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion,ser_action);
+ READWRITE(vtxPrev);
+ READWRITE(mapValue);
+ READWRITE(vOrderForm);
+ READWRITE(fTimeReceivedIsTxTime);
+ READWRITE(nTimeReceived);
+ READWRITE(fFromMe);
+ READWRITE(fSpent);
+
+ if (fRead)
+ {
+ pthis->strFromAccount = pthis->mapValue["fromaccount"];
+
+ if (mapValue.count("spent"))
+ BOOST_FOREACH(char c, pthis->mapValue["spent"])
+ pthis->vfSpent.push_back(c != '0');
+ else
+ pthis->vfSpent.assign(vout.size(), fSpent);
+ }
+
+ pthis->mapValue.erase("fromaccount");
+ pthis->mapValue.erase("version");
+ pthis->mapValue.erase("spent");
+ )
+
+ // marks certain txout's as spent
+ // returns true if any update took place
+ bool UpdateSpent(const std::vector<char>& vfNewSpent)
+ {
+ bool fReturn = false;
+ for (int i=0; i < vfNewSpent.size(); i++)
+ {
+ if (i == vfSpent.size())
+ break;
+
+ if (vfNewSpent[i] && !vfSpent[i])
+ {
+ vfSpent[i] = true;
+ fReturn = true;
+ fAvailableCreditCached = false;
+ }
+ }
+ return fReturn;
+ }
+
+ void MarkDirty()
+ {
+ fCreditCached = false;
+ fAvailableCreditCached = false;
+ fDebitCached = false;
+ fChangeCached = false;
+ }
+
+ void MarkSpent(unsigned int nOut)
+ {
+ if (nOut >= vout.size())
+ throw std::runtime_error("CWalletTx::MarkSpent() : nOut out of range");
+ vfSpent.resize(vout.size());
+ if (!vfSpent[nOut])
+ {
+ vfSpent[nOut] = true;
+ fAvailableCreditCached = false;
+ }
+ }
+
+ bool IsSpent(unsigned int nOut) const
+ {
+ if (nOut >= vout.size())
+ throw std::runtime_error("CWalletTx::IsSpent() : nOut out of range");
+ if (nOut >= vfSpent.size())
+ return false;
+ return (!!vfSpent[nOut]);
+ }
+
+ int64 GetDebit() const
+ {
+ if (vin.empty())
+ return 0;
+ if (fDebitCached)
+ return nDebitCached;
+ nDebitCached = pwallet->GetDebit(*this);
+ fDebitCached = true;
+ return nDebitCached;
+ }
+
+ int64 GetCredit(bool fUseCache=true) const
+ {
+ // Must wait until coinbase is safely deep enough in the chain before valuing it
+ if (IsCoinBase() && GetBlocksToMaturity() > 0)
+ return 0;
+
+ // GetBalance can assume transactions in mapWallet won't change
+ if (fUseCache && fCreditCached)
+ return nCreditCached;
+ nCreditCached = pwallet->GetCredit(*this);
+ fCreditCached = true;
+ return nCreditCached;
+ }
+
+ int64 GetAvailableCredit(bool fUseCache=true) const
+ {
+ // Must wait until coinbase is safely deep enough in the chain before valuing it
+ if (IsCoinBase() && GetBlocksToMaturity() > 0)
+ return 0;
+
+ if (fUseCache && fAvailableCreditCached)
+ return nAvailableCreditCached;
+
+ int64 nCredit = 0;
+ for (int i = 0; i < vout.size(); i++)
+ {
+ if (!IsSpent(i))
+ {
+ const CTxOut &txout = vout[i];
+ nCredit += pwallet->GetCredit(txout);
+ if (!MoneyRange(nCredit))
+ throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range");
+ }
+ }
+
+ nAvailableCreditCached = nCredit;
+ fAvailableCreditCached = true;
+ return nCredit;
+ }
+
+
+ int64 GetChange() const
+ {
+ if (fChangeCached)
+ return nChangeCached;
+ nChangeCached = pwallet->GetChange(*this);
+ fChangeCached = true;
+ return nChangeCached;
+ }
+
+ void GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, std::list<std::pair<std::string /* address */, int64> >& listReceived,
+ std::list<std::pair<std::string /* address */, int64> >& listSent, int64& nFee, std::string& strSentAccount) const;
+
+ void GetAccountAmounts(const std::string& strAccount, int64& nGenerated, int64& nReceived,
+ int64& nSent, int64& nFee) const;
+
+ bool IsFromMe() const
+ {
+ return (GetDebit() > 0);
+ }
+
+ bool IsConfirmed() const
+ {
+ // Quick answer in most cases
+ if (!IsFinal())
+ return false;
+ if (GetDepthInMainChain() >= 1)
+ return true;
+ if (!IsFromMe()) // using wtx's cached debit
+ return false;
+
+ // If no confirmations but it's from us, we can still
+ // consider it confirmed if all dependencies are confirmed
+ std::map<uint256, const CMerkleTx*> mapPrev;
+ std::vector<const CMerkleTx*> vWorkQueue;
+ vWorkQueue.reserve(vtxPrev.size()+1);
+ vWorkQueue.push_back(this);
+ for (int i = 0; i < vWorkQueue.size(); i++)
+ {
+ const CMerkleTx* ptx = vWorkQueue[i];
+
+ if (!ptx->IsFinal())
+ return false;
+ if (ptx->GetDepthInMainChain() >= 1)
+ continue;
+ if (!pwallet->IsFromMe(*ptx))
+ return false;
+
+ if (mapPrev.empty())
+ BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
+ mapPrev[tx.GetHash()] = &tx;
+
+ BOOST_FOREACH(const CTxIn& txin, ptx->vin)
+ {
+ if (!mapPrev.count(txin.prevout.hash))
+ return false;
+ vWorkQueue.push_back(mapPrev[txin.prevout.hash]);
+ }
+ }
+ return true;
+ }
+
+ bool WriteToDisk();
+
+ int64 GetTxTime() const;
+ int GetRequestCount() const;
+
+ void AddSupportingTransactions(CTxDB& txdb);
+
+ bool AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs=true);
+ bool AcceptWalletTransaction();
+
+ void RelayWalletTransaction(CTxDB& txdb);
+ void RelayWalletTransaction();
+};
+
+
+//
+// Private key that includes an expiration date in case it never gets used.
+//
+class CWalletKey
+{
+public:
+ CPrivKey vchPrivKey;
+ int64 nTimeCreated;
+ int64 nTimeExpires;
+ std::string strComment;
+ //// todo: add something to note what created it (user, getnewaddress, change)
+ //// maybe should have a map<string, string> property map
+
+ CWalletKey(int64 nExpires=0)
+ {
+ nTimeCreated = (nExpires ? GetTime() : 0);
+ nTimeExpires = nExpires;
+ }
+
+ IMPLEMENT_SERIALIZE
+ (
+ if (!(nType & SER_GETHASH))
+ READWRITE(nVersion);
+ READWRITE(vchPrivKey);
+ READWRITE(nTimeCreated);
+ READWRITE(nTimeExpires);
+ READWRITE(strComment);
+ )
+};
+
+
+
+
+
+
+//
+// Account information.
+// Stored in wallet with key "acc"+string account name
+//
+class CAccount
+{
+public:
+ std::vector<unsigned char> vchPubKey;
+
+ CAccount()
+ {
+ SetNull();
+ }
+
+ void SetNull()
+ {
+ vchPubKey.clear();
+ }
+
+ IMPLEMENT_SERIALIZE
+ (
+ if (!(nType & SER_GETHASH))
+ READWRITE(nVersion);
+ READWRITE(vchPubKey);
+ )
+};
+
+
+
+//
+// Internal transfers.
+// Database key is acentry<account><counter>
+//
+class CAccountingEntry
+{
+public:
+ std::string strAccount;
+ int64 nCreditDebit;
+ int64 nTime;
+ std::string strOtherAccount;
+ std::string strComment;
+
+ CAccountingEntry()
+ {
+ SetNull();
+ }
+
+ void SetNull()
+ {
+ nCreditDebit = 0;
+ nTime = 0;
+ strAccount.clear();
+ strOtherAccount.clear();
+ strComment.clear();
+ }
+
+ IMPLEMENT_SERIALIZE
+ (
+ if (!(nType & SER_GETHASH))
+ READWRITE(nVersion);
+ // Note: strAccount is serialized as part of the key, not here.
+ READWRITE(nCreditDebit);
+ READWRITE(nTime);
+ READWRITE(strOtherAccount);
+ READWRITE(strComment);
+ )
+};
+
+bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
+
+#endif