fbcd5c157720c52966102fb961044dd68a7b9b24
[novacoin.git] / src / wallet.h
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 #ifndef BITCOIN_WALLET_H
6 #define BITCOIN_WALLET_H
7
8 #include <string>
9 #include <vector>
10 #include <cstdlib>
11
12 #include "main.h"
13 #include "key.h"
14 #include "keystore.h"
15 #include "script.h"
16 #include "ui_interface.h"
17 #include "util.h"
18 #include "walletdb.h"
19 #include "base58.h"
20
21 extern bool fWalletUnlockMintOnly;
22 extern bool fConfChange;
23
24 class CAccountingEntry;
25 class CWalletTx;
26 class CReserveKey;
27 class COutput;
28 class CCoinControl;
29
30 //Settings
31 extern int64_t nTransactionFee;
32
33 // Set of selected transactions
34 typedef std::set<std::pair<const CWalletTx*,unsigned int> > CoinsSet;
35
36 // (client) version numbers for particular wallet features
37 enum WalletFeature
38 {
39     FEATURE_BASE = 10500, // the earliest version new wallets supports (only useful for getinfo's clientversion output)
40
41     FEATURE_WALLETCRYPT = 40000, // wallet encryption
42     FEATURE_COMPRPUBKEY = 60000, // compressed public keys
43     FEATURE_MALLKEY = 60017,
44     FEATURE_LATEST = 60017
45 };
46
47 // A key pool entry
48 class CKeyPool
49 {
50 public:
51     int64_t nTime;
52     CPubKey vchPubKey;
53
54     CKeyPool() : nTime(GetTime()) {}
55     CKeyPool(const CPubKey& vchPubKeyIn) : nTime(GetTime()), vchPubKey(vchPubKeyIn) {}
56
57     IMPLEMENT_SERIALIZE
58     (
59         if (!(nType & SER_GETHASH))
60             READWRITE(nVersion);
61         READWRITE(nTime);
62         READWRITE(vchPubKey);
63     )
64 };
65
66 // A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
67 // and provides the ability to create new transactions.
68 //
69 class CWallet : public CCryptoKeyStore
70 {
71 private:
72     bool SelectCoins(int64_t nTargetValue, unsigned int nSpendTime, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet, const CCoinControl *coinControl=NULL) const;
73
74     CWalletDB *pwalletdbEncryption, *pwalletdbDecryption;
75
76     // the current wallet version: clients below this version are not able to load the wallet
77     int nWalletVersion;
78
79     // the maximum wallet format version: memory-only variable that specifies to what version this wallet may be upgraded
80     int nWalletMaxVersion;
81
82     int64_t nNextResend;
83     int64_t nLastResend;
84
85     // stake mining statistics
86     uint64_t nKernelsTried;
87     uint64_t nCoinDaysTried;
88
89 public:
90     mutable CCriticalSection cs_wallet;
91
92     bool fFileBacked;
93     std::string strWalletFile;
94
95     std::set<int64_t> setKeyPool;
96     /*
97     std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
98     std::map<CMalleableKeyView, CKeyMetadata> mapMalleableKeyMetadata;
99     */
100
101     std::map<CBitcoinAddress, CKeyMetadata> mapKeyMetadata;
102
103     typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
104     MasterKeyMap mapMasterKeys;
105     unsigned int nMasterKeyMaxID;
106
107     CWallet();
108     CWallet(std::string strWalletFileIn);
109     void SetNull();
110
111     std::map<uint256, CWalletTx> mapWallet;
112     std::vector<uint256> vMintingWalletUpdated;
113     int64_t nOrderPosNext;
114     std::map<uint256, int> mapRequestCount;
115
116     std::map<CBitcoinAddress, std::string> mapAddressBook;
117
118     CPubKey vchDefaultKey;
119     int64_t nTimeFirstKey;
120
121     const CWalletTx* GetWalletTx(const uint256& hash) const;
122
123     // check whether we are allowed to upgrade (or already support) to the named feature
124     bool CanSupportFeature(enum WalletFeature wf) { return nWalletMaxVersion >= wf; }
125
126     void AvailableCoinsMinConf(std::vector<COutput>& vCoins, int nConf, int64_t nMinValue, int64_t nMaxValue) const;
127     void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl=NULL) const;
128     bool SelectCoinsMinConf(int64_t nTargetValue, unsigned int nSpendTime, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const;
129
130     // Simple select (without randomization)
131     bool SelectCoinsSimple(int64_t nTargetValue, int64_t nMinValue, int64_t nMaxValue, unsigned int nSpendTime, int nMinConf, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const;
132
133     // keystore implementation
134     // Generate a new key
135     CPubKey GenerateNewKey();
136     CMalleableKeyView GenerateNewMalleableKey();
137     // Adds a key to the store, and saves it to disk.
138     bool AddKey(const CKey& key);
139     bool AddKey(const CMalleableKey& mKey);
140     // Adds a key to the store, without saving it to disk (used by LoadWallet)
141     bool LoadKey(const CKey& key) { return CCryptoKeyStore::AddKey(key); }
142     // Load metadata (used by LoadWallet)
143     bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata);
144     bool LoadKeyMetadata(const CMalleableKeyView &keyView, const CKeyMetadata &metadata);
145
146     // Load malleable key without saving it to disk (used by LoadWallet)
147     bool LoadKey(const CMalleableKeyView &keyView, const CSecret &vchSecretH) { return CCryptoKeyStore::AddMalleableKey(keyView, vchSecretH); }
148     bool LoadCryptedKey(const CMalleableKeyView &keyView, const std::vector<unsigned char> &vchCryptedSecretH) { return CCryptoKeyStore::AddCryptedMalleableKey(keyView, vchCryptedSecretH); }
149
150     bool LoadMinVersion(int nVersion);
151
152     // Adds an encrypted key to the store, and saves it to disk.
153     bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
154     bool AddCryptedMalleableKey(const CMalleableKeyView& keyView, const std::vector<unsigned char> &vchCryptedSecretH);
155     // Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
156     bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret) { SetMinVersion(FEATURE_WALLETCRYPT); return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); }
157     bool AddCScript(const CScript& redeemScript);
158     bool LoadCScript(const CScript& redeemScript);
159
160     // Adds a watch-only address to the store, and saves it to disk.
161     bool AddWatchOnly(const CScript &dest);
162     bool RemoveWatchOnly(const CScript &dest);
163     // Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)
164     bool LoadWatchOnly(const CScript &dest);
165
166     bool Unlock(const SecureString& strWalletPassphrase);
167     bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
168     bool EncryptWallet(const SecureString& strWalletPassphrase);
169     bool DecryptWallet(const SecureString& strWalletPassphrase);
170
171     void GetAddresses(std::map<CBitcoinAddress, int64_t> &mapAddresses) const;
172     bool GetPEM(const CKeyID &keyID, const std::string &fileName, const SecureString &strPassPhrase) const;
173
174
175     /** Increment the next transaction order id
176         @return next transaction order id
177      */
178     int64_t IncOrderPosNext(CWalletDB *pwalletdb = NULL);
179
180     typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;
181     typedef std::multimap<int64_t, TxPair > TxItems;
182
183     /** Get the wallet's activity log
184         @return multimap of ordered transactions and accounting entries
185         @warning Returned pointers are *only* valid within the scope of passed acentries
186      */
187     TxItems OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount = "");
188
189     void MarkDirty();
190     bool AddToWallet(const CWalletTx& wtxIn);
191     bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false);
192     bool EraseFromWallet(uint256 hash);
193     void ClearOrphans();
194     void WalletUpdateSpent(const CTransaction& prevout, bool fBlock = false);
195     int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
196     int ScanForWalletTransaction(const uint256& hashTx);
197     void ReacceptWalletTransactions();
198     void ResendWalletTransactions(int64_t nBestBlockTime);
199     std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime);
200     int64_t GetBalance() const;
201     int64_t GetWatchOnlyBalance() const;
202     int64_t GetUnconfirmedBalance() const;
203     int64_t GetUnconfirmedWatchOnlyBalance() const;
204     int64_t GetImmatureBalance() const;
205     int64_t GetImmatureWatchOnlyBalance() const;
206     int64_t GetStake() const;
207     int64_t GetNewMint() const;
208     int64_t GetWatchOnlyStake() const;
209     int64_t GetWatchOnlyNewMint() const;
210     bool CreateTransaction(const std::vector<std::pair<CScript, int64_t> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, const CCoinControl *coinControl=NULL);
211     bool CreateTransaction(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, const CCoinControl *coinControl=NULL);
212     bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
213
214     void GetStakeWeightFromValue(const int64_t& nTime, const int64_t& nValue, uint64_t& nWeight);
215     bool CreateCoinStake(uint256 &hashTx, uint32_t nOut, uint32_t nTime, uint32_t nBits, CTransaction &txNew, CKey& key);
216     bool MergeCoins(const int64_t& nAmount, const int64_t& nMinValue, const int64_t& nMaxValue, std::list<uint256>& listMerged);
217
218     std::string SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, bool fAskFee=false);
219
220     bool NewKeyPool(unsigned int nSize = 0);
221     bool TopUpKeyPool(unsigned int nSize = 0);
222     void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool);
223     void KeepKey(int64_t nIndex);
224     void ReturnKey(int64_t nIndex);
225     bool GetKeyFromPool(CPubKey &key, bool fAllowReuse=true);
226     int64_t GetOldestKeyPoolTime();
227     void GetAllReserveKeys(std::set<CKeyID>& setAddress) const;
228
229     std::set< std::set<CBitcoinAddress> > GetAddressGroupings();
230     std::map<CBitcoinAddress, int64_t> GetAddressBalances();
231
232     isminetype IsMine(const CTxIn& txin) const;
233     int64_t GetDebit(const CTxIn& txin, const isminefilter& filter) const;
234     isminetype IsMine(const CTxOut& txout) const;
235     int64_t GetCredit(const CTxOut& txout, const isminefilter& filter) const;
236     bool IsChange(const CTxOut& txout) const;
237     int64_t GetChange(const CTxOut& txout) const;
238     bool IsMine(const CTransaction& tx) const;
239     bool IsFromMe(const CTransaction& tx) const;
240     int64_t GetDebit(const CTransaction& tx, const isminefilter& filter) const;
241     int64_t GetCredit(const CTransaction& tx, const isminefilter& filter) const;
242     int64_t GetChange(const CTransaction& tx) const;
243     void SetBestChain(const CBlockLocator& loc);
244
245     DBErrors LoadWallet(bool& fFirstRunRet);
246     DBErrors ZapWalletTx();
247
248     bool SetAddressBookName(const CTxDestination& address, const std::string& strName);
249     bool SetAddressBookName(const CBitcoinAddress& address, const std::string& strName);
250     bool DelAddressBookName(const CBitcoinAddress& address);
251     void UpdatedTransaction(const uint256 &hashTx);
252     void PrintWallet(const CBlock& block);
253     void Inventory(const uint256 &hash);
254
255     unsigned int GetKeyPoolSize()
256     {
257         return (unsigned int)(setKeyPool.size());
258     }
259
260     bool GetTransaction(const uint256 &hashTx, CWalletTx& wtx);
261     bool SetDefaultKey(const CPubKey &vchPubKey);
262
263     // signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower
264     bool SetMinVersion(enum WalletFeature, CWalletDB* pwalletdbIn = NULL, bool fExplicit = false);
265
266     // change which version we're allowed to upgrade to (note that this does not immediately imply upgrading to that format)
267     bool SetMaxVersion(int nVersion);
268
269     // get the current wallet format (the oldest client version guaranteed to understand this wallet)
270     int GetVersion() { return nWalletVersion; }
271
272     void FixSpentCoins(int& nMismatchSpent, int64_t& nBalanceInQuestion, bool fCheckOnly = false);
273     void DisableTransaction(const CTransaction &tx);
274
275     /** Address book entry changed.
276      * @note called with lock cs_wallet held.
277      */
278     boost::signals2::signal<void (CWallet *wallet, const CBitcoinAddress &address, const std::string &label, bool isMine, ChangeType status)> NotifyAddressBookChanged;
279
280     /** Wallet transaction added, removed or updated.
281      * @note called with lock cs_wallet held.
282      */
283     boost::signals2::signal<void (CWallet *wallet, const uint256 &hashTx, ChangeType status)> NotifyTransactionChanged;
284
285     /** Watch-only address added */
286     boost::signals2::signal<void (bool fHaveWatchOnly)> NotifyWatchonlyChanged;
287 };
288
289 /** A key allocated from the key pool. */
290 class CReserveKey
291 {
292 protected:
293     CWallet* pwallet;
294     int64_t nIndex;
295     CPubKey vchPubKey;
296 public:
297     CReserveKey(CWallet* pwalletIn) : pwallet(pwalletIn), nIndex(-1) {}
298
299     ~CReserveKey()
300     {
301         if (!fShutdown)
302             ReturnKey();
303     }
304
305     void ReturnKey();
306     CPubKey GetReservedKey();
307     void KeepKey();
308 };
309
310
311 typedef std::map<std::string, std::string> mapValue_t;
312
313 static void ReadOrderPos(int64_t& nOrderPos, mapValue_t& mapValue)
314 {
315     if (!mapValue.count("n"))
316     {
317         nOrderPos = -1; // TODO: calculate elsewhere
318         return;
319     }
320     nOrderPos = strtoll(mapValue["n"]);
321 }
322
323 static void WriteOrderPos(const int64_t& nOrderPos, mapValue_t& mapValue)
324 {
325     if (nOrderPos == -1)
326         return;
327     mapValue["n"] = i64tostr(nOrderPos);
328 }
329
330
331 // A transaction with a bunch of additional info that only the owner cares about.
332 // It includes any unrecorded transactions needed to link it back to the block chain.
333 //
334 class CWalletTx : public CMerkleTx
335 {
336 private:
337     const CWallet* pwallet;
338
339 public:
340     std::vector<CMerkleTx> vtxPrev;
341     mapValue_t mapValue;
342     std::vector<std::pair<std::string, std::string> > vOrderForm;
343     unsigned int fTimeReceivedIsTxTime;
344     unsigned int nTimeReceived;  // time received by this node
345     unsigned int nTimeSmart;
346     char fFromMe;
347     std::string strFromAccount;
348     std::vector<char> vfSpent; // which outputs are already spent
349     int64_t nOrderPos;  // position in ordered transaction list
350
351     // memory only
352     mutable bool fDebitCached;
353     mutable bool fWatchDebitCached;
354     mutable bool fCreditCached;
355     mutable bool fWatchCreditCached;
356     mutable bool fAvailableCreditCached;
357     mutable bool fImmatureCreditCached;
358     mutable bool fImmatureWatchCreditCached;
359     mutable bool fAvailableWatchCreditCached;
360     mutable bool fChangeCached;
361     mutable int64_t nDebitCached;
362     mutable int64_t nWatchDebitCached;
363     mutable int64_t nCreditCached;
364     mutable int64_t nWatchCreditCached;
365     mutable int64_t nAvailableCreditCached;
366     mutable int64_t nImmatureCreditCached;
367     mutable int64_t nImmatureWatchCreditCached;
368     mutable int64_t nAvailableWatchCreditCached;
369     mutable int64_t nChangeCached;
370
371     CWalletTx();
372     CWalletTx(const CWallet* pwalletIn);
373     CWalletTx(const CWallet* pwalletIn, const CMerkleTx& txIn);
374     CWalletTx(const CWallet* pwalletIn, const CTransaction& txIn);
375     void Init(const CWallet* pwalletIn);
376
377     IMPLEMENT_SERIALIZE
378     (
379         CWalletTx* pthis = const_cast<CWalletTx*>(this);
380         if (fRead)
381             pthis->Init(NULL);
382         char fSpent = false;
383
384         if (!fRead)
385         {
386             pthis->mapValue["fromaccount"] = pthis->strFromAccount;
387
388             std::string str;
389             for(char f :  vfSpent)
390             {
391                 str += (f ? '1' : '0');
392                 if (f)
393                     fSpent = true;
394             }
395             pthis->mapValue["spent"] = str;
396
397             WriteOrderPos(pthis->nOrderPos, pthis->mapValue);
398
399             if (nTimeSmart)
400                 pthis->mapValue["timesmart"] = strprintf("%u", nTimeSmart);
401         }
402
403         nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion,ser_action);
404         READWRITE(vtxPrev);
405         READWRITE(mapValue);
406         READWRITE(vOrderForm);
407         READWRITE(fTimeReceivedIsTxTime);
408         READWRITE(nTimeReceived);
409         READWRITE(fFromMe);
410         READWRITE(fSpent);
411
412         if (fRead)
413         {
414             pthis->strFromAccount = pthis->mapValue["fromaccount"];
415
416             if (mapValue.count("spent"))
417                 for(char c :  pthis->mapValue["spent"])
418                     pthis->vfSpent.push_back(c != '0');
419             else
420                 pthis->vfSpent.assign(vout.size(), fSpent);
421
422             ReadOrderPos(pthis->nOrderPos, pthis->mapValue);
423
424             pthis->nTimeSmart = mapValue.count("timesmart") ? (unsigned int)strtoll(pthis->mapValue["timesmart"]) : 0;
425         }
426
427         pthis->mapValue.erase("fromaccount");
428         pthis->mapValue.erase("version");
429         pthis->mapValue.erase("spent");
430         pthis->mapValue.erase("n");
431         pthis->mapValue.erase("timesmart");
432     )
433
434     // marks certain txout's as spent
435     // returns true if any update took place
436     bool UpdateSpent(const std::vector<char>& vfNewSpent);
437
438     // make sure balances are recalculated
439     void MarkDirty();
440     void BindWallet(CWallet *pwalletIn);
441     void MarkSpent(unsigned int nOut);
442     void MarkUnspent(unsigned int nOut);
443     bool IsSpent(unsigned int nOut) const;
444
445     int64_t GetDebit(const isminefilter& filter) const;
446     int64_t GetCredit(const isminefilter& filter) const;
447     int64_t GetImmatureCredit(bool fUseCache=true) const;
448     int64_t GetImmatureWatchOnlyCredit(bool fUseCache=true) const;
449     int64_t GetAvailableCredit(bool fUseCache=true) const;
450     int64_t GetAvailableWatchCredit(bool fUseCache=true) const;
451     int64_t GetChange() const;
452
453     void GetAmounts(int64_t& nGeneratedImmature, int64_t& nGeneratedMature, std::list<std::pair<CBitcoinAddress, int64_t> >& listReceived,
454                     std::list<std::pair<CBitcoinAddress, int64_t> >& listSent, int64_t& nFee, std::string& strSentAccount, const isminefilter& filter) const;
455
456     void GetAccountAmounts(const std::string& strAccount, int64_t& nGenerated, int64_t& nReceived,
457                            int64_t& nSent, int64_t& nFee, const isminefilter& filter) const;
458
459     bool IsFromMe(const isminefilter& filter) const
460     {
461         return (GetDebit(filter) > 0);
462     }
463
464     bool InMempool() const;
465     bool IsTrusted() const;
466
467     bool WriteToDisk();
468
469     int64_t GetTxTime() const;
470     int GetRequestCount() const;
471
472     void AddSupportingTransactions(CTxDB& txdb);
473
474     bool AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs=true);
475     bool AcceptWalletTransaction();
476
477     bool RelayWalletTransaction(CTxDB& txdb);
478     bool RelayWalletTransaction();
479 };
480
481
482
483
484 class COutput
485 {
486 public:
487     const CWalletTx *tx;
488     int i;
489     int nDepth;
490     bool fSpendable;
491
492     COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn) :
493             tx(txIn), i(iIn), nDepth(nDepthIn), fSpendable(fSpendableIn) {}
494
495     std::string ToString() const
496     {
497         return strprintf("COutput(%s, %d, %d, %d) [%s]", tx->GetHash().ToString().substr(0,10).c_str(), i, fSpendable, nDepth, FormatMoney(tx->vout[i].nValue).c_str());
498     }
499 };
500
501
502
503
504 // Private key that includes an expiration date in case it never gets used.
505 class CWalletKey
506 {
507 public:
508     CPrivKey vchPrivKey;
509     int64_t nTimeCreated;
510     int64_t nTimeExpires;
511     std::string strComment;
512     //// todo: add something to note what created it (user, getnewaddress, change)
513     ////   maybe should have a map<string, string> property map
514
515     CWalletKey(int64_t nExpires=0) : nTimeCreated(nExpires ? GetTime() : 0), nTimeExpires(nExpires) {}
516
517     IMPLEMENT_SERIALIZE
518     (
519         if (!(nType & SER_GETHASH))
520             READWRITE(nVersion);
521         READWRITE(vchPrivKey);
522         READWRITE(nTimeCreated);
523         READWRITE(nTimeExpires);
524         READWRITE(strComment);
525     )
526 };
527
528
529
530
531 /** Account information.
532  * Stored in wallet with key "acc"+string account name.
533  */
534 class CAccount
535 {
536 public:
537     CPubKey vchPubKey;
538
539     CAccount()
540     {
541         SetNull();
542     }
543
544     void SetNull()
545     {
546         vchPubKey = CPubKey();
547     }
548
549     IMPLEMENT_SERIALIZE
550     (
551         if (!(nType & SER_GETHASH))
552             READWRITE(nVersion);
553         READWRITE(vchPubKey);
554     )
555 };
556
557
558
559 /** Internal transfers.
560  * Database key is acentry<account><counter>.
561  */
562 class CAccountingEntry
563 {
564 public:
565     std::string strAccount = "";
566     int64_t nCreditDebit = 0;
567     int64_t nTime = 0;
568     std::string strOtherAccount = "";
569     std::string strComment = "";
570     mapValue_t mapValue;
571     int64_t nOrderPos = -1;  // position in ordered transaction list
572     uint64_t nEntryNo = 0;
573
574     CAccountingEntry() { }
575
576     IMPLEMENT_SERIALIZE
577     (
578         CAccountingEntry& me = *const_cast<CAccountingEntry*>(this);
579         if (!(nType & SER_GETHASH))
580             READWRITE(nVersion);
581         // Note: strAccount is serialized as part of the key, not here.
582         READWRITE(nCreditDebit);
583         READWRITE(nTime);
584         READWRITE(strOtherAccount);
585
586         if (!fRead)
587         {
588             WriteOrderPos(nOrderPos, me.mapValue);
589
590             if (!(mapValue.empty() && _ssExtra.empty()))
591             {
592                 CDataStream ss(nType, nVersion);
593                 ss.insert(ss.begin(), '\0');
594                 ss << mapValue;
595                 ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end());
596                 me.strComment.append(ss.str());
597             }
598         }
599
600         READWRITE(strComment);
601
602         size_t nSepPos = strComment.find("\0", 0, 1);
603         if (fRead)
604         {
605             me.mapValue.clear();
606             if (std::string::npos != nSepPos)
607             {
608                 CDataStream ss(std::vector<char>(strComment.begin() + nSepPos + 1, strComment.end()), nType, nVersion);
609                 ss >> me.mapValue;
610                 me._ssExtra = std::vector<char>(ss.begin(), ss.end());
611             }
612             ReadOrderPos(me.nOrderPos, me.mapValue);
613         }
614         if (std::string::npos != nSepPos)
615             me.strComment.erase(nSepPos);
616
617         me.mapValue.erase("n");
618     )
619
620 private:
621     std::vector<char> _ssExtra;
622 };
623
624 bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
625
626 #endif