This file is licensed under the MIT License (MIT) available on http://opensource.org/licenses/MIT.
区块链
区块链为比特比提供了一个公共账本,按照顺序和时间戳记录了交易。该系统可以防止双花交易和更改历史交易。
比特币网络中的每个全节点独立存储的区块链中,只包含该节点已经验证过的区块。当几个节点在它们的区块链中都包含了同一个区块,此时认为它们达成一致。节点之间为了保证一致性所遵循的验证规则别称为一致性规则。本节将讨论比特币核心使用多种一致性规则。
区块链概览
上图示意了一个简单版本的区块链。区块中包含的多个交易放置在区块的数据区,交易经过hash后组成pair,再进行hash,再组成pair,再进行hash,知道只剩下最后一个hash值,該值称为Merkle树的merkle根。
Merkle根保存在区块的头部中,每个区块头部还包含前一个区块的hash,这样就将区块链接起来(前向链表)。这样可以保证在不修改后续节点的情况下无法修改当前节点的内容。
交易也是被链接在一起。比特币钱包给人的印象是比特币从一个钱包到另一个钱包,但是实际上比特币是从一个交易到另一个交易。每个交易花费之前接收到的一个或多个交易的币,因此一个交易的输入是之前另一个交易的输出。
在将交易结果分送多个地址的情形下,一个交易可以产生多个输出,但是一个指定的交易输出只能在整条链中作为输入一次。后续任何的引用都会由于禁止双花导致失败。
输出和交易标志符(Transaction Identifiers,TXIDs)绑定,它是交易的签名。
由于每个输出只能被花费一次,因此区块链中所有的输出可以分为两类:未花费的输出(Unspent Transaction Outputs, UTXOS) 和已花费的输出。一个有效的交易,必须使用UTXOs作为输入。
除了基础币交易外,如果交易的输出值大于交易的输入值,这个交易会被拒绝;但是,如果交易的输入值大于交易的输出值,二者的差值则作为交易费用被挖出包含该交易区块的矿工占有。距离来说,上图显示的每个交易的输出都比输入少10000聪,缺少的部分就是作为交易费用的部分。
工作量证明POW(Proof Of Work)
区块链灾在网络上被匿名节点协作保存,因此比特币要求每个区块都投入一定工作量才能生成,以此来保证想要更新历史区块的不可靠节点需要比诚实节点付出更多的努力才能更新历史区块(不可靠节点更新历史区块的同时,诚实节点也在新增区块,二者是追赶的关系)。
链在一起的区块可以保证,如果不更新指定区块的所有后续区块,则无法更新该区块中的交易。因此,更新一个特定区块的代价随着新区块的增加而增加,同时放大了工作量证明的作用。
工作量证明机制利用了密码学hash结果明显的随机特性。一个好的hash算法将任意的数据转换成看起来随机的数字。如果输入数据的发生任何的变动,hash过程重新执行,一个新的随机数就会产生,因此无法通过更新输入数据有目的的预测hash结果。
为了证明节点为了生成区块做了一定的工作,节点必须产生出一个hash结果不超出指定值的区块头部。比如,如果最大的可能的hash值的个数为2^256-1,可以证明节点平均尝试2次就可以产生一个hash值小于2^255的头部。
在上面的例子中,节点几乎每个一次就可以成功一次。同时可以根据指定的目标门限,估计一次hash尝试成功的概率。比特币假定门限和成功概率是线性关系,门限越低,平均需要的尝试次数越多。
只有当区块的hash值满足一致性协议指定的难度值时,该区块才会被加入到区块链中。每隔2016个区块,网络利用存储在每个区块头中的时间戳计算产生这2016各区块的时间间隔。该间隔的理想值为120960S(两周)。
- 如果实际的间隔小于2周,则期望的难度值会按比例上升(最高300%),由此下一批2016个区块按相同速率产生,则刚好花费2周的时间。
- 如果实际的间隔大于2周,期望的难度值则会按比例下降(最低到75%)。
(注意:比特比核心实现时的一个1偏移错误导致需要使用2015个区块的时间戳代表2016个区块,引入一定偏差)
由于每个hash头都要满足指定的难度值,而且每个区块都会链接它前面的区块,因此更新一个区块平均来讲需要付出从该区块创造到当前时刻区块链整体算力的总和。因此只有你获得了了网络的大部分算力,才能够可靠的进行51%攻击修改交易历史(但是,需要直出的是,即使少于50%d 算力,仍然有很大可能性进行这种攻击)。
区块头部中提供了几个容易更新的字段,比如专门的nonce字段,因此获取新的hash值并不一定要等待新的交易。同时,只需要对80字节的区块头进行hash,因此在区块中包含大量的交易不会降低hash的效率,增加新的交易只需要重算Mercle树。
块高度和分叉
所有成功挖到新块的矿工都可以把他们的新块添加到区块链中(假定这些区块都是有效的)。这些区块通过它们的区块高度进行定位(区块高度是指当前区块到创世区块的之间的区块个数)。例如,2016是第一个进行难度调整的区块。
由于多个矿工可能几乎同时挖到新区块,因此可能存在多个区块拥有相同区块高度。这种情况下就在区块链中产生了明显的分叉,如上图所示。
当几个矿工同时生产出区块,每个节点独立的判断选择接受哪个,在没有其他考虑的情况下,节点通常选择接受他们看到的第一个区块。最终,一个矿工生产出来了一个区块,它附在了几条并行区块分叉中的一条,这时这条区块就比其他区块更有优势。假设一个分叉只包含有效的区块,正常的节点通常会跟随难度最大的区块继续工作,抛弃其他分叉上的孤儿区块。
如果不同的矿工为了不同的目的工作,长期的分叉也是可能。比如一些矿工在勤奋地延长区块,另一些却在进行51%攻击来修改交易历史。
由于可能存在多个分叉,因此区块高度不能作为区块的唯一标识,通常使用头部的hash值(通常进行字节顺序反转,并用16进制表示)。
交易数据
每个区块中必须包含一笔到多笔交易。这些交易中的第一笔都是币基础交易,或被称为生成交易,负责搜集和支付区块奖励(包括块补贴和包含在该块中的交易的手续费)。
生成交易的比特比作为未花费输出需要有特殊的条件:在100各区块以后才可以。这在一定程度上可以阻止矿工花费了该输出但是后续由于该区块所在分叉失效,导致该生成交易无效的情况。
区块当中并不强制要求一定有非生成交易,但是矿工为了获取交易手续费通常会包含额外的交易。
包含生成交易在内的所有交易,都被编码为二进制原始交易格式包含在区块中。
二进制原始交易格式通过hash产生一个交易标志TXIS,Merkle树算法把这些交易组成一对对,然后把他们hash在一起,如果这里有奇数各txid,没有txid的交易将会和自己的复制镜像配对;hash的结果之间继续进行配对hash,单独的结果还是和自己配对,这样依次递归,知道剩下唯一的hash结果,Merkle根。
一个包含5个交易的Merkle树生成过程如下:
ABCDEEEE .......Merkle root
/ \
ABCD EEEE
/ \ /
AB CD EE .......E is paired with itself
/ \ / \ /
A B C D E .........Transactions
正如在简化支付验证一节讲到的,Merkle树允许客户端通过向相邻完全节点请求区块头部的merkle根和一系列的中间hash结果来自己验证交易是否包含在指定区块中。相邻完全节点不一定必须是可信任节点,因为伪造节点头部和中间的哈希值代价巨大。
举例来说,如上图所示,为了验证交易D在区块中,SPV端只需要交易C的内容,以及hash值AB、EEEE和Merkle根,此外再不需要知道其他交易的任何内容。如果区块中的这5个交易都达到限定的最大值,那么下载该区块需要超过5000,000字节,而下载3各hash值和一个头部仅需要140字节。
注意:如果在区块中发现两个相同的交易ID,存在一种情况是Merkle树可能可能会和一个去除了了全部重复的区块发生碰撞,这是由于merkle树对不平衡(奇数)叶节点的复制处理。因此,把交易ID不同的交易放在同个区块中是实际可行的方案,这并不会增加诚实节点的负担,但是需要在节点缓存时进行检查。否则一个去除重复的有效节点可能和另一个节点有相同的merkle树和块hash值,但是因缓存的无效交易被拒绝,导致安全问题。
一致性规则的改变
为了保持一致性,所有的劝解点使用相同的一致性规则确认区块的有效性。但是,有时在引入新特性或防止网络滥用时会导致一致性规则的变化。当新的规则实施时,存在一个遵守新旧规则的节点同事存在的时期,此时有两种打破一致性的可能:
- 一个符合新规则的区块被新的节点接受,但是不能被老的节点接受。比如,区块中使用了新的交易特性,升级的节点理解该特性,并接受它,但是老的节点按照旧规则判断一致性失败拒绝该区块。
- 一个违反新规则的区块被新节点拒绝,但是会被老的节点接受。比如,一个滥用交易的特性在就区块中,该区块被新节点拒绝,但是被老节点接受。
在第一种情况下,被未升级节点拒绝,从旧节点接受数据的挖矿软件拒绝和从新节点接收数据的挖矿软件工作在相同的区块链。这会产生永久的分歧链,一个针对未升级的节点,一个针对已升级的节点,这被称为硬分叉
在第二种情况下,新节点拒绝旧区块的情况,如果新节点可以公职更多的算力是可以防止区块链发生硬分叉的。在这种情况下,未升级节点将会和新节点一样认为新节点的区块有效,因此新节点将会产生更强算力的链,此时旧节点也会接受最有效的长链。这被称为软分叉。
- 增强限制:旧客户端可以为新规则服务,新客户端只为新规则服务,因此新规则的服务能力大于旧规则服务能力,最终切- 换到新规则,导致暂时的分叉,称为软分叉。
- 减弱限制:旧客户端只为旧规则服务,新客户端可以为新规则和旧规则服务,因此旧规则的能力大于新规则的能力,形成永久的分叉,称为硬分叉。
尽管分叉表示对区块链实际的分裂,但是对一致性规则的改变通常还是会用潜在产生硬分叉或软分叉进行描述。比如“增加区块大小超过1MB需要一次硬分叉”,该例中,并不是真正需要一次区块链的分叉,只是可能而已。
一致性规则的改变可能通过多种方式引起。在比特比出现的前两年,中本聪通过释放后向兼容的版本改变强制立即使用新规则,进行过多次的软分叉。许多像BIP30这样的软分叉是通过在代码中预先编码指定的一个固定时间或区块高度实现的。这种通过指定固定日期进行分叉的方式称为用户发起软分叉(User Activated Soft Forks, UASF),它依靠大量的用户节点强制在指定日期后使新规则生效。
后续的软分叉会等待网络大部分算力(75%或95%)认可使用新的一致性规则。一旦超过认可门限,所有的节点都会使用新的规则。这种依赖矿工进行分叉的方式称为矿工发起软分叉(Miner Activated Soft Forks, MASF)。
检查分叉
未升级节点可能在两种分叉期间使用和发布错误的信息,存在多种情况可能导致经济损失。
- 未升级节点可能依赖和接受已经被新节点认为无效的区块,这些区块永远也不可能未来被接受区块链的一部分。
- 未升级节点也可能拒绝一些会被新节点添加的区块和交易,导致产生不完整的信息。
比特比核心包含检查区块分支的代码,通过查看区块链的工作量证明尽心判断。如果一个未升级节点收到的区块链头部表明该头部已经领先其认可有效的区块链头部6个块,节点就会通过getnetworkinfo
RPC函数结果发出一个警告,如果设定-alternotify
命令则还会调用该命令。这将警告操作者未升级节点不能升级到可能的最有效区块链。
全节点还能检查区块和交易的版本数字。如果最近收到的区块或交易的版本高于该节点使用的版本,它就会假定自己没有使用最新的一致性规则。比特比核心就会把这个情况通过getnetworkinfo
RPC函数结果发出一个警告,如果设定-alternotify
命令则还会调用该命令。
在另外一种情况下,如果区块和交易来自一个明显不使用最新协议的节点,那么其中的数据是不可依赖的。
SPV客户端通过连接到多个全节点可以探测可能的硬分叉,并且在排除掉传输延迟和无效区块后,可以判断他们是否在同一条链的相同高度。如果发生不一致,客户端将会从区块链较弱的节点断开。
SPV客户端还需要监控区块和交易的版本号变化,保证他们接受交易和创建新交易都是使用最新的一致性规则。