diff options
Diffstat (limited to 'src/wallet.h')
-rw-r--r-- | src/wallet.h | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/src/wallet.h b/src/wallet.h new file mode 100644 index 0000000000..f9d2ea0989 --- /dev/null +++ b/src/wallet.h @@ -0,0 +1,441 @@ +// 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 "script.h" + +class CWalletTx; +class CReserveKey; +class CWalletDB; + +extern std::map<uint256, CWalletTx> mapWallet; +extern std::vector<uint256> vWalletUpdated; +extern CCriticalSection cs_mapWallet; + +extern std::map<uint256, int> mapRequestCount; +extern CCriticalSection cs_mapRequestCount; + +extern std::map<std::string, std::string> mapAddressBook; +extern CCriticalSection cs_mapAddressBook; + +extern std::vector<unsigned char> vchDefaultKey; +extern CKey keyUser; + +bool AddToWallet(const CWalletTx& wtxIn); +bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false); +bool EraseFromWallet(uint256 hash); +void WalletUpdateSpent(const COutPoint& prevout); +int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); +void ReacceptWalletTransactions(); +void ResendWalletTransactions(); +int64 GetBalance(); +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); + + + +// +// 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: + 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(); + } + + CWalletTx(const CMerkleTx& txIn) : CMerkleTx(txIn) + { + Init(); + } + + CWalletTx(const CTransaction& txIn) : CMerkleTx(txIn) + { + Init(); + } + + void Init() + { + 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(); + 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 = CTransaction::GetDebit(); + 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 = CTransaction::GetCredit(); + 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 += txout.GetCredit(); + 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 = CTransaction::GetChange(); + 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 (!ptx->IsFromMe()) + 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); + ) +}; + +#endif |