区块链是一种分布式存储技术。一谈到分布式服务,就会提及CAP原则。
CAP原则是以下三个单词的首字母:
- Consistency(一致性):系统在执行某项操作后,仍然处于一致的状态。在分布式系统中,更新操作执行成功后,所有的用户都应该读取到最新的值,这样的系统被认为具有一致性。
- Availability(可用性):每一个操作总是能够在一定的时间内返回结果。这里需要注意的是“一定时间内”和“返回结果”,也就是说系统的结果必须在给定的时间内返回,若超时,则被认为是不可用的。
- Partition Tolerance(分区容错性):系统存在网络分区的情况下,仍然可以接受请求(即满足一致性和可用性)。网络分区指的是由于某种原因网络被分成若干个孤立的区域,而区域之间互不相通。分区容错性可理解为系统对结点动态加入和离开的处理能力,因为结点的加入和离开可认为是集群内部的网络分区。
它是分布式系统设计中的一个基本原则。这个原则指出,在一个分布式系统中,这三个要素最多只能同时满足两个,即不可能同时达到三者兼顾的状态。
一般情况下,在这三者之中,我们往往选择保留AP,即Availability(可用性)和Partition Tolerance(分区容错性),而战术性放弃Consistency(一致性)。
这是因为如果分布式服务不可用,那这个服务还有什么存在的意义?所以一定要保证Availability(可用性)。
Partition Tolerance(分区容错性)则在系统各节点之间网络出现问题时,单个分区还是可用的特性。如果不具备分区容错性,一个分区出现脑裂,则需要停止服务直到它同步完其他分区的数据。这个也是不能接受的。
但是Consistency(一致性)可以要求不是那么高,因为我们还有其他手段来补救。所以这儿谈的Consistency(一致性)我们可以称之为“强一致性”。在现实中,我们可以通过后续日志计算等方式,解决因为“弱一致性”导致的数据不同步的问题。
在区块链这样的分布式系统中,放弃的也是Consistency(一致性),即强一致性。这意味着,在区块链网络中,可能同时存在不同的链——它们还都是合法的。只是随着时间推移,这些链又会归于统一。但是又会在某个时间,再次分叉。
分叉
通过上面的分析,我们可以知道区块链分叉的原因主要是CAP原则。
我们可以将场景具体化,以方便大家理解分叉的原因。
转账发起方将转账记录发给验证节点后,验证节点会把它们发送给矿工节点。矿工节点将这些转账记录缓存起来,然后在其中挑选它认为有价值的转账记录(比如支付的手续费比较高的)打包到区块中。这意味着,不是每个矿工选择的转账记录都是一样的。进而可以推导出,不同矿工算出来的区块也是不一样的——虽然它们都是合法的。
矿工在暴力计算出区块后,会在全网广播,而由于网络距离或者抖动等问题,每个负责上链的节点收到的区块时间也会不同。
比如下图,甲矿工和乙矿工几乎同时算出来区块。
甲将区块最快速度发送给了上面的链,上面的链确认3这个区块合法,于是上链成功。后面收到的乙发来的区块,由于网络原因太晚了,就会被上面的链抛弃。
乙将区块最快速度发送给了下面的链,下面的链确认3’这个区块合法,于是上链成功。后面收到的甲发来的区块,由于网络原因太晚了,就会被下面的链抛弃。
甲乙相互发送各自最后一个区块给对方,发现它们区块高度相同(即区块的索引),则彼此什么都不做。
这样就慢慢演化成两条链。
最长链原则
通过上面的分析,我们可以知道理论上,区块链网络上可能同时存在多个高度一样的链,且它们都是合法的。但是这不是一种稳定态。为什么呢?
假如我们认为网络是稳定态,即某节点到某节点就是多长时间,那么是否意味着整个区块链就是稳定态?毕竟网络导致了分区。
但是我们忽视了一个重要问题,就是矿工计算区块的时间——它比网络时间要长很多。
在比特币中,矿工暴力计算出一个区块是分钟级别的长度,而网络通信是秒级别的。这样即使网络是稳态,那么它在整个区块产生和上链以及传播的过程中,占比是很低的。这就意味着,导致分区最重要的因素并不是网络通信的时差,而是区块产生的时间太过接近。
那么计算能力是否是稳态呢?是否牛X的计算能力一定会一直抢到区块上链的权力呢?计算能力当然是确定的,GPU什么配置,能产生多大的计算能力就是确定的。但是这并不意味着它一定每次都能抢到区块上链权。因为Hash算法是不可预测的,而且每个矿工可能选择的交易记录不一样,那么可能某个矿工运气特别好,它选择的记录组合花了很少的计算代价就暴力出来了合法的区块。
正因为每个矿工打包的交易记录不一样,而Hash算法存在不可预测性,这两个特性的叠加,导致区块链在生产过程中无法处于一种稳态。
如下图所示,一开始时可能比较多的区块链选择的是1 2 3’ 4’';而随着时间推移,大部分都统一到1 2 3 4 5 6 7这样的链。而后可能又出现分叉。
这就引出一个问题,假如有笔转账记录在3’中存在,而不存在于3 4 5 6 7 8。那么这笔转账记录是否生效?答案是它曾经生效过,但是它最终没生效。所以转账记录是否生效,不能只看它是否已经上链了,而是要看它上链多久的。越久的话,所包含它的区块被替换成其他区块的概率越低,越能说明它生效的概率大。在比特币中,一般认为“6次确认”,即包含它的区块后面还有5个区块在链上,才认为转账成功。