updated db.cpp to use make_preferred()
[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 license.txt or http://www.opensource.org/licenses/mit-license.php.
5
6 #include "headers.h"
7 #include "db.h"
8 #include "net.h"
9 #include <boost/version.hpp>
10 #include <boost/filesystem.hpp>
11 #include <boost/filesystem/fstream.hpp>
12
13 using namespace std;
14 using namespace boost;
15
16
17 unsigned int nWalletDBUpdated;
18 uint64 nAccountingEntryNumber = 0;
19
20
21
22 //
23 // CDB
24 //
25
26 static CCriticalSection cs_db;
27 static bool fDbEnvInit = false;
28 DbEnv dbenv(0);
29 static map<string, int> mapFileUseCount;
30 static map<string, Db*> mapDb;
31
32 static void EnvShutdown()
33 {
34     if (!fDbEnvInit)
35         return;
36
37     fDbEnvInit = false;
38     try
39     {
40         dbenv.close(0);
41     }
42     catch (const DbException& e)
43     {
44         printf("EnvShutdown exception: %s (%d)\n", e.what(), e.get_errno());
45     }
46     DbEnv(0).remove(GetDataDir().c_str(), 0);
47 }
48
49 class CDBInit
50 {
51 public:
52     CDBInit()
53     {
54     }
55     ~CDBInit()
56     {
57         EnvShutdown();
58     }
59 }
60 instance_of_cdbinit;
61
62
63 CDB::CDB(const char* pszFile, const char* pszMode) : pdb(NULL)
64 {
65     int ret;
66     if (pszFile == NULL)
67         return;
68
69     fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
70     bool fCreate = strchr(pszMode, 'c');
71     unsigned int nFlags = DB_THREAD;
72     if (fCreate)
73         nFlags |= DB_CREATE;
74
75     CRITICAL_BLOCK(cs_db)
76     {
77         if (!fDbEnvInit)
78         {
79             if (fShutdown)
80                 return;
81             string strDataDir = GetDataDir();
82             filesystem::path pathLogDir(strDataDir + "/database");
83             pathLogDir.make_preferred();
84             filesystem::create_directory(pathLogDir);
85             filesystem::path pathErrorFile(strDataDir + "/db.log");
86             pathErrorFile.make_preferred();
87             printf("dbenv.open LogDir=%s ErrorFile=%s\n", pathLogDir.string().c_str(), pathErrorFile.string().c_str());
88
89             int nDbCache = GetArg("-dbcache", 25);
90             dbenv.set_lg_dir(pathLogDir.string().c_str());
91             dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1);
92             dbenv.set_lg_bsize(1048576);
93             dbenv.set_lg_max(10485760);
94             dbenv.set_lk_max_locks(10000);
95             dbenv.set_lk_max_objects(10000);
96             dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug
97             dbenv.set_flags(DB_AUTO_COMMIT, 1);
98             dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1);
99             ret = dbenv.open(strDataDir.c_str(),
100                              DB_CREATE     |
101                              DB_INIT_LOCK  |
102                              DB_INIT_LOG   |
103                              DB_INIT_MPOOL |
104                              DB_INIT_TXN   |
105                              DB_THREAD     |
106                              DB_RECOVER,
107                              S_IRUSR | S_IWUSR);
108             if (ret > 0)
109                 throw runtime_error(strprintf("CDB() : error %d opening database environment", ret));
110             fDbEnvInit = true;
111         }
112
113         strFile = pszFile;
114         ++mapFileUseCount[strFile];
115         pdb = mapDb[strFile];
116         if (pdb == NULL)
117         {
118             pdb = new Db(&dbenv, 0);
119
120             ret = pdb->open(NULL,      // Txn pointer
121                             pszFile,   // Filename
122                             "main",    // Logical db name
123                             DB_BTREE,  // Database type
124                             nFlags,    // Flags
125                             0);
126
127             if (ret > 0)
128             {
129                 delete pdb;
130                 pdb = NULL;
131                 CRITICAL_BLOCK(cs_db)
132                     --mapFileUseCount[strFile];
133                 strFile = "";
134                 throw runtime_error(strprintf("CDB() : can't open database file %s, error %d", pszFile, ret));
135             }
136
137             if (fCreate && !Exists(string("version")))
138             {
139                 bool fTmp = fReadOnly;
140                 fReadOnly = false;
141                 WriteVersion(CLIENT_VERSION);
142                 fReadOnly = fTmp;
143             }
144
145             mapDb[strFile] = pdb;
146         }
147     }
148 }
149
150 void CDB::Close()
151 {
152     if (!pdb)
153         return;
154     if (!vTxn.empty())
155         vTxn.front()->abort();
156     vTxn.clear();
157     pdb = NULL;
158
159     // Flush database activity from memory pool to disk log
160     unsigned int nMinutes = 0;
161     if (fReadOnly)
162         nMinutes = 1;
163     if (strFile == "addr.dat")
164         nMinutes = 2;
165     if (strFile == "blkindex.dat" && IsInitialBlockDownload())
166         nMinutes = 5;
167
168     dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0);
169
170     CRITICAL_BLOCK(cs_db)
171         --mapFileUseCount[strFile];
172 }
173
174 void static CloseDb(const string& strFile)
175 {
176     CRITICAL_BLOCK(cs_db)
177     {
178         if (mapDb[strFile] != NULL)
179         {
180             // Close the database handle
181             Db* pdb = mapDb[strFile];
182             pdb->close(0);
183             delete pdb;
184             mapDb[strFile] = NULL;
185         }
186     }
187 }
188
189 bool CDB::Rewrite(const string& strFile, const char* pszSkip)
190 {
191     while (!fShutdown)
192     {
193         CRITICAL_BLOCK(cs_db)
194         {
195             if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0)
196             {
197                 // Flush log data to the dat file
198                 CloseDb(strFile);
199                 dbenv.txn_checkpoint(0, 0, 0);
200                 dbenv.lsn_reset(strFile.c_str(), 0);
201                 mapFileUseCount.erase(strFile);
202
203                 bool fSuccess = true;
204                 printf("Rewriting %s...\n", strFile.c_str());
205                 string strFileRes = strFile + ".rewrite";
206                 { // surround usage of db with extra {}
207                     CDB db(strFile.c_str(), "r");
208                     Db* pdbCopy = new Db(&dbenv, 0);
209     
210                     int ret = pdbCopy->open(NULL,                 // Txn pointer
211                                             strFileRes.c_str(),   // Filename
212                                             "main",    // Logical db name
213                                             DB_BTREE,  // Database type
214                                             DB_CREATE,    // Flags
215                                             0);
216                     if (ret > 0)
217                     {
218                         printf("Cannot create database file %s\n", strFileRes.c_str());
219                         fSuccess = false;
220                     }
221     
222                     Dbc* pcursor = db.GetCursor();
223                     if (pcursor)
224                         while (fSuccess)
225                         {
226                             CDataStream ssKey;
227                             CDataStream ssValue;
228                             int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
229                             if (ret == DB_NOTFOUND)
230                             {
231                                 pcursor->close();
232                                 break;
233                             }
234                             else if (ret != 0)
235                             {
236                                 pcursor->close();
237                                 fSuccess = false;
238                                 break;
239                             }
240                             if (pszSkip &&
241                                 strncmp(&ssKey[0], pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0)
242                                 continue;
243                             if (strncmp(&ssKey[0], "\x07version", 8) == 0)
244                             {
245                                 // Update version:
246                                 ssValue.clear();
247                                 ssValue << CLIENT_VERSION;
248                             }
249                             Dbt datKey(&ssKey[0], ssKey.size());
250                             Dbt datValue(&ssValue[0], ssValue.size());
251                             int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE);
252                             if (ret2 > 0)
253                                 fSuccess = false;
254                         }
255                     if (fSuccess)
256                     {
257                         db.Close();
258                         CloseDb(strFile);
259                         if (pdbCopy->close(0))
260                             fSuccess = false;
261                         delete pdbCopy;
262                     }
263                 }
264                 if (fSuccess)
265                 {
266                     Db dbA(&dbenv, 0);
267                     if (dbA.remove(strFile.c_str(), NULL, 0))
268                         fSuccess = false;
269                     Db dbB(&dbenv, 0);
270                     if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0))
271                         fSuccess = false;
272                 }
273                 if (!fSuccess)
274                     printf("Rewriting of %s FAILED!\n", strFileRes.c_str());
275                 return fSuccess;
276             }
277         }
278         Sleep(100);
279     }
280     return false;
281 }
282
283
284 void DBFlush(bool fShutdown)
285 {
286     // Flush log data to the actual data file
287     //  on all files that are not in use
288     printf("DBFlush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started");
289     if (!fDbEnvInit)
290         return;
291     CRITICAL_BLOCK(cs_db)
292     {
293         map<string, int>::iterator mi = mapFileUseCount.begin();
294         while (mi != mapFileUseCount.end())
295         {
296             string strFile = (*mi).first;
297             int nRefCount = (*mi).second;
298             printf("%s refcount=%d\n", strFile.c_str(), nRefCount);
299             if (nRefCount == 0)
300             {
301                 // Move log data to the dat file
302                 CloseDb(strFile);
303                 dbenv.txn_checkpoint(0, 0, 0);
304                 printf("%s flush\n", strFile.c_str());
305                 dbenv.lsn_reset(strFile.c_str(), 0);
306                 mapFileUseCount.erase(mi++);
307             }
308             else
309                 mi++;
310         }
311         if (fShutdown)
312         {
313             char** listp;
314             if (mapFileUseCount.empty())
315             {
316                 dbenv.log_archive(&listp, DB_ARCH_REMOVE);
317                 EnvShutdown();
318             }
319         }
320     }
321 }
322
323
324
325
326
327
328 //
329 // CTxDB
330 //
331
332 bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex)
333 {
334     assert(!fClient);
335     txindex.SetNull();
336     return Read(make_pair(string("tx"), hash), txindex);
337 }
338
339 bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex)
340 {
341     assert(!fClient);
342     return Write(make_pair(string("tx"), hash), txindex);
343 }
344
345 bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight)
346 {
347     assert(!fClient);
348
349     // Add to tx index
350     uint256 hash = tx.GetHash();
351     CTxIndex txindex(pos, tx.vout.size());
352     return Write(make_pair(string("tx"), hash), txindex);
353 }
354
355 bool CTxDB::EraseTxIndex(const CTransaction& tx)
356 {
357     assert(!fClient);
358     uint256 hash = tx.GetHash();
359
360     return Erase(make_pair(string("tx"), hash));
361 }
362
363 bool CTxDB::ContainsTx(uint256 hash)
364 {
365     assert(!fClient);
366     return Exists(make_pair(string("tx"), hash));
367 }
368
369 bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector<CTransaction>& vtx)
370 {
371     assert(!fClient);
372     vtx.clear();
373
374     // Get cursor
375     Dbc* pcursor = GetCursor();
376     if (!pcursor)
377         return false;
378
379     unsigned int fFlags = DB_SET_RANGE;
380     loop
381     {
382         // Read next record
383         CDataStream ssKey;
384         if (fFlags == DB_SET_RANGE)
385             ssKey << string("owner") << hash160 << CDiskTxPos(0, 0, 0);
386         CDataStream ssValue;
387         int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
388         fFlags = DB_NEXT;
389         if (ret == DB_NOTFOUND)
390             break;
391         else if (ret != 0)
392         {
393             pcursor->close();
394             return false;
395         }
396
397         // Unserialize
398         string strType;
399         uint160 hashItem;
400         CDiskTxPos pos;
401         ssKey >> strType >> hashItem >> pos;
402         int nItemHeight;
403         ssValue >> nItemHeight;
404
405         // Read transaction
406         if (strType != "owner" || hashItem != hash160)
407             break;
408         if (nItemHeight >= nMinHeight)
409         {
410             vtx.resize(vtx.size()+1);
411             if (!vtx.back().ReadFromDisk(pos))
412             {
413                 pcursor->close();
414                 return false;
415             }
416         }
417     }
418
419     pcursor->close();
420     return true;
421 }
422
423 bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex)
424 {
425     assert(!fClient);
426     tx.SetNull();
427     if (!ReadTxIndex(hash, txindex))
428         return false;
429     return (tx.ReadFromDisk(txindex.pos));
430 }
431
432 bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx)
433 {
434     CTxIndex txindex;
435     return ReadDiskTx(hash, tx, txindex);
436 }
437
438 bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex)
439 {
440     return ReadDiskTx(outpoint.hash, tx, txindex);
441 }
442
443 bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx)
444 {
445     CTxIndex txindex;
446     return ReadDiskTx(outpoint.hash, tx, txindex);
447 }
448
449 bool CTxDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
450 {
451     return Write(make_pair(string("blockindex"), blockindex.GetBlockHash()), blockindex);
452 }
453
454 bool CTxDB::EraseBlockIndex(uint256 hash)
455 {
456     return Erase(make_pair(string("blockindex"), hash));
457 }
458
459 bool CTxDB::ReadHashBestChain(uint256& hashBestChain)
460 {
461     return Read(string("hashBestChain"), hashBestChain);
462 }
463
464 bool CTxDB::WriteHashBestChain(uint256 hashBestChain)
465 {
466     return Write(string("hashBestChain"), hashBestChain);
467 }
468
469 bool CTxDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork)
470 {
471     return Read(string("bnBestInvalidWork"), bnBestInvalidWork);
472 }
473
474 bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork)
475 {
476     return Write(string("bnBestInvalidWork"), bnBestInvalidWork);
477 }
478
479 CBlockIndex static * InsertBlockIndex(uint256 hash)
480 {
481     if (hash == 0)
482         return NULL;
483
484     // Return existing
485     map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
486     if (mi != mapBlockIndex.end())
487         return (*mi).second;
488
489     // Create new
490     CBlockIndex* pindexNew = new CBlockIndex();
491     if (!pindexNew)
492         throw runtime_error("LoadBlockIndex() : new CBlockIndex failed");
493     mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
494     pindexNew->phashBlock = &((*mi).first);
495
496     return pindexNew;
497 }
498
499 bool CTxDB::LoadBlockIndex()
500 {
501     // Get database cursor
502     Dbc* pcursor = GetCursor();
503     if (!pcursor)
504         return false;
505
506     // Load mapBlockIndex
507     unsigned int fFlags = DB_SET_RANGE;
508     loop
509     {
510         // Read next record
511         CDataStream ssKey;
512         if (fFlags == DB_SET_RANGE)
513             ssKey << make_pair(string("blockindex"), uint256(0));
514         CDataStream ssValue;
515         int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
516         fFlags = DB_NEXT;
517         if (ret == DB_NOTFOUND)
518             break;
519         else if (ret != 0)
520             return false;
521
522         // Unserialize
523         string strType;
524         ssKey >> strType;
525         if (strType == "blockindex")
526         {
527             CDiskBlockIndex diskindex;
528             ssValue >> diskindex;
529
530             // Construct block index object
531             CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
532             pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
533             pindexNew->pnext          = InsertBlockIndex(diskindex.hashNext);
534             pindexNew->nFile          = diskindex.nFile;
535             pindexNew->nBlockPos      = diskindex.nBlockPos;
536             pindexNew->nHeight        = diskindex.nHeight;
537             pindexNew->nVersion       = diskindex.nVersion;
538             pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
539             pindexNew->nTime          = diskindex.nTime;
540             pindexNew->nBits          = diskindex.nBits;
541             pindexNew->nNonce         = diskindex.nNonce;
542
543             // Watch for genesis block
544             if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)
545                 pindexGenesisBlock = pindexNew;
546
547             if (!pindexNew->CheckIndex())
548                 return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
549         }
550         else
551         {
552             break;
553         }
554     }
555     pcursor->close();
556
557     // Calculate bnChainWork
558     vector<pair<int, CBlockIndex*> > vSortedByHeight;
559     vSortedByHeight.reserve(mapBlockIndex.size());
560     BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
561     {
562         CBlockIndex* pindex = item.second;
563         vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));
564     }
565     sort(vSortedByHeight.begin(), vSortedByHeight.end());
566     BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)
567     {
568         CBlockIndex* pindex = item.second;
569         pindex->bnChainWork = (pindex->pprev ? pindex->pprev->bnChainWork : 0) + pindex->GetBlockWork();
570     }
571
572     // Load hashBestChain pointer to end of best chain
573     if (!ReadHashBestChain(hashBestChain))
574     {
575         if (pindexGenesisBlock == NULL)
576             return true;
577         return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
578     }
579     if (!mapBlockIndex.count(hashBestChain))
580         return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index");
581     pindexBest = mapBlockIndex[hashBestChain];
582     nBestHeight = pindexBest->nHeight;
583     bnBestChainWork = pindexBest->bnChainWork;
584     printf("LoadBlockIndex(): hashBestChain=%s  height=%d\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight);
585
586     // Load bnBestInvalidWork, OK if it doesn't exist
587     ReadBestInvalidWork(bnBestInvalidWork);
588
589     // Verify blocks in the best chain
590     int nCheckLevel = GetArg("-checklevel", 1);
591     int nCheckDepth = GetArg( "-checkblocks", 2500);
592     if (nCheckDepth == 0)
593         nCheckDepth = 1000000000; // suffices until the year 19000
594     if (nCheckDepth > nBestHeight)
595         nCheckDepth = nBestHeight;
596     printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
597     CBlockIndex* pindexFork = NULL;
598     map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos;
599     for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
600     {
601         if (pindex->nHeight < nBestHeight-nCheckDepth)
602             break;
603         CBlock block;
604         if (!block.ReadFromDisk(pindex))
605             return error("LoadBlockIndex() : block.ReadFromDisk failed");
606         // check level 1: verify block validity
607         if (nCheckLevel>0 && !block.CheckBlock())
608         {
609             printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
610             pindexFork = pindex->pprev;
611         }
612         // check level 2: verify transaction index validity
613         if (nCheckLevel>1)
614         {
615             pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos);
616             mapBlockPos[pos] = pindex;
617             BOOST_FOREACH(const CTransaction &tx, block.vtx)
618             {
619                 uint256 hashTx = tx.GetHash();
620                 CTxIndex txindex;
621                 if (ReadTxIndex(hashTx, txindex))
622                 {
623                     // check level 3: checker transaction hashes
624                     if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos)
625                     {
626                         // either an error or a duplicate transaction
627                         CTransaction txFound;
628                         if (!txFound.ReadFromDisk(txindex.pos))
629                         {
630                             printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str());
631                             pindexFork = pindex->pprev;
632                         }
633                         else
634                             if (txFound.GetHash() != hashTx) // not a duplicate tx
635                             {
636                                 printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str());
637                                 pindexFork = pindex->pprev;
638                             }
639                     }
640                     // check level 4: check whether spent txouts were spent within the main chain
641                     int nOutput = 0;
642                     if (nCheckLevel>3)
643                         BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent)
644                         {
645                             if (!txpos.IsNull())
646                             {
647                                 pair<unsigned int, unsigned int> posFind = make_pair(txpos.nFile, txpos.nBlockPos);
648                                 if (!mapBlockPos.count(posFind))
649                                 {
650                                     printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str());
651                                     pindexFork = pindex->pprev;
652                                 }
653                                 // check level 6: check whether spent txouts were spent by a valid transaction that consume them
654                                 if (nCheckLevel>5)
655                                 {
656                                     CTransaction txSpend;
657                                     if (!txSpend.ReadFromDisk(txpos))
658                                     {
659                                         printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput);
660                                         pindexFork = pindex->pprev;
661                                     }
662                                     else if (!txSpend.CheckTransaction())
663                                     {
664                                         printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput);
665                                         pindexFork = pindex->pprev;
666                                     }
667                                     else
668                                     {
669                                         bool fFound = false;
670                                         BOOST_FOREACH(const CTxIn &txin, txSpend.vin)
671                                             if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput)
672                                                 fFound = true;
673                                         if (!fFound)
674                                         {
675                                             printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput);
676                                             pindexFork = pindex->pprev;
677                                         }
678                                     }
679                                 }
680                             }
681                             nOutput++;
682                         }
683                 }
684                 // check level 5: check whether all prevouts are marked spent
685                 if (nCheckLevel>4)
686                      BOOST_FOREACH(const CTxIn &txin, tx.vin)
687                      {
688                           CTxIndex txindex;
689                           if (ReadTxIndex(txin.prevout.hash, txindex))
690                               if (txindex.vSpent.size()-1 < txin.prevout.n || txindex.vSpent[txin.prevout.n].IsNull())
691                               {
692                                   printf("LoadBlockIndex(): *** found unspent prevout %s:%i in %s\n", txin.prevout.hash.ToString().c_str(), txin.prevout.n, hashTx.ToString().c_str());
693                                   pindexFork = pindex->pprev;
694                               }
695                      }
696             }
697         }
698     }
699     if (pindexFork)
700     {
701         // Reorg back to the fork
702         printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight);
703         CBlock block;
704         if (!block.ReadFromDisk(pindexFork))
705             return error("LoadBlockIndex() : block.ReadFromDisk failed");
706         CTxDB txdb;
707         block.SetBestChain(txdb, pindexFork);
708     }
709
710     return true;
711 }
712
713
714
715
716
717 //
718 // CAddrDB
719 //
720
721 bool CAddrDB::WriteAddrman(const CAddrMan& addrman)
722 {
723     return Write(string("addrman"), addrman);
724 }
725
726 bool CAddrDB::LoadAddresses()
727 {
728     if (Read(string("addrman"), addrman))
729     {
730         printf("Loaded %i addresses\n", addrman.size());
731         return true;
732     }
733     
734     // Read pre-0.6 addr records
735
736     vector<CAddress> vAddr;
737     vector<vector<unsigned char> > vDelete;
738
739     // Get cursor
740     Dbc* pcursor = GetCursor();
741     if (!pcursor)
742         return false;
743
744     loop
745     {
746         // Read next record
747         CDataStream ssKey;
748         CDataStream ssValue;
749         int ret = ReadAtCursor(pcursor, ssKey, ssValue);
750         if (ret == DB_NOTFOUND)
751             break;
752         else if (ret != 0)
753             return false;
754
755         // Unserialize
756         string strType;
757         ssKey >> strType;
758         if (strType == "addr")
759         {
760             CAddress addr;
761             ssValue >> addr;
762             vAddr.push_back(addr);
763         }
764     }
765     pcursor->close();
766
767     addrman.Add(vAddr, CNetAddr("0.0.0.0"));
768     printf("Loaded %i addresses\n", addrman.size());
769
770     // Note: old records left; we ran into hangs-on-startup
771     // bugs for some users who (we think) were running after
772     // an unclean shutdown.
773
774     return true;
775 }
776
777 bool LoadAddresses()
778 {
779     return CAddrDB("cr+").LoadAddresses();
780 }
781
782
783
784
785 //
786 // CWalletDB
787 //
788
789 bool CWalletDB::WriteName(const string& strAddress, const string& strName)
790 {
791     nWalletDBUpdated++;
792     return Write(make_pair(string("name"), strAddress), strName);
793 }
794
795 bool CWalletDB::EraseName(const string& strAddress)
796 {
797     // This should only be used for sending addresses, never for receiving addresses,
798     // receiving addresses must always have an address book entry if they're not change return.
799     nWalletDBUpdated++;
800     return Erase(make_pair(string("name"), strAddress));
801 }
802
803 bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account)
804 {
805     account.SetNull();
806     return Read(make_pair(string("acc"), strAccount), account);
807 }
808
809 bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
810 {
811     return Write(make_pair(string("acc"), strAccount), account);
812 }
813
814 bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
815 {
816     return Write(boost::make_tuple(string("acentry"), acentry.strAccount, ++nAccountingEntryNumber), acentry);
817 }
818
819 int64 CWalletDB::GetAccountCreditDebit(const string& strAccount)
820 {
821     list<CAccountingEntry> entries;
822     ListAccountCreditDebit(strAccount, entries);
823
824     int64 nCreditDebit = 0;
825     BOOST_FOREACH (const CAccountingEntry& entry, entries)
826         nCreditDebit += entry.nCreditDebit;
827
828     return nCreditDebit;
829 }
830
831 void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
832 {
833     bool fAllAccounts = (strAccount == "*");
834
835     Dbc* pcursor = GetCursor();
836     if (!pcursor)
837         throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor");
838     unsigned int fFlags = DB_SET_RANGE;
839     loop
840     {
841         // Read next record
842         CDataStream ssKey;
843         if (fFlags == DB_SET_RANGE)
844             ssKey << boost::make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64(0));
845         CDataStream ssValue;
846         int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
847         fFlags = DB_NEXT;
848         if (ret == DB_NOTFOUND)
849             break;
850         else if (ret != 0)
851         {
852             pcursor->close();
853             throw runtime_error("CWalletDB::ListAccountCreditDebit() : error scanning DB");
854         }
855
856         // Unserialize
857         string strType;
858         ssKey >> strType;
859         if (strType != "acentry")
860             break;
861         CAccountingEntry acentry;
862         ssKey >> acentry.strAccount;
863         if (!fAllAccounts && acentry.strAccount != strAccount)
864             break;
865
866         ssValue >> acentry;
867         entries.push_back(acentry);
868     }
869
870     pcursor->close();
871 }
872
873
874 int CWalletDB::LoadWallet(CWallet* pwallet)
875 {
876     pwallet->vchDefaultKey.clear();
877     int nFileVersion = 0;
878     vector<uint256> vWalletUpgrade;
879     bool fIsEncrypted = false;
880
881     //// todo: shouldn't we catch exceptions and try to recover and continue?
882     CRITICAL_BLOCK(pwallet->cs_wallet)
883     {
884         int nMinVersion = 0;
885         if (Read((string)"minversion", nMinVersion))
886         {
887             if (nMinVersion > CLIENT_VERSION)
888                 return DB_TOO_NEW;
889             pwallet->LoadMinVersion(nMinVersion);
890         }
891
892         // Get cursor
893         Dbc* pcursor = GetCursor();
894         if (!pcursor)
895         {
896             printf("Error getting wallet database cursor\n");
897             return DB_CORRUPT;
898         }
899
900         loop
901         {
902             // Read next record
903             CDataStream ssKey;
904             CDataStream ssValue;
905             int ret = ReadAtCursor(pcursor, ssKey, ssValue);
906             if (ret == DB_NOTFOUND)
907                 break;
908             else if (ret != 0)
909             {
910                 printf("Error reading next record from wallet database\n");
911                 return DB_CORRUPT;
912             }
913
914             // Unserialize
915             // Taking advantage of the fact that pair serialization
916             // is just the two items serialized one after the other
917             string strType;
918             ssKey >> strType;
919             if (strType == "name")
920             {
921                 string strAddress;
922                 ssKey >> strAddress;
923                 ssValue >> pwallet->mapAddressBook[strAddress];
924             }
925             else if (strType == "tx")
926             {
927                 uint256 hash;
928                 ssKey >> hash;
929                 CWalletTx& wtx = pwallet->mapWallet[hash];
930                 ssValue >> wtx;
931                 wtx.BindWallet(pwallet);
932
933                 if (wtx.GetHash() != hash)
934                     printf("Error in wallet.dat, hash mismatch\n");
935
936                 // Undo serialize changes in 31600
937                 if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
938                 {
939                     if (!ssValue.empty())
940                     {
941                         char fTmp;
942                         char fUnused;
943                         ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
944                         printf("LoadWallet() upgrading tx ver=%d %d '%s' %s\n", wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount.c_str(), hash.ToString().c_str());
945                         wtx.fTimeReceivedIsTxTime = fTmp;
946                     }
947                     else
948                     {
949                         printf("LoadWallet() repairing tx ver=%d %s\n", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str());
950                         wtx.fTimeReceivedIsTxTime = 0;
951                     }
952                     vWalletUpgrade.push_back(hash);
953                 }
954
955                 //// debug print
956                 //printf("LoadWallet  %s\n", wtx.GetHash().ToString().c_str());
957                 //printf(" %12I64d  %s  %s  %s\n",
958                 //    wtx.vout[0].nValue,
959                 //    DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(),
960                 //    wtx.hashBlock.ToString().substr(0,20).c_str(),
961                 //    wtx.mapValue["message"].c_str());
962             }
963             else if (strType == "acentry")
964             {
965                 string strAccount;
966                 ssKey >> strAccount;
967                 uint64 nNumber;
968                 ssKey >> nNumber;
969                 if (nNumber > nAccountingEntryNumber)
970                     nAccountingEntryNumber = nNumber;
971             }
972             else if (strType == "key" || strType == "wkey")
973             {
974                 vector<unsigned char> vchPubKey;
975                 ssKey >> vchPubKey;
976                 CKey key;
977                 if (strType == "key")
978                 {
979                     CPrivKey pkey;
980                     ssValue >> pkey;
981                     key.SetPubKey(vchPubKey);
982                     key.SetPrivKey(pkey);
983                     if (key.GetPubKey() != vchPubKey)
984                     {
985                         printf("Error reading wallet database: CPrivKey pubkey inconsistency\n");
986                         return DB_CORRUPT;
987                     }
988                     if (!key.IsValid())
989                     {
990                         printf("Error reading wallet database: invalid CPrivKey\n");
991                         return DB_CORRUPT;
992                     }
993                 }
994                 else
995                 {
996                     CWalletKey wkey;
997                     ssValue >> wkey;
998                     key.SetPubKey(vchPubKey);
999                     key.SetPrivKey(wkey.vchPrivKey);
1000                     if (key.GetPubKey() != vchPubKey)
1001                     {
1002                         printf("Error reading wallet database: CWalletKey pubkey inconsistency\n");
1003                         return DB_CORRUPT;
1004                     }
1005                     if (!key.IsValid())
1006                     {
1007                         printf("Error reading wallet database: invalid CWalletKey\n");
1008                         return DB_CORRUPT;
1009                     }
1010                 }
1011                 if (!pwallet->LoadKey(key))
1012                 {
1013                     printf("Error reading wallet database: LoadKey failed\n");
1014                     return DB_CORRUPT;
1015                 }
1016             }
1017             else if (strType == "mkey")
1018             {
1019                 unsigned int nID;
1020                 ssKey >> nID;
1021                 CMasterKey kMasterKey;
1022                 ssValue >> kMasterKey;
1023                 if(pwallet->mapMasterKeys.count(nID) != 0)
1024                 {
1025                     printf("Error reading wallet database: duplicate CMasterKey id %u\n", nID);
1026                     return DB_CORRUPT;
1027                 }
1028                 pwallet->mapMasterKeys[nID] = kMasterKey;
1029                 if (pwallet->nMasterKeyMaxID < nID)
1030                     pwallet->nMasterKeyMaxID = nID;
1031             }
1032             else if (strType == "ckey")
1033             {
1034                 vector<unsigned char> vchPubKey;
1035                 ssKey >> vchPubKey;
1036                 vector<unsigned char> vchPrivKey;
1037                 ssValue >> vchPrivKey;
1038                 if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
1039                 {
1040                     printf("Error reading wallet database: LoadCryptedKey failed\n");
1041                     return DB_CORRUPT;
1042                 }
1043                 fIsEncrypted = true;
1044             }
1045             else if (strType == "defaultkey")
1046             {
1047                 ssValue >> pwallet->vchDefaultKey;
1048             }
1049             else if (strType == "pool")
1050             {
1051                 int64 nIndex;
1052                 ssKey >> nIndex;
1053                 pwallet->setKeyPool.insert(nIndex);
1054             }
1055             else if (strType == "version")
1056             {
1057                 ssValue >> nFileVersion;
1058                 if (nFileVersion == 10300)
1059                     nFileVersion = 300;
1060             }
1061             else if (strType == "cscript")
1062             {
1063                 uint160 hash;
1064                 ssKey >> hash;
1065                 CScript script;
1066                 ssValue >> script;
1067                 if (!pwallet->LoadCScript(script))
1068                 {
1069                     printf("Error reading wallet database: LoadCScript failed\n");
1070                     return DB_CORRUPT;
1071                 }
1072             }
1073         }
1074         pcursor->close();
1075     }
1076
1077     BOOST_FOREACH(uint256 hash, vWalletUpgrade)
1078         WriteTx(hash, pwallet->mapWallet[hash]);
1079
1080     printf("nFileVersion = %d\n", nFileVersion);
1081
1082
1083     // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
1084     if (fIsEncrypted && (nFileVersion == 40000 || nFileVersion == 50000))
1085         return DB_NEED_REWRITE;
1086
1087     if (nFileVersion < CLIENT_VERSION) // Update
1088     {
1089         // Get rid of old debug.log file in current directory
1090         if (nFileVersion <= 105 && !pszSetDataDir[0])
1091             unlink("debug.log");
1092
1093         WriteVersion(CLIENT_VERSION);
1094     }
1095
1096     return DB_LOAD_OK;
1097 }
1098
1099 void ThreadFlushWalletDB(void* parg)
1100 {
1101     const string& strFile = ((const string*)parg)[0];
1102     static bool fOneThread;
1103     if (fOneThread)
1104         return;
1105     fOneThread = true;
1106     if (!GetBoolArg("-flushwallet", true))
1107         return;
1108
1109     unsigned int nLastSeen = nWalletDBUpdated;
1110     unsigned int nLastFlushed = nWalletDBUpdated;
1111     int64 nLastWalletUpdate = GetTime();
1112     while (!fShutdown)
1113     {
1114         Sleep(500);
1115
1116         if (nLastSeen != nWalletDBUpdated)
1117         {
1118             nLastSeen = nWalletDBUpdated;
1119             nLastWalletUpdate = GetTime();
1120         }
1121
1122         if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2)
1123         {
1124             TRY_CRITICAL_BLOCK(cs_db)
1125             {
1126                 // Don't do this if any databases are in use
1127                 int nRefCount = 0;
1128                 map<string, int>::iterator mi = mapFileUseCount.begin();
1129                 while (mi != mapFileUseCount.end())
1130                 {
1131                     nRefCount += (*mi).second;
1132                     mi++;
1133                 }
1134
1135                 if (nRefCount == 0 && !fShutdown)
1136                 {
1137                     map<string, int>::iterator mi = mapFileUseCount.find(strFile);
1138                     if (mi != mapFileUseCount.end())
1139                     {
1140                         printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
1141                         printf("Flushing wallet.dat\n");
1142                         nLastFlushed = nWalletDBUpdated;
1143                         int64 nStart = GetTimeMillis();
1144
1145                         // Flush wallet.dat so it's self contained
1146                         CloseDb(strFile);
1147                         dbenv.txn_checkpoint(0, 0, 0);
1148                         dbenv.lsn_reset(strFile.c_str(), 0);
1149
1150                         mapFileUseCount.erase(mi++);
1151                         printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart);
1152                     }
1153                 }
1154             }
1155         }
1156     }
1157 }
1158
1159 bool BackupWallet(const CWallet& wallet, const string& strDest)
1160 {
1161     if (!wallet.fFileBacked)
1162         return false;
1163     while (!fShutdown)
1164     {
1165         CRITICAL_BLOCK(cs_db)
1166         {
1167             if (!mapFileUseCount.count(wallet.strWalletFile) || mapFileUseCount[wallet.strWalletFile] == 0)
1168             {
1169                 // Flush log data to the dat file
1170                 CloseDb(wallet.strWalletFile);
1171                 dbenv.txn_checkpoint(0, 0, 0);
1172                 dbenv.lsn_reset(wallet.strWalletFile.c_str(), 0);
1173                 mapFileUseCount.erase(wallet.strWalletFile);
1174
1175                 // Copy wallet.dat
1176                 filesystem::path pathSrc(GetDataDir() + "/" + wallet.strWalletFile);
1177                 pathSrc.make_preferred();
1178                 filesystem::path pathDest(strDest);
1179                 pathDest.make_preferred();
1180                 if (filesystem::is_directory(pathDest))
1181                     pathDest = pathDest / wallet.strWalletFile;
1182
1183                 try {
1184 #if BOOST_VERSION >= 104000
1185                     filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
1186 #else
1187                     filesystem::copy_file(pathSrc, pathDest);
1188 #endif
1189                     printf("copied wallet.dat to %s\n", pathDest.string().c_str());
1190                     return true;
1191                 } catch(const filesystem::filesystem_error &e) {
1192                     printf("error copying wallet.dat to %s - %s\n", pathDest.string().c_str(), e.what());
1193                     return false;
1194                 }
1195             }
1196         }
1197         Sleep(100);
1198     }
1199     return false;
1200 }