比特币生态:详尽解释SegWit_SEG:scrt币总量

引言

同志们,币圈又见君,吾心神摇曳。

比特币的可扩展性问题是其面临的主要问题之一,也是许多人努力的方向。因为比特币自身的一些缺陷,另一个解决方案“隔离见证”也致力于提高可扩展性,但它同时也解决了许多问题,包括闪电网络实现所需修补的一些缺陷。本文中将会讲解隔离见证的优势及其工作原理。

隔离见证是由多个BIP描述的软分叉,其主要用意是优化比特币交易和区块的结构,将交易的签名”、“witness”或“解锁脚本”)从交易中移到一个独立的结构中。它不仅允许降低比特币交易的数据量大小,能让一个区块塞下更多的交易,也能解决“交易熔融性”问题,对支付通道和闪电网络这样基于比特币交易结构的技术来说极为关键。

向后兼容性

实际上,隔离见证不仅改变了交易的结构,也改变了交易的输出。不过,这不是说传统类型的UTXO和SegWit类型的UTXO无法在同一笔交易中花费:这种情况下,传统类型的UTXO将在输入内加载所有权证明,而隔离见证类型的UTXO将在交易输入以外的结构中加载证明。

不管怎么说,隔离见证的定位是一个软分叉,这个升级应该是可以忽略,无需强制的,而且,这也意味着,未升级的节点应该可以处理隔离见证类型的输出。实际上,旧的节点和钱包将以为任何人都能花费这些UTXO,也即这些UTXO是空签名也可花费的,因此即使在交易中没有看到签名,交易也仍然是有效的。而升级后的节点和钱包将在交易输入以外的地方,一个专门的“witness”字段寻找签名。

什么是UTXO?

一个未花费的交易输出就代表一定数量的比特币。多个UTXO可以组合、单个UTXO也可以拆分,做出支付所需的任何面额。

我们可以将UTXO理解成实物货币,因为它们必须作为完整的一个单元来使用。如果你想花5毛钱,你不可能掰开一个1块钱硬币来付款。相反,你必须花掉整个1块钱,然后拿5毛钱的找零。但是,不同于实物货币,UTXO没有标准面额。一个UTXO可以是任意数量的比特币。

顾名思义,一个UTXO就是一个比特币交易的输出。输出以UTXO的形式存在,直到被用作另一个交易的输入为止,这时就不再是未花费的。

在任意时间点,现有UTXO的集合都被称为UTXO集。比特币节点会追踪UTXO集,从而确定哪些代币未被花费,以及哪些人可以花费它们。该系统可以让比特币解决多重支付问题。双重花费问题是长期困扰数字货币尝试的一大难题。

理解比特币的UTXO模型

新的UTXO是通过花费现有UTXO创建的。每个比特币交易都由输入和输出组成。输入花费已有UTXO,输出则创建新的UTXO。Coinbase交易是一种特殊类型的交易,通过创建新的比特币来奖励找到区块的矿工。由于创造了新的比特币,coinbase交易没有输入,但是会产生一个或多个输出。

就像所有正常输出一样,coinbase交易的输出是新的UTXO。每个UTXO的历史都可以追溯到coinbase交易的一个或多个输出。比特币的UTXO模型不同于大多数数字货币系统,比特币的初衷是实现完全透明化、公平性和可审计性,UTXO可以帮助比特币实现这些目标。

在传统金融系统中,交易会从一个账户中取出资金转移到另一个账户中。比特币的UTXO模型没有账户,因此没有专门的发送方账户/地址,地址虽然被用来接收UTXO,但是永远不会直接记录在区块链上。比特币地址是scriptPubKeys的编码,包含在每个交易的输出中。

当比特币被花费出去时,输入只包含执行scriptPubKey所必需的签名和公钥,并没有提到比特币来自区块链上的哪个地址。但是,UTXO的上一个地址是可以轻松计算得出的,每个交易输入都通过交易id来指明其前序交易,并通过索引来指明使用该前序交易的哪一个输出,被引用的交易输出的scriptPubKey可以被转化成比特币地址。

UTXO模型可以让所有比特币节点在任意时刻就比特币的存在情况达成共识,也就是说,任何人都可以审计比特币的总供应量,来确保比特币的货币政策被严格遵守。

UTXO的组合和拆分

一个比特币交易可以包含任意数量的输入和输出。因此,用户可以任意组合和拆分UTXO来完成任意金额的付款。

例如,Alice持有两个UTXO,分别价值0.5BTC和0.7BTC。当她向Bob支付1BTC时,可以使用这两个UTXO作为输入,然后将1BTC的输入发送给Bob。

Alice还另外创建了一个0.199BTC的输出作为找零发送给自己。由于需要支付交易费,她无法给自己发送0.2BTC。

注意:交易费不以交易输出的形式体现。它是通过输入值和输出值之间的差额推算得出。

UTXO模型可以让比特币节点有效验证链上的每个交易。当节点收到一个交易时,无论该交易是否已经打包进区块,均可验证该交易内的UTXO是否真的有效且没有被花费。正因如此,比特币可以在不依赖可信第三方的情况下解决双重花费问题。

UTXO模型vs账户模型

大多数金融系统不使用UTXO模型。因此,用户不依靠某几种代币来控制资产,而是使用一个或多个账户,且每个账户都有余额,账户模型可以让金融机构和商家精确记录个人账户的借入贷出情况,避免找零和选币问题。

账户模型的优势是以牺牲透明性和可审计性为代价的,审计所有银行账户中的美元总量是不可能的。

另外,大多数账户模型饱受退单和账户透支等问题的困扰,由于比特币交易必须引用要被花费的UTXO,无效交易不可能被添加到区块链上。

UTXO模型为用户提供隐私优势。比特币用户可以将每个UTXO存储在不同的地址中分别处理。通过这种方式,用户可以隐藏其持有的UTXO之间的联系,避免暴露在公众视线中,对于区块链观察者来说,确定哪些UTXO属于哪些用户会变得更有难度。

比特币的设计极大降低了生成新地址的难度。账户模型系统使得生成新账户变得非常麻烦,甚至不可行,迫使用户将全部或大部分资金存放在一个账户中。

链分析公司试图通过各种方法破坏比特币的隐私性并确定UTXO的所有权,然而,这些方法靠的是假设和间接证据,而非严格的逻辑。

相关术语

交易:交易是比特币从一个地址转移到另一个地址的记录。所有交易都记录在区块链上的区块中。

UTXO集:是某一时间点存在的所有UTXO的集合。所有UTXO的总量就是比特币的当前供应量。

交易ID:是标识特定交易的一串字母和数字。这个字符串只是对交易进行二次SHA256计算得到的哈希值。

多重支付:就是有人将同一笔钱花了不止一次,并让一方或双方相信他们已经拿到了钱。比特币利用去中心化账本和带有时间戳的区块链解决了双重花费问题。

稀缺性:货币稀缺性指的是货币很难被找到或创造出来。虽然货币普及很重要,但是一旦货币可以被轻而易举地创造出来,会对经济产生负面影响。

案例讲解

Pay-to-Witness-Public-Key-Hash

我们用例子来说明一下隔离见证会如何改变交易的数据结构。从标准的Pay-to-Public-Key-Hash(P2PKH)交易类型开始。我们感兴趣的部分是输出,尤其是其“scriptPubKey”字段。我们先考虑一种标准的锁定脚本:

OP_DUPOP_HASH160<PubKeyHash>OP_EQUALVERIFYOP_CHECKSIG

而隔离见证之后的锁定脚本如下所示:

0<PubKeyHash>

如你所见,隔离见证的输出比传统类型的输出要简单很多:只有两个值会被推入脚本执行栈中。如我们上面说的,旧版本的比特币客户端会以为这个输出是掉在地上的钱,无需提供签名就能花费这个输出。不过,新的客户端会将第一个数字解释为版本号,而第二个则对应着一个锁定脚本。在现实中,只有压缩公钥的哈希值可以用在这里。再来看看这个输出被花费时的情形。传统交易的输出在花费时的数据结构如下:

"Vin":[

{"txid":"8adbca5e652c68f8f3c30ac658115bc4af395d0cc7e6beaea18168295c29d011",

"vout":0,

"scriptSig":"<ourscriptSig>"}]

但是,在花费一个隔离见证输出的时候,交易的scriptSig将为空,而所有的签名都会放到一个专门的地方:

"Vin":[

{"txid":"8adbca5e652c68f8f3c30ac658115bc4af395d0cc7e6beaea18168295c29d011",

"vout":0,

"scriptSig":""}]

"witness":"<Witnessdata>"

警告

虽然传统的客户端可以处理隔离见证的交易,但他们自己没法花这些钱:旧型的钱包可能会尝试用空签名来花用一个隔离见证的输出,但这笔交易在现实中是无效的。这就意味着,发送者必须知道接受方的钱包支不支持隔离见证,这样才能为之创建合适类型的输出。

由BIP143定义,隔离见证的输出应该用压缩公钥的哈希值来创建。如果你用的是传统类型的地址或者非压缩公钥的哈希值,这个输出将变得不可用。

Pay-to-Witness-Script-Hash

另一个关键的交易类型是P2SH。它让交易可以发送给脚本的哈希值。要花费P2SH交易的输出,花费者需要提供一个脚本,其哈希值应该与UTXO中的脚本哈希值匹配,并基于这个脚本提供签名/口令/别的东西。这个用法可以把解锁脚本保护起来,让发送者无从知晓一个地址的内容,并且也能节约空间:举个例子,一个多签名钱包的锁定脚本可能非常长,这样我们就必须把整个锁保存起来;有了P2SH可以只保存一个哈希值。假设现在有一个需要提供5个私钥中的2个的签名才能使用的多签名钱包。如果你使用传统的交易,P2SH交易输出的锁定脚本将如下:

HASH16054c557e07dde5bb6cb791c7a540e0a4796f5e97eEQUAL

要花它的时候,花费的人需要提供一个赎回脚本,这个脚本定义了花费条件,还有两个签名。所有这些都要放在交易的输入中:

"Vin":

[

"txid":"abcdef12345...",

"vout":0,

"scriptSig":"<SigA><SigB><2PubAPubBPubCPubDPubE5CHECKMULTISIG>",

]

再来看看使用隔离见证后的发送者和接收者。输出的锁定脚本如下:

09592d601848d04b172905e0ddb0adde59f1590f1e553ffc81ddc4b0ed927dd73

就像P2PKH交易一样,这个输出的脚本也变得更简单。第一个数值表示版本号,第二个是对应于赎回脚本的SHA256哈希值。使用这个函数某种意义上是为了用长度来区分P2WPKH的见证程序以及P2WSH的见证程序。

使用这一输出的交易如下所示:

"Vin":[

"txid":"abcdef12345...",

"vout":0,

"scriptSig":"",]

"witness":"<SigA><SigB><2PubAPubBPubCPubDPubE5CHECKMULTISIG>"

在P2SH中嵌入隔离见证

我们已经看到,使用隔离见证是有好处的。不过,上面的例子只对发送者和接收者都有升级软件的情形才适用。但现实并不总是如此。考虑这样一种情形:

Alice希望给Bob转账一些btc,Bob有支持隔离见证的钱包软件而她没有。他们显然只能用标准形式的交易,但Bob希望使用SegWit来减少手续费。

这时候,Bob可以创建一个包含了SegWit脚本的P2SH地址、Alice会把这个地址当成一个普通的P2SH地址,因此可以直接向这个地址转账而没有任何问题。但Bob可以使用SegWit交易来使用这个输出,并获得手续费折扣。

这就是SegWit交易的两种类型P2WSH和P2WPKH在P2SH内实现的方式。

P2SH(P2WPKH)

想在P2SH交易中实现一笔P2WPKH交易,Bob需要使用其公钥创建一个见证程序。然后把结果哈希、转码成一个地址:

0ab68025513c3dbd2f7b92a94e0581f5d50f654e7

第一个数值是版本号,而第二个数值是20字节的公钥哈希值。这个脚本先做SHA256哈希运算,再做RIPEMD160运算,就可得到一个20字节的哈希值。

3e0547268b3b19288b3adef9719ec8659f4b2b0b

转化成一个地址:

37Lx99uaGn5avKBxiW26HjedQE3LrDCZru

发送给这个地址的输出的锁定脚本,看起来也就跟一个普通的P2SH地址的脚本没啥区别:

HASH1603e0547268b3b19288b3adef9719ec8659f4b2b0bEQUAL

那么Bob花费输出的时候,交易的结构会像这样:

"Vin":[

{"txid":"8adbca5e652c68f8f3c30ac658115bc4af395d0cc7e6beaea18168295c29d011",

"vout":0,

"scriptSig":"0ab68025513c3dbd2f7b92a94e0581f5d50f654e7"}]

"witness":"<Witnessdata>"

在一开始,我们创建的赎回脚本会经过一次哈希计算,如果结果符合锁定脚本,这个脚本就会得到执行,程序会验证放在witness字段的签名。

P2SH(P2WSH)

P2WSH脚本也可以用P2SH来实现。我们考虑上面所说的2-5多签名钱包的例子。所有的步骤都跟P2SH(P2WPKH)没什么区别:首先,创建一个见证程序:

09592d601848d04b172905e0ddb0adde59f1590f1e553ffc81ddc4b0ed927dd73

第一个数值是版本号,第二个数值是32位的SHA256哈希值,对应于我们的签名脚本。然后我们拿这个见证程序的HASH160哈希值转成一个普通的P2SH地址。要使用发往这个地址的输出时,我们需在scriptSig字段公布这个见证程序,在witeness字段提供完整的多签名脚本。

隔离见证的好处

交易熔融性漏洞

SegWit解决的一个关键问题就是比特币交易的“熔融性”,也即比特币交易的ID是哈希值这一点所带来的问题。

在以往的比特币交易中,签名是放在交易的输入部分的,第三方可以更改签名且不会让交易失效。这使得第三方可以在完全不更改交易的“关键”字段的前提下更改交易的ID。这样一来,交易还是有效的,含义也还是一样的,但是有了另一个ID,这可以用来执行另一种攻击,比如DoS攻击。

SegWit解决了这个问题,因为所有的签名都是放在交易外面的,因此签名的变动不会导致交易的哈希值变动,也就不会影响交易的ID。隔离见证还引入了一个专门的标识符,叫做“wtxid”:它是交易和整个witness部分的哈希值,所以如果一笔交易在传播时没有附带任何witness数据,交易ID就等于wtxid。

这个解决方案使得我们可以创建一系列前后相继的未确认交易,而无需担心任何风险,这对闪电网络这样的协议来说是非常重要的。这里的意思是,如果不解决交易熔融性问题,支付通道的参与者就无法快速检索对手有没有把一笔过时的通道交易上链,因为同样内容的交易可能会以完全不同的ID出现。

网络和存储的扩展

Witness数据往往是交易数据中占比最大的一部分。在使用多签名脚本的交易中,witness最多可能占据交易数据量的75%。感谢SegWit,签名的传输变成了一个可选项:只有节点想要验证交易时,才需要请求这些数据。而没有支持SegWit的SPV客户端和节点也无需下载额外的数据,可以节省硬盘空间。

降低交易手续费

SegWit类型的交易比以往的交易类型更便宜,因为它减少了需要存储的witness数据。准确来说,“Size”的概念在SegWit类型的交易上略有不同。它引入了一个“虚拟大小”的概念:所有放在witness部分的数据都会乘以0.25来计算数据量大小,从而一个区块中可以塞进更多的交易。来看一个例子。

假设我们有一笔传统类型的交易,数据量大小为200字节,那么1MB的区块里面可以放进5000笔这样的交易。而一笔等效的SigWit交易有120字节是放在witness区域的,因此其虚拟大小为80+0.25*120=110字节,所以区块可以放入9090笔这样的交易。如果上链的手续费是每字节40聪,则交易费会从8000聪减低到4400聪,几乎打了个对折。

脚本版本

你可能已经注意到了,每个锁定脚本都会有1个字节来表示脚本的版本。使用不同的版本号就能以软分叉的形式增加或变更功能,语法改变、新的操作符等等。

签名验证的效率优化

隔离见证也优化了签名算法的效率,如CHECKSIG、CHECKMULTISIG等。在SegWit之前,哈希计算的次数与签名数量的平方成正比,但有了隔离见证后,算法的计算复杂度就减低到了O(n)。

SegWit所遇问题及挑战

即使它有这么多长处,它也有一些缺点。比特币社区也有许多人反对这一升级。我们来看看反对方提出的一些意见。

因为SegWit是一个软分叉,许多客户端可能不会升级,因此两种类型的UTXO会在网络中同时存在;诸如消除交易ID熔融性以及哈希计算次数线性上升这样的重大变更对非SegWit输出无效,因此网络仍会暴露在交易ID熔融性和哈希时间平方级上升的风险中。

SegWit会降低网络的安全性,执行完全验证的节点会大幅减少,因为只有那些适配了SegWit的节点才有能力验证交易的witness部分。

SegWit不能被废除。如果废除了它,所有变更都撤销,那么所有的SegWit输出就会变成大街上任人捡拾的钱。

SegWit希望一次解决所有问题,也正因此,它导致了大量的代码改动。它会让未来的工作更加负载,而且提高了出现驱之不去的软件bug的机会。

结论

虽然由SW解决的问题很有可能有更优雅的解决方案,我们仍然相信,这是提高网络的可扩展性并开启闪电网络等技术实现的最佳办法。

Billions项目组

诸君喜欢的话,还请点赞转发支持,我会持续更新,与君共同进步。

-END-

郑重声明: 本文版权归原作者所有, 转载文章仅为传播更多信息之目的, 如作者信息标记有误, 请第一时间联系我们修改或删除, 多谢。

金宝趣谈

[0:0ms0-3:501ms