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