xrpld 关系数据库接口(Relational Database Interface)全解析:从 `[relational_db]` 配置到 SQLite 节点数据库实现 xrpld 关系数据库接口Relational Database Interface全解析从[relational_db]配置到 SQLite 节点数据库实现【免费下载链接】rippledDecentralized cryptocurrency blockchain daemon implementing the XRP Ledger protocol in C项目地址: https://gitcode.com/GitHub_Trending/ri/rippled导读本文以 src/xrpld/app/rdb/README.md 为核心系统讲解 XRP Ledger 守护进程xrpld中关系数据库接口Relational Database Interface的设计原则、配置方式、目录结构与源码实现。读完本文你将掌握[relational_db]配置段如何选择后端数据库、RelationalDatabase抽象基类与SQLiteDatabase派生类的关系、节点数据库ledger.db / transaction.db的建表与 PRAGMA 调优参数以及 PeerFinder、State、Vacuum、Wallet 等辅助数据库在代码库中的实际落点可直接对照源码继续深入。模块定位与核心设计原则关系数据库接口Relational Database Interface是 xrpld 中负责持久化账本、交易、账户交易记录等结构化数据的统一抽象层。它在整个 xrpld 架构中处于承上启下的位置共识与交易处理流程产出的已验证账本validated ledger与交易数据最终都要落入关系数据库而account_tx、ledger等 RPC 的查询能力也依赖这一层提供的读取接口。其设计原则可以归纳为两条见 READMESQL 集中存放所有硬编码的 SQL 语句都应存放在xrpld/app/rdb目录下的文件中。除测试模块外xrpld 中任何其他文件都不得新增硬编码 SQL。这一约束让所有数据库访问语句可以被统一审查、统一维护避免 SQL 散落在业务代码各处。抽象基类 派生实现基类RelationalDatabase被多个派生类继承每个派生类为一种具体的数据库系统如 SQLite、PostgreSQL提供操作接口从而把“数据库方言差异”隔离在派生类内部。从代码层面看这两条原则在 RelationalDatabase.h抽象基类与 SQLiteDatabase.h当前唯一的派生实现中得到了落实。概览接口的三层结构按照 README 的 Overview 描述整个接口分为三个层次主数据存储层抽象接口RelationalDatabase被SQLiteDatabaseREADME 撰写时还存在PostgresDatabase继承用于操作软件的主数据存储即保存交易、账户、账本等核心数据的数据库辅助函数层detail目录下的文件提供补充函数供上述派生类访问底层数据库次级数据库访问层接口顶层剩余的文件供软件各模块访问各类次级关系数据库如 PeerFinder 数据库。需要特别说明的是README 中提到的PostgresDatabase在当前仓库代码中已经不存在全仓库搜索仅能在 README 文本中命中当前实际生效的派生实现只有SQLiteDatabase一个。这一点在“类的现状与演变”一节会详细展开。配置[relational_db]配置段README 指出配置段[relational_db]下有一个名为backend的属性其值用于指定节点数据库node databases使用哪种数据库实现。目前该属性的唯一合法取值是sqlite[relational_db] backendsqlite几点实操说明该配置段决定的是节点数据库node databases即保存账本与交易主数据的那组数据库的后端选择需要指出的是当前仓库的示例配置文件 cfg/xrpld-example.cfg 中并未出现[relational_db]段说明该段是可选的缺省即使用默认的 SQLite 后端从源码看SQLiteDatabase的成员useTxTables_见 SQLiteDatabase.h控制是否启用交易相关表当其为 false 时getTransactionsMinLedgerSeq、getAccountTransactionsMinLedgerSeq、deleteTransactionByLedgerSeq等交易表操作会直接返回空值见 SQLiteDatabase.cpp这解释了为什么某些节点可以只保留账本数据而不启用交易表。目录结构与源文件README 给出的目录结构以 2021 年 11 月为时间点。为了对比先完整保留原文档的结构src/xrpld/app/rdb/ ├── backend │ ├── detail │ │ ├── Node.cpp │ │ ├── Node.h │ │ └── SQLiteDatabase.cpp │ └── SQLiteDatabase.h ├── detail │ ├── PeerFinder.cpp │ ├── RelationalDatabase.cpp │ ├── State.cpp │ ├── Vacuum.cpp │ └── Wallet.cpp ├── PeerFinder.h ├── RelationalDatabase.h ├── README.md ├── State.h ├── Vacuum.h └── Wallet.h当前仓库2026 年的实际目录结构如下其中发生了明显的文件迁移阅读源码时请以当前结构为准src/xrpld/app/rdb/ ├── backend/ │ ├── detail/ │ │ ├── Node.cpp │ │ ├── Node.h │ │ └── SQLiteDatabase.cpp │ └── SQLiteDatabase.h ├── detail/ │ └── PeerFinder.cpp ├── PeerFinder.h └── README.md迁移后的相关文件实际落点原 README 中的位置当前实际位置RelationalDatabase.hinclude/xrpl/rdb/RelationalDatabase.hState.[h\|cpp]include/xrpl/server/State.h、src/libxrpl/server/State.cppVacuum.[h\|cpp]include/xrpl/server/Vacuum.h、src/libxrpl/server/Vacuum.cppWallet.[h\|cpp]include/xrpl/server/Wallet.h、src/libxrpl/server/Wallet.cppRelationalDatabase.cpp内含静态方法init已由 SQLiteDatabase.h 中的工厂函数setupRelationalDatabase取代文件内容一览README 中的“File Contents”表格完整列出每个文件负责的内容这是理解模块分工的关键索引整理如下文件内容Node.[h\|cpp]定义/实现SQLiteDatabase用于与 SQLite 节点数据库交互的方法SQLiteDatabase.[h\|cpp]定义/实现类SQLiteDatabase/SQLiteDatabaseImp继承自RelationalDatabase用于操作主数据存储PeerFinder.[h\|cpp]定义/实现与 PeerFinder SQLite 数据库交互的方法RelationalDatabase.cpp实现静态方法RelationalDatabase::init用于初始化RelationalDatabase实例RelationalDatabase.h定义抽象类RelationalDatabase即关系数据库接口的主类State.[h\|cpp]定义/实现与 State SQLite 数据库交互的方法涉及账本删除与数据库轮换ledger deletion and database rotationVacuum.[h\|cpp]定义/实现对 SQLite 数据库执行VACUUM操作的方法Wallet.[h\|cpp]定义/实现与 Wallet SQLite 数据库交互的方法对照当前源码上述各文件的核心函数签名均可验证详见后文各节。核心类抽象的RelationalDatabase抽象类RelationalDatabase是关系数据库接口的主类定义于同名头文件 include/xrpl/rdb/RelationalDatabase.h 中。README 描述其具备以下特征提供静态方法init()调用时根据系统配置创建某个派生类的具体实例除init()之外的所有方法均为虚方法virtual由派生类实现派生类包括SQLiteDatabase与PostgresDatabase后者已在当前代码中移除。从当前源码看README 中描述的静态工厂职责已由 SQLiteDatabase.h 末尾声明的自由函数承担/** * brief setupRelationalDatabase Creates and returns a SQLiteDatabase * instance based on configuration. Its recommended to use it as * a singleton, but its not enforced (e.g. if you have more than one * database). */ SQLiteDatabase setupRelationalDatabase(ServiceRegistry registry, Config const config, JobQueue jobQueue);RelationalDatabase定义了一组覆盖面很广的纯虚接口按功能可分为以下几类账本查询getMinLedgerSeq/getMaxLedgerSeqL139-L148、getLedgerInfoByIndex、getNewestLedgerInfo、getLedgerInfoByHash、getHashByIndex、getHashesByIndex单账本与区间批量两种重载L180-L203交易查询getTxHistory返回最近 20 笔交易L212、getTransaction支持按账本区间判定TxSearched::All/Some/UnknownL452账户交易分页查询getOldestAccountTxs/getNewestAccountTxs、对应的二进制变体getOldestAccountTxsB/getNewestAccountTxsB以及基于 marker 的分页方法oldestAccountTxPage/newestAccountTxPage/oldestAccountTxPageB/newestAccountTxPageBL329-L435数据删除deleteTransactionByLedgerSeq、deleteBeforeLedgerSeq、deleteTransactionsBeforeLedgerSeq、deleteAccountTransactionsBeforeLedgerSeq用于账本裁剪L236-L263统计与空间占用getTransactionCount、getAccountTransactionCount、getLedgerCountMinMax、getKBUsedAll/getKBUsedLedger/getKBUsedTransaction写入与生命周期saveValidatedLedger持久化已验证账本L295、closeLedgerDB、closeTransactionDB。接口还定义了若干与查询语义强相关的数据结构理解这些结构有助于读懂整个查询链LedgerHashPair账本哈希与其父账本哈希的配对L36-L40LedgerRange账本序号区间min/maxL42-L46AccountTxMarker分页游标由ledgerSeq与txnSeq组成L74-L78AccountTxOptions/AccountTxPageOptions查询参数集合包含账户、账本区间min/max 为 0 表示该方向无界、offset、limit、是否不限量bUnlimited等L80-L101DelegateFilter与DelegateType用于account_tx中按委托关系过滤的枚举与结构Actor表示他人代签、Authorizer表示本账户代他人签名L51-L62LedgerSpecifier账本定位符支持账本区间、快捷方式、序号、哈希四种形态L110。SQLite 实现SQLiteDatabase与节点数据库SQLiteDatabase是当前唯一的派生实现final类见 SQLiteDatabase.h它完整覆写了RelationalDatabase的所有纯虚方法。其私有成员揭示了节点数据库的组织方式private: std::reference_wrapperServiceRegistry registry_; bool useTxTables_; beast::Journal j_; std::unique_ptrDatabaseCon ledgerDb_, txdb_;ledgerDb_与txdb_分别是账本数据库与交易数据库的句柄通过checkoutLedger()/checkoutTransaction()取出soci::session使用L465-L480makeLedgerDBs负责按DatabaseCon::Setup与DatabaseCon::CheckpointerSetup打开这两类数据库实际工作委托给detail::makeLedgerDBs见 SQLiteDatabase.cpp构造函数签名SQLiteDatabase(ServiceRegistry registry, Config const config, JobQueue jobQueue)L391表明数据库的创建依赖配置对象、服务注册表与任务队列数据库后台写入由 JobQueue 驱动。数据库初始化与建表DBInit.h中的 SQL 与 PRAGMA节点数据库的表结构 DDL 与连接级调优参数集中在 include/xrpl/rdb/DBInit.h这是“所有 SQL 集中在 rdb 模块”原则的典型体现PRAGMA 设置以函数形式暴露L20-L36避免未替换的格式化模板被静默忽略[[nodiscard]] inline std::string commonDbPragmaJournal(std::string_view journalMode) { return std::format(PRAGMA journal_mode{};, journalMode); } [[nodiscard]] inline std::string commonDbPragmaSync(std::string_view synchronous) { return std::format(PRAGMA synchronous{};, synchronous); } [[nodiscard]] inline std::string commonDbPragmaTemp(std::string_view tempStore) { return std::format(PRAGMA temp_store{};, tempStore); }其中journal_mode、synchronous、temp_store是 SQLite 三个最关键的 I/O 与可靠性旋钮journal_mode控制 WAL/delete 等日志模式synchronous控制 fsync 频率OFF/NORMAL/FULL 对应不同的崩溃安全级别temp_store控制临时表存放位置。头文件注释还给出了一条安全策略如果配置的账本历史量达到kSqliteTuningCutoff 10000000L43以上含全量历史节点使用任何较低安全性的 SQLite 调优设置都会记录警告——因为如此体量的数据一旦遇到罕见故障将极难恢复。账本数据库ledger.dbL46的建表脚本kLgrDbInitL48-L68核心 DDL 如下CREATE TABLE IF NOT EXISTS Ledgers ( LedgerHash CHARACTER(64) PRIMARY KEY, LedgerSeq BIGINT UNSIGNED, PrevHash CHARACTER(64), TotalCoins BIGINT UNSIGNED, ClosingTime BIGINT UNSIGNED, PrevClosingTime BIGINT UNSIGNED, CloseTimeRes BIGINT UNSIGNED, CloseFlags BIGINT UNSIGNED, AccountSetHash CHARACTER(64), TransSetHash CHARACTER(64) ); CREATE INDEX IF NOT EXISTS SeqLedger ON Ledgers(LedgerSeq);可见账本表以LedgerHash64 字符十六进制哈希为主键并用LedgerSeq建立索引以支撑按序号的快速检索同时该脚本会清理历史遗留的Validations表“Old table and indexes no longer needed”。交易数据库transaction.dbL73的kTxDbInitL75则创建Transactions表TransID主键、TransType等字段与账户交易相关表后续部分以同样的方式继续展开。数据库方法的三分类README 将接口提供的方法归纳为三类这一分类与代码结构完全对应类别一供软件各组件使用的 SQLite 自由函数这些方法统一以soci::session作为参数以建立与 SQLite 数据库的连接定义并实现于PeerFinder.[h|cpp]、State.[h|cpp]、Vacuum.[h|cpp]、Wallet.[h|cpp]。它们不依赖RelationalDatabase实例而是面向具体业务库的“工具型”入口PeerFinder 数据库当前位于 src/xrpld/app/rdb/PeerFinder.h 与 src/xrpld/app/rdb/detail/PeerFinder.cpp提供initPeerFinderDB初始化并打开连接、updatePeerFinderDB按 schema 版本升级、readPeerFinderDB遍历全部条目并回调、savePeerFinderDB批量保存对等节点条目见 L20-L47。这些数据来自peer_finder::Store::Entry服务于节点发现与网络拓扑维护State 数据库当前位于 include/xrpl/server/State.h负责账本删除与数据库轮换相关状态Vacuum 数据库操作当前位于 include/xrpl/server/Vacuum.h提供唯一入口doVacuumDB(DatabaseCon::Setup const setup, beast::Journal j)L15负责“创建、初始化并对数据库执行清理”对应 SQLite 的VACUUM操作用于回收碎片空间Wallet 数据库当前位于 include/xrpl/server/Wallet.h负责钱包密钥/账户相关数据的存取。类别二仅由SQLiteDatabaseImp使用的节点数据库自由函数定义于Node.[h|cpp]当前位于 src/xrpld/app/rdb/backend/detail/Node.h 与 src/xrpld/app/rdb/backend/detail/Node.cpp。与类别一不同这些方法不面向客户端直接调用而是由RelationalDatabase的派生实例即SQLiteDatabase内部调用用于操作节点存储node store拥有的 SQLite 数据库。Node.h中的核心元素包括枚举TableType { Ledgers, Transactions, AccountTransactions }与配套计数kTableTypeCount 3L35-L36统一标识三类主数据表makeLedgerDBsL54打开账本与交易数据库返回DatabasePairValid含两个unique_ptrDatabaseCon与成功标志泛化查询/删除助手getMinLedgerSeq、getMaxLedgerSeq、deleteByLedgerSeq、deleteBeforeLedgerSeq、getRows等均以soci::session加TableType定位具体表L67-L100。这一设计带来的直接收益是SQLiteDatabase.cpp中的每个公共方法都极薄——先existsLedger()/existsTransaction()判断句柄是否存在再checkoutLedger()/checkoutTransaction()取出 session最后一行调用detail::层函数完成实际 SQL。例如 SQLiteDatabase.cpp 的getMinLedgerSeq就体现了这个三步模式。类别三RelationalDatabase/SQLiteDatabase/PostgresDatabase的成员函数用于访问节点存储node store。即第二节列出的账本查询、交易查询、账户交易分页、删除、统计等纯虚接口及其在SQLiteDatabase中的覆写实现。这一层是 RPC 层与数据库之间的正式“服务契约”业务代码只依赖RelationalDatabase指针不感知具体后端。类层次与现状演变从 README 到当前代码README成文于 2021 年 11 月描述的类层次为RelationalDatabase抽象基类含静态工厂 init() ├── SQLiteDatabase └── PostgresDatabase结合当前仓库的实际代码可以梳理出如下演变均为仓库内可验证的事实PostgresDatabase已不存在全仓库搜索仅能在 README 文本中命中PostgresDatabase无任何头文件或实现文件说明该派生类已从代码库移除当前只有SQLiteDatabase一个实现静态工厂改名换位README 描述的RelationalDatabase::init()及RelationalDatabase.cpp已不在src/xrpld/app/rdb目录中取而代之的是 SQLiteDatabase.h 中的setupRelationalDatabase工厂函数职责一致按配置创建具体实例建议以单例使用文件迁移RelationalDatabase.h上移至include/xrpl/rdb/State/Vacuum/Wallet三个模块迁移至xrpl/server命名空间include/xrpl/server/与src/libxrpl/server/SQLiteDatabase的实现下沉到backend/子目录与Node模块并列。这种“接口头文件进公共 include、实现按模块归位”的演化使得抽象接口可以被libxrpl与xrpld两侧共享而具体数据库操作仍集中在rdb目录保持了 README 最初确立的“SQL 集中于一处”的原则。总结如何在你的节点上使用这一层对运行和维护 xrpld 节点的用户而言本文涉及的技术点可以转化为三个可落地的操作配置后端如需显式指定节点数据库后端在配置文件中加入[relational_db]段并设置backendsqlite当前唯一合法值该段为可选项缺省即 SQLite理解数据文件节点数据库对应ledger.db账本表Ledgers含LedgerSeq索引与transaction.db交易表Transactions及账户交易表建表脚本见 DBInit.h数据库连接管理见 DatabaseCon.h 与 src/libxrpl/rdb/DatabaseCon.cpp追踪查询链路任何涉及账本/交易/账户历史的功能如account_tx、ledger、txRPC其数据访问都收敛到RelationalDatabase接口 →SQLiteDatabase覆写 →detail::Node层 SQL 这条调用链上可分别阅读 RelationalDatabase.h、SQLiteDatabase.cpp 与 Node.cpp 逐层深入。如需进一步研读建议按以下顺序展开先读 README 把握模块边界再对照 RelationalDatabase.h 理解接口全集最后以 SQLiteDatabase.cpp 为入口追踪具体方法的实现细节。【免费下载链接】rippledDecentralized cryptocurrency blockchain daemon implementing the XRP Ledger protocol in C项目地址: https://gitcode.com/GitHub_Trending/ri/rippled创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考