LCOV - code coverage report
Current view: top level - src/wallet - sqlite.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 74.0 % 423 313
Test Date: 2026-07-11 06:48:01 Functions: 90.2 % 41 37
Branches: 39.9 % 526 210

             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
        

Generated by: LCOV version 2.0-1