genesis                 1 
genesis                 2 
genesis                 3 
genesis                 4 
genesis                 5 
genesis                 6 #include "headers.h"
genesis                 7 #include "db.h"
genesis                 8 #include "net.h"
genesis                 9 #include <boost/filesystem.hpp>
genesis                10 #include <boost/filesystem/fstream.hpp>
genesis                11 
genesis                12 using namespace std;
genesis                13 using namespace boost;
genesis                14 
genesis                15 
genesis                16 unsigned int nWalletDBUpdated;
genesis                17 uint64 nAccountingEntryNumber = 0;
genesis                18 
genesis                19 
genesis                20 
genesis                21 
genesis                22 
genesis                23 
genesis                24 
genesis                25 static CCriticalSection cs_db;
genesis                26 static bool fDbEnvInit = false;
genesis                27 DbEnv dbenv(0);
genesis                28 static map<string, int> mapFileUseCount;
genesis                29 static map<string, Db*> mapDb;
genesis                30 
genesis                31 static void EnvShutdown()
genesis                32 {
genesis                33     if (!fDbEnvInit)
genesis                34         return;
genesis                35 
genesis                36     fDbEnvInit = false;
genesis                37     try
genesis                38     {
genesis                39         dbenv.close(0);
genesis                40     }
genesis                41     catch (const DbException& e)
genesis                42     {
genesis                43         printf("EnvShutdown exception: %s (%d)\n", e.what(), e.get_errno());
genesis                44     }
genesis                45     DbEnv(0).remove(GetDataDir().c_str(), 0);
genesis                46 }
genesis                47 
genesis                48 class CDBInit
genesis                49 {
genesis                50 public:
genesis                51     CDBInit()
genesis                52     {
genesis                53     }
genesis                54     ~CDBInit()
genesis                55     {
genesis                56         EnvShutdown();
genesis                57     }
genesis                58 }
genesis                59 instance_of_cdbinit;
genesis                60 
genesis                61 
genesis                62 CDB::CDB(const char* pszFile, const char* pszMode) : pdb(NULL)
genesis                63 {
genesis                64     int ret;
genesis                65     if (pszFile == NULL)
genesis                66         return;
genesis                67 
genesis                68     fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
genesis                69     bool fCreate = strchr(pszMode, 'c');
genesis                70     unsigned int nFlags = DB_THREAD;
genesis                71     if (fCreate)
genesis                72         nFlags |= DB_CREATE;
genesis                73 
genesis                74     CRITICAL_BLOCK(cs_db)
genesis                75     {
genesis                76         if (!fDbEnvInit)
genesis                77         {
genesis                78             if (fShutdown)
genesis                79                 return;
genesis                80             string strDataDir = GetDataDir();
genesis                81             string strLogDir = strDataDir + "/database";
genesis                82             filesystem::create_directory(strLogDir.c_str());
genesis                83             string strErrorFile = strDataDir + "/db.log";
genesis                84             printf("dbenv.open strLogDir=%s strErrorFile=%s\n", strLogDir.c_str(), strErrorFile.c_str());
genesis                85 
genesis                86             dbenv.set_lg_dir(strLogDir.c_str());
genesis                87             dbenv.set_lg_max(10000000);
genesis                88             dbenv.set_lk_max_locks(10000);
genesis                89             dbenv.set_lk_max_objects(10000);
genesis                90             dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); 
genesis                91             dbenv.set_flags(DB_AUTO_COMMIT, 1);
genesis                92             ret = dbenv.open(strDataDir.c_str(),
genesis                93                              DB_CREATE     |
genesis                94                              DB_INIT_LOCK  |
genesis                95                              DB_INIT_LOG   |
genesis                96                              DB_INIT_MPOOL |
genesis                97                              DB_INIT_TXN   |
genesis                98                              DB_THREAD     |
genesis                99                              DB_RECOVER,
genesis               100                              S_IRUSR | S_IWUSR);
genesis               101             if (ret > 0)
genesis               102                 throw runtime_error(strprintf("CDB() : error %d opening database environment", ret));
genesis               103             fDbEnvInit = true;
genesis               104         }
genesis               105 
genesis               106         strFile = pszFile;
genesis               107         ++mapFileUseCount[strFile];
genesis               108         pdb = mapDb[strFile];
genesis               109         if (pdb == NULL)
genesis               110         {
genesis               111             pdb = new Db(&dbenv, 0);
genesis               112 
genesis               113             ret = pdb->open(NULL,      
genesis               114                             pszFile,   
genesis               115                             "main",    
genesis               116                             DB_BTREE,  
genesis               117                             nFlags,    
genesis               118                             0);
genesis               119 
genesis               120             if (ret > 0)
genesis               121             {
genesis               122                 delete pdb;
genesis               123                 pdb = NULL;
genesis               124                 CRITICAL_BLOCK(cs_db)
genesis               125                     --mapFileUseCount[strFile];
genesis               126                 strFile = "";
genesis               127                 throw runtime_error(strprintf("CDB() : can't open database file %s, error %d", pszFile, ret));
genesis               128             }
genesis               129 
genesis               130             if (fCreate && !Exists(string("version")))
genesis               131             {
genesis               132                 bool fTmp = fReadOnly;
genesis               133                 fReadOnly = false;
genesis               134                 WriteVersion(VERSION);
genesis               135                 fReadOnly = fTmp;
genesis               136             }
genesis               137 
genesis               138             mapDb[strFile] = pdb;
genesis               139         }
genesis               140     }
genesis               141 }
genesis               142 
genesis               143 void CDB::Close()
genesis               144 {
genesis               145     if (!pdb)
genesis               146         return;
genesis               147     if (!vTxn.empty())
genesis               148         vTxn.front()->abort();
genesis               149     vTxn.clear();
genesis               150     pdb = NULL;
genesis               151 
genesis               152     
genesis               153     unsigned int nMinutes = 0;
genesis               154     if (fReadOnly)
genesis               155         nMinutes = 1;
genesis               156     if (strFile == "addr.dat")
genesis               157         nMinutes = 2;
genesis               158     if (strFile == "blkindex.dat" && IsInitialBlockDownload() && nBestHeight % 500 != 0)
genesis               159         nMinutes = 1;
genesis               160     dbenv.txn_checkpoint(0, nMinutes, 0);
genesis               161 
genesis               162     CRITICAL_BLOCK(cs_db)
genesis               163         --mapFileUseCount[strFile];
genesis               164 }
genesis               165 
genesis               166 void static CloseDb(const string& strFile)
genesis               167 {
genesis               168     CRITICAL_BLOCK(cs_db)
genesis               169     {
genesis               170         if (mapDb[strFile] != NULL)
genesis               171         {
genesis               172             
genesis               173             Db* pdb = mapDb[strFile];
genesis               174             pdb->close(0);
genesis               175             delete pdb;
genesis               176             mapDb[strFile] = NULL;
genesis               177         }
genesis               178     }
genesis               179 }
genesis               180 
genesis               181 bool CDB::Rewrite(const string& strFile, const char* pszSkip)
genesis               182 {
genesis               183     while (!fShutdown)
genesis               184     {
genesis               185         CRITICAL_BLOCK(cs_db)
genesis               186         {
genesis               187             if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0)
genesis               188             {
genesis               189                 
genesis               190                 CloseDb(strFile);
genesis               191                 dbenv.txn_checkpoint(0, 0, 0);
genesis               192                 dbenv.lsn_reset(strFile.c_str(), 0);
genesis               193                 mapFileUseCount.erase(strFile);
genesis               194 
genesis               195                 bool fSuccess = true;
genesis               196                 printf("Rewriting %s...\n", strFile.c_str());
genesis               197                 string strFileRes = strFile + ".rewrite";
genesis               198                 { 
genesis               199                     CDB db(strFile.c_str(), "r");
genesis               200                     Db* pdbCopy = new Db(&dbenv, 0);
genesis               201     
genesis               202                     int ret = pdbCopy->open(NULL,                 
genesis               203                                             strFileRes.c_str(),   
genesis               204                                             "main",    
genesis               205                                             DB_BTREE,  
genesis               206                                             DB_CREATE,    
genesis               207                                             0);
genesis               208                     if (ret > 0)
genesis               209                     {
genesis               210                         printf("Cannot create database file %s\n", strFileRes.c_str());
genesis               211                         fSuccess = false;
genesis               212                     }
genesis               213     
genesis               214                     Dbc* pcursor = db.GetCursor();
genesis               215                     if (pcursor)
genesis               216                         while (fSuccess)
genesis               217                         {
genesis               218                             CDataStream ssKey;
genesis               219                             CDataStream ssValue;
genesis               220                             int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
genesis               221                             if (ret == DB_NOTFOUND)
genesis               222                             {
genesis               223                                 pcursor->close();
genesis               224                                 break;
genesis               225                             }
genesis               226                             else if (ret != 0)
genesis               227                             {
genesis               228                                 pcursor->close();
genesis               229                                 fSuccess = false;
genesis               230                                 break;
genesis               231                             }
genesis               232                             if (pszSkip &&
genesis               233                                 strncmp(&ssKey[0], pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0)
genesis               234                                 continue;
genesis               235                             if (strncmp(&ssKey[0], "\x07version", 8) == 0)
genesis               236                             {
genesis               237                                 
genesis               238                                 ssValue.clear();
genesis               239                                 ssValue << VERSION;
genesis               240                             }
genesis               241                             Dbt datKey(&ssKey[0], ssKey.size());
genesis               242                             Dbt datValue(&ssValue[0], ssValue.size());
genesis               243                             int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE);
genesis               244                             if (ret2 > 0)
genesis               245                                 fSuccess = false;
genesis               246                         }
genesis               247                     if (fSuccess)
genesis               248                     {
genesis               249                         db.Close();
genesis               250                         CloseDb(strFile);
genesis               251                         if (pdbCopy->close(0))
genesis               252                             fSuccess = false;
genesis               253                         delete pdbCopy;
genesis               254                     }
genesis               255                 }
genesis               256                 if (fSuccess)
genesis               257                 {
genesis               258                     Db dbA(&dbenv, 0);
genesis               259                     if (dbA.remove(strFile.c_str(), NULL, 0))
genesis               260                         fSuccess = false;
genesis               261                     Db dbB(&dbenv, 0);
genesis               262                     if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0))
genesis               263                         fSuccess = false;
genesis               264                 }
genesis               265                 if (!fSuccess)
genesis               266                     printf("Rewriting of %s FAILED!\n", strFileRes.c_str());
genesis               267                 return fSuccess;
genesis               268             }
genesis               269         }
genesis               270         Sleep(100);
genesis               271     }
genesis               272     return false;
genesis               273 }
genesis               274 
genesis               275 
genesis               276 void DBFlush(bool fShutdown)
genesis               277 {
genesis               278     
genesis               279     
genesis               280     printf("DBFlush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started");
genesis               281     if (!fDbEnvInit)
genesis               282         return;
genesis               283     CRITICAL_BLOCK(cs_db)
genesis               284     {
genesis               285         map<string, int>::iterator mi = mapFileUseCount.begin();
genesis               286         while (mi != mapFileUseCount.end())
genesis               287         {
genesis               288             string strFile = (*mi).first;
genesis               289             int nRefCount = (*mi).second;
genesis               290             printf("%s refcount=%d\n", strFile.c_str(), nRefCount);
genesis               291             if (nRefCount == 0)
genesis               292             {
genesis               293                 
genesis               294                 CloseDb(strFile);
genesis               295                 dbenv.txn_checkpoint(0, 0, 0);
genesis               296                 printf("%s flush\n", strFile.c_str());
genesis               297                 dbenv.lsn_reset(strFile.c_str(), 0);
genesis               298                 mapFileUseCount.erase(mi++);
genesis               299             }
genesis               300             else
genesis               301                 mi++;
genesis               302         }
genesis               303         if (fShutdown)
genesis               304         {
genesis               305             char** listp;
genesis               306             if (mapFileUseCount.empty())
genesis               307             {
genesis               308                 dbenv.log_archive(&listp, DB_ARCH_REMOVE);
genesis               309                 EnvShutdown();
genesis               310             }
genesis               311         }
genesis               312     }
genesis               313 }
genesis               314 
genesis               315 
genesis               316 
genesis               317 
genesis               318 
genesis               319 
genesis               320 
genesis               321 
genesis               322 
genesis               323 
genesis               324 bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex)
genesis               325 {
genesis               326     assert(!fClient);
genesis               327     txindex.SetNull();
genesis               328     return Read(make_pair(string("tx"), hash), txindex);
genesis               329 }
genesis               330 
genesis               331 bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex)
genesis               332 {
genesis               333     assert(!fClient);
genesis               334     return Write(make_pair(string("tx"), hash), txindex);
genesis               335 }
genesis               336 
genesis               337 bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight)
genesis               338 {
genesis               339     assert(!fClient);
genesis               340 
genesis               341     
genesis               342     uint256 hash = tx.GetHash();
genesis               343     CTxIndex txindex(pos, tx.vout.size());
genesis               344     return Write(make_pair(string("tx"), hash), txindex);
genesis               345 }
genesis               346 
genesis               347 bool CTxDB::EraseTxIndex(const CTransaction& tx)
genesis               348 {
genesis               349     assert(!fClient);
genesis               350     uint256 hash = tx.GetHash();
genesis               351 
genesis               352     return Erase(make_pair(string("tx"), hash));
genesis               353 }
genesis               354 
genesis               355 bool CTxDB::ContainsTx(uint256 hash)
genesis               356 {
genesis               357     assert(!fClient);
genesis               358     return Exists(make_pair(string("tx"), hash));
genesis               359 }
genesis               360 
genesis               361 bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector<CTransaction>& vtx)
genesis               362 {
genesis               363     assert(!fClient);
genesis               364     vtx.clear();
genesis               365 
genesis               366     
genesis               367     Dbc* pcursor = GetCursor();
genesis               368     if (!pcursor)
genesis               369         return false;
genesis               370 
genesis               371     unsigned int fFlags = DB_SET_RANGE;
genesis               372     loop
genesis               373     {
genesis               374         
genesis               375         CDataStream ssKey;
genesis               376         if (fFlags == DB_SET_RANGE)
genesis               377             ssKey << string("owner") << hash160 << CDiskTxPos(0, 0, 0);
genesis               378         CDataStream ssValue;
genesis               379         int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
genesis               380         fFlags = DB_NEXT;
genesis               381         if (ret == DB_NOTFOUND)
genesis               382             break;
genesis               383         else if (ret != 0)
genesis               384         {
genesis               385             pcursor->close();
genesis               386             return false;
genesis               387         }
genesis               388 
genesis               389         
genesis               390         string strType;
genesis               391         uint160 hashItem;
genesis               392         CDiskTxPos pos;
genesis               393         ssKey >> strType >> hashItem >> pos;
genesis               394         int nItemHeight;
genesis               395         ssValue >> nItemHeight;
genesis               396 
genesis               397         
genesis               398         if (strType != "owner" || hashItem != hash160)
genesis               399             break;
genesis               400         if (nItemHeight >= nMinHeight)
genesis               401         {
genesis               402             vtx.resize(vtx.size()+1);
genesis               403             if (!vtx.back().ReadFromDisk(pos))
genesis               404             {
genesis               405                 pcursor->close();
genesis               406                 return false;
genesis               407             }
genesis               408         }
genesis               409     }
genesis               410 
genesis               411     pcursor->close();
genesis               412     return true;
genesis               413 }
genesis               414 
genesis               415 bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex)
genesis               416 {
genesis               417     assert(!fClient);
genesis               418     tx.SetNull();
genesis               419     if (!ReadTxIndex(hash, txindex))
genesis               420         return false;
genesis               421     return (tx.ReadFromDisk(txindex.pos));
genesis               422 }
genesis               423 
genesis               424 bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx)
genesis               425 {
genesis               426     CTxIndex txindex;
genesis               427     return ReadDiskTx(hash, tx, txindex);
genesis               428 }
genesis               429 
genesis               430 bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex)
genesis               431 {
genesis               432     return ReadDiskTx(outpoint.hash, tx, txindex);
genesis               433 }
genesis               434 
genesis               435 bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx)
genesis               436 {
genesis               437     CTxIndex txindex;
genesis               438     return ReadDiskTx(outpoint.hash, tx, txindex);
genesis               439 }
genesis               440 
genesis               441 bool CTxDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
genesis               442 {
genesis               443     return Write(make_pair(string("blockindex"), blockindex.GetBlockHash()), blockindex);
genesis               444 }
genesis               445 
genesis               446 bool CTxDB::EraseBlockIndex(uint256 hash)
genesis               447 {
genesis               448     return Erase(make_pair(string("blockindex"), hash));
genesis               449 }
genesis               450 
genesis               451 bool CTxDB::ReadHashBestChain(uint256& hashBestChain)
genesis               452 {
genesis               453     return Read(string("hashBestChain"), hashBestChain);
genesis               454 }
genesis               455 
genesis               456 bool CTxDB::WriteHashBestChain(uint256 hashBestChain)
genesis               457 {
genesis               458     return Write(string("hashBestChain"), hashBestChain);
genesis               459 }
genesis               460 
genesis               461 bool CTxDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork)
genesis               462 {
genesis               463     return Read(string("bnBestInvalidWork"), bnBestInvalidWork);
genesis               464 }
genesis               465 
genesis               466 bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork)
genesis               467 {
genesis               468     return Write(string("bnBestInvalidWork"), bnBestInvalidWork);
genesis               469 }
genesis               470 
genesis               471 CBlockIndex static * InsertBlockIndex(uint256 hash)
genesis               472 {
genesis               473     if (hash == 0)
genesis               474         return NULL;
genesis               475 
genesis               476     
genesis               477     map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
genesis               478     if (mi != mapBlockIndex.end())
genesis               479         return (*mi).second;
genesis               480 
genesis               481     
genesis               482     CBlockIndex* pindexNew = new CBlockIndex();
genesis               483     if (!pindexNew)
genesis               484         throw runtime_error("LoadBlockIndex() : new CBlockIndex failed");
genesis               485     mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
genesis               486     pindexNew->phashBlock = &((*mi).first);
genesis               487 
genesis               488     return pindexNew;
genesis               489 }
genesis               490 
genesis               491 bool CTxDB::LoadBlockIndex()
genesis               492 {
genesis               493     
genesis               494     Dbc* pcursor = GetCursor();
genesis               495     if (!pcursor)
genesis               496         return false;
genesis               497 
genesis               498     
genesis               499     unsigned int fFlags = DB_SET_RANGE;
genesis               500     loop
genesis               501     {
genesis               502         
genesis               503         CDataStream ssKey;
genesis               504         if (fFlags == DB_SET_RANGE)
genesis               505             ssKey << make_pair(string("blockindex"), uint256(0));
genesis               506         CDataStream ssValue;
genesis               507         int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
genesis               508         fFlags = DB_NEXT;
genesis               509         if (ret == DB_NOTFOUND)
genesis               510             break;
genesis               511         else if (ret != 0)
genesis               512             return false;
genesis               513 
genesis               514         
genesis               515         string strType;
genesis               516         ssKey >> strType;
genesis               517         if (strType == "blockindex")
genesis               518         {
genesis               519             CDiskBlockIndex diskindex;
genesis               520             ssValue >> diskindex;
genesis               521 
genesis               522             
genesis               523             CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
genesis               524             pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
genesis               525             pindexNew->pnext          = InsertBlockIndex(diskindex.hashNext);
genesis               526             pindexNew->nFile          = diskindex.nFile;
genesis               527             pindexNew->nBlockPos      = diskindex.nBlockPos;
genesis               528             pindexNew->nHeight        = diskindex.nHeight;
genesis               529             pindexNew->nVersion       = diskindex.nVersion;
genesis               530             pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
genesis               531             pindexNew->nTime          = diskindex.nTime;
genesis               532             pindexNew->nBits          = diskindex.nBits;
genesis               533             pindexNew->nNonce         = diskindex.nNonce;
genesis               534 
genesis               535             
genesis               536             if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)
genesis               537                 pindexGenesisBlock = pindexNew;
genesis               538 
genesis               539             if (!pindexNew->CheckIndex())
genesis               540                 return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
genesis               541         }
genesis               542         else
genesis               543         {
genesis               544             break;
genesis               545         }
genesis               546     }
genesis               547     pcursor->close();
genesis               548 
genesis               549     
genesis               550     vector<pair<int, CBlockIndex*> > vSortedByHeight;
genesis               551     vSortedByHeight.reserve(mapBlockIndex.size());
genesis               552     BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
genesis               553     {
genesis               554         CBlockIndex* pindex = item.second;
genesis               555         vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));
genesis               556     }
genesis               557     sort(vSortedByHeight.begin(), vSortedByHeight.end());
genesis               558     BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)
genesis               559     {
genesis               560         CBlockIndex* pindex = item.second;
genesis               561         pindex->bnChainWork = (pindex->pprev ? pindex->pprev->bnChainWork : 0) + pindex->GetBlockWork();
genesis               562     }
genesis               563 
genesis               564     
genesis               565     if (!ReadHashBestChain(hashBestChain))
genesis               566     {
genesis               567         if (pindexGenesisBlock == NULL)
genesis               568             return true;
genesis               569         return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
genesis               570     }
genesis               571     if (!mapBlockIndex.count(hashBestChain))
genesis               572         return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index");
genesis               573     pindexBest = mapBlockIndex[hashBestChain];
genesis               574     nBestHeight = pindexBest->nHeight;
genesis               575     bnBestChainWork = pindexBest->bnChainWork;
genesis               576     printf("LoadBlockIndex(): hashBestChain=%s  height=%d\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight);
genesis               577 
genesis               578     
genesis               579     ReadBestInvalidWork(bnBestInvalidWork);
genesis               580 
genesis               581     
genesis               582     CBlockIndex* pindexFork = NULL;
genesis               583     for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
genesis               584     {
genesis               585         if (pindex->nHeight < nBestHeight-2500 && !mapArgs.count("-checkblocks"))
genesis               586             break;
genesis               587         CBlock block;
genesis               588         if (!block.ReadFromDisk(pindex))
genesis               589             return error("LoadBlockIndex() : block.ReadFromDisk failed");
genesis               590         if (!block.CheckBlock())
genesis               591         {
genesis               592             printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
genesis               593             pindexFork = pindex->pprev;
genesis               594         }
genesis               595     }
genesis               596     if (pindexFork)
genesis               597     {
genesis               598         
genesis               599         printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight);
genesis               600         CBlock block;
genesis               601         if (!block.ReadFromDisk(pindexFork))
genesis               602             return error("LoadBlockIndex() : block.ReadFromDisk failed");
genesis               603         CTxDB txdb;
genesis               604         block.SetBestChain(txdb, pindexFork);
genesis               605     }
genesis               606 
genesis               607     return true;
genesis               608 }
genesis               609 
genesis               610 
genesis               611 
genesis               612 
genesis               613 
genesis               614 
genesis               615 
genesis               616 
genesis               617 
genesis               618 bool CAddrDB::WriteAddress(const CAddress& addr)
genesis               619 {
genesis               620     return Write(make_pair(string("addr"), addr.GetKey()), addr);
genesis               621 }
genesis               622 
genesis               623 bool CAddrDB::EraseAddress(const CAddress& addr)
genesis               624 {
genesis               625     return Erase(make_pair(string("addr"), addr.GetKey()));
genesis               626 }
genesis               627 
genesis               628 bool CAddrDB::LoadAddresses()
genesis               629 {
genesis               630     CRITICAL_BLOCK(cs_mapAddresses)
genesis               631     {
genesis               632         
genesis               633         Dbc* pcursor = GetCursor();
genesis               634         if (!pcursor)
genesis               635             return false;
genesis               636 
genesis               637         loop
genesis               638         {
genesis               639             
genesis               640             CDataStream ssKey;
genesis               641             CDataStream ssValue;
genesis               642             int ret = ReadAtCursor(pcursor, ssKey, ssValue);
genesis               643             if (ret == DB_NOTFOUND)
genesis               644                 break;
genesis               645             else if (ret != 0)
genesis               646                 return false;
genesis               647 
genesis               648             
genesis               649             string strType;
genesis               650             ssKey >> strType;
genesis               651             if (strType == "addr")
genesis               652             {
genesis               653                 CAddress addr;
genesis               654                 ssValue >> addr;
genesis               655                 mapAddresses.insert(make_pair(addr.GetKey(), addr));
genesis               656             }
genesis               657         }
genesis               658         pcursor->close();
genesis               659 
genesis               660         printf("Loaded %d addresses\n", mapAddresses.size());
genesis               661     }
genesis               662 
genesis               663     return true;
genesis               664 }
genesis               665 
genesis               666 bool LoadAddresses()
genesis               667 {
genesis               668     return CAddrDB("cr+").LoadAddresses();
genesis               669 }
genesis               670 
genesis               671 
genesis               672 
genesis               673 
genesis               674 
genesis               675 
genesis               676 
genesis               677 
genesis               678 bool CWalletDB::WriteName(const string& strAddress, const string& strName)
genesis               679 {
genesis               680     nWalletDBUpdated++;
genesis               681     return Write(make_pair(string("name"), strAddress), strName);
genesis               682 }
genesis               683 
genesis               684 bool CWalletDB::EraseName(const string& strAddress)
genesis               685 {
genesis               686     
genesis               687     
genesis               688     nWalletDBUpdated++;
genesis               689     return Erase(make_pair(string("name"), strAddress));
genesis               690 }
genesis               691 
genesis               692 bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account)
genesis               693 {
genesis               694     account.SetNull();
genesis               695     return Read(make_pair(string("acc"), strAccount), account);
genesis               696 }
genesis               697 
genesis               698 bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
genesis               699 {
genesis               700     return Write(make_pair(string("acc"), strAccount), account);
genesis               701 }
genesis               702 
genesis               703 bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
genesis               704 {
genesis               705     return Write(boost::make_tuple(string("acentry"), acentry.strAccount, ++nAccountingEntryNumber), acentry);
genesis               706 }
genesis               707 
genesis               708 int64 CWalletDB::GetAccountCreditDebit(const string& strAccount)
genesis               709 {
genesis               710     list<CAccountingEntry> entries;
genesis               711     ListAccountCreditDebit(strAccount, entries);
genesis               712 
genesis               713     int64 nCreditDebit = 0;
genesis               714     BOOST_FOREACH (const CAccountingEntry& entry, entries)
genesis               715         nCreditDebit += entry.nCreditDebit;
genesis               716 
genesis               717     return nCreditDebit;
genesis               718 }
genesis               719 
genesis               720 void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
genesis               721 {
genesis               722     bool fAllAccounts = (strAccount == "*");
genesis               723 
genesis               724     Dbc* pcursor = GetCursor();
genesis               725     if (!pcursor)
genesis               726         throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor");
genesis               727     unsigned int fFlags = DB_SET_RANGE;
genesis               728     loop
genesis               729     {
genesis               730         
genesis               731         CDataStream ssKey;
genesis               732         if (fFlags == DB_SET_RANGE)
genesis               733             ssKey << boost::make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64(0));
genesis               734         CDataStream ssValue;
genesis               735         int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
genesis               736         fFlags = DB_NEXT;
genesis               737         if (ret == DB_NOTFOUND)
genesis               738             break;
genesis               739         else if (ret != 0)
genesis               740         {
genesis               741             pcursor->close();
genesis               742             throw runtime_error("CWalletDB::ListAccountCreditDebit() : error scanning DB");
genesis               743         }
genesis               744 
genesis               745         
genesis               746         string strType;
genesis               747         ssKey >> strType;
genesis               748         if (strType != "acentry")
genesis               749             break;
genesis               750         CAccountingEntry acentry;
genesis               751         ssKey >> acentry.strAccount;
genesis               752         if (!fAllAccounts && acentry.strAccount != strAccount)
genesis               753             break;
genesis               754 
genesis               755         ssValue >> acentry;
genesis               756         entries.push_back(acentry);
genesis               757     }
genesis               758 
genesis               759     pcursor->close();
genesis               760 }
genesis               761 
genesis               762 
genesis               763 int CWalletDB::LoadWallet(CWallet* pwallet)
genesis               764 {
genesis               765     pwallet->vchDefaultKey.clear();
genesis               766     int nFileVersion = 0;
genesis               767     vector<uint256> vWalletUpgrade;
genesis               768     bool fIsEncrypted = false;
genesis               769 
genesis               770     
genesis               771 #ifndef WIN32
genesis               772     
genesis               773     fMinimizeToTray = false;
genesis               774     fMinimizeOnClose = false;
genesis               775 #endif
genesis               776 
genesis               777     
genesis               778     CRITICAL_BLOCK(pwallet->cs_wallet)
genesis               779     {
genesis               780         
genesis               781         Dbc* pcursor = GetCursor();
genesis               782         if (!pcursor)
genesis               783             return DB_CORRUPT;
genesis               784 
genesis               785         loop
genesis               786         {
genesis               787             
genesis               788             CDataStream ssKey;
genesis               789             CDataStream ssValue;
genesis               790             int ret = ReadAtCursor(pcursor, ssKey, ssValue);
genesis               791             if (ret == DB_NOTFOUND)
genesis               792                 break;
genesis               793             else if (ret != 0)
genesis               794                 return DB_CORRUPT;
genesis               795 
genesis               796             
genesis               797             
genesis               798             
genesis               799             string strType;
genesis               800             ssKey >> strType;
genesis               801             if (strType == "name")
genesis               802             {
genesis               803                 string strAddress;
genesis               804                 ssKey >> strAddress;
genesis               805                 ssValue >> pwallet->mapAddressBook[strAddress];
genesis               806             }
genesis               807             else if (strType == "tx")
genesis               808             {
genesis               809                 uint256 hash;
genesis               810                 ssKey >> hash;
genesis               811                 CWalletTx& wtx = pwallet->mapWallet[hash];
genesis               812                 ssValue >> wtx;
genesis               813                 wtx.pwallet = pwallet;
genesis               814 
genesis               815                 if (wtx.GetHash() != hash)
genesis               816                     printf("Error in wallet.dat, hash mismatch\n");
genesis               817 
genesis               818                 
genesis               819                 if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
genesis               820                 {
genesis               821                     if (!ssValue.empty())
genesis               822                     {
genesis               823                         char fTmp;
genesis               824                         char fUnused;
genesis               825                         ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
genesis               826                         printf("LoadWallet() upgrading tx ver=%d %d '%s' %s\n", wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount.c_str(), hash.ToString().c_str());
genesis               827                         wtx.fTimeReceivedIsTxTime = fTmp;
genesis               828                     }
genesis               829                     else
genesis               830                     {
genesis               831                         printf("LoadWallet() repairing tx ver=%d %s\n", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str());
genesis               832                         wtx.fTimeReceivedIsTxTime = 0;
genesis               833                     }
genesis               834                     vWalletUpgrade.push_back(hash);
genesis               835                 }
genesis               836 
genesis               837                 
genesis               838                 
genesis               839                 
genesis               840                 
genesis               841                 
genesis               842                 
genesis               843                 
genesis               844             }
genesis               845             else if (strType == "acentry")
genesis               846             {
genesis               847                 string strAccount;
genesis               848                 ssKey >> strAccount;
genesis               849                 uint64 nNumber;
genesis               850                 ssKey >> nNumber;
genesis               851                 if (nNumber > nAccountingEntryNumber)
genesis               852                     nAccountingEntryNumber = nNumber;
genesis               853             }
genesis               854             else if (strType == "key" || strType == "wkey")
genesis               855             {
genesis               856                 vector<unsigned char> vchPubKey;
genesis               857                 ssKey >> vchPubKey;
genesis               858                 CKey key;
genesis               859                 if (strType == "key")
genesis               860                 {
genesis               861                     CPrivKey pkey;
genesis               862                     ssValue >> pkey;
genesis               863                     key.SetPrivKey(pkey);
genesis               864                     if (key.GetPubKey() != vchPubKey || !key.IsValid())
genesis               865                         return DB_CORRUPT;
genesis               866                 }
genesis               867                 else
genesis               868                 {
genesis               869                     CWalletKey wkey;
genesis               870                     ssValue >> wkey;
genesis               871                     key.SetPrivKey(wkey.vchPrivKey);
genesis               872                     if (key.GetPubKey() != vchPubKey || !key.IsValid())
genesis               873                         return DB_CORRUPT;
genesis               874                 }
genesis               875                 if (!pwallet->LoadKey(key))
genesis               876                     return DB_CORRUPT;
genesis               877             }
genesis               878             else if (strType == "mkey")
genesis               879             {
genesis               880                 unsigned int nID;
genesis               881                 ssKey >> nID;
genesis               882                 CMasterKey kMasterKey;
genesis               883                 ssValue >> kMasterKey;
genesis               884                 if(pwallet->mapMasterKeys.count(nID) != 0)
genesis               885                     return DB_CORRUPT;
genesis               886                 pwallet->mapMasterKeys[nID] = kMasterKey;
genesis               887                 if (pwallet->nMasterKeyMaxID < nID)
genesis               888                     pwallet->nMasterKeyMaxID = nID;
genesis               889             }
genesis               890             else if (strType == "ckey")
genesis               891             {
genesis               892                 vector<unsigned char> vchPubKey;
genesis               893                 ssKey >> vchPubKey;
genesis               894                 vector<unsigned char> vchPrivKey;
genesis               895                 ssValue >> vchPrivKey;
genesis               896                 if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
genesis               897                     return DB_CORRUPT;
genesis               898                 fIsEncrypted = true;
genesis               899             }
genesis               900             else if (strType == "defaultkey")
genesis               901             {
genesis               902                 ssValue >> pwallet->vchDefaultKey;
genesis               903             }
genesis               904             else if (strType == "pool")
genesis               905             {
genesis               906                 int64 nIndex;
genesis               907                 ssKey >> nIndex;
genesis               908                 pwallet->setKeyPool.insert(nIndex);
genesis               909             }
genesis               910             else if (strType == "version")
genesis               911             {
genesis               912                 ssValue >> nFileVersion;
genesis               913                 if (nFileVersion == 10300)
genesis               914                     nFileVersion = 300;
genesis               915             }
genesis               916             else if (strType == "setting")
genesis               917             {
genesis               918                 string strKey;
genesis               919                 ssKey >> strKey;
genesis               920 
genesis               921                 
genesis               922 #ifndef QT_GUI
genesis               923                 if (strKey == "fGenerateBitcoins")  ssValue >> fGenerateBitcoins;
genesis               924 #endif
genesis               925                 if (strKey == "nTransactionFee")    ssValue >> nTransactionFee;
genesis               926                 if (strKey == "fLimitProcessors")   ssValue >> fLimitProcessors;
genesis               927                 if (strKey == "nLimitProcessors")   ssValue >> nLimitProcessors;
genesis               928                 if (strKey == "fMinimizeToTray")    ssValue >> fMinimizeToTray;
genesis               929                 if (strKey == "fMinimizeOnClose")   ssValue >> fMinimizeOnClose;
genesis               930                 if (strKey == "fUseProxy")          ssValue >> fUseProxy;
genesis               931                 if (strKey == "addrProxy")          ssValue >> addrProxy;
genesis               932                 if (fHaveUPnP && strKey == "fUseUPnP")           ssValue >> fUseUPnP;
genesis               933             }
genesis               934             else if (strType == "minversion")
genesis               935             {
genesis               936                 int nMinVersion = 0;
genesis               937                 ssValue >> nMinVersion;
genesis               938                 if (nMinVersion > VERSION)
genesis               939                     return DB_TOO_NEW;
genesis               940             }
genesis               941         }
genesis               942         pcursor->close();
genesis               943     }
genesis               944 
genesis               945     BOOST_FOREACH(uint256 hash, vWalletUpgrade)
genesis               946         WriteTx(hash, pwallet->mapWallet[hash]);
genesis               947 
genesis               948     printf("nFileVersion = %d\n", nFileVersion);
genesis               949     printf("fGenerateBitcoins = %d\n", fGenerateBitcoins);
genesis               950     printf("nTransactionFee = %"PRI64d"\n", nTransactionFee);
genesis               951     printf("fMinimizeToTray = %d\n", fMinimizeToTray);
genesis               952     printf("fMinimizeOnClose = %d\n", fMinimizeOnClose);
genesis               953     printf("fUseProxy = %d\n", fUseProxy);
genesis               954     printf("addrProxy = %s\n", addrProxy.ToString().c_str());
genesis               955     if (fHaveUPnP)
genesis               956         printf("fUseUPnP = %d\n", fUseUPnP);
genesis               957 
genesis               958 
genesis               959     
genesis               960     if (fIsEncrypted && (nFileVersion == 40000 || nFileVersion == 50000))
genesis               961         return DB_NEED_REWRITE;
genesis               962 
genesis               963     if (nFileVersion < VERSION) 
genesis               964     {
genesis               965         
genesis               966         if (nFileVersion <= 105 && !pszSetDataDir[0])
genesis               967             unlink("debug.log");
genesis               968 
genesis               969         WriteVersion(VERSION);
genesis               970     }
genesis               971 
genesis               972     return DB_LOAD_OK;
genesis               973 }
genesis               974 
genesis               975 void ThreadFlushWalletDB(void* parg)
genesis               976 {
genesis               977     const string& strFile = ((const string*)parg)[0];
genesis               978     static bool fOneThread;
genesis               979     if (fOneThread)
genesis               980         return;
genesis               981     fOneThread = true;
genesis               982     if (mapArgs.count("-noflushwallet"))
genesis               983         return;
genesis               984 
genesis               985     unsigned int nLastSeen = nWalletDBUpdated;
genesis               986     unsigned int nLastFlushed = nWalletDBUpdated;
genesis               987     int64 nLastWalletUpdate = GetTime();
genesis               988     while (!fShutdown)
genesis               989     {
genesis               990         Sleep(500);
genesis               991 
genesis               992         if (nLastSeen != nWalletDBUpdated)
genesis               993         {
genesis               994             nLastSeen = nWalletDBUpdated;
genesis               995             nLastWalletUpdate = GetTime();
genesis               996         }
genesis               997 
genesis               998         if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2)
genesis               999         {
genesis              1000             TRY_CRITICAL_BLOCK(cs_db)
genesis              1001             {
genesis              1002                 
genesis              1003                 int nRefCount = 0;
genesis              1004                 map<string, int>::iterator mi = mapFileUseCount.begin();
genesis              1005                 while (mi != mapFileUseCount.end())
genesis              1006                 {
genesis              1007                     nRefCount += (*mi).second;
genesis              1008                     mi++;
genesis              1009                 }
genesis              1010 
genesis              1011                 if (nRefCount == 0 && !fShutdown)
genesis              1012                 {
genesis              1013                     map<string, int>::iterator mi = mapFileUseCount.find(strFile);
genesis              1014                     if (mi != mapFileUseCount.end())
genesis              1015                     {
genesis              1016                         printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
genesis              1017                         printf("Flushing wallet.dat\n");
genesis              1018                         nLastFlushed = nWalletDBUpdated;
genesis              1019                         int64 nStart = GetTimeMillis();
genesis              1020 
genesis              1021                         
genesis              1022                         CloseDb(strFile);
genesis              1023                         dbenv.txn_checkpoint(0, 0, 0);
genesis              1024                         dbenv.lsn_reset(strFile.c_str(), 0);
genesis              1025 
genesis              1026                         mapFileUseCount.erase(mi++);
genesis              1027                         printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart);
genesis              1028                     }
genesis              1029                 }
genesis              1030             }
genesis              1031         }
genesis              1032     }
genesis              1033 }
genesis              1034 
genesis              1035 bool BackupWallet(const CWallet& wallet, const string& strDest)
genesis              1036 {
genesis              1037     if (!wallet.fFileBacked)
genesis              1038         return false;
genesis              1039     while (!fShutdown)
genesis              1040     {
genesis              1041         CRITICAL_BLOCK(cs_db)
genesis              1042         {
genesis              1043             if (!mapFileUseCount.count(wallet.strWalletFile) || mapFileUseCount[wallet.strWalletFile] == 0)
genesis              1044             {
genesis              1045                 
genesis              1046                 CloseDb(wallet.strWalletFile);
genesis              1047                 dbenv.txn_checkpoint(0, 0, 0);
genesis              1048                 dbenv.lsn_reset(wallet.strWalletFile.c_str(), 0);
genesis              1049                 mapFileUseCount.erase(wallet.strWalletFile);
genesis              1050 
genesis              1051                 
genesis              1052                 filesystem::path pathSrc(GetDataDir() + "/" + wallet.strWalletFile);
genesis              1053                 filesystem::path pathDest(strDest);
genesis              1054                 if (filesystem::is_directory(pathDest))
genesis              1055                     pathDest = pathDest / wallet.strWalletFile;
genesis              1056 #if BOOST_VERSION >= 104000
genesis              1057                 filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
genesis              1058 #else
genesis              1059                 filesystem::copy_file(pathSrc, pathDest);
genesis              1060 #endif
genesis              1061                 printf("copied wallet.dat to %s\n", pathDest.string().c_str());
genesis              1062 
genesis              1063                 return true;
genesis              1064             }
genesis              1065         }
genesis              1066         Sleep(100);
genesis              1067     }
genesis              1068     return false;
genesis              1069 }