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