Bitcoin Core dumptxoutset 支持命名管道:UTXO 集合免落盘流式导出与 SQLite 转换
本文介绍 Bitcoin Core 中 dumptxoutset RPC 新增的命名管道(named pipe / FIFO)输出能力(对应 PR #31560):dumptxoutset 在类 UNIX 系统上可以把压缩序列化的 UTXO 集合直接写入命名管道,由另一个进程(如 utxo_to_sqlite.py 转换脚本)即时消费,省去先把数 GB 的快照写入磁盘再读回的两步开销。读完本文,你能掌握 dumptxoutset 的完整参数用法、命名管道的工作机制与源码实现细节,并能复现"UTXO 快照 → SQLite"的一键流式管道流程。
dumptxoutset 与 UTXO 快照:背景回顾
dumptxoutset 是 Bitcoin Core 提供的"导出 UTXO 集合"的 RPC,其帮助文本(见 src/rpc/blockchain.cpp#L3072-L3107)说明它把序列化的 UTXO 集合写入文件,之后可以在支持该快照高度的节点上用 loadtxoutset 加载。本次改动并不修改快照的数据格式(magic utxo\xff + 版本号 + 网络魔数 + 基块哈希 + UTXO 数量 + 逐条压缩 Coin),而是扩展了"输出目的地":从"仅普通文件"扩展为"普通文件或命名管道"。
参数与返回结构
从源码中的 RPC 注册可以看到完整参数定义:
| 参数 | 类型 | 说明 |
|---|---|---|
path(位置参数,必填) |
string | 输出路径;相对路径会拼接到 datadir 之下。本次改动后,该路径也可以是类 UNIX 系统上的命名管道 |
type(位置参数,可选) |
string | latest 表示导出当前 tip 的 UTXO 集;rollback 表示临时回滚到历史块再导出。若改用命名参数 rollback=高度或哈希,则 type 可省略 |
rollback(命名选项) |
number 或 string | 回滚目标的高度或块哈希;离 tip 越远耗时越长,需要调大 -rpcclienttimeout |
in_memory(命名选项,默认 false) |
boolean | 回滚时的临时 UTXO 数据库是否完全放内存;可显著加速,但 mainnet 需要 10 GB 以上空闲 RAM(见 src/rpc/blockchain.cpp#L3087) |
成功时返回六个字段:coins_written、base_hash、base_height、path、txoutset_hash、nchaintx(src/rpc/blockchain.cpp#L3091-L3101)。源码给出的官方示例:
bitcoin-cli -rpcclienttimeout=0 dumptxoutset utxo.dat latest
bitcoin-cli -rpcclienttimeout=0 dumptxoutset utxo.dat rollback
bitcoin-cli -rpcclienttimeout=0 -named dumptxoutset utxo.dat rollback=853456
bitcoin-cli -rpcclienttimeout=0 -named dumptxoutset utxo.dat rollback=853456 in_memory=true
命名管道支持:源码实现解析
改动的核心在 dumptxoutset 的 handler 中(src/rpc/blockchain.cpp#L3131-L3151):
const fs::path path = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(self.Arg<std::string_view>("path")));
const auto path_info{fs::status(path)};
// Write to a temporary path and then move into `path` on completion
// to avoid confusion due to an interruption. If a named pipe passed, write directly to it.
const fs::path temppath = fs::is_fifo(path_info) ? path : path + ".incomplete";
可以看到三处针对 FIFO 的特殊分支,它们解释了命名管道路径与普通文件路径的行为差异:
- 临时文件策略:普通文件先写入
path + ".incomplete",完成后再fs::rename到目标名(src/rpc/blockchain.cpp#L3182-L3184),避免中途崩溃留下半截文件造成误解。命名管道则直接写入,因为管道不是可以 rename 的数据实体——数据必须流式送出,写多少消费多少。 - "已存在"检查:如果目标路径已存在且不是 FIFO,RPC 报错
path already exists. If you are sure this is what you want, move it out of the way first(src/rpc/blockchain.cpp#L3138-L3143)。这个检查对 FIFO 直接豁免——一个已存在的 FIFO 正是本次特性期望的输入。 - 打开方式:两种情况都用
fsbridge::fopen(temppath, "wb")以写模式打开;打开失败返回Couldn't open file ... for writing.。对于 FIFO,这个打开会阻塞直到有读端(例如utxo_to_sqlite.py进程)接入,管道写读两端就此会合。
判断依据是标准库的 fs::is_fifo(),即 POSIX 语义下的 FIFO 特殊文件(可用 mkfifo 系统调用或命令创建,参考 mkfifo(1)、mkfifo(3) 手册)。这也界定了平台适用性:Windows 上没有这种文件类型,因此该能力仅适用于类 UNIX 系统。
配套工具:utxo_to_sqlite.py 流式消费
contrib/utxo-tools/utxo_to_sqlite.py 是一个把压缩序列化 UTXO 集合转换为 SQLite3 数据库的 Python 脚本,正是文档点名的典型消费方。其输入格式与 dumptxoutset 的输出完全对应:
- 头部元数据:magic
utxo\xff、版本号(当前支持 2)、网络魔数(识别 Mainnet/Signet/Testnet3/Testnet4/Regtest)、基块哈希(32 字节)、UTXO 数量(8 字节小端)(utxo_to_sqlite.py#L140-L153); - 逐条记录:按
COutPoint(prevout hash + vout,hash 按 32 字节复用编码)+Coin(压缩的 height/coinbase 编码、DecompressAmount金额、DecompressScript脚本)解码,与核心compressor模块的编码互为逆操作。
脚本的命令行接口:
utxo_to_sqlite.py INFILE OUTFILE [--verbose] [--spk {hex,raw}] [--txid {hex,raw,rawle}]
- 输出表结构:
utxos(txid TEXT|BLOB, vout INT, value INT, coinbase INT, height INT, scriptpubkey TEXT|BLOB); --spk=raw/--txid=raw(或rawle,小端字节序)时相应列存为 BLOB,默认均为 hex 文本;- 每 16K 条批量
executemany+ commit,每 1M 条打印进度百分比;结束后还会校验输入已到 EOF,防止截断文件蒙混过关。
实战:命名管道一步到位的完整命令
传统两步做法(先落盘再转换):
bitcoin-cli dumptxoutset ~/utxos.dat latest
python3 contrib/utxo-tools/utxo_to_sqlite.py ~/utxos.dat ~/utxos.sqlite
借助命名管道,两步可以合并为一步流式管道(数据全程不落盘):
mkfifo /tmp/utxos.fifo
python3 contrib/utxo-tools/utxo_to_sqlite.py /tmp/utxos.fifo /tmp/utxos.sqlite &
bitcoin-cli -rpcclienttimeout=0 dumptxoutset /tmp/utxos.fifo latest
要点:
- 先启动读端脚本(其
open(infile, 'rb')会打开 FIFO 并阻塞等待写端),再执行dumptxoutset;顺序反过来由fopen语义保证也不会丢数据——两端都阻塞在 open 上,谁先执行都可以会合,但脚本若先因os.path.exists检查失败则不行,所以先mkfifo出 FIFO 是前提。 dumptxoutset打开 FIFO 后直接写(源码中temppath == path分支),utxo_to_sqlite.py边读边插入 SQLite,结束时打印TOTAL: N coins written to ...即表示流结束。- 快照很大时记得
-rpcclienttimeout=0,否则 cli 可能提前超时。
与 rollback 组合:历史快照也支持管道
dumptxoutset 的 rollback 模式会临时构建一个历史高度的 UTXO 数据库(leveldb)再导出。从源码看,回滚时若节点处于 prune 模式,handler 会先用 TemporaryPruneLock(RAII,锁名 dumptxoutset-rollback)在目标高度上注册修剪锁,防止回滚所需块数据在过程中被 prune 掉(src/rpc/blockchain.cpp#L3048-L3065、L3161-L3170);in_memory=true 时该临时数据库通过 DBParams{.memory_only = true} 完全驻留内存(src/rpc/blockchain.cpp#L3231-L3239)。命名管道与 rollback 正交可组合:把 path 换成 FIFO,即可把任意历史高度的 UTXO 集直接流式送给消费端,例如:
python3 contrib/utxo-tools/utxo_to_sqlite.py /tmp/utxos.fifo /tmp/utxos_h.sqlite &
bitcoin-cli -rpcclienttimeout=0 -named dumptxoutset /tmp/utxos.fifo rollback=853456 in_memory=true
需要提醒的既有前提(并非本特性引入):回滚深度受本地保留块数据限制,若目标高度早于 prune 后的首个块会报 Could not roll back to requested height since necessary block data is already pruned.;非正常关闭可能残留 temp_utxo_<height> 临时数据库目录,需要手动清理。
测试验证:功能测试如何覆盖管道路径
功能测试 test/functional/tool_utxo_to_sqlite.py 完整覆盖了该特性:
- 在 10 个块中造出 P2PKH、P2SH、P2PK(压缩/非压缩)、多签、P2WPKH、P2WSH、P2TR、PAY_TO_ANCHOR 及最大 10000 字节大脚本等各类输出,确保
DecompressScript的所有编码分支都被触达(tool_utxo_to_sqlite.py#L85-L118); - 用
dumptxoutset导出后,对--txid与--spk的全部 6 种编码组合分别转成 SQLite,并用coinstatsindex的 MuHash 与节点gettxoutsetinfo('muhash')逐一对比,证明转换无损(L124-L137); - 管道路径专测(L139-L152):非 Windows 平台上
os.mkfifo创建 FIFO,先以子进程启动utxo_to_sqlite.py读 FIFO,再调node.dumptxoutset(fifo, "rollback", {"rollback": target_height})把历史快照直接写进管道,最后比对 SQLite 重建的 MuHash 与gettxoutsetinfo('muhash', target_height)一致——即"rollback + 命名管道"的端到端正确性由测试固化。
小结
- 变更本身很小但实用:
dumptxoutset的path参数现在接受 FIFO,内部通过fs::is_fifo区分"先写.incomplete再 rename"(普通文件)与"直写不 rename"(管道)两条路径,并豁免对已存在 FIFO 的报错; - 收益:UTXO 快照的导出与下游解析之间省掉一次完整磁盘往返,
dumptxoutset | utxo_to_sqlite.py一步得到可查询的 SQLite 数据库,对"分析当前或历史 UTXO 集"的场景尤其友好; - 边界:仅类 UNIX 系统可用(Windows 无 FIFO);回滚导出仍受 prune 状态与 RAM 约束;管道中途断开会导致写端收到错误、快照不完整,建议配合功能测试中"先起读端、后开写端"的顺序操作。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00