a277508306e8656f01ae1980859bbc85be9a22a9
[novacoin.git] / src / db.cpp
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #include "db.h"
7 #include "net.h"
8 #include "checkpoints.h"
9 #include "util.h"
10 #include "main.h"
11 #include "kernel.h"
12 #include "ui_interface.h"
13 #include <boost/filesystem.hpp>
14 #include <boost/filesystem/fstream.hpp>
15
16 #ifndef WIN32
17 #include "sys/stat.h"
18 #endif
19
20 using namespace std;
21 using namespace boost;
22
23
24 unsigned int nWalletDBUpdated;
25
26
27
28 //
29 // CDB
30 //
31
32 CDBEnv bitdb;
33
34 void CDBEnv::EnvShutdown()
35 {
36     if (!fDbEnvInit)
37         return;
38
39     fDbEnvInit = false;
40     int ret = dbenv.close(0);
41     if (ret != 0)
42         printf("EnvShutdown exception: %s (%d)\n", DbEnv::strerror(ret), ret);
43     if (!fMockDb)
44         DbEnv(0).remove(strPath.c_str(), 0);
45 }
46
47 CDBEnv::CDBEnv() : dbenv(DB_CXX_NO_EXCEPTIONS)
48 {
49     fDbEnvInit = false;
50     fMockDb = false;
51 }
52
53 CDBEnv::~CDBEnv()
54 {
55     EnvShutdown();
56 }
57
58 void CDBEnv::Close()
59 {
60     EnvShutdown();
61 }
62
63 bool CDBEnv::Open(boost::filesystem::path pathEnv_)
64 {
65     if (fDbEnvInit)
66         return true;
67
68     if (fShutdown)
69         return false;
70
71     pathEnv = pathEnv_;
72     filesystem::path pathDataDir = pathEnv;
73     strPath = pathDataDir.string();
74     filesystem::path pathLogDir = pathDataDir / "database";
75     filesystem::create_directory(pathLogDir);
76     filesystem::path pathErrorFile = pathDataDir / "db.log";
77     printf("dbenv.open LogDir=%s ErrorFile=%s\n", pathLogDir.string().c_str(), pathErrorFile.string().c_str());
78
79     unsigned int nEnvFlags = 0;
80     if (GetBoolArg("-privdb", true))
81         nEnvFlags |= DB_PRIVATE;
82
83     int nDbCache = GetArg("-dbcache", 25);
84     dbenv.set_lg_dir(pathLogDir.string().c_str());
85     dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1);
86     dbenv.set_lg_bsize(1048576);
87     dbenv.set_lg_max(10485760);
88
89     // Bugfix: Bump lk_max_locks default to 537000, to safely handle reorgs with up to 5 blocks reversed
90     // dbenv.set_lk_max_locks(10000);
91     dbenv.set_lk_max_locks(537000);
92
93     dbenv.set_lk_max_objects(10000);
94     dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug
95     dbenv.set_flags(DB_AUTO_COMMIT, 1);
96     dbenv.set_flags(DB_TXN_WRITE_NOSYNC, 1);
97 #ifdef DB_LOG_AUTO_REMOVE
98     dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1);
99 #endif
100     int ret = dbenv.open(strPath.c_str(),
101                      DB_CREATE     |
102                      DB_INIT_LOCK  |
103                      DB_INIT_LOG   |
104                      DB_INIT_MPOOL |
105                      DB_INIT_TXN   |
106                      DB_THREAD     |
107                      DB_RECOVER    |
108                      nEnvFlags,
109                      S_IRUSR | S_IWUSR);
110     if (ret != 0)
111         return error("CDB() : error %s (%d) opening database environment", DbEnv::strerror(ret), ret);
112
113     fDbEnvInit = true;
114     fMockDb = false;
115
116     // Check that the number of locks is sufficient (to prevent chain fork possibility, read http://bitcoin.org/may15 for more info)
117     u_int32_t nMaxLocks;
118     if (!dbenv.get_lk_max_locks(&nMaxLocks))
119     {
120         int nBlocks, nDeepReorg;
121         std::string strMessage;
122
123         nBlocks = nMaxLocks / 48768;
124         nDeepReorg = (nBlocks - 1) / 2;
125
126         printf("Final lk_max_locks is %lu, sufficient for (worst case) %d block%s in a single transaction (up to a %d-deep reorganization)\n", (unsigned long)nMaxLocks, nBlocks, (nBlocks == 1) ? "" : "s", nDeepReorg);
127         if (nDeepReorg < 3)
128         {
129             if (nBlocks < 1)
130                 strMessage = strprintf(_("Warning: DB_CONFIG has set_lk_max_locks %lu, which may be too low for a single block. If this limit is reached, NovaCoin may stop working."), (unsigned long)nMaxLocks);
131             else
132                 strMessage = strprintf(_("Warning: DB_CONFIG has set_lk_max_locks %lu, which may be too low for a common blockchain reorganization. If this limit is reached, NovaCoin may stop working."), (unsigned long)nMaxLocks);
133
134             strMiscWarning = strMessage;
135             printf("*** %s\n", strMessage.c_str());
136         }
137     }
138
139     return true;
140 }
141
142 void CDBEnv::MakeMock()
143 {
144     if (fDbEnvInit)
145         throw runtime_error("CDBEnv::MakeMock(): already initialized");
146
147     if (fShutdown)
148         throw runtime_error("CDBEnv::MakeMock(): during shutdown");
149
150     printf("CDBEnv::MakeMock()\n");
151
152     dbenv.set_cachesize(1, 0, 1);
153     dbenv.set_lg_bsize(10485760*4);
154     dbenv.set_lg_max(10485760);
155     dbenv.set_lk_max_locks(10000);
156     dbenv.set_lk_max_objects(10000);
157     dbenv.set_flags(DB_AUTO_COMMIT, 1);
158 #ifdef DB_LOG_IN_MEMORY
159     dbenv.log_set_config(DB_LOG_IN_MEMORY, 1);
160 #endif
161     int ret = dbenv.open(NULL,
162                      DB_CREATE     |
163                      DB_INIT_LOCK  |
164                      DB_INIT_LOG   |
165                      DB_INIT_MPOOL |
166                      DB_INIT_TXN   |
167                      DB_THREAD     |
168                      DB_PRIVATE,
169                      S_IRUSR | S_IWUSR);
170     if (ret > 0)
171         throw runtime_error(strprintf("CDBEnv::MakeMock(): error %d opening database environment", ret));
172
173     fDbEnvInit = true;
174     fMockDb = true;
175 }
176
177 CDBEnv::VerifyResult CDBEnv::Verify(std::string strFile, bool (*recoverFunc)(CDBEnv& dbenv, std::string strFile))
178 {
179     LOCK(cs_db);
180     assert(mapFileUseCount.count(strFile) == 0);
181
182     Db db(&dbenv, 0);
183     int result = db.verify(strFile.c_str(), NULL, NULL, 0);
184     if (result == 0)
185         return VERIFY_OK;
186     else if (recoverFunc == NULL)
187         return RECOVER_FAIL;
188
189     // Try to recover:
190     bool fRecovered = (*recoverFunc)(*this, strFile);
191     return (fRecovered ? RECOVER_OK : RECOVER_FAIL);
192 }
193
194 bool CDBEnv::Salvage(std::string strFile, bool fAggressive,
195                      std::vector<CDBEnv::KeyValPair >& vResult)
196 {
197     LOCK(cs_db);
198     assert(mapFileUseCount.count(strFile) == 0);
199
200     u_int32_t flags = DB_SALVAGE;
201     if (fAggressive) flags |= DB_AGGRESSIVE;
202
203     stringstream strDump;
204
205     Db db(&dbenv, 0);
206     int result = db.verify(strFile.c_str(), NULL, &strDump, flags);
207     if (result != 0)
208     {
209         printf("ERROR: db salvage failed\n");
210         return false;
211     }
212
213     // Format of bdb dump is ascii lines:
214     // header lines...
215     // HEADER=END
216     // hexadecimal key
217     // hexadecimal value
218     // ... repeated
219     // DATA=END
220
221     string strLine;
222     while (!strDump.eof() && strLine != "HEADER=END")
223         getline(strDump, strLine); // Skip past header
224
225     std::string keyHex, valueHex;
226     while (!strDump.eof() && keyHex != "DATA=END")
227     {
228         getline(strDump, keyHex);
229         if (keyHex != "DATA_END")
230         {
231             getline(strDump, valueHex);
232             vResult.push_back(make_pair(ParseHex(keyHex),ParseHex(valueHex)));
233         }
234     }
235
236     return (result == 0);
237 }
238
239
240 void CDBEnv::CheckpointLSN(std::string strFile)
241 {
242     dbenv.txn_checkpoint(0, 0, 0);
243     if (fMockDb)
244         return;
245     dbenv.lsn_reset(strFile.c_str(), 0);
246 }
247
248
249 CDB::CDB(const char *pszFile, const char* pszMode) :
250     pdb(NULL), activeTxn(NULL)
251 {
252     int ret;
253     if (pszFile == NULL)
254         return;
255
256     fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
257     bool fCreate = strchr(pszMode, 'c');
258     unsigned int nFlags = DB_THREAD;
259     if (fCreate)
260         nFlags |= DB_CREATE;
261
262     {
263         LOCK(bitdb.cs_db);
264         if (!bitdb.Open(GetDataDir()))
265             throw runtime_error("env open failed");
266
267         strFile = pszFile;
268         ++bitdb.mapFileUseCount[strFile];
269         pdb = bitdb.mapDb[strFile];
270         if (pdb == NULL)
271         {
272             pdb = new Db(&bitdb.dbenv, 0);
273
274             bool fMockDb = bitdb.IsMock();
275             if (fMockDb)
276             {
277                 DbMpoolFile*mpf = pdb->get_mpf();
278                 ret = mpf->set_flags(DB_MPOOL_NOFILE, 1);
279                 if (ret != 0)
280                     throw runtime_error(strprintf("CDB() : failed to configure for no temp file backing for database %s", pszFile));
281             }
282
283             ret = pdb->open(NULL,      // Txn pointer
284                             fMockDb ? NULL : pszFile,   // Filename
285                             "main",    // Logical db name
286                             DB_BTREE,  // Database type
287                             nFlags,    // Flags
288                             0);
289
290             if (ret != 0)
291             {
292                 delete pdb;
293                 pdb = NULL;
294                 --bitdb.mapFileUseCount[strFile];
295                 strFile = "";
296                 throw runtime_error(strprintf("CDB() : can't open database file %s, error %d", pszFile, ret));
297             }
298
299             if (fCreate && !Exists(string("version")))
300             {
301                 bool fTmp = fReadOnly;
302                 fReadOnly = false;
303                 WriteVersion(CLIENT_VERSION);
304                 fReadOnly = fTmp;
305             }
306
307             bitdb.mapDb[strFile] = pdb;
308         }
309     }
310 }
311
312 static bool IsChainFile(std::string strFile)
313 {
314     if (strFile == "blkindex.dat")
315         return true;
316
317     return false;
318 }
319
320 void CDB::Close()
321 {
322     if (!pdb)
323         return;
324     if (activeTxn)
325         activeTxn->abort();
326     activeTxn = NULL;
327     pdb = NULL;
328
329     // Flush database activity from memory pool to disk log
330     unsigned int nMinutes = 0;
331     if (fReadOnly)
332         nMinutes = 1;
333     if (IsChainFile(strFile))
334         nMinutes = 2;
335     if (IsChainFile(strFile) && IsInitialBlockDownload())
336         nMinutes = 5;
337
338     bitdb.dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0);
339
340     {
341         LOCK(bitdb.cs_db);
342         --bitdb.mapFileUseCount[strFile];
343     }
344 }
345
346 void CDBEnv::CloseDb(const string& strFile)
347 {
348     {
349         LOCK(cs_db);
350         if (mapDb[strFile] != NULL)
351         {
352             // Close the database handle
353             Db* pdb = mapDb[strFile];
354             pdb->close(0);
355             delete pdb;
356             mapDb[strFile] = NULL;
357         }
358     }
359 }
360
361 bool CDBEnv::RemoveDb(const string& strFile)
362 {
363     this->CloseDb(strFile);
364
365     LOCK(cs_db);
366     int rc = dbenv.dbremove(NULL, strFile.c_str(), NULL, DB_AUTO_COMMIT);
367     return (rc == 0);
368 }
369
370 bool CDB::Rewrite(const string& strFile, const char* pszSkip)
371 {
372     while (!fShutdown)
373     {
374         {
375             LOCK(bitdb.cs_db);
376             if (!bitdb.mapFileUseCount.count(strFile) || bitdb.mapFileUseCount[strFile] == 0)
377             {
378                 // Flush log data to the dat file
379                 bitdb.CloseDb(strFile);
380                 bitdb.CheckpointLSN(strFile);
381                 bitdb.mapFileUseCount.erase(strFile);
382
383                 bool fSuccess = true;
384                 printf("Rewriting %s...\n", strFile.c_str());
385                 string strFileRes = strFile + ".rewrite";
386                 { // surround usage of db with extra {}
387                     CDB db(strFile.c_str(), "r");
388                     Db* pdbCopy = new Db(&bitdb.dbenv, 0);
389
390                     int ret = pdbCopy->open(NULL,                 // Txn pointer
391                                             strFileRes.c_str(),   // Filename
392                                             "main",    // Logical db name
393                                             DB_BTREE,  // Database type
394                                             DB_CREATE,    // Flags
395                                             0);
396                     if (ret > 0)
397                     {
398                         printf("Cannot create database file %s\n", strFileRes.c_str());
399                         fSuccess = false;
400                     }
401
402                     Dbc* pcursor = db.GetCursor();
403                     if (pcursor)
404                         while (fSuccess)
405                         {
406                             CDataStream ssKey(SER_DISK, CLIENT_VERSION);
407                             CDataStream ssValue(SER_DISK, CLIENT_VERSION);
408                             int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
409                             if (ret == DB_NOTFOUND)
410                             {
411                                 pcursor->close();
412                                 break;
413                             }
414                             else if (ret != 0)
415                             {
416                                 pcursor->close();
417                                 fSuccess = false;
418                                 break;
419                             }
420                             if (pszSkip &&
421                                 strncmp(&ssKey[0], pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0)
422                                 continue;
423                             if (strncmp(&ssKey[0], "\x07version", 8) == 0)
424                             {
425                                 // Update version:
426                                 ssValue.clear();
427                                 ssValue << CLIENT_VERSION;
428                             }
429                             Dbt datKey(&ssKey[0], ssKey.size());
430                             Dbt datValue(&ssValue[0], ssValue.size());
431                             int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE);
432                             if (ret2 > 0)
433                                 fSuccess = false;
434                         }
435                     if (fSuccess)
436                     {
437                         db.Close();
438                         bitdb.CloseDb(strFile);
439                         if (pdbCopy->close(0))
440                             fSuccess = false;
441                         delete pdbCopy;
442                     }
443                 }
444                 if (fSuccess)
445                 {
446                     Db dbA(&bitdb.dbenv, 0);
447                     if (dbA.remove(strFile.c_str(), NULL, 0))
448                         fSuccess = false;
449                     Db dbB(&bitdb.dbenv, 0);
450                     if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0))
451                         fSuccess = false;
452                 }
453                 if (!fSuccess)
454                     printf("Rewriting of %s FAILED!\n", strFileRes.c_str());
455                 return fSuccess;
456             }
457         }
458         Sleep(100);
459     }
460     return false;
461 }
462
463
464 void CDBEnv::Flush(bool fShutdown)
465 {
466     int64 nStart = GetTimeMillis();
467     // Flush log data to the actual data file
468     //  on all files that are not in use
469     printf("Flush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started");
470     if (!fDbEnvInit)
471         return;
472     {
473         LOCK(cs_db);
474         map<string, int>::iterator mi = mapFileUseCount.begin();
475         while (mi != mapFileUseCount.end())
476         {
477             string strFile = (*mi).first;
478             int nRefCount = (*mi).second;
479             printf("%s refcount=%d\n", strFile.c_str(), nRefCount);
480             if (nRefCount == 0)
481             {
482                 // Move log data to the dat file
483                 CloseDb(strFile);
484                 printf("%s checkpoint\n", strFile.c_str());
485                 dbenv.txn_checkpoint(0, 0, 0);
486                 if (!IsChainFile(strFile) || fDetachDB) {
487                     printf("%s detach\n", strFile.c_str());
488                     if (!fMockDb)
489                         dbenv.lsn_reset(strFile.c_str(), 0);
490                 }
491                 printf("%s closed\n", strFile.c_str());
492                 mapFileUseCount.erase(mi++);
493             }
494             else
495                 mi++;
496         }
497         printf("DBFlush(%s)%s ended %15"PRI64d"ms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started", GetTimeMillis() - nStart);
498         if (fShutdown)
499         {
500             char** listp;
501             if (mapFileUseCount.empty())
502             {
503                 dbenv.log_archive(&listp, DB_ARCH_REMOVE);
504                 Close();
505             }
506         }
507     }
508 }
509
510
511
512
513
514
515 //
516 // CTxDB
517 //
518
519 bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex)
520 {
521     assert(!fClient);
522     txindex.SetNull();
523     return Read(make_pair(string("tx"), hash), txindex);
524 }
525
526 bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex)
527 {
528     assert(!fClient);
529     return Write(make_pair(string("tx"), hash), txindex);
530 }
531
532 bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight)
533 {
534     assert(!fClient);
535
536     // Add to tx index
537     uint256 hash = tx.GetHash();
538     CTxIndex txindex(pos, tx.vout.size());
539     return Write(make_pair(string("tx"), hash), txindex);
540 }
541
542 bool CTxDB::EraseTxIndex(const CTransaction& tx)
543 {
544     assert(!fClient);
545     uint256 hash = tx.GetHash();
546
547     return Erase(make_pair(string("tx"), hash));
548 }
549
550 bool CTxDB::ContainsTx(uint256 hash)
551 {
552     assert(!fClient);
553     return Exists(make_pair(string("tx"), hash));
554 }
555
556 bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex)
557 {
558     assert(!fClient);
559     tx.SetNull();
560     if (!ReadTxIndex(hash, txindex))
561         return false;
562     return (tx.ReadFromDisk(txindex.pos));
563 }
564
565 bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx)
566 {
567     CTxIndex txindex;
568     return ReadDiskTx(hash, tx, txindex);
569 }
570
571 bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex)
572 {
573     return ReadDiskTx(outpoint.hash, tx, txindex);
574 }
575
576 bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx)
577 {
578     CTxIndex txindex;
579     return ReadDiskTx(outpoint.hash, tx, txindex);
580 }
581
582 bool CTxDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
583 {
584     return Write(make_pair(string("blockindex"), blockindex.GetBlockHash()), blockindex);
585 }
586
587 bool CTxDB::ReadHashBestChain(uint256& hashBestChain)
588 {
589     return Read(string("hashBestChain"), hashBestChain);
590 }
591
592 bool CTxDB::WriteHashBestChain(uint256 hashBestChain)
593 {
594     return Write(string("hashBestChain"), hashBestChain);
595 }
596
597 bool CTxDB::ReadBestInvalidTrust(CBigNum& bnBestInvalidTrust)
598 {
599     return Read(string("bnBestInvalidTrust"), bnBestInvalidTrust);
600 }
601
602 bool CTxDB::WriteBestInvalidTrust(CBigNum bnBestInvalidTrust)
603 {
604     return Write(string("bnBestInvalidTrust"), bnBestInvalidTrust);
605 }
606
607 bool CTxDB::ReadSyncCheckpoint(uint256& hashCheckpoint)
608 {
609     return Read(string("hashSyncCheckpoint"), hashCheckpoint);
610 }
611
612 bool CTxDB::WriteSyncCheckpoint(uint256 hashCheckpoint)
613 {
614     return Write(string("hashSyncCheckpoint"), hashCheckpoint);
615 }
616
617 bool CTxDB::ReadCheckpointPubKey(string& strPubKey)
618 {
619     return Read(string("strCheckpointPubKey"), strPubKey);
620 }
621
622 bool CTxDB::WriteCheckpointPubKey(const string& strPubKey)
623 {
624     return Write(string("strCheckpointPubKey"), strPubKey);
625 }
626
627 CBlockIndex static * InsertBlockIndex(uint256 hash)
628 {
629     if (hash == 0)
630         return NULL;
631
632     // Return existing
633     map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
634     if (mi != mapBlockIndex.end())
635         return (*mi).second;
636
637     // Create new
638     CBlockIndex* pindexNew = new CBlockIndex();
639     if (!pindexNew)
640         throw runtime_error("LoadBlockIndex() : new CBlockIndex failed");
641     mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
642     pindexNew->phashBlock = &((*mi).first);
643
644     return pindexNew;
645 }
646
647 bool CTxDB::LoadBlockIndex()
648 {
649     if (!LoadBlockIndexGuts())
650         return false;
651
652     if (fRequestShutdown)
653         return true;
654
655     // Calculate nChainTrust
656     vector<pair<int, CBlockIndex*> > vSortedByHeight;
657     vSortedByHeight.reserve(mapBlockIndex.size());
658     BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
659     {
660         CBlockIndex* pindex = item.second;
661         vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));
662     }
663     sort(vSortedByHeight.begin(), vSortedByHeight.end());
664     BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)
665     {
666         CBlockIndex* pindex = item.second;
667         pindex->nChainTrust = (pindex->pprev ? pindex->pprev->nChainTrust : 0) + pindex->GetBlockTrust();
668         // ppcoin: calculate stake modifier checksum
669         pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex);
670         if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum))
671             return error("CTxDB::LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016"PRI64x, pindex->nHeight, pindex->nStakeModifier);
672     }
673
674     // Load hashBestChain pointer to end of best chain
675     if (!ReadHashBestChain(hashBestChain))
676     {
677         if (pindexGenesisBlock == NULL)
678             return true;
679         return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
680     }
681     if (!mapBlockIndex.count(hashBestChain))
682         return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index");
683     pindexBest = mapBlockIndex[hashBestChain];
684     nBestHeight = pindexBest->nHeight;
685     nBestChainTrust = pindexBest->nChainTrust;
686     printf("LoadBlockIndex(): hashBestChain=%s  height=%d  trust=%s  date=%s\n",
687       hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, CBigNum(nBestChainTrust).ToString().c_str(),
688       DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
689
690     // ppcoin: load hashSyncCheckpoint
691     if (!ReadSyncCheckpoint(Checkpoints::hashSyncCheckpoint))
692         return error("CTxDB::LoadBlockIndex() : hashSyncCheckpoint not loaded");
693     printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str());
694
695     // Load bnBestInvalidTrust, OK if it doesn't exist
696     CBigNum bnBestInvalidTrust;
697     ReadBestInvalidTrust(bnBestInvalidTrust);
698     nBestInvalidTrust = bnBestInvalidTrust.getuint256();
699
700     // Verify blocks in the best chain
701     int nCheckLevel = GetArg("-checklevel", 1);
702     int nCheckDepth = GetArg( "-checkblocks", 2500);
703     if (nCheckDepth == 0)
704         nCheckDepth = 1000000000; // suffices until the year 19000
705     if (nCheckDepth > nBestHeight)
706         nCheckDepth = nBestHeight;
707     printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
708     CBlockIndex* pindexFork = NULL;
709     map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos;
710     for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
711     {
712         if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth)
713             break;
714         CBlock block;
715         if (!block.ReadFromDisk(pindex))
716             return error("LoadBlockIndex() : block.ReadFromDisk failed");
717         // check level 1: verify block validity
718         // check level 7: verify block signature too
719         if (nCheckLevel>0 && !block.CheckBlock(true, true, (nCheckLevel>6)))
720         {
721             printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
722             pindexFork = pindex->pprev;
723         }
724         // check level 2: verify transaction index validity
725         if (nCheckLevel>1)
726         {
727             pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos);
728             mapBlockPos[pos] = pindex;
729             BOOST_FOREACH(const CTransaction &tx, block.vtx)
730             {
731                 uint256 hashTx = tx.GetHash();
732                 CTxIndex txindex;
733                 if (ReadTxIndex(hashTx, txindex))
734                 {
735                     // check level 3: checker transaction hashes
736                     if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos)
737                     {
738                         // either an error or a duplicate transaction
739                         CTransaction txFound;
740                         if (!txFound.ReadFromDisk(txindex.pos))
741                         {
742                             printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str());
743                             pindexFork = pindex->pprev;
744                         }
745                         else
746                             if (txFound.GetHash() != hashTx) // not a duplicate tx
747                             {
748                                 printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str());
749                                 pindexFork = pindex->pprev;
750                             }
751                     }
752                     // check level 4: check whether spent txouts were spent within the main chain
753                     unsigned int nOutput = 0;
754                     if (nCheckLevel>3)
755                     {
756                         BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent)
757                         {
758                             if (!txpos.IsNull())
759                             {
760                                 pair<unsigned int, unsigned int> posFind = make_pair(txpos.nFile, txpos.nBlockPos);
761                                 if (!mapBlockPos.count(posFind))
762                                 {
763                                     printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str());
764                                     pindexFork = pindex->pprev;
765                                 }
766                                 // check level 6: check whether spent txouts were spent by a valid transaction that consume them
767                                 if (nCheckLevel>5)
768                                 {
769                                     CTransaction txSpend;
770                                     if (!txSpend.ReadFromDisk(txpos))
771                                     {
772                                         printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput);
773                                         pindexFork = pindex->pprev;
774                                     }
775                                     else if (!txSpend.CheckTransaction())
776                                     {
777                                         printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput);
778                                         pindexFork = pindex->pprev;
779                                     }
780                                     else
781                                     {
782                                         bool fFound = false;
783                                         BOOST_FOREACH(const CTxIn &txin, txSpend.vin)
784                                             if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput)
785                                                 fFound = true;
786                                         if (!fFound)
787                                         {
788                                             printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput);
789                                             pindexFork = pindex->pprev;
790                                         }
791                                     }
792                                 }
793                             }
794                             nOutput++;
795                         }
796                     }
797                 }
798                 // check level 5: check whether all prevouts are marked spent
799                 if (nCheckLevel>4)
800                 {
801                      BOOST_FOREACH(const CTxIn &txin, tx.vin)
802                      {
803                           CTxIndex txindex;
804                           if (ReadTxIndex(txin.prevout.hash, txindex))
805                               if (txindex.vSpent.size()-1 < txin.prevout.n || txindex.vSpent[txin.prevout.n].IsNull())
806                               {
807                                   printf("LoadBlockIndex(): *** found unspent prevout %s:%i in %s\n", txin.prevout.hash.ToString().c_str(), txin.prevout.n, hashTx.ToString().c_str());
808                                   pindexFork = pindex->pprev;
809                               }
810                      }
811                 }
812             }
813         }
814     }
815     if (pindexFork && !fRequestShutdown)
816     {
817         // Reorg back to the fork
818         printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight);
819         CBlock block;
820         if (!block.ReadFromDisk(pindexFork))
821             return error("LoadBlockIndex() : block.ReadFromDisk failed");
822         CTxDB txdb;
823         block.SetBestChain(txdb, pindexFork);
824     }
825
826     return true;
827 }
828
829
830
831 bool CTxDB::LoadBlockIndexGuts()
832 {
833     // Get database cursor
834     Dbc* pcursor = GetCursor();
835     if (!pcursor)
836         return false;
837
838     // Load mapBlockIndex
839     unsigned int fFlags = DB_SET_RANGE;
840     loop
841     {
842         // Read next record
843         CDataStream ssKey(SER_DISK, CLIENT_VERSION);
844         if (fFlags == DB_SET_RANGE)
845             ssKey << make_pair(string("blockindex"), uint256(0));
846         CDataStream ssValue(SER_DISK, CLIENT_VERSION);
847         int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
848         fFlags = DB_NEXT;
849         if (ret == DB_NOTFOUND)
850             break;
851         else if (ret != 0)
852             return false;
853
854         // Unserialize
855
856         try {
857         string strType;
858         ssKey >> strType;
859         if (strType == "blockindex" && !fRequestShutdown)
860         {
861             CDiskBlockIndex diskindex;
862             ssValue >> diskindex;
863
864             // Construct block index object
865             CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
866             pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
867             pindexNew->pnext          = InsertBlockIndex(diskindex.hashNext);
868             pindexNew->nFile          = diskindex.nFile;
869             pindexNew->nBlockPos      = diskindex.nBlockPos;
870             pindexNew->nHeight        = diskindex.nHeight;
871             pindexNew->nMint          = diskindex.nMint;
872             pindexNew->nMoneySupply   = diskindex.nMoneySupply;
873             pindexNew->nFlags         = diskindex.nFlags;
874             pindexNew->nStakeModifier = diskindex.nStakeModifier;
875             pindexNew->prevoutStake   = diskindex.prevoutStake;
876             pindexNew->nStakeTime     = diskindex.nStakeTime;
877             pindexNew->hashProofOfStake = diskindex.hashProofOfStake;
878             pindexNew->nVersion       = diskindex.nVersion;
879             pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
880             pindexNew->nTime          = diskindex.nTime;
881             pindexNew->nBits          = diskindex.nBits;
882             pindexNew->nNonce         = diskindex.nNonce;
883
884             // Watch for genesis block
885             if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
886                 pindexGenesisBlock = pindexNew;
887
888             if (!pindexNew->CheckIndex())
889                 return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
890
891             // ppcoin: build setStakeSeen
892             if (pindexNew->IsProofOfStake())
893                 setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime));
894         }
895         else
896         {
897             break; // if shutdown requested or finished loading block index
898         }
899         }    // try
900         catch (std::exception &e) {
901             return error("%s() : deserialize error", __PRETTY_FUNCTION__);
902         }
903     }
904     pcursor->close();
905
906     return true;
907 }
908
909
910
911
912
913 //
914 // CAddrDB
915 //
916
917
918 CAddrDB::CAddrDB()
919 {
920     pathAddr = GetDataDir() / "peers.dat";
921 }
922
923 bool CAddrDB::Write(const CAddrMan& addr)
924 {
925     // Generate random temporary filename
926     unsigned short randv = 0;
927     RAND_bytes((unsigned char *)&randv, sizeof(randv));
928     std::string tmpfn = strprintf("peers.dat.%04x", randv);
929
930     // serialize addresses, checksum data up to that point, then append csum
931     CDataStream ssPeers(SER_DISK, CLIENT_VERSION);
932     ssPeers << FLATDATA(pchMessageStart);
933     ssPeers << addr;
934     uint256 hash = Hash(ssPeers.begin(), ssPeers.end());
935     ssPeers << hash;
936
937     // open temp output file, and associate with CAutoFile
938     boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
939     FILE *file = fopen(pathTmp.string().c_str(), "wb");
940     CAutoFile fileout = CAutoFile(file, SER_DISK, CLIENT_VERSION);
941     if (!fileout)
942         return error("CAddrman::Write() : open failed");
943
944     // Write and commit header, data
945     try {
946         fileout << ssPeers;
947     }
948     catch (std::exception &e) {
949         return error("CAddrman::Write() : I/O error");
950     }
951     FileCommit(fileout);
952     fileout.fclose();
953
954     // replace existing peers.dat, if any, with new peers.dat.XXXX
955     if (!RenameOver(pathTmp, pathAddr))
956         return error("CAddrman::Write() : Rename-into-place failed");
957
958     return true;
959 }
960
961 bool CAddrDB::Read(CAddrMan& addr)
962 {
963     // open input file, and associate with CAutoFile
964     FILE *file = fopen(pathAddr.string().c_str(), "rb");
965     CAutoFile filein = CAutoFile(file, SER_DISK, CLIENT_VERSION);
966     if (!filein)
967         return error("CAddrman::Read() : open failed");
968
969     // use file size to size memory buffer
970     int fileSize = GetFilesize(filein);
971     int dataSize = fileSize - sizeof(uint256);
972     //Don't try to resize to a negative number if file is small
973     if ( dataSize < 0 ) dataSize = 0;
974     vector<unsigned char> vchData;
975     vchData.resize(dataSize);
976     uint256 hashIn;
977
978     // read data and checksum from file
979     try {
980         filein.read((char *)&vchData[0], dataSize);
981         filein >> hashIn;
982     }
983     catch (std::exception &e) {
984         return error("CAddrman::Read() 2 : I/O error or stream data corrupted");
985     }
986     filein.fclose();
987
988     CDataStream ssPeers(vchData, SER_DISK, CLIENT_VERSION);
989
990     // verify stored checksum matches input data
991     uint256 hashTmp = Hash(ssPeers.begin(), ssPeers.end());
992     if (hashIn != hashTmp)
993         return error("CAddrman::Read() : checksum mismatch; data corrupted");
994
995     unsigned char pchMsgTmp[4];
996     try {
997         // de-serialize file header (pchMessageStart magic number) and
998         ssPeers >> FLATDATA(pchMsgTmp);
999
1000         // verify the network matches ours
1001         if (memcmp(pchMsgTmp, pchMessageStart, sizeof(pchMsgTmp)))
1002             return error("CAddrman::Read() : invalid network magic number");
1003
1004         // de-serialize address data into one CAddrMan object
1005         ssPeers >> addr;
1006     }
1007     catch (std::exception &e) {
1008         return error("CAddrman::Read() : I/O error or stream data corrupted");
1009     }
1010
1011     return true;
1012 }
1013