作者:Magomed Aliev
时间:2021年8月25日
公众号:以太坊爱好者
比特币的可扩展性问题是其面临的主要问题之一,也是许多人努力的方向。比如说,有个设想是 “闪电网络”;但是,要在比特币网络中实现闪电网络,条件似乎还不具备,因为比特币自身的一些缺陷。另一个解决方案 “隔离见证(Segregated Witness)” 也致力于提高可扩展性,但它同时也解决了许多问题,包括闪电网络实现所需修补的一些缺陷。本文中我们会讲解隔离见证的优势及其工作原理。
隔离见证(SegWit)是一个由多个 BIP(141、142、143、144 和 145)描述的软分叉,其主要用意是优化比特币交易和区块的结构,将交易的签名(也叫 “脚本签名(scriptSig)”、“witness” 或 “解锁脚本”)从交易中移到一个独立的结构中。它不仅允许降低比特币交易的数据量大小(因此能让一个区块塞下更多的交易),也能解决 “交易熔融性(transaction malleability)” 问题(也就是我们开头提到阻碍闪电网络实现的缺陷),对支付通道和闪电网络这样基于比特币交易结构的技术来说极为关键。
隔离见证如何工作
在开始之前
我们先要简单回顾一下比特币的支付系统。它并不像银行那样,是一套账户和余额的列表。相反,每个比特币地址的余额都是由一系列发送给这个地址的交易来表示的;交易这一数据结构的主要部分就是输入和输出。输入是我们想要花费的前序交易(准确来说,输入不会是完整的一笔交易,而是某笔的输出,因为我们可能会在一笔交易中将资金转往多个地址),而交易的输出就是我们的资金发送的目的地址。下图展示了比特币交易的结构:
输出中的 PubKey Script 字段(下文简称为 “scriptPubKey”)就是我们所说的 “锁定脚本”。它用来保证只有接受地址的所有者才能使用这个支出。Signature Script 字段(下文简称为 “scriptSig”)也就是所谓的 “解锁脚本”,因为它是用来打开锁定脚本的钥匙,是用来证明地址所有权的。
(编者注:这里有一个 gif 动图,展示了比特币的堆栈是怎么执行的,但微信公众号推文中无法显示。强烈建议到网站上观看。)
后向兼容性
案例
Pay-to-Witness-Public-Key-Hash
- OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
- 0 <PubKeyHash>
- […]
- “Vin” : [
- {
- “txid”: “8adbca5e652c68f8f3c30ac658115bc4af395d0cc7e6beaea18168295c29d011”,
- “vout”: 0,
- “scriptSig”: “<our scriptSig>”
- }
- ]
- […]
- […]
- “Vin” : [
- {
- “txid”: “8adbca5e652c68f8f3c30ac658115bc4af395d0cc7e6beaea18168295c29d011”,
- “vout”: 0,
- “scriptSig”: “”
- }
- ]
- […]
- “witness”: “<Witness data>”
- […]
虽然传统的客户端可以处理隔离见证的交易(再次提醒,他们会把这些输出当成人人都可以花的钱),但他们自己没法花这些钱:旧型的钱包可能会尝试用空签名来花用一个隔离见证的输出,但这笔交易在现实中是无效的(更新之后的节点不会允许这样的交易上链)。这就意味着,发送者必须知道接受方的钱包支不支持隔离见证,这样才能为之创建合适类型的输出。
由 BIP 143 定义,隔离见证的输出应该用 压缩公钥 的哈希值来创建。如果你用的是传统类型的地址或者非压缩公钥的哈希值,这个输出将变得不可用(你的币会锁死)。
Pay-to-Witness-Script-Hash
- HASH160 54c557e07dde5bb6cb791c7a540e0a4796f5e97e EQUAL
- […]
- “Vin” : [
- “txid”: “abcdef12345…”,
- “vout”: 0,
- “scriptSig”: “<SigA> <SigB> <2 PubA PubB PubC PubD PubE 5 CHECKMULTISIG>”,
- ]
再来看看使用隔离见证后的发送者和接收者。输出的锁定脚本如下:
- 0 9592d601848d04b172905e0ddb0adde59f1590f1e553ffc81ddc4b0ed927dd73
- […]
- “Vin” : [
- “txid”: “abcdef12345…”,
- “vout”: 0,
- “scriptSig”: “”,
- ]
- […]
- “witness”: “<SigA> <SigB> <2 PubA PubB PubC PubD PubE 5 CHECKMULTISIG>”
- […]
P2SH(P2WPKH)
- 0 ab68025513c3dbd2f7b92a94e0581f5d50f654e7
- 3e0547268b3b19288b3adef9719ec8659f4b2b0b
转化成一个地址:
- 37Lx99uaGn5avKBxiW26HjedQE3LrDCZru
发送给这个地址的输出的锁定脚本,看起来也就跟一个普通的 P2SH 地址的脚本没啥区别:
- HASH160 3e0547268b3b19288b3adef9719ec8659f4b2b0b
- […]
- “Vin” : [
- {
- “txid”: “8adbca5e652c68f8f3c30ac658115bc4af395d0cc7e6beaea18168295c29d011”,
- “vout”: 0,
- “scriptSig”: “0 ab68025513c3dbd2f7b92a94e0581f5d50f654e7”
- }
- ]
- […]
- “witness”: “<Witness data>”
- […]
在一开始,我们创建的赎回脚本(也就是那个见证程序)会经过一次哈希计算,如果结果符合锁定脚本中的哈希值,这个脚本就会得到执行,程序会验证放在 witness 字段的签名。
P2SH(P2WSH)
- 0 9592d601848d04b172905e0ddb0adde59f1590f1e553ffc81ddc4b0ed927dd73
第一个数值是版本号,第二个数值是 32 位的 SHA256 哈希值,对应于我们的签名脚本。然后我们拿这个见证程序的 HASH160 哈希值转成一个普通的 P2SH 地址。要使用发往这个地址的输出时,我们需在 scriptSig 字段公布这个见证程序,在 witeness 字段提供完整的多签名脚本。
隔离见证的好处
交易熔融性漏洞
网络和存储的扩展
可用的区块空间扩大,降低交易手续费
脚本版本
签名验证的效率优化
那还有啥问题呢?
-
因为 SegWit 是一个软分叉,许多客户端可能不会升级,因此两种类型的 UTXO 会在网络中同时存在;诸如消除交易 ID 熔融性以及哈希计算次数线性上升这样的重大变更对非 SegWit 输出无效,因此网络仍会暴露在交易 ID 熔融性和哈希时间平方级上升的风险中。 -
SegWit 会降低网络的安全性,执行完全验证的节点会大幅减少,因为只有那些适配了 SegWit 的节点才有能力验证交易的 witness 部分。 -
SegWit 不能被废除。如果废除了它,所有变更都撤销,那么所有的 SegWit 输出就会变成大街上任人捡拾的钱。 -
SegWit 希望一次解决所有问题,也正因此,它导致了大量的代码改动。它会让未来的工作更加负载,而且提高了出现驱之不去的软件 bug 的机会。
结论
参考文献
-
Lightning network in depth, part 1: payment channels -
“Mastering bitcoin” — Andreas M. Antonopoulos -
Bitcoin Core blog -
Many segwit resources -
Good article about txn malleability
(完)
(文内有许多超链接,可点击左下 ”阅读原文“ 从 EthFans 网站上获取)
原文链接:
https://medium.com/softblocks/segregated-witness-for-dummies-d00606e8de63
作者: Magomed Aliev