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