假如先把去中心化的前提先去掉,我们都信赖一个中心化的机构比如说央行,央行发行货币是由印钞厂那里印钞等等的顺序后才开始发行货币的也就是我们以前最常见的纸币等,而想一下央行要是不发行实物货币了转为发行虚拟货币,(央行的公钥我们是都知道的)而我在和你交易时我把这个虚拟货币转给你,你在验证一下是不是央行发行的货币,这个想法好像还可以是吧,这个只是用到了密码学中的公私钥体系非对称加密算法,并没有用到区块链。因为这是个文件而这个文件有央行的签名,文件的内容是不可以伪造的可是我可以复制一份或者多份啊,这就跟实物货币不一样了假如我有一百元人民币我跟你买了一百元东西我把钱给你了而我就没有这一百元了,没办法花两次或多次这就是数字货币和实物货币的区别。这个叫花两次攻击:double spending attack,数字货币面临的一个主要的挑战就是如何解决double spending attack(花两次),来改进一下刚才的方法因为人民币是有编号的,那我要这个数字货币也加一个编号那么央行就要维护一个数据库了,比如说我获得了一个编辑号为1的数字货币,如果我把这个数字货币给你了你不但要验证是不是央行的还要验证我这个数字货币有没有被花出去过同时央行要改一下了因为我把这个数字货币给了你那么这个数字货币就在你手里了,假如我起了坏心思我复制了一份这个数字货币,我再给到别人那么别人就可以通过这个方法得知我是不是在重复使用这个货币了。这就解决了double spending attack的问题,这个方案是没错的实际中也时可以这么用的但这是一个中心化的方案数字货币的发行由央行控制和每一次交易都需要央行确认才能证明其合法性,依照这个方法我们能不能搞一个去中心化的方案把央行的职能改成广大的用户来承担这就是比特币数字货币系统要解决的一个问题,去中心化的货币要解决两个问题一个是数字货币的发行,谁有权利来决定数字货币的发行现在是去中心化了没有央行了,都是用户了该要怎么决定什么时候该发行,该发行多少。第二个问题怎么验证交易的有效性,怎么防止上面的double spending attack(花两次)。
第一个问题谁来发行货币。在比特币系统中是由挖矿决定的,第二个问题怎么解决double spending attack(花两次)其实解决方案是跟上面是类似的也是需要维护一个数据结构,来检查这个币以前有没有被花过被谁花过只不过这个数据结构不是由央行来维护,而是由所有的用户共同维护,这个数据结构计就是区块链。比如说有一个用户A获得了发行货币的权利(铸币权)那么他发行十个比特币
比特币系统中每个交易都包含了输入和输出两个部分,输入部分要说明币的来源,输出部分要给出输入人公钥的哈希,比如说A转给了BC各五个比特币而B又给CD各转了2,3各比特币而转币的过程中B也时要签名的也要说明币的来源这个时候C又把币给到了E这个时候E的证明就有点多了如上图,这就组成了一个小型的区块链,注意这里面有两种哈希指针第一种就是把它们穿起来变成一个链表第二种哈希指针是指向前面某个交易的这个是为了说明币的来源的,为什么要说明币的来源一是为了证明这个币不是凭空捏造的二是为了防止double spending attack(花两次)比如说B已经转钱给C和D了但是B又来一趟要转给F,签名还是B的签名,单看签名是没什么问题的但是查看币的来源就查出问题了这样一来就有效的防止了double spending attack(花两次)。回看到交易有没有想到一个问题就是在A和B进行交易的时候是不是B只需要知道A有没有转账转了多少就行了而A也是只需要知道B的公钥就行了这个说法貌似是对的但是也不全对因为在交易的时候B也要知道A的公钥一种解释是说我要知道钱是哪里来的谁给我的,A的公钥就是A的身份这样B就知道是A转给我钱了。其实还有一个更重要的原因不光是B需要知道A的公钥而是所有节点都需要知道A的公钥 为什么?为了验证A的签名这个转账交易要是合法的是有A的签名我们都知道签名都是私钥签名公钥验证,所以区块链上每个节点都是要独立验证的因为有的节点可能是有恶意的不能依靠别人所以我收到这个交易我就要验证是不是转给我的是不是合法我是旁观者也需要验证的所以大家都需要知道A的公钥。那么问题来了怎么才能知道A的公钥?A的公钥是这个交易中自己给出来的就A给B转账输入要知道币的来源输入当中还要说明A的公钥是什么这会存在一些人为的安全漏洞怎么去避免这个问题每个交易都是分为输入和输出两个部分,输入部分要说明币的来源还要A的公钥,输出部分说明要给出交款人公钥的哈希,那么A的币是在铸币交易是产生的它的输出里面是有A的公钥的哈希所以这个转账的A的公钥要跟这个币的来源的公钥的哈希一致,要是对不上就说明这个币不是给你的所以就解决了人为的仿造公的钥安全漏洞。所以说这些指向币的来源的哈希指针是很有作用的。在比特币系统中这些一验证的过程是通过实行脚本来实现的每个交易的输入是一段脚本包括给出的公钥这个也是在脚本里的,每个交易的输出也是一段脚本验证是不是合法的就是把当前交易的输入的脚本跟提供币的来源的那个输出脚本拼在一起看看能不能顺利执行如果能执行说明是合法的反之就是不合法的。
上图的例子中A的输入脚本下面拼接前面这个交易的输出脚本合并在一起运行如果没有错误那么就是通过的,
上图当中对比特币的一些细节做了简化实际系统当中每个区块可以包含很多个交易,这些交易就组织成了Merkle Tree(默克尔树),每个区块分为块头和块身两个部分(Block header、Block body)块头里包含的是一些宏观的信息,比如说用的是比特币的哪一个版本的协议,还有区块链中指向前一个区块的指针,还有整棵Merkle Tree(默克尔树)的根哈希值还有就是挖矿的target还有一个就是随机数nonce,整个块头的哈希要小于等于目标预值H(Block header)≤ target块头里存的就是目标预值的编码(nBits)这里要注意一点前一个区块的哈希只算的是区块的块头,只有Block header才可以把区块串联起来,而Block body有什么呢?有交易列表,取哈希是取块头的块身是不管的 ,而Merkle root hash能够保证这里的transaction list(交易记录) 是没有办法被篡改的。
以上这些理论还有一个简化的设想,上面说每个节点都需要验证交易实际当中系统中的节点分为全节点和轻节点,full node(全节点)是保存所有的信息的,验证每一个交易所以全节点也叫做(fully validating node)轻节点(light node)它只管保存Block header,一般来说轻节点没有办法独立验证交易的合法性
比如说这个交易是不是spending attack(花两次)轻节点是不知道的因为它没有存以前的交易,所以它是查不出来的系统中多数节点其实是轻节点,全节点的数不是很多。
一个问题,这些内容是怎么被写到区块链里去的?每个节点都可以发布交易对吧,每个账户都可以发布交易
这个交易是广播给所有节点的有些交易合法的有些交易可能是非法的,那么是谁来决定哪个交易写到下一个区块中呢?按照什么样的顺序写进去呢?如果每个节点自己决定行不行?比如我是个节点我收到了各种各样的交易然后我判断一下那些是合法的那些是不合法的然后我把它打包写到下一个区块里,构造成一个本地的区块链
就每个节点独立决定行不行?这肯定是不行的因为一致性是不同的我本地的区块链和你本地的区块链个那里面的数据可能就不一致了,区块链是什么?是一个去中心化的账本,既然是个账本那这个账本里的内容肯定是统一的,否则的话我记得账和你记得账不一样,那最后按那个账本来算呢?是吧。这个用分布式数据来说呢,叫做账本的内容要取得分布式共识(distributed consenas)分布式共识一个简单的例子就是分布式的哈希表(distributed hash table) 比如系统里有很多台机器共同维护一个全局的哈希表,那么这里需要取得共识的内容是key-value pairs(键值对)比如说有的人在我这台机器上插入一个key-value pairs(键值对)A 12345
那么别再另一台机器上也要能读出来这叫一个全局的哈希表,关于这个分布式共识有很多的理论研究学术界研究了很多年这里面有很多的不可能结论(impossibility resalt)其中最著名的一个就是 FLP impossibility resalt,这三个大写字母是三个作者姓的大写字母都是分布式系统的专家他们的结论是什么,在一个异步的系统里(asynchronras)网络传输时延没有上线就叫异步系统那么即使是有一个成员是有问题的(faulty)那么也不能取得共识这个结论听上去挺悲观的,如果这系统的网络传输是异步的,网络时延没有上限哪怕系统中有一个成员是有问题的(faulty)那么也没法达成共识,还有一个结论也是比较著名的 CAP Theorem 这CAP这三个字母是指分布式系统的三个性质,三个我们想要的性质C:Consistency(一致性)、A:Aailability(有效性)、
P:Partition tolerance(分区容忍性),这个CAP Theorem是说任何一个分布式系统,比如说这个分布式哈希表这三个性质中最多只能满足两个,不可能三个性质都满足。
分布式共识的一个比较著名的协议:Paxos,这个协议能够保证一致性,如果这个协议达成了共识,这个共识一定是一致的不会说一个成员认为的共识和另一个成员认为的共识不一样这个不会的一定是Consistency(一致性)但是某些情况下这个Paxos可能一直都达不成共识,这种可能性在实际中是比较小的但是也是客观存在的,这些作为扩展跟比特币实际关系是不大的。
来说一下比特币中的共识协议(Consensus in BitCoin)
比特币*识要解决的一个问题就是有些节点可能是有恶意的,我们假设系统中大多是节点是好的,有恶意的毕竟是小部分,那么这种情况下去怎么设计一个共识协议呢?
这里如果用到投票的话就就会出现很多的问题,就比如时间的问题、有些节点不作为的问题等等。
这来还有个更大的问题就是谁来投票,任何基于投票的方案首先要确定谁有投票权。要有一个membership(资格)的问题,如果这个区块链的membership(资格)是有严格定义的不是说谁都可以加入的,有的叫联盟链只有某些符合条件的才可以,在这个情况下基于投票的方案是可行的因为假设大多数是好的嘛所以这个是可行的,但是比特币系统中不是这样的,比特币系统中创建一个账户是很容易的,在本地产生一个公私钥对就是一个账户不需要任何人的批准,其实别人都不知道你产生了一个账户只有你跟外部产生交易的时候别人才知道,那这样一个有恶意的节点就可以抓这个空子用一台超级计算机不停的产生账户只要账户超过了投票总数的一半那么就完了,它就可以操纵投票结果了这种叫做女巫攻击(sybil attack)那这要怎么办呢?简单的直接投票是不行的
比特币系统中使用了一个很巧妙的机制来解决这个问题 用的同样是投票但是不是按照账户的数目投票是按照计算力来投票每个节点都可以在本地组装出一个候选区块把它认为合法的交易放到这个区块里然后尝试各种的nonce(随机数)值,回想之前的写过的
H(block header)≤ targert 这个block header里有个域是个随机数nonce,组装好后就开始试各种各样的nonce,这是一个4bytes看哪一个能满足这个不等式的要求,求出来的哈希落在指定范围如果某个节点找到了符合节点的nonce就说它获得了记账权,这个记账权就是往这个比特币去中心化的账本里写上下一个区块的权利,只有找到这个nonce的节点才具备发布下一个区块的权利,其它的节点收到这个区块后要验证一下这个区块的合法性比如说先验证一下这个block header的内容填的对不对像这个block header里有一个nBits域这个实际上是目标预值的一个编码检查一下这个nBits域是否符合难度要求然后再查一下这个nonce选出的nonce是不是这个block header的哈希是不是≤目标预值,换句话说你发布一个区块是不是真的有权利发布这个区块就把block header的哪几项都查一遍假设都符合要求,然后看看block body里面的交易列表验证一下每个交易都是合法的第一合法的签名,第二以前没被花过如果有任何一个出了问题那么这个区块是不能够被接收的要舍弃掉的,假设有个区块查过后都是符合要求的但是我们还是不愿意去接收它,有这种可能吗。
如下图所示:
一个节点是有恶意的,那个节点就是不接收这也是有可能的。
假设有一个获得记账权的节点发布了这个绿色的区块,而这个绿色的区块一切都是合法的我们应不应该接收它,它是插在中间的,插在这里有什么问题吗?在这个交易之前A把钱转给了B但是这个绿色的区块这里A把钱转给了自己,这个交易是合法的,你可能会觉得A转了B为什么还给自己转了这不是双花攻击吗?判断一个交易是不是双花攻击是看这个区块所在的分支,在这个分支上这个币有没有被花过两次这个绿色的分支并不是从一开始就有的,比如说A转给B 币的来源是第二个区块里的C转给A所以说验证这个就是当前交易到币的来源之间有没有被花过中间的区块是没有花过所以这个交易是合法的。但是这个感觉上是不能接受的,这个绿色的区块实际上是把上面的那个转账交易给回滚了,虽然说这个交易是合法的但是这个不在最长合法链上(logest valid chai)上面这个才是最长合法链,下面这个就等于它的分支,这就是说明比特币协议中接受的区块,应该是扩展最长合法链,应该是接在后面才是合法的区块,这个例子其实是一个分叉攻击的例子(forking attack)
通过往区块链中间位置插入一个区块,来回滚某个已经发生了的交易。区块链在正常情况下也可能出现分叉
就是如果有两个节点同时获得记账权,这节点都在本地组装一个区块然后去试各种各样的nonce如果两个接点在差不多的同一时间找到了同样符合要求的nonce它们就都可以把区块发布出去了,这时会出现两个等长的分叉如上图所示,如果按照最长合法链的原则的话这两个都是最长和法链该接受那个呢?
比特币协议中缺省情况下每个节点是接受它最早接受到的节点的所以不同节点根据在网络中的位置不同所以收到的区块也就不同,有些节点可能先收到上面那个有些可能会先收到下面那个,那么什么叫做接收一个区块
怎么区分它是接收还是不接收?比特币协议当中用的叫做本地上链,如果它沿着你这个区块往下扩展就算是认可了你这个发布了比如说收到上面的那个区块后又往下延伸了一个区块就说明认可了一个区块,反之就是不认可这个区块,如果出现系统中两个旷工两个节点差不多同时发布区块的情况像这种等长的临时性的分叉会维持一段时间,知道其中有某一个分叉是胜出的,那个没胜出的就被丢弃掉了。
出现这种情况的时候又是怎么分出谁赢谁输呢?
这种情况就看双方的算力谁的强谁的运气好来决定了,不一定是算力强的会胜出,也不一定是算力弱的会失败。
还有就是为什么大家会来竞争记账权,这个记账权有什么好处呢?
首先获得记账权的节点本身就有一定的权利,可以决定哪些交易被写到下一个区块里,但是这个不应该成为争夺记账权的主要动力,如果是已这个为动力的话就有点问题了,因为我们是希望凡是合法的交易都应该写到区块链里,比特币里设计了一个很巧妙的机制来解决这个问题,这个叫出块奖励(block reward)比特币协议里规定获得记账权的那个节点在发布的区块里可以有一个特殊的交易就是之前的铸币交易,在这个交易里可以发布一定数量的比特币这上面都是在说怎么验证交易的合法性现在回过头来说第一个问题谁来决定发行货币,这个铸币交易,是比特币系统中发行新的比特币的唯一方法,其它的都只不过是把已有的比特币转移到另一个账户
包括有的时候我们用美元来购买比特币这样也是没有产生新的比特币,这也只不过是互换,只有铸币交易是唯一一个产生新的比特币的途径,这个交易不用指明币的来源,因为这个币是凭空造出来的,那么可以造都少币呢?一开始比特币刚上线的时候每一个发布的区块可以产生50个比特币,但是协议规定21万个后奖励就要减半就成了25个再过21万个就又要减半12.5个比特币以此类推看上去减的很快而且现在的竞争比以前要厉害很多了但是想想一开始的时候没什么人去搞这个就像房价一样开始不怎么值钱但是物以稀为贵嘛,后面比特币的身价就开始一路暴涨了,这就是为什么有很多节点要争夺这个记账权的原因了。那么那个失败的区块的出块奖励就没了。
一个问题比特币要取得的共识是什么?
前面举了一个例子是分布式哈希表,那个例子当中要取得共识是这个表里的内容包含哪些键值对,那比特币中要取得的共识是什么,这个去中心化账本里的内容,那么谁能决定这个账本的内容?只有获得记账权的节点才可以往里面写东西,怎么获得记账权呢?就是写这个H(block header)≤ targert所以为什么会说比特币的共识机制是靠算力来投票的是因为这个性质puzzle friendly可以保证了求解的过程没有捷径只能一个一个nonce去试,所有某一个节点它的算力是某一个节点的十倍那么它获得记账权的概率也是那个节点的十倍,靠算力来投票,它是看你每秒有都少个nonce来投票,hash rate(算力)这个决定了投票的权重。
你可能会想到sybil attack(女巫攻击)直接投票的话不行会有sybil attack(女巫攻击),但其实不然因为他是靠算力投的你创建都少个账户都是没有影响的这并不会使你的hash rate(算力)怎么样,并不会使你每秒钟尝试的nonce怎么样所以投票的权重并没有改变。
一种说法比特币争夺记账权又叫做挖矿(mining)这个是一个比较形象的说法,因为比特币有人把它叫做数字黄金所以求解一个合法的nonce就像淘金一样,所以争夺记账权的节点就叫做矿工如果说他获得了记账权我们就说他挖到矿了或者说他挖到区块了,区块链中的每个区块你可以理解成是挖出来的。因为这就跟以前淘金热那时候一样都是在一个很大的空间里找一个很小的东西都很不容易。