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