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 : : 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
|