重构智能合约系列
《重构智能合约》系列是Antshares创始人的心血结晶,展示了他们在设计Antshares智能合约时积累的见解。该系列旨在提出一种新的智能合约设计,共分为三个部分,分别从确定性及资源控制、可扩展性与解耦、以及通用性与生态系统兼容性三个角度审视现有的智能合约系统。
自比特币、以太坊以及整个区块链技术诞生以来,“智能合约”一词频繁出现在金融和科技媒体中。该术语由密码学家Nick Szabo于1994年首次提出,与当代互联网概念一样古老。根据Szabo的定义,智能合约是一种计算机化的交易协议,用于执行合约的条款。传统上,合约的生命周期包括三个阶段:谈判、签署和执行,智能合约也是如此。然而,在区块链技术出现之前,单台计算机无法提供安全且可问责的签署和执行服务,因此智能合约一直停留在理论层面。
比特币引入了区块链技术,提供了多方记录、多方计算、规则集透明性和不可变性等特性。通过这些特性,创建了一个安全且可问责的记录载体和运行环境,使得智能合约的实践成为可能。
确定性与终止性
与传统的计算机程序不同,基于区块链的智能合约必须具备确定性和可终止性。区块链系统通过多方存储和计算实现数据的不可变性和计算的可信性。智能合约在区块链网络的多个节点上运行,因此,如果智能合约不具备确定性,多个节点之间的一致性(以及它们之间的共识)将无法实现,从而导致网络停滞。此外,如果智能合约永不终止,处理它的区块链节点将不得不消耗无限的时间和资源来运行合约,这同样会导致网络停滞。接下来,我们将讨论这两个主题——确定性和终止性,并阐述管理其影响的不同策略。
确定性
如果一个程序在不同计算机或同一计算机的不同运行中,基于相同的输入始终产生相同的输出,则该程序被认为是确定性的,否则是非确定性的。程序可能因以下原因而变得非确定性:
1. 调用非确定性系统函数:开发者在编码时倾向于调用系统函数以减少工作量。这些系统函数可能包含非确定性元素,例如随机数生成和系统时间获取函数。一旦程序调用非确定性函数并使用其输出,程序本身就会变得非确定性。
2. 非确定性数据源:如果程序在运行时获取数据,而数据源是非确定性的,程序也会变得非确定性。例如,请求搜索引擎查询的前10个搜索结果。搜索引擎可能会根据不同国家的IP地址返回不同的结果排名,从而在相同输入下产生不同的输出。
3. 动态调用:动态调用指的是程序调用第二个程序,而该程序只能在运行时确定。由于动态调用的目标仅在运行时决定,因此其行为变得非确定性。
由于非确定性合约可能在多方计算系统的不同节点上返回不同的结果,它们有可能破坏区块链网络的一致性,因此基于区块链的智能合约必须具备确定性。区块链开发者应意识到这一点,并在设计智能合约系统时消除所有非确定性因素。接下来,我们将探讨不同区块链系统如何处理这一问题。
比特币
比特币内置了一个脚本引擎来执行身份验证脚本。该脚本引擎是所有基于区块链的智能合约引擎的前身。比特币开发者可以在这个系统上编写简单的应用程序,但这些应用程序功能有限且非图灵完备。比特币没有提供系统功能或调用数据的能力,更不用说动态调用了。因此,我们可以得出结论,基于比特币的智能合约本质上是确定性的。
以太坊
以太坊被设计为一个图灵完备的智能合约平台,允许开发者编写任意类型的程序。以太坊平台提供了一个称为EVM的虚拟机来执行合约代码,以及一种类似于JavaScript的高级编程语言Solidity。基于以太坊的智能合约不提供非确定性系统功能,可访问的数据仅限于链上信息,而外部数据只能通过交易发送给合约。然而,以太坊的Call和CALLCODE指令的目标地址通过堆栈传递,使得合约在运行动态调用时可以调用其他合约的代码。这可能会导致合约的调用路径变得非确定性。幸运的是,合约可访问的数据本质上是确定性的,确保所有节点在运行动态调用时获得相同的目标地址。因此,我们可以得出结论,系统一致性得到了保证。然而,可能的非确定性调用路径可能会对可扩展性造成显著的性能损失。我们将在下一篇文章中详细讨论这一点。
Fabric
Fabric是Hyperledger下的一个子项目,其智能合约引擎嵌入在称为Docker的重型运行时环境中。由于Docker的特性,部署在Fabric上的智能合约几乎可以利用物理计算机的所有功能,这使得系统高度非确定性。因此,Fabric要求开发者在编码时避免使用非确定性功能,并计划提供一个专门的确定性函数库。然而,由于其底层设计的原因,仅依赖开发者遵守良好实践是不现实的。非确定性的幽灵可能会在极端情况下引发复杂问题和故障。
终止问题
终止问题是数理逻辑领域中的一个可计算性问题。简而言之,终止问题描述了无法确定给定程序是否能在有限时间内完成的基本问题。1936年,Alan Turing使用康托尔的对角线论证证明,这样的程序P无法被制定,意味着终止问题没有通用的算法解决方案。然而,基于区块链的智能合约必须保证在有限时间内完成,否则它们将消耗无限的时间和资源,导致系统停滞。因此,区块链的设计者必须假设所有智能合约都可能进入无限循环,并准备一种外部终止合约的机制。
图灵不完备性
图灵不完备的区块链系统提供有限的指令集,没有跳转和循环等指令。基于此类系统的智能合约无法进入无限循环,并最终在有限时间内终止。比特币就是一个例子。
步骤和费用计量
由于合约的终止无法在执行前预见,我们可以监控其执行的步骤数,每执行一个新指令增加一步。当步骤计量器读数超过预设限制时,合约被认为进入死循环,可以强制终止。另一种方法是安装费用计量器,其技术上与步骤计量器相同,但通过经济激励实现类似目标。
计时器
计时器终止机制使用执行时间度量来确定合约是否进入死循环:如果合约在设定截止时间后仍未完成执行,则被认为进入死循环并被强制终止。由于Docker运行时环境无法计算步骤或费用,计时器方法是Fabric的首选终止机制。
资源控制与隔离
除了资源控制外,虚拟化执行环境还作为一种隔离资源的手段,以确保系统安全。在公有区块链上,任何参与者都可以编写和上传智能合约,而这些合约在图灵完备平台上可能包含病毒和恶意软件。如果智能合约直接在区块链节点的主机操作系统上运行,病毒可能会自我复制,导致恶意合约破坏主机数据。因此,智能合约必须被限制在隔离的沙盒中,即虚拟机或Docker。
结论
通过分析确定性、终止性、资源控制和资源隔离,我们可以得出结论:区块链智能合约应具备确定性、可终止性,并受到准确的资源控制和隔离能力的约束。在这方面,专为区块链设计的虚拟机解决方案显然比Docker解决方案更具优势。然而,Docker解决方案具有编码语言灵活性,无需学习新语言,可以轻松集成到当前的开发生态系统中。这自然引出了一个问题:是否存在一种结合Docker和VM环境优势的解决方案?我们将在本系列的最后一篇文章中探讨这一问题。