提起智能合约,很多人的第一反应就是以太坊,甚至在维基百科中搜索智能合约的时候,都会给出如下的定义:

智能合约:(英语:Smart Contract)是一种特殊协议,在区块链内制定合约时使用,当中内含了代码函数 (Function),亦能与其他合约进行交互、做决策、存储资料及发送以太币等功能。

显然将智能合约仅仅定义为以太坊功能的一部分有点以偏概全,相比之下,IBM 给出的智能合约定义更为准确,更符合现代各类层出不穷的公链和合约:

IBM 定义的智能合约:只是存储在区块链上的程序,在满足预先确定的条件时会运行这些程序。它们通常用于自动执行协议,以便所有参与者都可以立即确定结果,而无需任何中间人参与,也不会浪费时间。它们还可以自动完成工作流程,在满足条件时触发下一个操作。

总结就是:

1. 存储在区块链上

2. 在满足特定条件下会运行特定逻辑

3. 运行逻辑不需要任何第三方参与

因此满足这三点的都可以看作是智能合约。其实比特币,莱特币以及 Doge 这些看起来只能转账代币的区块链系统也是满足智能合约的定义,其实它们的转账功能本身也是智能合约的一种。

但是我们通常不认为只能转账的区块链是智能合约平台,主要因为它们在第二条(在满足特定条件下会运行特定逻辑)下的场景太少,这个特定逻辑被缩限在几种固定的场景,例如比特币只有 P2PKH,P2PK,P2SH 等等标准交易逻辑,能够使用的场景无非也就是单签,多签等很有限的场景,无法根据开发者的需要自由定制执行逻辑,比如更丰富的前提条件,更复杂的逻辑控制,更灵活的合约间交互等等。因此更广泛意义上的智能合约还要加上第四点:

4. 图灵完备,可以执行任意逻辑

账户模型、UTXO模型与智能合约

账户模型

我们熟知的智能合约公链平台,例如以太坊,EOS,Solana 等在执行方式上都可以称作账户模型。

账户模型非常容易理解,和我们的支付宝账户,银行账户等等是一种思维方式,每个人有一个或多个“账户”,每个账户有一个“余额”。

A->B 转账的过程就是从账户 A 的余额中减去 X,然后再从账户 B 的余额中增加 X(不考虑手续费)。如果给这个转账过程增加一些逻辑条件,设定满足特定的条件,这个转账才能发生,那么就形成了智能合约。以太坊内部有一个虚拟机,被称为 EVM,这个虚拟机就是用来监听特定的条件,满足条件之后,自动执行转账。因为这个虚拟机可以执行编程代码,因此只需要用计算机高层编程语言编写逻辑,并且部署到链上就可以轻松实现任意的逻辑。

这种账户模型因为非常贴近面向对象的编程方式,只需要定义成员变量(各种余额数据),以及方法(合约),就可以轻松实现任意逻辑。也正因如此,市面上的绝大多数智能合约平台都是运行在账户模型之上。

账户模型也有一个很显著的弊端:就是虚拟机在分布式节点的条件下如何保证一致性。由于以太坊上所有的合约都是由发送以太坊交易来驱动的,因此收到交易的顺序会影响交易的结果,为了保证所有节点都执行相同的逻辑,就必须保证所有节点收到交易的顺序是一致的,如果不一致则会造成混乱。显然,在分布式的环境下,所有节点很难保持接收交易的一致性,尤其是高频交易的场景下,如果 A 给 B 连续快速发送10笔金额,必须要等到所有节点按顺序接收到所有交易后,才能结算完成。如果某个节点先收到了第十笔交易,那么就需要等待其他9笔交易都就位之后,才能处理第十笔。另外,每笔以太坊交易只能进行1对1转账,在高频场景,尤其是多对多的复杂情形下,非常吃力。

为了突出以下以太坊的性能问题,我们假设以下场景,A 账户要给100个人派发红包。如果使用 ETH 来发红包的话,必须按照顺序发送给1号,2号,3号...需要构造100个交易,一个接着一个进行发送,节点也必须一个接着一个按次序处理。因为每次发送都要等待上一次余额确定,因此1号,2号他们收到红包的顺序是确定的,100号只有等前面的人都收到红包之后,才能收到红包。

传统互联网应用使用账户模型的应用,都要配合数据库的强一致锁,或者强事务等来实现账户修改的安全,这个问题放在分布式的区块链上就格外显著。

核心原因就是,对账户的修改必须遵照严格的顺序来执行,顺序的先后不同可能会导致执行结果的千差万别(这也就是为什么以太坊的swap 一直解决不了矿工抢跑的问题,矿工可以将利于自己的交易插在别的用户前面,以此来改变执行结果)。

UTXO 模型

UTXO 模型是另一种主流区块链采用的模型,比特币,莱特币,DOGE 等区块链采用的是这种模型。

UTXO 的意思是“未花费交易输出”。这种模型非常类似我们日常使用的现金(纸币与硬币),可以看做一种改良版的现金(这里顺道提一句,央行发行的数字货币就是 UTXO 模型)。

区块链并不记载和维护某个地址有多少余额,记载的是一张张钞票是属于哪个地址。比特币的场景下,某个地址 A 的余额不能直接查询到,需要统计有多少张钞票是属于 A 的。比方说,我们有一个钱包(真的钱包),里面放了一张10元,一张100元,还放了一个1块的硬币,那么我们可以说,我们的钱包余额是111元(而且知道余额是由一张100,一张10块和一个1块所组成的),换言之,如果不去计算每一张纸币与面值,仅凭钱包本身是不知道有多少余额的,这与以太坊支付宝之类的账户模型有很大不同。

比特币转账的时候怎么转呢,同样很接近(但是不完全一样)我们平时使用现金支付的样子。还是刚才的真钱包,如 A 要给 B 付1块钱,那么 A 有3种方法可以付给 B,给他1块,给他10块找回9块,给他100块找回99块。找钱这一点与现金不太一样,或者可以说是改良的地方。A 给B10块找回9块,并不是让 B 找出来9块钱还给 A,而是 A 把10块钱烧掉(销毁 UTXO),然后由系统重新印出一张1块给B,印出一张9块给 A(重建 UTXO)。经过交易后,A 的钱包有一张面值100的钞票,一张面值9块的钞票,还有一张1块,余额是110块。

根据上面的描述,我们可以知道,比特币的转账和收款就是钱包里的纸钞不断消灭和生成的过程。需要知道比特币地址的余额,就需要把这个钱包地址的所有钞票拿出来,计算所有面值并求和。

同时,比特币支持多对多交易,比如说可以一笔交易让 A 同时给 DEF 转账1块:

1. 拿出100面值烧掉,印出99块还给 A,1块给 D。

2. 拿出10块面值烧掉,印出9块还给 A,1块给 E。

3. 拿出1块面值烧掉,不找零给 A,1块给 F。

UTXO 模型神奇之处就在于,上面3个步骤可以分三个不相关(并行交易与顺序无关)的交易来发送,也可以直接使用1个交易来进行发送。

对比以太坊,比特币要同时发送给100个人,只需要一笔交易就可以让100个人同时收到钱,性能差距可想而知。这样就理解为什么央行数字货币使用的是 UTXO 模型了,不然深圳怎么给5万个钱包发送1000万数字人民币?

UTXO 脚本控制,一个 UTXO(含有一定面值的钞票)可不可以被销毁,控制的粒度是 UTXO(单个钞票)的级别,对交易没有顺序要求,因此可以进行多对多交易以及并行交易校验,在现金转账的场景下有极高的性能。

UTXO 脚本智能化

刚才提到的 UTXO 模型在并行化上面有极大的优势,具备突出的拓展性能,但是为什么我们在 UTXO 的公链上很少能够看到智能合约呢?

主要是以下几点原因:

1. UTXO 脚本编程较为复杂

2. BTC 等公链限制了脚本类型,脚本体积等

3. 分布式状态管理较为复杂

我们逐个解释一下。首先很多人并不知道,其实比特币是可以自由编程的。我们从 Bitcoin 的 wiki 可以看到,Bitcoin 有大量操作码,这种操作码看上去及其不友好,长得非常像汇编语言.学习过比特币脚本原理的人应该知道,能不能花费比特币的判断是通过一个栈式结构来存储和校验的。

这可能颠覆你的认知「高性能智能合约也可以在比特币实现」

栈中依次放入解锁脚本和锁定脚本,然后依次执行操作码,如果最终栈的返回值是 true,那么此 UTXO 可花费,反之不可花费。

其实我们熟悉的很多编程语言,在计算机底层执行逻辑的时候,也是栈的结构,比如 Java,rust,go 等等。以 Java 为例, Java 存在栈内存和堆内存的概念,栈内存主要执行函数内部逻辑,堆内存主要存放对象等数据。由此可见,栈实际上是可以执行任意逻辑的,Java 编译之后的字节码就是在操作这个栈来实现各种复杂的业务逻辑。

比特币脚本使用的栈和虚拟机虽然不如 JVM 那么多复杂特性,但是通过一定的组合也是可以实现几乎全部的图灵完备逻辑。这里很多人会说比特币脚本没有死循环,因此不是图灵完备。实际上这是故意为之,为了保证计算一定会产生一个结果。其实以太坊等也没有真正的死循环,gas 烧尽之后循环就会停止,比特币脚本在做循环的时候,需要预先将循环重复写入到脚本栈中,想做死循环,就要写一个无限长的脚本,这种交易明显是毫无意义的,在实际的脚本编写中,比特币脚本都会指定一个上限循环次数,确保手续费在合理的范围内(和以太坊 gas 烧尽是同样的原理)。

说了这么多脚本栈,我们来看看比特币脚本如何实现一些智能合约。一个最典型的合约场景就是 ERC721,就是 NFT 合约。以太坊场景下要创建 NFT,首先要部署一个合约账户,然后所有的 NFT 所有权由这个账户管理,所有此 NFT 的转账都要和这个 NFT 合约账户交互。

在 UTXO 模型下,我们设计这样一种 UTXO,它内部存在一段数据和代码,标记此 UTXO 代表什么 NFT,谁可以解锁,怎么销毁它,怎么保证上限,那么这个 UTXO 就可以代表这个 NFT。拥有这个UTXO 的人就拥有了这个 NFT。想要转账这个 NFT,你就必须用私钥签名达成解锁条件,然后由比特币矿工来执行你的脚本,判断你是否可以转账这个 UTXO。更重要的是,同一个系列的 NFT,是分散在不同的 UTXO 中的,因此只要从分布式全局状态中找出满足特定条件的 UTXO,就可以判断出 NFT 都属于谁。这些 NFT 的转账可以并行,并且互相之间不会产生影响,这也就提供了最高的性能。

因此比特币合约的思想,就是使用单个 UTXO 脚本栈来存储状态和逻辑,整体状态由一批 UTXO 的状态共同组成,相对应以太坊的合约状态仅存在于一个账户中,对比之下,比特币的合约就拥有了和UTXO 一样级别的并发能力,也就为大规模的高性能使用打下了基础。

不考虑脚本体积和实用性以及客户端限制的话,在比特币上实现上上述逻辑从理论上是完全可行的,但是由于 UTXO 的独立特性,实际工程中会遇到两个难题,一个是 UTXO 互相感应的问题,另一个是合约溯源防伪的问题,这两个问题都被 MVC 链给巧妙解决了,因此可以最终实现可实用的高性能 UTXO 模型智能合约。

MVC 是一条完美实现比特币+高性能智能合约的 Web3 公链:

1. 采用兼容 UTXO 并行处理能力的一层智能合约技术“MetaTXID 方案”;

2. 结合了 UTXO 模型优势,是区块链领域上并发性最高,执行成本最低的 Layer-1 链上智能合约方案;

3. 首次实现了 UTXO 模型公链的实用性图灵完备,可满足一切Web3 应用和元宇宙应用的使用场景。

原文链接