aboutsummaryrefslogtreecommitdiff
path: root/src/txdb.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/txdb.cpp')
-rw-r--r--src/txdb.cpp189
1 files changed, 189 insertions, 0 deletions
diff --git a/src/txdb.cpp b/src/txdb.cpp
new file mode 100644
index 0000000000..67d15cb58f
--- /dev/null
+++ b/src/txdb.cpp
@@ -0,0 +1,189 @@
+// 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::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::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;
+
+ // 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() == 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;
+}