Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2020-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <bitcoin-build-config.h> // IWYU pragma: keep7#include <wallet/sqlite.h>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>19#include <sqlite3.h>21#include <cstdint>22#include <optional>23#include <utility>24#include <vector>26namespace wallet {27static constexpr int32_t WALLET_SCHEMA_VERSION = 0;29static std::span<const std::byte> SpanFromBlob(sqlite3_stmt* stmt, int col)30{31return {reinterpret_cast<const std::byte*>(sqlite3_column_blob(stmt, col)),32static_cast<size_t>(sqlite3_column_bytes(stmt, col))};33}35static 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 as39// the first parameter to the application-defined logger function whenever that function is40// invoked."41// Assert that this is the case:42assert(arg == nullptr);43LogWarning("SQLite Error. Code: %d. Message: %s", code, msg);44}46static int TraceSqlCallback(unsigned code, void* context, void* param1, void* param2)47{48auto* db = static_cast<SQLiteDatabase*>(context);49if (code == SQLITE_TRACE_STMT) {50auto* stmt = static_cast<sqlite3_stmt*>(param1);51// To be conservative and avoid leaking potentially secret information52// in the log file, only expand statements that query the database, not53// statements that update the database.54char* expanded{sqlite3_stmt_readonly(stmt) ? sqlite3_expanded_sql(stmt) : nullptr};55LogTrace(BCLog::WALLETDB, "[%s] SQLite Statement: %s\n", db->Filename(), expanded ? expanded : sqlite3_sql(stmt));56if (expanded) sqlite3_free(expanded);57}58return SQLITE_OK;59}61static bool BindBlobToStatement(sqlite3_stmt* stmt,62int index,63std::span<const std::byte> blob,64const std::string& description)65{66// Pass a pointer to the empty string "" below instead of passing the67// blob.data() pointer if the blob.data() pointer is null. Passing a null68// data pointer to bind_blob would cause sqlite to bind the SQL NULL value69// instead of the empty blob value X'', which would mess up SQL comparisons.70int res = sqlite3_bind_blob(stmt, index, blob.data() ? static_cast<const void*>(blob.data()) : "", blob.size(), SQLITE_STATIC);71if (res != SQLITE_OK) {72LogWarning("Unable to bind %s to statement: %s", description, sqlite3_errstr(res));73sqlite3_clear_bindings(stmt);74sqlite3_reset(stmt);75return false;76}78return true;79}81static std::optional<int> ReadPragmaInteger(sqlite3* db, const std::string& key, const std::string& description, bilingual_str& error)82{83std::string stmt_text = strprintf("PRAGMA %s", key);84sqlite3_stmt* pragma_read_stmt{nullptr};85int ret = sqlite3_prepare_v2(db, stmt_text.c_str(), -1, &pragma_read_stmt, nullptr);86if (ret != SQLITE_OK) {87sqlite3_finalize(pragma_read_stmt);88error = Untranslated(strprintf("SQLiteDatabase: Failed to prepare the statement to fetch %s: %s", description, sqlite3_errstr(ret)));89return std::nullopt;90}91ret = sqlite3_step(pragma_read_stmt);92if (ret != SQLITE_ROW) {93sqlite3_finalize(pragma_read_stmt);94error = Untranslated(strprintf("SQLiteDatabase: Failed to fetch %s: %s", description, sqlite3_errstr(ret)));95return std::nullopt;96}97int result = sqlite3_column_int(pragma_read_stmt, 0);98sqlite3_finalize(pragma_read_stmt);99return result;100}102static void SetPragma(sqlite3* db, const std::string& key, const std::string& value, const std::string& err_msg)103{104std::string stmt_text = strprintf("PRAGMA %s = %s", key, value);105int ret = sqlite3_exec(db, stmt_text.c_str(), nullptr, nullptr, nullptr);106if (ret != SQLITE_OK) {107throw std::runtime_error(strprintf("SQLiteDatabase: %s: %s\n", err_msg, sqlite3_errstr(ret)));108}109}111Mutex SQLiteDatabase::g_sqlite_mutex;112int SQLiteDatabase::g_sqlite_count = 0;114SQLiteDatabase::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{}118SQLiteDatabase::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{122LOCK(g_sqlite_mutex);123if (++g_sqlite_count == 1) {124// Setup logging125int ret = sqlite3_config(SQLITE_CONFIG_LOG, ErrorLogCallback, nullptr);126if (ret != SQLITE_OK) {127throw std::runtime_error(strprintf("SQLiteDatabase: Failed to setup error log: %s\n", sqlite3_errstr(ret)));128}129// Force serialized threading mode130ret = sqlite3_config(SQLITE_CONFIG_SERIALIZED);131if (ret != SQLITE_OK) {132throw std::runtime_error(strprintf("SQLiteDatabase: Failed to configure serialized threading mode: %s\n", sqlite3_errstr(ret)));133}134}135int ret = sqlite3_initialize(); // This is a no-op if sqlite3 is already initialized136if (ret != SQLITE_OK) {137throw std::runtime_error(strprintf("SQLiteDatabase: Failed to initialize SQLite: %s\n", sqlite3_errstr(ret)));138}139}141try {142Open(m_additional_flags);143} catch (const std::runtime_error&) {144// If open fails, cleanup this object and rethrow the exception145Cleanup();146throw;147}148}150void SQLiteBatch::SetupSQLStatements()151{152const 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};160for (const auto& [stmt_prepared, stmt_text] : statements) {161if (*stmt_prepared == nullptr) {162int res = sqlite3_prepare_v2(m_database.m_db, stmt_text, -1, stmt_prepared, nullptr);163if (res != SQLITE_OK) {164throw std::runtime_error(strprintf(165"SQLiteDatabase: Failed to setup SQL statements: %s\n", sqlite3_errstr(res)));166}167}168}169}171SQLiteDatabase::~SQLiteDatabase()172{173Cleanup();174}176void SQLiteDatabase::Cleanup() noexcept177{178AssertLockNotHeld(g_sqlite_mutex);180Close();182LOCK(g_sqlite_mutex);183if (--g_sqlite_count == 0) {184int ret = sqlite3_shutdown();185if (ret != SQLITE_OK) {186LogWarning("SQLiteDatabase: Failed to shutdown SQLite: %s", sqlite3_errstr(ret));187}188}189}191bool SQLiteDatabase::Verify(bilingual_str& error)192{193assert(m_db);195// Check the application ID matches our network magic196auto read_result = ReadPragmaInteger(m_db, "application_id", "the application id", error);197if (!read_result.has_value()) return false;198uint32_t app_id = static_cast<uint32_t>(read_result.value());199uint32_t net_magic = ReadBE32(Params().MessageStart().data());200if (app_id != net_magic) {201error = strprintf(_("SQLiteDatabase: Unexpected application id. Expected %u, got %u"), net_magic, app_id);202return false;203}205// Check our schema version206read_result = ReadPragmaInteger(m_db, "user_version", "sqlite wallet schema version", error);207if (!read_result.has_value()) return false;208int32_t user_ver = read_result.value();209if (user_ver != WALLET_SCHEMA_VERSION) {210error = strprintf(_("SQLiteDatabase: Unknown sqlite wallet schema version %d. Only version %d is supported"), user_ver, WALLET_SCHEMA_VERSION);211return false;212}214sqlite3_stmt* stmt{nullptr};215int ret = sqlite3_prepare_v2(m_db, "PRAGMA integrity_check", -1, &stmt, nullptr);216if (ret != SQLITE_OK) {217sqlite3_finalize(stmt);218error = strprintf(_("SQLiteDatabase: Failed to prepare statement to verify database: %s"), sqlite3_errstr(ret));219return false;220}221while (true) {222ret = sqlite3_step(stmt);223if (ret == SQLITE_DONE) {224break;225}226if (ret != SQLITE_ROW) {227error = strprintf(_("SQLiteDatabase: Failed to execute statement to verify database: %s"), sqlite3_errstr(ret));228break;229}230const char* msg = (const char*)sqlite3_column_text(stmt, 0);231if (!msg) {232error = strprintf(_("SQLiteDatabase: Failed to read database verification error: %s"), sqlite3_errstr(ret));233break;234}235std::string str_msg(msg);236if (str_msg == "ok") {237continue;238}239if (error.empty()) {240error = _("Failed to verify database") + Untranslated("\n");241}242error += Untranslated(strprintf("%s\n", str_msg));243}244sqlite3_finalize(stmt);245return error.empty();246}248void SQLiteDatabase::Open()249{250if (m_additional_flags & SQLITE_OPEN_MEMORY) {