协议演进 / BIP/比特币改进提案 / BIP-119
BIP-119
新增 OP_CHECKTEMPLATEVERIFY,让输出只能被一笔与预先承诺的交易模板哈希完全一致的交易花费。本 BIP 目前处于草案状态。
一、档案卡
| 编号 | BIP-119 |
|---|---|
| 标题 | CHECKTEMPLATEVERIFY |
| 作者 | Jeremy Rubin <[email protected]> |
| 指定日期 | 2020-01-06 |
| 层级 | Consensus (soft fork)(共识(软分叉)) |
| 类型 | Specification(规范类) |
| 状态 | Draft(草案) |
| 阅读版 | https://bips.dev/119 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0119.mediawiki |
二、放在哪一族
契约(covenant)族的核心提案:脚本第一次能约束“这枚币下一步必须变成什么样”,而不只是“谁能花”。它的前身是只承诺输出哈希的 OP_CHECKOUTPUTSHASHVERIFY,因不承诺版本号与锁定时间而不安全,已被本提案取代;它也曾被叫作 OP_SECURETHEBAG。
谱系上,它与 BIP-116/BIP-117 的 MAST 路线都着眼于让脚本表达更强的花费条件,但手段不同:那一族是“承诺一组策略、按需揭示并执行”,BIP-119 是“承诺一笔未来交易的确切模板、花费时逐字段核对”。与 BIP-118(SIGHASH_ANYPREVOUT)的关系原文专门论述:ANYSCRIPT 模式能用预签签名模拟模板,但 CTV 限制更死(输入个数、找零方式都被钉住)、只需哈希运算、脚本更短,且为未来模板升级(如 OP_TXHASH 一类设想)留了路径。原文还指出,OP_VAULT、OP_CHECKCONTRACTVERIFY、OP_TXHASH 等后续提案在其当前设计中都把 CTV 作为组成部分。
部署手法沿用先例:重定义一个 OP_NOP(这里是 OP_NOP4),与 BIP-65、BIP-112 改写 OP_NOP 语义的方式相同。
三、它要解决什么
3.1 预签名的三大成本
在没有契约原语时,想预先定好一枚币的去向,只能预签交易。原文指出这带来三类成本:
- 信任:预签交易要交给某方保管,保管方可能丢失或滥用;
- 交互:多方场景里,每换一种情形就要多方再签一轮;
- 存储:所有可能情形都要事先签好存好,情形一多就不可收拾。
3.2 把“去向”写进输出本身
OP_CHECKTEMPLATEVERIFY 引入交易模板:一种简单的花费限制,把实际花费交易与一个哈希化的交易规格做模式匹配。去向直接由脚本强制,不再依赖任何人保管签名——想按别的样子花,验证直接失败。原文列举的应用方向包括金库(vault)、支付池、拥堵控制、批量创建通道以及离散对数合约(DLC)等,具体构造见原文参考文献。
四、规则本身
4.1 操作码语义
OP_CHECKTEMPLATEVERIFY 使用 OP_NOP4(0xb3)。执行规则:
- 栈为空,失败;
- 栈顶元素不是 32 字节时,按 NOP 处理(共识层面);推荐的标准性规则对此类用法以 SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS 拒绝,为未来给其他长度赋义留路;
- 栈顶元素为 32 字节时,计算当前交易在当前输入序号下的 DefaultCheckTemplateVerifyHash,与栈顶不相等则失败;相等则按 NOP 继续。
最常见的裸形式是 34 字节脚本:0x20 <32 字节哈希> OP_CHECKTEMPLATEVERIFY。
4.2 模板哈希承诺了什么
DefaultCheckTemplateVerifyHash 是对以下字段按固定顺序拼接后取 SHA256:
- nVersion(4 字节,小端);
- nLockTime(4 字节,小端);
- scriptSigs 哈希(32 字节;仅当任一输入的 scriptSig 非空时才包含——SegWit 输入的 scriptSig 本就为空,通常省去);
- 输入个数(4 字节);
- sequences 哈希(32 字节:全部输入 nSequence 的 SHA256,与 BIP-341 的预计算值相同);
- 输出个数(4 字节);
- outputs 哈希(32 字节:全部输出按 CTxOut 序列化后的 SHA256);
- 当前输入序号 nIn(4 字节)。
注意它不承诺输入的具体 outpoint,只承诺输入个数、各输入的 nSequence 以及本输入的位置。因此给定已知输入时,整笔交易的 TXID 也可提前算出——原文强调这是与批量建通道等预签构造可组合的关键。
4.3 几条设计理由
- 承诺输入个数与序号:防“半花”(half-spend)问题——两个输出若都要求付给同一组输出又被合并进一笔交易,一半付款会被吞掉。承诺序号还使复用同一脚本的多个实例不可能挤进同一笔交易的同一位置,只能分开执行。
- 承诺 sequences 哈希:否则 TXID 可被锻改;且它能强制一个确切的 nSequence 值(OP_CSV 只能强制下限,做不到这一点)。
- 用哈希而非原值:这些子哈希多可与 SIGHASH_ALL 的预计算共享,且从脚本里构造模板哈希更安全、无歧义。
- 用 SHA256 而非 RIPEMD160:后者省 12 字节,但 20 字节哈希对第三方构造的程序有生日攻击风险。
- 不用标签化哈希:模板哈希只由 CTV 本身使用,不会被误认作其他哈希;且裸哈希将来配合 OP_CAT 等操作码动态构造时更省空间。
4.4 验证成本与递归的天然上限
实现必须缓存 scriptSigs、sequences、outputs 的子哈希(这是防 DoS 要求,不是优化):缓存就绪后每次 CTV 检查是 O(1);不缓存则 <H> CTV CTV … 式脚本会造成二次方哈希攻击面。
CTV 可以嵌套:花出去的输出再带 CTV 限制。但从花费哈希为 H 的输出出发,不可能再造出脚本含 H 的输出(哈希循环),因此每条模板链的“路径高度”严格递减,展开必然有限,不会无限自繁殖。
4.5 风险提示(原文专列)
- 模板原像未知或不可满足时,输出会永久不可花——但要求付款方先证明可花与“任何人可向任意地址付款”不兼容,原文接受这一风险;
- 地址复用做“转发合约”有资金损失风险:模板写死付 1 BTC,收到不足 1 BTC 会被冻死,多付部分会变成高额矿工费。原文归结为通用最佳实践:不要向不确定能否承接该付款的地址复用付款;
- P2SH(含嵌套 SegWit 的 P2SH)不能使用
<H> CTV片段:模板哈希必须承诺 scriptSig,而 scriptSig 里又要放赎回脚本,构成哈希循环。
五、谁必须动
普通持币人:无直接动作。向 CTV 输出付款与向普通地址付款无异;风险在收款方一侧的模板设计。
钱包与合约开发者:主要使用者。需正确构造模板哈希、用好子哈希缓存语义,并规避 4.5 的复用与冻死风险。
全节点与矿工:共识层软分叉,需升级才能执行新语义。激活前,原文要求共识上仍按 NOP 执行、策略上以 DISCOURAGE_UPGRADABLE_NOPS 拒绝进内存池;激活方式原文明确不在本 BIP 内讨论。
共识层:OP_NOP4 被赋予验证语义,规则只收紧;旧钱包仍可接收来自 CTV 输出的花费,只是要把带已确认 CTV 祖先的交易视为“可信”(可零确认花费)需升级。
六、现在算不算数,以及一个常见误读
状态为 Draft(草案),仍是草案、未激活。比特币主网至今没有 OP_CHECKTEMPLATEVERIFY,OP_NOP4 仍是空操作。它是契约类提案中讨论最久、构造最简的一个,但“讨论充分”不等于“已经生效”。
常见误读:“CTV 是图灵完备的智能合约,会让比特币变成以太坊。”不对。原文反复强调它刻意只做精确的模板匹配:除输入的具体指向外,交易细节在构造时就必须全部定死,灵活性远低于通用脚本;其设计取舍正是用有限的表达力换取便宜、可缓存、无二次方 DoS 的验证。能递归嵌套也不等于无限递归——路径高度严格递减,展开必然终止。
七、延伸
- 阅读版:https://bips.dev/119
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0119.mediawiki
- 相关:BIP-118 SIGHASH_ANYPREVOUT、BIP-116 MERKLEBRANCHVERIFY、BIP-117 尾调用语义、BIP-65 OP_CHECKLOCKTIMEVERIFY、BIP-112 CHECKSEQUENCEVERIFY
- 仓库总目录:https://github.com/bitcoin/bips
