Branch data 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 : : // BytePrefix compares equality with other byte spans that begin with the same prefix.
24 : : struct BytePrefix {
25 : : Span<const std::byte> prefix;
26 : : };
27 : : bool operator<(BytePrefix a, Span<const std::byte> b);
28 : : bool operator<(Span<const std::byte> a, BytePrefix b);
29 : :
30 : : class DatabaseCursor
31 : : {
32 : : public:
33 [ + - ]: 1315 : explicit DatabaseCursor() = default;
34 : 1321 : 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 : 0 : 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 [ + - ]: 19876 : explicit DatabaseBatch() = default;
60 : 19876 : virtual ~DatabaseBatch() = default;
61 : :
62 : : DatabaseBatch(const DatabaseBatch&) = delete;
63 : : DatabaseBatch& operator=(const DatabaseBatch&) = delete;
64 : :
65 : : virtual void Flush() = 0;
66 : : virtual void Close() = 0;
67 : :
68 : : template <typename K, typename T>
69 : 206 : bool Read(const K& key, T& value)
70 : : {
71 [ + - ]: 206 : DataStream ssKey{};
72 [ + - ]: 206 : ssKey.reserve(1000);
73 : 206 : ssKey << key;
74 : :
75 : 206 : DataStream ssValue{};
76 [ + - + + ]: 206 : if (!ReadKey(std::move(ssKey), ssValue)) return false;
77 : : try {
78 : 40 : ssValue >> value;
79 : 14 : return true;
80 [ - - ]: 0 : } catch (const std::exception&) {
81 : : return false;
82 : : }
83 : 206 : }
84 : :
85 : : template <typename K, typename T>
86 : 45692 : bool Write(const K& key, const T& value, bool fOverwrite = true)
87 : : {
88 [ + - ]: 45692 : DataStream ssKey{};
89 [ + - ]: 45692 : ssKey.reserve(1000);
90 : 45692 : ssKey << key;
91 : :
92 [ + - ]: 45692 : DataStream ssValue{};
93 [ + - ]: 45692 : ssValue.reserve(10000);
94 : 45692 : ssValue << value;
95 : :
96 [ + - ]: 45692 : return WriteKey(std::move(ssKey), std::move(ssValue), fOverwrite);
97 : 45692 : }
98 : :
99 : : template <typename K>
100 : 5019 : bool Erase(const K& key)
101 : : {
102 [ + - ]: 5019 : DataStream ssKey{};
103 [ + - ]: 5019 : ssKey.reserve(1000);
104 : 5019 : ssKey << key;
105 : :
106 [ + - ]: 5019 : return EraseKey(std::move(ssKey));
107 : 5019 : }
108 : :
109 : : template <typename K>
110 : 15 : bool Exists(const K& key)
111 : : {
112 [ + - ]: 15 : DataStream ssKey{};
113 [ + - ]: 15 : ssKey.reserve(1000);
114 : 15 : ssKey << key;
115 : :
116 [ + - ]: 15 : return HasKey(std::move(ssKey));
117 : 15 : }
118 : : virtual bool ErasePrefix(Span<const std::byte> prefix) = 0;
119 : :
120 : : virtual std::unique_ptr<DatabaseCursor> GetNewCursor() = 0;
121 : : virtual std::unique_ptr<DatabaseCursor> GetNewPrefixCursor(Span<const std::byte> prefix) = 0;
122 : : virtual bool TxnBegin() = 0;
123 : : virtual bool TxnCommit() = 0;
124 : : virtual bool TxnAbort() = 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 [ + + ]: 135 : WalletDatabase() : nUpdateCounter(0) {}
134 : 135 : 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 : : /** Indicate the a new database user has began using the database. Increments m_refcount */
142 : : virtual void AddRef() = 0;
143 : : /** Indicate that database user has stopped using the database and that it could be flushed or closed. Decrement m_refcount */
144 : : virtual void RemoveRef() = 0;
145 : :
146 : : /** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero
147 : : */
148 : : virtual bool Rewrite(const char* pszSkip=nullptr) = 0;
149 : :
150 : : /** Back up the entire database to a file.
151 : : */
152 : : virtual bool Backup(const std::string& strDest) const = 0;
153 : :
154 : : /** Make sure all changes are flushed to database file.
155 : : */
156 : : virtual void Flush() = 0;
157 : : /** Flush to the database file and close the database.
158 : : * Also close the environment if no other databases are open in it.
159 : : */
160 : : virtual void Close() = 0;
161 : : /* flush the wallet passively (TRY_LOCK)
162 : : ideal to be called periodically */
163 : : virtual bool PeriodicFlush() = 0;
164 : :
165 : : virtual void IncrementUpdateCounter() = 0;
166 : :
167 : : virtual void ReloadDbEnv() = 0;
168 : :
169 : : /** Return path to main database file for logs and error messages. */
170 : : virtual std::string Filename() = 0;
171 : :
172 : : virtual std::string Format() = 0;
173 : :
174 : : std::atomic<unsigned int> nUpdateCounter;
175 : : unsigned int nLastSeen{0};
176 : : unsigned int nLastFlushed{0};
177 : : int64_t nLastWalletUpdate{0};
178 : :
179 : : /** Make a DatabaseBatch connected to this database */
180 : : virtual std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) = 0;
181 : : };
182 : :
183 : : enum class DatabaseFormat {
184 : : BERKELEY,
185 : : SQLITE,
186 : : BERKELEY_RO,
187 : : BERKELEY_SWAP,
188 : : };
189 : :
190 [ + - + - : 2378 : struct DatabaseOptions {
+ - ][ + -
+ - # # #
# # # ]
[ + - ][ # #
# # # # #
# ][ # # #
# # # #
# ]
191 : : bool require_existing = false;
192 : : bool require_create = false;
193 : : std::optional<DatabaseFormat> require_format;
194 : : uint64_t create_flags = 0;
195 : : SecureString create_passphrase;
196 : :
197 : : // Specialized options. Not every option is supported by every backend.
198 : : bool verify = true; //!< Check data integrity on load.
199 : : bool use_unsafe_sync = false; //!< Disable file sync for faster performance.
200 : : bool use_shared_memory = false; //!< Let other processes access the database.
201 : : int64_t max_log_mb = 100; //!< Max log size to allow before consolidating.
202 : : };
203 : :
204 : : enum class DatabaseStatus {
205 : : SUCCESS,
206 : : FAILED_BAD_PATH,
207 : : FAILED_BAD_FORMAT,
208 : : FAILED_ALREADY_LOADED,
209 : : FAILED_ALREADY_EXISTS,
210 : : FAILED_NOT_FOUND,
211 : : FAILED_CREATE,
212 : : FAILED_LOAD,
213 : : FAILED_VERIFY,
214 : : FAILED_ENCRYPT,
215 : : FAILED_INVALID_BACKUP_FILE,
216 : : };
217 : :
218 : : /** Recursively list database paths in directory. */
219 : : std::vector<std::pair<fs::path, std::string>> ListDatabases(const fs::path& path);
220 : :
221 : : void ReadDatabaseArgs(const ArgsManager& args, DatabaseOptions& options);
222 : : std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
223 : :
224 : : fs::path BDBDataFile(const fs::path& path);
225 : : fs::path SQLiteDataFile(const fs::path& path);
226 : : bool IsBDBFile(const fs::path& path);
227 : : bool IsSQLiteFile(const fs::path& path);
228 : : } // namespace wallet
229 : :
230 : : #endif // BITCOIN_WALLET_DB_H
|