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