Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto
2 : // Copyright (c) 2009-2020 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 <optional.h>
12 : #include <streams.h>
13 : #include <support/allocators/secure.h>
14 : #include <util/memory.h>
15 :
16 : #include <atomic>
17 : #include <memory>
18 : #include <string>
19 :
20 : struct bilingual_str;
21 :
22 : void SplitWalletPath(const fs::path& wallet_path, fs::path& env_directory, std::string& database_filename);
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 236355 : explicit DatabaseBatch() {}
35 236355 : 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 14371 : bool Read(const K& key, T& value)
45 : {
46 14371 : CDataStream ssKey(SER_DISK, CLIENT_VERSION);
47 14371 : ssKey.reserve(1000);
48 14371 : ssKey << key;
49 :
50 14371 : CDataStream ssValue(SER_DISK, CLIENT_VERSION);
51 14371 : if (!ReadKey(std::move(ssKey), ssValue)) return false;
52 : try {
53 13855 : ssValue >> value;
54 13855 : return true;
55 0 : } catch (const std::exception&) {
56 : return false;
57 0 : }
58 14371 : }
59 :
60 : template <typename K, typename T>
61 438450 : bool Write(const K& key, const T& value, bool fOverwrite = true)
62 : {
63 438450 : CDataStream ssKey(SER_DISK, CLIENT_VERSION);
64 438450 : ssKey.reserve(1000);
65 438450 : ssKey << key;
66 :
67 438450 : CDataStream ssValue(SER_DISK, CLIENT_VERSION);
68 438450 : ssValue.reserve(10000);
69 438450 : ssValue << value;
70 :
71 438450 : return WriteKey(std::move(ssKey), std::move(ssValue), fOverwrite);
72 438450 : }
73 :
74 : template <typename K>
75 10950 : bool Erase(const K& key)
76 : {
77 10950 : CDataStream ssKey(SER_DISK, CLIENT_VERSION);
78 10950 : ssKey.reserve(1000);
79 10950 : ssKey << key;
80 :
81 10950 : return EraseKey(std::move(ssKey));
82 10950 : }
83 :
84 : template <typename K>
85 671 : bool Exists(const K& key)
86 : {
87 671 : CDataStream ssKey(SER_DISK, CLIENT_VERSION);
88 671 : ssKey.reserve(1000);
89 671 : ssKey << key;
90 :
91 671 : return HasKey(std::move(ssKey));
92 671 : }
93 :
94 : virtual bool StartCursor() = 0;
95 : virtual bool ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete) = 0;
96 : virtual void CloseCursor() = 0;
97 : virtual bool TxnBegin() = 0;
98 : virtual bool TxnCommit() = 0;
99 : virtual bool TxnAbort() = 0;
100 : };
101 :
102 : /** An instance of this class represents one database.
103 : **/
104 : class WalletDatabase
105 : {
106 : public:
107 : /** Create dummy DB handle */
108 1148 : WalletDatabase() : nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0) {}
109 1148 : virtual ~WalletDatabase() {};
110 :
111 : /** Open the database if it is not already opened. */
112 : virtual void Open(const char* mode) = 0;
113 :
114 : //! Counts the number of active database users to be sure that the database is not closed while someone is using it
115 1148 : std::atomic<int> m_refcount{0};
116 : /** Indicate the a new database user has began using the database. Increments m_refcount */
117 : virtual void AddRef() = 0;
118 : /** Indicate that database user has stopped using the database and that it could be flushed or closed. Decrement m_refcount */
119 : virtual void RemoveRef() = 0;
120 :
121 : /** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero
122 : */
123 : virtual bool Rewrite(const char* pszSkip=nullptr) = 0;
124 :
125 : /** Back up the entire database to a file.
126 : */
127 : virtual bool Backup(const std::string& strDest) const = 0;
128 :
129 : /** Make sure all changes are flushed to database file.
130 : */
131 : virtual void Flush() = 0;
132 : /** Flush to the database file and close the database.
133 : * Also close the environment if no other databases are open in it.
134 : */
135 : virtual void Close() = 0;
136 : /* flush the wallet passively (TRY_LOCK)
137 : ideal to be called periodically */
138 : virtual bool PeriodicFlush() = 0;
139 :
140 : virtual void IncrementUpdateCounter() = 0;
141 :
142 : virtual void ReloadDbEnv() = 0;
143 :
144 : /** Return path to main database file for logs and error messages. */
145 : virtual std::string Filename() = 0;
146 :
147 : std::atomic<unsigned int> nUpdateCounter;
148 : unsigned int nLastSeen;
149 : unsigned int nLastFlushed;
150 : int64_t nLastWalletUpdate;
151 :
152 : /** Make a DatabaseBatch connected to this database */
153 : virtual std::unique_ptr<DatabaseBatch> MakeBatch(const char* mode = "r+", bool flush_on_close = true) = 0;
154 : };
155 :
156 : /** RAII class that provides access to a DummyDatabase. Never fails. */
157 550305 : class DummyBatch : public DatabaseBatch
158 : {
159 : private:
160 0 : bool ReadKey(CDataStream&& key, CDataStream& value) override { return true; }
161 220108 : bool WriteKey(CDataStream&& key, CDataStream&& value, bool overwrite=true) override { return true; }
162 0 : bool EraseKey(CDataStream&& key) override { return true; }
163 0 : bool HasKey(CDataStream&& key) override { return true; }
164 :
165 : public:
166 219 : void Flush() override {}
167 0 : void Close() override {}
168 :
169 0 : bool StartCursor() override { return true; }
170 0 : bool ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete) override { return true; }
171 0 : void CloseCursor() override {}
172 0 : bool TxnBegin() override { return true; }
173 0 : bool TxnCommit() override { return true; }
174 0 : bool TxnAbort() override { return true; }
175 : };
176 :
177 : /** A dummy WalletDatabase that does nothing and never fails. Only used by unit tests.
178 : **/
179 610 : class DummyDatabase : public WalletDatabase
180 : {
181 : public:
182 0 : void Open(const char* mode) override {};
183 0 : void AddRef() override {}
184 0 : void RemoveRef() override {}
185 0 : bool Rewrite(const char* pszSkip=nullptr) override { return true; }
186 0 : bool Backup(const std::string& strDest) const override { return true; }
187 0 : void Close() override {}
188 0 : void Flush() override {}
189 0 : bool PeriodicFlush() override { return true; }
190 220108 : void IncrementUpdateCounter() override { ++nUpdateCounter; }
191 0 : void ReloadDbEnv() override {}
192 0 : std::string Filename() override { return "dummy"; }
193 110061 : std::unique_ptr<DatabaseBatch> MakeBatch(const char* mode = "r+", bool flush_on_close = true) override { return MakeUnique<DummyBatch>(); }
194 : };
195 :
196 : enum class DatabaseFormat {
197 : BERKELEY,
198 : SQLITE,
199 : };
200 :
201 6192 : struct DatabaseOptions {
202 1032 : bool require_existing = false;
203 1032 : bool require_create = false;
204 : Optional<DatabaseFormat> require_format;
205 1032 : uint64_t create_flags = 0;
206 : SecureString create_passphrase;
207 1032 : bool verify = true;
208 : };
209 :
210 : enum class DatabaseStatus {
211 : SUCCESS,
212 : FAILED_BAD_PATH,
213 : FAILED_BAD_FORMAT,
214 : FAILED_ALREADY_LOADED,
215 : FAILED_ALREADY_EXISTS,
216 : FAILED_NOT_FOUND,
217 : FAILED_CREATE,
218 : FAILED_LOAD,
219 : FAILED_VERIFY,
220 : FAILED_ENCRYPT,
221 : };
222 :
223 : std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
224 :
225 : #endif // BITCOIN_WALLET_DB_H
|