谈谈区块链(22):深入理解软硬分叉
比特币社区正在讨论用软分叉(soft-fork)的方式升级隔离见证(SegWit),目前存在着很多争议,一方面是隔离见证本身存在的争议,另一方面是软分叉而引起的争议(一部分人认为该用硬分叉的方式升级隔离见证),到底谁是谁非,今天我们就从技术视角全面剖析一下它。
软硬分叉涉及到的问题是去中心的化的节点软件、协议、版本升级的问题。是一个非常重要且值得讨论的问题。
一开始,所有的节点运行同样的软件,遵循着同样的共识协议,维护着同样的一条链(blockchain)。这时,一部分节点升级到了新版本的软件,拥有了新的共识协议,这时会出现下面四种情况:
新节点认为老节点发出的区块/交易合法;
新节点认为老节点发出的区块/交易不合法;
老节点认为新节点发出的区块/交易合法(没察觉变化);
老节点认为新节点发出的区块/交易不合法(察觉出了变化);
注意:不合法会分为所有交易都不合法和部分交易不合法。这里为了简化模型,把有部分交易不合法的都归为交易不合法。
实际情况是上面4种情况的组合,除此以外,我们还要增加一个维度,就是新节点和老节点的算力比,又分为下面两种类型:
新节点算力>50%;
新节点算力<50%;
注意,我们目前在网站上看到的各种关于软硬分叉的资料,都是基于新节点算力>50%的情况下讨论的。这里我们也只讨论新节点算力>50%。要注意,另一种情况下,即新节点算力<50%,情况会完全不一样。
软分叉是一个后来才出现的词,之前并没有。我们首先来讲一下什么是硬分叉(hard-fork)。
什么是硬分叉?
硬分叉是指:当系统中出现了新版本的软件(或称协议),并且和前版本软件不能兼容,老节点无法接受新节点挖出的全部或部分区块(认为不合法),导致同时出现两条链。尽管新节点算力较大,比如99%的算力为新节点,1%的老节点依然会维护着不同的一条链,因为新节点产生的区块老节点实在是无法接受(尽管它知道网络上99%的节点都接受了),这称为硬分叉。
注意:以上情况基于新节点算力>50%。
当必须硬分叉时,我们需要要求所有节点同时升级软件,未升级的节点将不能正常工作。如果有较多老节点不愿意升级,他们将工作在另外一条完全不一样的链上(这就是我们的ETC)。
下面这幅图说明了硬分叉产生的原因:新的节点要求比老的节点要宽松很多。
什么是软分叉?
软分叉是指:当系统中出现了新版本的软件(或称协议),并且和前版本软件不能兼容,新节点无法接受老节点挖出的全部或部分区块(认为不合法)。因为新节点算力较大,老节点挖出的区块将没有机会得到认可,新老双方从始至终都工作在同一条链上,这称为软分叉。
注意:以上情况基于新节点算力>50%。
下面这幅图说明了软分叉产生的原因:新的节点要求比老的节点要严格很多。
软硬分叉的优缺点
从上面的定义可以看出软硬分叉有各自的优缺点,首先软分叉和硬分叉相比拥有下面的优点:
软分叉总是只有一条链,没有分成两条链的风险;
软分叉不要求所有节点同一时间升级,允许逐步升级,且并不影响软分叉过程中的系统稳定性和有效性;
但软分叉也有缺点:
软分叉的前提是老的节点总是能够接受新节点的区块,这就要求把系统设计成向前兼容(forward compatible);
软分叉总是建立在对老节点进行欺骗的基础上,它让老节点没有察觉实际上已经发生的变化,某种程度上违背了单点完整验证的原则;
向前兼容(forward compatible)
向前兼容是非常有意思的术语,它不同于我们通常说的软件设计中向后兼容(backward compatible)的方式。它要求对于新可能出现的区块形态、共识机制有个预先的判断,并在老的系统中留有余地或后门。当新的节点被部署时,老的节点能够接受新节点所产生的区块。
那么,比特币里是如何实现向前兼容的?
答案是:非标准交易(non-standard transaction)。
比特币中设定了如下规则:
将所有交易分类为:标准交易、非标准交易和非法(invalid)三种;
如果发现非法交易,一律拒绝,如果该非法交易在某个区块中,则拒绝整个区块;
在标准配置下,所有节点对非标准交易采取以下态度:
不转发
不接受
不打包
对于已经进入区块的非标准交易采取以下态度:
接受该区块;
对区块中的所有交易,包含该非标准交易按既有规则进行验证;
下面我们用两个例子说明比特币如何使用非标准交易进行软分叉升级。
1、P2SH软分叉升级
P2SH包含在BIP16中,通过软分叉进行升级比特币系统,让比特币在支持P2PKH基础上,再支持一种叫P2SH的标准交易类型。
在此之前,比特币已经支持如下的脚本:”OP_HASH160 [20-byte-hash-value] OP_EQUAL”。要花费这样的脚本你只需要把hash值的原数据(preimage)推到(push data)栈上即可。
P2SH是对以上条件的一种更严格限制,在P2SH模式(新节点)下,你不但需要提供该hash值的原数据,还要保证:
该原数据是一个可执行的脚本;
该脚本执行结果返回:true;
该脚本中不能含有”push data”的操作;
以及其它的一些限制;
当支持P2SH的新节点被部署时,新节点的算力>50%(P2SH升级时要求>=55%),系统将处于下面的运行状态中:
P2SH交易被转发到老节点时,会被老节点认定为非标准交易(有了新的,或不能理解的OP_CODE),老节点不接受、不打包、不转发;
当包含有P2SH交易的区块广播到老节点时,老节点接受区块,并按原有规则验证该P2SH交易,结果通过,因为老的规则只要验证原数据的hash是否相等(显然是相等的);
老的节点创建了一个原数据为:123456的脚本输出,并花费该输出。老节点们能够接受。但是广播到新节点时,按新规则(必须是脚本…)则不通过,新节点拒绝接受,认定为非法,不会打包该交易。即使该交易被老节点打包,也会被新节点拒绝。因为新节点控制多数算力,这样的交易将永远无法生效;
系统同时维护一条链。
P2SH的升级细节:
要求支持P2SH的矿工在其coinbase交易里包含“/P2SH/” 字样;
2012年2月1日检查之前1个星期内的所有区块(约1000个),如果超过550个包含(约55%)则激活P2SH。
2、SegWit软分叉升级
SegWit主要包含在BIP141-144中,通过软分叉进行升级比特币系统,让比特币支持一系列SegWit的功能集。关于隔离见证的具体内容详见《谈谈区块连(21):比特币之隔离见证》。
通过软分叉升级需要让老的节点认定新的交易为非标准交易,但同时是合法的。隔离见证是如何做到的呢?答案是:anyone-can-spend的输出交易。
anyone-can-spend:
下面是一个anyone-can-spend的例子:
scriptPubKey: (empty)
要花费这样的输出,你只需要提供这样的签名脚本:
scriptSig: OP_TRUE
隔离见证中将脚本版本(script versioning)和anyone-can-spend完美结合。一个标准的P2WPKH的输出如下:
scriptPubKey: 0 <20-byte-key-hash> (0x0014{20-byte-key-hash})
这开头的0在新节点中将是脚本的版本号,在老节点中是一个anyone-can-spend的输出。
当支持SegWit的新节点被部署时,新节点的算力>50%(SegWit升级时要求>=95%),系统将处于下面的运行状态中:
SegWit交易被转发到老节点时,会被老节点认定为非标准交易(anyone-can-spend),老节点不接受、不打包、不转发;
当包含有SegWit交易的区块广播到老节点时,老节点接受区块,并按原有规则验证该SegWit交易,结果通过(因为它是谁都可以花费的);
老的节点尝试花费SegWit交易,因为它是谁都可以花费的。老节点们能够接受。但是广播到新节点时,按新规则(隔离见证的验证规则)则不通过,新节点拒绝接受,认定为非法,不会打包该交易。即使该交易被老节点打包,也会被新节点拒绝。因为新节点控制多数算力,这样的交易将永远无法生效;
系统同时维护一条链。
SegWit的升级细节:
升级到core 0.13.1及以上的支持SegWit;
2017年11月如果95%算力支持,则激活SegWit。
1MB限制的问题:
超过1MB大小的区块,对于老节点来说不是非标准交易,而是非法交易。为了解决这一问题,SegWit将欺骗老节点的伎俩发挥到了极致。它将整个Witness的部分放在原来整个block的外面。对于老节点来说它并不知道它接收的整个block后面还有一个witness的结构。
结束语
去中心化的、分布式的系统升级将是未来的主要挑战之一。软硬分叉都将扮演重要角色。软分叉的方案更加的聪明,能有效防止区块链的分叉。但却依赖于软件的向前兼容、依赖于欺骗老节点、依赖于老系统里预留的手段或后门。
有时,为了实施软分叉,必须要将本可简单设计的功能设计得更加复杂,增加了bug的风险,得不偿失!
尽管如此,软分叉相比硬分叉还是具有巨大优势,允许缓和升级,降低社区分裂的分险!
至于SegWit是该软分叉还是硬分叉的争论,我相信你已经也有了自己的看法。欢迎微信公众号里回复作者交流观点!
声明:此文出于传递更多信息之目的,并不意味着赞同其观点或证实其描述。本网站所提供的信息,只供参考之用。
-
比特币VS黄金 谁能跑赢通胀?
2024-12-21 -
特朗普两年时间通过加密货币赚了多少钱?
2024-12-21 -
为什么说比特币储备法案或打破加密货币四年周期?
2024-12-21 -
特朗普政府的加密版图
2024-12-19 -
香港虚拟资产指数如何改变亚洲加密货币市场?
2024-12-18