run as daemon without GUI,
[novacoin.git] / main.h
1 // Copyright (c) 2009-2010 Satoshi Nakamoto\r
2 // Distributed under the MIT/X11 software license, see the accompanying\r
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.\r
4 \r
5 class COutPoint;\r
6 class CInPoint;\r
7 class CDiskTxPos;\r
8 class CCoinBase;\r
9 class CTxIn;\r
10 class CTxOut;\r
11 class CTransaction;\r
12 class CBlock;\r
13 class CBlockIndex;\r
14 class CWalletTx;\r
15 class CKeyItem;\r
16 \r
17 static const unsigned int MAX_SIZE = 0x02000000;\r
18 static const int64 COIN = 100000000;\r
19 static const int64 CENT = 1000000;\r
20 static const int COINBASE_MATURITY = 100;\r
21 \r
22 static const CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);\r
23 \r
24 \r
25 \r
26 \r
27 \r
28 \r
29 extern CCriticalSection cs_main;\r
30 extern map<uint256, CBlockIndex*> mapBlockIndex;\r
31 extern const uint256 hashGenesisBlock;\r
32 extern CBlockIndex* pindexGenesisBlock;\r
33 extern int nBestHeight;\r
34 extern uint256 hashBestChain;\r
35 extern CBlockIndex* pindexBest;\r
36 extern unsigned int nTransactionsUpdated;\r
37 extern map<uint256, int> mapRequestCount;\r
38 extern CCriticalSection cs_mapRequestCount;\r
39 extern map<string, string> mapAddressBook;\r
40 extern CCriticalSection cs_mapAddressBook;\r
41 \r
42 // Settings\r
43 extern int fGenerateBitcoins;\r
44 extern int64 nTransactionFee;\r
45 extern CAddress addrIncoming;\r
46 extern int fLimitProcessors;\r
47 extern int nLimitProcessors;\r
48 \r
49 \r
50 \r
51 \r
52 \r
53 \r
54 \r
55 bool CheckDiskSpace(int64 nAdditionalBytes=0);\r
56 FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb");\r
57 FILE* AppendBlockFile(unsigned int& nFileRet);\r
58 bool AddKey(const CKey& key);\r
59 vector<unsigned char> GenerateNewKey();\r
60 bool AddToWallet(const CWalletTx& wtxIn);\r
61 void WalletUpdateSpent(const COutPoint& prevout);\r
62 void ReacceptWalletTransactions();\r
63 bool LoadBlockIndex(bool fAllowNew=true);\r
64 void PrintBlockTree();\r
65 bool ProcessMessages(CNode* pfrom);\r
66 bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv);\r
67 bool SendMessages(CNode* pto);\r
68 int64 GetBalance();\r
69 bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CKey& keyRet, int64& nFeeRequiredRet);\r
70 bool CommitTransaction(CWalletTx& wtxNew, const CKey& key);\r
71 bool BroadcastTransaction(CWalletTx& wtxNew);\r
72 string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);\r
73 string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);\r
74 void GenerateBitcoins(bool fGenerate);\r
75 void ThreadBitcoinMiner(void* parg);\r
76 void BitcoinMiner();\r
77 \r
78 \r
79 \r
80 \r
81 \r
82 \r
83 \r
84 \r
85 \r
86 \r
87 \r
88 \r
89 class CDiskTxPos\r
90 {\r
91 public:\r
92     unsigned int nFile;\r
93     unsigned int nBlockPos;\r
94     unsigned int nTxPos;\r
95 \r
96     CDiskTxPos()\r
97     {\r
98         SetNull();\r
99     }\r
100 \r
101     CDiskTxPos(unsigned int nFileIn, unsigned int nBlockPosIn, unsigned int nTxPosIn)\r
102     {\r
103         nFile = nFileIn;\r
104         nBlockPos = nBlockPosIn;\r
105         nTxPos = nTxPosIn;\r
106     }\r
107 \r
108     IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )\r
109     void SetNull() { nFile = -1; nBlockPos = 0; nTxPos = 0; }\r
110     bool IsNull() const { return (nFile == -1); }\r
111 \r
112     friend bool operator==(const CDiskTxPos& a, const CDiskTxPos& b)\r
113     {\r
114         return (a.nFile     == b.nFile &&\r
115                 a.nBlockPos == b.nBlockPos &&\r
116                 a.nTxPos    == b.nTxPos);\r
117     }\r
118 \r
119     friend bool operator!=(const CDiskTxPos& a, const CDiskTxPos& b)\r
120     {\r
121         return !(a == b);\r
122     }\r
123 \r
124     string ToString() const\r
125     {\r
126         if (IsNull())\r
127             return strprintf("null");\r
128         else\r
129             return strprintf("(nFile=%d, nBlockPos=%d, nTxPos=%d)", nFile, nBlockPos, nTxPos);\r
130     }\r
131 \r
132     void print() const\r
133     {\r
134         printf("%s", ToString().c_str());\r
135     }\r
136 };\r
137 \r
138 \r
139 \r
140 \r
141 class CInPoint\r
142 {\r
143 public:\r
144     CTransaction* ptx;\r
145     unsigned int n;\r
146 \r
147     CInPoint() { SetNull(); }\r
148     CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }\r
149     void SetNull() { ptx = NULL; n = -1; }\r
150     bool IsNull() const { return (ptx == NULL && n == -1); }\r
151 };\r
152 \r
153 \r
154 \r
155 \r
156 class COutPoint\r
157 {\r
158 public:\r
159     uint256 hash;\r
160     unsigned int n;\r
161 \r
162     COutPoint() { SetNull(); }\r
163     COutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; }\r
164     IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )\r
165     void SetNull() { hash = 0; n = -1; }\r
166     bool IsNull() const { return (hash == 0 && n == -1); }\r
167 \r
168     friend bool operator<(const COutPoint& a, const COutPoint& b)\r
169     {\r
170         return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));\r
171     }\r
172 \r
173     friend bool operator==(const COutPoint& a, const COutPoint& b)\r
174     {\r
175         return (a.hash == b.hash && a.n == b.n);\r
176     }\r
177 \r
178     friend bool operator!=(const COutPoint& a, const COutPoint& b)\r
179     {\r
180         return !(a == b);\r
181     }\r
182 \r
183     string ToString() const\r
184     {\r
185         return strprintf("COutPoint(%s, %d)", hash.ToString().substr(0,6).c_str(), n);\r
186     }\r
187 \r
188     void print() const\r
189     {\r
190         printf("%s\n", ToString().c_str());\r
191     }\r
192 };\r
193 \r
194 \r
195 \r
196 \r
197 //\r
198 // An input of a transaction.  It contains the location of the previous\r
199 // transaction's output that it claims and a signature that matches the\r
200 // output's public key.\r
201 //\r
202 class CTxIn\r
203 {\r
204 public:\r
205     COutPoint prevout;\r
206     CScript scriptSig;\r
207     unsigned int nSequence;\r
208 \r
209     CTxIn()\r
210     {\r
211         nSequence = UINT_MAX;\r
212     }\r
213 \r
214     explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=UINT_MAX)\r
215     {\r
216         prevout = prevoutIn;\r
217         scriptSig = scriptSigIn;\r
218         nSequence = nSequenceIn;\r
219     }\r
220 \r
221     CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=UINT_MAX)\r
222     {\r
223         prevout = COutPoint(hashPrevTx, nOut);\r
224         scriptSig = scriptSigIn;\r
225         nSequence = nSequenceIn;\r
226     }\r
227 \r
228     IMPLEMENT_SERIALIZE\r
229     (\r
230         READWRITE(prevout);\r
231         READWRITE(scriptSig);\r
232         READWRITE(nSequence);\r
233     )\r
234 \r
235     bool IsFinal() const\r
236     {\r
237         return (nSequence == UINT_MAX);\r
238     }\r
239 \r
240     friend bool operator==(const CTxIn& a, const CTxIn& b)\r
241     {\r
242         return (a.prevout   == b.prevout &&\r
243                 a.scriptSig == b.scriptSig &&\r
244                 a.nSequence == b.nSequence);\r
245     }\r
246 \r
247     friend bool operator!=(const CTxIn& a, const CTxIn& b)\r
248     {\r
249         return !(a == b);\r
250     }\r
251 \r
252     string ToString() const\r
253     {\r
254         string str;\r
255         str += strprintf("CTxIn(");\r
256         str += prevout.ToString();\r
257         if (prevout.IsNull())\r
258             str += strprintf(", coinbase %s", HexStr(scriptSig.begin(), scriptSig.end(), false).c_str());\r
259         else\r
260             str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str());\r
261         if (nSequence != UINT_MAX)\r
262             str += strprintf(", nSequence=%u", nSequence);\r
263         str += ")";\r
264         return str;\r
265     }\r
266 \r
267     void print() const\r
268     {\r
269         printf("%s\n", ToString().c_str());\r
270     }\r
271 \r
272     bool IsMine() const;\r
273     int64 GetDebit() const;\r
274 };\r
275 \r
276 \r
277 \r
278 \r
279 //\r
280 // An output of a transaction.  It contains the public key that the next input\r
281 // must be able to sign with to claim it.\r
282 //\r
283 class CTxOut\r
284 {\r
285 public:\r
286     int64 nValue;\r
287     CScript scriptPubKey;\r
288 \r
289 public:\r
290     CTxOut()\r
291     {\r
292         SetNull();\r
293     }\r
294 \r
295     CTxOut(int64 nValueIn, CScript scriptPubKeyIn)\r
296     {\r
297         nValue = nValueIn;\r
298         scriptPubKey = scriptPubKeyIn;\r
299     }\r
300 \r
301     IMPLEMENT_SERIALIZE\r
302     (\r
303         READWRITE(nValue);\r
304         READWRITE(scriptPubKey);\r
305     )\r
306 \r
307     void SetNull()\r
308     {\r
309         nValue = -1;\r
310         scriptPubKey.clear();\r
311     }\r
312 \r
313     bool IsNull()\r
314     {\r
315         return (nValue == -1);\r
316     }\r
317 \r
318     uint256 GetHash() const\r
319     {\r
320         return SerializeHash(*this);\r
321     }\r
322 \r
323     bool IsMine() const\r
324     {\r
325         return ::IsMine(scriptPubKey);\r
326     }\r
327 \r
328     int64 GetCredit() const\r
329     {\r
330         if (IsMine())\r
331             return nValue;\r
332         return 0;\r
333     }\r
334 \r
335     friend bool operator==(const CTxOut& a, const CTxOut& b)\r
336     {\r
337         return (a.nValue       == b.nValue &&\r
338                 a.scriptPubKey == b.scriptPubKey);\r
339     }\r
340 \r
341     friend bool operator!=(const CTxOut& a, const CTxOut& b)\r
342     {\r
343         return !(a == b);\r
344     }\r
345 \r
346     string ToString() const\r
347     {\r
348         if (scriptPubKey.size() < 6)\r
349             return "CTxOut(error)";\r
350         return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,24).c_str());\r
351     }\r
352 \r
353     void print() const\r
354     {\r
355         printf("%s\n", ToString().c_str());\r
356     }\r
357 };\r
358 \r
359 \r
360 \r
361 \r
362 //\r
363 // The basic transaction that is broadcasted on the network and contained in\r
364 // blocks.  A transaction can contain multiple inputs and outputs.\r
365 //\r
366 class CTransaction\r
367 {\r
368 public:\r
369     int nVersion;\r
370     vector<CTxIn> vin;\r
371     vector<CTxOut> vout;\r
372     unsigned int nLockTime;\r
373 \r
374 \r
375     CTransaction()\r
376     {\r
377         SetNull();\r
378     }\r
379 \r
380     IMPLEMENT_SERIALIZE\r
381     (\r
382         READWRITE(this->nVersion);\r
383         nVersion = this->nVersion;\r
384         READWRITE(vin);\r
385         READWRITE(vout);\r
386         READWRITE(nLockTime);\r
387     )\r
388 \r
389     void SetNull()\r
390     {\r
391         nVersion = 1;\r
392         vin.clear();\r
393         vout.clear();\r
394         nLockTime = 0;\r
395     }\r
396 \r
397     bool IsNull() const\r
398     {\r
399         return (vin.empty() && vout.empty());\r
400     }\r
401 \r
402     uint256 GetHash() const\r
403     {\r
404         return SerializeHash(*this);\r
405     }\r
406 \r
407     bool IsFinal(int64 nBlockTime=0) const\r
408     {\r
409         // Time based nLockTime implemented in 0.1.6,\r
410         // do not use time based until most 0.1.5 nodes have upgraded.\r
411         if (nLockTime == 0)\r
412             return true;\r
413         if (nBlockTime == 0)\r
414             nBlockTime = GetAdjustedTime();\r
415         if (nLockTime < (nLockTime < 500000000 ? nBestHeight : nBlockTime))\r
416             return true;\r
417         foreach(const CTxIn& txin, vin)\r
418             if (!txin.IsFinal())\r
419                 return false;\r
420         return true;\r
421     }\r
422 \r
423     bool IsNewerThan(const CTransaction& old) const\r
424     {\r
425         if (vin.size() != old.vin.size())\r
426             return false;\r
427         for (int i = 0; i < vin.size(); i++)\r
428             if (vin[i].prevout != old.vin[i].prevout)\r
429                 return false;\r
430 \r
431         bool fNewer = false;\r
432         unsigned int nLowest = UINT_MAX;\r
433         for (int i = 0; i < vin.size(); i++)\r
434         {\r
435             if (vin[i].nSequence != old.vin[i].nSequence)\r
436             {\r
437                 if (vin[i].nSequence <= nLowest)\r
438                 {\r
439                     fNewer = false;\r
440                     nLowest = vin[i].nSequence;\r
441                 }\r
442                 if (old.vin[i].nSequence < nLowest)\r
443                 {\r
444                     fNewer = true;\r
445                     nLowest = old.vin[i].nSequence;\r
446                 }\r
447             }\r
448         }\r
449         return fNewer;\r
450     }\r
451 \r
452     bool IsCoinBase() const\r
453     {\r
454         return (vin.size() == 1 && vin[0].prevout.IsNull());\r
455     }\r
456 \r
457     bool CheckTransaction() const\r
458     {\r
459         // Basic checks that don't depend on any context\r
460         if (vin.empty() || vout.empty())\r
461             return error("CTransaction::CheckTransaction() : vin or vout empty");\r
462 \r
463         // Check for negative values\r
464         foreach(const CTxOut& txout, vout)\r
465             if (txout.nValue < 0)\r
466                 return error("CTransaction::CheckTransaction() : txout.nValue negative");\r
467 \r
468         if (IsCoinBase())\r
469         {\r
470             if (vin[0].scriptSig.size() < 2 || vin[0].scriptSig.size() > 100)\r
471                 return error("CTransaction::CheckTransaction() : coinbase script size");\r
472         }\r
473         else\r
474         {\r
475             foreach(const CTxIn& txin, vin)\r
476                 if (txin.prevout.IsNull())\r
477                     return error("CTransaction::CheckTransaction() : prevout is null");\r
478         }\r
479 \r
480         return true;\r
481     }\r
482 \r
483     bool IsMine() const\r
484     {\r
485         foreach(const CTxOut& txout, vout)\r
486             if (txout.IsMine())\r
487                 return true;\r
488         return false;\r
489     }\r
490 \r
491     int64 GetDebit() const\r
492     {\r
493         int64 nDebit = 0;\r
494         foreach(const CTxIn& txin, vin)\r
495             nDebit += txin.GetDebit();\r
496         return nDebit;\r
497     }\r
498 \r
499     int64 GetCredit() const\r
500     {\r
501         int64 nCredit = 0;\r
502         foreach(const CTxOut& txout, vout)\r
503             nCredit += txout.GetCredit();\r
504         return nCredit;\r
505     }\r
506 \r
507     int64 GetValueOut() const\r
508     {\r
509         int64 nValueOut = 0;\r
510         foreach(const CTxOut& txout, vout)\r
511         {\r
512             if (txout.nValue < 0)\r
513                 throw runtime_error("CTransaction::GetValueOut() : negative value");\r
514             nValueOut += txout.nValue;\r
515         }\r
516         return nValueOut;\r
517     }\r
518 \r
519     int64 GetMinFee(unsigned int nBlockSize=1) const\r
520     {\r
521         // Base fee is 1 cent per kilobyte\r
522         unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK);\r
523         int64 nMinFee = (1 + (int64)nBytes / 1000) * CENT;\r
524 \r
525         // Transactions under 60K are free as long as block size is under 80K\r
526         // (about 27,000bc if made of 50bc inputs)\r
527         if (nBytes < 60000 && nBlockSize < 80000)\r
528             nMinFee = 0;\r
529 \r
530         // Transactions under 3K are free as long as block size is under 200K\r
531         if (nBytes < 3000 && nBlockSize < 200000)\r
532             nMinFee = 0;\r
533 \r
534         // To limit dust spam, require a 0.01 fee if any output is less than 0.01\r
535         if (nMinFee < CENT)\r
536             foreach(const CTxOut& txout, vout)\r
537                 if (txout.nValue < CENT)\r
538                     nMinFee = CENT;\r
539 \r
540         return nMinFee;\r
541     }\r
542 \r
543 \r
544 \r
545     bool ReadFromDisk(CDiskTxPos pos, FILE** pfileRet=NULL)\r
546     {\r
547         CAutoFile filein = OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb");\r
548         if (!filein)\r
549             return error("CTransaction::ReadFromDisk() : OpenBlockFile failed");\r
550 \r
551         // Read transaction\r
552         if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)\r
553             return error("CTransaction::ReadFromDisk() : fseek failed");\r
554         filein >> *this;\r
555 \r
556         // Return file pointer\r
557         if (pfileRet)\r
558         {\r
559             if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)\r
560                 return error("CTransaction::ReadFromDisk() : second fseek failed");\r
561             *pfileRet = filein.release();\r
562         }\r
563         return true;\r
564     }\r
565 \r
566 \r
567     friend bool operator==(const CTransaction& a, const CTransaction& b)\r
568     {\r
569         return (a.nVersion  == b.nVersion &&\r
570                 a.vin       == b.vin &&\r
571                 a.vout      == b.vout &&\r
572                 a.nLockTime == b.nLockTime);\r
573     }\r
574 \r
575     friend bool operator!=(const CTransaction& a, const CTransaction& b)\r
576     {\r
577         return !(a == b);\r
578     }\r
579 \r
580 \r
581     string ToString() const\r
582     {\r
583         string str;\r
584         str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%d, vout.size=%d, nLockTime=%d)\n",\r
585             GetHash().ToString().substr(0,6).c_str(),\r
586             nVersion,\r
587             vin.size(),\r
588             vout.size(),\r
589             nLockTime);\r
590         for (int i = 0; i < vin.size(); i++)\r
591             str += "    " + vin[i].ToString() + "\n";\r
592         for (int i = 0; i < vout.size(); i++)\r
593             str += "    " + vout[i].ToString() + "\n";\r
594         return str;\r
595     }\r
596 \r
597     void print() const\r
598     {\r
599         printf("%s", ToString().c_str());\r
600     }\r
601 \r
602 \r
603 \r
604     bool DisconnectInputs(CTxDB& txdb);\r
605     bool ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx, int nHeight, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee=0);\r
606     bool ClientConnectInputs();\r
607 \r
608     bool AcceptTransaction(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL);\r
609 \r
610     bool AcceptTransaction(bool fCheckInputs=true, bool* pfMissingInputs=NULL)\r
611     {\r
612         CTxDB txdb("r");\r
613         return AcceptTransaction(txdb, fCheckInputs, pfMissingInputs);\r
614     }\r
615 \r
616 protected:\r
617     bool AddToMemoryPool();\r
618 public:\r
619     bool RemoveFromMemoryPool();\r
620 };\r
621 \r
622 \r
623 \r
624 \r
625 \r
626 //\r
627 // A transaction with a merkle branch linking it to the block chain\r
628 //\r
629 class CMerkleTx : public CTransaction\r
630 {\r
631 public:\r
632     uint256 hashBlock;\r
633     vector<uint256> vMerkleBranch;\r
634     int nIndex;\r
635 \r
636     // memory only\r
637     mutable bool fMerkleVerified;\r
638     mutable bool fGetCreditCached;\r
639     mutable int64 nGetCreditCached;\r
640 \r
641 \r
642     CMerkleTx()\r
643     {\r
644         Init();\r
645     }\r
646 \r
647     CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)\r
648     {\r
649         Init();\r
650     }\r
651 \r
652     void Init()\r
653     {\r
654         hashBlock = 0;\r
655         nIndex = -1;\r
656         fMerkleVerified = false;\r
657         fGetCreditCached = false;\r
658         nGetCreditCached = 0;\r
659     }\r
660 \r
661     IMPLEMENT_SERIALIZE\r
662     (\r
663         nSerSize += SerReadWrite(s, *(CTransaction*)this, nType, nVersion, ser_action);\r
664         nVersion = this->nVersion;\r
665         READWRITE(hashBlock);\r
666         READWRITE(vMerkleBranch);\r
667         READWRITE(nIndex);\r
668     )\r
669 \r
670     int64 GetCredit(bool fUseCache=false) const\r
671     {\r
672         // Must wait until coinbase is safely deep enough in the chain before valuing it\r
673         if (IsCoinBase() && GetBlocksToMaturity() > 0)\r
674             return 0;\r
675 \r
676         // GetBalance can assume transactions in mapWallet won't change\r
677         if (fUseCache && fGetCreditCached)\r
678             return nGetCreditCached;\r
679         nGetCreditCached = CTransaction::GetCredit();\r
680         fGetCreditCached = true;\r
681         return nGetCreditCached;\r
682     }\r
683 \r
684 \r
685     int SetMerkleBranch(const CBlock* pblock=NULL);\r
686     int GetDepthInMainChain(int& nHeightRet) const;\r
687     int GetDepthInMainChain() const { int nHeight; return GetDepthInMainChain(nHeight); }\r
688     bool IsInMainChain() const { return GetDepthInMainChain() > 0; }\r
689     int GetBlocksToMaturity() const;\r
690     bool AcceptTransaction(CTxDB& txdb, bool fCheckInputs=true);\r
691     bool AcceptTransaction() { CTxDB txdb("r"); return AcceptTransaction(txdb); }\r
692 };\r
693 \r
694 \r
695 \r
696 \r
697 //\r
698 // A transaction with a bunch of additional info that only the owner cares\r
699 // about.  It includes any unrecorded transactions needed to link it back\r
700 // to the block chain.\r
701 //\r
702 class CWalletTx : public CMerkleTx\r
703 {\r
704 public:\r
705     vector<CMerkleTx> vtxPrev;\r
706     map<string, string> mapValue;\r
707     vector<pair<string, string> > vOrderForm;\r
708     unsigned int fTimeReceivedIsTxTime;\r
709     unsigned int nTimeReceived;  // time received by this node\r
710     char fFromMe;\r
711     char fSpent;\r
712     //// probably need to sign the order info so know it came from payer\r
713 \r
714     // memory only UI hints\r
715     mutable unsigned int nTimeDisplayed;\r
716     mutable int nLinesDisplayed;\r
717 \r
718 \r
719     CWalletTx()\r
720     {\r
721         Init();\r
722     }\r
723 \r
724     CWalletTx(const CMerkleTx& txIn) : CMerkleTx(txIn)\r
725     {\r
726         Init();\r
727     }\r
728 \r
729     CWalletTx(const CTransaction& txIn) : CMerkleTx(txIn)\r
730     {\r
731         Init();\r
732     }\r
733 \r
734     void Init()\r
735     {\r
736         fTimeReceivedIsTxTime = false;\r
737         nTimeReceived = 0;\r
738         fFromMe = false;\r
739         fSpent = false;\r
740         nTimeDisplayed = 0;\r
741         nLinesDisplayed = 0;\r
742     }\r
743 \r
744     IMPLEMENT_SERIALIZE\r
745     (\r
746         nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion, ser_action);\r
747         nVersion = this->nVersion;\r
748         READWRITE(vtxPrev);\r
749         READWRITE(mapValue);\r
750         READWRITE(vOrderForm);\r
751         READWRITE(fTimeReceivedIsTxTime);\r
752         READWRITE(nTimeReceived);\r
753         READWRITE(fFromMe);\r
754         READWRITE(fSpent);\r
755     )\r
756 \r
757     bool WriteToDisk()\r
758     {\r
759         return CWalletDB().WriteTx(GetHash(), *this);\r
760     }\r
761 \r
762 \r
763     int64 GetTxTime() const;\r
764     int GetRequestCount() const;\r
765 \r
766     void AddSupportingTransactions(CTxDB& txdb);\r
767 \r
768     bool AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs=true);\r
769     bool AcceptWalletTransaction() { CTxDB txdb("r"); return AcceptWalletTransaction(txdb); }\r
770 \r
771     void RelayWalletTransaction(CTxDB& txdb);\r
772     void RelayWalletTransaction() { CTxDB txdb("r"); RelayWalletTransaction(txdb); }\r
773 };\r
774 \r
775 \r
776 \r
777 \r
778 //\r
779 // A txdb record that contains the disk location of a transaction and the\r
780 // locations of transactions that spend its outputs.  vSpent is really only\r
781 // used as a flag, but having the location is very helpful for debugging.\r
782 //\r
783 class CTxIndex\r
784 {\r
785 public:\r
786     CDiskTxPos pos;\r
787     vector<CDiskTxPos> vSpent;\r
788 \r
789     CTxIndex()\r
790     {\r
791         SetNull();\r
792     }\r
793 \r
794     CTxIndex(const CDiskTxPos& posIn, unsigned int nOutputs)\r
795     {\r
796         pos = posIn;\r
797         vSpent.resize(nOutputs);\r
798     }\r
799 \r
800     IMPLEMENT_SERIALIZE\r
801     (\r
802         if (!(nType & SER_GETHASH))\r
803             READWRITE(nVersion);\r
804         READWRITE(pos);\r
805         READWRITE(vSpent);\r
806     )\r
807 \r
808     void SetNull()\r
809     {\r
810         pos.SetNull();\r
811         vSpent.clear();\r
812     }\r
813 \r
814     bool IsNull()\r
815     {\r
816         return pos.IsNull();\r
817     }\r
818 \r
819     friend bool operator==(const CTxIndex& a, const CTxIndex& b)\r
820     {\r
821         if (a.pos != b.pos || a.vSpent.size() != b.vSpent.size())\r
822             return false;\r
823         for (int i = 0; i < a.vSpent.size(); i++)\r
824             if (a.vSpent[i] != b.vSpent[i])\r
825                 return false;\r
826         return true;\r
827     }\r
828 \r
829     friend bool operator!=(const CTxIndex& a, const CTxIndex& b)\r
830     {\r
831         return !(a == b);\r
832     }\r
833 };\r
834 \r
835 \r
836 \r
837 \r
838 \r
839 //\r
840 // Nodes collect new transactions into a block, hash them into a hash tree,\r
841 // and scan through nonce values to make the block's hash satisfy proof-of-work\r
842 // requirements.  When they solve the proof-of-work, they broadcast the block\r
843 // to everyone and the block is added to the block chain.  The first transaction\r
844 // in the block is a special one that creates a new coin owned by the creator\r
845 // of the block.\r
846 //\r
847 // Blocks are appended to blk0001.dat files on disk.  Their location on disk\r
848 // is indexed by CBlockIndex objects in memory.\r
849 //\r
850 class CBlock\r
851 {\r
852 public:\r
853     // header\r
854     int nVersion;\r
855     uint256 hashPrevBlock;\r
856     uint256 hashMerkleRoot;\r
857     unsigned int nTime;\r
858     unsigned int nBits;\r
859     unsigned int nNonce;\r
860 \r
861     // network and disk\r
862     vector<CTransaction> vtx;\r
863 \r
864     // memory only\r
865     mutable vector<uint256> vMerkleTree;\r
866 \r
867 \r
868     CBlock()\r
869     {\r
870         SetNull();\r
871     }\r
872 \r
873     IMPLEMENT_SERIALIZE\r
874     (\r
875         READWRITE(this->nVersion);\r
876         nVersion = this->nVersion;\r
877         READWRITE(hashPrevBlock);\r
878         READWRITE(hashMerkleRoot);\r
879         READWRITE(nTime);\r
880         READWRITE(nBits);\r
881         READWRITE(nNonce);\r
882 \r
883         // ConnectBlock depends on vtx being last so it can calculate offset\r
884         if (!(nType & (SER_GETHASH|SER_BLOCKHEADERONLY)))\r
885             READWRITE(vtx);\r
886         else if (fRead)\r
887             const_cast<CBlock*>(this)->vtx.clear();\r
888     )\r
889 \r
890     void SetNull()\r
891     {\r
892         nVersion = 1;\r
893         hashPrevBlock = 0;\r
894         hashMerkleRoot = 0;\r
895         nTime = 0;\r
896         nBits = 0;\r
897         nNonce = 0;\r
898         vtx.clear();\r
899         vMerkleTree.clear();\r
900     }\r
901 \r
902     bool IsNull() const\r
903     {\r
904         return (nBits == 0);\r
905     }\r
906 \r
907     uint256 GetHash() const\r
908     {\r
909         return Hash(BEGIN(nVersion), END(nNonce));\r
910     }\r
911 \r
912 \r
913     uint256 BuildMerkleTree() const\r
914     {\r
915         vMerkleTree.clear();\r
916         foreach(const CTransaction& tx, vtx)\r
917             vMerkleTree.push_back(tx.GetHash());\r
918         int j = 0;\r
919         for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)\r
920         {\r
921             for (int i = 0; i < nSize; i += 2)\r
922             {\r
923                 int i2 = min(i+1, nSize-1);\r
924                 vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]),  END(vMerkleTree[j+i]),\r
925                                            BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));\r
926             }\r
927             j += nSize;\r
928         }\r
929         return (vMerkleTree.empty() ? 0 : vMerkleTree.back());\r
930     }\r
931 \r
932     vector<uint256> GetMerkleBranch(int nIndex) const\r
933     {\r
934         if (vMerkleTree.empty())\r
935             BuildMerkleTree();\r
936         vector<uint256> vMerkleBranch;\r
937         int j = 0;\r
938         for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)\r
939         {\r
940             int i = min(nIndex^1, nSize-1);\r
941             vMerkleBranch.push_back(vMerkleTree[j+i]);\r
942             nIndex >>= 1;\r
943             j += nSize;\r
944         }\r
945         return vMerkleBranch;\r
946     }\r
947 \r
948     static uint256 CheckMerkleBranch(uint256 hash, const vector<uint256>& vMerkleBranch, int nIndex)\r
949     {\r
950         if (nIndex == -1)\r
951             return 0;\r
952         foreach(const uint256& otherside, vMerkleBranch)\r
953         {\r
954             if (nIndex & 1)\r
955                 hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash));\r
956             else\r
957                 hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside));\r
958             nIndex >>= 1;\r
959         }\r
960         return hash;\r
961     }\r
962 \r
963 \r
964     bool WriteToDisk(bool fWriteTransactions, unsigned int& nFileRet, unsigned int& nBlockPosRet)\r
965     {\r
966         // Open history file to append\r
967         CAutoFile fileout = AppendBlockFile(nFileRet);\r
968         if (!fileout)\r
969             return error("CBlock::WriteToDisk() : AppendBlockFile failed");\r
970         if (!fWriteTransactions)\r
971             fileout.nType |= SER_BLOCKHEADERONLY;\r
972 \r
973         // Write index header\r
974         unsigned int nSize = fileout.GetSerializeSize(*this);\r
975         fileout << FLATDATA(pchMessageStart) << nSize;\r
976 \r
977         // Write block\r
978         nBlockPosRet = ftell(fileout);\r
979         if (nBlockPosRet == -1)\r
980             return error("CBlock::WriteToDisk() : ftell failed");\r
981         fileout << *this;\r
982 \r
983         // Flush stdio buffers and commit to disk before returning\r
984         fflush(fileout);\r
985 #ifdef __WXMSW__\r
986         _commit(_fileno(fileout));\r
987 #else\r
988         fsync(fileno(fileout));\r
989 #endif\r
990 \r
991         return true;\r
992     }\r
993 \r
994     bool ReadFromDisk(unsigned int nFile, unsigned int nBlockPos, bool fReadTransactions=true)\r
995     {\r
996         SetNull();\r
997 \r
998         // Open history file to read\r
999         CAutoFile filein = OpenBlockFile(nFile, nBlockPos, "rb");\r
1000         if (!filein)\r
1001             return error("CBlock::ReadFromDisk() : OpenBlockFile failed");\r
1002         if (!fReadTransactions)\r
1003             filein.nType |= SER_BLOCKHEADERONLY;\r
1004 \r
1005         // Read block\r
1006         filein >> *this;\r
1007 \r
1008         // Check the header\r
1009         if (CBigNum().SetCompact(nBits) > bnProofOfWorkLimit)\r
1010             return error("CBlock::ReadFromDisk() : nBits errors in block header");\r
1011         if (GetHash() > CBigNum().SetCompact(nBits).getuint256())\r
1012             return error("CBlock::ReadFromDisk() : GetHash() errors in block header");\r
1013 \r
1014         return true;\r
1015     }\r
1016 \r
1017 \r
1018 \r
1019     void print() const\r
1020     {\r
1021         printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%d)\n",\r
1022             GetHash().ToString().substr(0,16).c_str(),\r
1023             nVersion,\r
1024             hashPrevBlock.ToString().substr(0,16).c_str(),\r
1025             hashMerkleRoot.ToString().substr(0,6).c_str(),\r
1026             nTime, nBits, nNonce,\r
1027             vtx.size());\r
1028         for (int i = 0; i < vtx.size(); i++)\r
1029         {\r
1030             printf("  ");\r
1031             vtx[i].print();\r
1032         }\r
1033         printf("  vMerkleTree: ");\r
1034         for (int i = 0; i < vMerkleTree.size(); i++)\r
1035             printf("%s ", vMerkleTree[i].ToString().substr(0,6).c_str());\r
1036         printf("\n");\r
1037     }\r
1038 \r
1039 \r
1040     int64 GetBlockValue(int64 nFees) const;\r
1041     bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex);\r
1042     bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex);\r
1043     bool ReadFromDisk(const CBlockIndex* blockindex, bool fReadTransactions=true);\r
1044     bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos);\r
1045     bool CheckBlock() const;\r
1046     bool AcceptBlock();\r
1047 };\r
1048 \r
1049 \r
1050 \r
1051 \r
1052 \r
1053 \r
1054 //\r
1055 // The block chain is a tree shaped structure starting with the\r
1056 // genesis block at the root, with each block potentially having multiple\r
1057 // candidates to be the next block.  pprev and pnext link a path through the\r
1058 // main/longest chain.  A blockindex may have multiple pprev pointing back\r
1059 // to it, but pnext will only point forward to the longest branch, or will\r
1060 // be null if the block is not part of the longest chain.\r
1061 //\r
1062 class CBlockIndex\r
1063 {\r
1064 public:\r
1065     const uint256* phashBlock;\r
1066     CBlockIndex* pprev;\r
1067     CBlockIndex* pnext;\r
1068     unsigned int nFile;\r
1069     unsigned int nBlockPos;\r
1070     int nHeight;\r
1071 \r
1072     // block header\r
1073     int nVersion;\r
1074     uint256 hashMerkleRoot;\r
1075     unsigned int nTime;\r
1076     unsigned int nBits;\r
1077     unsigned int nNonce;\r
1078 \r
1079 \r
1080     CBlockIndex()\r
1081     {\r
1082         phashBlock = NULL;\r
1083         pprev = NULL;\r
1084         pnext = NULL;\r
1085         nFile = 0;\r
1086         nBlockPos = 0;\r
1087         nHeight = 0;\r
1088 \r
1089         nVersion       = 0;\r
1090         hashMerkleRoot = 0;\r
1091         nTime          = 0;\r
1092         nBits          = 0;\r
1093         nNonce         = 0;\r
1094     }\r
1095 \r
1096     CBlockIndex(unsigned int nFileIn, unsigned int nBlockPosIn, CBlock& block)\r
1097     {\r
1098         phashBlock = NULL;\r
1099         pprev = NULL;\r
1100         pnext = NULL;\r
1101         nFile = nFileIn;\r
1102         nBlockPos = nBlockPosIn;\r
1103         nHeight = 0;\r
1104 \r
1105         nVersion       = block.nVersion;\r
1106         hashMerkleRoot = block.hashMerkleRoot;\r
1107         nTime          = block.nTime;\r
1108         nBits          = block.nBits;\r
1109         nNonce         = block.nNonce;\r
1110     }\r
1111 \r
1112     uint256 GetBlockHash() const\r
1113     {\r
1114         return *phashBlock;\r
1115     }\r
1116 \r
1117     bool IsInMainChain() const\r
1118     {\r
1119         return (pnext || this == pindexBest);\r
1120     }\r
1121 \r
1122     bool EraseBlockFromDisk()\r
1123     {\r
1124         // Open history file\r
1125         CAutoFile fileout = OpenBlockFile(nFile, nBlockPos, "rb+");\r
1126         if (!fileout)\r
1127             return false;\r
1128 \r
1129         // Overwrite with empty null block\r
1130         CBlock block;\r
1131         block.SetNull();\r
1132         fileout << block;\r
1133 \r
1134         return true;\r
1135     }\r
1136 \r
1137     enum { nMedianTimeSpan=11 };\r
1138 \r
1139     int64 GetMedianTimePast() const\r
1140     {\r
1141         unsigned int pmedian[nMedianTimeSpan];\r
1142         unsigned int* pbegin = &pmedian[nMedianTimeSpan];\r
1143         unsigned int* pend = &pmedian[nMedianTimeSpan];\r
1144 \r
1145         const CBlockIndex* pindex = this;\r
1146         for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev)\r
1147             *(--pbegin) = pindex->nTime;\r
1148 \r
1149         sort(pbegin, pend);\r
1150         return pbegin[(pend - pbegin)/2];\r
1151     }\r
1152 \r
1153     int64 GetMedianTime() const\r
1154     {\r
1155         const CBlockIndex* pindex = this;\r
1156         for (int i = 0; i < nMedianTimeSpan/2; i++)\r
1157         {\r
1158             if (!pindex->pnext)\r
1159                 return nTime;\r
1160             pindex = pindex->pnext;\r
1161         }\r
1162         return pindex->GetMedianTimePast();\r
1163     }\r
1164 \r
1165 \r
1166 \r
1167     string ToString() const\r
1168     {\r
1169         return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nHeight=%d, merkle=%s, hashBlock=%s)",\r
1170             pprev, pnext, nFile, nBlockPos, nHeight,\r
1171             hashMerkleRoot.ToString().substr(0,6).c_str(),\r
1172             GetBlockHash().ToString().substr(0,16).c_str());\r
1173     }\r
1174 \r
1175     void print() const\r
1176     {\r
1177         printf("%s\n", ToString().c_str());\r
1178     }\r
1179 };\r
1180 \r
1181 \r
1182 \r
1183 //\r
1184 // Used to marshal pointers into hashes for db storage.\r
1185 //\r
1186 class CDiskBlockIndex : public CBlockIndex\r
1187 {\r
1188 public:\r
1189     uint256 hashPrev;\r
1190     uint256 hashNext;\r
1191 \r
1192     CDiskBlockIndex()\r
1193     {\r
1194         hashPrev = 0;\r
1195         hashNext = 0;\r
1196     }\r
1197 \r
1198     explicit CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex)\r
1199     {\r
1200         hashPrev = (pprev ? pprev->GetBlockHash() : 0);\r
1201         hashNext = (pnext ? pnext->GetBlockHash() : 0);\r
1202     }\r
1203 \r
1204     IMPLEMENT_SERIALIZE\r
1205     (\r
1206         if (!(nType & SER_GETHASH))\r
1207             READWRITE(nVersion);\r
1208 \r
1209         READWRITE(hashNext);\r
1210         READWRITE(nFile);\r
1211         READWRITE(nBlockPos);\r
1212         READWRITE(nHeight);\r
1213 \r
1214         // block header\r
1215         READWRITE(this->nVersion);\r
1216         READWRITE(hashPrev);\r
1217         READWRITE(hashMerkleRoot);\r
1218         READWRITE(nTime);\r
1219         READWRITE(nBits);\r
1220         READWRITE(nNonce);\r
1221     )\r
1222 \r
1223     uint256 GetBlockHash() const\r
1224     {\r
1225         CBlock block;\r
1226         block.nVersion        = nVersion;\r
1227         block.hashPrevBlock   = hashPrev;\r
1228         block.hashMerkleRoot  = hashMerkleRoot;\r
1229         block.nTime           = nTime;\r
1230         block.nBits           = nBits;\r
1231         block.nNonce          = nNonce;\r
1232         return block.GetHash();\r
1233     }\r
1234 \r
1235 \r
1236     string ToString() const\r
1237     {\r
1238         string str = "CDiskBlockIndex(";\r
1239         str += CBlockIndex::ToString();\r
1240         str += strprintf("\n                hashBlock=%s, hashPrev=%s, hashNext=%s)",\r
1241             GetBlockHash().ToString().c_str(),\r
1242             hashPrev.ToString().substr(0,16).c_str(),\r
1243             hashNext.ToString().substr(0,16).c_str());\r
1244         return str;\r
1245     }\r
1246 \r
1247     void print() const\r
1248     {\r
1249         printf("%s\n", ToString().c_str());\r
1250     }\r
1251 };\r
1252 \r
1253 \r
1254 \r
1255 \r
1256 \r
1257 \r
1258 \r
1259 \r
1260 //\r
1261 // Describes a place in the block chain to another node such that if the\r
1262 // other node doesn't have the same branch, it can find a recent common trunk.\r
1263 // The further back it is, the further before the fork it may be.\r
1264 //\r
1265 class CBlockLocator\r
1266 {\r
1267 protected:\r
1268     vector<uint256> vHave;\r
1269 public:\r
1270 \r
1271     CBlockLocator()\r
1272     {\r
1273     }\r
1274 \r
1275     explicit CBlockLocator(const CBlockIndex* pindex)\r
1276     {\r
1277         Set(pindex);\r
1278     }\r
1279 \r
1280     explicit CBlockLocator(uint256 hashBlock)\r
1281     {\r
1282         map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);\r
1283         if (mi != mapBlockIndex.end())\r
1284             Set((*mi).second);\r
1285     }\r
1286 \r
1287     IMPLEMENT_SERIALIZE\r
1288     (\r
1289         if (!(nType & SER_GETHASH))\r
1290             READWRITE(nVersion);\r
1291         READWRITE(vHave);\r
1292     )\r
1293 \r
1294     void Set(const CBlockIndex* pindex)\r
1295     {\r
1296         vHave.clear();\r
1297         int nStep = 1;\r
1298         while (pindex)\r
1299         {\r
1300             vHave.push_back(pindex->GetBlockHash());\r
1301 \r
1302             // Exponentially larger steps back\r
1303             for (int i = 0; pindex && i < nStep; i++)\r
1304                 pindex = pindex->pprev;\r
1305             if (vHave.size() > 10)\r
1306                 nStep *= 2;\r
1307         }\r
1308         vHave.push_back(hashGenesisBlock);\r
1309     }\r
1310 \r
1311     int GetDistanceBack()\r
1312     {\r
1313         // Retrace how far back it was in the sender's branch\r
1314         int nDistance = 0;\r
1315         int nStep = 1;\r
1316         foreach(const uint256& hash, vHave)\r
1317         {\r
1318             map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);\r
1319             if (mi != mapBlockIndex.end())\r
1320             {\r
1321                 CBlockIndex* pindex = (*mi).second;\r
1322                 if (pindex->IsInMainChain())\r
1323                     return nDistance;\r
1324             }\r
1325             nDistance += nStep;\r
1326             if (nDistance > 10)\r
1327                 nStep *= 2;\r
1328         }\r
1329         return nDistance;\r
1330     }\r
1331 \r
1332     CBlockIndex* GetBlockIndex()\r
1333     {\r
1334         // Find the first block the caller has in the main chain\r
1335         foreach(const uint256& hash, vHave)\r
1336         {\r
1337             map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);\r
1338             if (mi != mapBlockIndex.end())\r
1339             {\r
1340                 CBlockIndex* pindex = (*mi).second;\r
1341                 if (pindex->IsInMainChain())\r
1342                     return pindex;\r
1343             }\r
1344         }\r
1345         return pindexGenesisBlock;\r
1346     }\r
1347 \r
1348     uint256 GetBlockHash()\r
1349     {\r
1350         // Find the first block the caller has in the main chain\r
1351         foreach(const uint256& hash, vHave)\r
1352         {\r
1353             map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);\r
1354             if (mi != mapBlockIndex.end())\r
1355             {\r
1356                 CBlockIndex* pindex = (*mi).second;\r
1357                 if (pindex->IsInMainChain())\r
1358                     return hash;\r
1359             }\r
1360         }\r
1361         return hashGenesisBlock;\r
1362     }\r
1363 \r
1364     int GetHeight()\r
1365     {\r
1366         CBlockIndex* pindex = GetBlockIndex();\r
1367         if (!pindex)\r
1368             return 0;\r
1369         return pindex->nHeight;\r
1370     }\r
1371 };\r
1372 \r
1373 \r
1374 \r
1375 \r
1376 \r
1377 \r
1378 //\r
1379 // Private key that includes an expiration date in case it never gets used.\r
1380 //\r
1381 class CWalletKey\r
1382 {\r
1383 public:\r
1384     CPrivKey vchPrivKey;\r
1385     int64 nTimeCreated;\r
1386     int64 nTimeExpires;\r
1387     string strComment;\r
1388     //// todo: add something to note what created it (user, getnewaddress, change)\r
1389     ////   maybe should have a map<string, string> property map\r
1390 \r
1391     CWalletKey(int64 nTimeExpiresIn=0)\r
1392     {\r
1393         nTimeCreated = (nTimeExpiresIn ? GetTime() : 0);\r
1394         nTimeExpires = nTimeExpiresIn;\r
1395     }\r
1396 \r
1397     IMPLEMENT_SERIALIZE\r
1398     (\r
1399         if (!(nType & SER_GETHASH))\r
1400             READWRITE(nVersion);\r
1401         READWRITE(vchPrivKey);\r
1402         READWRITE(nTimeCreated);\r
1403         READWRITE(nTimeExpires);\r
1404         READWRITE(strComment);\r
1405     )\r
1406 };\r
1407 \r
1408 \r
1409 \r
1410 \r
1411 \r
1412 \r
1413 extern map<uint256, CTransaction> mapTransactions;\r
1414 extern map<uint256, CWalletTx> mapWallet;\r
1415 extern vector<uint256> vWalletUpdated;\r
1416 extern CCriticalSection cs_mapWallet;\r
1417 extern map<vector<unsigned char>, CPrivKey> mapKeys;\r
1418 extern map<uint160, vector<unsigned char> > mapPubKeys;\r
1419 extern CCriticalSection cs_mapKeys;\r
1420 extern CKey keyUser;\r