协议演进 / BIP/比特币改进提案 / BIP-114

BIP-114 默克尔化抽象语法树

定义一种用默克尔树编码互斥脚本分支的新 witness 程序(版本 1、32 字节的 MAST 根),花费时只揭示实际执行的那一支,未执行分支不公开,赎回体积从与分支数成正比降为对数级。本 BIP 目前处于已关闭状态。

一、档案卡

档案卡
编号BIP-114
标题Merkelized Abstract Syntax Tree
作者Johnson Lau <[email protected]>
指定日期2016-04-02
层级Consensus (soft fork)(共识(软分叉))
类型Specification(规范类)
状态Closed(已关闭)
阅读版https://bips.dev/114
官方原文https://github.com/bitcoin/bips/blob/master/bip-0114.mediawiki

二、放在哪一族

脚本表达能力演进族,站在两步改革的延长线上:

BIP-16:P2SH——把赎回条件从 scriptPubKey 换成一个 20 字节哈希,花费时才由赎回者给出脚本,解决了“条件难指定、大脚本占 UTXO、发送方付费”三个问题

BIP-141:隔离见证(共识层)——P2WSH 把脚本移入 witness,恢复 10,000 字节脚本上限;本 BIP 明确依赖(depends on)BIP-141 部署

BIP-114:再进一步——P2SH 与 P2WSH 在花费时都必须公开脚本的全部分支,包括没有执行的那些;MAST 则只公开执行的一支

它的例题直接取自时间锁族:把 BIP-112 的带超时托管、HTLC 脚本“压平”为若干互斥分支,展示分支化之后的可读性与体积收益。思想来源上,原文致谢称 MAST 的想法来自 Russell O’Connor、Pieter Wuille 与 Peter Todd。

后来 Taproot 的脚本树(taptree,见 BIP-341)以不同机制实现了“只揭示所走的那一支”这一核心直觉;但那是另一套设计,不能与本提案混为一谈——本提案本身从未激活。

三、它要解决什么

3.1 原始脚本模型的五个问题

原文回顾了比特币脚本系统的演进,并列出原始设计对复杂脚本的不足:

  1. 接收方难以指定赎回条件;
  2. 大脚本占用更多 UTXO 空间;
  3. 追加的区块空间由发送方付费;
  4. 为防 DoS,脚本被限制在 10,000 字节、201 个操作码以内;
  5. 脚本中未执行的分支、以及非共识强制的数据,对全网公开,既占区块空间,又损害隐私。

BIP-16 修好了前三条,但受脚本中数据推送 520 字节上限约束,P2SH 脚本不能超过 520 字节,且花费时仍须公开全部未执行分支。BIP-141 的 P2WSH 把上限恢复回 10,000 字节,但同样要公开未执行分支。

3.2 MAST 的解法

用默克尔树编码脚本的各个分支。花费时,用户只需提供所执行的分支,以及把这些分支连接到固定大小的默克尔根所需的哈希。赎回栈的体积由此从 O(n) 降到 O(log n)(n 为分支数)。随之而来的好处,原文列了三项:

四、规则本身

4.1 新的 witness 程序类型

在 BIP-141 下,版本字节为 1 或更大的 witness 程序被视为任何人可花费(anyone-can-spend)。本 BIP 新增验证规则:当 witness 程序的版本字节为 1、且程序大小为 32 字节时,该程序即 MAST Root;若版本为 1 但程序不是 32 字节,则不对程序或 witness 栈作进一步解释,留作未来扩展。

4.2 花费时 witness 的构成

赎回此类输出时,witness 自底向上依次为:

4.3 哈希的计算

计算出的 MAST Root 与 witness 程序不符,脚本即失败。

4.4 版本 0 的执行规则

4.5 受限的 MAST:先压平,再上树

原文说明,本提案是一般化 MAST 的一个受限情形:只允许执行一条分支,用户须把复杂条件先变换为若干互斥分支。例如 (A or B) and (C or D or E) and (F or G),在一般化设计里是 7 个分支加一份“总条件”;在本提案里须展开为 12 个互斥分支,构成 4 层默克尔树,花费时只出示其中一条。

这样取舍的收益是:Subscript 在 witness 栈中的位置固定,可以做静态分析(如静态计算 SigOpsCost、对含禁用操作码的脚本提前终止);合约各方若不想互相暴露脚本,只需彼此提供 H(Subscript),把原文留到赎回时。代价只在条件非常复杂时出现:分支数可能更多、赎回 witness 可能更占空间,建树与存储成本由合约相关方自己承担。

原文举了量级感很强的例子:现行 CHECKMULTISIG 最多 20 个公钥,用 MAST 可把一个 3-of-2000 多签展开为 1,331,334,000 个 3-of-3 的 CHECKMULTISIGVERIFY 分支、构成 31 层 MAST,而 scriptPubKey 仍保持固定 34 字节,赎回 witness 不到 1,500 字节。又如把“消息签名密钥”作为一个分支作数据承诺,最多只多花 32 字节或零成本。

4.6 尚未闭合之处

原文有两处细节留作占位:MAST Script 求值时配套的新增或重定义操作码,写为 “BIPXXX”;SigOpsCost 的计数方式,写为 “BIPYYY”。部署一节也只写:本 BIP 依赖 BIP-141,将在 BIP-141 强制执行后以 BIP-9(version bits)部署,具体细节待定(Exact details TBD)。参考实现标注为进行中(WIP)。

五、谁必须动

普通持币人:无直接操作。不使用 MAST 输出的资金不受影响。

钱包开发者:构造 MAST 输出的一方要负责把条件压平为互斥分支、建树、保管各分支脚本与路径;花费时只组装所走分支的 witness。原文在向后兼容一节特别提醒:钱包应始终警惕任何人可花费的脚本——在未升级节点眼里,MAST 程序正是这种形态。

全节点与矿工:升级节点按新规则验证版本 1、32 字节的 witness 程序;未升级节点把这类程序当作任何人可花费脚本,仍能正常运行——这是软分叉的形态。

共识层:新增一类 witness 程序的解释规则。它不改既有脚本的语义,但一旦上线,未升级节点对 MAST 输出的“有效性”判断会与升级节点不同,这正是它须走 BIP-9 部署的原因。

六、现在算不算数,以及一个常见误读

状态为 Closed(已关闭)。它从未在比特币主网激活,部署细节在原文中始终是“待定”,配套操作码与 SigOpsCost 的引用也停留在占位符。今天在链上实际运行的“只揭示一支”的机制是 Taproot 的脚本树,其结构、哈希与版本安排都与本提案不同。读 BIP-114,是为了理解 MAST 这一思想最初被完整写成规范时的样子:它想解决的问题、它受限的设计、以及它未走完的最后一步。

常见误读:

“Taproot 就是 BIP-114 的实现,所以 BIP-114 其实已经上线了。”

不对。两者共享“用默克尔树组织脚本分支、花费时只揭示一支”的核心直觉,但 Taproot 是一套独立的新设计(见 BIP-341、BIP-342),其 witness 程序版本、树的构造与脚本版本安排都不是按 BIP-114 的规范来的。BIP-114 本身的状态是 Closed,把它等同于 Taproot,会同时抹掉两份文档各自的具体规则。

七、延伸

本页内容整理自 bitcoin/bips 仓库与 bips.dev,事实已与仓库核对;解读仅供学习参考。