玩币族移动版

玩币族首页 > 币圈百科 >

比太公开课:隔离验证

152418ko2hs1p6i2dvymv8.jpg.thumb

  大家好,我是比太的文浩,在开始本次的《比太公开课》之前,先给大家拜个早年,祝大家新春快乐!

  距离上次的《比太公开课》又过了很长的时间,原因嘛,还是那个字“忙”。

  这段时间,关于“硬分叉 软分叉 ”,“Core Classic ”等话题在国内外比特币社区中都引起了非常大的争议,还曾有不少人询问过我们比太团队的意见:

  * 有国外的业内媒体给我们发来过调查问卷;

  * 有用户问比太站队站哪边(当然,我个人对于“站队”是很反感的);

  * 还有不少人向我们咨询一些相关的技术细节,比如曾有一些网友通过QQ、微信具体向我们咨询关于SegWit的技术细节;

  另外,这段时间我还曾参与了两次相关的讨论会议:

  * 在北京与多家企业一同和核心开发者 Jeff Garzik 进行技术交流;

  * 在好比特的年会上参与分叉相关的技术讨论;

  参与讨论的过程中,发现大家也是针尖对麦芒,争吵的不亦乐乎。

  本次公开课不会去讨论争议的部分,由于有不少用户很关心像“隔离验证”这类的技术实现,巴比特也希望我们能跟大家交流一下相关的技术内容,因此,我准备了这一次《比太公开课》,希望能用一种尽可能清晰、简单的方式给大家讲述一下“隔离验证”的相关内容。

  本次公开课所采用的方式与之前略有不同:

  在比太微信群中以语音为主的方式进行;

  比太QQ群和巴比特论坛则以文字的方式同步主要内容;

  感兴趣的同学可自行选择自己方便的方式参与本次公开课;

  在几个地方问问题都可以,我们会根据情况选择回答,不过,问问题的时候请不要用语音,我不一定来得及听;

  在正式开始聊“隔离验证”之前,我先强调几点:

  本次交流不聊分叉、块大小、分裂、谁对谁错等话题,只聊隔离验证的技术原理;

  我先假定本次交流的听众对于像 hash 、签名等这类的内容有着最基础的了解(并不需要你真懂,只需要大概明白含义就够了),我不会去给你讲“什么是 hash ”、“什么是签名 ”等诸如此类的内容,如果实在听不懂,请自行谷歌学习;

  我会用尽可能简单的方式给大家讲述清楚隔离验证的技术原理,尽量让那些不太懂技术的人也能理解隔离验证的原理;

  本次公开课的主要内容,错过的人还可以在巴比特论坛上看到:

  http://8btc.com/thread-28719-1-1.html

  隔离验证本身与块大小这一话题其实没什么关系,“隔离验证一定程度上增加了块大小”这一点其实是副产品,并不是其主要目的,不过由于块大小、分叉的话题太过激烈,而隔离验证恰恰是矛盾一方所努力推进的技术实现,因此被当做是与 2MB 相对应的提升块大小的技术实现。比如,我们经常看到有人说“Classic 是直接升级为 2MB ,Core 是采用另一种叫隔离验证的复杂技术来升级到最多也就是 1.8MB”这类的话,其实,压根就不是那么一回事。

  这里,我必须反复强调这句话“隔离验证就是隔离验证,它的主要目的跟它的字面意思一样,就是要隔离的做验证,而不是为了增加块大小,最终隔离验证能增加块大小只是它的副产品”,请记住这句话。

  好了,在正式进入到隔离验证的讨论之前,我先问大家一个问题:比特币交易的结构是什么样子的

  今天听课的不是业内人士就是比特币爱好者,大家或多或少对于比特币交易还是有一些理解的,不少人可能还看过类似的一些讲述交易结构的文章,码农们没准儿还翻过 bitcoin wiki 和 开发者文档等内容,甚至还知道一些诸如:TxIn、TxOut、OP_CHECKSIG、OP_EQUAL、ScriptSig、ScriptPubKey 等名词,但您真的“懂”比特币交易了吗

  比如说,比特币交易为什么会设计成这个样子 它好在哪里 不好在哪里

  好了,在正式进入到隔离验证的讨论之前,我先问大家一个问题:比特币交易的结构是什么样子的

  今天听课的不是业内人士就是比特币爱好者,大家或多或少对于比特币交易还是有一些理解的,不少人可能还看过类似的一些讲述交易结构的文章,码农们没准儿还翻过 bitcoin wiki 和 开发者文档等内容,甚至还知道一些诸如:TxIn、TxOut、OP_CHECKSIG、OP_EQUAL、ScriptSig、ScriptPubKey 等名词,但您真的“懂”比特币交易了吗

  比如说,比特币交易为什么会设计成这个样子 它好在哪里 不好在哪里

  让我们来看一个具体的比特币交易:

  bitcoin-cli getrawtransaction c0a0d0f4de3be3b57f516f127a6fa5
d5895f09bfacbb001853593320fb0a4164

  0100000001473e2a366b081a0e6645199692ccf2f6e25e4556a182
65785a88b46d50fd68c2000000006a4730440220296dd1587b8290a0
4a9253de431b5dbb698030527df5ca75592ab29eea12e85b0220737ca
fd85b79a7dea1b29c0a5753432d1dacb50f5225221974e38134617ffc85
012103dd38b9b13b24498c382045afb08a4256c3c8bf86e15122df741bd
2c2a0bd120fffffffff02a0d21e000000000017a914d1640264c522d9a31aaf6
9207e57d0a224eb7e668770110100000000001976a914dfd6b01e5ec1ec
b1568da79931ddd8327dafd9b588ac00000000

  tx_id = tx_hash = c0a0d0f4de3be3b57f516f127a6fa5d5895f09bfac
bb001853593320fb0a4164

  raw_tx = 0100000001473e2a366b081a0e6645199692ccf2f6e25e4556a1826578
5a88b46d50fd68c2000000006a4730440220296dd1587b8290a04a9253de
431b5dbb698030527df5ca75592ab29eea12e85b0220737cafd85b79a7dea
1b29c0a5753432d1dacb50f5225221974e38134617ffc85012103dd38b9b1
3b24498c382045afb08a4256c3c8bf86e15122df741bd2c2a0bd120fffffffff02
a0d21e000000000017a914d1640264c522d9a31aaf69207e57d0a224eb7
e668770110100000000001976a914dfd6b01e5ec1ecb1568da79931ddd8
327dafd9b588ac00000000

  tx_hash = double_sha256(raw_tx)

  这其实就是原始格式(16进制)的比特币交易:rawtx。比特币网络上传播着的就是这种交易,你发送、接收的比特币交易其实也是这个样子的。

  有人可能会说了,看不懂。

  看不懂 没关系,理解今天的内容,并不需要你能看懂交易格式。

  刚才那笔交易中,签名是这个样子的:

  30440220296dd1587b8290a04a9253de431b5dbb698030527df5ca7559
2ab29eea12e85b0220737cafd85b79a7dea1b29c0a5753432d1dacb50f5225
221974e38134617ffc8501

  好了,大家现在可以找个文本编辑器(记事本之类的),然后在原始交易 rawtx 中搜索一下签名,问大家一个问题,签名大约出现在交易中的哪个位置

  搜过的人现在应该都能回答了,在中间靠前的位置,也就是说,签名在交易中,基本上在前半部分的内容里(其实就是 TxIn 的位置)。

  现在的问题是,签名为什么要在这里,在这里有什么好处

  答案是:中本聪是这么设计的,所以签名在这里。好处嘛,其实也没什么好处,不止是没有好处,缺点却还不少。

  1、由于这种设计,比特币的交易结构中就凭空的隐藏了不少“秘籍”,比如说:未签名交易其实就是用了另一个叫 ScriptPubKey 的内容,先占据着签名所需的位置,然后对这个未签名的交易做签名,再把签名的结果替换进去。这其实是很麻烦的一件事,既不容易说清楚,也很难用代码去实现。当一个交易中有多个输入(TxIn)的时候,又要有一套“秘籍”来依次准备未签名交易,依次把签名替换回去;而当一个交易中又涉及到多重签名的交易时,则有需要另一套约定好的规则来准备未签名交易,再进行签名后的数据替换工作;如果一个交易既涉及多个输入,又涉及多重签名呢 那就是秘籍套秘籍,反正是麻烦的要死;有兴趣且有能力的童鞋们不妨去翻翻比特币协议在各种语言中的实现部分,就会发现,无论是 C++、Java、Python 等语言所编写的比特币协议库,通常都需要写非常多的、混乱不堪的代码来做上述的交易数据构造工作,很头疼,写过的都懂。

  2、将签名放在交易结构中,由于签名的可塑性,使得交易也就有了可塑性,比如说,很早以前我就给大家讲过的因为椭圆曲线的对称性,s和s’都是能被验证通过的签名,这种情况下,任何接收到你所广播的交易的节点,都有能力用s’来替换掉s,然后重新广播,重新广播的交易其实有着相同的内容(输入 TxIn 和输出 TxOut),但却有着不同的 tx_id (tx_hash),这样就能达到混淆视听的目的,甚至影响到一些比特币企业(如交易所)的服务。交易延展性不会直接导致您丢币,但会影响到个人和企业对于比特币交易状态的判断,进而可能导致可能出现的资产管理风险。之前,bitcoin-core 在 BIP62 中进行过一些试图努力解决交易延展性问题的尝试,但从某种意义上来讲,交易延展性其实是无法彻底根治的,至少私钥拥有者可以重新生成一个签名,交易不变但签名变了,最终的 tx_id 也就变了,这种情形应用于多重签名的场合,甚至可能会影响到其它钥匙的持有人对于交易的判断,导致一些潜在的资产风险,在当前的交易结构下,我们是无法彻底杜绝这种情况的发生的;

  3、当我们需要对交易进行签名时,对每个 TxIn 进行签署的 hash 都是不同的(参见上述的“秘籍”),所以对于“冷钱包”这种离线签名的实现方式其实增加了很大的难度,无论是数据结构还是代码的层面;

  也就是说,将签名放在交易内容中其实没有任何好处,反而增加的结构的复杂度和交易延展性的风险,这显然是得不偿失的。

  那么,最合理的交易结构到底应该是什么样子的呢 其实很简单:

  TxIns + TxOuts + [签名]

  也就是说把签名单独拿出来,放到外面就能解决上述的所有问题了。

  这就回到了今天我们要谈论的标题 – “隔离验证”。

  隔离验证其实就是把原来的比特币交易中签名的部分单独拿出来放到另一个叫 witness 的结构中,来达到我所说的目的。

  看到这里,大家就明白了吧,通常一个看起来很复杂的课题“隔离验证”,其基本原理其实并不复杂,所要达到的目的其实很简单,就是要把签名拿出来,放到另一个地方,也就是所谓的“隔离”,就这么简单。

  签名就是要用来进行“验证”的数据,放在另一个地方就是要“隔离”出来,所以给这件事情起名为“隔离验证”也就再合理不过的了。

  通过上面的讲述,大家就应该能理解隔离验证的好处了,其好处的确是巨大的:

  交易是交易,签名是签名,对于交易来说,只关心 TxIn 和 TxOut 就好了,我们都清楚一个比特币交易其实就是花一笔之前收到的钱,也就是说要用之前收到的 TxOut 作为这一笔交易的 TxIn 然后发给后续的 TxOut,隔离之后的交易结构使得当您决定好花哪一笔钱、要花给谁的时候,交易的内容就已经是确定了的,交易的数据就不会再发生改变了,最终的 tx_id 也就是不变的了。想要验证签名 那就去 witness 里找到对应的签名数据验证一下合法性即可,又简单、有没有交易延展性的问题,用码农的语言来说,那可真是“不要太爽”!

  大家都知道,我们比太钱包提供的是易用安全的冷钱包解决方案,对于我们来说,当然希望在离线签名的过程中,冷私钥需要签署的 hash 是精确的而不是变化的,这其实也是隔离验证的好处之一。

  刚才,我再巴比特论坛上看到有人问隔离验证是不是对闪电网络有好处

  我的回答是,隔离验证对于所有的基于比特币区块链的扩展应用(甚至包括交易所和钱包等)都有好处,精确的 tx_id 当然会让很多基于 tx_id 所扩展出来的应用都容易的多,也可靠的多。

  上述好处其实就是隔离验证的本质。

  所谓的隔离验证,其实本质上不是为了解决块大小的问题而产生的改动,它也不是像一些人所说的那样“是 Core 团队中 BlockStream 公司的几名核心开发者的为了阻挠扩容而采取的阴谋”,而是比特币交易本来就应该是那个样子才对。隔离验证的结构改进,跟当年的压缩格式的公钥(关于这部分内容,可参阅我们之前的一次公开课 – 八卦中本聪,中的内容 http://8btc.com/thread-14057-3-1.html )一样,都属于由于最初的结构设计的不合理而需要改进的内容。

  也就是说,比特币的交易,本来就应该是“隔离验证”的才对,只是由于最初中本聪设计成了当前的样子,所以一直才保留至今,如果当年就下了狠心给改好了,没准就没有今天的这么多争议了,比特币程序员们也能省下很多脑细胞用来干更多有意义的事情,而不是跟交易的结构做斗争,各类的比特币企业也能少受一些交易延展性的困扰,等等等等。

  好了,讨论了这么多,那么,隔离验证到底应不应该做呢

  我的答案是:当然应该做,合理的改进干嘛不做?比如说,“压缩格式的公钥”,这个改进到底应不应该做呢?

  隔离验证的改进应该如何做呢

  由于要考虑到向下兼容、要考虑到各类客户端旧版本的兼容情况,所以开发者们希望尽可能用一种“软分叉”的方式来实现,为了做到这一点,当前一共提出了4个相关的 bip (141-144)。

  我们都知道,对于任何一个计算机系统来说,新设计一套结构都是容易的,但想要做到向下兼容就要困难很多,想要让新老结构共存且旧版本还能正常运行就更加困难,尤其是当我们考虑到这些新旧结构的数据还要在同一个区块链上传播的情况,就需要进行更多的努力了。关于这些部分,在几个 bip 中进行了比较详细的描述,有兴趣的可进一步阅读相关技术文档:

  比如说:

  bip141 详细讲述了一个叫 “witness” 的新结构,脚本和签名等数据被移动到了这个新结构中,同时介绍了隔离验证如何做到的向下兼容等;

  bip142 讲述了隔离验证的新的地址格式;

  bip143 举例描述了隔离验证交易签名的验证方式;

  bip144 讲述了如何在保持向下兼容的情况下节点间通报支持隔离验证的情况及传播和请求验证数据的方式;

  好了,通过讲述这些内容,大家应该大致能明白隔离验证到底是怎么一回事了,隔离验证本身跟块大小并没有什么关系,只是由于验证数据处于兼容的目的被放在了另一块空间中,同时修改了块上限的计算方式使得隔离验证本身能起到一定程度的扩容作用,才让大家把它当成是另一种扩容方案,并且被当做是 2MB 方案的对立面。

  最后,总结一下,隔离验证其实是对之前不太合理的比特币交易结构的一次优化,开发者们试图用一种影响尽可能小的、尽可能向下兼容的、“软分叉”的方式来实现,这种改进本身(就像是“压缩格式的公钥”一样)是非常合理的,与块大小之争没什么直接的关系。如果隔离验证的软分叉上线之后,我们可能会在相当长的一段时间里、在比特币网络上都能看到新旧版本的交易同时存在,就像直到今天,仍有人在用 5 开头的私钥(而不是压缩版本的 K 和 L 开头的私钥)一样。

  隔离验证能带来的块大小增加只是个副产品,块大小到底应不应该增加、应该如何增加,那其实是另一个话题,这需要各方充分讨论,并尽可能客观公正的听取对方的意见,我本人就不对块大小争论进行任何评论了。而关于到底应该如何管理比特币代码的问题,这属于 governance issue ,这是政治问题,更不在本次公开课的讨论范围中。

  隔离验证是一个应该做的改进,由于与块大小的争议混到了一起,使得不少人在看待“隔离验证”的时候带上了很多的感情色彩。个人建议,隔离验证就是隔离验证,如果要做到向下兼容、软分叉且不出任何问题,需要核心开发者们、产业链上下游的相关企业们、比特币钱包的开发者们共同努力,确保此项改进的安全进行。如果非要问我隔离验证方案是否有风险,我反而觉得最大的风险反而是大家逼着说“你这隔离验证的方案啥时候能上 2MB 可是下个月就能分叉”,逼着核心开发者们叫着劲的仓促上马以达到提升块大小的目的,这就有点得不偿失了,隔离验证的升级还是需要做充分的测试,相关企业和软件解决方案也应尽可能充分的测试兼容性,然后再上线才好。

知识: 隔离验证