LCOV - code coverage report
Current view: top level - src/wallet - sqlite.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 0 425 0.0 %
Date: 2024-01-03 14:57:27 Functions: 0 35 0.0 %
Branches: 0 753 0.0 %

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

Generated by: LCOV version 1.14