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#ifndef BITCOIN_WALLET_SQLITE_H6#define BITCOIN_WALLET_SQLITE_H8#include <sync.h>9#include <wallet/db.h>11#include <semaphore>13struct bilingual_str;15struct sqlite3_stmt;16struct sqlite3;18namespace wallet {19class SQLiteDatabase;21/** RAII class that provides a database cursor */22class SQLiteCursor : public DatabaseCursor23{24public:25sqlite3_stmt* m_cursor_stmt{nullptr};26// Copies of the prefix things for the prefix cursor.27// Prevents SQLite from accessing temp variables for the prefix things.28std::vector<std::byte> m_prefix_range_start;29std::vector<std::byte> m_prefix_range_end;31explicit SQLiteCursor() = default;32explicit SQLiteCursor(std::vector<std::byte> start_range, std::vector<std::byte> end_range)33: m_prefix_range_start(std::move(start_range)),34m_prefix_range_end(std::move(end_range))35{}36~SQLiteCursor() override;38Status Next(DataStream& key, DataStream& value) override;39};41/** Class responsible for executing SQL statements in SQLite databases.42* Methods are virtual so they can be overridden by unit tests testing unusual database conditions. */43class SQliteExecHandler44{45public:46virtual ~SQliteExecHandler() = default;47virtual int Exec(SQLiteDatabase& database, const std::string& statement);48};50/** RAII class that provides access to a WalletDatabase */51class SQLiteBatch : public DatabaseBatch52{53private:54SQLiteDatabase& m_database;55std::unique_ptr<SQliteExecHandler> m_exec_handler{std::make_unique<SQliteExecHandler>()};57sqlite3_stmt* m_read_stmt{nullptr};58sqlite3_stmt* m_insert_stmt{nullptr};59sqlite3_stmt* m_overwrite_stmt{nullptr};60sqlite3_stmt* m_delete_stmt{nullptr};61sqlite3_stmt* m_delete_prefix_stmt{nullptr};63/** Whether this batch has started a database transaction and whether it owns SQLiteDatabase::m_write_semaphore.64* If the batch starts a db tx, it acquires the semaphore and sets this to true, keeping the semaphore65* until the transaction ends to prevent other batch objects from writing to the database.66*67* If this batch did not start a transaction, the semaphore is acquired transiently when writing and m_txn68* is not set.69*70* m_txn is different from HasActiveTxn() as it is only true when this batch has started the transaction,71* not just when any batch has started a transaction.72*/73bool m_txn{false};75void SetupSQLStatements();76bool ExecStatement(sqlite3_stmt* stmt, std::span<const std::byte> blob);78protected:79bool ReadKey(DataStream&& key, DataStream& value) override;80bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite = true) override;81bool EraseKey(DataStream&& key) override;82bool HasKey(DataStream&& key) override;83bool ErasePrefix(std::span<const std::byte> prefix) override;85public:86explicit SQLiteBatch(SQLiteDatabase& database);87~SQLiteBatch() override { Close(); }89void SetExecHandler(std::unique_ptr<SQliteExecHandler>&& handler) { m_exec_handler = std::move(handler); }91void Close() override;93std::unique_ptr<DatabaseCursor> GetNewCursor() override;94std::unique_ptr<DatabaseCursor> GetNewPrefixCursor(std::span<const std::byte> prefix) override;95bool TxnBegin() override;96bool TxnCommit() override;97bool TxnAbort() override;98bool HasActiveTxn() override { return m_txn; }99};101/** An instance of this class represents one SQLite3 database.102**/103class SQLiteDatabase : public WalletDatabase104{105private:106friend class SQLiteBatch;108const fs::path m_dir_path;110const std::string m_file_path;112const int m_additional_flags;114/**115* This mutex protects SQLite initialization and shutdown.116* sqlite3_config() and sqlite3_shutdown() are not thread-safe (sqlite3_initialize() is).117* Concurrent threads that execute SQLiteDatabase::SQLiteDatabase() should have just one118* of them do the init and the rest wait for it to complete before all can proceed.119*/120static Mutex g_sqlite_mutex;121static int g_sqlite_count GUARDED_BY(g_sqlite_mutex);123void Cleanup() noexcept EXCLUSIVE_LOCKS_REQUIRED(!g_sqlite_mutex);125void Open(int additional_flags);127protected:128SQLiteDatabase(const fs::path& dir_path, const fs::path& file_path, const DatabaseOptions& options, int additional_flags);130public:131SQLiteDatabase() = delete;133/** Create DB handle to real database */134SQLiteDatabase(const fs::path& dir_path, const fs::path& file_path, const DatabaseOptions& options);136~SQLiteDatabase();138// Batches must acquire this semaphore on writing, and release when done writing.139// This ensures that only one batch is modifying the database at a time.140std::binary_semaphore m_write_semaphore;142bool Verify(bilingual_str& error);144/** Open the database if it is not already opened */145void Open() override;147/** Close the database */148void Close() override;150/** Rewrite the entire database on disk */151bool Rewrite() override;153/** Back up the entire database to a file.154*/155bool Backup(const std::string& dest) const override;157std::string Filename() override { return m_file_path; }158/** Return paths to all database created files */159std::vector<fs::path> Files() override160{161std::vector<fs::path> files;162files.emplace_back(m_dir_path / fs::PathFromString(m_file_path));163files.emplace_back(m_dir_path / fs::PathFromString(m_file_path + "-journal"));164return files;165}166std::string Format() override { return "sqlite"; }168/** Make a SQLiteBatch connected to this database */169std::unique_ptr<DatabaseBatch> MakeBatch() override;171/** Return true if there is an on-going txn in this connection */172bool HasActiveTxn();174sqlite3* m_db{nullptr};175bool m_use_unsafe_sync;176};178/** An in-memory SQLiteDatabase. Used as a temporary build artifact where no179* on-disk persistence is needed. */180class InMemoryWalletDatabase : public SQLiteDatabase181{182public:183InMemoryWalletDatabase();184std::vector<fs::path> Files() override { return {}; }185};187std::unique_ptr<SQLiteDatabase> MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);189std::unique_ptr<WalletDatabase> MakeInMemoryWalletDatabase();191std::string SQLiteDatabaseVersion();192} // namespace wallet194#endif // BITCOIN_WALLET_SQLITE_H