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