BTC共识协议
编辑
数字货币的问题
如果央行通过发行一种数字货币,采用公私钥对进行签名,央行存储私钥,将公钥公布出去。用户可以通过公钥验证收到的数字货币的真伪。
但是这种会存在一种致命的问题:“双花”攻击(double spending attack),即一笔钱被花了两次甚至多次。用户在得到数字货币后,对文件进行复制,就等于又得到了一份数字货币。数字货币面临的主要挑战就是防止双花攻击。
如果央行对数字货币进行编号,每份数字货币上都有一个专门的编号,央行需要维护一张特别大的数据库表,用来记录哪个编号的货币在哪个人手里。交易的时候,不仅要验证货币的签名,还要从央行验证这个编号的货币是否确实在该人手里。交易后,央行要更新数据库表中拥有该编号的人的信息。这样就可以用来防范双花攻击。
该方案的问题:是一个中心化的方案,每次交易都要通过央行确认。
去中心化数字货币
数字货币的发行权问题:没有了央行,谁来发行货币?什么时候发行?发行多少?
在比特系统中,由挖矿决定。
如何防范双花攻击:
维护一个数据结构,用来检测这个币有没有被花过、被谁花过。只是这个数据结构不由央行维护,而是有每一个用户共同维护。
这个数据结构就是区块链。
比特币交易流程:(红色线条表示转出,绿色线表示比特币的来源)
其中:
● A通过铸币交易凭空得到10个比特币,写入区块链中
● A给B、C每人转5个比特币,这个交易需要有A的签名(A用自己的私钥来进行签名,其他节点可以通过A的公钥来验证)。同时这个交易会包含输入部分和输出部分:需要记录A的比特币的来源和A的公钥(输入部分)、收款人的公钥的哈希(输出部分)。
● 输入部分、输出部分其实就是一段脚本,称为 BitCoin Script
● 。。。。。
这里存在2种哈希指针:
● 将区块链链表连接起来的哈希指针
● 说明币的来源的哈希指针
记录币的来源,可以证明这个币不是捏造的,同时也可以防范双花攻击。
比特币系统中,没有提供查询某个人对应的比特币地址的功能。与银行转账类似,银行转账时需要先通过其他方式获得要交易对手的银行卡账号才可以转账,而银行不提供查询他人银行账号的功能,比特币转账时也需要先通过其他渠道得知对方的比特币地址才可以转账。
A给B转账,除了A要知道B的公钥来进行转账外,其他所有电脑节点还需要知道A的公钥。因为A给B转账这个交易会需要加上A的签名,其他每个节点都需要通过A的公钥来验证这个签名的有效性,因为可能存在恶意节点,所以不能依赖其他节点的验证结果,每个节点都必须独立验证,即使这个节点本身不是交易的双方,也需要获取A的公钥进行验证该笔交易。
其他节点如何获取A的公钥?在A给B转账时,在交易的输入部分会直接给出A的公钥。用以让其他节点来验证A的签名的有效性。
既然A的公钥是在输入脚本中直接给出的,如何证明交易的输入给出的是A的公钥和签名而不是其他人的公钥和签名?在前一个提供币的来源的交易(即图中的铸币交易)中,交易的输出部分会给出交易对手(即A)的公钥的哈希。A给B转账时,交易的输入部分给出的A的公钥需要和前面币来源交易输出部分的A的公钥哈希能匹配上。
区块的内容
一个区块中,会有很多类似上面的交易,这些交易组成一个merkle tree存储在这个区块中。
一个区块分为:block header 和 block body。
block header记录的是这个区块的宏观内容,例如使用的比特币协议的版本号(version)、区块链中指向前一个区块的指针(hash of previous block header)、整棵 merkle tree的根哈希(merkle root hash)、挖矿的难度目标阈值(target)、挖矿的随机数(nonce)。
target中存储的就是目标阈值的编码(nBit),挖矿寻找一个随机数nonce,最终使得拼出来的整个区块头的哈希满足: Hash(block \space header) \le target
block body中记录的有交易列表(transaction list)。
系统中并不是所有节点都要验证每次交易。
全节点(full node)保存区块链的所有信息,验证每个交易。所以也称为 fully validating node。
轻节点(light node)也叫 light weight node。一般情况下,轻节点无法独立验证交易的合法性。
系统中大部分的都是轻节点。只有全节点才会验证每次交易。
分布式共识
分布式共识(distributed consensus)。比特币是“去中心化”的,没有中心节点,系统内的每个节点都在本地维护的有一个账本(distributed hash table),需要保证每个节点维护的链上的交易不会冲突。
一个简单的分布式共识是一个哈希表,系统内有很多机器,共同维护一个全局的哈希表。
分布式共识有很多论文,也有很多“不可能”结论,最出名的是FLP impossibility result:系统中是异步的(asynchronous),且通信时延没有上限,只要有一台机器出错(faulty),就不可能达成共识。
分布式系统的CAP Theorem:C指的Consistency(强一致性),A指的Availability(可用性),P指的Partition tolerance(分区容错性)。任何一个分布式系统,这三个性质中最多可以同时满足两个,不可能同时满足。
分布式共识的一个著名的协议 Paxos:该协议能保证Consistency,所有成员的共识是一致的,不会出现不一样。但是某些情况下,该协议可能一直没有办法达成共识,虽然该情况出现的概率比较小,但是客观存在。
参考:https://cloud.tencent.com/developer/article/1702057 我还没看
比特币中的共识协议,需要解决有些节点是恶意的问题。
简单的投票机制可行么?
如果我们假设系统内大多数节点都是好的,只有少量恶意的。可以采用投票机制:某个节点提出一个候选区块,根据收到的交易信息,筛选出合法交易,按照某个顺序打包成一个区块中,然后把这个候选区块发布给所有节点。每个节点收到候选区块后检查该区块内的交易是否都是合法的,如果都是合法的则投赞成票,如果含有非法交易则投反对票。最后统计如果超半数的节点投赞成,则该区块正式接受写入区块链中。
该机制可能会存在的一些问题:
● DOS攻击:恶意节点一直发送包含有恶意交易的候选区块来进行投票,导致系统无法正常工作。需要解决哪些节点才能提出候选区块问题。
● 行政不作为:如果系统内有超半数的节点因为某些原因一直不投票,则最后统计的票数永远不能超半数,则导致系统瘫痪。
● 效率问题:节点间的网络延迟、每轮投票要等待多久。
该机制还有一个更大的问题:任何投票机制都要首先确定谁有投票权,要有 membership。
如果一个区块链的membership是有严格定义的,不是随便一个节点都可以加入(例如联盟链hyperledger,只有符合某些条件的大公司才能加入)。这种情况下,投票机制是可行的。
但是比特币系统中不是这样的,比特币的账户只需要在本地创建公私钥对即可,不需要别人批准,甚至别人都不知道这个账户的存在,除非转账等交易时别人才知道该账户的存在。这种情况下,如果有一台超级计算机专一用来产生公私钥对账户,当其产生的账户数超过了区块链中所有节点数的一半,那么就拥有了投票的控制权。这种攻击方式称为“女巫攻击”(Sybil attack)。
所以,简单的直接投票机制对于比特币系统是不适用的。
比特币中的投票机制
比特币中的投票不是按照节点数目来投票,而是按照计算力来投票。
每个节点都可以在本地组装一个候选区块,把它认为合法的交易组装到该区块中。然后开始尝试各种 nonce 值,使得拼出来的区块头满足Hash(block \space header) \le target。nonce的长度为 4 byte,如果哪个节点找到了符合要求的nonce,它就获得了记账权(向比特币账本里写入下一个区块的权利)。只有获得了记账权的节点才有权利发布下一个区块。
其他节点收到这个区块后,要验证这个区块的合法性。比如会验证这个区块的区块头中的nBits域(该域其实就是target的编码),需要验证nBits域设置的是否符合比特币的难度要求,检查选出的nonce是否满足整个 block header的哈希小于等于target目标阈值。然后检查 block body中每个交易都是合法的,要有合法的签名,没有双花情况。
即使该区块的所有交易合法,其他节点也不一定要接受该区块,还需要满足扩展最长合法链等。
最长合法链
当一个拥有记账权的节点,发布了一个区块,区块内部的交易也是合法的,但是该区块没有接到前面区块链后面,而是另起了一个分支,就会出现一些其他情况。
如图所示,新产生的区块6,其block header中记录的前一个区块哈希指针指向区块3,那么它就接入到了区块3后面。
不同分支的区块链不会查询其他分支的交易。如图区块4中有一笔交易 A转账给B,对于区块6来说,这笔交易相当于被“回滚”了,区块6只记录了A转账给D的交易。
区块6不在最长合法链(longest valid chain)上,只是一个分支。
比特币协议中规定,接受的区块应该是在扩展最长合法链,所以只有连到区块5的后面的才是合法的区块。
图中这种情况称为分叉攻击(forking attack),通过往区块链中间插入区块,来回滚已经发生了的交易。
等长分叉
除了分叉攻击外,区块链在正常情况下也会出现分叉。
如果有两个节点在本地组装交易,同时找到了nonce拥有了记账权,每个节点在区块链中写入一个区块,就会在区块链末尾出现两个分叉的区块,因为这两个区块等长,无法用最长合法链判断。
对于这种情况,比特币协议中,每个节点缺省会接受自己最早收到的那个。因为在网络中位置不同,离节点A近的节点接受了区块4,离节点B近的节点接受了区块5。
如何表示节点接受了哪个区块?在比特币中,以接着这个区块向后扩展表示接受了这个区块。比如节点C接着节点A的区块4向后扩展了新的区块,就表明节点C认可了区块4.
所以,在比特币中,如果两个矿工几乎同时发布了区块,那么这俩区块的分叉会维持一段时间,最后随着其中一个区块的向后扩展,会在这个分叉中胜出。例如上图中的区块4、区块5的分叉会维持一段时间,当节点C组装了新的区块接到了区块4后面,那么区块4所在的分叉就成了最长合法链,下面的区块5就成了orphan block 被丢弃。
竞争记账权
为什么节点要抢记账权?
首先,拥有记账权的节点,就等于拥有了筛选写入哪些交易的权力,它可以决定往区块中写入哪些交易。但是,在设计这个协议时,不应该让筛选写入的交易称为争夺记账权的主要动力。我们希望的是所有合法的交易都应该能够被写入区块链中。
比特币中设计了“出块奖励”(block reword):比特币中规定,拥有记账权的节点,在发布区块时,可以写入一个特殊的交易——铸币交易(coinbase transaction)。在这个交易中,可以发行一定数量的比特币。铸币交易是比特币系统中出现新的比特币的唯一方法,该交易不用指定币的来源,是凭空造出来的,其他交易都只是从一个账户到另一个账户的转账。
铸币交易可以造多少币?
比特币系统刚上线时,每个发布的区块的可以产生50 BTC,也就是“出块奖励”。但是协议中规定,在达到21万个区块以后,这个奖励要减半到25 BTC。再过21万个区块,再减半到12.5 BTC。依次类推,每达到21万个区块,就再减半, 6.25 BTC、3.125 BTC..直到最终产出为0。
虽然有“出块奖励”,但是如果拥有记账权的节点比较自私,它可能会只打包自己的交易,而不管其他人的交易(打包其他人的交易,还需要去验证交易的合法性,交易比较多时区块大还可能影响网络带宽等)。为避免这种情况,比特币系统设计了交易费(transaction fee)。这种交易费可以认为是一种小费,A给B转账,转出 1 BTC,B收到0.99 BTC,其中的 0.01 BTC 就作为交易费给了打包这个交易的记账权节点。
这个交易费很少,可以理解为一种小费,金额一般很小,例子中的0.01 BTC已经是很大的一笔交易费了。也有一些简单的交易没有交易费。目前“矿工”们“挖矿”主要还是为了争夺“出块奖励”。
比特币系统设计的整个系统平均每10分钟会产生一个区块,达到21万区块大约需要4年时间,即平均4年出块奖励会减少一半。可能若干年后,出块奖励特别小时,交易费就变成主要的了。
比特币被称为”数字黄金“(digital gold),这个争夺记账权的过程就称为 “挖矿”(mining),争夺记账权的节点被称为”矿工“(miner)。
比特币系统共识协议的本质
比特币系统要取得的共识是账本内容。
能决定账本内容的是取得记账权的节点,只有取得记账权的节点才能向账本里写入区块。
而获取记账权的方式,就是解puzzle找到 nonce,满足Hash(block \space header) \le target。而解这个puzzle,因为puzzle friendly性质,所以没有捷径,只能一个一个去尝试,需要靠算力。如果一个节点的算力是另一个节点的10倍,那它算出nonce的概率也是另一个节点的10倍,就更有机会获得记账权。
所以,比特币共识协议的本质,是靠算力来投票。不是看有多少个人或者多少台计算机,而是看每秒能算nonce的数量,这个称为 hash rate。hash rate决定了这个节点的权重,hash rate越高,越容易获取记账权,越容易出块。
- 1
- 0
-
赞助
支付宝
微信
-
分享