Branch data Line data Source code
1 : : // Copyright (c) 2020-present The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #include <bitcoin-build-config.h> // IWYU pragma: keep
6 : :
7 : : #include <wallet/sqlite.h>
8 : :
9 : : #include <chainparams.h>
10 : : #include <crypto/common.h>
11 : : #include <sync.h>
12 : : #include <util/check.h>
13 : : #include <util/fs_helpers.h>
14 : : #include <util/log.h>
15 : : #include <util/strencodings.h>
16 : : #include <util/translation.h>
17 : : #include <wallet/db.h>
18 : :
19 : : #include <sqlite3.h>
20 : :
21 : : #include <cstdint>
22 : : #include <optional>
23 : : #include <utility>
24 : : #include <vector>
25 : :
26 : : namespace wallet {
27 : : static constexpr int32_t WALLET_SCHEMA_VERSION = 0;
28 : :
29 : 542 : static std::span<const std::byte> SpanFromBlob(sqlite3_stmt* stmt, int col)
30 : : {
31 : 542 : return {reinterpret_cast<const std::byte*>(sqlite3_column_blob(stmt, col)),
32 : 542 : static_cast<size_t>(sqlite3_column_bytes(stmt, col))};
33 : : }
34 : :
35 : 2 : static void ErrorLogCallback(void* arg, int code, const char* msg)
36 : : {
37 : : // From sqlite3_config() documentation for the SQLITE_CONFIG_LOG option:
38 : : // "The void pointer that is the second argument to SQLITE_CONFIG_LOG is passed through as
39 : : // the first parameter to the application-defined logger function whenever that function is
40 : : // invoked."
41 : : // Assert that this is the case:
42 [ - + ]: 2 : assert(arg == nullptr);
43 : 2 : LogWarning("SQLite Error. Code: %d. Message: %s", code, msg);
44 : 2 : }
45 : :
46 : 43283 : static int TraceSqlCallback(unsigned code, void* context, void* param1, void* param2)
47 : : {
48 : 43283 : auto* db = static_cast<SQLiteDatabase*>(context);
49 [ + - ]: 43283 : if (code == SQLITE_TRACE_STMT) {
50 : 43283 : auto* stmt = static_cast<sqlite3_stmt*>(param1);
51 : : // To be conservative and avoid leaking potentially secret information
52 : : // in the log file, only expand statements that query the database, not
53 : : // statements that update the database.
54 [ + + ]: 43283 : char* expanded{sqlite3_stmt_readonly(stmt) ? sqlite3_expanded_sql(stmt) : nullptr};
55 [ + - + + : 43283 : LogTrace(BCLog::WALLETDB, "[%s] SQLite Statement: %s\n", db->Filename(), expanded ? expanded : sqlite3_sql(stmt));
+ - ]
56 [ + + ]: 43283 : if (expanded) sqlite3_free(expanded);
57 : : }
58 : 43283 : return SQLITE_OK;
59 : : }
60 : :
61 : 58461 : static bool BindBlobToStatement(sqlite3_stmt* stmt,
62 : : int index,
63 : : std::span<const std::byte> blob,
64 : : const std::string& description)
65 : : {
66 : : // Pass a pointer to the empty string "" below instead of passing the
67 : : // blob.data() pointer if the blob.data() pointer is null. Passing a null
68 : : // data pointer to bind_blob would cause sqlite to bind the SQL NULL value
69 : : // instead of the empty blob value X'', which would mess up SQL comparisons.
70 [ + + ]: 58461 : int res = sqlite3_bind_blob(stmt, index, blob.data() ? static_cast<const void*>(blob.data()) : "", blob.size(), SQLITE_STATIC);
71 [ - + ]: 58461 : if (res != SQLITE_OK) {
72 : 0 : LogWarning("Unable to bind %s to statement: %s", description, sqlite3_errstr(res));
73 : 0 : sqlite3_clear_bindings(stmt);
74 : 0 : sqlite3_reset(stmt);
75 : 0 : return false;
76 : : }
77 : :
78 : : return true;
79 : : }
80 : :
81 : 28 : static std::optional<int> ReadPragmaInteger(sqlite3* db, const std::string& key, const std::string& description, bilingual_str& error)
82 : : {
83 : 28 : std::string stmt_text = strprintf("PRAGMA %s", key);
84 : 28 : sqlite3_stmt* pragma_read_stmt{nullptr};
85 [ + - ]: 28 : int ret = sqlite3_prepare_v2(db, stmt_text.c_str(), -1, &pragma_read_stmt, nullptr);
86 [ - + ]: 28 : if (ret != SQLITE_OK) {
87 [ # # ]: 0 : sqlite3_finalize(pragma_read_stmt);
88 [ # # # # : 0 : error = Untranslated(strprintf("SQLiteDatabase: Failed to prepare the statement to fetch %s: %s", description, sqlite3_errstr(ret)));
# # ]
89 : 0 : return std::nullopt;
90 : : }
91 [ + - ]: 28 : ret = sqlite3_step(pragma_read_stmt);
92 [ - + ]: 28 : if (ret != SQLITE_ROW) {
93 [ # # ]: 0 : sqlite3_finalize(pragma_read_stmt);
94 [ # # # # : 0 : error = Untranslated(strprintf("SQLiteDatabase: Failed to fetch %s: %s", description, sqlite3_errstr(ret)));
# # ]
95 : 0 : return std::nullopt;
96 : : }
97 [ + - ]: 28 : int result = sqlite3_column_int(pragma_read_stmt, 0);
98 [ + - ]: 28 : sqlite3_finalize(pragma_read_stmt);
99 : 28 : return result;
100 : 28 : }
101 : :
102 : 366 : static void SetPragma(sqlite3* db, const std::string& key, const std::string& value, const std::string& err_msg)
103 : : {
104 : 366 : std::string stmt_text = strprintf("PRAGMA %s = %s", key, value);
105 [ + - ]: 366 : int ret = sqlite3_exec(db, stmt_text.c_str(), nullptr, nullptr, nullptr);
106 [ - + ]: 366 : if (ret != SQLITE_OK) {
107 [ # # # # : 0 : throw std::runtime_error(strprintf("SQLiteDatabase: %s: %s\n", err_msg, sqlite3_errstr(ret)));
# # ]
108 : : }
109 : 366 : }
110 : :
111 : : Mutex SQLiteDatabase::g_sqlite_mutex;
112 : : int SQLiteDatabase::g_sqlite_count = 0;
113 : :
114 : 14 : SQLiteDatabase::SQLiteDatabase(const fs::path& dir_path, const fs::path& file_path, const DatabaseOptions& options)
115 : 14 : : SQLiteDatabase(dir_path, file_path, options, /*additional_flags=*/0)
116 : 14 : {}
117 : :
118 : 93 : SQLiteDatabase::SQLiteDatabase(const fs::path& dir_path, const fs::path& file_path, const DatabaseOptions& options, int additional_flags)
119 [ + - - + : 186 : : WalletDatabase(), m_dir_path(dir_path), m_file_path(fs::PathToString(file_path)), m_additional_flags(additional_flags), m_write_semaphore(1), m_use_unsafe_sync(options.use_unsafe_sync)
+ - ]
120 : : {
121 : 93 : {
122 [ + - ]: 93 : LOCK(g_sqlite_mutex);
123 [ + + ]: 93 : if (++g_sqlite_count == 1) {
124 : : // Setup logging
125 [ + - ]: 67 : int ret = sqlite3_config(SQLITE_CONFIG_LOG, ErrorLogCallback, nullptr);
126 [ - + ]: 67 : if (ret != SQLITE_OK) {
127 [ # # # # : 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup error log: %s\n", sqlite3_errstr(ret)));
# # ]
128 : : }
129 : : // Force serialized threading mode
130 [ + - ]: 67 : ret = sqlite3_config(SQLITE_CONFIG_SERIALIZED);
131 [ - + ]: 67 : if (ret != SQLITE_OK) {
132 [ # # # # : 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to configure serialized threading mode: %s\n", sqlite3_errstr(ret)));
# # ]
133 : : }
134 : : }
135 [ + - ]: 93 : int ret = sqlite3_initialize(); // This is a no-op if sqlite3 is already initialized
136 [ - + ]: 93 : if (ret != SQLITE_OK) {
137 [ # # # # : 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to initialize SQLite: %s\n", sqlite3_errstr(ret)));
# # ]
138 : : }
139 : 0 : }
140 : :
141 : 93 : try {
142 [ + - ]: 93 : Open(m_additional_flags);
143 [ - - ]: 0 : } catch (const std::runtime_error&) {
144 : : // If open fails, cleanup this object and rethrow the exception
145 : 0 : Cleanup();
146 : 0 : throw;
147 : 0 : }
148 : 93 : }
149 : :
150 : 19542 : void SQLiteBatch::SetupSQLStatements()
151 : : {
152 : 19542 : const std::vector<std::pair<sqlite3_stmt**, const char*>> statements{
153 : 19542 : {&m_read_stmt, "SELECT value FROM main WHERE key = ?"},
154 : 19542 : {&m_insert_stmt, "INSERT INTO main VALUES(?, ?)"},
155 : 19542 : {&m_overwrite_stmt, "INSERT or REPLACE into main values(?, ?)"},
156 : 19542 : {&m_delete_stmt, "DELETE FROM main WHERE key = ?"},
157 : 19542 : {&m_delete_prefix_stmt, "DELETE FROM main WHERE instr(key, ?) = 1"},
158 : 19542 : };
159 : :
160 [ + - + + ]: 117252 : for (const auto& [stmt_prepared, stmt_text] : statements) {
161 [ + - ]: 97710 : if (*stmt_prepared == nullptr) {
162 [ + - ]: 97710 : int res = sqlite3_prepare_v2(m_database.m_db, stmt_text, -1, stmt_prepared, nullptr);
163 [ - + ]: 97710 : if (res != SQLITE_OK) {
164 : 0 : throw std::runtime_error(strprintf(
165 [ # # # # : 0 : "SQLiteDatabase: Failed to setup SQL statements: %s\n", sqlite3_errstr(res)));
# # ]
166 : : }
167 : : }
168 : : }
169 : 19542 : }
170 : :
171 : 107 : SQLiteDatabase::~SQLiteDatabase()
172 : : {
173 : 93 : Cleanup();
174 : 107 : }
175 : :
176 : 93 : void SQLiteDatabase::Cleanup() noexcept
177 : : {
178 : 93 : AssertLockNotHeld(g_sqlite_mutex);
179 : :
180 : 93 : Close();
181 : :
182 : 93 : LOCK(g_sqlite_mutex);
183 [ + + ]: 93 : if (--g_sqlite_count == 0) {
184 : 67 : int ret = sqlite3_shutdown();
185 [ - + ]: 67 : if (ret != SQLITE_OK) {
186 : 0 : LogWarning("SQLiteDatabase: Failed to shutdown SQLite: %s", sqlite3_errstr(ret));
187 : : }
188 : : }
189 : 93 : }
190 : :
191 : 14 : bool SQLiteDatabase::Verify(bilingual_str& error)
192 : : {
193 [ - + ]: 14 : assert(m_db);
194 : :
195 : : // Check the application ID matches our network magic
196 [ + - + - ]: 28 : auto read_result = ReadPragmaInteger(m_db, "application_id", "the application id", error);
197 [ + - ]: 14 : if (!read_result.has_value()) return false;
198 : 14 : uint32_t app_id = static_cast<uint32_t>(read_result.value());
199 [ - + ]: 14 : uint32_t net_magic = ReadBE32(Params().MessageStart().data());
200 [ - + ]: 14 : if (app_id != net_magic) {
201 : 0 : error = strprintf(_("SQLiteDatabase: Unexpected application id. Expected %u, got %u"), net_magic, app_id);
202 : 0 : return false;
203 : : }
204 : :
205 : : // Check our schema version
206 [ + - + - ]: 28 : read_result = ReadPragmaInteger(m_db, "user_version", "sqlite wallet schema version", error);
207 [ + - ]: 14 : if (!read_result.has_value()) return false;
208 [ - + ]: 14 : int32_t user_ver = read_result.value();
209 [ - + ]: 14 : if (user_ver != WALLET_SCHEMA_VERSION) {
210 : 0 : error = strprintf(_("SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported"), user_ver, WALLET_SCHEMA_VERSION);
211 : 0 : return false;
212 : : }
213 : :
214 : 14 : sqlite3_stmt* stmt{nullptr};
215 : 14 : int ret = sqlite3_prepare_v2(m_db, "PRAGMA integrity_check", -1, &stmt, nullptr);
216 [ - + ]: 14 : if (ret != SQLITE_OK) {
217 : 0 : sqlite3_finalize(stmt);
218 : 0 : error = strprintf(_("SQLiteDatabase: Failed to prepare statement to verify database: %s"), sqlite3_errstr(ret));
219 : 0 : return false;
220 : : }
221 : 28 : while (true) {
222 : 28 : ret = sqlite3_step(stmt);
223 [ + + ]: 28 : if (ret == SQLITE_DONE) {
224 : : break;
225 : : }
226 [ - + ]: 14 : if (ret != SQLITE_ROW) {
227 : 0 : error = strprintf(_("SQLiteDatabase: Failed to execute statement to verify database: %s"), sqlite3_errstr(ret));
228 : 0 : break;
229 : : }
230 : 14 : const char* msg = (const char*)sqlite3_column_text(stmt, 0);
231 [ - + ]: 14 : if (!msg) {
232 : 0 : error = strprintf(_("SQLiteDatabase: Failed to read database verification error: %s"), sqlite3_errstr(ret));
233 : 0 : break;
234 : : }
235 : 14 : std::string str_msg(msg);
236 [ + - ]: 14 : if (str_msg == "ok") {
237 : 14 : continue;
238 : : }
239 [ # # ]: 0 : if (error.empty()) {
240 [ # # # # : 0 : error = _("Failed to verify database") + Untranslated("\n");
# # ]
241 : : }
242 [ # # # # : 0 : error += Untranslated(strprintf("%s\n", str_msg));
# # ]
243 : 14 : }
244 : 14 : sqlite3_finalize(stmt);
245 : 14 : return error.empty();
246 : : }
247 : :
248 : 2 : void SQLiteDatabase::Open()
249 : : {
250 [ + + ]: 2 : if (m_additional_flags & SQLITE_OPEN_MEMORY) {
251 [ + - ]: 1 : throw std::runtime_error("SQLiteDatabase: Cannot reopen an in-memory database");
252 : : }
253 : 1 : Open(m_additional_flags);
254 : 1 : }
255 : :
256 : 94 : void SQLiteDatabase::Open(int additional_flags)
257 : : {
258 : 94 : int flags = SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | additional_flags;
259 : :
260 [ + - ]: 94 : if (m_db == nullptr) {
261 [ + + ]: 94 : if (!(flags & SQLITE_OPEN_MEMORY)) {
262 : 15 : TryCreateDirectories(m_dir_path);
263 [ - + ]: 15 : if (!IsDirWritable(m_dir_path)) {
264 [ # # # # : 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to open database in directory '%s': directory is not writable", fs::PathToString(m_dir_path)));
# # ]
265 : : }
266 : : }
267 : :
268 : 94 : int ret = sqlite3_open_v2(m_file_path.c_str(), &m_db, flags, nullptr);
269 [ - + ]: 94 : if (ret != SQLITE_OK) {
270 [ # # # # : 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to open database: %s\n", sqlite3_errstr(ret)));
# # ]
271 : : }
272 : 94 : ret = sqlite3_extended_result_codes(m_db, 1);
273 [ - + ]: 94 : if (ret != SQLITE_OK) {
274 [ # # # # : 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to enable extended result codes: %s\n", sqlite3_errstr(ret)));
# # ]
275 : : }
276 : : // Trace SQL statements if tracing is enabled with -debug=walletdb -loglevel=walletdb:trace
277 [ + - ]: 94 : if (util::log::ShouldTraceLog(BCLog::WALLETDB)) {
278 : 94 : ret = sqlite3_trace_v2(m_db, SQLITE_TRACE_STMT, TraceSqlCallback, this);
279 [ - + ]: 94 : if (ret != SQLITE_OK) {
280 [ # # ]: 0 : LogWarning("Failed to enable SQL tracing for %s", Filename());
281 : : }
282 : : }
283 : : }
284 : :
285 [ - + ]: 94 : if (sqlite3_db_readonly(m_db, "main") != 0) {
286 [ # # ]: 0 : throw std::runtime_error("SQLiteDatabase: Database opened in readonly mode but read-write permissions are needed");
287 : : }
288 : :
289 : : // Acquire an exclusive lock on the database
290 : : // First change the locking mode to exclusive
291 [ + - + - : 188 : SetPragma(m_db, "locking_mode", "exclusive", "Unable to change database locking mode to exclusive");
+ - ]
292 : : // Now begin a transaction to acquire the exclusive lock. This lock won't be released until we close because of the exclusive locking mode.
293 : 94 : int ret = sqlite3_exec(m_db, "BEGIN EXCLUSIVE TRANSACTION", nullptr, nullptr, nullptr);
294 [ - + ]: 94 : if (ret != SQLITE_OK) {
295 [ # # ]: 0 : throw std::runtime_error("SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another instance of " CLIENT_NAME "?\n");
296 : : }
297 : 94 : ret = sqlite3_exec(m_db, "COMMIT", nullptr, nullptr, nullptr);
298 [ - + ]: 94 : if (ret != SQLITE_OK) {
299 [ # # # # : 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Unable to end exclusive lock transaction: %s\n", sqlite3_errstr(ret)));
# # ]
300 : : }
301 : :
302 : : // Enable fullfsync for the platforms that use it
303 [ + - + - : 188 : SetPragma(m_db, "fullfsync", "true", "Failed to enable fullfsync");
+ - ]
304 : :
305 [ - + ]: 94 : if (m_use_unsafe_sync) {
306 : : // Use normal synchronous mode for the journal
307 : 0 : LogWarning("SQLite is configured to not wait for data to be flushed to disk. Data loss and corruption may occur.");
308 [ # # # # : 0 : SetPragma(m_db, "synchronous", "OFF", "Failed to set synchronous mode to OFF");
# # ]
309 : : }
310 : :
311 : : // Make the table for our key-value pairs
312 : : // First check that the main table exists
313 : 94 : sqlite3_stmt* check_main_stmt{nullptr};
314 : 94 : ret = sqlite3_prepare_v2(m_db, "SELECT name FROM sqlite_master WHERE type='table' AND name='main'", -1, &check_main_stmt, nullptr);
315 [ - + ]: 94 : if (ret != SQLITE_OK) {
316 [ # # # # : 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to prepare statement to check table existence: %s\n", sqlite3_errstr(ret)));
# # ]
317 : : }
318 : 94 : ret = sqlite3_step(check_main_stmt);
319 [ - + ]: 94 : if (sqlite3_finalize(check_main_stmt) != SQLITE_OK) {
320 [ # # # # : 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to finalize statement checking table existence: %s\n", sqlite3_errstr(ret)));
# # ]
321 : : }
322 : 94 : bool table_exists;
323 [ + + ]: 94 : if (ret == SQLITE_DONE) {
324 : : table_exists = false;
325 [ - + ]: 5 : } else if (ret == SQLITE_ROW) {
326 : : table_exists = true;
327 : : } else {
328 [ # # # # : 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to execute statement to check table existence: %s\n", sqlite3_errstr(ret)));
# # ]
329 : : }
330 : :
331 : : // Do the db setup things because the table doesn't exist only when we are creating a new wallet
332 : 89 : if (!table_exists) {
333 : 89 : ret = sqlite3_exec(m_db, "CREATE TABLE main(key BLOB PRIMARY KEY NOT NULL, value BLOB NOT NULL)", nullptr, nullptr, nullptr);
334 [ - + ]: 89 : if (ret != SQLITE_OK) {
335 [ # # # # : 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to create new database: %s\n", sqlite3_errstr(ret)));
# # ]
336 : : }
337 : :
338 : : // Set the application id
339 : 89 : uint32_t app_id = ReadBE32(Params().MessageStart().data());
340 [ + - + - : 178 : SetPragma(m_db, "application_id", strprintf("%d", static_cast<int32_t>(app_id)),
+ - ]
341 : 89 : "Failed to set the application id");
342 : :
343 : : // Set the user version
344 [ + - + - : 178 : SetPragma(m_db, "user_version", strprintf("%d", WALLET_SCHEMA_VERSION),
+ - ]
345 : 178 : "Failed to set the wallet schema version");
346 : : }
347 : 94 : }
348 : :
349 : 0 : bool SQLiteDatabase::Rewrite()
350 : : {
351 : : // Rewrite the database using the VACUUM command: https://sqlite.org/lang_vacuum.html
352 : 0 : int ret = sqlite3_exec(m_db, "VACUUM", nullptr, nullptr, nullptr);
353 : 0 : return ret == SQLITE_OK;
354 : : }
355 : :
356 : 0 : bool SQLiteDatabase::Backup(const std::string& dest) const
357 : : {
358 : 0 : sqlite3* db_copy;
359 : 0 : int res = sqlite3_open(dest.c_str(), &db_copy);
360 [ # # ]: 0 : if (res != SQLITE_OK) {
361 : 0 : sqlite3_close(db_copy);
362 : 0 : return false;
363 : : }
364 : 0 : sqlite3_backup* backup = sqlite3_backup_init(db_copy, "main", m_db, "main");
365 [ # # ]: 0 : if (!backup) {
366 : 0 : LogWarning("Unable to begin sqlite backup: %s", sqlite3_errmsg(m_db));
367 : 0 : sqlite3_close(db_copy);
368 : 0 : return false;
369 : : }
370 : : // Specifying -1 will copy all of the pages
371 : 0 : res = sqlite3_backup_step(backup, -1);
372 [ # # ]: 0 : if (res != SQLITE_DONE) {
373 : 0 : LogWarning("Unable to continue sqlite backup: %s", sqlite3_errstr(res));
374 : 0 : sqlite3_backup_finish(backup);
375 : 0 : sqlite3_close(db_copy);
376 : 0 : return false;
377 : : }
378 : 0 : res = sqlite3_backup_finish(backup);
379 : 0 : sqlite3_close(db_copy);
380 : 0 : return res == SQLITE_OK;
381 : : }
382 : :
383 : 99 : void SQLiteDatabase::Close()
384 : : {
385 : 99 : int res = sqlite3_close(m_db);
386 [ - + ]: 99 : if (res != SQLITE_OK) {
387 [ # # # # : 0 : throw std::runtime_error(strprintf("SQLiteDatabase: Failed to close database: %s\n", sqlite3_errstr(res)));
# # ]
388 : : }
389 : 99 : m_db = nullptr;
390 : 99 : }
391 : :
392 : 13245 : bool SQLiteDatabase::HasActiveTxn()
393 : : {
394 : : // 'sqlite3_get_autocommit' returns true by default, and false if a transaction has begun and not been committed or rolled back.
395 [ + - + + ]: 13245 : return m_db && sqlite3_get_autocommit(m_db) == 0;
396 : : }
397 : :
398 : 13243 : int SQliteExecHandler::Exec(SQLiteDatabase& database, const std::string& statement)
399 : : {
400 : 13243 : return sqlite3_exec(database.m_db, statement.data(), nullptr, nullptr, nullptr);
401 : : }
402 : :
403 : 109 : std::unique_ptr<DatabaseBatch> SQLiteDatabase::MakeBatch()
404 : : {
405 : : // We ignore flush_on_close because we don't do manual flushing for SQLite
406 : 109 : return std::make_unique<SQLiteBatch>(*this);
407 : : }
408 : :
409 : 19542 : SQLiteBatch::SQLiteBatch(SQLiteDatabase& database)
410 [ + - ]: 19542 : : m_database(database)
411 : : {
412 : : // Make sure we have a db handle
413 [ - + ]: 19542 : assert(m_database.m_db);
414 : :
415 [ + - ]: 19542 : SetupSQLStatements();
416 : 19542 : }
417 : :
418 : 19542 : void SQLiteBatch::Close()
419 : : {
420 : 19542 : bool force_conn_refresh = false;
421 : :
422 : : // If we began a transaction, and it wasn't committed, abort the transaction in progress
423 [ + + ]: 19542 : if (m_txn) {
424 [ - + ]: 1 : if (TxnAbort()) {
425 : 0 : LogWarning("SQLiteBatch: Batch closed unexpectedly without the transaction being explicitly committed or aborted");
426 : : } else {
427 : : // If transaction cannot be aborted, it means there is a bug or there has been data corruption. Try to recover in this case
428 : : // by closing and reopening the database. Closing the database should also ensure that any changes made since the transaction
429 : : // was opened will be rolled back and future transactions can succeed without committing old data.
430 : 1 : force_conn_refresh = true;
431 : 1 : LogWarning("SQLiteBatch: Batch closed and failed to abort transaction, resetting db connection..");
432 : : }
433 : : }
434 : :
435 : : // Free all of the prepared statements
436 : 19542 : const std::vector<std::pair<sqlite3_stmt**, const char*>> statements{
437 : 19542 : {&m_read_stmt, "read"},
438 : 19542 : {&m_insert_stmt, "insert"},
439 : 19542 : {&m_overwrite_stmt, "overwrite"},
440 : 19542 : {&m_delete_stmt, "delete"},
441 : 19542 : {&m_delete_prefix_stmt, "delete prefix"},
442 : 19542 : };
443 : :
444 [ + - + + ]: 117252 : for (const auto& [stmt_prepared, stmt_description] : statements) {
445 [ + - ]: 97710 : int res = sqlite3_finalize(*stmt_prepared);
446 [ - + ]: 97710 : if (res != SQLITE_OK) {
447 [ # # # # ]: 0 : LogWarning("SQLiteBatch: Batch closed but could not finalize %s statement: %s",
448 : : stmt_description, sqlite3_errstr(res));
449 : : }
450 : 97710 : *stmt_prepared = nullptr;
451 : : }
452 : :
453 [ + + ]: 19542 : if (force_conn_refresh) {
454 [ - + ]: 1 : if (m_database.m_additional_flags & SQLITE_OPEN_MEMORY) {
455 [ # # ]: 0 : throw std::runtime_error("SQLiteDatabase: Cannot recover in-memory database connection");
456 : : }
457 [ + - ]: 1 : m_database.Close();
458 : 1 : try {
459 [ + - ]: 1 : m_database.Open();
460 : : // If TxnAbort failed and we refreshed the connection, the semaphore was not released, so release it here to avoid deadlocks on future writes.
461 : 1 : m_database.m_write_semaphore.release();
462 [ - - ]: 0 : } catch (const std::runtime_error&) {
463 : : // If open fails, cleanup this object and rethrow the exception
464 [ - - ]: 0 : m_database.Close();
465 : 0 : throw;
466 : 0 : }
467 : : }
468 : 19542 : }
469 : :
470 : 38 : bool SQLiteBatch::ReadKey(DataStream&& key, DataStream& value)
471 : : {
472 [ + - ]: 38 : if (!m_database.m_db) return false;
473 [ - + ]: 38 : assert(m_read_stmt);
474 : :
475 : : // Bind: leftmost parameter in statement is index 1
476 [ + - + - ]: 76 : if (!BindBlobToStatement(m_read_stmt, 1, key, "key")) return false;
477 : 38 : int res = sqlite3_step(m_read_stmt);
478 [ + + ]: 38 : if (res != SQLITE_ROW) {
479 [ - + ]: 8 : if (res != SQLITE_DONE) {
480 : : // SQLITE_DONE means "not found", don't log an error in that case.
481 : 0 : LogWarning("Unable to execute read statement: %s", sqlite3_errstr(res));
482 : : }
483 : 8 : sqlite3_clear_bindings(m_read_stmt);
484 : 8 : sqlite3_reset(m_read_stmt);
485 : 8 : return false;
486 : : }
487 : : // Leftmost column in result is index 0
488 [ - + ]: 30 : value.clear();
489 : 30 : value.write(SpanFromBlob(m_read_stmt, 0));
490 : :
491 : 30 : sqlite3_clear_bindings(m_read_stmt);
492 : 30 : sqlite3_reset(m_read_stmt);
493 : 30 : return true;
494 : : }
495 : :
496 : 28988 : bool SQLiteBatch::WriteKey(DataStream&& key, DataStream&& value, bool overwrite)
497 : : {
498 [ + - ]: 28988 : if (!m_database.m_db) return false;
499 [ + - - + ]: 28988 : assert(m_insert_stmt && m_overwrite_stmt);
500 : :
501 : 28988 : sqlite3_stmt* stmt;
502 [ + + ]: 28988 : if (overwrite) {
503 : : stmt = m_overwrite_stmt;
504 : : } else {
505 : 281 : stmt = m_insert_stmt;
506 : : }
507 : :
508 : : // Bind: leftmost parameter in statement is index 1
509 : : // Insert index 1 is key, 2 is value
510 [ + - + - ]: 57976 : if (!BindBlobToStatement(stmt, 1, key, "key")) return false;
511 [ + - + - ]: 57976 : if (!BindBlobToStatement(stmt, 2, value, "value")) return false;
512 : :
513 : : // Acquire semaphore if not previously acquired when creating a transaction.
514 [ + + ]: 28988 : if (!m_txn) m_database.m_write_semaphore.acquire();
515 : :
516 : : // Execute
517 : 28988 : int res = sqlite3_step(stmt);
518 : 28988 : sqlite3_clear_bindings(stmt);
519 : 28988 : sqlite3_reset(stmt);
520 [ + + ]: 28988 : if (res != SQLITE_DONE) {
521 : 2 : LogWarning("Unable to execute write statement: %s", sqlite3_errstr(res));
522 : : }
523 : :
524 [ + + ]: 28988 : if (!m_txn) m_database.m_write_semaphore.release();
525 : :
526 : 28988 : return res == SQLITE_DONE;
527 : : }
528 : :
529 : 6 : bool SQLiteBatch::ExecStatement(sqlite3_stmt* stmt, std::span<const std::byte> blob)
530 : : {
531 [ + - ]: 6 : if (!m_database.m_db) return false;
532 [ - + ]: 6 : assert(stmt);
533 : :
534 : : // Bind: leftmost parameter in statement is index 1
535 [ + - + - ]: 6 : if (!BindBlobToStatement(stmt, 1, blob, "key")) return false;
536 : :
537 : : // Acquire semaphore if not previously acquired when creating a transaction.
538 [ + + ]: 6 : if (!m_txn) m_database.m_write_semaphore.acquire();
539 : :
540 : : // Execute
541 : 6 : int res = sqlite3_step(stmt);
542 : 6 : sqlite3_clear_bindings(stmt);
543 : 6 : sqlite3_reset(stmt);
544 [ - + ]: 6 : if (res != SQLITE_DONE) {
545 : 0 : LogWarning("Unable to execute exec statement: %s", sqlite3_errstr(res));
546 : : }
547 : :
548 [ + + ]: 6 : if (!m_txn) m_database.m_write_semaphore.release();
549 : :
550 : 6 : return res == SQLITE_DONE;
551 : : }
552 : :
553 : 3 : bool SQLiteBatch::EraseKey(DataStream&& key)
554 : : {
555 [ - + ]: 3 : return ExecStatement(m_delete_stmt, key);
556 : : }
557 : :
558 : 3 : bool SQLiteBatch::ErasePrefix(std::span<const std::byte> prefix)
559 : : {
560 : 3 : return ExecStatement(m_delete_prefix_stmt, prefix);
561 : : }
562 : :
563 : 11 : bool SQLiteBatch::HasKey(DataStream&& key)
564 : : {
565 [ + - ]: 11 : if (!m_database.m_db) return false;
566 [ - + ]: 11 : assert(m_read_stmt);
567 : :
568 : : // Bind: leftmost parameter in statement is index 1
569 [ + - + - ]: 22 : if (!BindBlobToStatement(m_read_stmt, 1, key, "key")) return false;
570 : 11 : int res = sqlite3_step(m_read_stmt);
571 : 11 : sqlite3_clear_bindings(m_read_stmt);
572 : 11 : sqlite3_reset(m_read_stmt);
573 : 11 : return res == SQLITE_ROW;
574 : : }
575 : :
576 : 474 : DatabaseCursor::Status SQLiteCursor::Next(DataStream& key, DataStream& value)
577 : : {
578 : 474 : int res = sqlite3_step(m_cursor_stmt);
579 [ + + ]: 474 : if (res == SQLITE_DONE) {
580 : : return Status::DONE;
581 : : }
582 [ - + ]: 256 : if (res != SQLITE_ROW) {
583 : 0 : LogWarning("Unable to execute cursor step: %s", sqlite3_errstr(res));
584 : 0 : return Status::FAIL;
585 : : }
586 : :
587 [ - + ]: 256 : key.clear();
588 [ - + ]: 256 : value.clear();
589 : :
590 : : // Leftmost column in result is index 0
591 : 256 : key.write(SpanFromBlob(m_cursor_stmt, 0));
592 : 256 : value.write(SpanFromBlob(m_cursor_stmt, 1));
593 : 256 : return Status::MORE;
594 : : }
595 : :
596 : 436 : SQLiteCursor::~SQLiteCursor()
597 : : {
598 : 218 : sqlite3_clear_bindings(m_cursor_stmt);
599 : 218 : sqlite3_reset(m_cursor_stmt);
600 : 218 : int res = sqlite3_finalize(m_cursor_stmt);
601 [ - + ]: 218 : if (res != SQLITE_OK) {
602 : 0 : LogWarning("Cursor closed but could not finalize cursor statement: %s",
603 : : sqlite3_errstr(res));
604 : : }
605 : 436 : }
606 : :
607 : 0 : std::unique_ptr<DatabaseCursor> SQLiteBatch::GetNewCursor()
608 : : {
609 [ # # ]: 0 : if (!m_database.m_db) return nullptr;
610 : 0 : auto cursor = std::make_unique<SQLiteCursor>();
611 : :
612 : 0 : const char* stmt_text = "SELECT key, value FROM main";
613 [ # # ]: 0 : int res = sqlite3_prepare_v2(m_database.m_db, stmt_text, -1, &cursor->m_cursor_stmt, nullptr);
614 [ # # ]: 0 : if (res != SQLITE_OK) {
615 : 0 : throw std::runtime_error(strprintf(
616 [ # # # # : 0 : "%s: Failed to setup cursor SQL statement: %s\n", __func__, sqlite3_errstr(res)));
# # ]
617 : : }
618 : :
619 : 0 : return cursor;
620 : 0 : }
621 : :
622 : 218 : std::unique_ptr<DatabaseCursor> SQLiteBatch::GetNewPrefixCursor(std::span<const std::byte> prefix)
623 : : {
624 [ - + ]: 218 : if (!m_database.m_db) return nullptr;
625 : :
626 : : // To get just the records we want, the SQL statement does a comparison of the binary data
627 : : // where the data must be greater than or equal to the prefix, and less than
628 : : // the prefix incremented by one (when interpreted as an integer)
629 : 218 : std::vector<std::byte> start_range(prefix.begin(), prefix.end());
630 [ + - ]: 218 : std::vector<std::byte> end_range(prefix.begin(), prefix.end());
631 : 218 : auto it = end_range.rbegin();
632 [ + + ]: 230 : for (; it != end_range.rend(); ++it) {
633 [ + + ]: 224 : if (*it == std::byte(std::numeric_limits<unsigned char>::max())) {
634 : 12 : *it = std::byte(0);
635 : 12 : continue;
636 : : }
637 : 212 : *it = std::byte(std::to_integer<unsigned char>(*it) + 1);
638 : 212 : break;
639 : : }
640 [ + + ]: 218 : if (it == end_range.rend()) {
641 : : // If the prefix is all 0xff bytes, clear end_range as we won't need it
642 [ + + ]: 6 : end_range.clear();
643 : : }
644 : :
645 [ + - ]: 218 : auto cursor = std::make_unique<SQLiteCursor>(start_range, end_range);
646 [ - + ]: 218 : if (!cursor) return nullptr;
647 : :
648 [ + + ]: 218 : const char* stmt_text = end_range.empty() ? "SELECT key, value FROM main WHERE key >= ?" :
649 : 212 : "SELECT key, value FROM main WHERE key >= ? AND key < ?";
650 [ + - ]: 218 : int res = sqlite3_prepare_v2(m_database.m_db, stmt_text, -1, &cursor->m_cursor_stmt, nullptr);
651 [ - + ]: 218 : if (res != SQLITE_OK) {
652 : 0 : throw std::runtime_error(strprintf(
653 [ # # # # : 0 : "SQLiteDatabase: Failed to setup cursor SQL statement: %s\n", sqlite3_errstr(res)));
# # ]
654 : : }
655 : :
656 [ + - - + : 218 : if (!BindBlobToStatement(cursor->m_cursor_stmt, 1, cursor->m_prefix_range_start, "prefix_start")) return nullptr;
+ - - + ]
657 [ + + ]: 218 : if (!end_range.empty()) {
658 [ + - - + : 212 : if (!BindBlobToStatement(cursor->m_cursor_stmt, 2, cursor->m_prefix_range_end, "prefix_end")) return nullptr;
+ - - + ]
659 : : }
660 : :
661 : 218 : return cursor;
662 : 218 : }
663 : :
664 : 6622 : bool SQLiteBatch::TxnBegin()
665 : : {
666 [ + - + - ]: 6622 : if (!m_database.m_db || m_txn) return false;
667 : 6622 : m_database.m_write_semaphore.acquire();
668 [ - + ]: 6622 : Assert(!m_database.HasActiveTxn());
669 [ - + + - ]: 6622 : int res = Assert(m_exec_handler)->Exec(m_database, "BEGIN TRANSACTION");
670 [ - + ]: 6622 : if (res != SQLITE_OK) {
671 : 0 : LogWarning("SQLiteBatch: Failed to begin the transaction");
672 : 0 : m_database.m_write_semaphore.release();
673 : : } else {
674 : 6622 : m_txn = true;
675 : : }
676 : 6622 : return res == SQLITE_OK;
677 : : }
678 : :
679 : 6622 : bool SQLiteBatch::TxnCommit()
680 : : {
681 [ + - + + ]: 6622 : if (!m_database.m_db || !m_txn) return false;
682 [ - + ]: 6621 : Assert(m_database.HasActiveTxn());
683 [ - + + - ]: 6621 : int res = Assert(m_exec_handler)->Exec(m_database, "COMMIT TRANSACTION");
684 [ - + ]: 6621 : if (res != SQLITE_OK) {
685 : 0 : LogWarning("SQLiteBatch: Failed to commit the transaction");
686 : : } else {
687 : 6621 : m_txn = false;
688 : 6621 : m_database.m_write_semaphore.release();
689 : : }
690 : 6621 : return res == SQLITE_OK;
691 : : }
692 : :
693 : 2 : bool SQLiteBatch::TxnAbort()
694 : : {
695 [ + - + + ]: 2 : if (!m_database.m_db || !m_txn) return false;
696 [ - + ]: 1 : Assert(m_database.HasActiveTxn());
697 [ - + + - ]: 1 : int res = Assert(m_exec_handler)->Exec(m_database, "ROLLBACK TRANSACTION");
698 [ + - ]: 1 : if (res != SQLITE_OK) {
699 : 1 : LogWarning("SQLiteBatch: Failed to abort the transaction");
700 : : } else {
701 : 0 : m_txn = false;
702 : 0 : m_database.m_write_semaphore.release();
703 : : }
704 : 1 : return res == SQLITE_OK;
705 : : }
706 : :
707 : 14 : std::unique_ptr<SQLiteDatabase> MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
708 : : {
709 : 14 : try {
710 [ + - ]: 14 : fs::path data_file = SQLiteDataFile(path);
711 [ + - + - ]: 14 : auto db = std::make_unique<SQLiteDatabase>(data_file.parent_path(), data_file, options);
712 [ + - + - : 14 : if (options.verify && !db->Verify(error)) {
- + ]
713 : 0 : status = DatabaseStatus::FAILED_VERIFY;
714 : 0 : return nullptr;
715 : : }
716 : 14 : status = DatabaseStatus::SUCCESS;
717 : 14 : return db;
718 [ - - ]: 28 : } catch (const std::runtime_error& e) {
719 : 0 : status = DatabaseStatus::FAILED_LOAD;
720 [ - - - - ]: 0 : error = Untranslated(e.what());
721 : 0 : return nullptr;
722 : 0 : }
723 : : }
724 : :
725 : 79 : InMemoryWalletDatabase::InMemoryWalletDatabase()
726 [ + - + - ]: 237 : : SQLiteDatabase(fs::path{}, fs::path{":memory:"}, DatabaseOptions(), SQLITE_OPEN_MEMORY)
727 : 79 : {}
728 : :
729 : 0 : std::unique_ptr<WalletDatabase> MakeInMemoryWalletDatabase()
730 : : {
731 : 0 : return std::make_unique<InMemoryWalletDatabase>();
732 : : }
733 : :
734 : 5 : std::string SQLiteDatabaseVersion()
735 : : {
736 : 5 : return std::string(sqlite3_libversion());
737 : : }
738 : : } // namespace wallet
|