sqlite.cpp raw

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