]>
Commit | Line | Data |
---|---|---|
b2120e22 | 1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
db0e8ccd | 2 | // Copyright (c) 2009-2013 The Bitcoin developers |
e8ef3da7 | 3 | // Distributed under the MIT/X11 software license, see the accompanying |
3a25a2b9 | 4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
e8ef3da7 WL |
5 | #ifndef BITCOIN_WALLET_H |
6 | #define BITCOIN_WALLET_H | |
7 | ||
336fe971 EL |
8 | #include "walletdb.h" |
9 | ||
9c7722b7 LD |
10 | #include <string> |
11 | #include <vector> | |
12 | ||
13 | #include <stdlib.h> | |
14 | ||
ed6d0b5f | 15 | #include "main.h" |
e8ef3da7 | 16 | #include "key.h" |
2a45a494 | 17 | #include "keystore.h" |
e8ef3da7 | 18 | #include "script.h" |
ab1b288f | 19 | #include "ui_interface.h" |
9c7722b7 | 20 | #include "util.h" |
e8ef3da7 | 21 | |
c3f95ef1 | 22 | class CAccountingEntry; |
e8ef3da7 WL |
23 | class CWalletTx; |
24 | class CReserveKey; | |
9b0369c7 | 25 | class COutput; |
336fe971 | 26 | class CWalletDB; |
e8ef3da7 | 27 | |
6b8de05d | 28 | /** (client) version numbers for particular wallet features */ |
439e1497 PW |
29 | enum WalletFeature |
30 | { | |
31 | FEATURE_BASE = 10500, // the earliest version new wallets supports (only useful for getinfo's clientversion output) | |
32 | ||
33 | FEATURE_WALLETCRYPT = 40000, // wallet encryption | |
34 | FEATURE_COMPRPUBKEY = 60000, // compressed public keys | |
35 | ||
36 | FEATURE_LATEST = 60000 | |
37 | }; | |
38 | ||
ed6d0b5f PW |
39 | |
40 | /** A key pool entry */ | |
41 | class CKeyPool | |
42 | { | |
43 | public: | |
44 | int64 nTime; | |
fd61d6f5 | 45 | CPubKey vchPubKey; |
ed6d0b5f PW |
46 | |
47 | CKeyPool() | |
48 | { | |
49 | nTime = GetTime(); | |
50 | } | |
51 | ||
fd61d6f5 | 52 | CKeyPool(const CPubKey& vchPubKeyIn) |
ed6d0b5f PW |
53 | { |
54 | nTime = GetTime(); | |
55 | vchPubKey = vchPubKeyIn; | |
56 | } | |
57 | ||
58 | IMPLEMENT_SERIALIZE | |
59 | ( | |
60 | if (!(nType & SER_GETHASH)) | |
61 | READWRITE(nVersion); | |
62 | READWRITE(nTime); | |
63 | READWRITE(vchPubKey); | |
64 | ) | |
65 | }; | |
66 | ||
61885513 GA |
67 | /** Address book data */ |
68 | class CAddressBookData | |
69 | { | |
70 | public: | |
71 | std::string name; | |
a41d5fe0 | 72 | std::string purpose; |
61885513 GA |
73 | |
74 | CAddressBookData() | |
75 | { | |
a41d5fe0 | 76 | purpose = "unknown"; |
61885513 | 77 | } |
61885513 GA |
78 | }; |
79 | ||
6b8de05d PW |
80 | /** A CWallet is an extension of a keystore, which also maintains a set of transactions and balances, |
81 | * and provides the ability to create new transactions. | |
82 | */ | |
00588c3f | 83 | class CWallet : public CCryptoKeyStore, public CWalletInterface |
e8ef3da7 WL |
84 | { |
85 | private: | |
bde280b9 | 86 | bool SelectCoins(int64 nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const; |
e8ef3da7 | 87 | |
96f34cd5 | 88 | CWalletDB *pwalletdbEncryption; |
e8ef3da7 | 89 | |
439e1497 | 90 | // the current wallet version: clients below this version are not able to load the wallet |
0b807a41 PW |
91 | int nWalletVersion; |
92 | ||
e7494052 | 93 | // the maximum wallet format version: memory-only variable that specifies to what version this wallet may be upgraded |
439e1497 PW |
94 | int nWalletMaxVersion; |
95 | ||
203d1ae6 LD |
96 | int64 nNextResend; |
97 | int64 nLastResend; | |
98 | ||
e8ef3da7 | 99 | public: |
6cc4a62c GA |
100 | mutable CCriticalSection cs_wallet; |
101 | ||
e8ef3da7 WL |
102 | bool fFileBacked; |
103 | std::string strWalletFile; | |
104 | ||
bde280b9 | 105 | std::set<int64> setKeyPool; |
4addb2c0 | 106 | std::map<CKeyID, CKeyMetadata> mapKeyMetadata; |
0b807a41 | 107 | |
4e87d341 MC |
108 | typedef std::map<unsigned int, CMasterKey> MasterKeyMap; |
109 | MasterKeyMap mapMasterKeys; | |
110 | unsigned int nMasterKeyMaxID; | |
111 | ||
e8ef3da7 WL |
112 | CWallet() |
113 | { | |
439e1497 PW |
114 | nWalletVersion = FEATURE_BASE; |
115 | nWalletMaxVersion = FEATURE_BASE; | |
e8ef3da7 | 116 | fFileBacked = false; |
4e87d341 | 117 | nMasterKeyMaxID = 0; |
96f34cd5 | 118 | pwalletdbEncryption = NULL; |
da7b8c12 | 119 | nOrderPosNext = 0; |
c4316fef PW |
120 | nNextResend = 0; |
121 | nLastResend = 0; | |
e8ef3da7 WL |
122 | } |
123 | CWallet(std::string strWalletFileIn) | |
124 | { | |
439e1497 PW |
125 | nWalletVersion = FEATURE_BASE; |
126 | nWalletMaxVersion = FEATURE_BASE; | |
e8ef3da7 WL |
127 | strWalletFile = strWalletFileIn; |
128 | fFileBacked = true; | |
4e87d341 | 129 | nMasterKeyMaxID = 0; |
96f34cd5 | 130 | pwalletdbEncryption = NULL; |
da7b8c12 | 131 | nOrderPosNext = 0; |
c4316fef PW |
132 | nNextResend = 0; |
133 | nLastResend = 0; | |
e8ef3da7 WL |
134 | } |
135 | ||
e8ef3da7 | 136 | std::map<uint256, CWalletTx> mapWallet; |
9c7722b7 | 137 | int64 nOrderPosNext; |
e8ef3da7 | 138 | std::map<uint256, int> mapRequestCount; |
e8ef3da7 | 139 | |
61885513 | 140 | std::map<CTxDestination, CAddressBookData> mapAddressBook; |
e8ef3da7 | 141 | |
fd61d6f5 | 142 | CPubKey vchDefaultKey; |
e8ef3da7 | 143 | |
fdbb537d JG |
144 | std::set<COutPoint> setLockedCoins; |
145 | ||
3869fb89 JG |
146 | int64 nTimeFirstKey; |
147 | ||
439e1497 PW |
148 | // check whether we are allowed to upgrade (or already support) to the named feature |
149 | bool CanSupportFeature(enum WalletFeature wf) { return nWalletMaxVersion >= wf; } | |
150 | ||
a2709fad | 151 | void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true) const; |
9b0369c7 | 152 | bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const; |
fdbb537d JG |
153 | bool IsLockedCoin(uint256 hash, unsigned int n) const; |
154 | void LockCoin(COutPoint& output); | |
155 | void UnlockCoin(COutPoint& output); | |
156 | void UnlockAllCoins(); | |
157 | void ListLockedCoins(std::vector<COutPoint>& vOutpts); | |
9b0369c7 | 158 | |
acd65016 | 159 | // keystore implementation |
9976cf07 | 160 | // Generate a new key |
fd61d6f5 | 161 | CPubKey GenerateNewKey(); |
d825e6a3 | 162 | // Adds a key to the store, and saves it to disk. |
4addb2c0 | 163 | bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey); |
d825e6a3 | 164 | // Adds a key to the store, without saving it to disk (used by LoadWallet) |
dfa23b94 | 165 | bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); } |
4addb2c0 PW |
166 | // Load metadata (used by LoadWallet) |
167 | bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata); | |
d825e6a3 | 168 | |
439e1497 | 169 | bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; } |
0b807a41 | 170 | |
d825e6a3 | 171 | // Adds an encrypted key to the store, and saves it to disk. |
4addb2c0 | 172 | bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); |
d825e6a3 | 173 | // Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) |
2f15e86a | 174 | bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); |
922e8e29 GA |
175 | bool AddCScript(const CScript& redeemScript); |
176 | bool LoadCScript(const CScript& redeemScript) { return CCryptoKeyStore::AddCScript(redeemScript); } | |
4e87d341 | 177 | |
94f778bd DN |
178 | bool Unlock(const SecureString& strWalletPassphrase); |
179 | bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); | |
180 | bool EncryptWallet(const SecureString& strWalletPassphrase); | |
acd65016 | 181 | |
434e4273 PW |
182 | void GetKeyBirthTimes(std::map<CKeyID, int64> &mapKeyBirth) const; |
183 | ||
da7b8c12 LD |
184 | /** Increment the next transaction order id |
185 | @return next transaction order id | |
186 | */ | |
4291e8fe | 187 | int64 IncOrderPosNext(CWalletDB *pwalletdb = NULL); |
da7b8c12 | 188 | |
c3f95ef1 LD |
189 | typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair; |
190 | typedef std::multimap<int64, TxPair > TxItems; | |
ddb709e9 LD |
191 | |
192 | /** Get the wallet's activity log | |
193 | @return multimap of ordered transactions and accounting entries | |
194 | @warning Returned pointers are *only* valid within the scope of passed acentries | |
195 | */ | |
196 | TxItems OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount = ""); | |
c3f95ef1 | 197 | |
95d888a6 | 198 | void MarkDirty(); |
e8ef3da7 | 199 | bool AddToWallet(const CWalletTx& wtxIn); |
00588c3f PW |
200 | void SyncTransaction(const uint256 &hash, const CTransaction& tx, const CBlock* pblock); |
201 | bool AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate); | |
202 | void EraseFromWallet(const uint256 &hash); | |
e8ef3da7 WL |
203 | void WalletUpdateSpent(const CTransaction& prevout); |
204 | int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); | |
205 | void ReacceptWalletTransactions(); | |
206 | void ResendWalletTransactions(); | |
bde280b9 WL |
207 | int64 GetBalance() const; |
208 | int64 GetUnconfirmedBalance() const; | |
8fdb7e10 | 209 | int64 GetImmatureBalance() const; |
1f00f4e9 GA |
210 | bool CreateTransaction(const std::vector<std::pair<CScript, int64> >& vecSend, |
211 | CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason); | |
212 | bool CreateTransaction(CScript scriptPubKey, int64 nValue, | |
213 | CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet, std::string& strFailReason); | |
e8ef3da7 | 214 | bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); |
bde280b9 | 215 | std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); |
10254401 | 216 | std::string SendMoneyToDestination(const CTxDestination &address, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); |
e8ef3da7 | 217 | |
37971fcc | 218 | bool NewKeyPool(); |
13dd2d09 | 219 | bool TopUpKeyPool(unsigned int kpSize = 0); |
bde280b9 WL |
220 | int64 AddReserveKey(const CKeyPool& keypool); |
221 | void ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool); | |
222 | void KeepKey(int64 nIndex); | |
223 | void ReturnKey(int64 nIndex); | |
71ac5052 | 224 | bool GetKeyFromPool(CPubKey &key); |
bde280b9 | 225 | int64 GetOldestKeyPoolTime(); |
434e4273 | 226 | void GetAllReserveKeys(std::set<CKeyID>& setAddress) const; |
e8ef3da7 | 227 | |
b1093efa GM |
228 | std::set< std::set<CTxDestination> > GetAddressGroupings(); |
229 | std::map<CTxDestination, int64> GetAddressBalances(); | |
22dfd735 | 230 | |
3624356e GA |
231 | std::set<CTxDestination> GetAccountAddresses(std::string strAccount) const; |
232 | ||
e8ef3da7 | 233 | bool IsMine(const CTxIn& txin) const; |
bde280b9 | 234 | int64 GetDebit(const CTxIn& txin) const; |
e8ef3da7 WL |
235 | bool IsMine(const CTxOut& txout) const |
236 | { | |
237 | return ::IsMine(*this, txout.scriptPubKey); | |
238 | } | |
bde280b9 | 239 | int64 GetCredit(const CTxOut& txout) const |
e8ef3da7 WL |
240 | { |
241 | if (!MoneyRange(txout.nValue)) | |
242 | throw std::runtime_error("CWallet::GetCredit() : value out of range"); | |
243 | return (IsMine(txout) ? txout.nValue : 0); | |
244 | } | |
e679ec96 | 245 | bool IsChange(const CTxOut& txout) const; |
bde280b9 | 246 | int64 GetChange(const CTxOut& txout) const |
e8ef3da7 WL |
247 | { |
248 | if (!MoneyRange(txout.nValue)) | |
249 | throw std::runtime_error("CWallet::GetChange() : value out of range"); | |
250 | return (IsChange(txout) ? txout.nValue : 0); | |
251 | } | |
252 | bool IsMine(const CTransaction& tx) const | |
253 | { | |
254 | BOOST_FOREACH(const CTxOut& txout, tx.vout) | |
255 | if (IsMine(txout)) | |
256 | return true; | |
257 | return false; | |
258 | } | |
259 | bool IsFromMe(const CTransaction& tx) const | |
260 | { | |
261 | return (GetDebit(tx) > 0); | |
262 | } | |
bde280b9 | 263 | int64 GetDebit(const CTransaction& tx) const |
e8ef3da7 | 264 | { |
bde280b9 | 265 | int64 nDebit = 0; |
e8ef3da7 WL |
266 | BOOST_FOREACH(const CTxIn& txin, tx.vin) |
267 | { | |
268 | nDebit += GetDebit(txin); | |
269 | if (!MoneyRange(nDebit)) | |
270 | throw std::runtime_error("CWallet::GetDebit() : value out of range"); | |
271 | } | |
272 | return nDebit; | |
273 | } | |
bde280b9 | 274 | int64 GetCredit(const CTransaction& tx) const |
e8ef3da7 | 275 | { |
bde280b9 | 276 | int64 nCredit = 0; |
e8ef3da7 WL |
277 | BOOST_FOREACH(const CTxOut& txout, tx.vout) |
278 | { | |
279 | nCredit += GetCredit(txout); | |
280 | if (!MoneyRange(nCredit)) | |
281 | throw std::runtime_error("CWallet::GetCredit() : value out of range"); | |
282 | } | |
283 | return nCredit; | |
284 | } | |
bde280b9 | 285 | int64 GetChange(const CTransaction& tx) const |
e8ef3da7 | 286 | { |
bde280b9 | 287 | int64 nChange = 0; |
e8ef3da7 WL |
288 | BOOST_FOREACH(const CTxOut& txout, tx.vout) |
289 | { | |
290 | nChange += GetChange(txout); | |
291 | if (!MoneyRange(nChange)) | |
292 | throw std::runtime_error("CWallet::GetChange() : value out of range"); | |
293 | } | |
294 | return nChange; | |
295 | } | |
ed6d0b5f | 296 | void SetBestChain(const CBlockLocator& loc); |
e8ef3da7 | 297 | |
eed1785f | 298 | DBErrors LoadWallet(bool& fFirstRunRet); |
ae3d0aba | 299 | |
a41d5fe0 | 300 | bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose); |
ae3d0aba | 301 | |
a41d5fe0 | 302 | bool DelAddressBook(const CTxDestination& address); |
e8ef3da7 | 303 | |
fe4a6550 | 304 | void UpdatedTransaction(const uint256 &hashTx); |
e8ef3da7 | 305 | |
e8ef3da7 WL |
306 | void Inventory(const uint256 &hash) |
307 | { | |
e8ef3da7 | 308 | { |
f8dcd5ca | 309 | LOCK(cs_wallet); |
e8ef3da7 WL |
310 | std::map<uint256, int>::iterator mi = mapRequestCount.find(hash); |
311 | if (mi != mapRequestCount.end()) | |
312 | (*mi).second++; | |
313 | } | |
314 | } | |
315 | ||
13dd2d09 | 316 | unsigned int GetKeyPoolSize() |
4e87d341 MC |
317 | { |
318 | return setKeyPool.size(); | |
319 | } | |
320 | ||
fd61d6f5 | 321 | bool SetDefaultKey(const CPubKey &vchPubKey); |
0b807a41 | 322 | |
439e1497 PW |
323 | // signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower |
324 | bool SetMinVersion(enum WalletFeature, CWalletDB* pwalletdbIn = NULL, bool fExplicit = false); | |
325 | ||
326 | // change which version we're allowed to upgrade to (note that this does not immediately imply upgrading to that format) | |
327 | bool SetMaxVersion(int nVersion); | |
328 | ||
329 | // get the current wallet format (the oldest client version guaranteed to understand this wallet) | |
330 | int GetVersion() { return nWalletVersion; } | |
ab1b288f WL |
331 | |
332 | /** Address book entry changed. | |
333 | * @note called with lock cs_wallet held. | |
334 | */ | |
dcd0b077 WL |
335 | boost::signals2::signal<void (CWallet *wallet, const CTxDestination |
336 | &address, const std::string &label, bool isMine, | |
337 | const std::string &purpose, | |
338 | ChangeType status)> NotifyAddressBookChanged; | |
ab1b288f WL |
339 | |
340 | /** Wallet transaction added, removed or updated. | |
341 | * @note called with lock cs_wallet held. | |
342 | */ | |
dcd0b077 WL |
343 | boost::signals2::signal<void (CWallet *wallet, const uint256 &hashTx, |
344 | ChangeType status)> NotifyTransactionChanged; | |
e8ef3da7 WL |
345 | }; |
346 | ||
6b8de05d | 347 | /** A key allocated from the key pool. */ |
e8ef3da7 WL |
348 | class CReserveKey |
349 | { | |
350 | protected: | |
351 | CWallet* pwallet; | |
bde280b9 | 352 | int64 nIndex; |
fd61d6f5 | 353 | CPubKey vchPubKey; |
e8ef3da7 WL |
354 | public: |
355 | CReserveKey(CWallet* pwalletIn) | |
356 | { | |
357 | nIndex = -1; | |
358 | pwallet = pwalletIn; | |
359 | } | |
360 | ||
361 | ~CReserveKey() | |
362 | { | |
b31499ec | 363 | ReturnKey(); |
e8ef3da7 WL |
364 | } |
365 | ||
366 | void ReturnKey(); | |
360cfe14 | 367 | bool GetReservedKey(CPubKey &pubkey); |
e8ef3da7 WL |
368 | void KeepKey(); |
369 | }; | |
370 | ||
371 | ||
9c7722b7 LD |
372 | typedef std::map<std::string, std::string> mapValue_t; |
373 | ||
374 | ||
bdab0cf5 | 375 | static void ReadOrderPos(int64& nOrderPos, mapValue_t& mapValue) |
9c7722b7 LD |
376 | { |
377 | if (!mapValue.count("n")) | |
378 | { | |
379 | nOrderPos = -1; // TODO: calculate elsewhere | |
380 | return; | |
381 | } | |
382 | nOrderPos = atoi64(mapValue["n"].c_str()); | |
383 | } | |
384 | ||
385 | ||
bdab0cf5 | 386 | static void WriteOrderPos(const int64& nOrderPos, mapValue_t& mapValue) |
9c7722b7 LD |
387 | { |
388 | if (nOrderPos == -1) | |
389 | return; | |
390 | mapValue["n"] = i64tostr(nOrderPos); | |
391 | } | |
392 | ||
393 | ||
ea0796bd | 394 | /** A transaction with a bunch of additional info that only the owner cares about. |
6b8de05d PW |
395 | * It includes any unrecorded transactions needed to link it back to the block chain. |
396 | */ | |
e8ef3da7 WL |
397 | class CWalletTx : public CMerkleTx |
398 | { | |
4c6e2295 | 399 | private: |
e8ef3da7 WL |
400 | const CWallet* pwallet; |
401 | ||
4c6e2295 | 402 | public: |
e8ef3da7 | 403 | std::vector<CMerkleTx> vtxPrev; |
9c7722b7 | 404 | mapValue_t mapValue; |
e8ef3da7 WL |
405 | std::vector<std::pair<std::string, std::string> > vOrderForm; |
406 | unsigned int fTimeReceivedIsTxTime; | |
407 | unsigned int nTimeReceived; // time received by this node | |
c3f95ef1 | 408 | unsigned int nTimeSmart; |
e8ef3da7 WL |
409 | char fFromMe; |
410 | std::string strFromAccount; | |
d825e6a3 | 411 | std::vector<char> vfSpent; // which outputs are already spent |
9c7722b7 | 412 | int64 nOrderPos; // position in ordered transaction list |
e8ef3da7 WL |
413 | |
414 | // memory only | |
cdcc319c WL |
415 | mutable bool fDebitCached; |
416 | mutable bool fCreditCached; | |
966a0e8c | 417 | mutable bool fImmatureCreditCached; |
cdcc319c WL |
418 | mutable bool fAvailableCreditCached; |
419 | mutable bool fChangeCached; | |
bde280b9 WL |
420 | mutable int64 nDebitCached; |
421 | mutable int64 nCreditCached; | |
966a0e8c | 422 | mutable int64 nImmatureCreditCached; |
bde280b9 WL |
423 | mutable int64 nAvailableCreditCached; |
424 | mutable int64 nChangeCached; | |
e8ef3da7 | 425 | |
e8ef3da7 WL |
426 | CWalletTx() |
427 | { | |
428 | Init(NULL); | |
429 | } | |
430 | ||
431 | CWalletTx(const CWallet* pwalletIn) | |
432 | { | |
433 | Init(pwalletIn); | |
434 | } | |
435 | ||
436 | CWalletTx(const CWallet* pwalletIn, const CMerkleTx& txIn) : CMerkleTx(txIn) | |
437 | { | |
438 | Init(pwalletIn); | |
439 | } | |
440 | ||
441 | CWalletTx(const CWallet* pwalletIn, const CTransaction& txIn) : CMerkleTx(txIn) | |
442 | { | |
443 | Init(pwalletIn); | |
444 | } | |
445 | ||
446 | void Init(const CWallet* pwalletIn) | |
447 | { | |
448 | pwallet = pwalletIn; | |
449 | vtxPrev.clear(); | |
450 | mapValue.clear(); | |
451 | vOrderForm.clear(); | |
452 | fTimeReceivedIsTxTime = false; | |
453 | nTimeReceived = 0; | |
c3f95ef1 | 454 | nTimeSmart = 0; |
e8ef3da7 WL |
455 | fFromMe = false; |
456 | strFromAccount.clear(); | |
457 | vfSpent.clear(); | |
458 | fDebitCached = false; | |
459 | fCreditCached = false; | |
966a0e8c | 460 | fImmatureCreditCached = false; |
e8ef3da7 WL |
461 | fAvailableCreditCached = false; |
462 | fChangeCached = false; | |
463 | nDebitCached = 0; | |
464 | nCreditCached = 0; | |
966a0e8c | 465 | nImmatureCreditCached = 0; |
e8ef3da7 WL |
466 | nAvailableCreditCached = 0; |
467 | nChangeCached = 0; | |
9c7722b7 | 468 | nOrderPos = -1; |
e8ef3da7 WL |
469 | } |
470 | ||
471 | IMPLEMENT_SERIALIZE | |
472 | ( | |
473 | CWalletTx* pthis = const_cast<CWalletTx*>(this); | |
474 | if (fRead) | |
475 | pthis->Init(NULL); | |
476 | char fSpent = false; | |
477 | ||
478 | if (!fRead) | |
479 | { | |
480 | pthis->mapValue["fromaccount"] = pthis->strFromAccount; | |
481 | ||
482 | std::string str; | |
483 | BOOST_FOREACH(char f, vfSpent) | |
484 | { | |
485 | str += (f ? '1' : '0'); | |
486 | if (f) | |
487 | fSpent = true; | |
488 | } | |
489 | pthis->mapValue["spent"] = str; | |
9c7722b7 LD |
490 | |
491 | WriteOrderPos(pthis->nOrderPos, pthis->mapValue); | |
c3f95ef1 LD |
492 | |
493 | if (nTimeSmart) | |
494 | pthis->mapValue["timesmart"] = strprintf("%u", nTimeSmart); | |
e8ef3da7 WL |
495 | } |
496 | ||
497 | nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion,ser_action); | |
498 | READWRITE(vtxPrev); | |
499 | READWRITE(mapValue); | |
500 | READWRITE(vOrderForm); | |
501 | READWRITE(fTimeReceivedIsTxTime); | |
502 | READWRITE(nTimeReceived); | |
503 | READWRITE(fFromMe); | |
504 | READWRITE(fSpent); | |
505 | ||
506 | if (fRead) | |
507 | { | |
508 | pthis->strFromAccount = pthis->mapValue["fromaccount"]; | |
509 | ||
510 | if (mapValue.count("spent")) | |
511 | BOOST_FOREACH(char c, pthis->mapValue["spent"]) | |
512 | pthis->vfSpent.push_back(c != '0'); | |
513 | else | |
514 | pthis->vfSpent.assign(vout.size(), fSpent); | |
e8ef3da7 | 515 | |
9c7722b7 LD |
516 | ReadOrderPos(pthis->nOrderPos, pthis->mapValue); |
517 | ||
c3f95ef1 LD |
518 | pthis->nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(pthis->mapValue["timesmart"]) : 0; |
519 | } | |
520 | ||
e8ef3da7 WL |
521 | pthis->mapValue.erase("fromaccount"); |
522 | pthis->mapValue.erase("version"); | |
523 | pthis->mapValue.erase("spent"); | |
9c7722b7 | 524 | pthis->mapValue.erase("n"); |
c3f95ef1 | 525 | pthis->mapValue.erase("timesmart"); |
e8ef3da7 WL |
526 | ) |
527 | ||
528 | // marks certain txout's as spent | |
529 | // returns true if any update took place | |
530 | bool UpdateSpent(const std::vector<char>& vfNewSpent) | |
531 | { | |
532 | bool fReturn = false; | |
c376ac35 | 533 | for (unsigned int i = 0; i < vfNewSpent.size(); i++) |
e8ef3da7 WL |
534 | { |
535 | if (i == vfSpent.size()) | |
536 | break; | |
537 | ||
538 | if (vfNewSpent[i] && !vfSpent[i]) | |
539 | { | |
540 | vfSpent[i] = true; | |
541 | fReturn = true; | |
542 | fAvailableCreditCached = false; | |
543 | } | |
544 | } | |
545 | return fReturn; | |
546 | } | |
547 | ||
d825e6a3 | 548 | // make sure balances are recalculated |
e8ef3da7 WL |
549 | void MarkDirty() |
550 | { | |
551 | fCreditCached = false; | |
552 | fAvailableCreditCached = false; | |
553 | fDebitCached = false; | |
554 | fChangeCached = false; | |
555 | } | |
556 | ||
4c6e2295 PW |
557 | void BindWallet(CWallet *pwalletIn) |
558 | { | |
559 | pwallet = pwalletIn; | |
560 | MarkDirty(); | |
561 | } | |
562 | ||
e8ef3da7 WL |
563 | void MarkSpent(unsigned int nOut) |
564 | { | |
565 | if (nOut >= vout.size()) | |
566 | throw std::runtime_error("CWalletTx::MarkSpent() : nOut out of range"); | |
567 | vfSpent.resize(vout.size()); | |
568 | if (!vfSpent[nOut]) | |
569 | { | |
570 | vfSpent[nOut] = true; | |
571 | fAvailableCreditCached = false; | |
572 | } | |
573 | } | |
574 | ||
575 | bool IsSpent(unsigned int nOut) const | |
576 | { | |
577 | if (nOut >= vout.size()) | |
578 | throw std::runtime_error("CWalletTx::IsSpent() : nOut out of range"); | |
579 | if (nOut >= vfSpent.size()) | |
580 | return false; | |
581 | return (!!vfSpent[nOut]); | |
582 | } | |
583 | ||
bde280b9 | 584 | int64 GetDebit() const |
e8ef3da7 WL |
585 | { |
586 | if (vin.empty()) | |
587 | return 0; | |
588 | if (fDebitCached) | |
589 | return nDebitCached; | |
590 | nDebitCached = pwallet->GetDebit(*this); | |
591 | fDebitCached = true; | |
592 | return nDebitCached; | |
593 | } | |
594 | ||
bde280b9 | 595 | int64 GetCredit(bool fUseCache=true) const |
e8ef3da7 WL |
596 | { |
597 | // Must wait until coinbase is safely deep enough in the chain before valuing it | |
598 | if (IsCoinBase() && GetBlocksToMaturity() > 0) | |
599 | return 0; | |
600 | ||
601 | // GetBalance can assume transactions in mapWallet won't change | |
602 | if (fUseCache && fCreditCached) | |
603 | return nCreditCached; | |
604 | nCreditCached = pwallet->GetCredit(*this); | |
605 | fCreditCached = true; | |
606 | return nCreditCached; | |
607 | } | |
608 | ||
966a0e8c PK |
609 | int64 GetImmatureCredit(bool fUseCache=true) const |
610 | { | |
611 | if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) | |
612 | { | |
613 | if (fUseCache && fImmatureCreditCached) | |
614 | return nImmatureCreditCached; | |
615 | nImmatureCreditCached = pwallet->GetCredit(*this); | |
616 | fImmatureCreditCached = true; | |
617 | return nImmatureCreditCached; | |
618 | } | |
619 | ||
620 | return 0; | |
621 | } | |
622 | ||
bde280b9 | 623 | int64 GetAvailableCredit(bool fUseCache=true) const |
e8ef3da7 WL |
624 | { |
625 | // Must wait until coinbase is safely deep enough in the chain before valuing it | |
626 | if (IsCoinBase() && GetBlocksToMaturity() > 0) | |
627 | return 0; | |
628 | ||
629 | if (fUseCache && fAvailableCreditCached) | |
630 | return nAvailableCreditCached; | |
631 | ||
bde280b9 | 632 | int64 nCredit = 0; |
c376ac35 | 633 | for (unsigned int i = 0; i < vout.size(); i++) |
e8ef3da7 WL |
634 | { |
635 | if (!IsSpent(i)) | |
636 | { | |
637 | const CTxOut &txout = vout[i]; | |
638 | nCredit += pwallet->GetCredit(txout); | |
639 | if (!MoneyRange(nCredit)) | |
640 | throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range"); | |
641 | } | |
642 | } | |
643 | ||
644 | nAvailableCreditCached = nCredit; | |
645 | fAvailableCreditCached = true; | |
646 | return nCredit; | |
647 | } | |
648 | ||
649 | ||
bde280b9 | 650 | int64 GetChange() const |
e8ef3da7 WL |
651 | { |
652 | if (fChangeCached) | |
653 | return nChangeCached; | |
654 | nChangeCached = pwallet->GetChange(*this); | |
655 | fChangeCached = true; | |
656 | return nChangeCached; | |
657 | } | |
658 | ||
e07c8e91 | 659 | void GetAmounts(std::list<std::pair<CTxDestination, int64> >& listReceived, |
10254401 | 660 | std::list<std::pair<CTxDestination, int64> >& listSent, int64& nFee, std::string& strSentAccount) const; |
e8ef3da7 | 661 | |
e07c8e91 | 662 | void GetAccountAmounts(const std::string& strAccount, int64& nReceived, |
bde280b9 | 663 | int64& nSent, int64& nFee) const; |
e8ef3da7 WL |
664 | |
665 | bool IsFromMe() const | |
666 | { | |
667 | return (GetDebit() > 0); | |
668 | } | |
669 | ||
670 | bool IsConfirmed() const | |
671 | { | |
672 | // Quick answer in most cases | |
05df3fc6 | 673 | if (!IsFinalTx(*this)) |
e8ef3da7 WL |
674 | return false; |
675 | if (GetDepthInMainChain() >= 1) | |
676 | return true; | |
677 | if (!IsFromMe()) // using wtx's cached debit | |
678 | return false; | |
679 | ||
680 | // If no confirmations but it's from us, we can still | |
681 | // consider it confirmed if all dependencies are confirmed | |
682 | std::map<uint256, const CMerkleTx*> mapPrev; | |
683 | std::vector<const CMerkleTx*> vWorkQueue; | |
684 | vWorkQueue.reserve(vtxPrev.size()+1); | |
685 | vWorkQueue.push_back(this); | |
c376ac35 | 686 | for (unsigned int i = 0; i < vWorkQueue.size(); i++) |
e8ef3da7 WL |
687 | { |
688 | const CMerkleTx* ptx = vWorkQueue[i]; | |
689 | ||
05df3fc6 | 690 | if (!IsFinalTx(*ptx)) |
e8ef3da7 WL |
691 | return false; |
692 | if (ptx->GetDepthInMainChain() >= 1) | |
693 | continue; | |
694 | if (!pwallet->IsFromMe(*ptx)) | |
695 | return false; | |
696 | ||
697 | if (mapPrev.empty()) | |
da7bbd9d | 698 | { |
e8ef3da7 WL |
699 | BOOST_FOREACH(const CMerkleTx& tx, vtxPrev) |
700 | mapPrev[tx.GetHash()] = &tx; | |
da7bbd9d | 701 | } |
e8ef3da7 WL |
702 | |
703 | BOOST_FOREACH(const CTxIn& txin, ptx->vin) | |
704 | { | |
705 | if (!mapPrev.count(txin.prevout.hash)) | |
706 | return false; | |
707 | vWorkQueue.push_back(mapPrev[txin.prevout.hash]); | |
708 | } | |
709 | } | |
710 | return true; | |
711 | } | |
712 | ||
713 | bool WriteToDisk(); | |
714 | ||
bde280b9 | 715 | int64 GetTxTime() const; |
e8ef3da7 WL |
716 | int GetRequestCount() const; |
717 | ||
450cbb09 | 718 | void AddSupportingTransactions(); |
b1f15b21 | 719 | bool AcceptWalletTransaction(); |
e8ef3da7 WL |
720 | void RelayWalletTransaction(); |
721 | }; | |
722 | ||
723 | ||
9b0369c7 CM |
724 | |
725 | ||
726 | class COutput | |
727 | { | |
728 | public: | |
729 | const CWalletTx *tx; | |
730 | int i; | |
731 | int nDepth; | |
732 | ||
733 | COutput(const CWalletTx *txIn, int iIn, int nDepthIn) | |
734 | { | |
735 | tx = txIn; i = iIn; nDepth = nDepthIn; | |
736 | } | |
737 | ||
738 | std::string ToString() const | |
739 | { | |
1c06aa98 | 740 | return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString().c_str(), i, nDepth, FormatMoney(tx->vout[i].nValue).c_str()); |
9b0369c7 CM |
741 | } |
742 | ||
743 | void print() const | |
744 | { | |
881a85a2 | 745 | LogPrintf("%s\n", ToString().c_str()); |
9b0369c7 CM |
746 | } |
747 | }; | |
748 | ||
749 | ||
750 | ||
751 | ||
6b8de05d | 752 | /** Private key that includes an expiration date in case it never gets used. */ |
e8ef3da7 WL |
753 | class CWalletKey |
754 | { | |
755 | public: | |
756 | CPrivKey vchPrivKey; | |
bde280b9 WL |
757 | int64 nTimeCreated; |
758 | int64 nTimeExpires; | |
e8ef3da7 WL |
759 | std::string strComment; |
760 | //// todo: add something to note what created it (user, getnewaddress, change) | |
761 | //// maybe should have a map<string, string> property map | |
762 | ||
bde280b9 | 763 | CWalletKey(int64 nExpires=0) |
e8ef3da7 WL |
764 | { |
765 | nTimeCreated = (nExpires ? GetTime() : 0); | |
766 | nTimeExpires = nExpires; | |
767 | } | |
768 | ||
769 | IMPLEMENT_SERIALIZE | |
770 | ( | |
771 | if (!(nType & SER_GETHASH)) | |
772 | READWRITE(nVersion); | |
773 | READWRITE(vchPrivKey); | |
774 | READWRITE(nTimeCreated); | |
775 | READWRITE(nTimeExpires); | |
776 | READWRITE(strComment); | |
777 | ) | |
778 | }; | |
779 | ||
780 | ||
781 | ||
782 | ||
783 | ||
784 | ||
6b8de05d PW |
785 | /** Account information. |
786 | * Stored in wallet with key "acc"+string account name. | |
787 | */ | |
e8ef3da7 WL |
788 | class CAccount |
789 | { | |
790 | public: | |
fd61d6f5 | 791 | CPubKey vchPubKey; |
e8ef3da7 WL |
792 | |
793 | CAccount() | |
794 | { | |
795 | SetNull(); | |
796 | } | |
797 | ||
798 | void SetNull() | |
799 | { | |
fd61d6f5 | 800 | vchPubKey = CPubKey(); |
e8ef3da7 WL |
801 | } |
802 | ||
803 | IMPLEMENT_SERIALIZE | |
804 | ( | |
805 | if (!(nType & SER_GETHASH)) | |
806 | READWRITE(nVersion); | |
807 | READWRITE(vchPubKey); | |
808 | ) | |
809 | }; | |
810 | ||
811 | ||
812 | ||
6b8de05d PW |
813 | /** Internal transfers. |
814 | * Database key is acentry<account><counter>. | |
815 | */ | |
e8ef3da7 WL |
816 | class CAccountingEntry |
817 | { | |
818 | public: | |
819 | std::string strAccount; | |
bde280b9 WL |
820 | int64 nCreditDebit; |
821 | int64 nTime; | |
e8ef3da7 WL |
822 | std::string strOtherAccount; |
823 | std::string strComment; | |
9c7722b7 LD |
824 | mapValue_t mapValue; |
825 | int64 nOrderPos; // position in ordered transaction list | |
826 | uint64 nEntryNo; | |
e8ef3da7 WL |
827 | |
828 | CAccountingEntry() | |
829 | { | |
830 | SetNull(); | |
831 | } | |
832 | ||
833 | void SetNull() | |
834 | { | |
835 | nCreditDebit = 0; | |
836 | nTime = 0; | |
837 | strAccount.clear(); | |
838 | strOtherAccount.clear(); | |
839 | strComment.clear(); | |
9c7722b7 | 840 | nOrderPos = -1; |
e8ef3da7 WL |
841 | } |
842 | ||
843 | IMPLEMENT_SERIALIZE | |
844 | ( | |
9c7722b7 | 845 | CAccountingEntry& me = *const_cast<CAccountingEntry*>(this); |
e8ef3da7 WL |
846 | if (!(nType & SER_GETHASH)) |
847 | READWRITE(nVersion); | |
848 | // Note: strAccount is serialized as part of the key, not here. | |
849 | READWRITE(nCreditDebit); | |
850 | READWRITE(nTime); | |
851 | READWRITE(strOtherAccount); | |
9c7722b7 LD |
852 | |
853 | if (!fRead) | |
854 | { | |
855 | WriteOrderPos(nOrderPos, me.mapValue); | |
856 | ||
857 | if (!(mapValue.empty() && _ssExtra.empty())) | |
858 | { | |
859 | CDataStream ss(nType, nVersion); | |
860 | ss.insert(ss.begin(), '\0'); | |
861 | ss << mapValue; | |
862 | ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end()); | |
863 | me.strComment.append(ss.str()); | |
864 | } | |
865 | } | |
866 | ||
e8ef3da7 | 867 | READWRITE(strComment); |
9c7722b7 LD |
868 | |
869 | size_t nSepPos = strComment.find("\0", 0, 1); | |
870 | if (fRead) | |
871 | { | |
872 | me.mapValue.clear(); | |
873 | if (std::string::npos != nSepPos) | |
874 | { | |
875 | CDataStream ss(std::vector<char>(strComment.begin() + nSepPos + 1, strComment.end()), nType, nVersion); | |
876 | ss >> me.mapValue; | |
877 | me._ssExtra = std::vector<char>(ss.begin(), ss.end()); | |
878 | } | |
879 | ReadOrderPos(me.nOrderPos, me.mapValue); | |
880 | } | |
881 | if (std::string::npos != nSepPos) | |
882 | me.strComment.erase(nSepPos); | |
883 | ||
884 | me.mapValue.erase("n"); | |
e8ef3da7 | 885 | ) |
9c7722b7 LD |
886 | |
887 | private: | |
888 | std::vector<char> _ssExtra; | |
e8ef3da7 WL |
889 | }; |
890 | ||
e8ef3da7 | 891 | #endif |