区块链需要升级怎么办?
在区块链世界中,大家都知道升级现有的区块链很烦,比区块链中任何东西都难搞。
区块链本质上是一写即用:没有办法真正 “升级” 传统意义上的区块链,只能创建一个保留旧区块的新区块链。就好像把你已经死去的狗换成了同一品种的另一只狗,然后为了安抚孩子们,你开始叫它同一个名字。
只是在分叉时,原来的狗并没有死,而且我猜新的狗植入了原来狗所有的记忆。这只是个不恰当的比喻,不用太认真。无论如何,我觉得你应该明白了。没有升级,只有分叉。从区块链诞生起,这种模式就一直存在。
可能现在还有人的柜子里有一台旧电脑,从 2009 年开始就在运行比特币挖矿程序,所以传统意义上,比特币并没有升级。
假设你能找到那个柜子和一个适配的老客户端,你仍然可以连接到 2009 年的比特币(估计大部分交易来自倒卖盗版《X战警起源:金刚狼》的人)。
没有升级,只有分叉。从区块链诞生起,这种模式就一直存在。
升级区块链很难
一般来说,这是分布式系统的问题,但像比特币这样的去中心化系统的问题是,没有一个实体控制网络上的所有计算机。
你不能给每一个比特币矿工打电话,告诉他们必须升级。你可以给一些真正重要的比特币矿工打电话,但这是一个 bug,不是比特币网络的一个特性。
现在许多区块链处理这个问题的方法是提前升级客户端,升级后的客户端同时支持网络的两个版本和一个 if 语句,该语句在某个区块数切换到新的代码。以太坊就是使用这个方法在定期更新。
现在这个方法还不错,但它并不能真正解决每次你想改变时都要分叉的问题,它只是给你时间。再说,这是不文明的。当伦敦投票选举市长时,并不是按照政治路线分成伦敦和伦敦经典,而是选择让大多数人高兴(或者更准确地说,让大多数人较少反感)的市长。这种形式化的治理体系是减少区块链生态系统不确定性所需要的。
现在,如果不信任第三方为你提供定期、可信的更新,就不可能拥有像在物联网设备中找到的那样运行时间长的轻客户端。不过老实说,在现实世界里的大多数物联网制造商,都是能不更新就不更新。安全更新物联网设备是一个难题,但大多数制造商根本不在乎。如果物联网制造商在更新其软件的时候,能达到运行区块链节点所需的靠谱程度,那么 Mirai 就不会发生。
当然,解决这个问题的另一个办法是,永远不要尝试更新区块链。
这在很大程度上就是比特币的解决方案,虽然可以说比起长期运行的轻客户和治理,社区更关注的是让 10 家赚了点钱的矿工的 ASIC 投资作废。不过,为了达成这篇文章的标题里的主张,我们也将让 “用不更新” 这种方法作废,因为我觉得大多数人都会同意更新软件是一件好事,而且通常是一个很好的启发,让你去思考一个主题,这与喜欢比特币的人秉持的信念截然相反。
链上升级和其他难题
让客户端更新的一种方法是在链上部署整个客户端。你可以使用某种链上治理方法来选择是否接受该客户端,然后如果接受,那么世界上所有的客户端都可以安装新版本和通过 Linux 分叉,而不是区块链分叉。当然,你不能仅仅在区块链上部署二进制文件,首先,这基本上赋予了 government 在任何人的计算机上运行任意代码的能力。这不仅仅意味着他们可以在区块链上做任何他们喜欢做的事情,而且他们可以把你的电脑变成僵尸网络节点,他们可以在你的图片文件夹里放满 Danny DeVito 油画(说真的,这是一个库存惊人的艺术流派),甚至是挖比特币(但愿不会如此)。即使你完全信任链上治理,为每一个操作系统和每一个可用的架构部署二进制文件也是一个很大的组织管理问题。
假设我们在虚拟机中运行整个客户端。我们用 Java 或 Scala 编写它,在区块链上部署 Java 字节码,或者我们做一些类似于苹果公司做的事情,用 LLVM 支持的本地语言编译并部署 LLVM 位码。好吧,这是更好的,但是不管你使用的 VM 格式是什么,你都在很大程度上限制了你可以在其中构建客户端的语言。另外,你还在区块链上部署一个巨大的 blob,而在区块链里空间是很珍贵的(或者应该是很珍贵的,但实际上存储租金并没有得到广泛的实现)。这忽略了这样一个事实,即当你构建一个 LLVM 语言时,你会根据操作系统生成不同的位代码,苹果只能逍遥法外,因为他们的操作系统在不同的设备上,他们部署了兼容的 api。
最后,在链上部署整个客户端的任何策略最终都会遇到这样的问题:处理回滚会将整个事情变成一场滑稽的闹剧,因为回滚策略是由回滚的内容定义的。面对链上更新,定义分叉选择规则或回滚策略没有好的答案。
假设我们将定义区块链逻辑的代码从其余代码中分离出来,然后将其编译为 VM 字节码。我所说的 “区块链逻辑” 是指定义区块链逻辑的代码。
以太坊负责账户、余额和智能合约。ZCash 对交易进行零知识证明。比特币的基础计算效率极低。在一般情况下,是代码告诉我们如何根据交易更改状态。我们在网络、实现速度等方面仍然存在竞争,虽然这意味着我们不能用这种方法更新网络代码,但是在一个分布式网络中保持多个不同版本的节点比让这些节点在不断更新的可变状态上达成共识要好得多。我们可以使用像 libp2p 这样的可扩展网络协商协议,允许新节点使用新的通信协议,同时仍然允许旧节点参与。
为了避免前面提到的回滚问题,我们必须将逻辑分离到共识级别以下。这意味着我们只能更改将交易映射到状态更改的代码。这确实意味着我们不能改变分叉选择的规则、回滚策略或共识算法,但是我们必须在某个地方进行抽象权衡。共识算法不能改变,因为它可能会使区块无效,并且我们只能允许改变链上影响状态的东西。
区块链分叉是如何进行的?
设计波卡的升级接口
为了便于论证,并且因为你可能已经知道我在这里要引入一些东西,让我们将这个逻辑称为区块链的 “runtime”。
如果我们从头开始构建一个新的链,我们可以选择自己的共识算法等,我们希望使我们的代码尽可能通用。
因此,我们希望让 runtime 做出尽可能多的选择。
例如,如果我们选择像 Tendermint 或 PBFT 这样的 PoA 共识算法,那么我们可以同时拥有这两种算法,允许 runtime 选择权限。
这意味着,如果我们想改变在权限之间达成共识的方式,那么我们仍然只能硬分叉,但实际上,这一系统最终还是非常灵活。使用在链上选择权限的 PoA 系统,我们可以创建许可链(意味着只有某些方可以参与网络)和无许可链(意味着任何人都可以参与网络)。我们可以对任何一种策略使用任意数量的策略,但例如,我们可以通过对权益不同的质押者进行随机选择,来确定权限池(类似节点的意思),从而创建一个权益证明链。这解决了升级策略不确定的问题:升级不能追溯地更改前一个区块的权限集,只能更改未来权限集的选择方式。
runtime 还应该能够自己决定何时升级以及如何升级,因为我们可以使用链上治理来执行这些升级。由于治理也是在 runtime 中定义的,这意味着你可以对 runtime 进行编程,以限制允许治理更改的内容。也许不允许改变治理结构本身,但其他一切都是公平的游戏。也许它只允许调整一些小事情,但系统的基本规则必须保持不变。也许你可以改变任何事情,但不同的权力层次需要不同级别的票数。这完全取决于 runtime 的开发人员。
这是我们在 Parity Substrate 中采用的方法,Substrate 是我们在 Parity 基础上构建的区块链开发工具包。共识和网络由 Substrate 处理,链的逻辑、权限选择和自动升级由 runtime 处理。
是的,正如你现在可能已经收集到的,“runtime” 术语是从 Substrate 复制而来的。这也意味着你将影响共识的代码分离出来,你可以使用不同的后端。
例如,在 Polkadot 中,我们可以在 “验证人”、“提名人”、“收集人” 和 “钓鱼人” 之间共享 Polkadot 特定的代码。
即使节点扮演不同的角色,它们都可以就网络的状态达成一致,并相应地采取行动。
就网络而言,它们只在提交给网络的交易种类上有所不同。任何从外部世界获取数据的东西,无论是一个节点的错误行为报告、天气测量还是一个人向另一个人汇款,都被建模为一个交易,状态被更新为对此的响应。我们在 Polkadot 中使用的 Substrate 允许我们以一种民主的方式对网络进行更改,不再需要任何客户端,而且已经过测试:我们使用本文中解释的确切方法将 Polkadot PoC1 升级到 PoC2。
我们希望这种模式能够在区块链领域开创一个新的实验时代,但这由你来决定。
欢迎学习 Substrate:
https://substrate.dev/
关注 Substrate 进展:
https://github.com/paritytech/substrate
关注 Polkadot 进展:
https://github.com/paritytech/polkadot
PolkaWorld
微信号:PolkaWorld
波卡(Polkadot)第一中文社区,带你寻找 Web 3.0 时代新机遇!