X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fdb.cpp;h=e52e6cf0568e8b62af4d7261f721f8134dc78825;hb=9795536e660254a25984d0fc81a548eaf0e91c92;hp=1dea92eadc0f4c0ffa9ad46a015090cd06d033e9;hpb=0fa89d8e816807a621419495d7bdc6366979a0f0;p=novacoin.git diff --git a/src/db.cpp b/src/db.cpp index 1dea92e..e52e6cf 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -1,10 +1,13 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2011 The Bitcoin developers +// Copyright (c) 2011-2012 The PPCoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. #include "headers.h" #include "db.h" #include "net.h" +#include "checkpoints.h" #include #include @@ -27,6 +30,23 @@ DbEnv dbenv(0); static map mapFileUseCount; static map mapDb; +static void EnvShutdown() +{ + if (!fDbEnvInit) + return; + + fDbEnvInit = false; + try + { + dbenv.close(0); + } + catch (const DbException& e) + { + printf("EnvShutdown exception: %s (%d)\n", e.what(), e.get_errno()); + } + DbEnv(0).remove(GetDataDir().c_str(), 0); +} + class CDBInit { public: @@ -35,11 +55,7 @@ public: } ~CDBInit() { - if (fDbEnvInit) - { - dbenv.close(0); - fDbEnvInit = false; - } + EnvShutdown(); } } instance_of_cdbinit; @@ -164,6 +180,101 @@ void static CloseDb(const string& strFile) } } +bool CDB::Rewrite(const string& strFile, const char* pszSkip) +{ + while (!fShutdown) + { + CRITICAL_BLOCK(cs_db) + { + if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0) + { + // Flush log data to the dat file + CloseDb(strFile); + dbenv.txn_checkpoint(0, 0, 0); + dbenv.lsn_reset(strFile.c_str(), 0); + mapFileUseCount.erase(strFile); + + bool fSuccess = true; + printf("Rewriting %s...\n", strFile.c_str()); + string strFileRes = strFile + ".rewrite"; + { // surround usage of db with extra {} + CDB db(strFile.c_str(), "r"); + Db* pdbCopy = new Db(&dbenv, 0); + + int ret = pdbCopy->open(NULL, // Txn pointer + strFileRes.c_str(), // Filename + "main", // Logical db name + DB_BTREE, // Database type + DB_CREATE, // Flags + 0); + if (ret > 0) + { + printf("Cannot create database file %s\n", strFileRes.c_str()); + fSuccess = false; + } + + Dbc* pcursor = db.GetCursor(); + if (pcursor) + while (fSuccess) + { + CDataStream ssKey; + CDataStream ssValue; + int ret = db.ReadAtCursor(pcursor, ssKey, ssValue, DB_NEXT); + if (ret == DB_NOTFOUND) + { + pcursor->close(); + break; + } + else if (ret != 0) + { + pcursor->close(); + fSuccess = false; + break; + } + if (pszSkip && + strncmp(&ssKey[0], pszSkip, std::min(ssKey.size(), strlen(pszSkip))) == 0) + continue; + if (strncmp(&ssKey[0], "\x07version", 8) == 0) + { + // Update version: + ssValue.clear(); + ssValue << VERSION; + } + Dbt datKey(&ssKey[0], ssKey.size()); + Dbt datValue(&ssValue[0], ssValue.size()); + int ret2 = pdbCopy->put(NULL, &datKey, &datValue, DB_NOOVERWRITE); + if (ret2 > 0) + fSuccess = false; + } + if (fSuccess) + { + db.Close(); + CloseDb(strFile); + if (pdbCopy->close(0)) + fSuccess = false; + delete pdbCopy; + } + } + if (fSuccess) + { + Db dbA(&dbenv, 0); + if (dbA.remove(strFile.c_str(), NULL, 0)) + fSuccess = false; + Db dbB(&dbenv, 0); + if (dbB.rename(strFileRes.c_str(), NULL, strFile.c_str(), 0)) + fSuccess = false; + } + if (!fSuccess) + printf("Rewriting of %s FAILED!\n", strFileRes.c_str()); + return fSuccess; + } + } + Sleep(100); + } + return false; +} + + void DBFlush(bool fShutdown) { // Flush log data to the actual data file @@ -195,9 +306,10 @@ void DBFlush(bool fShutdown) { char** listp; if (mapFileUseCount.empty()) + { dbenv.log_archive(&listp, DB_ARCH_REMOVE); - dbenv.close(0); - fDbEnvInit = false; + EnvShutdown(); + } } } } @@ -348,14 +460,24 @@ bool CTxDB::WriteHashBestChain(uint256 hashBestChain) return Write(string("hashBestChain"), hashBestChain); } -bool CTxDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork) +bool CTxDB::ReadBestInvalidTrust(uint64& nBestInvalidTrust) { - return Read(string("bnBestInvalidWork"), bnBestInvalidWork); + return Read(string("nBestInvalidTrust"), nBestInvalidTrust); } -bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork) +bool CTxDB::WriteBestInvalidTrust(uint64 nBestInvalidTrust) { - return Write(string("bnBestInvalidWork"), bnBestInvalidWork); + return Write(string("nBestInvalidTrust"), nBestInvalidTrust); +} + +bool CTxDB::ReadSyncCheckpoint(uint256& hashCheckpoint) +{ + return Read(string("hashSyncCheckpoint"), hashCheckpoint); +} + +bool CTxDB::WriteSyncCheckpoint(uint256 hashCheckpoint) +{ + return Write(string("hashSyncCheckpoint"), hashCheckpoint); } CBlockIndex static * InsertBlockIndex(uint256 hash) @@ -415,7 +537,10 @@ bool CTxDB::LoadBlockIndex() pindexNew->pnext = InsertBlockIndex(diskindex.hashNext); pindexNew->nFile = diskindex.nFile; pindexNew->nBlockPos = diskindex.nBlockPos; + pindexNew->nChainTrust = diskindex.nChainTrust; pindexNew->nHeight = diskindex.nHeight; + pindexNew->fProofOfStake = diskindex.fProofOfStake; + pindexNew->prevoutStake = diskindex.prevoutStake; pindexNew->nVersion = diskindex.nVersion; pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; pindexNew->nTime = diskindex.nTime; @@ -428,6 +553,10 @@ bool CTxDB::LoadBlockIndex() if (!pindexNew->CheckIndex()) return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight); + + // ppcoin: build setStakeSeen + if (pindexNew->fProofOfStake) + setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); } else { @@ -436,21 +565,6 @@ bool CTxDB::LoadBlockIndex() } pcursor->close(); - // Calculate bnChainWork - vector > vSortedByHeight; - vSortedByHeight.reserve(mapBlockIndex.size()); - BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) - { - CBlockIndex* pindex = item.second; - vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); - } - sort(vSortedByHeight.begin(), vSortedByHeight.end()); - BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight) - { - CBlockIndex* pindex = item.second; - pindex->bnChainWork = (pindex->pprev ? pindex->pprev->bnChainWork : 0) + pindex->GetBlockWork(); - } - // Load hashBestChain pointer to end of best chain if (!ReadHashBestChain(hashBestChain)) { @@ -462,11 +576,16 @@ bool CTxDB::LoadBlockIndex() return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index"); pindexBest = mapBlockIndex[hashBestChain]; nBestHeight = pindexBest->nHeight; - bnBestChainWork = pindexBest->bnChainWork; - printf("LoadBlockIndex(): hashBestChain=%s height=%d\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight); + nBestChainTrust = pindexBest->nChainTrust; + printf("LoadBlockIndex(): hashBestChain=%s height=%d trust=%d\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, nBestChainTrust); - // Load bnBestInvalidWork, OK if it doesn't exist - ReadBestInvalidWork(bnBestInvalidWork); + // ppcoin: load hashSyncCheckpoint + if (!ReadSyncCheckpoint(Checkpoints::hashSyncCheckpoint)) + return error("CTxDB::LoadBlockIndex() : hashSyncCheckpoint not loaded"); + printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str()); + + // Load nBestInvalidTrust, OK if it doesn't exist + ReadBestInvalidTrust(nBestInvalidTrust); // Verify blocks in the best chain CBlockIndex* pindexFork = NULL; @@ -519,24 +638,6 @@ bool CAddrDB::LoadAddresses() { CRITICAL_BLOCK(cs_mapAddresses) { - // Load user provided addresses - CAutoFile filein = fopen((GetDataDir() + "/addr.txt").c_str(), "rt"); - if (filein) - { - try - { - char psz[1000]; - while (fgets(psz, sizeof(psz), filein)) - { - CAddress addr(psz, NODE_NETWORK); - addr.nTime = 0; // so it won't relay unless successfully connected - if (addr.IsValid()) - AddAddress(addr); - } - } - catch (...) { } - } - // Get cursor Dbc* pcursor = GetCursor(); if (!pcursor) @@ -610,7 +711,7 @@ bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account) bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry) { - return Write(make_tuple(string("acentry"), acentry.strAccount, ++nAccountingEntryNumber), acentry); + return Write(boost::make_tuple(string("acentry"), acentry.strAccount, ++nAccountingEntryNumber), acentry); } int64 CWalletDB::GetAccountCreditDebit(const string& strAccount) @@ -627,8 +728,6 @@ int64 CWalletDB::GetAccountCreditDebit(const string& strAccount) void CWalletDB::ListAccountCreditDebit(const string& strAccount, list& entries) { - int64 nCreditDebit = 0; - bool fAllAccounts = (strAccount == "*"); Dbc* pcursor = GetCursor(); @@ -640,7 +739,7 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, listvchDefaultKey.clear(); int nFileVersion = 0; vector vWalletUpgrade; + bool fIsEncrypted = false; // Modify defaults -#ifndef __WXMSW__ +#ifndef WIN32 // Tray icon sometimes disappears on 9.10 karmic koala 64-bit, leaving no way to access the program fMinimizeToTray = false; fMinimizeOnClose = false; #endif //// todo: shouldn't we catch exceptions and try to recover and continue? - CRITICAL_BLOCK(pwallet->cs_mapWallet) - CRITICAL_BLOCK(pwallet->cs_KeyStore) + CRITICAL_BLOCK(pwallet->cs_wallet) { // Get cursor Dbc* pcursor = GetCursor(); @@ -779,7 +878,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet) key.SetPrivKey(wkey.vchPrivKey); } if (!pwallet->LoadKey(key)) - return false; + return DB_CORRUPT; } else if (strType == "mkey") { @@ -788,7 +887,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet) CMasterKey kMasterKey; ssValue >> kMasterKey; if(pwallet->mapMasterKeys.count(nID) != 0) - return false; + return DB_CORRUPT; pwallet->mapMasterKeys[nID] = kMasterKey; if (pwallet->nMasterKeyMaxID < nID) pwallet->nMasterKeyMaxID = nID; @@ -800,7 +899,8 @@ int CWalletDB::LoadWallet(CWallet* pwallet) vector vchPrivKey; ssValue >> vchPrivKey; if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey)) - return false; + return DB_CORRUPT; + fIsEncrypted = true; } else if (strType == "defaultkey") { @@ -824,7 +924,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet) ssKey >> strKey; // Options -#ifndef GUI +#ifndef QT_GUI if (strKey == "fGenerateBitcoins") ssValue >> fGenerateBitcoins; #endif if (strKey == "nTransactionFee") ssValue >> nTransactionFee; @@ -835,6 +935,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet) if (strKey == "fUseProxy") ssValue >> fUseProxy; if (strKey == "addrProxy") ssValue >> addrProxy; if (fHaveUPnP && strKey == "fUseUPnP") ssValue >> fUseUPnP; + if (strKey == "nBalanceReserve") ssValue >> nBalanceReserve; } else if (strType == "minversion") { @@ -861,8 +962,11 @@ int CWalletDB::LoadWallet(CWallet* pwallet) printf("fUseUPnP = %d\n", fUseUPnP); - // Upgrade - if (nFileVersion < VERSION) + // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc: + if (fIsEncrypted && (nFileVersion == 40000 || nFileVersion == 50000)) + return DB_NEED_REWRITE; + + if (nFileVersion < VERSION) // Update { // Get rid of old debug.log file in current directory if (nFileVersion <= 105 && !pszSetDataDir[0]) @@ -871,7 +975,6 @@ int CWalletDB::LoadWallet(CWallet* pwallet) WriteVersion(VERSION); } - return DB_LOAD_OK; }