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