首页
/ Bitcoin Core 发布说明解读:taproot 从 getdeploymentinfo 中移除及 Taproot 检测的替代方案

Bitcoin Core 发布说明解读:taproot 从 getdeploymentinfo 中移除及 Taproot 检测的替代方案

2026-09-06 10:34:27作者:韦蓉瑛

本文解读 Bitcoin Core 发布说明 release-notes-26201.md:自该改动起,getdeploymentinfodeployments 对象中不再包含 taproot 条目,因为其历史激活高度已不再被代码库任何位置引用。读完本文,你将掌握 getdeploymentinfo 的完整返回结构、script_flags 数组的生成原理,以及依赖旧字段检测 Taproot 支持的应用应如何迁移——要么假定 Taproot 自 v24.0 起永远激活,要么改为检查 script_flags 中的 TAPROOT 标志(自 v31.0 起可用)。

一、发布说明原文:发生了什么

该发布说明归属于 RPC 类别,完整内容只有一条变更(对应上游 PR #26201):

'taproot' has been removed from 'getdeploymentinfo' because its historical activation height is no longer used anywhere in the codebase. Applications that rely on deployments.taproot to detect Taproot support should either assume Taproot to be always active (since Bitcoin Core v24.0), or check for TAPROOT in the script_flags array returned by getdeploymentinfo (since Bitcoin Core v31.0).

要点拆解:

  1. 移除对象getdeploymentinfo 返回值的 deployments.taproot 字段;
  2. 移除原因:Taproot 的历史激活高度(historical activation height)已不被代码库中任何地方使用,保留该条目纯属冗余;
  3. 官方给出的两条迁移路径
    • 直接假定 Taproot 永远激活(对主网而言,自 Bitcoin Core v24.0 起这是安全的);
    • 或检查 getdeploymentinfo 返回的 script_flags 数组中是否含有 TAPROOT(该数组自 Bitcoin Core v31.0 起存在)。

这属于一个破坏性 RPC 变更:任何通过 "taproot" in deployments 判断链是否支持 Taproot 的外部程序,在新版本节点上会检测失败。理解其背景和替代机制是升级节点前必须做的事。

二、为什么可以移除:从源码看 Taproot 的激活方式

要理解"历史激活高度不再被使用"这句话,需要区分 Bitcoin Core 中软分叉(softfork)的两种激活机制。

2.1 Buried Deployment 与 BIP9 Deployment

共识参数头文件 src/consensus/params.h 中定义了两种部署枚举:

  • BuriedDeployment(埋入式部署):激活高度在共识变更早已激活之后被硬编码进客户端实现(参见 BIP 90 思路)。该文件注释明确写道:

    "A buried deployment is one where the height of the activation has been hardcoded into the client implementation long after the consensus change has activated. See BIP 90. Consensus changes for which the new rules are enforced from genesis are not listed here."

    当前枚举只保留 5 项:DEPLOYMENT_HEIGHTINCBDEPLOYMENT_CLTVDEPLOYMENT_DERSIGDEPLOYMENT_CSVDEPLOYMENT_SEGWIT——注意其中已经没有 DEPLOYMENT_TAPROOT,这正是 PR #26201 落地的直接证据。

  • DeploymentPos(BIP9 部署):通过区块版本号位(version bit)信号投票激活的变更,见同文件 DeploymentPos 枚举

2.2 为什么 Taproot 不需要"埋入高度"

Taproot 的激活高度曾长期保留在 BuriedDeployment 枚举中以供历史追溯,但代码库中真正执行 Taproot 规则的地方,并不通过查询这个高度来决定"是否启用"。从源码结构看,Taproot 的脚本验证标志是无条件开启的——验证层在计算某个区块应使用的脚本验证标志时,直接把 SCRIPT_VERIFY_TAPROOT 放在基础标志里,详见 GetBlockScriptFlags 实现

script_verify_flags GetBlockScriptFlags(const CBlockIndex& block_index, const ChainstateManager& chainman)
{
    const Consensus::Params& consensusparams = chainman.GetConsensus();

    // BIP16 didn't become active until Apr 1 2012 (on mainnet, and
    // retroactively applied to testnet)
    // However, only one historical block violated the P2SH rules (on both
    // mainnet and testnet).
    // Similarly, only one historical block violated the TAPROOT rules on
    // mainnet.
    // For simplicity, always leave P2SH+WITNESS+TAPROOT on except for the two
    // violating blocks.
    script_verify_flags flags{SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_TAPROOT};
    const auto it{consensusparams.script_flag_exceptions.find(*Assert(block_index.phashBlock))};
    if (it != consensusparams.script_flag_exceptions.end()) {
        flags = it->second;
    }
    ...
}

这段代码透露了两个关键设计事实:

  1. P2SHWITNESSTAPROOT 三个标志默认常开,不依赖任何激活高度查询;
  2. 主网上只有一个历史区块违反了 TAPROOT 规则(以及 P2SH 规则),因此通过 consensusparams.script_flag_exceptions 例外表单独豁免这两个区块,而不是把 TAPROOT 标志做成"高度达到才启用"的条件开关。

既然没有任何执行路径再去读 Taproot 的激活高度,getdeploymentinfo 中保留 deployments.taproot 条目及其 height 字段就成了纯展示性冗余——这正是发布说明中"its historical activation height is no longer used anywhere in the codebase"的准确含义。

三、推荐的替代方案:检查 script_flags 中的 TAPROOT

发布说明建议的第二条迁移路径,是把检测逻辑从 deployments 对象迁移到 script_flags 数组。

3.1 script_flags 是如何生成的

getdeploymentinfo 的实现位于 src/rpc/blockchain.cpp,其核心输出逻辑:

const auto flagnames = GetScriptFlagNames(GetBlockScriptFlags(*blockindex, chainman));
UniValue uv_flagnames(UniValue::VARR);
uv_flagnames.push_backV(flagnames.begin(), flagnames.end());
deploymentinfo.pushKV("script_flags", uv_flagnames);

也就是说,script_flags 数组不是一份独立的配置,而是直接复用区块验证时使用的同一套标志位计算逻辑 GetBlockScriptFlags,再经由 GetScriptFlagNames 将位掩码翻译为字符串名。函数把已知的 21 个标志名逐一映射(P2SHDERSIGWITNESSTAPROOT 等),无法识别的剩余位以十六进制补出,保证输出与实际生效的脚本验证规则严格一致。

由于上节已说明 GetBlockScriptFlags 默认常开 SCRIPT_VERIFY_TAPROOT,因此在正常同步的链尖上,script_flags 会稳定包含 TAPROOT。功能测试 test/functional/rpc_blockchain.py 也锁定了这一行为:

"script_flags": ["CHECKLOCKTIMEVERIFY","CHECKSEQUENCEVERIFY","DERSIG","NULLDUMMY","P2SH","TAPROOT","WITNESS"],

3.2 两条迁移路径的适用前提

迁移路径 做法 适用前提 / 限制
假定 Taproot 永远激活 删除 Taproot 检测代码,按已激活处理 主网场景,且节点/钱包最低版本可假定为 Bitcoin Core v24.0 及以上;不适用于仍支持极旧链状态的工具
检查 script_flagsTAPROOT 解析 getdeploymentinfo 返回的 script_flags 数组 需要节点已支持该数组(Bitcoin Core v31.0 起),旧版本节点不会返回此字段,检测逻辑需做存在性回退

从源码结构看,第二条路径更为通用:它回答的是"该高度上的区块实际执行哪些脚本规则"这一语义,而非某个历史部署条目的存在与否,语义上也更符合 getdeploymentinfo 的字段定位。

四、getdeploymentinfo 的完整结构与用法

结合 RPC 帮助定义,完整介绍该命令的入参与返回,便于直接对接:

命令getdeploymentinfo [blockhash]

参数

参数 类型 默认值 说明
blockhash string (hex) 当前链尖哈希 查询部署状态的区块哈希

返回对象(依据 RPCHelpForDeployment 及实现代码):

字段 类型 说明
hash string 请求的区块哈希(或链尖)
height numeric 请求的区块高度(或链尖)
script_flags array 该区块生效的脚本验证标志名称列表(如 TAPROOTWITNESSP2SHDERSIG 等),自 v31.0 起存在
deployments object 各软分叉部署状态,键为部署名(heightincbcltvdersigcsvsegwit 等;改动后不再含 taproot

deployments 下每个条目的结构(来自 RPCHelpForDeployment):

  • type"buried""bip9"
  • active:布尔值,规则是否已对内存池和下一个区块强制执行;
  • height:规则开始(或将要开始)强制执行的第一个区块高度(仅 buried 类型,或状态为 activebip9 类型);
  • bip9(仅 bip9 类型):含 bitstart_timetimeoutmin_activation_heightstatusdefined/started/locked_in/active/failed)、sincestatus_next,以及 started/locked_in 状态下的 statisticsperiodthresholdelapsedcountpossible)和 signalling 串。

注意实现细节:DeploymentInfo 函数(src/rpc/blockchain.cpp)通过逐项调用 SoftForkDescPushBack 填充 deployments 对象,当前列出 HEIGHTINCBDERSIGCLTVCSVSEGWITTESTDUMMY 六项——与 params.hBuriedDeployment 枚举项一一对应。命令自身的描述文案也呼应了这一设计:"Consensus changes for which the new rules are enforced from genesis are not listed in 'deployments'."(自创世起强制的规则不列入 deployments)。

五、对下游开发者的落地建议

  1. 升级前排查:搜索代码中对 getdeploymentinfo 返回值的 deployments.taproot / ["taproot"] / .get("taproot") 等访问,确认命中后按第 3.2 节两条路径改造;
  2. 优先改造为检查 script_flags"TAPROOT" in result["script_flags"],并对不支持 script_flags 字段的旧节点做回退(回退策略可直接假定 Taproot 已激活);
  3. 验证改造:可参考仓库内功能测试 test/functional/rpc_blockchain.py 中对 script_flags 的断言方式,以及 test/functional/feature_taproot.py 中对 Taproot 规则激活状态的测试,作为行为基准;
  4. 语义澄清deployments 回答"某部署的激活状态",script_flags 回答"该区块实际执行哪些脚本规则"。检测"链是否支持 Taproot"本质是后者问题,因此官方推荐以 script_flags 为准。

六、小结

PR #26201 移除 getdeploymentinfo 中的 taproot 条目,是一次基于代码考古的 API 瘦身:Taproot 的验证标志在 GetBlockScriptFlags 中无条件常开(仅对个别历史违规区块通过例外表豁免),其埋入激活高度失去存在意义后,BuriedDeployment 枚举(src/consensus/params.h)与 RPC 输出同步收敛。对依赖旧字段的应用,官方路径是"假定 Taproot 自 v24.0 起永远激活"或"检查 v31.0 起返回的 script_flags 数组中的 TAPROOT"——后者与区块验证逻辑同源,是语义更准确的长期方案。

登录后查看全文
热门项目推荐
相关项目推荐