db.h raw

   1  // Copyright (c) 2009-2010 Satoshi Nakamoto
   2  // Copyright (c) 2009-present The Bitcoin Core developers
   3  // Distributed under the MIT software license, see the accompanying
   4  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   5  
   6  #ifndef BITCOIN_WALLET_DB_H
   7  #define BITCOIN_WALLET_DB_H
   8  
   9  #include <clientversion.h>
  10  #include <streams.h>
  11  #include <support/allocators/secure.h>
  12  #include <util/fs.h>
  13  
  14  #include <atomic>
  15  #include <memory>
  16  #include <optional>
  17  #include <string>
  18  
  19  class ArgsManager;
  20  struct bilingual_str;
  21  
  22  namespace wallet {
  23  // BytePrefix compares equality with other byte spans that begin with the same prefix.
  24  struct BytePrefix {
  25      std::span<const std::byte> prefix;
  26  };
  27  bool operator<(BytePrefix a, std::span<const std::byte> b);
  28  bool operator<(std::span<const std::byte> a, BytePrefix b);
  29  
  30  class DatabaseCursor
  31  {
  32  public:
  33      explicit DatabaseCursor() = default;
  34      virtual ~DatabaseCursor() = default;
  35  
  36      DatabaseCursor(const DatabaseCursor&) = delete;
  37      DatabaseCursor& operator=(const DatabaseCursor&) = delete;
  38  
  39      enum class Status
  40      {
  41          FAIL,
  42          MORE,
  43          DONE,
  44      };
  45  
  46      virtual Status Next(DataStream& key, DataStream& value) { return Status::FAIL; }
  47  };
  48  
  49  /** RAII class that provides access to a WalletDatabase */
  50  class DatabaseBatch
  51  {
  52  private:
  53      virtual bool ReadKey(DataStream&& key, DataStream& value) = 0;
  54      virtual bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite = true) = 0;
  55      virtual bool EraseKey(DataStream&& key) = 0;
  56      virtual bool HasKey(DataStream&& key) = 0;
  57  
  58  public:
  59      explicit DatabaseBatch() = default;
  60      virtual ~DatabaseBatch() = default;
  61  
  62      DatabaseBatch(const DatabaseBatch&) = delete;
  63      DatabaseBatch& operator=(const DatabaseBatch&) = delete;
  64  
  65      virtual void Close() = 0;
  66  
  67      template <typename K, typename T>
  68      bool Read(const K& key, T& value)
  69      {
  70          DataStream ssKey{};
  71          ssKey.reserve(1000);
  72          ssKey << key;
  73  
  74          DataStream ssValue{};
  75          if (!ReadKey(std::move(ssKey), ssValue)) return false;
  76          try {
  77              ssValue >> value;
  78              return true;
  79          } catch (const std::exception&) {
  80              return false;
  81          }
  82      }
  83  
  84      template <typename K, typename T>
  85      bool Write(const K& key, const T& value, bool fOverwrite = true)
  86      {
  87          DataStream ssKey{};
  88          ssKey.reserve(1000);
  89          ssKey << key;
  90  
  91          DataStream ssValue{};
  92          ssValue.reserve(10000);
  93          ssValue << value;
  94  
  95          return WriteKey(std::move(ssKey), std::move(ssValue), fOverwrite);
  96      }
  97  
  98      template <typename K>
  99      bool Erase(const K& key)
 100      {
 101          DataStream ssKey{};
 102          ssKey.reserve(1000);
 103          ssKey << key;
 104  
 105          return EraseKey(std::move(ssKey));
 106      }
 107  
 108      template <typename K>
 109      bool Exists(const K& key)
 110      {
 111          DataStream ssKey{};
 112          ssKey.reserve(1000);
 113          ssKey << key;
 114  
 115          return HasKey(std::move(ssKey));
 116      }
 117      virtual bool ErasePrefix(std::span<const std::byte> prefix) = 0;
 118  
 119      virtual std::unique_ptr<DatabaseCursor> GetNewCursor() = 0;
 120      virtual std::unique_ptr<DatabaseCursor> GetNewPrefixCursor(std::span<const std::byte> prefix) = 0;
 121      virtual bool TxnBegin() = 0;
 122      virtual bool TxnCommit() = 0;
 123      virtual bool TxnAbort() = 0;
 124      virtual bool HasActiveTxn() = 0;
 125  };
 126  
 127  /** An instance of this class represents one database.
 128   **/
 129  class WalletDatabase
 130  {
 131  public:
 132      /** Create dummy DB handle */
 133      WalletDatabase() = default;
 134      virtual ~WalletDatabase() = default;
 135  
 136      /** Open the database if it is not already opened. */
 137      virtual void Open() = 0;
 138  
 139      //! Counts the number of active database users to be sure that the database is not closed while someone is using it
 140      std::atomic<int> m_refcount{0};
 141  
 142      /** Rewrite the entire database on disk
 143       */
 144      virtual bool Rewrite() = 0;
 145  
 146      /** Back up the entire database to a file.
 147       */
 148      virtual bool Backup(const std::string& strDest) const = 0;
 149  
 150      /** Flush to the database file and close the database.
 151       *  Also close the environment if no other databases are open in it.
 152       */
 153      virtual void Close() = 0;
 154  
 155      /** Return path to main database file for logs and error messages. */
 156      virtual std::string Filename() = 0;
 157  
 158      /** Return paths to all database created files */
 159      virtual std::vector<fs::path> Files() = 0;
 160  
 161      virtual std::string Format() = 0;
 162  
 163      /** Make a DatabaseBatch connected to this database */
 164      virtual std::unique_ptr<DatabaseBatch> MakeBatch() = 0;
 165  };
 166  
 167  enum class DatabaseFormat {
 168      SQLITE,
 169      BERKELEY_RO,
 170  };
 171  
 172  struct DatabaseOptions {
 173      bool require_existing = false;
 174      bool require_create = false;
 175      std::optional<DatabaseFormat> require_format;
 176      uint64_t create_flags = 0;
 177      SecureString create_passphrase;
 178  
 179      // Specialized options. Not every option is supported by every backend.
 180      bool verify = true;             //!< Check data integrity on load.
 181      bool use_unsafe_sync = false;   //!< Disable file sync for faster performance.
 182      bool use_shared_memory = false; //!< Let other processes access the database.
 183      int64_t max_log_mb = 100;       //!< Max log size to allow before consolidating.
 184  };
 185  
 186  enum class DatabaseStatus {
 187      SUCCESS,
 188      FAILED_BAD_PATH,
 189      FAILED_BAD_FORMAT,
 190      FAILED_LEGACY_DISABLED,
 191      FAILED_ALREADY_LOADED,
 192      FAILED_ALREADY_EXISTS,
 193      FAILED_NOT_FOUND,
 194      FAILED_CREATE,
 195      FAILED_LOAD,
 196      FAILED_VERIFY,
 197      FAILED_ENCRYPT,
 198      FAILED_INVALID_BACKUP_FILE,
 199      FAILED_NEW_UNNAMED,
 200  };
 201  
 202  /** Recursively list database paths in directory. */
 203  std::vector<std::pair<fs::path, std::string>> ListDatabases(const fs::path& path);
 204  
 205  void ReadDatabaseArgs(const ArgsManager& args, DatabaseOptions& options);
 206  std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
 207  
 208  fs::path BDBDataFile(const fs::path& path);
 209  fs::path SQLiteDataFile(const fs::path& path);
 210  bool IsBDBFile(const fs::path& path);
 211  bool IsSQLiteFile(const fs::path& path);
 212  } // namespace wallet
 213  
 214  #endif // BITCOIN_WALLET_DB_H
 215