Remove unused includes.
[novacoin.git] / src / checkpoints.cpp
1 // Copyright (c) 2009-2012 The Bitcoin developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include <boost/assign/list_of.hpp> // for 'map_list_of()'
6 #include <boost/foreach.hpp>
7 #include <algorithm>
8
9 #include "checkpoints.h"
10
11 #include "txdb.h"
12 #include "main.h"
13 #include "uint256.h"
14
15 namespace Checkpoints
16 {
17     typedef std::map<int, std::pair<uint256, unsigned int> > MapCheckpoints;
18     typedef std::list<uint256> ListBannedBlocks;
19
20     //
21     // What makes a good checkpoint block?
22     // + Is surrounded by blocks with reasonable timestamps
23     //   (no blocks before with a timestamp after, none after with
24     //    timestamp before)
25     // + Contains no strange transactions
26     //
27     static MapCheckpoints mapCheckpoints =
28         boost::assign::map_list_of
29         ( 0,     std::make_pair(hashGenesisBlock, 1360105017) )
30         ( 13560, std::make_pair(uint256("0xa1591a0fcbf11f282d671581edb9f0aadcd06fee69761081e0a3245914c13729"), 1364674052) )
31         ( 143990, std::make_pair(uint256("0x00000000001ff5c3940a9f73ad4a990f64955179bde0f743c76dbf0031429efc"), 1418953493) )
32         ( 149000, std::make_pair(uint256("0x7a24acfcadcf43054e7f7d9f273522c0dfc5791ba4006e0273e7521a8d36c525"), 1420872125) )
33         ( 160000, std::make_pair(uint256("0x000000000001cb1133043d38d077c0e93f66c8b2566779f10f182137d1e34a68"), 1425150237) )
34         ( 200000, std::make_pair(uint256("0x0000000000029f8bbf66e6ea6f3e5db55009404aae0fe395a53dd33142b2bff2"), 1441127233) )
35         ( 221047, std::make_pair(uint256("0xa28aef712e7aa0c285bfe29351ca21ed416689139e3063ef770fc826a8b9e9da"), 1449431646) )
36     ;
37     
38     static ListBannedBlocks listBanned =
39         boost::assign::list_of
40         // Invalid block #221047 with future timestamp of 2016/02/23 09:24:17 UTC
41         ( uint256("0x46223e5432ceffe650d5729b4bb8479dcdf0ca1e534fa8e69382dc87b42ea94b") )
42     ;
43
44     // TestNet has no checkpoints
45     static MapCheckpoints mapCheckpointsTestnet =
46         boost::assign::map_list_of
47         ( 0, std::make_pair(hashGenesisBlockTestNet, 1360105017) )
48         ;
49
50     bool CheckHardened(int nHeight, const uint256& hash)
51     {
52         MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
53
54         MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
55         if (i == checkpoints.end()) return true;
56         return hash == i->second.first;
57     }
58
59     bool CheckBanned(const uint256 &nHash)
60     {
61         if (fTestNet) // Testnet has no banned blocks
62             return true;
63         ListBannedBlocks::const_iterator it = std::find(listBanned.begin(), listBanned.end(), nHash);
64         return it == listBanned.end();
65     }
66
67     int GetTotalBlocksEstimate()
68     {
69         MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
70
71         return checkpoints.rbegin()->first;
72     }
73
74     unsigned int GetLastCheckpointTime()
75     {
76         MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
77
78         return checkpoints.rbegin()->second.second;
79     }
80
81     CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
82     {
83         MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
84
85         BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
86         {
87             const uint256& hash = i.second.first;
88             std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
89             if (t != mapBlockIndex.end())
90                 return t->second;
91         }
92         return NULL;
93     }
94
95     // ppcoin: synchronized checkpoint (centrally broadcasted)
96     uint256 hashSyncCheckpoint = 0;
97     uint256 hashPendingCheckpoint = 0;
98     CSyncCheckpoint checkpointMessage;
99     CSyncCheckpoint checkpointMessagePending;
100     uint256 hashInvalidCheckpoint = 0;
101     CCriticalSection cs_hashSyncCheckpoint;
102
103     // ppcoin: get last synchronized checkpoint
104     CBlockIndex* GetLastSyncCheckpoint()
105     {
106         LOCK(cs_hashSyncCheckpoint);
107         if (!mapBlockIndex.count(hashSyncCheckpoint))
108             error("GetSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str());
109         else
110             return mapBlockIndex[hashSyncCheckpoint];
111         return NULL;
112     }
113
114     // ppcoin: only descendant of current sync-checkpoint is allowed
115     bool ValidateSyncCheckpoint(uint256 hashCheckpoint)
116     {
117         if (!mapBlockIndex.count(hashSyncCheckpoint))
118             return error("ValidateSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str());
119         if (!mapBlockIndex.count(hashCheckpoint))
120             return error("ValidateSyncCheckpoint: block index missing for received sync-checkpoint %s", hashCheckpoint.ToString().c_str());
121
122         CBlockIndex* pindexSyncCheckpoint = mapBlockIndex[hashSyncCheckpoint];
123         CBlockIndex* pindexCheckpointRecv = mapBlockIndex[hashCheckpoint];
124
125         if (pindexCheckpointRecv->nHeight <= pindexSyncCheckpoint->nHeight)
126         {
127             // Received an older checkpoint, trace back from current checkpoint
128             // to the same height of the received checkpoint to verify
129             // that current checkpoint should be a descendant block
130             CBlockIndex* pindex = pindexSyncCheckpoint;
131             while (pindex->nHeight > pindexCheckpointRecv->nHeight)
132                 if (!(pindex = pindex->pprev))
133                     return error("ValidateSyncCheckpoint: pprev null - block index structure failure");
134             if (pindex->GetBlockHash() != hashCheckpoint)
135             {
136                 hashInvalidCheckpoint = hashCheckpoint;
137                 return error("ValidateSyncCheckpoint: new sync-checkpoint %s is conflicting with current sync-checkpoint %s", hashCheckpoint.ToString().c_str(), hashSyncCheckpoint.ToString().c_str());
138             }
139             return false; // ignore older checkpoint
140         }
141
142         // Received checkpoint should be a descendant block of the current
143         // checkpoint. Trace back to the same height of current checkpoint
144         // to verify.
145         CBlockIndex* pindex = pindexCheckpointRecv;
146         while (pindex->nHeight > pindexSyncCheckpoint->nHeight)
147             if (!(pindex = pindex->pprev))
148                 return error("ValidateSyncCheckpoint: pprev2 null - block index structure failure");
149         if (pindex->GetBlockHash() != hashSyncCheckpoint)
150         {
151             hashInvalidCheckpoint = hashCheckpoint;
152             return error("ValidateSyncCheckpoint: new sync-checkpoint %s is not a descendant of current sync-checkpoint %s", hashCheckpoint.ToString().c_str(), hashSyncCheckpoint.ToString().c_str());
153         }
154         return true;
155     }
156
157     bool WriteSyncCheckpoint(const uint256& hashCheckpoint)
158     {
159         CTxDB txdb;
160         txdb.TxnBegin();
161         if (!txdb.WriteSyncCheckpoint(hashCheckpoint))
162         {
163             txdb.TxnAbort();
164             return error("WriteSyncCheckpoint(): failed to write to db sync checkpoint %s", hashCheckpoint.ToString().c_str());
165         }
166         if (!txdb.TxnCommit())
167             return error("WriteSyncCheckpoint(): failed to commit to db sync checkpoint %s", hashCheckpoint.ToString().c_str());
168
169 #ifndef USE_LEVELDB
170         txdb.Close();
171 #endif
172
173         Checkpoints::hashSyncCheckpoint = hashCheckpoint;
174         return true;
175     }
176
177     bool AcceptPendingSyncCheckpoint()
178     {
179         LOCK(cs_hashSyncCheckpoint);
180         if (hashPendingCheckpoint != 0 && mapBlockIndex.count(hashPendingCheckpoint))
181         {
182             if (!ValidateSyncCheckpoint(hashPendingCheckpoint))
183             {
184                 hashPendingCheckpoint = 0;
185                 checkpointMessagePending.SetNull();
186                 return false;
187             }
188
189             CTxDB txdb;
190             CBlockIndex* pindexCheckpoint = mapBlockIndex[hashPendingCheckpoint];
191             if (!pindexCheckpoint->IsInMainChain())
192             {
193                 CBlock block;
194                 if (!block.ReadFromDisk(pindexCheckpoint))
195                     return error("AcceptPendingSyncCheckpoint: ReadFromDisk failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
196                 if (!block.SetBestChain(txdb, pindexCheckpoint))
197                 {
198                     hashInvalidCheckpoint = hashPendingCheckpoint;
199                     return error("AcceptPendingSyncCheckpoint: SetBestChain failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
200                 }
201             }
202
203 #ifndef USE_LEVELDB
204             txdb.Close();
205 #endif
206             if (!WriteSyncCheckpoint(hashPendingCheckpoint))
207                 return error("AcceptPendingSyncCheckpoint(): failed to write sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
208             hashPendingCheckpoint = 0;
209             checkpointMessage = checkpointMessagePending;
210             checkpointMessagePending.SetNull();
211             printf("AcceptPendingSyncCheckpoint : sync-checkpoint at %s\n", hashSyncCheckpoint.ToString().c_str());
212             // relay the checkpoint
213             if (!checkpointMessage.IsNull())
214             {
215                 BOOST_FOREACH(CNode* pnode, vNodes)
216                     checkpointMessage.RelayTo(pnode);
217             }
218             return true;
219         }
220         return false;
221     }
222
223     // Automatically select a suitable sync-checkpoint 
224     uint256 AutoSelectSyncCheckpoint()
225     {
226         const CBlockIndex *pindex = pindexBest;
227         // Search backward for a block within max span and maturity window
228         while (pindex->pprev && (pindex->GetBlockTime() + CHECKPOINT_MAX_SPAN > pindexBest->GetBlockTime() || pindex->nHeight + 8 > pindexBest->nHeight))
229             pindex = pindex->pprev;
230         return pindex->GetBlockHash();
231     }
232
233     // Check against synchronized checkpoint
234     bool CheckSync(const uint256& hashBlock, const CBlockIndex* pindexPrev)
235     {
236         if (fTestNet) return true; // Testnet has no checkpoints
237         int nHeight = pindexPrev->nHeight + 1;
238
239         LOCK(cs_hashSyncCheckpoint);
240         // sync-checkpoint should always be accepted block
241         assert(mapBlockIndex.count(hashSyncCheckpoint));
242         const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint];
243
244         if (nHeight > pindexSync->nHeight)
245         {
246             // trace back to same height as sync-checkpoint
247             const CBlockIndex* pindex = pindexPrev;
248             while (pindex->nHeight > pindexSync->nHeight)
249                 if (!(pindex = pindex->pprev))
250                     return error("CheckSync: pprev null - block index structure failure");
251             if (pindex->nHeight < pindexSync->nHeight || pindex->GetBlockHash() != hashSyncCheckpoint)
252                 return false; // only descendant of sync-checkpoint can pass check
253         }
254         if (nHeight == pindexSync->nHeight && hashBlock != hashSyncCheckpoint)
255             return false; // same height with sync-checkpoint
256         if (nHeight < pindexSync->nHeight && !mapBlockIndex.count(hashBlock))
257             return false; // lower height than sync-checkpoint
258         return true;
259     }
260
261     bool WantedByPendingSyncCheckpoint(uint256 hashBlock)
262     {
263         LOCK(cs_hashSyncCheckpoint);
264         if (hashPendingCheckpoint == 0)
265             return false;
266         if (hashBlock == hashPendingCheckpoint)
267             return true;
268         if (mapOrphanBlocks.count(hashPendingCheckpoint) 
269             && hashBlock == WantedByOrphan(mapOrphanBlocks[hashPendingCheckpoint]))
270             return true;
271         return false;
272     }
273
274     // ppcoin: reset synchronized checkpoint to last hardened checkpoint
275     bool ResetSyncCheckpoint()
276     {
277         LOCK(cs_hashSyncCheckpoint);
278         const uint256& hash = mapCheckpoints.rbegin()->second.first;
279         if (mapBlockIndex.count(hash) && !mapBlockIndex[hash]->IsInMainChain())
280         {
281             // checkpoint block accepted but not yet in main chain
282             printf("ResetSyncCheckpoint: SetBestChain to hardened checkpoint %s\n", hash.ToString().c_str());
283             CTxDB txdb;
284             CBlock block;
285             if (!block.ReadFromDisk(mapBlockIndex[hash]))
286                 return error("ResetSyncCheckpoint: ReadFromDisk failed for hardened checkpoint %s", hash.ToString().c_str());
287             if (!block.SetBestChain(txdb, mapBlockIndex[hash]))
288             {
289                 return error("ResetSyncCheckpoint: SetBestChain failed for hardened checkpoint %s", hash.ToString().c_str());
290             }
291
292 #ifndef USE_LEVELDB
293             txdb.Close();
294 #endif
295
296         }
297         else if(!mapBlockIndex.count(hash))
298         {
299             // checkpoint block not yet accepted
300             hashPendingCheckpoint = hash;
301             checkpointMessagePending.SetNull();
302             printf("ResetSyncCheckpoint: pending for sync-checkpoint %s\n", hashPendingCheckpoint.ToString().c_str());
303         }
304
305         BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints)
306         {
307             const uint256& hash = i.second.first;
308             if (mapBlockIndex.count(hash) && mapBlockIndex[hash]->IsInMainChain())
309             {
310                 if (!WriteSyncCheckpoint(hash))
311                     return error("ResetSyncCheckpoint: failed to write sync checkpoint %s", hash.ToString().c_str());
312                 printf("ResetSyncCheckpoint: sync-checkpoint reset to %s\n", hashSyncCheckpoint.ToString().c_str());
313                 return true;
314             }
315         }
316
317         return false;
318     }
319
320     void AskForPendingSyncCheckpoint(CNode* pfrom)
321     {
322         LOCK(cs_hashSyncCheckpoint);
323         if (pfrom && hashPendingCheckpoint != 0 && (!mapBlockIndex.count(hashPendingCheckpoint)) && (!mapOrphanBlocks.count(hashPendingCheckpoint)))
324             pfrom->AskFor(CInv(MSG_BLOCK, hashPendingCheckpoint));
325     }
326
327     bool SetCheckpointPrivKey(std::string strPrivKey)
328     {
329         // Test signing a sync-checkpoint with genesis block
330         CSyncCheckpoint checkpoint;
331         checkpoint.hashCheckpoint = !fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet;
332         CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
333         sMsg << (CUnsignedSyncCheckpoint)checkpoint;
334         checkpoint.vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end());
335
336         std::vector<unsigned char> vchPrivKey = ParseHex(strPrivKey);
337         CKey key;
338         key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
339         if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig))
340             return false;
341
342         // Test signing successful, proceed
343         CSyncCheckpoint::strMasterPrivKey = strPrivKey;
344         return true;
345     }
346
347     bool SendSyncCheckpoint(uint256 hashCheckpoint)
348     {
349         CSyncCheckpoint checkpoint;
350         checkpoint.hashCheckpoint = hashCheckpoint;
351         CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
352         sMsg << (CUnsignedSyncCheckpoint)checkpoint;
353         checkpoint.vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end());
354
355         if (CSyncCheckpoint::strMasterPrivKey.empty())
356             return error("SendSyncCheckpoint: Checkpoint master key unavailable.");
357         std::vector<unsigned char> vchPrivKey = ParseHex(CSyncCheckpoint::strMasterPrivKey);
358         CKey key;
359         key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
360         if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig))
361             return error("SendSyncCheckpoint: Unable to sign checkpoint, check private key?");
362
363         if(!checkpoint.ProcessSyncCheckpoint(NULL))
364         {
365             printf("WARNING: SendSyncCheckpoint: Failed to process checkpoint.\n");
366             return false;
367         }
368
369         // Relay checkpoint
370         {
371             LOCK(cs_vNodes);
372             BOOST_FOREACH(CNode* pnode, vNodes)
373                 checkpoint.RelayTo(pnode);
374         }
375         return true;
376     }
377
378     // Is the sync-checkpoint outside maturity window?
379     bool IsMatureSyncCheckpoint()
380     {
381         LOCK(cs_hashSyncCheckpoint);
382         // sync-checkpoint should always be accepted block
383         assert(mapBlockIndex.count(hashSyncCheckpoint));
384         const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint];
385         return (nBestHeight >= pindexSync->nHeight + nCoinbaseMaturity ||
386                 pindexSync->GetBlockTime() + nStakeMinAge < GetAdjustedTime());
387     }
388 }
389
390 // ppcoin: sync-checkpoint master key
391 const std::string CSyncCheckpoint::strMasterPubKey = "04a51b735f816de4ec3f891d5b38bbc91e1f7245c7c08d17990760b86b4d8fc3910a850ffecf73bfa8886f01739a0c4c4322201282d07b6e48ce931cc92af94850";
392
393 std::string CSyncCheckpoint::strMasterPrivKey = "";
394
395 // ppcoin: verify signature of sync-checkpoint message
396 bool CSyncCheckpoint::CheckSignature()
397 {
398     CKey key;
399     if (!key.SetPubKey(ParseHex(CSyncCheckpoint::strMasterPubKey)))
400         return error("CSyncCheckpoint::CheckSignature() : SetPubKey failed");
401     if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig))
402         return error("CSyncCheckpoint::CheckSignature() : verify signature failed");
403
404     // Now unserialize the data
405     CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
406     sMsg >> *(CUnsignedSyncCheckpoint*)this;
407     return true;
408 }
409
410 // process synchronized checkpoint
411 bool CSyncCheckpoint::ProcessSyncCheckpoint(CNode* pfrom)
412 {
413     if (!CheckSignature())
414         return false;
415
416     LOCK(Checkpoints::cs_hashSyncCheckpoint);
417     if (!mapBlockIndex.count(hashCheckpoint))
418     {
419         // We haven't received the checkpoint chain, keep the checkpoint as pending
420         Checkpoints::hashPendingCheckpoint = hashCheckpoint;
421         Checkpoints::checkpointMessagePending = *this;
422         printf("ProcessSyncCheckpoint: pending for sync-checkpoint %s\n", hashCheckpoint.ToString().c_str());
423         // Ask this guy to fill in what we're missing
424         if (pfrom)
425         {
426             pfrom->PushGetBlocks(pindexBest, hashCheckpoint);
427             // ask directly as well in case rejected earlier by duplicate
428             // proof-of-stake because getblocks may not get it this time
429             pfrom->AskFor(CInv(MSG_BLOCK, mapOrphanBlocks.count(hashCheckpoint)? WantedByOrphan(mapOrphanBlocks[hashCheckpoint]) : hashCheckpoint));
430         }
431         return false;
432     }
433
434     if (!Checkpoints::ValidateSyncCheckpoint(hashCheckpoint))
435         return false;
436
437     CTxDB txdb;
438     CBlockIndex* pindexCheckpoint = mapBlockIndex[hashCheckpoint];
439     if (!pindexCheckpoint->IsInMainChain())
440     {
441         // checkpoint chain received but not yet main chain
442         CBlock block;
443         if (!block.ReadFromDisk(pindexCheckpoint))
444             return error("ProcessSyncCheckpoint: ReadFromDisk failed for sync checkpoint %s", hashCheckpoint.ToString().c_str());
445         if (!block.SetBestChain(txdb, pindexCheckpoint))
446         {
447             Checkpoints::hashInvalidCheckpoint = hashCheckpoint;
448             return error("ProcessSyncCheckpoint: SetBestChain failed for sync checkpoint %s", hashCheckpoint.ToString().c_str());
449         }
450     }
451
452 #ifndef USE_LEVELDB
453     txdb.Close();
454 #endif
455
456     if (!Checkpoints::WriteSyncCheckpoint(hashCheckpoint))
457         return error("ProcessSyncCheckpoint(): failed to write sync checkpoint %s", hashCheckpoint.ToString().c_str());
458     Checkpoints::checkpointMessage = *this;
459     Checkpoints::hashPendingCheckpoint = 0;
460     Checkpoints::checkpointMessagePending.SetNull();
461     printf("ProcessSyncCheckpoint: sync-checkpoint at %s\n", hashCheckpoint.ToString().c_str());
462     return true;
463 }