协议演进 / BIP/比特币改进提案 / BIP-385
BIP-385
把任意原始脚本和任意已有地址各自包成一个描述符,让描述符语言能覆盖现存的每一种输出。本 BIP 目前处于已部署状态。
一、档案卡
| 编号 | BIP-385 |
|---|---|
| 标题 | raw() and addr() Output Script Descriptors |
| 作者 | Pieter Wuille <[email protected]>, Ava Chow <[email protected]> |
| 指定日期 | 2021-06-27 |
| 层级 | Applications(应用) |
| 类型 | Specification(规范类) |
| 状态 | Deployed(已部署) |
| 依赖 | BIP-380 |
| 阅读版 | https://bips.dev/385 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0385.mediawiki |
二、放在哪一族
输出脚本描述符(Output Script Descriptors)族的“兜底”一篇。这一族由 BIP-380 定通用语法与操作,其余各篇各管一类脚本表达式:
BIP-381:非 SegWit 描述符,如 pk()、pkh()
BIP-382:SegWit 描述符,如 wpkh()
BIP-383:多签描述符 multi()、sortedmulti()
BIP-384:combo() 描述符
BIP-386:Taproot 的 tr() 描述符
前几篇覆盖的都是结构规整、钱包日常生成的脚本。BIP-385 补上最后的缺口:碰到任何不在上述模板里的脚本、或者手边只有一个地址时,也能写成描述符,交给同一套描述符工具处理。
三、它要解决什么
描述符的目标,是用一段文本完整说明“这个钱包要看住哪些输出脚本、地址从哪里派生”。但现实中的脚本并不都长在模板里:
- 历史上出现过、或应用自定的任意脚本,无法用
pk()、wsh()等结构化表达式拼出来; - 有时使用者手边只有一个现成地址(例如别人给的收款地址、只看不花的观察地址),连它的脚本结构都不必知道,只想把它纳入描述符体系管理。
原文的动机一句话:为了让描述符与今天正在使用的脚本最大限度兼容,需要能把任意输出脚本、或一个地址,直接包进描述符。没有这一层兜底,描述符语言就总有一块覆盖不到的角落,钱包在导入、导出、只读观察等环节遇到这类输出就只能另走一套逻辑。
四、规则本身
本篇定义两个新的脚本表达式,都只能用作顶层描述符,不能嵌套进 sh()、wsh() 等其他表达式里。
4.1 raw()
写法为 raw(HEX),参数是一串十六进制字符串,表示一段比特币脚本(script)。这个描述符产生的输出脚本,就是 HEX 所表示的那段脚本本身,不做任何加工、包装或哈希。
例如测试向量中 raw(deadbeef) 产生的脚本就是 deadbeef;一长串十六进制的 P2WSH 风格脚本也可以原样放进去。
参数必须是合法十六进制:raw(asdf) 是无效描述符。
4.2 addr()
写法为 addr(ADDR),参数是一个比特币地址。描述符产生的输出脚本,就是该地址对应的输出脚本——即把地址解码还原成的那段 scriptPubKey。
例如测试向量中给出一个 P2SH 地址,其产生的脚本是对应的 OP_HASH160 <20 字节哈希> OP_EQUAL 形式。地址本身无效(如 addr(asdf))则描述符无效。
4.3 为什么只能在顶层
raw() 已经是一段完整脚本,再把它嵌进 sh() 或 wsh() 里哈希一层,语义上既多余又容易误导;addr() 展开后同样是完整输出脚本。原文的无效用例明确列出:sh(raw(...))、wsh(raw(...))、sh(addr(...))、wsh(addr(...)) 全部无效。实现遇到这种嵌套应直接拒绝。
4.4 向后兼容与实现
两者都沿用 BIP-380 的格式与通用操作。作为全新的描述符,它们与此前任何实现都不兼容——旧软件不认识是预期行为。addr() 复用已有地址格式,因此相对容易实现。原文注明:raw() 与 addr() 描述符自 Bitcoin Core 0.17 起已实现。
五、谁必须动
普通持币人:无直接变化。日常收款地址由钱包按常规模板生成,一般用不到手写 raw() 或 addr()。
钱包开发者:解析器需支持这两个顶层表达式:raw() 做十六进制校验后原样输出脚本,addr() 先校验并解码地址再输出其脚本;同时拒绝一切嵌套用法。在做钱包导入、只读观察、任意脚本登记时,这是补全覆盖面的工具。
全节点与矿工:无须改动。描述符是钱包层面的表示法,不改变任何脚本的共识有效性;raw() 包住的脚本上链后是否合法,仍按原有共识规则判断。
共识层:本 BIP 不修改共识规则。
六、现在算不算数,以及一个常见误读
状态为 Deployed,原文称已在 Bitcoin Core 0.17 实现。它算不算数,不看网络投票,而看钱包与工具是否按同一语法解析——描述符是应用层的互操作约定,Deployed 表示这套写法已有实现并稳定下来,可供其他钱包对齐。
需要强调的是,addr() 与 raw() 只负责“表示”,不负责“能花”。把一个地址包成描述符,不等于钱包就掌握了花这笔钱所需的私钥或赎回脚本。
常见误读:
“有了 addr() 描述符,就等于导入了这个地址的钱包。”
不对。它只把地址对应的输出脚本登记为描述符的产出,钱包最多能据此监视该地址的收支(只读观察)。要花费其中的资金,仍需相应的私钥或脚本知识,那些都不在地址本身、也不在本 BIP 里。
七、延伸
- 阅读版:https://bips.dev/385
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0385.mediawiki
- 相关:BIP-380 描述符通用操作、BIP-381 非 SegWit 描述符、BIP-386
tr()描述符 - 仓库总目录:https://github.com/bitcoin/bips
