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