文章目录
[北大肖臻-区块链技术与应用笔记]第三节课——共识机制
一、数字货币
💵 假设权威机构——中央银行发行数字货币
数字货币与纸质货币
直接为货币的面额等信息,用央行的私钥签名,然后使用的时候,用户直接拿央行的公钥验证签名(假设大家都知道公钥)。
问题:虽然签名保证了没办法篡改其中的内容,但是这样的数字货币可复制,因为数字货币本质上还是一个文件——花两次攻击(double spending attack)。不像是纸质货币,花出去手上就没有。
解决双花攻击——中心化方法
仅仅有面额是不够的,每个数字货币还要有编号,先不考虑去中心化,央行还要维护一个数据库,即记录每个编号的数字货币是归哪个用户所有。
在支付时,不仅要用公钥验证签名是央行签署的,还要通过央行验证该货币是归自己所有,央行再将货币所有者改成支付给的那个用户。
不仅数字货币的发行是由央行统一控制,而且每次交易都要由央行确认其合法性,这种方案是一个中心化的方案。
去中心化
将央行的职能改成由广大的用户来共同承担,也就是去中心化的方案,这是BTC等数字货币系统要解决的问题,即:
1️⃣ 怎么决定数字货币的发行及发行量
2️⃣ 怎么验证交易的合法性,防止双花攻击
第一个问题在BTC系统中是挖矿决定的
第二个问题的解决,要维护一个数据结构,由所有用户来共同维护,这个数据结构也不再是关系表,而是区块链。
举例
假设用户A获得了铸币权(发行货币的权利),他发行了10个BTC。然后他将这10个BTC转给B和C,每个人分5个BTC。接下来B给C 2个货币,给D 3个货币。最后C将所得的7个货币全部给E。
BTC系统中每个交易都分为输入部分和输出部分,输入部分要给出这笔交易的BTC的来源以及付款方的公钥,输出部分要给出收款人的公钥的哈希值。比如A要转给B钱,就需要给出B的哈希。
这里涉及两种哈希指针,将各个区块串起来的哈希指针;另一种是为了说明币的来源是从哪个交易来的。
“说明币的来源”也就防止了双花攻击,如在下图中,B已经将自己的5个BTC花掉了,假设B尝试再花一次,将5个BTC转给F。这时顺着区块链去检查这个区块到来源交易之间的区块,发现B已经花了来源区块的BTC,说明这新个交易是不合法的,也就不会接受这个区块进入区块链。
BTC系统中的收款地址就是收款人的公钥取哈希再经过一些转换得到的。
BTC系统也没有提供查询某用户的公钥或账户地址的功能,要向某用户转账,就需要对方提供公钥或账户地址。这种情况收款方可以把公钥公布在网站上。
然而A向B转账,除了A需要知道B的地址,B也需要知道A的公钥。因为一方面A的公钥代表A的身份,B要知道转账的是谁,另一方面是为了验证BTC交易中A的签名(私钥签名公钥验证),也就是说所有结点都需要知道A的公钥才行,每个结点都需要独立验证,即使是一个和交易无关的旁观者也要验证这笔交易的合法性。
❓ 如何知道A的公钥
A的公钥是A自己写在这笔交易的输入部分里,即在交易中付款方自己宣称的。但这样是否会造成其他人可以伪造成A来发起交易?如B的同伙B’说自己是A,然后用自己的私钥签名,将自己的公钥说是A的公钥放在交易输入部分里,尝试将A账户上的BTC转走。
因为币的来源(图中铸币交易)中交易的输出部分有收款人A的公钥的哈希值,这时B’伪造的公钥的哈希就和A的公钥的哈希对不上了,所以可以防止这种攻击。
倘若B’直接使用A的公钥写上去,但因为没有A的私钥,这时签名就无法用A的公钥验证了,显然也是不行的。
我给你发送信息,用你的公钥加密,你收到信息以后用你自己的私钥解密
交易的输入部分和输出部分实际上都是脚本Bitcoin Script,A的公钥也是写在这笔交易的输入脚本里面。对公钥的验证过程,实际上就是把当前这笔交易的输入脚本,和币的来源的交易的输出脚本拼在一起,看看能不能顺利执行。
每个区块中可以有很多交易,这些交易就组成了上节课学习的Merkle Tree。
二、区块结构
注意全结点(fully validating node)是有块身的,需要验证所有交易的合法性;轻结点(light node)是没有块身的,没有办法独立验证交易的合法性。
轻结点没有参与区块链的构造和维护,只是利用了区块链中的部分信息。
系统中大部分结点是轻结点,全结点不是很多。
这节课主要是对全结点进行说明。
块头(block header)
块头里保存的是区块的宏观的信息。
1️⃣ version: 用的是BTC的哪个版本的协议
2️⃣ 指向前一个区块块头的哈希指针(注意!这里的哈希值只计算前一个区块的块头,块头保存的Merkle Tree的根哈希就已经可以保证区块中保存的所有交易没有被篡改了)
3️⃣ Merkle root hash: 整棵Merkle Tree的根哈希值
4️⃣ target: 挖矿的难度目标阈值target
5️⃣ nonce: 挖矿用的随机数nonce,要使得 H ( b l o c k h e a d e r ) ≤ t a r g e t H(blockheader)\le target H(blockheader)≤target
块身(block body)
交易列表
三、共识协议
每个账户都可以发布交易,区块链可以看做去中心化的账本,那么发布的交易应该写在哪个区块里呢?交易广播给每个区块,每个人都在自己本地的区块链上写入交易,如何保证写入后的一致性?也就是说账本的内容要取得分布式的共识(distributed consensus)。
分布式的共识的简单的例子:分布式的哈希表
此时需要取得共识的是哈希表中有哪些hash pair
分布式系统的不可能结论
FLP impossibility result
FLP impossibility result
讲的是在一个异步的系统(asynchronous system)中,网络传输的时延没有上限,即使只有一个成员是有问题(faulty)的,也不可能取得共识。
CAP Theorem
CAP是分布式系统想要的三个性质,Consistency一致性、Availability可用性、Partition tolerance分区容忍性。而CAP Theorem
是说任何一个分布式系统中,CAP三个性质最多只能满足其中两个,不可能三个全满足。
一致性(C):每次读取要么获得最近写入的数据,要么获得一个错误。
可用性(A):每次请求都能获得一个(非错误)响应,但不保证返回的是最新写入的数据(对应HA,机器故障时仍然能够提供服务)。
分区容错性(P):尽管任意数量的消息被节点间的网络丢失(或延迟),系统仍继续运行(网络分区/网络故障时仍然能够提供服务)。
分布式共识中一个比较著名的协议是Paxos
,这个协议能够保证一致性。即如果该协议达成了共识,这个共识一定是一致的(即不会出现系统中两个成员的共识不一致)。但是Paxos
协议是有一个较小的概率(虽然小但是客观存在),使得系统一直无法达成共识。
BTC中的共识机制
BTC系统中的共识要考虑到有些结点是有恶意的,假设系统中大部分结点是友好的,有恶意的结点占少数。
共识
在普通的分布式系统中,如分布式哈希表里,取得的共识就是哈希表中的内容。BTC系统中,共识协议取得的共识是去中心化的账本里的交易。
只有获得记账权的结点可以往区块里写交易,而获得记账权的途径就是解那个不等式puzzle,根据第一节课学习的哈希函数puzzle friendly的性质,求解这个puzzle的过程没有捷径,只能一个一个nonce去尝试,所以可以作为工作量的证明,算力越强得到出块奖励的概率也就越大,所以才说BTC系统中是靠算力来投票的。
直接投票方式——按照账户数
一种思路是用投票的方式,将所有交易写入一个候选区块,然后发给所有结点,大家验证这个区块中的交易是不是都是合法的,然后投赞成和反对票,按一定投票比通过后将候选区块写入区块链中。
❓ 问题:membership问题,任何基于投票的系统都要考虑谁有投票权,例如hyperledger fabric就是一个联盟链的协议,规定了谁可以参加(只有一些有实力的大公司可以参与)。
因为BTC系统中要产生账户只要在本地生成公私钥对就可以了,所以如果用这种方式,那么有恶意的人就可以进行女巫攻击(sybil attack),只要不断产生账户,然后获取大量的投票权就能控制整个区块链了。
计算力投票
每个结点都可以在本地组装出一个候选区块,把它认为合法的区块放在这个区块里,然后就开始尝试各种nonce值(4 byte),使得
H
(
b
l
o
c
k
h
e
a
d
e
r
)
≤
t
a
r
g
e
t
H(blockheader)\le target
H(blockheader)≤target。如果某个结点找到了符合要求的nonce,也就**获得了记账权——往BTC去中心化的账本(区块链)里写入下一个区块的权力
**,其它结点收到这个区块之后,要验证这个区块的合法性
如检查target的编码nBits域设置的是不是符合BTC协议规定的难度要求、检查带nonce的块头哈希值是不是小于target、检查块身中的每个交易是否都有合法的签名、检查每个交易都没有双花等
候选区块合法了就要去接收吗?
根据前一个区块指针就知道应该插入到哪个位置
如上图,C转账给A,A又将这些BTC转给B,然后A又发起了一次交易把BTC转给自己,这个交易的候选区块在下面,它希望挂在如图的位置上(分支上)。这里其实A所做的相当于将A转给B这个交易回滚了,仅仅做双花的检查会发现这两个分支都是没问题的,但如果接收了,那么在这个分支上A又获得了转给B的那些BTC。
这是一个分叉攻击(forking attack) ,通过往区块链中间位置插入区块,来回滚某个已经发生了的交易。这样一个候选区块检测其内容是合法的,但不应当被接受。
如果两个结点同时获得记账权,此时都能插入候选区块,该接收哪个?
这种等长的,多条最长合法链(分支)的情况会维持一段时间,直到某个分支胜出。假如上面的先找到下一个区块,那么下面这个区块就成为了
orphan block
被丢弃掉。因为
orphan block
不在最长合法链里,所以里面的出块奖励的铸币交易也就无效了。
什么是接受一个区块?如果一个结点收到一个区块后,沿着这个区块继续往下扩展,那么就算该结点接受了这个区块。
因为投票是靠算力的,创建多少个账户都没有影响,创建很多账户并不会使每秒尝试的nonce数目增加。
BTC中的激励机制——出块奖励
让大家去竞争记账权的动力是什么?获得记账权的结点本身有一定的权力,如可以决定哪些交易被写入下一个区块中,但这不应当成为竞争记账权的主要动力,因为BTC系统设计来希望所有交易都能被公平写入账本。出块奖励机制解决了这个问题。
BTC协议中规定,获得记账权的结点,在发布的区块里可以有一个特殊的交易——铸币交易,在这个交易中可以发布一定数量的BTC,这是发行BTC(产生新的BTC)的唯一方法,不必指定币的来源。这也就解决了前面谈及的去中心化系统中的第一个问题——谁来发行BTC和发行多少BTC。
BTC刚出现时,出块奖励是50个BTC,BTC协议规定每21万个区块之后,出块奖励就要减半,也就变成25个BTC。如今的情况是每个区块中能产生12.5个BTC。
为什么形容取得记账权的过程为挖矿(mining)?
矿的数量有限,BTC总量有限。
挖矿的过程很难,挖到矿的回报很大,BTC取得记账权来获得出块奖励也是一样。
争夺记账权的结点称为矿工
参考资料
1、BitCoin and Cryptocurrency Technologies:A Comprehensive Introduction
2、以太坊白皮书、黄皮书、源代码
3、Solidity文档