Move CWalletDB code to new walletdb module.
[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 "db.h"
7 #include "util.h"
8 #include "main.h"
9 #include "wallet.h"
10 #include <boost/version.hpp>
11 #include <boost/filesystem.hpp>
12 #include <boost/filesystem/fstream.hpp>
13
14 #ifndef WIN32
15 #include "sys/stat.h"
16 #endif
17
18 using namespace std;
19 using namespace boost;
20
21
22 unsigned int nWalletDBUpdated;
23
24
25
26 //
27 // CDB
28 //
29
30 CCriticalSection cs_db;
31 static bool fDbEnvInit = false;
32 DbEnv dbenv(0);
33 map<string, int> mapFileUseCount;
34 static map<string, Db*> mapDb;
35
36 static void EnvShutdown()
37 {
38     if (!fDbEnvInit)
39         return;
40
41     fDbEnvInit = false;
42     try
43     {
44         dbenv.close(0);
45     }
46     catch (const DbException& e)
47     {
48         printf("EnvShutdown exception: %s (%d)\n", e.what(), e.get_errno());
49     }
50     DbEnv(0).remove(GetDataDir().string().c_str(), 0);
51 }
52
53 class CDBInit
54 {
55 public:
56     CDBInit()
57     {
58     }
59     ~CDBInit()
60     {
61         EnvShutdown();
62     }
63 }
64 instance_of_cdbinit;
65
66
67 CDB::CDB(const char *pszFile, const char* pszMode) : pdb(NULL)
68 {
69     int ret;
70     if (pszFile == NULL)
71         return;
72
73     fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
74     bool fCreate = strchr(pszMode, 'c');
75     unsigned int nFlags = DB_THREAD;
76     if (fCreate)
77         nFlags |= DB_CREATE;
78
79     {
80         LOCK(cs_db);
81         if (!fDbEnvInit)
82         {
83             if (fShutdown)
84                 return;
85             filesystem::path pathDataDir = GetDataDir();
86             filesystem::path pathLogDir = pathDataDir / "database";
87             filesystem::create_directory(pathLogDir);
88             filesystem::path pathErrorFile = pathDataDir / "db.log";
89             printf("dbenv.open LogDir=%s ErrorFile=%s\n", pathLogDir.string().c_str(), pathErrorFile.string().c_str());
90
91             int nDbCache = GetArg("-dbcache", 25);
92             dbenv.set_lg_dir(pathLogDir.string().c_str());
93             dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1);
94             dbenv.set_lg_bsize(1048576);
95             dbenv.set_lg_max(10485760);
96             dbenv.set_lk_max_locks(10000);
97             dbenv.set_lk_max_objects(10000);
98             dbenv.set_errfile(fopen(pathErrorFile.string().c_str(), "a")); /// debug
99             dbenv.set_flags(DB_AUTO_COMMIT, 1);
100             dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1);
101             ret = dbenv.open(pathDataDir.string().c_str(),
102                              DB_CREATE     |
103                              DB_INIT_LOCK  |
104                              DB_INIT_LOG   |
105                              DB_INIT_MPOOL |
106                              DB_INIT_TXN   |
107                              DB_THREAD     |
108                              DB_RECOVER,
109                              S_IRUSR | S_IWUSR);
110             if (ret > 0)
111                 throw runtime_error(strprintf("CDB() : error %d opening database environment", ret));
112             fDbEnvInit = true;
113         }
114
115         strFile = pszFile;
116         ++mapFileUseCount[strFile];
117         pdb = mapDb[strFile];
118         if (pdb == NULL)
119         {
120             pdb = new Db(&dbenv, 0);
121
122             ret = pdb->open(NULL,      // Txn pointer
123                             pszFile,   // Filename
124                             "main",    // Logical db name
125                             DB_BTREE,  // Database type
126                             nFlags,    // Flags
127                             0);
128
129             if (ret > 0)
130             {
131                 delete pdb;
132                 pdb = NULL;
133                 {
134                      LOCK(cs_db);
135                     --mapFileUseCount[strFile];
136                 }
137                 strFile = "";
138                 throw runtime_error(strprintf("CDB() : can't open database file %s, error %d", pszFile, ret));
139             }
140
141             if (fCreate && !Exists(string("version")))
142             {
143                 bool fTmp = fReadOnly;
144                 fReadOnly = false;
145                 WriteVersion(CLIENT_VERSION);
146                 fReadOnly = fTmp;
147             }
148
149             mapDb[strFile] = pdb;
150         }
151     }
152 }
153
154 void CDB::Close()
155 {
156     if (!pdb)
157         return;
158     if (!vTxn.empty())
159         vTxn.front()->abort();
160     vTxn.clear();
161     pdb = NULL;
162
163     // Flush database activity from memory pool to disk log
164     unsigned int nMinutes = 0;
165     if (fReadOnly)
166         nMinutes = 1;
167     if (strFile == "addr.dat")
168         nMinutes = 2;
169     if (strFile == "blkindex.dat" && IsInitialBlockDownload())
170         nMinutes = 5;
171
172     dbenv.txn_checkpoint(nMinutes ? GetArg("-dblogsize", 100)*1024 : 0, nMinutes, 0);
173
174     {
175         LOCK(cs_db);
176         --mapFileUseCount[strFile];
177     }
178 }
179
180 void CloseDb(const string& strFile)
181 {
182     {
183         LOCK(cs_db);
184         if (mapDb[strFile] != NULL)
185         {
186             // Close the database handle
187             Db* pdb = mapDb[strFile];
188             pdb->close(0);
189             delete pdb;
190             mapDb[strFile] = NULL;
191         }
192     }
193 }
194
195 bool CDB::Rewrite(const string& strFile, const char* pszSkip)
196 {
197     while (!fShutdown)
198     {
199         {
200             LOCK(cs_db);
201             if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0)
202             {
203                 // Flush log data to the dat file
204                 CloseDb(strFile);
205                 dbenv.txn_checkpoint(0, 0, 0);
206                 dbenv.lsn_reset(strFile.c_str(), 0);
207                 mapFileUseCount.erase(strFile);
208
209                 bool fSuccess = true;
210                 printf("Rewriting %s...\n", strFile.c_str());
211                 string strFileRes = strFile + ".rewrite";
212                 { // surround usage of db with extra {}
213                     CDB db(strFile.c_str(), "r");
214                     Db* pdbCopy = new Db(&dbenv, 0);
215     
216                     int ret = pdbCopy->open(NULL,                 // Txn pointer
217                                             strFileRes.c_str(),   // Filename
218                                             "main",    // Logical db name
219                                             DB_BTREE,  // Database type
220                                             DB_CREATE,    // Flags
221                                             0);
222                     if (ret > 0)
223                     {
224                         printf("Cannot create database file %s\n", strFileRes.c_str());
225                         fSuccess = false;
226                     }
227     
228                     Dbc* pcursor = db.GetCursor();
229                     if (pcursor)
230                         while (fSuccess)
231                         {
232                             CDataStream ssKey;
233                             CDataStream ssValue;
234                             int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
235                             if (ret == DB_NOTFOUND)
236                             {
237                                 pcursor->close();
238                                 break;
239                             }
240                             else if (ret != 0)
241                             {
242                                 pcursor->close();
243                                 fSuccess = false;
244                                 break;
245                             }
246                             if (pszSkip &&
247                                 strncmp(&ssKey[0], pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0)
248                                 continue;
249                             if (strncmp(&ssKey[0], "\x07version", 8) == 0)
250                             {
251                                 // Update version:
252                                 ssValue.clear();
253                                 ssValue << CLIENT_VERSION;
254                             }
255                             Dbt datKey(&ssKey[0], ssKey.size());
256                             Dbt datValue(&ssValue[0], ssValue.size());
257                             int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE);
258                             if (ret2 > 0)
259                                 fSuccess = false;
260                         }
261                     if (fSuccess)
262                     {
263                         db.Close();
264                         CloseDb(strFile);
265                         if (pdbCopy->close(0))
266                             fSuccess = false;
267                         delete pdbCopy;
268                     }
269                 }
270                 if (fSuccess)
271                 {
272                     Db dbA(&dbenv, 0);
273                     if (dbA.remove(strFile.c_str(), NULL, 0))
274                         fSuccess = false;
275                     Db dbB(&dbenv, 0);
276                     if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0))
277                         fSuccess = false;
278                 }
279                 if (!fSuccess)
280                     printf("Rewriting of %s FAILED!\n", strFileRes.c_str());
281                 return fSuccess;
282             }
283         }
284         Sleep(100);
285     }
286     return false;
287 }
288
289
290 void DBFlush(bool fShutdown)
291 {
292     // Flush log data to the actual data file
293     //  on all files that are not in use
294     printf("DBFlush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started");
295     if (!fDbEnvInit)
296         return;
297     {
298         LOCK(cs_db);
299         map<string, int>::iterator mi = mapFileUseCount.begin();
300         while (mi != mapFileUseCount.end())
301         {
302             string strFile = (*mi).first;
303             int nRefCount = (*mi).second;
304             printf("%s refcount=%d\n", strFile.c_str(), nRefCount);
305             if (nRefCount == 0)
306             {
307                 // Move log data to the dat file
308                 CloseDb(strFile);
309                 dbenv.txn_checkpoint(0, 0, 0);
310                 printf("%s flush\n", strFile.c_str());
311                 dbenv.lsn_reset(strFile.c_str(), 0);
312                 mapFileUseCount.erase(mi++);
313             }
314             else
315                 mi++;
316         }
317         if (fShutdown)
318         {
319             char** listp;
320             if (mapFileUseCount.empty())
321             {
322                 dbenv.log_archive(&listp, DB_ARCH_REMOVE);
323                 EnvShutdown();
324             }
325         }
326     }
327 }
328
329
330
331
332
333
334 //
335 // CTxDB
336 //
337
338 bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex)
339 {
340     assert(!fClient);
341     txindex.SetNull();
342     return Read(make_pair(string("tx"), hash), txindex);
343 }
344
345 bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex)
346 {
347     assert(!fClient);
348     return Write(make_pair(string("tx"), hash), txindex);
349 }
350
351 bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight)
352 {
353     assert(!fClient);
354
355     // Add to tx index
356     uint256 hash = tx.GetHash();
357     CTxIndex txindex(pos, tx.vout.size());
358     return Write(make_pair(string("tx"), hash), txindex);
359 }
360
361 bool CTxDB::EraseTxIndex(const CTransaction& tx)
362 {
363     assert(!fClient);
364     uint256 hash = tx.GetHash();
365
366     return Erase(make_pair(string("tx"), hash));
367 }
368
369 bool CTxDB::ContainsTx(uint256 hash)
370 {
371     assert(!fClient);
372     return Exists(make_pair(string("tx"), hash));
373 }
374
375 bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector<CTransaction>& vtx)
376 {
377     assert(!fClient);
378     vtx.clear();
379
380     // Get cursor
381     Dbc* pcursor = GetCursor();
382     if (!pcursor)
383         return false;
384
385     unsigned int fFlags = DB_SET_RANGE;
386     loop
387     {
388         // Read next record
389         CDataStream ssKey;
390         if (fFlags == DB_SET_RANGE)
391             ssKey << string("owner") << hash160 << CDiskTxPos(0, 0, 0);
392         CDataStream ssValue;
393         int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
394         fFlags = DB_NEXT;
395         if (ret == DB_NOTFOUND)
396             break;
397         else if (ret != 0)
398         {
399             pcursor->close();
400             return false;
401         }
402
403         // Unserialize
404         string strType;
405         uint160 hashItem;
406         CDiskTxPos pos;
407         ssKey >> strType >> hashItem >> pos;
408         int nItemHeight;
409         ssValue >> nItemHeight;
410
411         // Read transaction
412         if (strType != "owner" || hashItem != hash160)
413             break;
414         if (nItemHeight >= nMinHeight)
415         {
416             vtx.resize(vtx.size()+1);
417             if (!vtx.back().ReadFromDisk(pos))
418             {
419                 pcursor->close();
420                 return false;
421             }
422         }
423     }
424
425     pcursor->close();
426     return true;
427 }
428
429 bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex)
430 {
431     assert(!fClient);
432     tx.SetNull();
433     if (!ReadTxIndex(hash, txindex))
434         return false;
435     return (tx.ReadFromDisk(txindex.pos));
436 }
437
438 bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx)
439 {
440     CTxIndex txindex;
441     return ReadDiskTx(hash, tx, txindex);
442 }
443
444 bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex)
445 {
446     return ReadDiskTx(outpoint.hash, tx, txindex);
447 }
448
449 bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx)
450 {
451     CTxIndex txindex;
452     return ReadDiskTx(outpoint.hash, tx, txindex);
453 }
454
455 bool CTxDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
456 {
457     return Write(make_pair(string("blockindex"), blockindex.GetBlockHash()), blockindex);
458 }
459
460 bool CTxDB::EraseBlockIndex(uint256 hash)
461 {
462     return Erase(make_pair(string("blockindex"), hash));
463 }
464
465 bool CTxDB::ReadHashBestChain(uint256& hashBestChain)
466 {
467     return Read(string("hashBestChain"), hashBestChain);
468 }
469
470 bool CTxDB::WriteHashBestChain(uint256 hashBestChain)
471 {
472     return Write(string("hashBestChain"), hashBestChain);
473 }
474
475 bool CTxDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork)
476 {
477     return Read(string("bnBestInvalidWork"), bnBestInvalidWork);
478 }
479
480 bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork)
481 {
482     return Write(string("bnBestInvalidWork"), bnBestInvalidWork);
483 }
484
485 CBlockIndex static * InsertBlockIndex(uint256 hash)
486 {
487     if (hash == 0)
488         return NULL;
489
490     // Return existing
491     map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
492     if (mi != mapBlockIndex.end())
493         return (*mi).second;
494
495     // Create new
496     CBlockIndex* pindexNew = new CBlockIndex();
497     if (!pindexNew)
498         throw runtime_error("LoadBlockIndex() : new CBlockIndex failed");
499     mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
500     pindexNew->phashBlock = &((*mi).first);
501
502     return pindexNew;
503 }
504
505 bool CTxDB::LoadBlockIndex()
506 {
507     // Get database cursor
508     Dbc* pcursor = GetCursor();
509     if (!pcursor)
510         return false;
511
512     // Load mapBlockIndex
513     unsigned int fFlags = DB_SET_RANGE;
514     loop
515     {
516         // Read next record
517         CDataStream ssKey;
518         if (fFlags == DB_SET_RANGE)
519             ssKey << make_pair(string("blockindex"), uint256(0));
520         CDataStream ssValue;
521         int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
522         fFlags = DB_NEXT;
523         if (ret == DB_NOTFOUND)
524             break;
525         else if (ret != 0)
526             return false;
527
528         // Unserialize
529         string strType;
530         ssKey >> strType;
531         if (strType == "blockindex")
532         {
533             CDiskBlockIndex diskindex;
534             ssValue >> diskindex;
535
536             // Construct block index object
537             CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
538             pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
539             pindexNew->pnext          = InsertBlockIndex(diskindex.hashNext);
540             pindexNew->nFile          = diskindex.nFile;
541             pindexNew->nBlockPos      = diskindex.nBlockPos;
542             pindexNew->nHeight        = diskindex.nHeight;
543             pindexNew->nVersion       = diskindex.nVersion;
544             pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
545             pindexNew->nTime          = diskindex.nTime;
546             pindexNew->nBits          = diskindex.nBits;
547             pindexNew->nNonce         = diskindex.nNonce;
548
549             // Watch for genesis block
550             if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)
551                 pindexGenesisBlock = pindexNew;
552
553             if (!pindexNew->CheckIndex())
554                 return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
555         }
556         else
557         {
558             break;
559         }
560     }
561     pcursor->close();
562
563     // Calculate bnChainWork
564     vector<pair<int, CBlockIndex*> > vSortedByHeight;
565     vSortedByHeight.reserve(mapBlockIndex.size());
566     BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
567     {
568         CBlockIndex* pindex = item.second;
569         vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));
570     }
571     sort(vSortedByHeight.begin(), vSortedByHeight.end());
572     BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)
573     {
574         CBlockIndex* pindex = item.second;
575         pindex->bnChainWork = (pindex->pprev ? pindex->pprev->bnChainWork : 0) + pindex->GetBlockWork();
576     }
577
578     // Load hashBestChain pointer to end of best chain
579     if (!ReadHashBestChain(hashBestChain))
580     {
581         if (pindexGenesisBlock == NULL)
582             return true;
583         return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
584     }
585     if (!mapBlockIndex.count(hashBestChain))
586         return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index");
587     pindexBest = mapBlockIndex[hashBestChain];
588     nBestHeight = pindexBest->nHeight;
589     bnBestChainWork = pindexBest->bnChainWork;
590     printf("LoadBlockIndex(): hashBestChain=%s  height=%d\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight);
591
592     // Load bnBestInvalidWork, OK if it doesn't exist
593     ReadBestInvalidWork(bnBestInvalidWork);
594
595     // Verify blocks in the best chain
596     int nCheckLevel = GetArg("-checklevel", 1);
597     int nCheckDepth = GetArg( "-checkblocks", 2500);
598     if (nCheckDepth == 0)
599         nCheckDepth = 1000000000; // suffices until the year 19000
600     if (nCheckDepth > nBestHeight)
601         nCheckDepth = nBestHeight;
602     printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
603     CBlockIndex* pindexFork = NULL;
604     map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos;
605     for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
606     {
607         if (pindex->nHeight < nBestHeight-nCheckDepth)
608             break;
609         CBlock block;
610         if (!block.ReadFromDisk(pindex))
611             return error("LoadBlockIndex() : block.ReadFromDisk failed");
612         // check level 1: verify block validity
613         if (nCheckLevel>0 && !block.CheckBlock())
614         {
615             printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
616             pindexFork = pindex->pprev;
617         }
618         // check level 2: verify transaction index validity
619         if (nCheckLevel>1)
620         {
621             pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos);
622             mapBlockPos[pos] = pindex;
623             BOOST_FOREACH(const CTransaction &tx, block.vtx)
624             {
625                 uint256 hashTx = tx.GetHash();
626                 CTxIndex txindex;
627                 if (ReadTxIndex(hashTx, txindex))
628                 {
629                     // check level 3: checker transaction hashes
630                     if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos)
631                     {
632                         // either an error or a duplicate transaction
633                         CTransaction txFound;
634                         if (!txFound.ReadFromDisk(txindex.pos))
635                         {
636                             printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str());
637                             pindexFork = pindex->pprev;
638                         }
639                         else
640                             if (txFound.GetHash() != hashTx) // not a duplicate tx
641                             {
642                                 printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str());
643                                 pindexFork = pindex->pprev;
644                             }
645                     }
646                     // check level 4: check whether spent txouts were spent within the main chain
647                     int nOutput = 0;
648                     if (nCheckLevel>3)
649                     {
650                         BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent)
651                         {
652                             if (!txpos.IsNull())
653                             {
654                                 pair<unsigned int, unsigned int> posFind = make_pair(txpos.nFile, txpos.nBlockPos);
655                                 if (!mapBlockPos.count(posFind))
656                                 {
657                                     printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str());
658                                     pindexFork = pindex->pprev;
659                                 }
660                                 // check level 6: check whether spent txouts were spent by a valid transaction that consume them
661                                 if (nCheckLevel>5)
662                                 {
663                                     CTransaction txSpend;
664                                     if (!txSpend.ReadFromDisk(txpos))
665                                     {
666                                         printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput);
667                                         pindexFork = pindex->pprev;
668                                     }
669                                     else if (!txSpend.CheckTransaction())
670                                     {
671                                         printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput);
672                                         pindexFork = pindex->pprev;
673                                     }
674                                     else
675                                     {
676                                         bool fFound = false;
677                                         BOOST_FOREACH(const CTxIn &txin, txSpend.vin)
678                                             if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput)
679                                                 fFound = true;
680                                         if (!fFound)
681                                         {
682                                             printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput);
683                                             pindexFork = pindex->pprev;
684                                         }
685                                     }
686                                 }
687                             }
688                             nOutput++;
689                         }
690                     }
691                 }
692                 // check level 5: check whether all prevouts are marked spent
693                 if (nCheckLevel>4)
694                 {
695                      BOOST_FOREACH(const CTxIn &txin, tx.vin)
696                      {
697                           CTxIndex txindex;
698                           if (ReadTxIndex(txin.prevout.hash, txindex))
699                               if (txindex.vSpent.size()-1 < txin.prevout.n || txindex.vSpent[txin.prevout.n].IsNull())
700                               {
701                                   printf("LoadBlockIndex(): *** found unspent prevout %s:%i in %s\n", txin.prevout.hash.ToString().c_str(), txin.prevout.n, hashTx.ToString().c_str());
702                                   pindexFork = pindex->pprev;
703                               }
704                      }
705                 }
706             }
707         }
708     }
709     if (pindexFork)
710     {
711         // Reorg back to the fork
712         printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight);
713         CBlock block;
714         if (!block.ReadFromDisk(pindexFork))
715             return error("LoadBlockIndex() : block.ReadFromDisk failed");
716         CTxDB txdb;
717         block.SetBestChain(txdb, pindexFork);
718     }
719
720     return true;
721 }
722
723
724
725
726
727 //
728 // CAddrDB
729 //
730
731 bool CAddrDB::WriteAddrman(const CAddrMan& addrman)
732 {
733     return Write(string("addrman"), addrman);
734 }
735
736 bool CAddrDB::LoadAddresses()
737 {
738     if (Read(string("addrman"), addrman))
739     {
740         printf("Loaded %i addresses\n", addrman.size());
741         return true;
742     }
743     
744     // Read pre-0.6 addr records
745
746     vector<CAddress> vAddr;
747     vector<vector<unsigned char> > vDelete;
748
749     // Get cursor
750     Dbc* pcursor = GetCursor();
751     if (!pcursor)
752         return false;
753
754     loop
755     {
756         // Read next record
757         CDataStream ssKey;
758         CDataStream ssValue;
759         int ret = ReadAtCursor(pcursor, ssKey, ssValue);
760         if (ret == DB_NOTFOUND)
761             break;
762         else if (ret != 0)
763             return false;
764
765         // Unserialize
766         string strType;
767         ssKey >> strType;
768         if (strType == "addr")
769         {
770             CAddress addr;
771             ssValue >> addr;
772             vAddr.push_back(addr);
773         }
774     }
775     pcursor->close();
776
777     addrman.Add(vAddr, CNetAddr("0.0.0.0"));
778     printf("Loaded %i addresses\n", addrman.size());
779
780     // Note: old records left; we ran into hangs-on-startup
781     // bugs for some users who (we think) were running after
782     // an unclean shutdown.
783
784     return true;
785 }
786
787 bool LoadAddresses()
788 {
789     return CAddrDB("cr+").LoadAddresses();
790 }
791
792