src/net.h \
src/key.h \
src/db.h \
+ src/txdb.h \
+ src/leveldb.h \
src/walletdb.h \
src/script.h \
src/init.h \
src/addrman.cpp \
src/db.cpp \
src/leveldb.cpp \
+ src/txdb.cpp \
src/walletdb.cpp \
src/qt/clientmodel.cpp \
src/qt/guiutil.cpp \
#include "checkpoints.h"
-#include "db.h"
+#include "txdb.h"
#include "main.h"
#include "uint256.h"
bool WriteSyncCheckpoint(const uint256& hashCheckpoint)
{
- pblocktree->TxnBegin();
- if (!pblocktree->WriteSyncCheckpoint(hashCheckpoint))
{
- pblocktree->TxnAbort();
- return error("WriteSyncCheckpoint(): failed to write to db sync checkpoint %s", hashCheckpoint.ToString().c_str());
+ LOCK(Checkpoints::cs_hashSyncCheckpoint);
+
+ if (!pblocktree->WriteSyncCheckpoint(hashCheckpoint))
+ {
+ return error("WriteSyncCheckpoint(): failed to write to db sync checkpoint %s", hashCheckpoint.ToString().c_str());
+ }
}
- if (!pblocktree->TxnCommit())
- return error("WriteSyncCheckpoint(): failed to commit to db sync checkpoint %s", hashCheckpoint.ToString().c_str());
Checkpoints::hashSyncCheckpoint = hashCheckpoint;
return true;
}
-
-
-
-
-//
-// CBlockTreeDB and CCoinsDB
-//
-
-bool CCoinsDB::HaveCoins(uint256 hash) {
- assert(!fClient);
- return Exists(make_pair('c', hash));
-}
-
-bool CCoinsDB::ReadCoins(uint256 hash, CCoins &coins) {
- assert(!fClient);
- return Read(make_pair('c', hash), coins);
-}
-
-bool CCoinsDB::WriteCoins(uint256 hash, const CCoins &coins) {
- assert(!fClient);
- if (coins.IsPruned())
- return Erase(make_pair('c', hash));
- else
- return Write(make_pair('c', hash), coins);
-}
-
-bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
-{
- return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
-}
-
-bool CCoinsDB::ReadHashBestChain(uint256& hashBestChain)
-{
- return Read('B', hashBestChain);
-}
-
-bool CCoinsDB::WriteHashBestChain(uint256 hashBestChain)
-{
- return Write('B', hashBestChain);
-}
-
-bool CBlockTreeDB::ReadBestInvalidTrust(CBigNum& bnBestInvalidTrust)
-{
- return Read('I', bnBestInvalidTrust);
-}
-
-bool CBlockTreeDB::WriteBestInvalidTrust(CBigNum bnBestInvalidTrust)
-{
- return Write('I', bnBestInvalidTrust);
-}
-
-bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
- return Write(make_pair('f', nFile), info);
-}
-
-bool CBlockTreeDB::ReadSyncCheckpoint(uint256& hashCheckpoint)
-{
- return Read('H', hashCheckpoint);
-}
-
-bool CBlockTreeDB::WriteSyncCheckpoint(uint256 hashCheckpoint)
-{
- return Write('H', hashCheckpoint);
-}
-
-bool CBlockTreeDB::ReadCheckpointPubKey(string& strPubKey)
-{
- return Read('K', strPubKey);
-}
-
-bool CBlockTreeDB::WriteCheckpointPubKey(const string& strPubKey)
-{
- return Write('K', strPubKey);
-}
-
-
-bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
- return Read(make_pair('f', nFile), info);
-}
-
-bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
- return Write('l', nFile);
-}
-
-bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
- return Read('l', nFile);
-}
-
-CCoinsViewDB::CCoinsViewDB() : db("cr+") {}
-bool CCoinsViewDB::GetCoins(uint256 txid, CCoins &coins) { return db.ReadCoins(txid, coins); }
-bool CCoinsViewDB::SetCoins(uint256 txid, const CCoins &coins) { return db.WriteCoins(txid, coins); }
-bool CCoinsViewDB::HaveCoins(uint256 txid) { return db.HaveCoins(txid); }
-CBlockIndex *CCoinsViewDB::GetBestBlock() {
- uint256 hashBestChain;
- if (!db.ReadHashBestChain(hashBestChain))
- return NULL;
- std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hashBestChain);
- if (it == mapBlockIndex.end())
- return NULL;
- return it->second;
-}
-bool CCoinsViewDB::SetBestBlock(CBlockIndex *pindex) { return db.WriteHashBestChain(pindex->GetBlockHash()); }
-bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) {
- printf("Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size());
-
- if (!db.TxnBegin())
- return false;
- bool fOk = true;
- for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++) {
- fOk = db.WriteCoins(it->first, it->second);
- if (!fOk)
- break;
- }
- if (fOk)
- fOk = db.WriteHashBestChain(pindex->GetBlockHash());
-
- if (!fOk)
- db.TxnAbort();
- else
- fOk = db.TxnCommit();
-
- return fOk;
-}
-
-CBlockIndex static * InsertBlockIndex(uint256 hash)
-{
- if (hash == 0)
- return NULL;
-
- // Return existing
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
- if (mi != mapBlockIndex.end())
- return (*mi).second;
-
- // Create new
- CBlockIndex* pindexNew = new CBlockIndex();
- if (!pindexNew)
- throw runtime_error("LoadBlockIndex() : new CBlockIndex failed");
- mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
- pindexNew->phashBlock = &((*mi).first);
-
- return pindexNew;
-}
-
-bool LoadBlockIndexDB()
-{
- if (!pblocktree->LoadBlockIndexGuts())
- return false;
-
- if (fRequestShutdown)
- return true;
-
- // Calculate nChainTrust
- vector<pair<int, CBlockIndex*> > 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->nChainTrust = (pindex->pprev ? pindex->pprev->nChainTrust : 0) + pindex->GetBlockTrust();
- pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx;
- if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS && !(pindex->nStatus & BLOCK_FAILED_MASK))
- setBlockIndexValid.insert(pindex);
-
- // Calculate stake modifier checksum
- pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex);
- if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum))
- return error("CTxDB::LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016"PRI64x, pindex->nHeight, pindex->nStakeModifier);
- }
-
- // Load block file info
- pblocktree->ReadLastBlockFile(nLastBlockFile);
- printf("LoadBlockIndex(): last block file = %i\n", nLastBlockFile);
- if (pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile))
- printf("LoadBlockIndex(): last block file: %s\n", infoLastBlockFile.ToString().c_str());
-
- // Load hashBestChain pointer to end of best chain
- pindexBest = pcoinsTip->GetBestBlock();
- if (pindexBest == NULL)
- {
- if (pindexGenesisBlock == NULL)
- return true;
- return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded");
- }
- hashBestChain = pindexBest->GetBlockHash();
- nBestHeight = pindexBest->nHeight;
- nBestChainTrust = pindexBest->nChainTrust;
-
- // set 'next' pointers in best chain
- CBlockIndex *pindex = pindexBest;
- while(pindex != NULL && pindex->pprev != NULL) {
- CBlockIndex *pindexPrev = pindex->pprev;
- pindexPrev->pnext = pindex;
- pindex = pindexPrev;
- }
- printf("LoadBlockIndex(): hashBestChain=%s height=%d date=%s\n",
- hashBestChain.ToString().substr(0,20).c_str(), nBestHeight,
- DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
-
- // Load sync-checkpoint
- if (!pblocktree->ReadSyncCheckpoint(Checkpoints::hashSyncCheckpoint))
- return error("CTxDB::LoadBlockIndex() : hashSyncCheckpoint not loaded");
- printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str());
-
- // Load bnBestInvalidTrust, OK if it doesn't exist
- CBigNum bnBestInvalidTrust;
- pblocktree->ReadBestInvalidTrust(bnBestInvalidTrust);
- nBestInvalidTrust = bnBestInvalidTrust.getuint256();
-
- // Verify blocks in the best chain
- int nCheckLevel = GetArg("-checklevel", 1);
- int nCheckDepth = GetArg( "-checkblocks", 2500);
- if (nCheckDepth == 0)
- nCheckDepth = 1000000000; // suffices until the year 19000
- if (nCheckDepth > nBestHeight)
- nCheckDepth = nBestHeight;
- printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
- CBlockIndex* pindexFork = NULL;
- for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
- {
- if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth)
- break;
- CBlock block;
- if (!block.ReadFromDisk(pindex))
- return error("LoadBlockIndex() : block.ReadFromDisk failed");
- // check level 1: verify block validity
- if (nCheckLevel>0 && !block.CheckBlock())
- {
- printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
- pindexFork = pindex->pprev;
- }
- // TODO: stronger verifications
- }
- if (pindexFork && !fRequestShutdown)
- {
- // TODO: reorg back
- return error("LoadBlockIndex(): chain database corrupted");
- }
-
- return true;
-}
-
-
-
-bool CBlockTreeDB::LoadBlockIndexGuts()
-{
- // Get database cursor
- Dbc* pcursor = GetCursor();
- if (!pcursor)
- return false;
-
- // Load mapBlockIndex
- unsigned int fFlags = DB_SET_RANGE;
- while (true)
- {
- // Read next record
- CDataStream ssKey(SER_DISK, CLIENT_VERSION);
- if (fFlags == DB_SET_RANGE)
- ssKey << make_pair('b', uint256(0));
- CDataStream ssValue(SER_DISK, CLIENT_VERSION);
- int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
- fFlags = DB_NEXT;
- if (ret == DB_NOTFOUND)
- break;
- else if (ret != 0)
- return false;
-
- // Unserialize
-
- try {
- char chType;
- ssKey >> chType;
- if (chType == 'b' && !fRequestShutdown)
- {
- CDiskBlockIndex diskindex;
- ssValue >> diskindex;
-
- uint256 blockHash = diskindex.GetBlockHash();
-
- // Construct block index object
- CBlockIndex* pindexNew = InsertBlockIndex(blockHash);
- pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
- pindexNew->nHeight = diskindex.nHeight;
- pindexNew->nFile = diskindex.nFile;
- pindexNew->nDataPos = diskindex.nDataPos;
- pindexNew->nUndoPos = diskindex.nUndoPos;
- pindexNew->nMint = diskindex.nMint;
- pindexNew->nMoneySupply = diskindex.nMoneySupply;
- pindexNew->nFlags = diskindex.nFlags;
- pindexNew->nStakeModifier = diskindex.nStakeModifier;
- pindexNew->prevoutStake = diskindex.prevoutStake;
- pindexNew->nStakeTime = diskindex.nStakeTime;
- pindexNew->hashProofOfStake = diskindex.hashProofOfStake;
- pindexNew->nVersion = diskindex.nVersion;
- pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
- pindexNew->nTime = diskindex.nTime;
- pindexNew->nBits = diskindex.nBits;
- pindexNew->nNonce = diskindex.nNonce;
- pindexNew->nStatus = diskindex.nStatus;
- pindexNew->nTx = diskindex.nTx;
-
- // Watch for genesis block
- if (pindexGenesisBlock == NULL && blockHash == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
- pindexGenesisBlock = pindexNew;
-
- if (!pindexNew->CheckIndex())
- return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString().c_str());
-
- // Build setStakeSeen
- if (pindexNew->IsProofOfStake())
- setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime));
- }
- else
- {
- break; // if shutdown requested or finished loading block index
- }
- } // try
- catch (std::exception &e) {
- return error("%s() : deserialize error", __PRETTY_FUNCTION__);
- }
- }
- pcursor->close();
-
- return true;
-}
-
-
-
-
-
//
// CAddrDB
//
bool static Rewrite(const std::string& strFile, const char* pszSkip = NULL);
};
-
-
-
-
-
-
-/** Access to the transaction database (coins.dat) */
-class CCoinsDB : public CDB
-{
-public:
- CCoinsDB(const char* pszMode="r+") : CDB("coins.dat", pszMode) { }
-private:
- CCoinsDB(const CCoinsDB&);
- void operator=(const CCoinsDB&);
-public:
- bool ReadCoins(uint256 hash, CCoins &coins);
- bool WriteCoins(uint256 hash, const CCoins& coins);
- bool HaveCoins(uint256 hash);
- bool ReadHashBestChain(uint256& hashBestChain);
- bool WriteHashBestChain(uint256 hashBestChain);
-};
-
-
-/** CCoinsView backed by a CCoinsDB */
-class CCoinsViewDB : public CCoinsView
-{
-protected:
- CCoinsDB db;
-public:
- CCoinsViewDB();
- bool GetCoins(uint256 txid, CCoins &coins);
- bool SetCoins(uint256 txid, const CCoins &coins);
- bool HaveCoins(uint256 txid);
- CBlockIndex *GetBestBlock();
- bool SetBestBlock(CBlockIndex *pindex);
- bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
-};
-
-
-/** Access to the block database (chain.dat) */
-class CBlockTreeDB : public CDB
-{
-public:
- CBlockTreeDB(const char* pszMode="r+") : CDB("blktree.dat", pszMode) { }
-private:
- CBlockTreeDB(const CBlockTreeDB&);
- void operator=(const CBlockTreeDB&);
-public:
- bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
- bool ReadBestInvalidTrust(CBigNum& bnBestInvalidTrust);
- bool WriteBestInvalidTrust(CBigNum bnBestInvalidTrust);
- bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo);
- bool WriteBlockFileInfo(int nFile, const CBlockFileInfo &fileinfo);
- bool ReadLastBlockFile(int &nFile);
- bool WriteLastBlockFile(int nFile);
- bool ReadSyncCheckpoint(uint256& hashCheckpoint);
- bool WriteSyncCheckpoint(uint256 hashCheckpoint);
- bool ReadCheckpointPubKey(std::string& strPubKey);
- bool WriteCheckpointPubKey(const std::string& strPubKey);
- bool LoadBlockIndexGuts();
-};
-
-
-bool LoadBlockIndexDB();
-
-
/** Access to the (IP) address database (peers.dat) */
class CAddrDB
{
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "db.h"
+#include "txdb.h"
#include "walletdb.h"
#include "bitcoinrpc.h"
#include "net.h"
uiInterface.InitMessage(_("Loading block index..."));
printf("Loading block index...\n");
nStart = GetTimeMillis();
- pblocktree = new CBlockTreeDB("cr+");
+ pblocktree = new CBlockTreeDB();
pcoinsdbview = new CCoinsViewDB();
pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
#include <leveldb/env.h>
#include <leveldb/cache.h>
#include <leveldb/filter_policy.h>
+#include <memenv/memenv.h>
#include <boost/filesystem.hpp>
return options;
}
-CLevelDB::CLevelDB(const boost::filesystem::path &path) {
+CLevelDB::CLevelDB(const boost::filesystem::path &path, bool fMemory) {
penv = NULL;
readoptions.verify_checksums = true;
iteroptions.verify_checksums = true;
syncoptions.sync = true;
options = GetOptions();
options.create_if_missing = true;
- boost::filesystem::create_directory(path);
- printf("Opening LevelDB in %s\n", path.string().c_str());
+ if (fMemory) {
+ penv = leveldb::NewMemEnv(leveldb::Env::Default());
+ options.env = penv;
+ } else {
+ boost::filesystem::create_directory(path);
+ printf("Opening LevelDB in %s\n", path.string().c_str());
+ }
leveldb::Status status = leveldb::DB::Open(options, path.string(), &pdb);
if (!status.ok())
throw std::runtime_error(strprintf("CLevelDB(): error opening database environment %s", status.ToString().c_str()));
leveldb::DB *pdb;
public:
- CLevelDB(const boost::filesystem::path &path);
+ CLevelDB(const boost::filesystem::path &path, bool fMemory = false);
~CLevelDB();
template<typename K, typename V> bool Read(const K& key, V& value) {
#include "alert.h"
#include "checkpoints.h"
#include "db.h"
+#include "txdb.h"
#include "net.h"
#include "init.h"
#include "ui_interface.h"
CBlockIndex *CCoinsView::GetBestBlock() { return NULL; }
bool CCoinsView::SetBestBlock(CBlockIndex *pindex) { return false; }
bool CCoinsView::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) { return false; }
+bool CCoinsView::GetStats(CCoinsStats &stats) { return false; }
CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { }
bool CCoinsViewBacked::GetCoins(uint256 txid, CCoins &coins) { return base->GetCoins(txid, coins); }
CBlockIndex *CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); }
bool CCoinsViewBacked::SetBestBlock(CBlockIndex *pindex) { return base->SetBestBlock(pindex); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
+bool CCoinsViewBacked::GetStats(CCoinsStats &stats) { return base->GetStats(stats); }
bool CCoinsViewBacked::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) { return base->BatchWrite(mapCoins, pindex); }
return OpenDiskFile(pos, "rev", fReadOnly);
}
+CBlockIndex * InsertBlockIndex(uint256 hash)
+{
+ if (hash == 0)
+ return NULL;
+
+ // Return existing
+ map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
+ if (mi != mapBlockIndex.end())
+ return (*mi).second;
+
+ // Create new
+ CBlockIndex* pindexNew = new CBlockIndex();
+ if (!pindexNew)
+ throw runtime_error("InsertBlockIndex() : new CBlockIndex failed");
+ mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
+ pindexNew->phashBlock = &((*mi).first);
+
+ return pindexNew;
+}
+
+bool static LoadBlockIndexDB()
+{
+ if (!pblocktree->LoadBlockIndexGuts())
+ return false;
+
+ if (fRequestShutdown)
+ return true;
+
+ // Calculate nChainTrust
+ vector<pair<int, CBlockIndex*> > 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->nChainTrust = (pindex->pprev ? pindex->pprev->nChainTrust : 0) + pindex->GetBlockTrust();
+ pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx;
+ if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS && !(pindex->nStatus & BLOCK_FAILED_MASK))
+ setBlockIndexValid.insert(pindex);
+
+ // Calculate stake modifier checksum
+ pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex);
+ if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum))
+ return error("LoadBlockIndexDB() : Failed stake modifier checkpoint height=%d, modifier=0x%016"PRI64x, pindex->nHeight, pindex->nStakeModifier);
+ }
+
+ // Load block file info
+ pblocktree->ReadLastBlockFile(nLastBlockFile);
+ printf("LoadBlockIndexDB(): last block file = %i\n", nLastBlockFile);
+ if (pblocktree->ReadBlockFileInfo(nLastBlockFile, infoLastBlockFile))
+ printf("LoadBlockIndexDB(): last block file: %s\n", infoLastBlockFile.ToString().c_str());
+
+ // Load hashBestChain pointer to end of best chain
+ pindexBest = pcoinsTip->GetBestBlock();
+ if (pindexBest == NULL)
+ {
+ if (pindexGenesisBlock == NULL)
+ return true;
+ return error("LoadBlockIndexDB() : hashBestChain not loaded");
+ }
+ hashBestChain = pindexBest->GetBlockHash();
+ nBestHeight = pindexBest->nHeight;
+ nBestChainTrust = pindexBest->nChainTrust;
+
+ // set 'next' pointers in best chain
+ CBlockIndex *pindex = pindexBest;
+ while(pindex != NULL && pindex->pprev != NULL) {
+ CBlockIndex *pindexPrev = pindex->pprev;
+ pindexPrev->pnext = pindex;
+ pindex = pindexPrev;
+ }
+ printf("LoadBlockIndexDB(): hashBestChain=%s height=%d date=%s\n",
+ hashBestChain.ToString().substr(0,20).c_str(), nBestHeight,
+ DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str());
+
+ // Load sync-checkpoint
+ if (!pblocktree->ReadSyncCheckpoint(Checkpoints::hashSyncCheckpoint))
+ return error("LoadBlockIndexDB() : hashSyncCheckpoint not loaded");
+ printf("LoadBlockIndexDB(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str());
+
+ // Load bnBestInvalidTrust, OK if it doesn't exist
+ CBigNum bnBestInvalidTrust;
+ pblocktree->ReadBestInvalidTrust(bnBestInvalidTrust);
+ nBestInvalidTrust = bnBestInvalidTrust.getuint256();
+
+ // Verify blocks in the best chain
+ int nCheckLevel = GetArg("-checklevel", 1);
+ int nCheckDepth = GetArg( "-checkblocks", 2500);
+ if (nCheckDepth == 0)
+ nCheckDepth = 1000000000; // suffices until the year 19000
+ if (nCheckDepth > nBestHeight)
+ nCheckDepth = nBestHeight;
+ printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
+ CBlockIndex* pindexFork = NULL;
+ for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
+ {
+ if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth)
+ break;
+ CBlock block;
+ if (!block.ReadFromDisk(pindex))
+ return error("LoadBlockIndexDB() : block.ReadFromDisk failed");
+ // check level 1: verify block validity
+ if (nCheckLevel>0 && !block.CheckBlock())
+ {
+ printf("LoadBlockIndexDB() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
+ pindexFork = pindex->pprev;
+ }
+ // TODO: stronger verifications
+ }
+ if (pindexFork && !fRequestShutdown)
+ {
+ // TODO: reorg back
+ return error("LoadBlockIndexDB(): chain database corrupted");
+ }
+
+ return true;
+}
+
+
bool LoadBlockIndex(bool fAllowNew)
{
CBigNum bnTrustedModulus;
// if checkpoint master key changed must reset sync-checkpoint
if (!pblocktree->ReadCheckpointPubKey(strPubKey) || strPubKey != CSyncCheckpoint::strMasterPubKey)
{
- // write checkpoint master key to db
- pblocktree->TxnBegin();
- if (!pblocktree->WriteCheckpointPubKey(CSyncCheckpoint::strMasterPubKey))
- return error("LoadBlockIndex() : failed to write new checkpoint master key to db");
- if (!pblocktree->TxnCommit())
- return error("LoadBlockIndex() : failed to commit new checkpoint master key to db");
+ {
+ LOCK(Checkpoints::cs_hashSyncCheckpoint);
+ // write checkpoint master key to db
+ if (!pblocktree->WriteCheckpointPubKey(CSyncCheckpoint::strMasterPubKey))
+ return error("LoadBlockIndex() : failed to write new checkpoint master key to db");
+ }
+
if ((!fTestNet) && !Checkpoints::ResetSyncCheckpoint())
return error("LoadBlockIndex() : failed to reset sync-checkpoint");
}
bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow);
bool SetBestChain(CBlockIndex* pindexNew);
bool ConnectBestBlock();
+CBlockIndex * InsertBlockIndex(uint256 hash);
uint256 WantedByOrphan(const CBlock* pblockOrphan);
const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake);
void StakeMiner(CWallet *pwallet);
extern CTxMemPool mempool;
+struct CCoinsStats
+{
+ int nHeight;
+ uint64 nTransactions;
+ uint64 nTransactionOutputs;
+ uint64 nSerializedSize;
+
+ CCoinsStats() : nHeight(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0) {}
+};
+
/** Abstract view on the open txout dataset. */
class CCoinsView
{
// Modify the currently active block index
virtual bool SetBestBlock(CBlockIndex *pindex);
virtual bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
+ virtual bool GetStats(CCoinsStats &stats);
};
/** CCoinsView backed by another CCoinsView */
bool SetBestBlock(CBlockIndex *pindex);
void SetBackend(CCoinsView &viewIn);
bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
+ bool GetStats(CCoinsStats &stats);
};
/** CCoinsView that adds a memory cache for transactions to another CCoinsView */
obj/key.o \
obj/db.o \
obj/leveldb.o \
+ obj/txdb.o \
obj/init.o \
obj/irc.o \
obj/keystore.o \
obj/key.o \
obj/db.o \
obj/leveldb.o \
+ obj/txdb.o \
obj/init.o \
obj/irc.o \
obj/keystore.o \
obj/key.o \
obj/db.o \
obj/leveldb.o \
+ obj/txdb.o \
obj/init.o \
obj/irc.o \
obj/keystore.o \
obj/key.o \
obj/db.o \
obj/leveldb.o \
+ obj/txdb.o \
obj/init.o \
obj/irc.o \
obj/keystore.o \
obj/key.o \
obj/db.o \
obj/leveldb.o \
+ obj/txdb.o \
obj/init.o \
obj/irc.o \
obj/keystore.o \
--- /dev/null
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2012 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "txdb.h"
+#include "main.h"
+
+using namespace std;
+
+void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
+ if (coins.IsPruned())
+ batch.Erase(make_pair('c', hash));
+ else
+ batch.Write(make_pair('c', hash), coins);
+}
+
+void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
+ batch.Write('B', hash);
+}
+
+CCoinsViewDB::CCoinsViewDB(bool fMemory) : db(GetDataDir() / "coins", fMemory) {
+}
+
+bool CCoinsViewDB::GetCoins(uint256 txid, CCoins &coins) {
+ return db.Read(make_pair('c', txid), coins);
+}
+
+bool CCoinsViewDB::SetCoins(uint256 txid, const CCoins &coins) {
+ CLevelDBBatch batch;
+ BatchWriteCoins(batch, txid, coins);
+ return db.WriteBatch(batch);
+}
+
+bool CCoinsViewDB::HaveCoins(uint256 txid) {
+ return db.Exists(make_pair('c', txid));
+}
+
+CBlockIndex *CCoinsViewDB::GetBestBlock() {
+ uint256 hashBestChain;
+ if (!db.Read('B', hashBestChain))
+ return NULL;
+ std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(hashBestChain);
+ if (it == mapBlockIndex.end())
+ return NULL;
+ return it->second;
+}
+
+bool CCoinsViewDB::SetBestBlock(CBlockIndex *pindex) {
+ CLevelDBBatch batch;
+ BatchWriteHashBestChain(batch, pindex->GetBlockHash());
+ return db.WriteBatch(batch);
+}
+
+bool CCoinsViewDB::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) {
+ printf("Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size());
+
+ CLevelDBBatch batch;
+ for (std::map<uint256, CCoins>::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
+ BatchWriteCoins(batch, it->first, it->second);
+ BatchWriteHashBestChain(batch, pindex->GetBlockHash());
+
+ return db.WriteBatch(batch);
+}
+
+CBlockTreeDB::CBlockTreeDB(bool fMemory) : CLevelDB(GetDataDir() / "blktree", fMemory) {
+}
+
+bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
+{
+ return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
+}
+
+bool CBlockTreeDB::ReadBestInvalidTrust(CBigNum& bnBestInvalidTrust)
+{
+ return Read('I', bnBestInvalidTrust);
+}
+
+bool CBlockTreeDB::WriteBestInvalidTrust(CBigNum bnBestInvalidTrust)
+{
+ return Write('I', bnBestInvalidTrust);
+}
+
+bool CBlockTreeDB::ReadSyncCheckpoint(uint256& hashCheckpoint)
+{
+ return Read('H', hashCheckpoint);
+}
+
+bool CBlockTreeDB::WriteSyncCheckpoint(uint256 hashCheckpoint)
+{
+ return Write('H', hashCheckpoint);
+}
+
+bool CBlockTreeDB::ReadCheckpointPubKey(string& strPubKey)
+{
+ return Read('K', strPubKey);
+}
+
+bool CBlockTreeDB::WriteCheckpointPubKey(const string& strPubKey)
+{
+ return Write('K', strPubKey);
+}
+
+bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
+ return Write(make_pair('f', nFile), info);
+}
+
+bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
+ return Read(make_pair('f', nFile), info);
+}
+
+bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
+ return Write('l', nFile);
+}
+
+bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
+ return Read('l', nFile);
+}
+
+bool CCoinsViewDB::GetStats(CCoinsStats &stats) {
+ leveldb::Iterator *pcursor = db.NewIterator();
+ pcursor->SeekToFirst();
+
+ while (pcursor->Valid()) {
+ try {
+ leveldb::Slice slKey = pcursor->key();
+ CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
+ char chType;
+ ssKey >> chType;
+ if (chType == 'c' && !fRequestShutdown) {
+ leveldb::Slice slValue = pcursor->value();
+ CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
+ CCoins coins;
+ ssValue >> coins;
+ uint256 txhash;
+ ssKey >> txhash;
+
+ stats.nTransactions++;
+ BOOST_FOREACH(const CTxOut &out, coins.vout) {
+ if (!out.IsNull())
+ stats.nTransactionOutputs++;
+ }
+ stats.nSerializedSize += 32 + slValue.size();
+ }
+ pcursor->Next();
+ } catch (std::exception &e) {
+ return error("%s() : deserialize error", __PRETTY_FUNCTION__);
+ }
+ }
+ delete pcursor;
+ stats.nHeight = GetBestBlock()->nHeight;
+ return true;
+}
+
+bool CBlockTreeDB::LoadBlockIndexGuts()
+{
+ leveldb::Iterator *pcursor = NewIterator();
+
+ CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
+ ssKeySet << make_pair('b', uint256(0));
+ pcursor->Seek(ssKeySet.str());
+
+ // Load mapBlockIndex
+ while (pcursor->Valid()) {
+ try {
+ leveldb::Slice slKey = pcursor->key();
+ CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
+ char chType;
+ ssKey >> chType;
+ if (chType == 'b' && !fRequestShutdown) {
+ leveldb::Slice slValue = pcursor->value();
+ CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
+ CDiskBlockIndex diskindex;
+ ssValue >> diskindex;
+
+ uint256 blockHash = diskindex.GetBlockHash();
+
+ // Construct block index object
+ CBlockIndex* pindexNew = InsertBlockIndex(blockHash);
+ pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
+ pindexNew->nHeight = diskindex.nHeight;
+ pindexNew->nFile = diskindex.nFile;
+ pindexNew->nDataPos = diskindex.nDataPos;
+ pindexNew->nUndoPos = diskindex.nUndoPos;
+ pindexNew->nMint = diskindex.nMint;
+ pindexNew->nMoneySupply = diskindex.nMoneySupply;
+ pindexNew->nFlags = diskindex.nFlags;
+ pindexNew->nStakeModifier = diskindex.nStakeModifier;
+ pindexNew->prevoutStake = diskindex.prevoutStake;
+ pindexNew->nStakeTime = diskindex.nStakeTime;
+ pindexNew->hashProofOfStake = diskindex.hashProofOfStake;
+ pindexNew->nVersion = diskindex.nVersion;
+ pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
+ pindexNew->nTime = diskindex.nTime;
+ pindexNew->nBits = diskindex.nBits;
+ pindexNew->nNonce = diskindex.nNonce;
+ pindexNew->nStatus = diskindex.nStatus;
+ pindexNew->nTx = diskindex.nTx;
+
+ // Watch for genesis block
+ if (pindexGenesisBlock == NULL && blockHash == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))
+ pindexGenesisBlock = pindexNew;
+
+ if (!pindexNew->CheckIndex())
+ return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString().c_str());
+
+ // Build setStakeSeen
+ if (pindexNew->IsProofOfStake())
+ setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime));
+
+ pcursor->Next();
+ } else {
+ break; // if shutdown requested or finished loading block index
+ }
+ } catch (std::exception &e) {
+ return error("%s() : deserialize error", __PRETTY_FUNCTION__);
+ }
+ }
+ delete pcursor;
+
+ return true;
+}
--- /dev/null
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2012 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#ifndef BITCOIN_TXDB_LEVELDB_H
+#define BITCOIN_TXDB_LEVELDB_H
+
+#include "main.h"
+#include "leveldb.h"
+
+/** CCoinsView backed by the LevelDB coin database (coins/) */
+class CCoinsViewDB : public CCoinsView
+{
+protected:
+ CLevelDB db;
+public:
+ CCoinsViewDB(bool fMemory = false);
+
+ bool GetCoins(uint256 txid, CCoins &coins);
+ bool SetCoins(uint256 txid, const CCoins &coins);
+ bool HaveCoins(uint256 txid);
+ CBlockIndex *GetBestBlock();
+ bool SetBestBlock(CBlockIndex *pindex);
+ bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
+ bool GetStats(CCoinsStats &stats);
+};
+
+/** Access to the block database (blktree/) */
+class CBlockTreeDB : public CLevelDB
+{
+public:
+ CBlockTreeDB(bool fMemory = false);
+private:
+ CBlockTreeDB(const CBlockTreeDB&);
+ void operator=(const CBlockTreeDB&);
+public:
+ bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
+ bool ReadBestInvalidTrust(CBigNum& bnBestInvalidTrust);
+ bool WriteBestInvalidTrust(CBigNum bnBestInvalidTrust);
+ bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo);
+ bool WriteBlockFileInfo(int nFile, const CBlockFileInfo &fileinfo);
+ bool ReadLastBlockFile(int &nFile);
+ bool WriteLastBlockFile(int nFile);
+ bool ReadSyncCheckpoint(uint256& hashCheckpoint);
+ bool WriteSyncCheckpoint(uint256 hashCheckpoint);
+ bool ReadCheckpointPubKey(std::string& strPubKey);
+ bool WriteCheckpointPubKey(const std::string& strPubKey);
+ bool LoadBlockIndexGuts();
+};
+
+#endif // BITCOIN_TXDB_LEVELDB_H