Bitcoin Core 0.16.3 发布说明深度解析:CVE-2018-17144 拒绝服务漏洞修复与版本升级要点
本文基于 Bitcoin Core 仓库中 release-notes-0.16.3.md 发布说明展开,覆盖 0.16.3 小版本发布的完整背景:面向矿工的拒绝服务漏洞(CVE-2018-17144)是如何被定位并修复的、0.16 系列的升级/降级注意事项与链状态(chainstate)格式兼容性问题,以及该版本全部四条变更记录(共识修复、signrawtransaction* 报错行为、bitcoinconsensus 库错误码、-prune 帮助文本)在当前代码库中的对应实现位置,读完可掌握一次安全小版本发布的完整技术脉络。
一、发布概览与定位
0.16.3 是 Bitcoin Core 0.16.x 系列中的一个新小版本(minor release),发布说明明确其定位是"包含若干 bug 修复的补丁版本"。它的核心驱动力是一个需要尽快修复的安全问题:在 0.14.0 至 0.16.2 版本间存在的、可被矿工利用的拒绝服务(Denial-of-Service)漏洞 CVE-2018-17144。发布说明给出的建议是——任何运行在受漏洞影响版本上的节点都应尽快升级到 0.16.3。
该版本共有 6 位贡献者直接参与(Anthony Towns、Hennadii Stepanov、Matt Corallo、Suhas Daftuar、Thomas Kerin、Wladimir J. van der Laan),安全问题的报告者为匿名。
二、如何升级(含链状态格式转换注意事项)
发布说明中"如何升级"一节给出了完整的操作路径,这里完整继承并说明其每一步的技术含义:
- 先关闭旧版本:如果正在运行更旧的版本,先将其关闭。
- 等待完全退出:旧版本完全退出可能需要几分钟(老版本尤其如此),必须等待进程真正终止,避免对链数据库的并发写入。
- 替换程序文件:
- Windows:运行安装包;
- macOS:替换
/Applications/Bitcoin-Qt; - Linux:替换
bitcoind/bitcoin-qt可执行文件。
- 首次运行 0.15.0 或更新版本时的链状态转换:第一次运行 0.15.0 及以后版本时,chainstate 数据库会被转换为新格式,耗时从几分钟到半小时不等,取决于机器速度。因此从 0.14 及更早版本升级的用户,除了替换二进制之外,还要预留这次数据库迁移时间。
- 更老版本的不兼容边界:块数据库(block database)格式在 0.8.0 也发生过变化,不存在 0.8 之前版本到 0.15.0 及以上版本的自动升级代码。也就是说,从 0.7.x 及更早版本直接升级、且不重新下载区块链,是不受支持的;不过旧格式的钱包文件(
wallet.dat)一如既往仍然受支持。
三、降级警告:0.16+ 钱包与旧版本不兼容
发布说明特别给出了"降级警告"小节,这一点在实际运维中容易被忽视:
- 0.16 及以后版本创建的新钱包与 0.16 之前的版本不兼容。如果在旧版本中尝试使用新创建的钱包,将无法工作。
- 用旧版本创建的已有钱包不受影响,降级后仍可正常使用。
因此,如果你计划长期停留在 0.16 之前的版本,不应在升级期间创建新钱包;或者干脆不要降级。
四、兼容性说明
发布说明"兼容性"一节给出 0.16.3 时代的支持矩阵:
- 经过充分测试的操作系统:基于 Linux 内核的系统、macOS 10.8+、Windows Vista 及以后版本;
- Windows XP 不受支持;
- 其他大多数类 Unix 系统上"应该也能工作",但没有被频繁测试。
需要注意的是,这是 0.16.3 发布时的兼容性描述。当前仓库(Bitcoin Core master)已经切换到 CMake 构建体系(见 CMakeLists.txt),其支持的构建平台由 ci/ 与 depends/ 下的交叉编译环境脚本共同覆盖(如 ci/test/00_setup_env_mac_native.sh、depends/hosts/ 等),实际支持范围远大于当年的描述,两者不要混淆。
五、CVE-2018-17144:可被矿工利用的拒绝服务漏洞
5.1 漏洞机制
0.16.3 发布说明指出,CVE-2018-17144 存在于 0.14.0 至 0.16.2 的 Bitcoin Core 中,且可被矿工利用。其原理可以从当前源码中直接印证。
在 src/consensus/tx_check.cpp 中,CheckTransaction() 里有如下注释与检查代码:
// Check for duplicate inputs (see CVE-2018-17144)
// While Consensus::CheckTxInputs does check if all inputs of a tx are available, and UpdateCoins marks all inputs
// of a tx as spent, it does not check if the tx has duplicate inputs.
// Failure to run this check will result in either a crash or an inflation bug, depending on the implementation of
// the underlying coins database.
std::set<COutPoint> vInOutPoints;
for (const auto& txin : tx.vin) {
if (!vInOutPoints.insert(txin.prevout).second)
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-inputs-duplicate");
}
要点拆解:
- 漏洞根源:
Consensus::CheckTxInputs只检查交易的所有输入是否"可用(available)",UpdateCoins会把交易的所有输入标记为已花费,但两者都不检查交易内部是否存在重复输入。 - 后果:缺少这个检查时,"根据底层 coins 数据库的实现不同,结果要么是崩溃,要么是通胀 bug(inflation bug)"。对 0.16.3 之前的实际表现是崩溃,即拒绝服务。
- 修复方式:在
CheckTransaction()(不依赖任何上下文的基础校验函数)中,用一个std::set<COutPoint>收集所有txin.prevout,一旦insert失败(即同一个上一输出prevout出现两次),就以TX_CONSENSUS级别拒绝该交易,拒绝原因为bad-txns-inputs-duplicate。 - 可被矿工利用的原因:只有矿工能通过打包交易把这样的恶意交易放进区块;攻击者只需挖出一个包含"重复输入交易"的区块,所有验证该区块的节点都会在连接区块时崩溃/断链,而攻击者自己可以停在旧高度或跳过该区块,从而获得相对优势。这就是发布说明中"exploitable by miners"的含义。
5.2 该检查在验证流程中的位置
从源码结构看,CheckTransaction() 是上下文无关(context-free)的基础交易校验,它在两条路径上被执行(见 src/consensus/tx_verify.cpp 中的注释):
- 内存池路径:
MemPoolAccept::PreChecks在更早阶段就会调用CheckTransaction(); - 区块连接路径:
Chainstate::ConnectBlock通过CheckBlock()调用CheckTransaction()。
这意味着恶意交易无论走"广播进内存池"还是"直接打包进区块",都会在进入共识状态之前被以 bad-txns-inputs-duplicate 拒绝。另外,src/policy/packages.h 中的注释也明确将"同一 prevout 在一次交易中被引用多次"的冲突归口到 CheckTransaction() 处理(see bad-txns-inputs-duplicate in CheckTransaction()),并在 src/validation.cpp 附近有同样的引用,说明包(package)验证逻辑在设计上依赖这一共识级检查。
5.3 仓库中的可运行验证:重复输入基准测试
当前仓库自带一个专门针对该漏洞修复的基准测试 src/bench/duplicate_inputs.cpp。它的做法是:
- 构造一个合法 coinbase 交易,以及一个"naughty"(恶意)交易;
- 恶意交易填充约
((MAX_BLOCK_SERIALIZED_SIZE / WITNESS_SCALE_FACTOR) - 两个交易已占用大小) / 41 - 100个随机输入,并在最后一个输入上再追加一个与末尾输入完全相同的prevout(naughtyTx.vin.emplace_back(naughtyTx.vin.back()),见 src/bench/duplicate_inputs.cpp#L65),即人为制造重复输入,同时让区块逼近大小上限以检验攻击载荷的规模; - 在基准循环中反复调用
CheckBlock(),并断言两个事实(见 src/bench/duplicate_inputs.cpp#L72-L76):
bench.run([&] {
BlockValidationState cvstate{};
assert(!CheckBlock(block, cvstate, chainparams.GetConsensus(), false, false));
assert(cvstate.GetRejectReason() == "bad-txns-inputs-duplicate");
});
CheckBlock()必须返回失败;- 拒绝原因必须精确等于
bad-txns-inputs-duplicate。
这是"修复有效"的最直接证据:只要该断言通过,就说明 CVE-2018-17144 的攻击区块会在块校验阶段被确定性拒绝,而不是导致崩溃。
六、0.16.3 完整变更记录(Change Log)逐条解读
发布说明共列出 4 条变更,下面逐条给出其在当前仓库中的对应实现线索。
6.1 Consensus:修复交易内重复输入导致的崩溃(#14249)
- 原始记录:
#14249 696b936 Fix crash bug with duplicate inputs within a transaction (TheBlueMatt, sdaftuar)。 - 即第五节详细剖析的 CVE-2018-17144 修复。当前实现落在 src/consensus/tx_check.cpp 的重复输入检查中,配套验证见 src/bench/duplicate_inputs.cpp。
6.2 RPC and other APIs:signrawtransaction* 缺少金额时给出错误(#13547)
- 原始记录:
#13547 212ef1f Make signrawtransaction* give an error when amount is needed but missing (ajtowns)。 - 背景:
signrawtransaction/signrawtransactionwithkey等 RPC 在签名时若缺少输出金额信息(例如 UTXO 数据不完整),0.16.3 之前的行为可能静默地部分签名;该修复让这类"需要金额却拿不到金额"的情形明确返回错误,避免用户误以为交易已完整签名。 - 在当前仓库中,
signrawtransaction*系列 RPC 的实现位于 src/rpc/rawtransaction.cpp,客户端参数注册在 src/rpc/client.cpp,行为测试覆盖在 src/test/rpc_tests.cpp 与模糊测试 src/test/fuzz/rpc.cpp 中,可作为回归验证的入口。
6.3 Miscellaneous:bitcoinconsensus 库错误码修正(#13655)
- 原始记录:
#13655 1cdbea7 bitcoinconsensus: invalid flags error should be set to bitcoinconsensus_err (afk11)。 - 含义:
bitcoinconsensus是 Bitcoin Core 对外提供的轻量级共识校验 C 库(bitcoinconsensus_verify系列接口),供不想链接完整 Core 的第三方做交易脚本/共识验证。该修复修正了一个错误处理 bug:当调用方传入了非法的验证标志(invalid flags)时,错误应正确设置到库的bitcoinconsensus_err错误槽位中,而不是丢失或置错。 - 适用对象是使用 libbitcoinconsensus 的嵌入方:如果你在程序里调用了该库并依赖其错误码分支,升级时需注意错误信息的语义变化。当前仓库已重构为
libbitcoinkernel体系(见 libbitcoinkernel.pc.in 与 doc/design/libraries.md),但 0.16.3 这条记录反映的是当年独立bitcoinconsensus目标的行为修正。
6.4 Documentation:修正 -prune 的帮助输出(#13844)
- 原始记录:
#13844 11b9dbb correct the help output for -prune (hebasto)。 - 含义:
-prune是控制区块文件修剪(pruning)的启动参数,用于在保留 UTXO 集的同时释放区块链占用的磁盘空间。本修复纠正了-prune在帮助输出中的说明文本,使其与真实行为一致,避免用户按错误说明配置修剪值。 - 仓库中与磁盘空间缩减相关的现行文档可参考 doc/reduce-memory.md 与 doc/reduce-traffic.md,配置文件示例见 share/examples/bitcoin.conf,可用于理解
prune=在配置文件中的一般写法。
七、给运维者的操作核对清单
把发布说明整理成可执行的检查清单:
- 确认版本范围:若节点版本落在 0.14.0 ~ 0.16.2(含)区间,升级优先级为最高(CVE-2018-17144 可被矿工利用)。
- 升级前:停止旧节点并等待其完全退出;确认备份了
wallet.dat等用户数据文件(发布说明未要求备份,但这是替换二进制前的通用安全习惯)。 - 升级中:按平台替换程序(Windows 安装包 / macOS 替换
Bitcoin-Qt/ Linux 替换bitcoind、bitcoin-qt)。 - 升级后首次启动:预留 chainstate 数据库格式转换时间(几分钟至半小时)。
- 若计划降级:确认没有在 0.16+ 中新建钱包,否则新钱包在旧版本中不可用。
- 若使用 0.7.x 及更早的数据目录:0.16.3 不提供自动链数据库迁移,需重新同步区块链(钱包文件仍可继续使用)。
八、小结
0.16.3 是 0.16 系列中一次典型的"安全驱动"小版本发布:核心是 #14249 对交易内重复输入共识校验的补强,直接封堵了可被矿工利用、能导致节点崩溃的 CVE-2018-17144;配套三条变更分别改进了 signrawtransaction* 的错误反馈、libbitcoinconsensus 的错误码正确性与 -prune 的帮助文本。在当前仓库中,修复代码(src/consensus/tx_check.cpp)与回归基准(src/bench/duplicate_inputs.cpp)至今可查可跑,是理解"一条 release note 背后从漏洞机理到共识代码再到验证用例"完整链条的最佳样本。
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 StartedRust0627
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