Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto 2 : // Copyright (c) 2009-2021 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 <fs.h> 11 : #include <streams.h> 12 : #include <support/allocators/secure.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 : 24 : /** RAII class that provides access to a WalletDatabase */ 25 : class DatabaseBatch 26 : { 27 : private: 28 : virtual bool ReadKey(CDataStream&& key, CDataStream& value) = 0; 29 : virtual bool WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite=true) = 0; 30 : virtual bool EraseKey(CDataStream&& key) = 0; 31 : virtual bool HasKey(CDataStream&& key) = 0; 32 : 33 : public: 34 450613 : explicit DatabaseBatch() {} 35 450612 : virtual ~DatabaseBatch() {} 36 : 37 : DatabaseBatch(const DatabaseBatch&) = delete; 38 : DatabaseBatch& operator=(const DatabaseBatch&) = delete; 39 : 40 : virtual void Flush() = 0; 41 : virtual void Close() = 0; 42 : 43 : template <typename K, typename T> 44 41878 : bool Read(const K& key, T& value) 45 : { 46 41878 : CDataStream ssKey(SER_DISK, CLIENT_VERSION); 47 41878 : ssKey.reserve(1000); 48 41878 : ssKey << key; 49 : 50 41878 : CDataStream ssValue(SER_DISK, CLIENT_VERSION); 51 41878 : if (!ReadKey(std::move(ssKey), ssValue)) return false; 52 : try { 53 35617 : ssValue >> value; 54 35617 : return true; 55 0 : } catch (const std::exception&) { 56 0 : return false; 57 0 : } 58 41878 : } 59 : 60 : template <typename K, typename T> 61 570323 : bool Write(const K& key, const T& value, bool fOverwrite = true) 62 : { 63 570323 : CDataStream ssKey(SER_DISK, CLIENT_VERSION); 64 570323 : ssKey.reserve(1000); 65 570323 : ssKey << key; 66 : 67 570323 : CDataStream ssValue(SER_DISK, CLIENT_VERSION); 68 570323 : ssValue.reserve(10000); 69 570323 : ssValue << value; 70 : 71 570323 : return WriteKey(std::move(ssKey), std::move(ssValue), fOverwrite); 72 570323 : } 73 : 74 : template <typename K> 75 23359 : bool Erase(const K& key) 76 : { 77 23359 : CDataStream ssKey(SER_DISK, CLIENT_VERSION); 78 23359 : ssKey.reserve(1000); 79 23359 : ssKey << key; 80 : 81 23359 : return EraseKey(std::move(ssKey)); 82 23359 : } 83 : 84 : template <typename K> 85 : bool Exists(const K& key) 86 : { 87 : CDataStream ssKey(SER_DISK, CLIENT_VERSION); 88 : ssKey.reserve(1000); 89 : ssKey << key; 90 : 91 : return HasKey(std::move(ssKey)); 92 : } 93 : virtual bool ErasePrefix(Span<const std::byte> prefix) = 0; 94 : 95 : virtual bool StartCursor() = 0; 96 : virtual bool ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete) = 0; 97 : virtual void CloseCursor() = 0; 98 : virtual bool TxnBegin() = 0; 99 : virtual bool TxnCommit() = 0; 100 : virtual bool TxnAbort() = 0; 101 : }; 102 : 103 : /** An instance of this class represents one database. 104 : **/ 105 : class WalletDatabase 106 : { 107 : public: 108 : /** Create dummy DB handle */ 109 9075 : WalletDatabase() : nUpdateCounter(0) {} 110 3025 : virtual ~WalletDatabase() {}; 111 : 112 : /** Open the database if it is not already opened. */ 113 : virtual void Open() = 0; 114 : 115 : //! Counts the number of active database users to be sure that the database is not closed while someone is using it 116 3025 : std::atomic<int> m_refcount{0}; 117 : /** Indicate the a new database user has began using the database. Increments m_refcount */ 118 : virtual void AddRef() = 0; 119 : /** Indicate that database user has stopped using the database and that it could be flushed or closed. Decrement m_refcount */ 120 : virtual void RemoveRef() = 0; 121 : 122 : /** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero 123 : */ 124 : virtual bool Rewrite(const char* pszSkip=nullptr) = 0; 125 : 126 : /** Back up the entire database to a file. 127 : */ 128 : virtual bool Backup(const std::string& strDest) const = 0; 129 : 130 : /** Make sure all changes are flushed to database file. 131 : */ 132 : virtual void Flush() = 0; 133 : /** Flush to the database file and close the database. 134 : * Also close the environment if no other databases are open in it. 135 : */ 136 : virtual void Close() = 0; 137 : /* flush the wallet passively (TRY_LOCK) 138 : ideal to be called periodically */ 139 : virtual bool PeriodicFlush() = 0; 140 : 141 : virtual void IncrementUpdateCounter() = 0; 142 : 143 : virtual void ReloadDbEnv() = 0; 144 : 145 : /** Return path to main database file for logs and error messages. */ 146 : virtual std::string Filename() = 0; 147 : 148 : virtual std::string Format() = 0; 149 : 150 : std::atomic<unsigned int> nUpdateCounter; 151 3025 : unsigned int nLastSeen{0}; 152 3025 : unsigned int nLastFlushed{0}; 153 3025 : int64_t nLastWalletUpdate{0}; 154 : 155 : /** Make a DatabaseBatch connected to this database */ 156 : virtual std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) = 0; 157 : 158 1209 : virtual bool SupportsAutoBackup() { return false; } 159 : }; 160 : 161 : /** RAII class that provides access to a DummyDatabase. Never fails. */ 162 : class DummyBatch : public DatabaseBatch 163 : { 164 : private: 165 0 : bool ReadKey(CDataStream&& key, CDataStream& value) override { return true; } 166 124 : bool WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite=true) override { return true; } 167 0 : bool EraseKey(CDataStream&& key) override { return true; } 168 0 : bool HasKey(CDataStream&& key) override { return true; } 169 0 : bool ErasePrefix(Span<const std::byte> prefix) override { return true; } 170 : 171 : public: 172 0 : void Flush() override {} 173 0 : void Close() override {} 174 : 175 0 : bool StartCursor() override { return true; } 176 0 : bool ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete) override { return true; } 177 0 : void CloseCursor() override {} 178 0 : bool TxnBegin() override { return true; } 179 0 : bool TxnCommit() override { return true; } 180 0 : bool TxnAbort() override { return true; } 181 : }; 182 : 183 : /** A dummy WalletDatabase that does nothing and never fails. Only used by unit tests. 184 : **/ 185 : class DummyDatabase : public WalletDatabase 186 : { 187 : public: 188 0 : void Open() override {}; 189 0 : void AddRef() override {} 190 0 : void RemoveRef() override {} 191 0 : bool Rewrite(const char* pszSkip=nullptr) override { return true; } 192 0 : bool Backup(const std::string& strDest) const override { return true; } 193 0 : void Close() override {} 194 0 : void Flush() override {} 195 0 : bool PeriodicFlush() override { return true; } 196 124 : void IncrementUpdateCounter() override { ++nUpdateCounter; } 197 0 : void ReloadDbEnv() override {} 198 0 : std::string Filename() override { return "dummy"; } 199 0 : std::string Format() override { return "dummy"; } 200 85 : std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override { return std::make_unique<DummyBatch>(); } 201 : }; 202 : 203 : enum class DatabaseFormat { 204 : BERKELEY, 205 : SQLITE, 206 : }; 207 : 208 34251 : struct DatabaseOptions { 209 11417 : bool require_existing = false; 210 11417 : bool require_create = false; 211 : std::optional<DatabaseFormat> require_format; 212 11417 : uint64_t create_flags = 0; 213 : SecureString create_passphrase; 214 : 215 : // Specialized options. Not every option is supported by every backend. 216 11417 : bool verify = true; //!< Check data integrity on load. 217 11417 : bool use_unsafe_sync = false; //!< Disable file sync for faster performance. 218 11417 : bool use_shared_memory = false; //!< Let other processes access the database. 219 11417 : int64_t max_log_mb = 100; //!< Max log size to allow before consolidating. 220 : }; 221 : 222 : enum class DatabaseStatus { 223 : SUCCESS, 224 : FAILED_BAD_PATH, 225 : FAILED_BAD_FORMAT, 226 : FAILED_ALREADY_LOADED, 227 : FAILED_ALREADY_EXISTS, 228 : FAILED_NOT_FOUND, 229 : FAILED_CREATE, 230 : FAILED_LOAD, 231 : FAILED_VERIFY, 232 : FAILED_ENCRYPT, 233 : FAILED_INVALID_BACKUP_FILE, 234 : }; 235 : 236 : /** Recursively list database paths in directory. */ 237 : std::vector<fs::path> ListDatabases(const fs::path& path); 238 : 239 : void ReadDatabaseArgs(const ArgsManager& args, DatabaseOptions& options); 240 : std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); 241 : 242 : fs::path BDBDataFile(const fs::path& path); 243 : fs::path SQLiteDataFile(const fs::path& path); 244 : bool IsBDBFile(const fs::path& path); 245 : bool IsSQLiteFile(const fs::path& path); 246 : } // namespace wallet 247 : 248 : #endif // BITCOIN_WALLET_DB_H