LCOV - code coverage report
Current view: top level - src - dbwrapper.h (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 35 87 40.2 %
Date: 2023-09-26 12:08:55 Functions: 14 57 24.6 %

          Line data    Source code
       1             : // Copyright (c) 2012-2022 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #ifndef BITCOIN_DBWRAPPER_H
       6             : #define BITCOIN_DBWRAPPER_H
       7             : 
       8             : #include <attributes.h>
       9             : #include <serialize.h>
      10             : #include <span.h>
      11             : #include <streams.h>
      12             : #include <util/check.h>
      13             : #include <util/fs.h>
      14             : 
      15             : #include <cstddef>
      16             : #include <exception>
      17             : #include <memory>
      18             : #include <optional>
      19             : #include <stdexcept>
      20             : #include <string>
      21             : #include <vector>
      22             : 
      23             : static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64;
      24             : static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024;
      25             : 
      26             : //! User-controlled performance and debug options.
      27           0 : struct DBOptions {
      28             :     //! Compact database on startup.
      29           0 :     bool force_compact = false;
      30             : };
      31             : 
      32             : //! Application-specific storage settings.
      33             : struct DBParams {
      34             :     //! Location in the filesystem where leveldb data will be stored.
      35             :     fs::path path;
      36             :     //! Configures various leveldb cache settings.
      37             :     size_t cache_bytes;
      38             :     //! If true, use leveldb's memory environment.
      39             :     bool memory_only = false;
      40             :     //! If true, remove all existing data.
      41             :     bool wipe_data = false;
      42             :     //! If true, store data obfuscated via simple XOR. If false, XOR with a
      43             :     //! zero'd byte array.
      44             :     bool obfuscate = false;
      45             :     //! Passed-through options.
      46             :     DBOptions options{};
      47             : };
      48             : 
      49             : class dbwrapper_error : public std::runtime_error
      50             : {
      51             : public:
      52           0 :     explicit dbwrapper_error(const std::string& msg) : std::runtime_error(msg) {}
      53             : };
      54             : 
      55             : class CDBWrapper;
      56             : 
      57             : /** These should be considered an implementation detail of the specific database.
      58             :  */
      59             : namespace dbwrapper_private {
      60             : 
      61             : /** Work around circular dependency, as well as for testing in dbwrapper_tests.
      62             :  * Database obfuscation should be considered an implementation detail of the
      63             :  * specific database.
      64             :  */
      65             : const std::vector<unsigned char>& GetObfuscateKey(const CDBWrapper &w);
      66             : 
      67             : }; // namespace dbwrapper_private
      68             : 
      69             : bool DestroyDB(const std::string& path_str);
      70             : 
      71             : /** Batch of changes queued to be written to a CDBWrapper */
      72             : class CDBBatch
      73             : {
      74             :     friend class CDBWrapper;
      75             : 
      76             : private:
      77             :     const CDBWrapper &parent;
      78             : 
      79             :     struct WriteBatchImpl;
      80             :     const std::unique_ptr<WriteBatchImpl> m_impl_batch;
      81             : 
      82             :     DataStream ssKey{};
      83             :     DataStream ssValue{};
      84             : 
      85             :     size_t size_estimate{0};
      86             : 
      87             :     void WriteImpl(Span<const std::byte> key, DataStream& ssValue);
      88             :     void EraseImpl(Span<const std::byte> key);
      89             : 
      90             : public:
      91             :     /**
      92             :      * @param[in] _parent   CDBWrapper that this batch is to be submitted to
      93             :      */
      94             :     explicit CDBBatch(const CDBWrapper& _parent);
      95             :     ~CDBBatch();
      96             :     void Clear();
      97             : 
      98             :     template <typename K, typename V>
      99           1 :     void Write(const K& key, const V& value)
     100             :     {
     101           1 :         ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
     102           1 :         ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE);
     103           1 :         ssKey << key;
     104           1 :         ssValue << value;
     105           1 :         WriteImpl(ssKey, ssValue);
     106           1 :         ssKey.clear();
     107           1 :         ssValue.clear();
     108           1 :     }
     109             : 
     110             :     template <typename K>
     111           0 :     void Erase(const K& key)
     112             :     {
     113           0 :         ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
     114           0 :         ssKey << key;
     115           0 :         EraseImpl(ssKey);
     116           0 :         ssKey.clear();
     117           0 :     }
     118             : 
     119           0 :     size_t SizeEstimate() const { return size_estimate; }
     120             : };
     121             : 
     122             : class CDBIterator
     123             : {
     124             : public:
     125             :     struct IteratorImpl;
     126             : 
     127             : private:
     128             :     const CDBWrapper &parent;
     129             :     const std::unique_ptr<IteratorImpl> m_impl_iter;
     130             : 
     131             :     void SeekImpl(Span<const std::byte> key);
     132             :     Span<const std::byte> GetKeyImpl() const;
     133             :     Span<const std::byte> GetValueImpl() const;
     134             : 
     135             : public:
     136             : 
     137             :     /**
     138             :      * @param[in] _parent          Parent CDBWrapper instance.
     139             :      * @param[in] _piter           The original leveldb iterator.
     140             :      */
     141             :     CDBIterator(const CDBWrapper& _parent, std::unique_ptr<IteratorImpl> _piter);
     142             :     ~CDBIterator();
     143             : 
     144             :     bool Valid() const;
     145             : 
     146             :     void SeekToFirst();
     147             : 
     148           2 :     template<typename K> void Seek(const K& key) {
     149           2 :         DataStream ssKey{};
     150           2 :         ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
     151           2 :         ssKey << key;
     152           2 :         SeekImpl(ssKey);
     153           2 :     }
     154             : 
     155             :     void Next();
     156             : 
     157           0 :     template<typename K> bool GetKey(K& key) {
     158             :         try {
     159           0 :             DataStream ssKey{GetKeyImpl()};
     160           0 :             ssKey >> key;
     161           0 :         } catch (const std::exception&) {
     162           0 :             return false;
     163           0 :         }
     164           0 :         return true;
     165           0 :     }
     166             : 
     167           0 :     template<typename V> bool GetValue(V& value) {
     168             :         try {
     169           0 :             DataStream ssValue{GetValueImpl()};
     170           0 :             ssValue.Xor(dbwrapper_private::GetObfuscateKey(parent));
     171           0 :             ssValue >> value;
     172           0 :         } catch (const std::exception&) {
     173           0 :             return false;
     174           0 :         }
     175           0 :         return true;
     176           0 :     }
     177             : };
     178             : 
     179             : struct LevelDBContext;
     180             : 
     181             : class CDBWrapper
     182             : {
     183             :     friend const std::vector<unsigned char>& dbwrapper_private::GetObfuscateKey(const CDBWrapper &w);
     184             : private:
     185             :     //! holds all leveldb-specific fields of this class
     186             :     std::unique_ptr<LevelDBContext> m_db_context;
     187             : 
     188             :     //! the name of this database
     189             :     std::string m_name;
     190             : 
     191             :     //! a key used for optional XOR-obfuscation of the database
     192             :     std::vector<unsigned char> obfuscate_key;
     193             : 
     194             :     //! the key under which the obfuscation key is stored
     195             :     static const std::string OBFUSCATE_KEY_KEY;
     196             : 
     197             :     //! the length of the obfuscate key in number of bytes
     198             :     static const unsigned int OBFUSCATE_KEY_NUM_BYTES;
     199             : 
     200             :     std::vector<unsigned char> CreateObfuscateKey() const;
     201             : 
     202             :     //! path to filesystem storage
     203             :     const fs::path m_path;
     204             : 
     205             :     //! whether or not the database resides in memory
     206             :     bool m_is_memory;
     207             : 
     208             :     std::optional<std::string> ReadImpl(Span<const std::byte> key) const;
     209             :     bool ExistsImpl(Span<const std::byte> key) const;
     210             :     size_t EstimateSizeImpl(Span<const std::byte> key1, Span<const std::byte> key2) const;
     211       38610 :     auto& DBContext() const LIFETIMEBOUND { return *Assert(m_db_context); }
     212             : 
     213             : public:
     214             :     CDBWrapper(const DBParams& params);
     215             :     ~CDBWrapper();
     216             : 
     217             :     CDBWrapper(const CDBWrapper&) = delete;
     218             :     CDBWrapper& operator=(const CDBWrapper&) = delete;
     219             : 
     220             :     template <typename K, typename V>
     221       19267 :     bool Read(const K& key, V& value) const
     222             :     {
     223       19267 :         DataStream ssKey{};
     224       19267 :         ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
     225       19267 :         ssKey << key;
     226       19267 :         std::optional<std::string> strValue{ReadImpl(ssKey)};
     227       19267 :         if (!strValue) {
     228       19267 :             return false;
     229             :         }
     230             :         try {
     231           0 :             DataStream ssValue{MakeByteSpan(*strValue)};
     232           0 :             ssValue.Xor(obfuscate_key);
     233           0 :             ssValue >> value;
     234           0 :         } catch (const std::exception&) {
     235           0 :             return false;
     236           0 :         }
     237           0 :         return true;
     238       19267 :     }
     239             : 
     240             :     template <typename K, typename V>
     241           1 :     bool Write(const K& key, const V& value, bool fSync = false)
     242             :     {
     243           1 :         CDBBatch batch(*this);
     244           1 :         batch.Write(key, value);
     245           1 :         return WriteBatch(batch, fSync);
     246           1 :     }
     247             : 
     248             :     //! @returns filesystem path to the on-disk data.
     249           0 :     std::optional<fs::path> StoragePath() {
     250           0 :         if (m_is_memory) {
     251           0 :             return {};
     252             :         }
     253           0 :         return m_path;
     254           0 :     }
     255             : 
     256             :     template <typename K>
     257           1 :     bool Exists(const K& key) const
     258             :     {
     259           1 :         DataStream ssKey{};
     260           1 :         ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
     261           1 :         ssKey << key;
     262           1 :         return ExistsImpl(ssKey);
     263           1 :     }
     264             : 
     265             :     template <typename K>
     266           0 :     bool Erase(const K& key, bool fSync = false)
     267             :     {
     268           0 :         CDBBatch batch(*this);
     269           0 :         batch.Erase(key);
     270           0 :         return WriteBatch(batch, fSync);
     271           0 :     }
     272             : 
     273             :     bool WriteBatch(CDBBatch& batch, bool fSync = false);
     274             : 
     275             :     // Get an estimate of LevelDB memory usage (in bytes).
     276             :     size_t DynamicMemoryUsage() const;
     277             : 
     278             :     CDBIterator* NewIterator();
     279             : 
     280             :     /**
     281             :      * Return true if the database managed by this class contains no entries.
     282             :      */
     283             :     bool IsEmpty();
     284             : 
     285             :     template<typename K>
     286           0 :     size_t EstimateSize(const K& key_begin, const K& key_end) const
     287             :     {
     288           0 :         DataStream ssKey1{}, ssKey2{};
     289           0 :         ssKey1.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
     290           0 :         ssKey2.reserve(DBWRAPPER_PREALLOC_KEY_SIZE);
     291           0 :         ssKey1 << key_begin;
     292           0 :         ssKey2 << key_end;
     293           0 :         return EstimateSizeImpl(ssKey1, ssKey2);
     294           0 :     }
     295             : };
     296             : 
     297             : #endif // BITCOIN_DBWRAPPER_H

Generated by: LCOV version 1.14