Use std::numeric_limits<> for typesafe INT_MAX/etc
[novacoin.git] / src / main.h
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2011 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
5 #ifndef BITCOIN_MAIN_H
6 #define BITCOIN_MAIN_H
7
8 #include "bignum.h"
9 #include "net.h"
10 #include "key.h"
11 #include "script.h"
12 #include "db.h"
13
14 #include <list>
15
16 class CBlock;
17 class CBlockIndex;
18 class CWalletTx;
19 class CWallet;
20 class CKeyItem;
21 class CReserveKey;
22 class CWalletDB;
23
24 class CAddress;
25 class CInv;
26 class CRequestTracker;
27 class CNode;
28 class CBlockIndex;
29
30 static const int CLIENT_VERSION = 59900;
31 static const bool VERSION_IS_BETA = true;
32 extern const std::string CLIENT_NAME;
33
34 static const unsigned int MAX_BLOCK_SIZE = 1000000;
35 static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
36 static const int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
37 static const int64 COIN = 100000000;
38 static const int64 CENT = 1000000;
39 static const int64 MIN_TX_FEE = 50000;
40 static const int64 MIN_RELAY_TX_FEE = 10000;
41 static const int64 MAX_MONEY = 21000000 * COIN;
42 inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
43 static const int COINBASE_MATURITY = 100;
44 // Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp.
45 static const int LOCKTIME_THRESHOLD = 500000000; // Tue Nov  5 00:53:20 1985 UTC
46 #ifdef USE_UPNP
47 static const int fHaveUPnP = true;
48 #else
49 static const int fHaveUPnP = false;
50 #endif
51
52
53
54
55
56
57 extern CCriticalSection cs_main;
58 extern std::map<uint256, CBlockIndex*> mapBlockIndex;
59 extern uint256 hashGenesisBlock;
60 extern CBlockIndex* pindexGenesisBlock;
61 extern int nBestHeight;
62 extern CBigNum bnBestChainWork;
63 extern CBigNum bnBestInvalidWork;
64 extern uint256 hashBestChain;
65 extern CBlockIndex* pindexBest;
66 extern unsigned int nTransactionsUpdated;
67 extern double dHashesPerSec;
68 extern int64 nHPSTimerStart;
69 extern int64 nTimeBestReceived;
70 extern CCriticalSection cs_setpwalletRegistered;
71 extern std::set<CWallet*> setpwalletRegistered;
72
73 // Settings
74 extern int fGenerateBitcoins;
75 extern int64 nTransactionFee;
76 extern int fLimitProcessors;
77 extern int nLimitProcessors;
78 extern int fMinimizeToTray;
79 extern int fMinimizeOnClose;
80 extern int fUseUPnP;
81
82
83
84
85
86 class CReserveKey;
87 class CTxDB;
88 class CTxIndex;
89
90 void RegisterWallet(CWallet* pwalletIn);
91 void UnregisterWallet(CWallet* pwalletIn);
92 bool ProcessBlock(CNode* pfrom, CBlock* pblock);
93 bool CheckDiskSpace(uint64 nAdditionalBytes=0);
94 FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb");
95 FILE* AppendBlockFile(unsigned int& nFileRet);
96 bool LoadBlockIndex(bool fAllowNew=true);
97 void PrintBlockTree();
98 bool ProcessMessages(CNode* pfrom);
99 bool SendMessages(CNode* pto, bool fSendTrickle);
100 void GenerateBitcoins(bool fGenerate, CWallet* pwallet);
101 CBlock* CreateNewBlock(CReserveKey& reservekey);
102 void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
103 void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
104 bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
105 bool CheckProofOfWork(uint256 hash, unsigned int nBits);
106 unsigned int ComputeMinWork(unsigned int nBase, int64 nTime);
107 int GetNumBlocksOfPeers();
108 bool IsInitialBlockDownload();
109 std::string GetWarnings(std::string strFor);
110
111
112
113
114
115
116
117
118
119
120
121
122 bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut);
123
124 template<typename T>
125 bool WriteSetting(const std::string& strKey, const T& value)
126 {
127     bool fOk = false;
128     BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
129     {
130         std::string strWalletFile;
131         if (!GetWalletFile(pwallet, strWalletFile))
132             continue;
133         fOk |= CWalletDB(strWalletFile).WriteSetting(strKey, value);
134     }
135     return fOk;
136 }
137
138
139 class CDiskTxPos
140 {
141 public:
142     unsigned int nFile;
143     unsigned int nBlockPos;
144     unsigned int nTxPos;
145
146     CDiskTxPos()
147     {
148         SetNull();
149     }
150
151     CDiskTxPos(unsigned int nFileIn, unsigned int nBlockPosIn, unsigned int nTxPosIn)
152     {
153         nFile = nFileIn;
154         nBlockPos = nBlockPosIn;
155         nTxPos = nTxPosIn;
156     }
157
158     IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
159     void SetNull() { nFile = -1; nBlockPos = 0; nTxPos = 0; }
160     bool IsNull() const { return (nFile == -1); }
161
162     friend bool operator==(const CDiskTxPos& a, const CDiskTxPos& b)
163     {
164         return (a.nFile     == b.nFile &&
165                 a.nBlockPos == b.nBlockPos &&
166                 a.nTxPos    == b.nTxPos);
167     }
168
169     friend bool operator!=(const CDiskTxPos& a, const CDiskTxPos& b)
170     {
171         return !(a == b);
172     }
173
174     std::string ToString() const
175     {
176         if (IsNull())
177             return strprintf("null");
178         else
179             return strprintf("(nFile=%d, nBlockPos=%d, nTxPos=%d)", nFile, nBlockPos, nTxPos);
180     }
181
182     void print() const
183     {
184         printf("%s", ToString().c_str());
185     }
186 };
187
188
189
190
191 class CInPoint
192 {
193 public:
194     CTransaction* ptx;
195     unsigned int n;
196
197     CInPoint() { SetNull(); }
198     CInPoint(CTransaction* ptxIn, unsigned int nIn) { ptx = ptxIn; n = nIn; }
199     void SetNull() { ptx = NULL; n = -1; }
200     bool IsNull() const { return (ptx == NULL && n == -1); }
201 };
202
203
204
205
206 class COutPoint
207 {
208 public:
209     uint256 hash;
210     unsigned int n;
211
212     COutPoint() { SetNull(); }
213     COutPoint(uint256 hashIn, unsigned int nIn) { hash = hashIn; n = nIn; }
214     IMPLEMENT_SERIALIZE( READWRITE(FLATDATA(*this)); )
215     void SetNull() { hash = 0; n = -1; }
216     bool IsNull() const { return (hash == 0 && n == -1); }
217
218     friend bool operator<(const COutPoint& a, const COutPoint& b)
219     {
220         return (a.hash < b.hash || (a.hash == b.hash && a.n < b.n));
221     }
222
223     friend bool operator==(const COutPoint& a, const COutPoint& b)
224     {
225         return (a.hash == b.hash && a.n == b.n);
226     }
227
228     friend bool operator!=(const COutPoint& a, const COutPoint& b)
229     {
230         return !(a == b);
231     }
232
233     std::string ToString() const
234     {
235         return strprintf("COutPoint(%s, %d)", hash.ToString().substr(0,10).c_str(), n);
236     }
237
238     void print() const
239     {
240         printf("%s\n", ToString().c_str());
241     }
242 };
243
244
245
246
247 //
248 // An input of a transaction.  It contains the location of the previous
249 // transaction's output that it claims and a signature that matches the
250 // output's public key.
251 //
252 class CTxIn
253 {
254 public:
255     COutPoint prevout;
256     CScript scriptSig;
257     unsigned int nSequence;
258
259     CTxIn()
260     {
261         nSequence = std::numeric_limits<unsigned int>::max();
262     }
263
264     explicit CTxIn(COutPoint prevoutIn, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max())
265     {
266         prevout = prevoutIn;
267         scriptSig = scriptSigIn;
268         nSequence = nSequenceIn;
269     }
270
271     CTxIn(uint256 hashPrevTx, unsigned int nOut, CScript scriptSigIn=CScript(), unsigned int nSequenceIn=std::numeric_limits<unsigned int>::max())
272     {
273         prevout = COutPoint(hashPrevTx, nOut);
274         scriptSig = scriptSigIn;
275         nSequence = nSequenceIn;
276     }
277
278     IMPLEMENT_SERIALIZE
279     (
280         READWRITE(prevout);
281         READWRITE(scriptSig);
282         READWRITE(nSequence);
283     )
284
285     bool IsFinal() const
286     {
287         return (nSequence == std::numeric_limits<unsigned int>::max());
288     }
289
290     friend bool operator==(const CTxIn& a, const CTxIn& b)
291     {
292         return (a.prevout   == b.prevout &&
293                 a.scriptSig == b.scriptSig &&
294                 a.nSequence == b.nSequence);
295     }
296
297     friend bool operator!=(const CTxIn& a, const CTxIn& b)
298     {
299         return !(a == b);
300     }
301
302     std::string ToString() const
303     {
304         std::string str;
305         str += strprintf("CTxIn(");
306         str += prevout.ToString();
307         if (prevout.IsNull())
308             str += strprintf(", coinbase %s", HexStr(scriptSig).c_str());
309         else
310             str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24).c_str());
311         if (nSequence != std::numeric_limits<unsigned int>::max())
312             str += strprintf(", nSequence=%u", nSequence);
313         str += ")";
314         return str;
315     }
316
317     void print() const
318     {
319         printf("%s\n", ToString().c_str());
320     }
321 };
322
323
324
325
326 //
327 // An output of a transaction.  It contains the public key that the next input
328 // must be able to sign with to claim it.
329 //
330 class CTxOut
331 {
332 public:
333     int64 nValue;
334     CScript scriptPubKey;
335
336     CTxOut()
337     {
338         SetNull();
339     }
340
341     CTxOut(int64 nValueIn, CScript scriptPubKeyIn)
342     {
343         nValue = nValueIn;
344         scriptPubKey = scriptPubKeyIn;
345     }
346
347     IMPLEMENT_SERIALIZE
348     (
349         READWRITE(nValue);
350         READWRITE(scriptPubKey);
351     )
352
353     void SetNull()
354     {
355         nValue = -1;
356         scriptPubKey.clear();
357     }
358
359     bool IsNull()
360     {
361         return (nValue == -1);
362     }
363
364     uint256 GetHash() const
365     {
366         return SerializeHash(*this);
367     }
368
369     friend bool operator==(const CTxOut& a, const CTxOut& b)
370     {
371         return (a.nValue       == b.nValue &&
372                 a.scriptPubKey == b.scriptPubKey);
373     }
374
375     friend bool operator!=(const CTxOut& a, const CTxOut& b)
376     {
377         return !(a == b);
378     }
379
380     std::string ToString() const
381     {
382         if (scriptPubKey.size() < 6)
383             return "CTxOut(error)";
384         return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30).c_str());
385     }
386
387     void print() const
388     {
389         printf("%s\n", ToString().c_str());
390     }
391 };
392
393
394
395
396 //
397 // The basic transaction that is broadcasted on the network and contained in
398 // blocks.  A transaction can contain multiple inputs and outputs.
399 //
400 class CTransaction
401 {
402 public:
403     int nVersion;
404     std::vector<CTxIn> vin;
405     std::vector<CTxOut> vout;
406     unsigned int nLockTime;
407
408     // Denial-of-service detection:
409     mutable int nDoS;
410     bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; }
411
412     CTransaction()
413     {
414         SetNull();
415     }
416
417     IMPLEMENT_SERIALIZE
418     (
419         READWRITE(this->nVersion);
420         nVersion = this->nVersion;
421         READWRITE(vin);
422         READWRITE(vout);
423         READWRITE(nLockTime);
424     )
425
426     void SetNull()
427     {
428         nVersion = 1;
429         vin.clear();
430         vout.clear();
431         nLockTime = 0;
432         nDoS = 0;  // Denial-of-service prevention
433     }
434
435     bool IsNull() const
436     {
437         return (vin.empty() && vout.empty());
438     }
439
440     uint256 GetHash() const
441     {
442         return SerializeHash(*this);
443     }
444
445     bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const
446     {
447         // Time based nLockTime implemented in 0.1.6
448         if (nLockTime == 0)
449             return true;
450         if (nBlockHeight == 0)
451             nBlockHeight = nBestHeight;
452         if (nBlockTime == 0)
453             nBlockTime = GetAdjustedTime();
454         if ((int64)nLockTime < (nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime))
455             return true;
456         BOOST_FOREACH(const CTxIn& txin, vin)
457             if (!txin.IsFinal())
458                 return false;
459         return true;
460     }
461
462     bool IsNewerThan(const CTransaction& old) const
463     {
464         if (vin.size() != old.vin.size())
465             return false;
466         for (int i = 0; i < vin.size(); i++)
467             if (vin[i].prevout != old.vin[i].prevout)
468                 return false;
469
470         bool fNewer = false;
471         unsigned int nLowest = std::numeric_limits<unsigned int>::max();
472         for (int i = 0; i < vin.size(); i++)
473         {
474             if (vin[i].nSequence != old.vin[i].nSequence)
475             {
476                 if (vin[i].nSequence <= nLowest)
477                 {
478                     fNewer = false;
479                     nLowest = vin[i].nSequence;
480                 }
481                 if (old.vin[i].nSequence < nLowest)
482                 {
483                     fNewer = true;
484                     nLowest = old.vin[i].nSequence;
485                 }
486             }
487         }
488         return fNewer;
489     }
490
491     bool IsCoinBase() const
492     {
493         return (vin.size() == 1 && vin[0].prevout.IsNull());
494     }
495
496     int GetSigOpCount() const
497     {
498         int n = 0;
499         BOOST_FOREACH(const CTxIn& txin, vin)
500             n += txin.scriptSig.GetSigOpCount();
501         BOOST_FOREACH(const CTxOut& txout, vout)
502             n += txout.scriptPubKey.GetSigOpCount();
503         return n;
504     }
505
506     bool IsStandard() const
507     {
508         BOOST_FOREACH(const CTxIn& txin, vin)
509             if (!txin.scriptSig.IsPushOnly())
510                 return error("nonstandard txin: %s", txin.scriptSig.ToString().c_str());
511         BOOST_FOREACH(const CTxOut& txout, vout)
512             if (!::IsStandard(txout.scriptPubKey))
513                 return error("nonstandard txout: %s", txout.scriptPubKey.ToString().c_str());
514         return true;
515     }
516
517     int64 GetValueOut() const
518     {
519         int64 nValueOut = 0;
520         BOOST_FOREACH(const CTxOut& txout, vout)
521         {
522             nValueOut += txout.nValue;
523             if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
524                 throw std::runtime_error("CTransaction::GetValueOut() : value out of range");
525         }
526         return nValueOut;
527     }
528
529     static bool AllowFree(double dPriority)
530     {
531         // Large (in bytes) low-priority (new, small-coin) transactions
532         // need a fee.
533         return dPriority > COIN * 144 / 250;
534     }
535
536     int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=true, bool fForRelay=false) const
537     {
538         // Base fee is either MIN_TX_FEE or MIN_RELAY_TX_FEE
539         int64 nBaseFee = fForRelay ? MIN_RELAY_TX_FEE : MIN_TX_FEE;
540
541         unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK);
542         unsigned int nNewBlockSize = nBlockSize + nBytes;
543         int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee;
544
545         if (fAllowFree)
546         {
547             if (nBlockSize == 1)
548             {
549                 // Transactions under 10K are free
550                 // (about 4500bc if made of 50bc inputs)
551                 if (nBytes < 10000)
552                     nMinFee = 0;
553             }
554             else
555             {
556                 // Free transaction area
557                 if (nNewBlockSize < 27000)
558                     nMinFee = 0;
559             }
560         }
561
562         // To limit dust spam, require MIN_TX_FEE/MIN_RELAY_TX_FEE if any output is less than 0.01
563         if (nMinFee < nBaseFee)
564             BOOST_FOREACH(const CTxOut& txout, vout)
565                 if (txout.nValue < CENT)
566                     nMinFee = nBaseFee;
567
568         // Raise the price as the block approaches full
569         if (nBlockSize != 1 && nNewBlockSize >= MAX_BLOCK_SIZE_GEN/2)
570         {
571             if (nNewBlockSize >= MAX_BLOCK_SIZE_GEN)
572                 return MAX_MONEY;
573             nMinFee *= MAX_BLOCK_SIZE_GEN / (MAX_BLOCK_SIZE_GEN - nNewBlockSize);
574         }
575
576         if (!MoneyRange(nMinFee))
577             nMinFee = MAX_MONEY;
578         return nMinFee;
579     }
580
581
582     bool ReadFromDisk(CDiskTxPos pos, FILE** pfileRet=NULL)
583     {
584         CAutoFile filein = OpenBlockFile(pos.nFile, 0, pfileRet ? "rb+" : "rb");
585         if (!filein)
586             return error("CTransaction::ReadFromDisk() : OpenBlockFile failed");
587
588         // Read transaction
589         if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)
590             return error("CTransaction::ReadFromDisk() : fseek failed");
591         filein >> *this;
592
593         // Return file pointer
594         if (pfileRet)
595         {
596             if (fseek(filein, pos.nTxPos, SEEK_SET) != 0)
597                 return error("CTransaction::ReadFromDisk() : second fseek failed");
598             *pfileRet = filein.release();
599         }
600         return true;
601     }
602
603     friend bool operator==(const CTransaction& a, const CTransaction& b)
604     {
605         return (a.nVersion  == b.nVersion &&
606                 a.vin       == b.vin &&
607                 a.vout      == b.vout &&
608                 a.nLockTime == b.nLockTime);
609     }
610
611     friend bool operator!=(const CTransaction& a, const CTransaction& b)
612     {
613         return !(a == b);
614     }
615
616
617     std::string ToString() const
618     {
619         std::string str;
620         str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%d, vout.size=%d, nLockTime=%d)\n",
621             GetHash().ToString().substr(0,10).c_str(),
622             nVersion,
623             vin.size(),
624             vout.size(),
625             nLockTime);
626         for (int i = 0; i < vin.size(); i++)
627             str += "    " + vin[i].ToString() + "\n";
628         for (int i = 0; i < vout.size(); i++)
629             str += "    " + vout[i].ToString() + "\n";
630         return str;
631     }
632
633     void print() const
634     {
635         printf("%s", ToString().c_str());
636     }
637
638
639     bool ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet);
640     bool ReadFromDisk(CTxDB& txdb, COutPoint prevout);
641     bool ReadFromDisk(COutPoint prevout);
642     bool DisconnectInputs(CTxDB& txdb);
643     bool ConnectInputs(CTxDB& txdb, std::map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
644                        CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee=0);
645     bool ClientConnectInputs();
646     bool CheckTransaction() const;
647     bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL);
648     bool AcceptToMemoryPool(bool fCheckInputs=true, bool* pfMissingInputs=NULL);
649 protected:
650     bool AddToMemoryPoolUnchecked();
651 public:
652     bool RemoveFromMemoryPool();
653 };
654
655
656
657
658
659 //
660 // A transaction with a merkle branch linking it to the block chain
661 //
662 class CMerkleTx : public CTransaction
663 {
664 public:
665     uint256 hashBlock;
666     std::vector<uint256> vMerkleBranch;
667     int nIndex;
668
669     // memory only
670     mutable char fMerkleVerified;
671
672
673     CMerkleTx()
674     {
675         Init();
676     }
677
678     CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)
679     {
680         Init();
681     }
682
683     void Init()
684     {
685         hashBlock = 0;
686         nIndex = -1;
687         fMerkleVerified = false;
688     }
689
690
691     IMPLEMENT_SERIALIZE
692     (
693         nSerSize += SerReadWrite(s, *(CTransaction*)this, nType, nVersion, ser_action);
694         nVersion = this->nVersion;
695         READWRITE(hashBlock);
696         READWRITE(vMerkleBranch);
697         READWRITE(nIndex);
698     )
699
700
701     int SetMerkleBranch(const CBlock* pblock=NULL);
702     int GetDepthInMainChain(CBlockIndex* &pindexRet) const;
703     int GetDepthInMainChain() const { CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
704     bool IsInMainChain() const { return GetDepthInMainChain() > 0; }
705     int GetBlocksToMaturity() const;
706     bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true);
707     bool AcceptToMemoryPool();
708 };
709
710
711
712
713 //
714 // A txdb record that contains the disk location of a transaction and the
715 // locations of transactions that spend its outputs.  vSpent is really only
716 // used as a flag, but having the location is very helpful for debugging.
717 //
718 class CTxIndex
719 {
720 public:
721     CDiskTxPos pos;
722     std::vector<CDiskTxPos> vSpent;
723
724     CTxIndex()
725     {
726         SetNull();
727     }
728
729     CTxIndex(const CDiskTxPos& posIn, unsigned int nOutputs)
730     {
731         pos = posIn;
732         vSpent.resize(nOutputs);
733     }
734
735     IMPLEMENT_SERIALIZE
736     (
737         if (!(nType & SER_GETHASH))
738             READWRITE(nVersion);
739         READWRITE(pos);
740         READWRITE(vSpent);
741     )
742
743     void SetNull()
744     {
745         pos.SetNull();
746         vSpent.clear();
747     }
748
749     bool IsNull()
750     {
751         return pos.IsNull();
752     }
753
754     friend bool operator==(const CTxIndex& a, const CTxIndex& b)
755     {
756         return (a.pos    == b.pos &&
757                 a.vSpent == b.vSpent);
758     }
759
760     friend bool operator!=(const CTxIndex& a, const CTxIndex& b)
761     {
762         return !(a == b);
763     }
764     int GetDepthInMainChain() const;
765  
766 };
767
768
769
770
771
772 //
773 // Nodes collect new transactions into a block, hash them into a hash tree,
774 // and scan through nonce values to make the block's hash satisfy proof-of-work
775 // requirements.  When they solve the proof-of-work, they broadcast the block
776 // to everyone and the block is added to the block chain.  The first transaction
777 // in the block is a special one that creates a new coin owned by the creator
778 // of the block.
779 //
780 // Blocks are appended to blk0001.dat files on disk.  Their location on disk
781 // is indexed by CBlockIndex objects in memory.
782 //
783 class CBlock
784 {
785 public:
786     // header
787     int nVersion;
788     uint256 hashPrevBlock;
789     uint256 hashMerkleRoot;
790     unsigned int nTime;
791     unsigned int nBits;
792     unsigned int nNonce;
793
794     // network and disk
795     std::vector<CTransaction> vtx;
796
797     // memory only
798     mutable std::vector<uint256> vMerkleTree;
799
800     // Denial-of-service detection:
801     mutable int nDoS;
802     bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; }
803
804     CBlock()
805     {
806         SetNull();
807     }
808
809     IMPLEMENT_SERIALIZE
810     (
811         READWRITE(this->nVersion);
812         nVersion = this->nVersion;
813         READWRITE(hashPrevBlock);
814         READWRITE(hashMerkleRoot);
815         READWRITE(nTime);
816         READWRITE(nBits);
817         READWRITE(nNonce);
818
819         // ConnectBlock depends on vtx being last so it can calculate offset
820         if (!(nType & (SER_GETHASH|SER_BLOCKHEADERONLY)))
821             READWRITE(vtx);
822         else if (fRead)
823             const_cast<CBlock*>(this)->vtx.clear();
824     )
825
826     void SetNull()
827     {
828         nVersion = 1;
829         hashPrevBlock = 0;
830         hashMerkleRoot = 0;
831         nTime = 0;
832         nBits = 0;
833         nNonce = 0;
834         vtx.clear();
835         vMerkleTree.clear();
836         nDoS = 0;
837     }
838
839     bool IsNull() const
840     {
841         return (nBits == 0);
842     }
843
844     uint256 GetHash() const
845     {
846         return Hash(BEGIN(nVersion), END(nNonce));
847     }
848
849     int64 GetBlockTime() const
850     {
851         return (int64)nTime;
852     }
853
854     int GetSigOpCount() const
855     {
856         int n = 0;
857         BOOST_FOREACH(const CTransaction& tx, vtx)
858             n += tx.GetSigOpCount();
859         return n;
860     }
861
862
863     uint256 BuildMerkleTree() const
864     {
865         vMerkleTree.clear();
866         BOOST_FOREACH(const CTransaction& tx, vtx)
867             vMerkleTree.push_back(tx.GetHash());
868         int j = 0;
869         for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
870         {
871             for (int i = 0; i < nSize; i += 2)
872             {
873                 int i2 = std::min(i+1, nSize-1);
874                 vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]),  END(vMerkleTree[j+i]),
875                                            BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2])));
876             }
877             j += nSize;
878         }
879         return (vMerkleTree.empty() ? 0 : vMerkleTree.back());
880     }
881
882     std::vector<uint256> GetMerkleBranch(int nIndex) const
883     {
884         if (vMerkleTree.empty())
885             BuildMerkleTree();
886         std::vector<uint256> vMerkleBranch;
887         int j = 0;
888         for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
889         {
890             int i = std::min(nIndex^1, nSize-1);
891             vMerkleBranch.push_back(vMerkleTree[j+i]);
892             nIndex >>= 1;
893             j += nSize;
894         }
895         return vMerkleBranch;
896     }
897
898     static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex)
899     {
900         if (nIndex == -1)
901             return 0;
902         BOOST_FOREACH(const uint256& otherside, vMerkleBranch)
903         {
904             if (nIndex & 1)
905                 hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash));
906             else
907                 hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside));
908             nIndex >>= 1;
909         }
910         return hash;
911     }
912
913
914     bool WriteToDisk(unsigned int& nFileRet, unsigned int& nBlockPosRet)
915     {
916         // Open history file to append
917         CAutoFile fileout = AppendBlockFile(nFileRet);
918         if (!fileout)
919             return error("CBlock::WriteToDisk() : AppendBlockFile failed");
920
921         // Write index header
922         unsigned int nSize = fileout.GetSerializeSize(*this);
923         fileout << FLATDATA(pchMessageStart) << nSize;
924
925         // Write block
926         nBlockPosRet = ftell(fileout);
927         if (nBlockPosRet == -1)
928             return error("CBlock::WriteToDisk() : ftell failed");
929         fileout << *this;
930
931         // Flush stdio buffers and commit to disk before returning
932         fflush(fileout);
933         if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0)
934         {
935 #ifdef WIN32
936             _commit(_fileno(fileout));
937 #else
938             fsync(fileno(fileout));
939 #endif
940         }
941
942         return true;
943     }
944
945     bool ReadFromDisk(unsigned int nFile, unsigned int nBlockPos, bool fReadTransactions=true)
946     {
947         SetNull();
948
949         // Open history file to read
950         CAutoFile filein = OpenBlockFile(nFile, nBlockPos, "rb");
951         if (!filein)
952             return error("CBlock::ReadFromDisk() : OpenBlockFile failed");
953         if (!fReadTransactions)
954             filein.nType |= SER_BLOCKHEADERONLY;
955
956         // Read block
957         filein >> *this;
958
959         // Check the header
960         if (!CheckProofOfWork(GetHash(), nBits))
961             return error("CBlock::ReadFromDisk() : errors in block header");
962
963         return true;
964     }
965
966
967
968     void print() const
969     {
970         printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%d)\n",
971             GetHash().ToString().substr(0,20).c_str(),
972             nVersion,
973             hashPrevBlock.ToString().substr(0,20).c_str(),
974             hashMerkleRoot.ToString().substr(0,10).c_str(),
975             nTime, nBits, nNonce,
976             vtx.size());
977         for (int i = 0; i < vtx.size(); i++)
978         {
979             printf("  ");
980             vtx[i].print();
981         }
982         printf("  vMerkleTree: ");
983         for (int i = 0; i < vMerkleTree.size(); i++)
984             printf("%s ", vMerkleTree[i].ToString().substr(0,10).c_str());
985         printf("\n");
986     }
987
988
989     bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex);
990     bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex);
991     bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true);
992     bool SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew);
993     bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos);
994     bool CheckBlock() const;
995     bool AcceptBlock();
996 };
997
998
999
1000
1001
1002
1003 //
1004 // The block chain is a tree shaped structure starting with the
1005 // genesis block at the root, with each block potentially having multiple
1006 // candidates to be the next block.  pprev and pnext link a path through the
1007 // main/longest chain.  A blockindex may have multiple pprev pointing back
1008 // to it, but pnext will only point forward to the longest branch, or will
1009 // be null if the block is not part of the longest chain.
1010 //
1011 class CBlockIndex
1012 {
1013 public:
1014     const uint256* phashBlock;
1015     CBlockIndex* pprev;
1016     CBlockIndex* pnext;
1017     unsigned int nFile;
1018     unsigned int nBlockPos;
1019     int nHeight;
1020     CBigNum bnChainWork;
1021
1022     // block header
1023     int nVersion;
1024     uint256 hashMerkleRoot;
1025     unsigned int nTime;
1026     unsigned int nBits;
1027     unsigned int nNonce;
1028
1029
1030     CBlockIndex()
1031     {
1032         phashBlock = NULL;
1033         pprev = NULL;
1034         pnext = NULL;
1035         nFile = 0;
1036         nBlockPos = 0;
1037         nHeight = 0;
1038         bnChainWork = 0;
1039
1040         nVersion       = 0;
1041         hashMerkleRoot = 0;
1042         nTime          = 0;
1043         nBits          = 0;
1044         nNonce         = 0;
1045     }
1046
1047     CBlockIndex(unsigned int nFileIn, unsigned int nBlockPosIn, CBlock& block)
1048     {
1049         phashBlock = NULL;
1050         pprev = NULL;
1051         pnext = NULL;
1052         nFile = nFileIn;
1053         nBlockPos = nBlockPosIn;
1054         nHeight = 0;
1055         bnChainWork = 0;
1056
1057         nVersion       = block.nVersion;
1058         hashMerkleRoot = block.hashMerkleRoot;
1059         nTime          = block.nTime;
1060         nBits          = block.nBits;
1061         nNonce         = block.nNonce;
1062     }
1063
1064     CBlock GetBlockHeader() const
1065     {
1066         CBlock block;
1067         block.nVersion       = nVersion;
1068         if (pprev)
1069             block.hashPrevBlock = pprev->GetBlockHash();
1070         block.hashMerkleRoot = hashMerkleRoot;
1071         block.nTime          = nTime;
1072         block.nBits          = nBits;
1073         block.nNonce         = nNonce;
1074         return block;
1075     }
1076
1077     uint256 GetBlockHash() const
1078     {
1079         return *phashBlock;
1080     }
1081
1082     int64 GetBlockTime() const
1083     {
1084         return (int64)nTime;
1085     }
1086
1087     CBigNum GetBlockWork() const
1088     {
1089         CBigNum bnTarget;
1090         bnTarget.SetCompact(nBits);
1091         if (bnTarget <= 0)
1092             return 0;
1093         return (CBigNum(1)<<256) / (bnTarget+1);
1094     }
1095
1096     bool IsInMainChain() const
1097     {
1098         return (pnext || this == pindexBest);
1099     }
1100
1101     bool CheckIndex() const
1102     {
1103         return CheckProofOfWork(GetBlockHash(), nBits);
1104     }
1105
1106     bool EraseBlockFromDisk()
1107     {
1108         // Open history file
1109         CAutoFile fileout = OpenBlockFile(nFile, nBlockPos, "rb+");
1110         if (!fileout)
1111             return false;
1112
1113         // Overwrite with empty null block
1114         CBlock block;
1115         block.SetNull();
1116         fileout << block;
1117
1118         return true;
1119     }
1120
1121     enum { nMedianTimeSpan=11 };
1122
1123     int64 GetMedianTimePast() const
1124     {
1125         int64 pmedian[nMedianTimeSpan];
1126         int64* pbegin = &pmedian[nMedianTimeSpan];
1127         int64* pend = &pmedian[nMedianTimeSpan];
1128
1129         const CBlockIndex* pindex = this;
1130         for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev)
1131             *(--pbegin) = pindex->GetBlockTime();
1132
1133         std::sort(pbegin, pend);
1134         return pbegin[(pend - pbegin)/2];
1135     }
1136
1137     int64 GetMedianTime() const
1138     {
1139         const CBlockIndex* pindex = this;
1140         for (int i = 0; i < nMedianTimeSpan/2; i++)
1141         {
1142             if (!pindex->pnext)
1143                 return GetBlockTime();
1144             pindex = pindex->pnext;
1145         }
1146         return pindex->GetMedianTimePast();
1147     }
1148
1149
1150
1151     std::string ToString() const
1152     {
1153         return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nHeight=%d, merkle=%s, hashBlock=%s)",
1154             pprev, pnext, nFile, nBlockPos, nHeight,
1155             hashMerkleRoot.ToString().substr(0,10).c_str(),
1156             GetBlockHash().ToString().substr(0,20).c_str());
1157     }
1158
1159     void print() const
1160     {
1161         printf("%s\n", ToString().c_str());
1162     }
1163 };
1164
1165
1166
1167 //
1168 // Used to marshal pointers into hashes for db storage.
1169 //
1170 class CDiskBlockIndex : public CBlockIndex
1171 {
1172 public:
1173     uint256 hashPrev;
1174     uint256 hashNext;
1175
1176     CDiskBlockIndex()
1177     {
1178         hashPrev = 0;
1179         hashNext = 0;
1180     }
1181
1182     explicit CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex)
1183     {
1184         hashPrev = (pprev ? pprev->GetBlockHash() : 0);
1185         hashNext = (pnext ? pnext->GetBlockHash() : 0);
1186     }
1187
1188     IMPLEMENT_SERIALIZE
1189     (
1190         if (!(nType & SER_GETHASH))
1191             READWRITE(nVersion);
1192
1193         READWRITE(hashNext);
1194         READWRITE(nFile);
1195         READWRITE(nBlockPos);
1196         READWRITE(nHeight);
1197
1198         // block header
1199         READWRITE(this->nVersion);
1200         READWRITE(hashPrev);
1201         READWRITE(hashMerkleRoot);
1202         READWRITE(nTime);
1203         READWRITE(nBits);
1204         READWRITE(nNonce);
1205     )
1206
1207     uint256 GetBlockHash() const
1208     {
1209         CBlock block;
1210         block.nVersion        = nVersion;
1211         block.hashPrevBlock   = hashPrev;
1212         block.hashMerkleRoot  = hashMerkleRoot;
1213         block.nTime           = nTime;
1214         block.nBits           = nBits;
1215         block.nNonce          = nNonce;
1216         return block.GetHash();
1217     }
1218
1219
1220     std::string ToString() const
1221     {
1222         std::string str = "CDiskBlockIndex(";
1223         str += CBlockIndex::ToString();
1224         str += strprintf("\n                hashBlock=%s, hashPrev=%s, hashNext=%s)",
1225             GetBlockHash().ToString().c_str(),
1226             hashPrev.ToString().substr(0,20).c_str(),
1227             hashNext.ToString().substr(0,20).c_str());
1228         return str;
1229     }
1230
1231     void print() const
1232     {
1233         printf("%s\n", ToString().c_str());
1234     }
1235 };
1236
1237
1238
1239
1240
1241
1242
1243
1244 //
1245 // Describes a place in the block chain to another node such that if the
1246 // other node doesn't have the same branch, it can find a recent common trunk.
1247 // The further back it is, the further before the fork it may be.
1248 //
1249 class CBlockLocator
1250 {
1251 protected:
1252     std::vector<uint256> vHave;
1253 public:
1254
1255     CBlockLocator()
1256     {
1257     }
1258
1259     explicit CBlockLocator(const CBlockIndex* pindex)
1260     {
1261         Set(pindex);
1262     }
1263
1264     explicit CBlockLocator(uint256 hashBlock)
1265     {
1266         std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
1267         if (mi != mapBlockIndex.end())
1268             Set((*mi).second);
1269     }
1270
1271     CBlockLocator(const std::vector<uint256>& vHaveIn)
1272     {
1273         vHave = vHaveIn;
1274     }
1275
1276     IMPLEMENT_SERIALIZE
1277     (
1278         if (!(nType & SER_GETHASH))
1279             READWRITE(nVersion);
1280         READWRITE(vHave);
1281     )
1282
1283     void SetNull()
1284     {
1285         vHave.clear();
1286     }
1287
1288     bool IsNull()
1289     {
1290         return vHave.empty();
1291     }
1292
1293     void Set(const CBlockIndex* pindex)
1294     {
1295         vHave.clear();
1296         int nStep = 1;
1297         while (pindex)
1298         {
1299             vHave.push_back(pindex->GetBlockHash());
1300
1301             // Exponentially larger steps back
1302             for (int i = 0; pindex && i < nStep; i++)
1303                 pindex = pindex->pprev;
1304             if (vHave.size() > 10)
1305                 nStep *= 2;
1306         }
1307         vHave.push_back(hashGenesisBlock);
1308     }
1309
1310     int GetDistanceBack()
1311     {
1312         // Retrace how far back it was in the sender's branch
1313         int nDistance = 0;
1314         int nStep = 1;
1315         BOOST_FOREACH(const uint256& hash, vHave)
1316         {
1317             std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
1318             if (mi != mapBlockIndex.end())
1319             {
1320                 CBlockIndex* pindex = (*mi).second;
1321                 if (pindex->IsInMainChain())
1322                     return nDistance;
1323             }
1324             nDistance += nStep;
1325             if (nDistance > 10)
1326                 nStep *= 2;
1327         }
1328         return nDistance;
1329     }
1330
1331     CBlockIndex* GetBlockIndex()
1332     {
1333         // Find the first block the caller has in the main chain
1334         BOOST_FOREACH(const uint256& hash, vHave)
1335         {
1336             std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
1337             if (mi != mapBlockIndex.end())
1338             {
1339                 CBlockIndex* pindex = (*mi).second;
1340                 if (pindex->IsInMainChain())
1341                     return pindex;
1342             }
1343         }
1344         return pindexGenesisBlock;
1345     }
1346
1347     uint256 GetBlockHash()
1348     {
1349         // Find the first block the caller has in the main chain
1350         BOOST_FOREACH(const uint256& hash, vHave)
1351         {
1352             std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
1353             if (mi != mapBlockIndex.end())
1354             {
1355                 CBlockIndex* pindex = (*mi).second;
1356                 if (pindex->IsInMainChain())
1357                     return hash;
1358             }
1359         }
1360         return hashGenesisBlock;
1361     }
1362
1363     int GetHeight()
1364     {
1365         CBlockIndex* pindex = GetBlockIndex();
1366         if (!pindex)
1367             return 0;
1368         return pindex->nHeight;
1369     }
1370 };
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380 //
1381 // Alerts are for notifying old versions if they become too obsolete and
1382 // need to upgrade.  The message is displayed in the status bar.
1383 // Alert messages are broadcast as a vector of signed data.  Unserializing may
1384 // not read the entire buffer if the alert is for a newer version, but older
1385 // versions can still relay the original data.
1386 //
1387 class CUnsignedAlert
1388 {
1389 public:
1390     int nVersion;
1391     int64 nRelayUntil;      // when newer nodes stop relaying to newer nodes
1392     int64 nExpiration;
1393     int nID;
1394     int nCancel;
1395     std::set<int> setCancel;
1396     int nMinVer;            // lowest version inclusive
1397     int nMaxVer;            // highest version inclusive
1398     std::set<std::string> setSubVer;  // empty matches all
1399     int nPriority;
1400
1401     // Actions
1402     std::string strComment;
1403     std::string strStatusBar;
1404     std::string strReserved;
1405
1406     IMPLEMENT_SERIALIZE
1407     (
1408         READWRITE(this->nVersion);
1409         nVersion = this->nVersion;
1410         READWRITE(nRelayUntil);
1411         READWRITE(nExpiration);
1412         READWRITE(nID);
1413         READWRITE(nCancel);
1414         READWRITE(setCancel);
1415         READWRITE(nMinVer);
1416         READWRITE(nMaxVer);
1417         READWRITE(setSubVer);
1418         READWRITE(nPriority);
1419
1420         READWRITE(strComment);
1421         READWRITE(strStatusBar);
1422         READWRITE(strReserved);
1423     )
1424
1425     void SetNull()
1426     {
1427         nVersion = 1;
1428         nRelayUntil = 0;
1429         nExpiration = 0;
1430         nID = 0;
1431         nCancel = 0;
1432         setCancel.clear();
1433         nMinVer = 0;
1434         nMaxVer = 0;
1435         setSubVer.clear();
1436         nPriority = 0;
1437
1438         strComment.clear();
1439         strStatusBar.clear();
1440         strReserved.clear();
1441     }
1442
1443     std::string ToString() const
1444     {
1445         std::string strSetCancel;
1446         BOOST_FOREACH(int n, setCancel)
1447             strSetCancel += strprintf("%d ", n);
1448         std::string strSetSubVer;
1449         BOOST_FOREACH(std::string str, setSubVer)
1450             strSetSubVer += "\"" + str + "\" ";
1451         return strprintf(
1452                 "CAlert(\n"
1453                 "    nVersion     = %d\n"
1454                 "    nRelayUntil  = %"PRI64d"\n"
1455                 "    nExpiration  = %"PRI64d"\n"
1456                 "    nID          = %d\n"
1457                 "    nCancel      = %d\n"
1458                 "    setCancel    = %s\n"
1459                 "    nMinVer      = %d\n"
1460                 "    nMaxVer      = %d\n"
1461                 "    setSubVer    = %s\n"
1462                 "    nPriority    = %d\n"
1463                 "    strComment   = \"%s\"\n"
1464                 "    strStatusBar = \"%s\"\n"
1465                 ")\n",
1466             nVersion,
1467             nRelayUntil,
1468             nExpiration,
1469             nID,
1470             nCancel,
1471             strSetCancel.c_str(),
1472             nMinVer,
1473             nMaxVer,
1474             strSetSubVer.c_str(),
1475             nPriority,
1476             strComment.c_str(),
1477             strStatusBar.c_str());
1478     }
1479
1480     void print() const
1481     {
1482         printf("%s", ToString().c_str());
1483     }
1484 };
1485
1486 class CAlert : public CUnsignedAlert
1487 {
1488 public:
1489     std::vector<unsigned char> vchMsg;
1490     std::vector<unsigned char> vchSig;
1491
1492     CAlert()
1493     {
1494         SetNull();
1495     }
1496
1497     IMPLEMENT_SERIALIZE
1498     (
1499         READWRITE(vchMsg);
1500         READWRITE(vchSig);
1501     )
1502
1503     void SetNull()
1504     {
1505         CUnsignedAlert::SetNull();
1506         vchMsg.clear();
1507         vchSig.clear();
1508     }
1509
1510     bool IsNull() const
1511     {
1512         return (nExpiration == 0);
1513     }
1514
1515     uint256 GetHash() const
1516     {
1517         return SerializeHash(*this);
1518     }
1519
1520     bool IsInEffect() const
1521     {
1522         return (GetAdjustedTime() < nExpiration);
1523     }
1524
1525     bool Cancels(const CAlert& alert) const
1526     {
1527         if (!IsInEffect())
1528             return false; // this was a no-op before 31403
1529         return (alert.nID <= nCancel || setCancel.count(alert.nID));
1530     }
1531
1532     bool AppliesTo(int nVersion, std::string strSubVerIn) const
1533     {
1534         // TODO: rework for client-version-embedded-in-strSubVer ?
1535         return (IsInEffect() &&
1536                 nMinVer <= nVersion && nVersion <= nMaxVer &&
1537                 (setSubVer.empty() || setSubVer.count(strSubVerIn)));
1538     }
1539
1540     bool AppliesToMe() const
1541     {
1542         return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<std::string>()));
1543     }
1544
1545     bool RelayTo(CNode* pnode) const
1546     {
1547         if (!IsInEffect())
1548             return false;
1549         // returns true if wasn't already contained in the set
1550         if (pnode->setKnown.insert(GetHash()).second)
1551         {
1552             if (AppliesTo(pnode->nVersion, pnode->strSubVer) ||
1553                 AppliesToMe() ||
1554                 GetAdjustedTime() < nRelayUntil)
1555             {
1556                 pnode->PushMessage("alert", *this);
1557                 return true;
1558             }
1559         }
1560         return false;
1561     }
1562
1563     bool CheckSignature()
1564     {
1565         CKey key;
1566         if (!key.SetPubKey(ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284")))
1567             return error("CAlert::CheckSignature() : SetPubKey failed");
1568         if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
1569             return error("CAlert::CheckSignature() : verify signature failed");
1570
1571         // Now unserialize the data
1572         CDataStream sMsg(vchMsg);
1573         sMsg >> *(CUnsignedAlert*)this;
1574         return true;
1575     }
1576
1577     bool ProcessAlert();
1578 };
1579
1580 #endif