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