123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- // 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"
- #include "hash.h"
- #include "chainparams.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(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
- }
-
- bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) {
- return db.Read(make_pair('c', txid), coins);
- }
-
- bool CCoinsViewDB::SetCoins(const uint256 &txid, const CCoins &coins) {
- CLevelDBBatch batch;
- BatchWriteCoins(batch, txid, coins);
- return db.WriteBatch(batch);
- }
-
- bool CCoinsViewDB::HaveCoins(const 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);
- if (pindex)
- BatchWriteHashBestChain(batch, pindex->GetBlockHash());
-
- return db.WriteBatch(batch);
- }
-
- CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDB(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
- }
-
- bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
- {
- return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
- }
-
- bool CBlockTreeDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork)
- {
- return Read('I', bnBestInvalidWork);
- }
-
- bool CBlockTreeDB::WriteBestInvalidWork(const CBigNum& bnBestInvalidWork)
- {
- return Write('I', bnBestInvalidWork);
- }
-
- 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::WriteReindexing(bool fReindexing) {
- if (fReindexing)
- return Write('R', '1');
- else
- return Erase('R');
- }
-
- bool CBlockTreeDB::ReadReindexing(bool &fReindexing) {
- fReindexing = Exists('R');
- return true;
- }
-
- bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
- return Read('l', nFile);
- }
-
- bool CCoinsViewDB::GetStats(CCoinsStats &stats) {
- leveldb::Iterator *pcursor = db.NewIterator();
- pcursor->SeekToFirst();
-
- CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
- stats.hashBlock = GetBestBlock()->GetBlockHash();
- ss << stats.hashBlock;
- int64 nTotalAmount = 0;
- while (pcursor->Valid()) {
- boost::this_thread::interruption_point();
- 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') {
- 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;
- ss << txhash;
- ss << VARINT(coins.nVersion);
- ss << (coins.fCoinBase ? 'c' : 'n');
- ss << VARINT(coins.nHeight);
- stats.nTransactions++;
- for (unsigned int i=0; i<coins.vout.size(); i++) {
- const CTxOut &out = coins.vout[i];
- if (!out.IsNull()) {
- stats.nTransactionOutputs++;
- ss << VARINT(i+1);
- ss << out;
- nTotalAmount += out.nValue;
- }
- }
- stats.nSerializedSize += 32 + slValue.size();
- ss << VARINT(0);
- }
- pcursor->Next();
- } catch (std::exception &e) {
- return error("%s() : deserialize error", __PRETTY_FUNCTION__);
- }
- }
- delete pcursor;
- stats.nHeight = GetBestBlock()->nHeight;
- stats.hashSerialized = ss.GetHash();
- stats.nTotalAmount = nTotalAmount;
- return true;
- }
-
- bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
- return Read(make_pair('t', txid), pos);
- }
-
- bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
- CLevelDBBatch batch;
- for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
- batch.Write(make_pair('t', it->first), it->second);
- return WriteBatch(batch);
- }
-
- bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
- return Write(std::make_pair('F', name), fValue ? '1' : '0');
- }
-
- bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
- char ch;
- if (!Read(std::make_pair('F', name), ch))
- return false;
- fValue = ch == '1';
- 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()) {
- boost::this_thread::interruption_point();
- 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') {
- leveldb::Slice slValue = pcursor->value();
- CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
- CDiskBlockIndex diskindex;
- ssValue >> diskindex;
-
- // Construct block index object
- CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
- pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
- pindexNew->nHeight = diskindex.nHeight;
- pindexNew->nFile = diskindex.nFile;
- pindexNew->nDataPos = diskindex.nDataPos;
- pindexNew->nUndoPos = diskindex.nUndoPos;
- 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 && diskindex.GetBlockHash() == Params().HashGenesisBlock())
- pindexGenesisBlock = pindexNew;
-
- if (!pindexNew->CheckIndex())
- return error("LoadBlockIndex() : CheckIndex failed: %s", pindexNew->ToString().c_str());
-
- 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;
- }
|