From 0d81464be78ce83545132dfdf1c359868063cc8f Mon Sep 17 00:00:00 2001 From: James O'Beirne Date: Mon, 7 Sep 2015 15:22:23 -0700 Subject: [PATCH] Refactor leveldbwrapper Was "Add chainstate obfuscation to avoid spurious antivirus detection" Zcash: Extracted the refactor, omitting the chainstate obfuscation. --- src/Makefile.test.include | 1 + src/leveldbwrapper.cpp | 8 ++++++ src/leveldbwrapper.h | 13 +++++++++ src/test/leveldbwrapper_tests.cpp | 45 +++++++++++++++++++++++++++++++ src/txdb.cpp | 21 +++++---------- 5 files changed, 74 insertions(+), 14 deletions(-) create mode 100644 src/test/leveldbwrapper_tests.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 582ecb577..02ae5ad3e 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -60,6 +60,7 @@ BITCOIN_TESTS =\ test/getarg_tests.cpp \ test/hash_tests.cpp \ test/key_tests.cpp \ + test/leveldbwrapper_tests.cpp \ test/main_tests.cpp \ test/mempool_tests.cpp \ test/miner_tests.cpp \ diff --git a/src/leveldbwrapper.cpp b/src/leveldbwrapper.cpp index b5d024abb..22658b092 100644 --- a/src/leveldbwrapper.cpp +++ b/src/leveldbwrapper.cpp @@ -12,6 +12,7 @@ #include #include #include +#include void HandleError(const leveldb::Status& status) { @@ -87,3 +88,10 @@ bool CLevelDBWrapper::WriteBatch(CLevelDBBatch& batch, bool fSync) HandleError(status); return true; } + +bool CLevelDBWrapper::IsEmpty() +{ + boost::scoped_ptr it(NewIterator()); + it->SeekToFirst(); + return !(it->Valid()); +} diff --git a/src/leveldbwrapper.h b/src/leveldbwrapper.h index 639f736a5..2bcef7daf 100644 --- a/src/leveldbwrapper.h +++ b/src/leveldbwrapper.h @@ -86,6 +86,12 @@ private: leveldb::DB* pdb; public: + /** + * @param[in] path Location in the filesystem where leveldb data will be stored. + * @param[in] nCacheSize Configures various leveldb cache settings. + * @param[in] fMemory If true, use leveldb's memory environment. + * @param[in] fWipe If true, remove all existing data. + */ CLevelDBWrapper(const boost::filesystem::path& path, size_t nCacheSize, bool fMemory = false, bool fWipe = false); ~CLevelDBWrapper(); @@ -168,6 +174,13 @@ public: { return pdb->NewIterator(iteroptions); } + + /** + * Return true if the database managed by this class contains no entries. + */ + bool IsEmpty(); + }; #endif // BITCOIN_LEVELDBWRAPPER_H + diff --git a/src/test/leveldbwrapper_tests.cpp b/src/test/leveldbwrapper_tests.cpp new file mode 100644 index 000000000..3fa74573f --- /dev/null +++ b/src/test/leveldbwrapper_tests.cpp @@ -0,0 +1,45 @@ +// Copyright (c) 2012-2013 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "leveldbwrapper.h" +#include "uint256.h" +#include "random.h" +#include "test/test_bitcoin.h" + +#include // for 'operator+=()' +#include +#include + +using namespace std; +using namespace boost::assign; // bring 'operator+=()' into scope +using namespace boost::filesystem; + +// Test if a string consists entirely of null characters +bool is_null_key(const vector& key) { + bool isnull = true; + + for (unsigned int i = 0; i < key.size(); i++) + isnull &= (key[i] == '\x00'); + + return isnull; +} + +BOOST_FIXTURE_TEST_SUITE(leveldbwrapper_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(leveldbwrapper) +{ + { + path ph = temp_directory_path() / unique_path(); + CLevelDBWrapper dbw(ph, (1 << 20), true, false); + char key = 'k'; + uint256 in = GetRandHash(); + uint256 res; + + BOOST_CHECK(dbw.Write(key, in)); + BOOST_CHECK(dbw.Read(key, res)); + BOOST_CHECK_EQUAL(res.ToString(), in.ToString()); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/txdb.cpp b/src/txdb.cpp index a40df59aa..3ca19a356 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -50,17 +50,6 @@ void static BatchWriteNullifier(CLevelDBBatch &batch, const uint256 &nf, const b batch.Write(make_pair(DB_NULLIFIER, nf), true); } -void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) { - if (coins.IsPruned()) - batch.Erase(make_pair(DB_COINS, hash)); - else - batch.Write(make_pair(DB_COINS, hash), coins); -} - -void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) { - batch.Write(DB_BEST_BLOCK, hash); -} - void static BatchWriteHashBestAnchor(CLevelDBBatch &batch, const uint256 &hash) { batch.Write(DB_BEST_ANCHOR, hash); } @@ -68,7 +57,8 @@ void static BatchWriteHashBestAnchor(CLevelDBBatch &batch, const uint256 &hash) CCoinsViewDB::CCoinsViewDB(std::string dbName, size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / dbName, nCacheSize, fMemory, fWipe) { } -CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) { +CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) +{ } @@ -123,7 +113,10 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, size_t changed = 0; for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { if (it->second.flags & CCoinsCacheEntry::DIRTY) { - BatchWriteCoins(batch, it->first, it->second.coins); + if (it->second.coins.IsPruned()) + batch.Erase(make_pair(DB_COINS, it->first)); + else + batch.Write(make_pair(DB_COINS, it->first), it->second.coins); changed++; } count++; @@ -150,7 +143,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, } if (!hashBlock.IsNull()) - BatchWriteHashBestChain(batch, hashBlock); + batch.Write(DB_BEST_BLOCK, hashBlock); if (!hashAnchor.IsNull()) BatchWriteHashBestAnchor(batch, hashAnchor);