/ home / newsletters /
Bitcoin Optech Newsletter #157
本周的 Newsletter 概述了关于一个新提案 opcode 的讨论,并链接到一个更新后的用于追踪 bech32m 支持的维基页面。文中还包括我们的常规部分,其中包含来自一次 Bitcoin Core PR 审查俱乐部会议的重点内容、关于如何为 taproot 做准备的建议,以及对一些流行比特币基础设施项目值得注意的更改的描述。
新闻
-
● 请求对
OP_CHECKSIGFROMSTACK
设计建议: Jeremy Rubin 公告到 Bitcoin-Dev 邮件列表上,提交了一个关于 OP_CHECKSIGFROMSTACK opcode 的草案规范,并邀请那些倾向于替代设计的开发者提出反馈。部分替代方案得到了讨论,但讨论也分支出是否应该同时引入 OP_CAT opcode。OP_CAT
和OP_CSFS
可以实现任意交易内省——即允许将比特币接收至一个脚本,该脚本可以检查随后花费这些比特币的交易几乎任何部分。此功能可启用许多高级特性(包括其他一些提案升级如 SIGHASH_ANYPREVOUT 和 OP_CHECKTEMPLATEVERIFY 的某些版本1),但OP_CAT
也使得创建递归的契约成为可能,这些契约可能会永久地限制投入该契约之比特币的可花费性。一些人反对在比特币中允许契约,但也有论点认为最糟糕的情况(递归契约)已经在现有比特币中成为可能,因此不必过于担心启用OP_CAT
或类似 opcode。尽管有这些讨论,Rubin 仍决定将其
OP_CSFS
提案与添加OP_CAT
的任何提案独立开来,认为仅OP_CSFS
自身也已足够有用。 -
● 跟踪 bech32m 支持: Bitcoin Wiki 上的 bech32 采用情况页面已更新,以跟踪支持向 bech32m 地址(用于 taproot)发送和接收的各软件与服务。
Bitcoin Core PR 审查俱乐部
在本月度栏目中,我们总结了一次最近的 Bitcoin Core PR 审查俱乐部会议的情况,并重点介绍了一些重要的问答。点击下面的问题即可查看会议中的答案摘要。
Use script_util helpers for creating P2{PKH,SH,WPKH,WSH} scripts 是 Sebastian Falbesoner 提交的一个拉取请求,用以在功能测试中用 script_util
辅助函数替换手动脚本创建,并修复了 get_multisig()
函数中的一个错误。此次审查俱乐部会议中对提案中使用的各脚本输出类型及相关术语作了详细解析。
-
script_util.py
中的key_to_p2pkh_script
、script_to_p2sh_script
、key_to_p2wpkh_script
和script_to_p2wsh_script
分别做什么?这些是用于构建 Pay to Public Key Hash、Pay to Script Hash、Pay to Witness Public Key Hash 以及 Pay to Witness Script Hash 脚本(CScript 对象)的辅助函数,输入为公钥或脚本。 ➚
-
请定义 scriptPubKey、scriptSig 和 witness。
scriptPubKey 和 scriptSig 分别是交易输出和输入中的字段,用于指定并满足花费条件。witness 是一个为同样目的而设置的附加字段,由隔离见证引入。花费要求在输出的 scriptPubKey 中被承诺,花费该输出的输入必须在 scriptSig 和/或 witness 中提供满足这些要求的数据。 ➚
-
请定义 redeem script 和 witness script。它们之间是什么关系?
P2SH 和 P2WSH 输出类型会在 scriptPubKey 中提交一个脚本哈希。当花费该输出时,花费者需提供完整脚本以及任何签名或其他验证所需的数据。该脚本在出现在 scriptSig 中时称为 redeemScript,而在 witness 中时称为 witness script。从这个角度来说,它们是对应的:对于 P2SH 输出,redeemScript 相当于 P2WSH 输出的 witness script。二者并不相互排斥,因为花费一个 P2SH-P2WSH 输出的交易会同时包含这二者。 ➚
-
如果要将币发送给一个在脚本中定义了花费条件的人,输出的 scriptPubKey 中包含什么?在花费这笔币时,输入需要提供什么?
scriptPubKey 中包含脚本哈希和用于验证匹配的操作码:
OP_HASH160 OP_PUSHBYTES_20 <20B script hash> OP_EQUAL
。而 scriptSig 则包含脚本本身及初始堆栈数据。 ➚ -
当一个不支持隔离见证的节点验证一个 P2SH-P2WSH 输入时,它会做什么?而一个支持隔离见证的节点又会多做什么?
不支持隔离见证的节点看不到 witness;它只执行 P2SH 的规则,验证 redeemScript 与 scriptPubKey 中提交的哈希是否匹配。支持隔离见证的节点则能识别出这是一个见证程序,并利用 witness 中的数据和相应的 scriptCode 来执行隔离见证规则。 ➚
-
在原始的
get_multisig()
函数中,那个 P2SH-P2WSH 脚本有何问题?它在 P2SH-P2WSH 的 redeemScript 中直接使用了 witness script,而非其哈希值。 ➚
准备 taproot #4:从 P2WPKH 到单签 P2TR
这是一个系列的每周内容,介绍在区块高度 709,632 激活 taproot 前,开发者和服务提供商如何做好准备。
对于已经支持接收和使用 v0 segwit P2WPKH 输出的钱包来说,将其升级到用于单签的 v1 segwit P2TR 应该相对容易。以下是主要步骤:
-
● 使用新的 BIP32 密钥推导路径: 你不需要修改你的 BIP32 分层确定性 (HD) 代码,并且你的用户也不需要更换种子。2 然而,我们强烈建议你为你的 P2TR 公钥使用新的推导路径(例如由 BIP86 定义);如果你不这样做,当你在 ECDSA 和 schnorr 签名两者中都使用相同密钥时,可能会导致潜在攻击。
-
● 通过其哈希值调整你的公钥: 尽管在单签场景中技术上并非必须,尤其当你的所有密钥都来自随机选定的 BIP32 种子时,BIP341 建议让你的密钥承诺到一个不可花费的脚本哈希树中。其操作很简单,只需要使用椭圆曲线加法操作,将你的公钥与该公钥哈希得到的曲线点相加即可。遵循这一建议的好处在于,如果你日后添加无脚本的多签支持,或者为
tr()
描述符添加支持,你也可以使用相同的代码。 -
● 创建你的地址并进行监控: 使用 bech32m 来创建你的地址。付款将发送到脚本
OP_1 <tweaked_pubkey>
。你可以使用与扫描 v0 segwit 地址(如 P2WPKH)相同的方法来扫描支付到该脚本的交易。 -
● 创建支出交易: 对于 taproot 来说,所有的非见证字段都与 P2WPKH 相同,因此你无需担心交易序列化的改变。
-
● 创建签名消息: 这是对支出交易数据的承诺。大部分数据与为 P2WPKH 交易所签名的内容相同,但字段的顺序已改变,并且有一些额外内容需要签名。实现这一点只需要对各种数据进行序列化和哈希处理,所以编写这部分代码应该相对容易。
-
● 对签名消息的哈希进行签名: 生成 schnorr 签名有多种方法。最好的方式是不“自己动手写加密”而是使用你信任的、经过充分审阅的库提供的函数。但如果因某些原因你无法这样做,BIP340 提供了一种算法,如果你已经有可用于制作 ECDSA 签名的原语,那么实现它应该相当简单。当你获得签名后,将其放入输入的见证数据中,然后发送你的支出交易。
即使在 taproot 于区块 709,632 激活之前,你也可以使用 testnet、公用默认 signet 或者 Bitcoin Core 的私有 regtest 模式来测试你的代码。如果你为开源钱包添加了 taproot 支持,我们鼓励你将实现它的拉取请求链接添加到 Bitcoin Wiki 上的 taproot 用法和 bech32m 采用页面,以便其他开发者可以从你的代码中学习。
发布与候选发布
面向流行比特币基础设施项目的新版本与候选发布。请考虑升级到新版本,或协助测试候选版本。
- ● LND 0.13.1-beta.rc2 是一个维护版本,针对 0.13.0-beta 中引入的功能进行了少量改进与错误修复。
值得注意的代码和文档更改
本周在 Bitcoin Core、C-Lightning、Eclair、LND、Rust-Lightning、libsecp256k1、Hardware Wallet Interface (HWI)、Rust Bitcoin、BTCPay Server、比特币改进提案(BIPs)以及闪电网络规范(BOLTs)上值得注意的变更:
-
● C-Lightning #4625 更新了其闪电网络 (LN) offers 的实现,以匹配最新的规范变更。值得注意的是,offers 已不再需要附带签名。这一改动显著缩短了 offers 的编码字符串,从而改善了二维码的识别度。
-
● Eclair #1746 增加了将数据并行复制到 PostgreSQL 数据库的功能,与原先的 SQLite 数据库同时使用。此功能旨在为那些最终计划切换后端的服务器提供测试便利。去年,Suredbits 工程师 Roman Taranchenko 在 Optech 的现场报告 中描述了如何将 Eclair 与 PostgreSQL 后端结合使用来满足企业需求。
-
● LND #5447 添加了一份文档,介绍了如何使用可在集群节点间进行复制的替代数据库来部署多个 LND 节点,以实现自动故障切换。感兴趣的读者可对比 Newsletter #128 中提到的 Eclair 所采用的方法。
-
● Libsecp256k1 #844 对 schnorr 签名 的 API 进行了多项更新,其中最显著的是一个提交,允许对任意长度的数据进行签名与验证。目前比特币中的所有签名都针对 32 字节哈希,但对可变长度数据进行签名可能在比特币链外应用中具有价值,或者可用于实现如 OP_CHECKSIGFROMSTACK 这类新 opcode 的签名验证功能。预计 BIP340(比特币的 schnorr 签名规范)将进行更新,以描述如何安全地对可变长度数据进行签名。
-
● BIPs #943 更新了 BIP118,改为基于即将激活的 taproot 和 tapscript,而不再基于 SegWit v0。同时,此次修订将原本标题 SIGHASH_NOINPUT 更名为 SIGHASH_ANYPREVOUT,以体现当前该签名标志已被称为“ANYPREVOUT”,因为虽然签名可适用于任何前置输出,但对输入的部分信息仍然会进行承诺。
-
● BTCPay Server #2655 指示网页浏览器在用户点击指向区块浏览器的交易链接时,不要发送 HTTP
referer
字段,这可避免向区块浏览器暴露具体是从哪个 BTCPay server 跳转而来,从而表明该服务端是交易的来源或接收者。即便如此,如果用户对隐私有较高需求,仍应尽量避免在第三方区块浏览器中直接查询自己的交易。
脚注
-
在使用
OP_CHECKSIGFROMSTACK
(OP_CSFS
)实现诸如 BIP118 中的 SIGHASH_ANYPREVOUT 或 BIP119 中的 OP_CHECKTEMPLATEVERIFY 等提案的核心特性时,如果以 scriptpath 花费方式进行,其占用的区块空间会比那些经过优化的提案更多。支持OP_CSFS
的理由是可以先引入通用构造,验证人们确实有需求后,再对共识进行修改,添加更高效的实现。此外,由于 taproot 引入了 keypath 花费,任何脚本在特定场合都可以使用最少的区块空间来完成执行,从而减少对在不最佳情形下依然能省空间的特定构造的需求。 ↩ -
当 Electrum 升级到 segwit v0 时,要求任何希望使用 bech32 地址接收资金的用户都生成新的种子。虽然这在技术上并非必要,但它使 Electrum 的作者能够在其自定义种子推导方法中引入一些新的功能。其中一个功能是允许通过种子版本号来指定一个种子应当使用的脚本。这使得旧脚本可以被安全地逐步弃用(例如,未来某个版本的 Electrum 可能会发布,它将不再支持接收到传统的 P2PKH 地址)。
大约在 Electrum 开发者部署其版本化种子同期,Bitcoin Core 的开发者开始使用 输出脚本描述符 来解决相同的问题——允许逐步弃用脚本(同时也解决了其他问题)。下表对比了 Electrum 的版本化种子和 Bitcoin Core 的描述符与此前两者都使用的 隐式脚本 方法(目前在大多数其他钱包中仍普遍使用)。
脚本管理 初始备份 引入新脚本 扫描(带宽/CPU 成本) 弃用脚本 隐式脚本(例如 BIP44) 种子词 自动(无需用户操作) 必须扫描所有受支持的脚本,O(n) 无法警告用户他们使用了不受支持的脚本 显式脚本(版本化种子) 种子词(包含版本位) 用户必须备份新的种子;资金要么被拆分到两个独立钱包中,要么需要用户将旧钱包的资金转移到新钱包 只扫描单一脚本模板,O(1) 警告用户有关不受支持的脚本 显式脚本(描述符) 种子词和描述符 用户必须备份新的描述符 仅扫描实际使用过的脚本模板,O(n);对于新钱包而言 n=1 警告用户有关不受支持的脚本