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