Bitcoin Forum

Local => 媒体 => Topic started by: foladgoad on May 03, 2017, 01:54:50 AM



Title: 最小可行性区块链原理解析
Post by: foladgoad on May 03, 2017, 01:54:50 AM
加密货币,特别是比特币,几乎从各个方面都得到了大量关注:规则、管理、税务、技术、产品创新等等,不胜枚举。“点对点(去中心化)电子现金系统”的概念颠覆了我们以前对货币和金融所持有的设想。
即便如此,把数字货币方面搁到一边,还有一个可以说是更有趣更深远的创新,即底层的区块链技术。无论你对比特币或是它的山寨币衍生品有什么看法,作为一种货币和价值存储手段,它们背后的运作基础都来自于中本聪概括的区块链原理:

我们运用点对点网络提出了重复花费问题的解决方案。网络通过将交易散列到一个进行中的基于散列的工作量证明链,来对交易进行时间戳标记,并形成一个记录,这个记录只有在重做工作量证明的情况下才能被改变。最长的链不仅作为它所见证事件发生时序的证据,而且也证明它来自最大的CPU功率池……网络本身要求架构最小化。

区块链对任何“货币”都是不可知的。事实上,它可以适用于促成很多其他使用案例。因此,理解“最小可行区块链”背后的方法和原理是有好处的:

以下将从头开始解释为什么需要特定的部分(数字签名、工作量证明、交易区块),以及它们如何集合起来形成具有卓越性能的“最小可行区块链”。

 

用三式记账法保障交易安全
 

Alice和Bob是集邮爱好者,偶尔会做做交易。如果双方都看到喜欢的东西,可以当场协商完成交换。换言之,这是个简单的以物易物的系统。
有一天Bob拿来一枚邮票,Alice觉得她必须要收藏,但问题是Bob对Alice所提供的交换物不是特别感兴趣。Alice沮丧不已,她继续和Bob协商,最后达成一致:他们做个单方交易,Bob先把邮票给Alice,Alice承诺以后再偿还Bob。

Bob和Alice已经认识有一阵子了, 但是为了确保两个人都信守承诺(主要是Alice),他们同意让朋友Chuck来对交易“进行公证”。
他们把图2这个可以表明Bob给了Alice一枚“红色邮票”的交易收据做了三个副本(三方各持一份)。Bob和Alice可以用收据来记录他们的交易, Chuck存储副本作为交易证据。这个设定很简单,但其中有一些很重要的属性:

Chuck可以鉴定Alice和Bob两个人的真实性,以确保不会有人在他们不知情的情况下蓄意伪造交易。
Chuck账簿中的收据证明了交易发生。如果Alice声称交易从未发生,那么Bob可以去找Chuck,用他的收据来证明Alice说谎。
如果Chuck的账簿中没有收据,就证明交易未发生过。Alice和Bob都不能伪造交易。他们可以伪造交易收据,声称对方说谎,但同样的,他们可以去找Chuck,查看他的账簿。
Alice和Bob都不能篡改当前的交易。如果任意一方篡改了交易,他们可以去Chuck那儿,用储存在Chuck账簿中的副本核实他们的副本。
以上操作就是“三式记账法”,操作简便,对参与双方都能提供很好的保障。但你也看到了它的缺点,对吧?我们对中间人寄予了很大的信任。如果Chuck决定和另一方串通,那么整个系统就土崩瓦解了。
 

用公钥基础设施(PKI)保障交易安全
 

Bob不满于使用“可靠中间人”的不安全性,他决定研究一下,发现公钥密码可以免去使用中间人的需要!这里解释一下:

公钥密码,也叫做不对称密码,指的是一种密码算法,它需要两个单独的钥匙,一个是秘密的(私有的),另一个是公共的。尽管这个钥匙对应的两部分不同,但有数学联系。公钥用于对纯文本加密或者查验数字签名;私钥用于解密密码文本或者创建数字签名。

运用第三方(Chuck)的原本意图是要确认有三个属性:

验证真实性: 不能有恶意的一方伪装成其他人。
不可否认性: 事实发生后,参与方不能声称交易没有发生过。
完整性:事实发生后,不能再修改交易收据。
结果是,公钥密码可以满足以上所有要求。简单地说,工作流程如图3所示。
Alice和Bob分别生成一个固定的公钥-私钥对。
Alice和Bob公布出他们的公钥。
Alice以纯文本的形式写一个交易收据。
Alice用她的私钥对交易信息的纯文本进行加密。
Alice在密码文本上添加一个“由……签名”的纯文本备注。
Alice和Bob都储存相应的输出结果。
注意只有在多方参与的时候才需要第五步:如果你不知道是谁签署了信息,就不知道该用谁的公钥来解密,这个问题很快就会变得有关紧要。
这看起来像是没什么特别理由的大量工作,但我们还是来检验一下新收据的属性:
Bob不知道Alice的私钥,但问题不大,因为他可以查询她的公钥(公钥是全世界共享的),然后用公钥来解密交易的密码文本。
Alice并不是真的在给交易内容“加密”,而是通过使用她的私钥给她“签名”的交易编码:任何人都可以用她的公钥对密码文本进行解密,由于她是唯一拥有私钥的人,这个机制保证了只有她能生成交易的秘密文本。
Bob或针对这个问题的任何其他人,如何获得Alice的公钥?有很多种方法来分发公钥——例如,Alice公布在她的网站上。我们可以假定有这样的合适的机制。

因此,使用公钥基础设施(PKI)可以满足我们之前所有的要求:

Bob可以用Alice的公钥通过解密密码文本来证明签名交易的真实性。
只有Alice知道她的私钥,因此Alice不能否认交易的发生——她已经签名了。
没有Alice的私钥,Bob或任何其他人都不能伪造或修改交易。
注意第二条,Alice可以否认她是那个有争议的公钥——私钥对的真正所有者。
Alice和Bob只储存了签名交易的副本,消除了对中间人的需要。“神奇”的公钥密码和双方以物易物系统完美匹配。
余额 = Σ(收据)

随着公钥基础设施到位,Bob和Alice又完成了一些交易:Alice从Bob处得到另一张邮票,Bob从Alice那儿也挑了一张邮票。它们都按照与之前相同的步骤,生成签名交易并将它们附加到各自的分类账簿中。
记录是安全的,但有一个小问题:不清楚是否任何一方有未结余额。先前只有一个交易,很清楚是谁欠谁的(Alice欠Bob)以及欠了多少(一枚红色邮票),但是有多个交易以后,情况变得模糊起来。所有的邮票都是等值的吗?如果是,那么Alice有一个负余额。如果不是,那就谁也说不准了!为了解决这个问题,Alice和Bob达成一致如下:

黄色邮票的价值是红色邮票的两倍。
蓝色邮票和红色邮票等值。
最后为了确保他们新协议的安全性,他们用交易的相对值更新了每个交易,重新生成了分类账簿。新的账簿看起来像图5那样。
这样,计算最终余额现在变成了一个简单的事,循环访问所有的交易,将适当的借贷记录应用于各方。最终结果是Alice欠Bob 2个“价值单位”。什么是“价值单位”? 它是由Alice和Bob都同意的任意交换媒介,另外,由于“价值单位”并不耳熟能详,Alice和Bob同意将1个价值单位称为1个chroma(复数形式:chroms)。

上面这些看起来都是小事,但每一个参与者的余额都是分类账簿中所有收据的一个函数这一事实有重要的意义:任何人都可以计算大家的余额。不需要任何可靠的中间人,也不必对系统进行审计。任何人都可以遍历整个分类账簿,核实交易,计算出每一方的未结余额。

 

多方转移和验证
 

接下来,Bob无意中发现John有一枚邮票,他实在很喜欢。他告诉John他和Alice在使用的安全分类账簿,并问他是否愿意做个交易,Bob把Alice欠他的余额作为支付手段转移给John——即Bob从John那儿获得邮票,Alice之前欠Bob的金额将变成她欠John的。John同意了,但现在他们有个问题:Bob如何能以安全和可验证的方式把他的余额“转移”给John?经过一番协商,他们想出一个巧妙的计划(如图6所示)。
Bob按照与之前相同的步骤创建了一个新交易,不过他先计算出他想要转移的加密交易的SHA-256校验和(一个唯一的指纹),然后将校验和嵌入新收据中“是什么”一栏。事实上,他在将之前与Alice的交易与新的转移收据链接起来,这样就把它的价值转移给了John。
为了保持事物的简单性,我们假定所有的转移都会“消费掉”被转移交易的全部价值。要把这个系统扩展到使部分转移成为可能并不难,但此时没有必要考虑得那么复杂。

随着新交易到位,John为了安全起见,做了一个加密分类账簿的副本(现在有三个副本)并运行了一些检查来验证它的完整性:

John提取了Alice和Bob的公钥,验证前三个交易的真实性。
John证实了Bob转移的是一个“有效”交易:
2-1. 待转移交易的地址是Bob。
2-2. Bob此前没有把这个交易转移给任何其他人。
如果所有检查都通过了,他们就完成交易,我们可以通过遍历分类账簿来计算新的余额:Bob有一个净零数余额,Alice有2个chroma的借额,John有2个chroma的贷额(由Alice提供)。这样John现在就可以把他的新分类账簿拿给Alice并要求她支付,即使Alice没有出席交易,也没有问题:

Alice可以用Bob的公钥核实新转移交易的签名。
Alice可以核实转移的交易是对她和Bob一个有效交易的引用。
以上转移和验证过程是系统一个了不起的属性!注意要让它全部能工作,我们需要两个使能技术:一个是公钥基础设施的运用,使数字签名验证成为可能;另一个是收据账簿,使我们能够查看完整的交易记录以验证余额并链接先前的交易来进行转移。

John和Bob对这个巧妙的解决办法很满意,然后两人分头回家:Bob带着新邮票,John有了新的分类账簿。表面上看一切完美,但是他们刚刚把自己暴露在了一个极具挑战性的安全问题之下……你发现了吗?

 

重复消费和分布式一致性
 

在与John完成交易后不久,Bob意识到他们刚刚在他们的系统中引入了一个严重的漏洞,如果他迅速行动,就可以利用这个漏洞:Bob和John都更新了他们的分类账簿来包括新的交易,但是Alice和其他任何人都不知道交易已经发生。结果是,没有什么能阻止Bob接近网络中的其他人,给他们展示旧的账簿副本,而旧的账簿副本里没有他和John的交易!如果Bob说服他们进行交易,就像他和John做的那样,他就可以“重复消费”同一个交易,想进行多少次都可以!
p7
当然,一旦多人拿着新的分类帐簿要求Alice支付,欺诈行为将被检测到,但这已经无济于事了——Bob已经带着战利品跑掉了!

只有两个参与者的时候,不可能受到双重消费攻击,因为要完成交易,你要验证并同时更新两个分类账簿,因此所有分类账簿始终保持同步。然而当我们再添加另外一个参与者时,我们就引入了各参与者之间账簿不完全和不一致的可能性,这就使双重消费成为可能。

在计算机科学语言中,双方分类账簿具有“强一致性”,超过两方的分类账簿则需要某种形式的分布式一致性以解决双重消费的问题。

这个问题最简单的可能的解决方案是要求分类账簿中列出的各方都必须在每个新交易发生时都在场,以便每个人可以同时更新他们的账簿。这个策略对小型的群组有效,但不能扩展到有大量参与者的情况。

 

分布式一致性网络的要求
 

我们来设想一下,我们想要将分类账簿扩展到全世界所有集邮者,这样任何人都可以用一种安全的方式交易他们喜欢的邮票。显然,由于地理位置,时区和其他限制,要求每个参与者在每个交易登记的时候都在场是不可能实现的。我们能建立一个不需要每个人都在场批准的系统吗?

地理位置算不上一个真正的问题:我们可以把交流转移到线上。
时区问题可以通过软件解决,我们不需要每个人手动更新分类账簿。相反,我们可以建立一个软件,它能在每个参与者的计算机上运行并代表他们自动接收、批准以及向分类账簿添加交易。
事实上,我们可以建立一个点对点(P2P)网络,负责分发新的交易并获得每个人的批准! 但很可惜,说起来容易做起来难。例如,虽然P2P网络可以解决我们的地理位置和时区问题,但试想即便只有一个参与者离线,会出现什么情况? 我们是不是要阻止所有交易,直到他们再次上线?

注意,“如何”构建P2P网络本身就是一个庞大的课题,构建这样一个网络的底层机制也远超出我们讨论的范围……我们把它作为一个练习留给读者。
p8

原来分布式一致性的问题在计算机科学中已经被深入研究过,并且已经提出了一些有希望成功的解决方案。例如,两阶段提交(2PC)和Paxos都使这样一种机制成为可能,即我们只需要参与者的大多数法定人数(50%以上)接受就能安全地提交新的交易:只要大多数人已经接受交易,就能保证群组中剩下的人最终汇合在同一个交易历史。

即便如此,单单有2PC或Paxos是不够的。比如,在每天都有新参与者加入而其他人不预先通知就消失的情况下,2PC或Paxos如何知道我们P2P集邮者网络中的参与者总数?如果有一个先前的参与者离线,他们是临时还是永久离线?相似地,还有另一个我们必须考虑的更具挑战性的“Sybil攻击”:没有办法阻止一个恶意参与者创建许多档案,以在我们的P2P网络中获取不公平的投票权份额。

如果系统中的参与者数量是固定的,并且已经验证他们的身份真实有效(也就是说,这是一个可信网络),那么2PC和Paxos都会工作得很好。但我们不断变化的集邮者P2P网络并不是这样的情况。我们走进死胡同了吗? 嗯,并不尽然……

这个问题有个明显的解决方案是从问题陈述中消除“分布的”部分。我们可以不建立一个P2P分布式系统,而是建立一个所有集邮者的全局注册表,记录他们的帐户信息,对他们进行验证并(尝试)确保没人能通过创建多个身份作弊,最重要的是,保证有一个共享的分类账簿副本!具体来说,我们可以建立一个网站,这些交易在网站上进行,网站将在它的集中式数据库里记录所有的交易,以此确保交易的完整性和正确排序。

以上是一个实用的解决方案,但我们得承认,它不尽如人意,因为它迫使我们失去了分类账簿系统点对点的性质。它将所有的信任置于一个单一的集中式系统,这就带来了一组全新的问题:什么是系统的正常运行时间,安全性和冗余;谁来维护系统,他们维护系统的动因是什么;谁有管理访问权限等等。集中式带来了它自己的一系列挑战。

让我们回顾一下在P2P设计中遇到的一些问题:

确保每个参与者始终保持更新状态(强一致性系统)会产生很高的协调成本,影响可用性。如果单个点不可达,整个系统都无法提交新交易。
在实践中,我们不知道P2P网络的全局状态:参与者人数,个体是暂时离线还是决定离开网络等。
假设我们可以解决上述限制,系统仍然可能受到Sybil攻击,恶意用户可以伪造许多身份行使不公平的投票权。
不幸的是,解决上述所有限制是不可能的,除非我们放松一些要求: CAP定理告诉我们,我们的分布式系统不能有很强的一致性,可用性和分区容忍性。因此在实践中,我们的P2P系统必须在(更)弱一致性的假设下操作并克服它可能带来的影响:

我们必须接受一些分类账簿不同步(至少是暂时不同步);
系统最终必须收敛于所有交易的整体序(线性一致性);
系统必须以可预测的方式解决分类账簿冲突;
系统必须强制执行全局不变量——例如,没有重复消费;
系统应该免受Sybil和类似的攻击。
 

保护网络免受Sybil攻击
 

在分布式系统中实现一致性,比如通过对每个参与者的投票计数,会出现很多关于各节点“投票权”的问题:允许谁参与,某些节点是否有更多的投票权,是否每个人都平等,以及我们如何强制执行这些规则?

为了保持简单,我们假定每个人的投票是平等的。第一步,我们可以要求每个参与者用私钥在他们的投票上签名,就像在他们的交易收据上签名一样,并将投票传播到他们的节点上——在投票上签名确保了别人不能代表他们投票。然后我们可以制定一个规则,只允许提交一票。如果同一个钥匙签名了多个投票,那么所有的投票都作废——已经下定决心!到目前为止还好,现在难的部分来了……

最开始我们怎么知道允许哪个特定的节点参与?如果只需要一个独特的私钥来签名投票,那么恶意用户可以简单地生成无限的新密钥充斥网络。根本问题是,当生成和使用伪造身份很便宜时,任何投票系统都很容易被颠覆。

为了解决这个问题,我们需要使提交投票的过程变得“昂贵”。提高生成新身份的成本,或者提交投票的过程必须产生足够高的成本。为了让问题更明确,我们来想几个现实世界的例子:

你在当地政府选举中投票时,会要求你出示身份证件(例如护照),而伪造身份证件的成本很高(希望如此)。理论上,没什么能阻止你生成多个伪造的身份证件,但如果成本足够高(伪造的货币成本,被抓的风险等),那么运行Sybil攻击的成本将远大于其收益。
或者,假设提交投票给你带来了一些其他成本(例如支付费用)。如果成本足够高,那么再次的,运行大规模Sybil攻击的障碍也增强了。
注意,上述例子都不能完全“解决”Sybil攻击,但它们也不需要被完全解决。只要我们将攻击的成本提高到大于成功破坏系统所能得到的值,那么系统就是安全的,会按照预期运行。

注意,我们所使用的“安全”的定义是很宽松的。系统仍然会受到操纵,确切的投票计数会受到影响,但关键是恶意参与者不能影响最终的结果。

 

参与所要求的工作量证明
 

任何用户都可以通过生成新的私钥—公钥对来轻易地(并且花很少的钱)在我们的P2P网络中生成新的“身份”。同样,任何用户都可以用他们的私钥签名投票并将其发送到P2P网络——这也很便宜,我们的收件箱中大量的垃圾邮件清楚地说明了这一点。 因此,提交新的投票很便宜,恶意用户可以轻易地用尽可能多的投票淹没网络。

但是,如果将以上其中一个步骤变得昂贵,使你不得不消耗更多的精力、时间或金钱,情况会怎样呢? 这就是工作量证明背后的核心思想:

工作量证明步骤对于发送者来说应该是“昂贵的”。
他人验证工作量证明的步骤应该是“便宜的”。
这样一种方法有很多种可能的执行方式,但是为了达到我们的目的,我们可以再次使用之前遇到的密码散列函数的属性(如图9所示)。
p9

很容易计算任何给定消息的散列值。
生成具有给定散列值的消息很昂贵。
我们可以在我们的系统中施加一个新规则,要求每个签名投票必须具有以特定子串开始的散列值,即需要部分散列冲突,比如两个零的前缀。如果这看起来完全是任意的,那是因为它确实是任意的。跟着我的思路,我们通过几个步骤来看看这是如何生效的:

我们假定一个有效的投票陈述是个简单的字符串:”I vote for Bob” (“我投票给Bob”)。
我们可以用同样的SHA-256算法来为我们的投票生成一个散列值。
代码1
生成的散列值无效因为它没有以我们要求的两个零子串开头。
我们修改一下投票陈述,附加一个任意字符串再试一下:
代码2
生成的散列值也不满足我们的条件,我们更新值,一次又一次地尝试…… 155次尝试之后我们最终得到了:
代码3
上述工作流程的关键属性是,每次我们修改完输入,加密散列函数(在这种情况下是SHA-256)的输出是完全不同的:当我们增加计数时,前一次尝试的散列值并不能透露下一次尝试所得到的散列值的任何信息。因此,生成有效投票并不仅仅是个“难的问题”,我们可以把它比喻成彩票,每次新尝试都会给你一个随机的输出。同时我们也可以通过更改所需前缀的长度来调整彩票的赔率:

SHA-256校验和中的每个字符都有16个可能的值: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f.
为了生成有两个零前缀的有效散列,发送者平均需要256 (16^2)次尝试。
将要求变为5个零平均会需要1,000,000 (16^5) 多次尝试……关键是,我们可以轻易提高成本,让发送者找到一个有效散列需要耗费更多CPU周期。
我们可以在一个现代CPU上计算多少个SHA256校验和?它的成本取决于信息大小,CPU 架构和其他变量。如果你对此感到好奇,可以打开控制台,运行一个基准测试程序: $> openssl speed sha.

最终结果是,生成有效投票对于发送者来说是“昂贵的”,但对于接收者验证仍然是微不足道的。接收者散列交易(一次运算)并且核实校验和中包含所需的散列冲突前缀……太好了,那么这对我们的P2P系统有什么用呢?上述工作证明机制使我们能够调整提交投票的成本,从而使破坏系统的总成本(即假冒足够多的有效投票来确保特定结果)高于攻击系统能够获得的价值。

注意,“生成消息的高成本”在很多其他环境中是个有用的属性。例如,垃圾邮件能够运作恰恰是因为生成信息特别便宜。如果我们可以提高发送电子邮件的成本,例如要求工作量证明签名,那么我们可以通过使成本高于利润来打破垃圾邮件的商业模式。

 

建立最小可行区块链
 

我们已经谈到了很多基础内容。在讨论区块链如何帮助我们构建安全的分布式账簿之前,我们来快速地扼要概述一下我们的网络设定,属性和待解决的挑战(如图10所示):
p10

Alice和Bob完成交易并记录在各自的分类账簿中。 完成后,Bob有一个来自Alice的受公钥基础设施保障的借据。
Bob和John完成一个交易,他将Alice的收据转移给John。Bob和John都更新了账簿,但是Alice对交易尚不知情。
2-1. 皆大欢喜的情景:John要求Alice偿还他的新借据,然后Alice得到Bob的公钥,核实了他的交易,如果交易有效,她向John支付所需金额。
2-2. 不太欢乐的情景:Bob用没有记录他和John交易的旧账簿与Katy创建了一个重复消费交易,然后Katy和John同时出现在Alice家却发现只有一个人能得到报偿。
由于分布式账簿的“弱一致性”,重复消费是有可能的:Alice和Katy都不知道John和Bob之间的交易,这就使Bob利用了不一致性为自己谋利。有解决办法吗?如果网络很小,所有参与者都是已知的,那么我们可以要求每个交易在被认定为有效前必须被网络“接受”:

全体一致:每当交易发生时,双方联系所有其他参与者,告知他们交易的有关内容,等所有参与者“同意”后才能提交交易。因此,所有分类账簿同时更新,不可能发生重复消费。
法定人数一致:提高网络的处理速度和可用性(即如果有人离线,仍然可以处理交易),我们可以将上述全体一致的情况放宽到法定人数一致(整个网络的50%)。
对于参与者已知且已核实的小型网络,以上任何一个策略都能立即解决问题。然而,两种策略都不能扩展应用于更大型的动态网络,因为在任何时间点都无法得知参与者的总数和他们的身份:

我们不知道要联系多