协议演进 / BIP/比特币改进提案 / BIP-384
BIP-384
定义 combo() 输出脚本描述符表达式,用一个密钥一次生成 P2PK 与 P2PKH 脚本,钥匙带压缩公钥时再同时生成 P2WPKH 与 P2SH-P2WPKH 脚本。本 BIP 目前处于已部署状态。
一、档案卡
| 编号 | BIP-384 |
|---|---|
| 标题 | combo() Output Script Descriptors |
| 作者 | Pieter Wuille <[email protected]>, Ava Chow <[email protected]> |
| 指定日期 | 2021-06-27 |
| 层级 | Applications(应用) |
| 类型 | Specification(规范类) |
| 状态 | Deployed(已部署) |
| 依赖 | BIP-380 |
| 阅读版 | https://bips.dev/384 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0384.mediawiki |
二、放在哪一族
输出脚本描述符族中的“打包”一员。通用语法、校验和与密钥表达式都在 BIP-380,本 BIP 在档案上依赖它,只新增一个顶层表达式。
它不定义任何新脚本,而是把同族其他篇的表达式按一把钥匙打包:
BIP-381:pk() 给出 P2PK,pkh() 给出 P2PKH
BIP-382:wpkh() 给出 P2WPKH,sh(wpkh()) 组合给出 P2SH-P2WPKH
BIP-384(本篇):combo(KEY) 一次把上面两到四种脚本全部生成,省去逐个写的四行描述符
与它相邻的是 BIP-385 的 raw() 与 addr()——同样是顶层表达式,但那两个面向原始脚本与既有地址,与本篇的“一钥多格式”用途不同。
三、它要解决什么
原文的动机很明确:为了让传统“以钥匙为中心”的钱包更容易过渡到以描述符为中心的钱包,最好能拿一把钥匙,直接生成传统钱包软件过去通常会生成的那一整套脚本。
传统钱包的逻辑是先有一把钥匙,再由软件决定用它做几种地址。描述符的逻辑正相反:先写明脚本表达式,钥匙只是参数。两边在迁移时对不上——用户手里只有钥匙与旧地址,却不知该写哪几行描述符,才能让新钱包监视到旧钱包用过的全部输出。
combo() 就是这座桥:把一把钥匙放进去,传统上会由它派生的几种脚本一次性全列出来。新钱包导入这一个描述符,就能同时认出这把钥匙名下的老格式与 SegWit 格式输出,不必逐种猜测、逐行补写。
四、规则本身
4.1 定义与位置
新增一个顶层脚本表达式 combo(KEY)。它只能作顶层表达式使用,不能放进 sh()、wsh() 等其他表达式里;它的参数只能是一个密钥表达式(写法见 BIP-380),不能放脚本表达式。原文把 sh(combo(...))、wsh(combo(...)) 与 combo(pkh(...)) 都列为无效描述符。
与族内其他表达式“一式一脚本”不同,combo() 是“一式多脚本”:一个描述符对应两到四个输出脚本,钱包要把它们全部纳入监视范围。
4.2 生成哪几个脚本
规则分两档,取决于钥匙是否带压缩公钥:
- 任何钥匙都生成两个:P2PK 脚本,与把同一钥匙放进
pk()的结果相同;P2PKH 脚本,与放进pkh()的结果相同。 - 钥匙是或带有压缩公钥时,再多生成两个:P2WPKH 脚本,与放进
wpkh()的结果相同;P2SH-P2WPKH 脚本,与放进sh(wpkh())的结果相同。
因此:压缩公钥的钥匙得四个脚本,非压缩公钥的钥匙只得前两个。原因与 BIP-382 的限制同源——SegWit 的 wpkh() 只接受压缩公钥,非压缩钥匙在那一档下无脚本可生成,combo() 只能跳过,而不是报错。
4.3 与扩展钥匙配合
参数可以是带派生路径的扩展钥匙。此时每个子索引都按上述规则成套生成:原文测试向量中,带 /* 的扩展私钥在子索引 0 与 1 下,各生成 P2PK、P2PKH、P2WPKH、P2SH-P2WPKH 四个脚本。钱包据此按索引成批监视,而不是只盯住某一个地址。
五、谁必须动
普通持币人:无直接变化。把老钱包的钥匙迁入支持描述符的钱包时,一个 combo() 描述符即可覆盖旧软件用过的几种收款格式,减少漏监视的风险。
钱包开发者:实现描述符时需支持 combo() 这一顶层表达式,展开为两到四个脚本并全部纳入监视;须按钥匙是否带压缩公钥决定是否生成 SegWit 两项,不得对非压缩钥匙强行生成 wpkh() 类脚本;并拒绝把 combo() 嵌进其他表达式的写法。
全节点与矿工:无须改动。它生成的每一种脚本都是既有的标准脚本,共识规则不变。
六、现在算不算数,以及一个常见误读
状态为 Deployed(已部署)。原文记载:combo() 描述符自 Bitcoin Core 0.17 起已有实现。它采用 BIP-380 的格式与通用操作;原文称其为全新描述符、与此前任何实现并不兼容,但生成的脚本都是标准脚本,既有软件对这些脚本本身并不陌生。
它的定位是过渡工具:新设计的钱包通常应直接用 pk()、pkh()、wpkh() 等表达式写明自己真正要用的那一种格式;combo() 的价值在导入与兼容——把历史上一把钥匙撒出去的几种格式一次收齐。
常见误读:
“combo() 对任何钥匙都固定生成四个脚本。”
不对。原文写明生成的是 2 个或 4 个,取决于钥匙:P2PK 与 P2PKH 始终有;只有钥匙是或带有压缩公钥时,才再加 P2WPKH 与 P2SH-P2WPKH。拿非压缩公钥去核对,只找到两个脚本不是实现出错,而是规范本身如此。
七、延伸
- 阅读版:https://bips.dev/384
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0384.mediawiki
- 相关:BIP-380 描述符通用操作、BIP-381 非 Segwit 描述符、BIP-382 Segwit 描述符、BIP-385
raw()与addr()描述符 - 仓库总目录:https://github.com/bitcoin/bips
