changeset 3660:ca9488dc3b38 draft

Remove BDB block database support
author Pieter Wuille <pieter.wuille@gmail.com>
date Tue, 16 Oct 2012 22:23:39 +0200
parents 7c2963c3101d
children d89dee56cd34 6ffdcd9b1fe7
files bitcoin-qt.pro src/makefile.linux-mingw src/makefile.mingw src/makefile.osx src/makefile.unix src/test/test_bitcoin.cpp src/txdb-bdb.cpp src/txdb-bdb.h src/txdb-leveldb.cpp src/txdb-leveldb.h src/txdb.cpp src/txdb.h
diffstat 12 files changed, 266 insertions(+), 539 deletions(-) [+]
line wrap: on
line diff
--- a/bitcoin-qt.pro
+++ b/bitcoin-qt.pro
@@ -90,33 +90,23 @@
     QTPLUGIN += qcncodecs qjpcodecs qtwcodecs qkrcodecs qtaccessiblewidgets
 }
 
-contains(USE_LEVELDB, -) {
-    message(Building without LevelDB)
-    SOURCES += src/txdb-bdb.cpp
-    HEADERS += src/txdb-bdb.h
+INCLUDEPATH += src/leveldb/include src/leveldb/helpers
+LIBS += $$PWD/src/leveldb/libleveldb.a $$PWD/src/leveldb/libmemenv.a
+!windows {
+    genleveldb.commands = cd $$PWD/src/leveldb ; $(MAKE) libleveldb.a libmemenv.a
 } else {
-    message(Building with LevelDB)
-    DEFINES += USE_LEVELDB
-    INCLUDEPATH += src/leveldb/include src/leveldb/helpers
-    LIBS += $$PWD/src/leveldb/libleveldb.a $$PWD/src/leveldb/libmemenv.a
-    SOURCES += src/leveldb.cpp src/txdb-leveldb.cpp
-    HEADERS += src/leveldb.h src/txdb-leveldb.h
-    !windows {
-        genleveldb.commands = cd $$PWD/src/leveldb ; $(MAKE) libleveldb.a libmemenv.a
-    } else {
-        # make an educated guess about what the ranlib command is called
-        isEmpty(QMAKE_RANLIB) {
-            QMAKE_RANLIB = $$replace(QMAKE_STRIP, strip, ranlib)
-        }
-        genleveldb.commands = cd $$PWD/src/leveldb ; CC=$$QMAKE_CC CXX=$$QMAKE_CXX TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="-I$$BOOST_INCLUDE_PATH" LDFLAGS="-L$$BOOST_LIB_PATH" $(MAKE) libleveldb.a libmemenv.a ; $$QMAKE_RANLIB $$PWD/src/leveldb/libleveldb.a ; $$QMAKE_RANLIB $$PWD/src/leveldb/libmemenv.a
+    # make an educated guess about what the ranlib command is called
+    isEmpty(QMAKE_RANLIB) {
+        QMAKE_RANLIB = $$replace(QMAKE_STRIP, strip, ranlib)
     }
-    genleveldb.target = $$PWD/src/leveldb/libleveldb.a
-    genleveldb.depends = FORCE
-    PRE_TARGETDEPS += $$PWD/src/leveldb/libleveldb.a
-    QMAKE_EXTRA_TARGETS += genleveldb
-    # Gross ugly hack that depends on qmake internals, unfortunately there's no other way to do it.
-    QMAKE_CLEAN += $$PWD/src/leveldb/libleveldb.a; cd $$PWD/src/leveldb ; $(MAKE) clean
+    genleveldb.commands = cd $$PWD/src/leveldb ; CC=$$QMAKE_CC CXX=$$QMAKE_CXX TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="-I$$BOOST_INCLUDE_PATH" LDFLAGS="-L$$BOOST_LIB_PATH" $(MAKE) libleveldb.a libmemenv.a ; $$QMAKE_RANLIB $$PWD/src/leveldb/libleveldb.a ; $$QMAKE_RANLIB $$PWD/src/leveldb/libmemenv.a
 }
+genleveldb.target = $$PWD/src/leveldb/libleveldb.a
+genleveldb.depends = FORCE
+PRE_TARGETDEPS += $$PWD/src/leveldb/libleveldb.a
+QMAKE_EXTRA_TARGETS += genleveldb
+# Gross ugly hack that depends on qmake internals, unfortunately there's no other way to do it.
+QMAKE_CLEAN += $$PWD/src/leveldb/libleveldb.a; cd $$PWD/src/leveldb ; $(MAKE) clean
 
 # regenerate src/build.h
 !windows|contains(USE_BUILD_INFO, 1) {
@@ -202,7 +192,9 @@
     src/qt/rpcconsole.h \
     src/version.h \
     src/netbase.h \
-    src/clientversion.h
+    src/clientversion.h \
+    src/txdb.h \
+    src/leveldb.h
 
 SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
     src/qt/transactiontablemodel.cpp \
@@ -262,7 +254,9 @@
     src/qt/notificator.cpp \
     src/qt/qtipcserver.cpp \
     src/qt/rpcconsole.cpp \
-    src/noui.cpp
+    src/noui.cpp \
+    src/leveldb.cpp \
+    src/txdb.cpp
 
 RESOURCES += \
     src/qt/bitcoin.qrc
--- a/src/makefile.linux-mingw
+++ b/src/makefile.linux-mingw
@@ -6,7 +6,6 @@
 
 USE_UPNP:=0
 USE_IPV6:=1
-USE_LEVELDB:=1
 
 INCLUDEPATHS= \
  -I"$(CURDIR)" \
@@ -83,21 +82,18 @@
     obj/util.o \
     obj/wallet.o \
     obj/walletdb.o \
-    obj/noui.o
+    obj/noui.o \
+    obj/leveldb.o \
+    obj/txdb.o
 
 all: bitcoind.exe
 
-ifdef USE_LEVELDB
 LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
-DEFS += -I"$(CURDIR)/leveldb/include" -DUSE_LEVELDB
+DEFS += -I"$(CURDIR)/leveldb/include"
 DEFS += -I"$(CURDIR)/leveldb/helpers"
-OBJS += obj/leveldb.o obj/txdb-leveldb.o
 leveldb/libleveldb.a:
 	@echo "Building LevelDB ..."; cd leveldb; TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="-I$(INCLUDEPATHS)" LDFLAGS="-L$(LIBPATHS)" make libleveldb.a libmemenv.a; cd ..
 obj/leveldb.o: leveldb/libleveldb.a
-else
-OBJS += obj/txdb-bdb.o
-endif
 
 obj/build.h: FORCE
 	/bin/sh ../share/genbuild.sh obj/build.h
--- a/src/makefile.mingw
+++ b/src/makefile.mingw
@@ -4,7 +4,6 @@
 
 USE_UPNP:=0
 USE_IPV6:=1
-USE_LEVELDB:=1
 
 INCLUDEPATHS= \
  -I"C:\boost-1.50.0-mgw" \
@@ -79,7 +78,9 @@
     obj/util.o \
     obj/wallet.o \
     obj/walletdb.o \
-    obj/noui.o
+    obj/noui.o \
+    obj/leveldb.o \
+    obj/txdb.o
 
 
 all: bitcoind.exe
@@ -90,17 +91,12 @@
 #
 # LevelDB support
 #
-ifdef USE_LEVELDB
 LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
-DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) -DUSE_LEVELDB
+DEFS += $(addprefix -I,$(CURDIR)/leveldb/include)
 DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
-OBJS += obj/leveldb.o obj/txdb-leveldb.o
 leveldb/libleveldb.a:
     cd leveldb; make libleveldb.a libmemenv.a; cd ..
 obj/leveldb.o: leveldb/libleveldb.lib
-else
-OBJS += obj/txdb-bdb.o
-endif
 
 obj/%.o: %.cpp $(HEADERS)
 	g++ -c $(CFLAGS) -o $@ $<
--- a/src/makefile.osx
+++ b/src/makefile.osx
@@ -21,7 +21,6 @@
 
 USE_UPNP:=1
 USE_IPV6:=1
-USE_LEVELDB:=1
 
 LIBS= -dead_strip
 
@@ -97,7 +96,9 @@
     obj/util.o \
     obj/wallet.o \
     obj/walletdb.o \
-    obj/noui.o
+    obj/noui.o \
+    obj/leveldb.o \
+    obj/txdb.o
 
 ifndef USE_UPNP
 	override USE_UPNP = -
@@ -123,17 +124,12 @@
 #
 # LevelDB support
 #
-ifdef USE_LEVELDB
 LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
-DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) -DUSE_LEVELDB
+DEFS += $(addprefix -I,$(CURDIR)/leveldb/include)
 DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
-OBJS += obj/leveldb.o obj/txdb-leveldb.o
 leveldb/libleveldb.a:
 	@echo "Building LevelDB ..."; cd leveldb; make libleveldb.a libmemenv.a; cd ..
 obj/leveldb.o: leveldb/libleveldb.a
-else
-OBJS += obj/txdb-bdb.o
-endif
 
 # auto-generated dependencies:
 -include obj/*.P
--- a/src/makefile.unix
+++ b/src/makefile.unix
@@ -4,7 +4,6 @@
 
 USE_UPNP:=0
 USE_IPV6:=1
-USE_LEVELDB:=1
 
 LINK:=$(CXX)
 
@@ -128,7 +127,9 @@
     obj/util.o \
     obj/wallet.o \
     obj/walletdb.o \
-    obj/noui.o
+    obj/noui.o \
+    obj/leveldb.o \
+    obj/txdb.o
 
 
 all: bitcoind
@@ -139,17 +140,12 @@
 #
 # LevelDB support
 #
-ifdef USE_LEVELDB
 LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
-DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) -DUSE_LEVELDB
+DEFS += $(addprefix -I,$(CURDIR)/leveldb/include)
 DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
-OBJS += obj/leveldb.o obj/txdb-leveldb.o
 leveldb/libleveldb.a:
 	@echo "Building LevelDB ..."; cd leveldb; make libleveldb.a libmemenv.a; cd ..;
 obj/leveldb.o: leveldb/libleveldb.a
-else
-OBJS += obj/txdb-bdb.o
-endif
 
 # auto-generated dependencies:
 -include obj/*.P
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -19,13 +19,8 @@
         fPrintToDebugger = true; // don't want to write to debug.log file
         noui_connect();
         bitdb.MakeMock();
-#ifdef USE_LEVELDB
         pblocktree = new CBlockTreeDB(true);
         pcoinsdbview = new CCoinsViewDB(true);
-#else
-        pblocktree = new CBlockTreeDB();
-        pcoinsdbview = new CCoinsViewDB();
-#endif
         pcoinsTip = new CCoinsViewCache(*pcoinsdbview);
         LoadBlockIndex(true);
         bool fFirstRun;
deleted file mode 100644
--- a/src/txdb-bdb.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-// 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-bdb.h"
-
-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 CCoinsDB::ReadHashBestChain(uint256& hashBestChain)
-{
-    return Read('B', hashBestChain);
-}
-
-bool CCoinsDB::WriteHashBestChain(uint256 hashBestChain)
-{
-    return Write('B', hashBestChain);
-}
-
-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(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);
-}
-
-CCoinsViewDB::CCoinsViewDB() : db() {}
-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;
-}
-
-
-bool CBlockTreeDB::LoadBlockIndexGuts()
-{
-    // Get database cursor
-    Dbc* pcursor = GetCursor();
-    if (!pcursor)
-        return false;
-
-    // Load mapBlockIndex
-    unsigned int fFlags = DB_SET_RANGE;
-    loop
-    {
-        // 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;
-
-            // 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());
-        }
-        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;
-}
deleted file mode 100644
--- a/src/txdb-bdb.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// 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_BDB_H
-#define BITCOIN_TXDB_BDB_H
-
-#include "db.h"
-
-/** Access to the transaction database (coins.dat) */
-class CCoinsDB : public CDB
-{
-public:
-    CCoinsDB() : CDB("coins.dat", "cr+") { }
-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 (blktree.dat) */
-class CBlockTreeDB : public CDB
-{
-public:
-    CBlockTreeDB() : CDB("blktree.dat", "cr+") { }
-private:
-    CBlockTreeDB(const CBlockTreeDB&);
-    void operator=(const CBlockTreeDB&);
-public:
-    bool WriteBlockIndex(const CDiskBlockIndex& blockindex);
-    bool ReadBestInvalidWork(CBigNum& bnBestInvalidWork);
-    bool WriteBestInvalidWork(CBigNum bnBestInvalidWork);
-    bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo);
-    bool WriteBlockFileInfo(int nFile, const CBlockFileInfo &fileinfo);
-    bool ReadLastBlockFile(int &nFile);
-    bool WriteLastBlockFile(int nFile);
-    bool LoadBlockIndexGuts();
-};
-
-#endif // BITCOIN_TXDB_BDB_H
deleted file mode 100644
--- a/src/txdb-leveldb.cpp
+++ /dev/null
@@ -1,189 +0,0 @@
-// 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-leveldb.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;
-}
deleted file mode 100644
--- a/src/txdb-leveldb.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// 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 ReadBestInvalidWork(CBigNum& bnBestInvalidWork);
-    bool WriteBestInvalidWork(const CBigNum& bnBestInvalidWork);
-    bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo);
-    bool WriteBlockFileInfo(int nFile, const CBlockFileInfo &fileinfo);
-    bool ReadLastBlockFile(int &nFile);
-    bool WriteLastBlockFile(int nFile);
-    bool LoadBlockIndexGuts();
-};
-
-#endif // BITCOIN_TXDB_LEVELDB_H
new file mode 100644
--- /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;
+}
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -2,13 +2,46 @@
 // 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_H
-#define BITCOIN_TXDB_H
+#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);
 
-#ifdef USE_LEVELDB
-#include "txdb-leveldb.h"
-#else
-#include "txdb-bdb.h"
-#endif
+    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);
+};
 
-#endif // BITCOIN_TXDB_H
+/** 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 ReadBestInvalidWork(CBigNum& bnBestInvalidWork);
+    bool WriteBestInvalidWork(const CBigNum& bnBestInvalidWork);
+    bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo);
+    bool WriteBlockFileInfo(int nFile, const CBlockFileInfo &fileinfo);
+    bool ReadLastBlockFile(int &nFile);
+    bool WriteLastBlockFile(int nFile);
+    bool LoadBlockIndexGuts();
+};
+
+#endif // BITCOIN_TXDB_LEVELDB_H