-
+ 470D1A940F0BBB26B40B7A30562BF5F7B929ACA78162358C65BC4EED8FE5E7B91DD1660058B7864E1B76E7B7E62A623661FA15F79373DA7F6BBC1A7D4D0DB2B2bitcoin/src/db.cpp(0 . 0)(1 . 1100)
 4158 //  /****************************\
 4159 // *      EXPERIMENTAL BRANCH.    *
 4160 // *    FOR LABORATORY USE ONLY.  *
 4161 // ********************************
 4162 //           ************
 4163 //          **************
 4164 //         ****************
 4165 //        ****   ****   ****
 4166 //        ***     ***    ***
 4167 //        ***     ***    ***
 4168 //         ***    * *    **
 4169 //         ******** ********
 4170 //         *******   ******
 4171 //             ***   **
 4172 //           *  ******* **
 4173 //           ** * * * * *
 4174 //     **     *         *     ***
 4175 //    ****    * *     * *    ****
 4176 //    ****    *** * * **     ***
 4177 //     ****    *********   ******
 4178 //    *******    *****    *******
 4179 //    *********        ****** **
 4180 //     **   ******   ******
 4181 //            **  *******       **
 4182 //    **       *******         ***
 4183 //   ****   ********  ************
 4184 //   ************    ************
 4185 //    ********             *******
 4186 //   ******                   ****
 4187 //    ***                      ***
 4188 // ********************************
 4189 // Copyright (c) 2009-2010 Satoshi Nakamoto
 4190 // Copyright (c) 2009-2012 The Bitcoin developers
 4191 // Distributed under the MIT/X11 software license, see the accompanying
 4192 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
 4193 
 4194 #include "headers.h"
 4195 #include "db.h"
 4196 #include "net.h"
 4197 #include <boost/filesystem.hpp>
 4198 #include <boost/filesystem/fstream.hpp>
 4199 
 4200 using namespace std;
 4201 using namespace boost;
 4202 
 4203 
 4204 unsigned int nWalletDBUpdated;
 4205 uint64 nAccountingEntryNumber = 0;
 4206 
 4207 
 4208 
 4209 //
 4210 // CDB
 4211 //
 4212 
 4213 static CCriticalSection cs_db;
 4214 static bool fDbEnvInit = false;
 4215 DbEnv dbenv(0);
 4216 static map<string, int> mapFileUseCount;
 4217 static map<string, Db*> mapDb;
 4218 
 4219 static void EnvShutdown()
 4220 {
 4221     if (!fDbEnvInit)
 4222         return;
 4223 
 4224     fDbEnvInit = false;
 4225     try
 4226     {
 4227         dbenv.close(0);
 4228     }
 4229     catch (const DbException& e)
 4230     {
 4231         printf("EnvShutdown exception: %s (%d)\n", e.what(), e.get_errno());
 4232     }
 4233     DbEnv(0).remove(GetDataDir().c_str(), 0);
 4234 }
 4235 
 4236 class CDBInit
 4237 {
 4238 public:
 4239     CDBInit()
 4240     {
 4241     }
 4242     ~CDBInit()
 4243     {
 4244         EnvShutdown();
 4245     }
 4246 }
 4247 instance_of_cdbinit;
 4248 
 4249 
 4250 CDB::CDB(const char* pszFile, const char* pszMode) : pdb(NULL)
 4251 {
 4252     int ret;
 4253     if (pszFile == NULL)
 4254         return;
 4255 
 4256     fReadOnly = (!strchr(pszMode, '+') && !strchr(pszMode, 'w'));
 4257     bool fCreate = strchr(pszMode, 'c');
 4258     unsigned int nFlags = DB_THREAD;
 4259     if (fCreate)
 4260         nFlags |= DB_CREATE;
 4261 
 4262     CRITICAL_BLOCK(cs_db)
 4263     {
 4264         if (!fDbEnvInit)
 4265         {
 4266             if (fShutdown)
 4267                 return;
 4268             string strDataDir = GetDataDir();
 4269             string strLogDir = strDataDir + "/database";
 4270             filesystem::create_directory(strLogDir.c_str());
 4271             string strErrorFile = strDataDir + "/db.log";
 4272             printf("dbenv.open strLogDir=%s strErrorFile=%s\n", strLogDir.c_str(), strErrorFile.c_str());
 4273 
 4274             dbenv.set_lg_dir(strLogDir.c_str());
 4275             dbenv.set_lg_max(10000000);
 4276             dbenv.set_lk_max_locks(10000);
 4277             dbenv.set_lk_max_objects(10000);
 4278             dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); /// debug
 4279             dbenv.set_flags(DB_AUTO_COMMIT, 1);
 4280             ret = dbenv.open(strDataDir.c_str(),
 4281                              DB_CREATE     |
 4282                              DB_INIT_LOCK  |
 4283                              DB_INIT_LOG   |
 4284                              DB_INIT_MPOOL |
 4285                              DB_INIT_TXN   |
 4286                              DB_THREAD     |
 4287                              DB_RECOVER,
 4288                              S_IRUSR | S_IWUSR);
 4289             if (ret > 0)
 4290                 throw runtime_error(strprintf("CDB() : error %d opening database environment", ret));
 4291             fDbEnvInit = true;
 4292         }
 4293 
 4294         strFile = pszFile;
 4295         ++mapFileUseCount[strFile];
 4296         pdb = mapDb[strFile];
 4297         if (pdb == NULL)
 4298         {
 4299             pdb = new Db(&dbenv, 0);
 4300 
 4301             ret = pdb->open(NULL,      // Txn pointer
 4302                             pszFile,   // Filename
 4303                             "main",    // Logical db name
 4304                             DB_BTREE,  // Database type
 4305                             nFlags,    // Flags
 4306                             0);
 4307 
 4308             if (ret > 0)
 4309             {
 4310                 delete pdb;
 4311                 pdb = NULL;
 4312                 CRITICAL_BLOCK(cs_db)
 4313                     --mapFileUseCount[strFile];
 4314                 strFile = "";
 4315                 throw runtime_error(strprintf("CDB() : can't open database file %s, error %d", pszFile, ret));
 4316             }
 4317 
 4318             if (fCreate && !Exists(string("version")))
 4319             {
 4320                 bool fTmp = fReadOnly;
 4321                 fReadOnly = false;
 4322                 WriteVersion(VERSION);
 4323                 fReadOnly = fTmp;
 4324             }
 4325 
 4326             mapDb[strFile] = pdb;
 4327         }
 4328     }
 4329 }
 4330 
 4331 void CDB::Close()
 4332 {
 4333     if (!pdb)
 4334         return;
 4335     if (!vTxn.empty())
 4336         vTxn.front()->abort();
 4337     vTxn.clear();
 4338     pdb = NULL;
 4339 
 4340     // Flush database activity from memory pool to disk log
 4341     unsigned int nMinutes = 0;
 4342     if (fReadOnly)
 4343         nMinutes = 1;
 4344     if (strFile == "addr.dat")
 4345         nMinutes = 2;
 4346     if (strFile == "blkindex.dat" && IsInitialBlockDownload() && nBestHeight % 500 != 0)
 4347         nMinutes = 1;
 4348     dbenv.txn_checkpoint(0, nMinutes, 0);
 4349 
 4350     CRITICAL_BLOCK(cs_db)
 4351         --mapFileUseCount[strFile];
 4352 }
 4353 
 4354 void static CloseDb(const string& strFile)
 4355 {
 4356     CRITICAL_BLOCK(cs_db)
 4357     {
 4358         if (mapDb[strFile] != NULL)
 4359         {
 4360             // Close the database handle
 4361             Db* pdb = mapDb[strFile];
 4362             pdb->close(0);
 4363             delete pdb;
 4364             mapDb[strFile] = NULL;
 4365         }
 4366     }
 4367 }
 4368 
 4369 bool CDB::Rewrite(const string& strFile, const char* pszSkip)
 4370 {
 4371     while (!fShutdown)
 4372     {
 4373         CRITICAL_BLOCK(cs_db)
 4374         {
 4375             if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0)
 4376             {
 4377                 // Flush log data to the dat file
 4378                 CloseDb(strFile);
 4379                 dbenv.txn_checkpoint(0, 0, 0);
 4380                 dbenv.lsn_reset(strFile.c_str(), 0);
 4381                 mapFileUseCount.erase(strFile);
 4382 
 4383                 bool fSuccess = true;
 4384                 printf("Rewriting %s...\n", strFile.c_str());
 4385                 string strFileRes = strFile + ".rewrite";
 4386                 { // surround usage of db with extra {}
 4387                     CDB db(strFile.c_str(), "r");
 4388                     Db* pdbCopy = new Db(&dbenv, 0);
 4389     
 4390                     int ret = pdbCopy->open(NULL,                 // Txn pointer
 4391                                             strFileRes.c_str(),   // Filename
 4392                                             "main",    // Logical db name
 4393                                             DB_BTREE,  // Database type
 4394                                             DB_CREATE,    // Flags
 4395                                             0);
 4396                     if (ret > 0)
 4397                     {
 4398                         printf("Cannot create database file %s\n", strFileRes.c_str());
 4399                         fSuccess = false;
 4400                     }
 4401     
 4402                     Dbc* pcursor = db.GetCursor();
 4403                     if (pcursor)
 4404                         while (fSuccess)
 4405                         {
 4406                             CDataStream ssKey;
 4407                             CDataStream ssValue;
 4408                             int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT);
 4409                             if (ret == DB_NOTFOUND)
 4410                             {
 4411                                 pcursor->close();
 4412                                 break;
 4413                             }
 4414                             else if (ret != 0)
 4415                             {
 4416                                 pcursor->close();
 4417                                 fSuccess = false;
 4418                                 break;
 4419                             }
 4420                             if (pszSkip &&
 4421                                 strncmp(&ssKey[0], pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0)
 4422                                 continue;
 4423                             if (strncmp(&ssKey[0], "\x07version", 8) == 0)
 4424                             {
 4425                                 // Update version:
 4426                                 ssValue.clear();
 4427                                 ssValue << VERSION;
 4428                             }
 4429                             Dbt datKey(&ssKey[0], ssKey.size());
 4430                             Dbt datValue(&ssValue[0], ssValue.size());
 4431                             int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE);
 4432                             if (ret2 > 0)
 4433                                 fSuccess = false;
 4434                         }
 4435                     if (fSuccess)
 4436                     {
 4437                         db.Close();
 4438                         CloseDb(strFile);
 4439                         if (pdbCopy->close(0))
 4440                             fSuccess = false;
 4441                         delete pdbCopy;
 4442                     }
 4443                 }
 4444                 if (fSuccess)
 4445                 {
 4446                     Db dbA(&dbenv, 0);
 4447                     if (dbA.remove(strFile.c_str(), NULL, 0))
 4448                         fSuccess = false;
 4449                     Db dbB(&dbenv, 0);
 4450                     if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0))
 4451                         fSuccess = false;
 4452                 }
 4453                 if (!fSuccess)
 4454                     printf("Rewriting of %s FAILED!\n", strFileRes.c_str());
 4455                 return fSuccess;
 4456             }
 4457         }
 4458         Sleep(100);
 4459     }
 4460     return false;
 4461 }
 4462 
 4463 
 4464 void DBFlush(bool fShutdown)
 4465 {
 4466     // Flush log data to the actual data file
 4467     //  on all files that are not in use
 4468     printf("DBFlush(%s)%s\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started");
 4469     if (!fDbEnvInit)
 4470         return;
 4471     CRITICAL_BLOCK(cs_db)
 4472     {
 4473         map<string, int>::iterator mi = mapFileUseCount.begin();
 4474         while (mi != mapFileUseCount.end())
 4475         {
 4476             string strFile = (*mi).first;
 4477             int nRefCount = (*mi).second;
 4478             printf("%s refcount=%d\n", strFile.c_str(), nRefCount);
 4479             if (nRefCount == 0)
 4480             {
 4481                 // Move log data to the dat file
 4482                 CloseDb(strFile);
 4483                 dbenv.txn_checkpoint(0, 0, 0);
 4484                 printf("%s flush\n", strFile.c_str());
 4485                 dbenv.lsn_reset(strFile.c_str(), 0);
 4486                 mapFileUseCount.erase(mi++);
 4487             }
 4488             else
 4489                 mi++;
 4490         }
 4491         if (fShutdown)
 4492         {
 4493             char** listp;
 4494             if (mapFileUseCount.empty())
 4495             {
 4496                 dbenv.log_archive(&listp, DB_ARCH_REMOVE);
 4497                 EnvShutdown();
 4498             }
 4499         }
 4500     }
 4501 }
 4502 
 4503 
 4504 
 4505 
 4506 
 4507 
 4508 //
 4509 // CTxDB
 4510 //
 4511 
 4512 bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex)
 4513 {
 4514     assert(!fClient);
 4515     txindex.SetNull();
 4516     return Read(make_pair(string("tx"), hash), txindex);
 4517 }
 4518 
 4519 bool CTxDB::UpdateTxIndex(uint256 hash, const CTxIndex& txindex)
 4520 {
 4521     assert(!fClient);
 4522     return Write(make_pair(string("tx"), hash), txindex);
 4523 }
 4524 
 4525 bool CTxDB::AddTxIndex(const CTransaction& tx, const CDiskTxPos& pos, int nHeight)
 4526 {
 4527     assert(!fClient);
 4528 
 4529     // Add to tx index
 4530     uint256 hash = tx.GetHash();
 4531     CTxIndex txindex(pos, tx.vout.size());
 4532     return Write(make_pair(string("tx"), hash), txindex);
 4533 }
 4534 
 4535 bool CTxDB::EraseTxIndex(const CTransaction& tx)
 4536 {
 4537     assert(!fClient);
 4538     uint256 hash = tx.GetHash();
 4539 
 4540     return Erase(make_pair(string("tx"), hash));
 4541 }
 4542 
 4543 bool CTxDB::ContainsTx(uint256 hash)
 4544 {
 4545     assert(!fClient);
 4546     return Exists(make_pair(string("tx"), hash));
 4547 }
 4548 
 4549 bool CTxDB::ReadOwnerTxes(uint160 hash160, int nMinHeight, vector<CTransaction>& vtx)
 4550 {
 4551     assert(!fClient);
 4552     vtx.clear();
 4553 
 4554     // Get cursor
 4555     Dbc* pcursor = GetCursor();
 4556     if (!pcursor)
 4557         return false;
 4558 
 4559     unsigned int fFlags = DB_SET_RANGE;
 4560     loop
 4561     {
 4562         // Read next record
 4563         CDataStream ssKey;
 4564         if (fFlags == DB_SET_RANGE)
 4565             ssKey << string("owner") << hash160 << CDiskTxPos(0, 0, 0);
 4566         CDataStream ssValue;
 4567         int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
 4568         fFlags = DB_NEXT;
 4569         if (ret == DB_NOTFOUND)
 4570             break;
 4571         else if (ret != 0)
 4572         {
 4573             pcursor->close();
 4574             return false;
 4575         }
 4576 
 4577         // Unserialize
 4578         string strType;
 4579         uint160 hashItem;
 4580         CDiskTxPos pos;
 4581         ssKey >> strType >> hashItem >> pos;
 4582         int nItemHeight;
 4583         ssValue >> nItemHeight;
 4584 
 4585         // Read transaction
 4586         if (strType != "owner" || hashItem != hash160)
 4587             break;
 4588         if (nItemHeight >= nMinHeight)
 4589         {
 4590             vtx.resize(vtx.size()+1);
 4591             if (!vtx.back().ReadFromDisk(pos))
 4592             {
 4593                 pcursor->close();
 4594                 return false;
 4595             }
 4596         }
 4597     }
 4598 
 4599     pcursor->close();
 4600     return true;
 4601 }
 4602 
 4603 bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx, CTxIndex& txindex)
 4604 {
 4605     assert(!fClient);
 4606     tx.SetNull();
 4607     if (!ReadTxIndex(hash, txindex))
 4608         return false;
 4609     return (tx.ReadFromDisk(txindex.pos));
 4610 }
 4611 
 4612 bool CTxDB::ReadDiskTx(uint256 hash, CTransaction& tx)
 4613 {
 4614     CTxIndex txindex;
 4615     return ReadDiskTx(hash, tx, txindex);
 4616 }
 4617 
 4618 bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx, CTxIndex& txindex)
 4619 {
 4620     return ReadDiskTx(outpoint.hash, tx, txindex);
 4621 }
 4622 
 4623 bool CTxDB::ReadDiskTx(COutPoint outpoint, CTransaction& tx)
 4624 {
 4625     CTxIndex txindex;
 4626     return ReadDiskTx(outpoint.hash, tx, txindex);
 4627 }
 4628 
 4629 bool CTxDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
 4630 {
 4631     return Write(make_pair(string("blockindex"), blockindex.GetBlockHash()), blockindex);
 4632 }
 4633 
 4634 bool CTxDB::EraseBlockIndex(uint256 hash)
 4635 {
 4636     return Erase(make_pair(string("blockindex"), hash));
 4637 }
 4638 
 4639 bool CTxDB::ReadHashBestChain(uint256& hashBestChain)
 4640 {
 4641     return Read(string("hashBestChain"), hashBestChain);
 4642 }
 4643 
 4644 bool CTxDB::WriteHashBestChain(uint256 hashBestChain)
 4645 {
 4646     return Write(string("hashBestChain"), hashBestChain);
 4647 }
 4648 
 4649 bool CTxDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork)
 4650 {
 4651     return Read(string("bnBestInvalidWork"), bnBestInvalidWork);
 4652 }
 4653 
 4654 bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork)
 4655 {
 4656     return Write(string("bnBestInvalidWork"), bnBestInvalidWork);
 4657 }
 4658 
 4659 CBlockIndex static * InsertBlockIndex(uint256 hash)
 4660 {
 4661     if (hash == 0)
 4662         return NULL;
 4663 
 4664     // Return existing
 4665     map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
 4666     if (mi != mapBlockIndex.end())
 4667         return (*mi).second;
 4668 
 4669     // Create new
 4670     CBlockIndex* pindexNew = new CBlockIndex();
 4671     if (!pindexNew)
 4672         throw runtime_error("LoadBlockIndex() : new CBlockIndex failed");
 4673     mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
 4674     pindexNew->phashBlock = &((*mi).first);
 4675 
 4676     return pindexNew;
 4677 }
 4678 
 4679 bool CTxDB::LoadBlockIndex()
 4680 {
 4681     // Get database cursor
 4682     Dbc* pcursor = GetCursor();
 4683     if (!pcursor)
 4684         return false;
 4685 
 4686     // Load mapBlockIndex
 4687     unsigned int fFlags = DB_SET_RANGE;
 4688     loop
 4689     {
 4690         // Read next record
 4691         CDataStream ssKey;
 4692         if (fFlags == DB_SET_RANGE)
 4693             ssKey << make_pair(string("blockindex"), uint256(0));
 4694         CDataStream ssValue;
 4695         int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
 4696         fFlags = DB_NEXT;
 4697         if (ret == DB_NOTFOUND)
 4698             break;
 4699         else if (ret != 0)
 4700             return false;
 4701 
 4702         // Unserialize
 4703         string strType;
 4704         ssKey >> strType;
 4705         if (strType == "blockindex")
 4706         {
 4707             CDiskBlockIndex diskindex;
 4708             ssValue >> diskindex;
 4709 
 4710             // Construct block index object
 4711             CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
 4712             pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
 4713             pindexNew->pnext          = InsertBlockIndex(diskindex.hashNext);
 4714             pindexNew->nFile          = diskindex.nFile;
 4715             pindexNew->nBlockPos      = diskindex.nBlockPos;
 4716             pindexNew->nHeight        = diskindex.nHeight;
 4717             pindexNew->nVersion       = diskindex.nVersion;
 4718             pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
 4719             pindexNew->nTime          = diskindex.nTime;
 4720             pindexNew->nBits          = diskindex.nBits;
 4721             pindexNew->nNonce         = diskindex.nNonce;
 4722 
 4723             // Watch for genesis block
 4724             if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)
 4725                 pindexGenesisBlock = pindexNew;
 4726 
 4727             if (!pindexNew->CheckIndex())
 4728                 return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight);
 4729         }
 4730         else
 4731         {
 4732             break;
 4733         }
 4734     }
 4735     pcursor->close();
 4736 
 4737     // Calculate bnChainWork
 4738     vector<pair<int, CBlockIndex*> > vSortedByHeight;
 4739     vSortedByHeight.reserve(mapBlockIndex.size());
 4740     BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex)
 4741     {
 4742         CBlockIndex* pindex = item.second;
 4743         vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex));
 4744     }
 4745     sort(vSortedByHeight.begin(), vSortedByHeight.end());
 4746     BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight)
 4747     {
 4748         CBlockIndex* pindex = item.second;
 4749         pindex->bnChainWork = (pindex->pprev ? pindex->pprev->bnChainWork : 0) + pindex->GetBlockWork();
 4750     }
 4751 
 4752     // Load hashBestChain pointer to end of best chain
 4753     if (!ReadHashBestChain(hashBestChain))
 4754     {
 4755         if (pindexGenesisBlock == NULL)
 4756             return true;
 4757         return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
 4758     }
 4759     if (!mapBlockIndex.count(hashBestChain))
 4760         return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index");
 4761     pindexBest = mapBlockIndex[hashBestChain];
 4762     nBestHeight = pindexBest->nHeight;
 4763     bnBestChainWork = pindexBest->bnChainWork;
 4764     printf("LoadBlockIndex(): hashBestChain=%s  height=%d\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight);
 4765 
 4766     // Load bnBestInvalidWork, OK if it doesn't exist
 4767     ReadBestInvalidWork(bnBestInvalidWork);
 4768 
 4769     // Verify blocks in the best chain
 4770     CBlockIndex* pindexFork = NULL;
 4771     for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
 4772     {
 4773         if (pindex->nHeight < nBestHeight-2500 && !mapArgs.count("-checkblocks"))
 4774             break;
 4775         CBlock block;
 4776         if (!block.ReadFromDisk(pindex))
 4777             return error("LoadBlockIndex() : block.ReadFromDisk failed");
 4778         if (!block.CheckBlock())
 4779         {
 4780             printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
 4781             pindexFork = pindex->pprev;
 4782         }
 4783     }
 4784     if (pindexFork)
 4785     {
 4786         // Reorg back to the fork
 4787         printf("LoadBlockIndex() : *** moving best chain pointer back to block %d\n", pindexFork->nHeight);
 4788         CBlock block;
 4789         if (!block.ReadFromDisk(pindexFork))
 4790             return error("LoadBlockIndex() : block.ReadFromDisk failed");
 4791         CTxDB txdb;
 4792         block.SetBestChain(txdb, pindexFork);
 4793     }
 4794 
 4795     return true;
 4796 }
 4797 
 4798 
 4799 
 4800 
 4801 
 4802 //
 4803 // CAddrDB
 4804 //
 4805 
 4806 bool CAddrDB::WriteAddress(const CAddress& addr)
 4807 {
 4808     return Write(make_pair(string("addr"), addr.GetKey()), addr);
 4809 }
 4810 
 4811 bool CAddrDB::EraseAddress(const CAddress& addr)
 4812 {
 4813     return Erase(make_pair(string("addr"), addr.GetKey()));
 4814 }
 4815 
 4816 bool CAddrDB::LoadAddresses()
 4817 {
 4818     CRITICAL_BLOCK(cs_mapAddresses)
 4819     {
 4820         // Get cursor
 4821         Dbc* pcursor = GetCursor();
 4822         if (!pcursor)
 4823             return false;
 4824 
 4825         loop
 4826         {
 4827             // Read next record
 4828             CDataStream ssKey;
 4829             CDataStream ssValue;
 4830             int ret = ReadAtCursor(pcursor, ssKey, ssValue);
 4831             if (ret == DB_NOTFOUND)
 4832                 break;
 4833             else if (ret != 0)
 4834                 return false;
 4835 
 4836             // Unserialize
 4837             string strType;
 4838             ssKey >> strType;
 4839             if (strType == "addr")
 4840             {
 4841                 CAddress addr;
 4842                 ssValue >> addr;
 4843                 mapAddresses.insert(make_pair(addr.GetKey(), addr));
 4844             }
 4845         }
 4846         pcursor->close();
 4847 
 4848         printf("Loaded %d addresses\n", mapAddresses.size());
 4849     }
 4850 
 4851     return true;
 4852 }
 4853 
 4854 bool LoadAddresses()
 4855 {
 4856     return CAddrDB("cr+").LoadAddresses();
 4857 }
 4858 
 4859 
 4860 
 4861 
 4862 //
 4863 // CWalletDB
 4864 //
 4865 
 4866 bool CWalletDB::WriteName(const string& strAddress, const string& strName)
 4867 {
 4868     nWalletDBUpdated++;
 4869     return Write(make_pair(string("name"), strAddress), strName);
 4870 }
 4871 
 4872 bool CWalletDB::EraseName(const string& strAddress)
 4873 {
 4874     // This should only be used for sending addresses, never for receiving addresses,
 4875     // receiving addresses must always have an address book entry if they're not change return.
 4876     nWalletDBUpdated++;
 4877     return Erase(make_pair(string("name"), strAddress));
 4878 }
 4879 
 4880 bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account)
 4881 {
 4882     account.SetNull();
 4883     return Read(make_pair(string("acc"), strAccount), account);
 4884 }
 4885 
 4886 bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account)
 4887 {
 4888     return Write(make_pair(string("acc"), strAccount), account);
 4889 }
 4890 
 4891 bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry)
 4892 {
 4893     return Write(boost::make_tuple(string("acentry"), acentry.strAccount, ++nAccountingEntryNumber), acentry);
 4894 }
 4895 
 4896 int64 CWalletDB::GetAccountCreditDebit(const string& strAccount)
 4897 {
 4898     list<CAccountingEntry> entries;
 4899     ListAccountCreditDebit(strAccount, entries);
 4900 
 4901     int64 nCreditDebit = 0;
 4902     BOOST_FOREACH (const CAccountingEntry& entry, entries)
 4903         nCreditDebit += entry.nCreditDebit;
 4904 
 4905     return nCreditDebit;
 4906 }
 4907 
 4908 void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountingEntry>& entries)
 4909 {
 4910     bool fAllAccounts = (strAccount == "*");
 4911 
 4912     Dbc* pcursor = GetCursor();
 4913     if (!pcursor)
 4914         throw runtime_error("CWalletDB::ListAccountCreditDebit() : cannot create DB cursor");
 4915     unsigned int fFlags = DB_SET_RANGE;
 4916     loop
 4917     {
 4918         // Read next record
 4919         CDataStream ssKey;
 4920         if (fFlags == DB_SET_RANGE)
 4921             ssKey << boost::make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64(0));
 4922         CDataStream ssValue;
 4923         int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
 4924         fFlags = DB_NEXT;
 4925         if (ret == DB_NOTFOUND)
 4926             break;
 4927         else if (ret != 0)
 4928         {
 4929             pcursor->close();
 4930             throw runtime_error("CWalletDB::ListAccountCreditDebit() : error scanning DB");
 4931         }
 4932 
 4933         // Unserialize
 4934         string strType;
 4935         ssKey >> strType;
 4936         if (strType != "acentry")
 4937             break;
 4938         CAccountingEntry acentry;
 4939         ssKey >> acentry.strAccount;
 4940         if (!fAllAccounts && acentry.strAccount != strAccount)
 4941             break;
 4942 
 4943         ssValue >> acentry;
 4944         entries.push_back(acentry);
 4945     }
 4946 
 4947     pcursor->close();
 4948 }
 4949 
 4950 
 4951 int CWalletDB::LoadWallet(CWallet* pwallet)
 4952 {
 4953     pwallet->vchDefaultKey.clear();
 4954     int nFileVersion = 0;
 4955     vector<uint256> vWalletUpgrade;
 4956     bool fIsEncrypted = false;
 4957 
 4958     // Modify defaults
 4959 #ifndef WIN32
 4960     // Tray icon sometimes disappears on 9.10 karmic koala 64-bit, leaving no way to access the program
 4961     fMinimizeToTray = false;
 4962     fMinimizeOnClose = false;
 4963 #endif
 4964 
 4965     //// todo: shouldn't we catch exceptions and try to recover and continue?
 4966     CRITICAL_BLOCK(pwallet->cs_wallet)
 4967     {
 4968         // Get cursor
 4969         Dbc* pcursor = GetCursor();
 4970         if (!pcursor)
 4971             return DB_CORRUPT;
 4972 
 4973         loop
 4974         {
 4975             // Read next record
 4976             CDataStream ssKey;
 4977             CDataStream ssValue;
 4978             int ret = ReadAtCursor(pcursor, ssKey, ssValue);
 4979             if (ret == DB_NOTFOUND)
 4980                 break;
 4981             else if (ret != 0)
 4982                 return DB_CORRUPT;
 4983 
 4984             // Unserialize
 4985             // Taking advantage of the fact that pair serialization
 4986             // is just the two items serialized one after the other
 4987             string strType;
 4988             ssKey >> strType;
 4989             if (strType == "name")
 4990             {
 4991                 string strAddress;
 4992                 ssKey >> strAddress;
 4993                 ssValue >> pwallet->mapAddressBook[strAddress];
 4994             }
 4995             else if (strType == "tx")
 4996             {
 4997                 uint256 hash;
 4998                 ssKey >> hash;
 4999                 CWalletTx& wtx = pwallet->mapWallet[hash];
 5000                 ssValue >> wtx;
 5001                 wtx.pwallet = pwallet;
 5002 
 5003                 if (wtx.GetHash() != hash)
 5004                     printf("Error in wallet.dat, hash mismatch\n");
 5005 
 5006                 // Undo serialize changes in 31600
 5007                 if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703)
 5008                 {
 5009                     if (!ssValue.empty())
 5010                     {
 5011                         char fTmp;
 5012                         char fUnused;
 5013                         ssValue >> fTmp >> fUnused >> wtx.strFromAccount;
 5014                         printf("LoadWallet() upgrading tx ver=%d %d '%s' %s\n", wtx.fTimeReceivedIsTxTime, fTmp, wtx.strFromAccount.c_str(), hash.ToString().c_str());
 5015                         wtx.fTimeReceivedIsTxTime = fTmp;
 5016                     }
 5017                     else
 5018                     {
 5019                         printf("LoadWallet() repairing tx ver=%d %s\n", wtx.fTimeReceivedIsTxTime, hash.ToString().c_str());
 5020                         wtx.fTimeReceivedIsTxTime = 0;
 5021                     }
 5022                     vWalletUpgrade.push_back(hash);
 5023                 }
 5024 
 5025                 //// debug print
 5026                 //printf("LoadWallet  %s\n", wtx.GetHash().ToString().c_str());
 5027                 //printf(" %12I64d  %s  %s  %s\n",
 5028                 //    wtx.vout[0].nValue,
 5029                 //    DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(),
 5030                 //    wtx.hashBlock.ToString().substr(0,20).c_str(),
 5031                 //    wtx.mapValue["message"].c_str());
 5032             }
 5033             else if (strType == "acentry")
 5034             {
 5035                 string strAccount;
 5036                 ssKey >> strAccount;
 5037                 uint64 nNumber;
 5038                 ssKey >> nNumber;
 5039                 if (nNumber > nAccountingEntryNumber)
 5040                     nAccountingEntryNumber = nNumber;
 5041             }
 5042             else if (strType == "key" || strType == "wkey")
 5043             {
 5044                 vector<unsigned char> vchPubKey;
 5045                 ssKey >> vchPubKey;
 5046                 CKey key;
 5047                 if (strType == "key")
 5048                 {
 5049                     CPrivKey pkey;
 5050                     ssValue >> pkey;
 5051                     key.SetPrivKey(pkey);
 5052                     if (key.GetPubKey() != vchPubKey || !key.IsValid())
 5053                         return DB_CORRUPT;
 5054                 }
 5055                 else
 5056                 {
 5057                     CWalletKey wkey;
 5058                     ssValue >> wkey;
 5059                     key.SetPrivKey(wkey.vchPrivKey);
 5060                     if (key.GetPubKey() != vchPubKey || !key.IsValid())
 5061                         return DB_CORRUPT;
 5062                 }
 5063                 if (!pwallet->LoadKey(key))
 5064                     return DB_CORRUPT;
 5065             }
 5066             else if (strType == "mkey")
 5067             {
 5068                 unsigned int nID;
 5069                 ssKey >> nID;
 5070                 CMasterKey kMasterKey;
 5071                 ssValue >> kMasterKey;
 5072                 if(pwallet->mapMasterKeys.count(nID) != 0)
 5073                     return DB_CORRUPT;
 5074                 pwallet->mapMasterKeys[nID] = kMasterKey;
 5075                 if (pwallet->nMasterKeyMaxID < nID)
 5076                     pwallet->nMasterKeyMaxID = nID;
 5077             }
 5078             else if (strType == "ckey")
 5079             {
 5080                 vector<unsigned char> vchPubKey;
 5081                 ssKey >> vchPubKey;
 5082                 vector<unsigned char> vchPrivKey;
 5083                 ssValue >> vchPrivKey;
 5084                 if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
 5085                     return DB_CORRUPT;
 5086                 fIsEncrypted = true;
 5087             }
 5088             else if (strType == "defaultkey")
 5089             {
 5090                 ssValue >> pwallet->vchDefaultKey;
 5091             }
 5092             else if (strType == "pool")
 5093             {
 5094                 int64 nIndex;
 5095                 ssKey >> nIndex;
 5096                 pwallet->setKeyPool.insert(nIndex);
 5097             }
 5098             else if (strType == "version")
 5099             {
 5100                 ssValue >> nFileVersion;
 5101                 if (nFileVersion == 10300)
 5102                     nFileVersion = 300;
 5103             }
 5104             else if (strType == "setting")
 5105             {
 5106                 string strKey;
 5107                 ssKey >> strKey;
 5108 
 5109                 // Options
 5110 #ifndef QT_GUI
 5111                 if (strKey == "fGenerateBitcoins")  ssValue >> fGenerateBitcoins;
 5112 #endif
 5113                 if (strKey == "nTransactionFee")    ssValue >> nTransactionFee;
 5114                 if (strKey == "fLimitProcessors")   ssValue >> fLimitProcessors;
 5115                 if (strKey == "nLimitProcessors")   ssValue >> nLimitProcessors;
 5116                 if (strKey == "fMinimizeToTray")    ssValue >> fMinimizeToTray;
 5117                 if (strKey == "fMinimizeOnClose")   ssValue >> fMinimizeOnClose;
 5118                 if (strKey == "fUseProxy")          ssValue >> fUseProxy;
 5119                 if (strKey == "addrProxy")          ssValue >> addrProxy;
 5120                 if (fHaveUPnP && strKey == "fUseUPnP")           ssValue >> fUseUPnP;
 5121             }
 5122             else if (strType == "minversion")
 5123             {
 5124                 int nMinVersion = 0;
 5125                 ssValue >> nMinVersion;
 5126                 if (nMinVersion > VERSION)
 5127                     return DB_TOO_NEW;
 5128             }
 5129         }
 5130         pcursor->close();
 5131     }
 5132 
 5133     BOOST_FOREACH(uint256 hash, vWalletUpgrade)
 5134         WriteTx(hash, pwallet->mapWallet[hash]);
 5135 
 5136     printf("nFileVersion = %d\n", nFileVersion);
 5137     printf("fGenerateBitcoins = %d\n", fGenerateBitcoins);
 5138     printf("nTransactionFee = %"PRI64d"\n", nTransactionFee);
 5139     printf("fMinimizeToTray = %d\n", fMinimizeToTray);
 5140     printf("fMinimizeOnClose = %d\n", fMinimizeOnClose);
 5141     printf("fUseProxy = %d\n", fUseProxy);
 5142     printf("addrProxy = %s\n", addrProxy.ToString().c_str());
 5143     if (fHaveUPnP)
 5144         printf("fUseUPnP = %d\n", fUseUPnP);
 5145 
 5146 
 5147     // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc:
 5148     if (fIsEncrypted && (nFileVersion == 40000 || nFileVersion == 50000))
 5149         return DB_NEED_REWRITE;
 5150 
 5151     if (nFileVersion < VERSION) // Update
 5152     {
 5153         // Get rid of old debug.log file in current directory
 5154         if (nFileVersion <= 105 && !pszSetDataDir[0])
 5155             unlink("debug.log");
 5156 
 5157         WriteVersion(VERSION);
 5158     }
 5159 
 5160     return DB_LOAD_OK;
 5161 }
 5162 
 5163 void ThreadFlushWalletDB(void* parg)
 5164 {
 5165     const string& strFile = ((const string*)parg)[0];
 5166     static bool fOneThread;
 5167     if (fOneThread)
 5168         return;
 5169     fOneThread = true;
 5170     if (mapArgs.count("-noflushwallet"))
 5171         return;
 5172 
 5173     unsigned int nLastSeen = nWalletDBUpdated;
 5174     unsigned int nLastFlushed = nWalletDBUpdated;
 5175     int64 nLastWalletUpdate = GetTime();
 5176     while (!fShutdown)
 5177     {
 5178         Sleep(500);
 5179 
 5180         if (nLastSeen != nWalletDBUpdated)
 5181         {
 5182             nLastSeen = nWalletDBUpdated;
 5183             nLastWalletUpdate = GetTime();
 5184         }
 5185 
 5186         if (nLastFlushed != nWalletDBUpdated && GetTime() - nLastWalletUpdate >= 2)
 5187         {
 5188             TRY_CRITICAL_BLOCK(cs_db)
 5189             {
 5190                 // Don't do this if any databases are in use
 5191                 int nRefCount = 0;
 5192                 map<string, int>::iterator mi = mapFileUseCount.begin();
 5193                 while (mi != mapFileUseCount.end())
 5194                 {
 5195                     nRefCount += (*mi).second;
 5196                     mi++;
 5197                 }
 5198 
 5199                 if (nRefCount == 0 && !fShutdown)
 5200                 {
 5201                     map<string, int>::iterator mi = mapFileUseCount.find(strFile);
 5202                     if (mi != mapFileUseCount.end())
 5203                     {
 5204                         printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
 5205                         printf("Flushing wallet.dat\n");
 5206                         nLastFlushed = nWalletDBUpdated;
 5207                         int64 nStart = GetTimeMillis();
 5208 
 5209                         // Flush wallet.dat so it's self contained
 5210                         CloseDb(strFile);
 5211                         dbenv.txn_checkpoint(0, 0, 0);
 5212                         dbenv.lsn_reset(strFile.c_str(), 0);
 5213 
 5214                         mapFileUseCount.erase(mi++);
 5215                         printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart);
 5216                     }
 5217                 }
 5218             }
 5219         }
 5220     }
 5221 }
 5222 
 5223 bool BackupWallet(const CWallet& wallet, const string& strDest)
 5224 {
 5225     if (!wallet.fFileBacked)
 5226         return false;
 5227     while (!fShutdown)
 5228     {
 5229         CRITICAL_BLOCK(cs_db)
 5230         {
 5231             if (!mapFileUseCount.count(wallet.strWalletFile) || mapFileUseCount[wallet.strWalletFile] == 0)
 5232             {
 5233                 // Flush log data to the dat file
 5234                 CloseDb(wallet.strWalletFile);
 5235                 dbenv.txn_checkpoint(0, 0, 0);
 5236                 dbenv.lsn_reset(wallet.strWalletFile.c_str(), 0);
 5237                 mapFileUseCount.erase(wallet.strWalletFile);
 5238 
 5239                 // Copy wallet.dat
 5240                 filesystem::path pathSrc(GetDataDir() + "/" + wallet.strWalletFile);
 5241                 filesystem::path pathDest(strDest);
 5242                 if (filesystem::is_directory(pathDest))
 5243                     pathDest = pathDest / wallet.strWalletFile;
 5244 #if BOOST_VERSION >= 104000
 5245                 filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
 5246 #else
 5247                 filesystem::copy_file(pathSrc, pathDest);
 5248 #endif
 5249                 printf("copied wallet.dat to %s\n", pathDest.string().c_str());
 5250 
 5251                 return true;
 5252             }
 5253         }
 5254         Sleep(100);
 5255     }
 5256     return false;
 5257 }