协议演进 / BIP/比特币改进提案 / BIP-17
BIP-17
P2SH 之争中落败的一方:不用求值栈上的脚本,而是重定义 OP_NOP2 为 OP_CHECKHASHVERIFY,让收款方以哈希指定再花费所需的脚本。本 BIP 目前处于已关闭状态。
一、档案卡
| 编号 | BIP-17 |
|---|---|
| 标题 | OP_CHECKHASHVERIFY (CHV) |
| 作者 | Luke Dashjr <[email protected]> |
| 指定日期 | 2012-01-18 |
| 层级 | Consensus (soft fork)(共识(软分叉)) |
| 类型 | Specification(规范类) |
| 状态 | Closed(已关闭) |
| 阅读版 | https://bips.dev/17 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0017.mediawiki |
二、放在哪一族
P2SH(付给脚本哈希)之争中的一方,与 BIP-16 正面竞争。
三份文档目标完全相同:让收款方用一个 20 字节哈希指定“这笔钱将来要满足什么脚本才能花”,付款人只付给哈希。分歧只在实现机制:
- BIP-12(OP_EVAL):新增一个能“执行栈上脚本”的操作码,能力最强,也被认为最危险;
- BIP-16:不加操作码,认出一种特殊形式的 scriptPubKey 后做额外两阶段验证;
- BIP-17(本页):重定义既有的 OP_NOP2 为新操作码 OP_CHECKHASHVERIFY,只核对哈希、不“执行”被哈希的那段脚本——原文 Rationale 明说它意在取代 BIP-12 与 BIP-16 这两种“验完哈希再求值脚本”的路线。
配套关系与另外两方相同:应用场景来自 BIP-11 的 M-of-N 多签,地址格式用 BIP-13。结局是 BIP-16 被采用、本页关闭;其后 BIP-18 又进一步把表述重写,但走的仍是 BIP-16 的协议。
三、它要解决什么
动机与 BIP-16 原文几乎逐字相同,因为要解决的是同一个问题:
把“提供赎回条件”的责任,从付款人转移到赎回人。 这样付款人无论面对多复杂的花费条件,都只需要处理一个固定长度的 20 字节哈希:短到可以扫 QR 码、可以轻松复制粘贴。
同样,原文也记录了争议:有人认为复杂与多签交易直接把完整脚本给付款人即可,不必多此一举;作者的立场是哈希化能最小改动既有“向 20 字节地址付款”的基础设施,让商户、交易所与软件更快支持多签。
所以 BIP-17 的独立价值不在“要不要 P2SH”,而在“用哪种机制实现 P2SH 更安全、更干净”——它试图避开“把栈上数据当脚本执行”这一步。
四、规则本身
4.1 新操作码 OP_CHECKHASHVERIFY
它重定义既有的 OP_NOP2,执行时:
- 取“先前脚本的末尾部分”——一般即 scriptSig,自最后一个被求值的 OP_CODESEPARATOR 起(没有 OP_CODESEPARATOR 则自脚本开头;没有先前脚本则哈希空字符串)——计算其哈希;
- 与栈顶元素比较:栈为空则脚本立即失败;
- 哈希相符则什么都不做、如同 OP_NOP 继续执行;不符则脚本立即失败;
- 关键细节:相符时栈顶的哈希不弹出——这是为向后兼容保留的动作。
该操作码重定义只适用于时间戳在 2012 年 2 月 23 日之后的区块中的交易验证。
4.2 新的标准交易类型
[20-byte-hash-value] OP_CHECKHASHVERIFY OP_DROP
其中哈希值部分必须是压入 20 字节的操作码(0x14)后跟恰好 20 字节。
对应的花费 scriptSig 为:
...signatures... OP_CODESEPARATOR {script}
花费交易要算标准,必须恰好包含一个 OP_CODESEPARATOR,且其后附加的脚本本身属于其他标准交易类型之一。
4.3 例
单签:
scriptSig: [signature] OP_CODESEPARATOR [pubkey] OP_CHECKSIG
scriptPubKey: [20-byte-hash of {[pubkey] OP_CHECKSIG}] OP_CHECKHASHVERIFY OP_DROP
2-of-3 多签同理:OP_CODESEPARATOR 后接 2 [pubkey1] [pubkey2] [pubkey3] 3 OP_CHECKMULTISIG,scriptPubKey 里放该脚本的 20 字节哈希。
与 BIP-16 对照着看差别最清楚:BIP-16 是把序列化脚本作为数据压栈、再取出当作 scriptPubKey 执行;BIP-17 是脚本本体仍写在 scriptSig 里、用 OP_CODESEPARATOR 划界,操作码只负责“核对这一段的哈希是否与输出承诺的一致”。
五、谁必须动
普通持币人 / 付款人:与 BIP-16 情形相同,只向短哈希付款,不必处理完整脚本。
收款方 / 钱包开发者:保管完整脚本,花费时按“签名 … OP_CODESEPARATOR 脚本”的格式出示,且脚本须为标准类型。
全节点与矿工(共识层):需实现 OP_NOP2 的重定义与新验证规则,并按第六节的办法以 coinbase 字符串 “p2sh/CHV” 表态、在门槛达标后统一切换。
旧实现:把这类交易视为非标准,通常不转发、不打包。且与 BIP-16 不同,原文明确指出:旧实现在验证支持本提案的软件所建的区块时,不会核对脚本哈希是否匹配。原文同时保留了与 BIP-16 相同的 1 确认攻击说明(旧软件看有效、新软件看无效的交易被自挖出块后骗 1 确认放货),评定为成本高、实操难。原文还提到:选用 OP_NOP2,是为了让链上已有的 OP_EVAL(BIP-12)交易仍可被赎回。
六、现在算不算数,以及一个常见误读
状态为 Closed:未获采用,已经关闭。它设计的部署门槛(2012 年 2 月 8 日检查此前 7 天区块,coinbase 含 “p2sh/CHV” 的须达 60%,达标则 2 月 23 日后全面验证;多数算力不支持则推迟乃至否决)没有走完——P2SH 这场竞争的胜出者是 BIP-16,其状态为 Deployed、已实际激活。
因此今天链上的 P2SH 输出长的是 BIP-16 的样子(OP_HASH160 <hash> OP_EQUAL),不是本页的 <hash> OP_CHECKHASHVERIFY OP_DROP;OP_NOP2 后来也没有变成 OP_CHECKHASHVERIFY。本页的价值是档案性的:它完整保留了当年关于“是否应该让脚本系统求值栈上脚本”的另一种答案。
常见误读:
“BIP-17 是 P2SH 的另一个名字,内容和 BIP-16 一样。”
不对。目标一样,机制是互斥的竞争关系:原文 Rationale 直说本提案要取代 BIP-12 与 BIP-16。一个被采用、一个被关闭,读历史时不能把两者混成同一份规范。
七、延伸
- 阅读版:https://bips.dev/17
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0017.mediawiki
- 相关:BIP-16 P2SH(被采用的一方)、BIP-11 M-of-N 标准交易、BIP-13 P2SH 地址格式、BIP-12 OP_EVAL、BIP-18 hashScriptCheck
- 仓库总目录:https://github.com/bitcoin/bips
