硬币模型和账户模型
我们常说区块链是公共账本。但是,区块链这个账本的记账形式可是大有学问。
在这一点上,比特币和几乎所有的智能合约公链都不同。比特币采用的是所谓的基于UTXO的模型(UTXO-based model),我称之为硬币模型。而支持智能合约的公链们,包括这一赛道的代表以太坊,采用的大都是所谓的基于账户的模型(account-based model)。
在计算机术语里,Transaction(交易)常缩写为Tx,所以,UTXO就是Unspent Transaction(Tx) Output的缩写。这是缩写套着缩写。
英文缩写不太容易为读者所理解,于是我把它叫做基于硬币的模型(coin-based model),或者硬币模型。
硬币(coin)这个词来自于中本聪2008年发表的比特币白皮书第2小节“交易”。小节开篇就定义了一个概念“电子硬币”(electronic coin):什么是一枚电子硬币呢?一枚电子硬币就是一连串的数字签名(digital signature)。这一连串的数字签名其实是签署确认了该枚电子硬币转移的全部历史交易记录。
交易就是一个管道,价值从这一端流进来,叫做输入(input),从另一端流出去,叫做输出(output)。如果这个输出没有再被另外一笔交易作为输入,也就是没有被花费,那么它就叫做未花费的交易输出(UTXO)。
由此可见,一个UTXO的背后,有着一连串的交易历史。这一连串的交易历史上,都有正确的数字签名。这一连串的数字签名,就定义了一枚电子硬币。
我们就可以简单的说,一个UTXO就是一枚尚未被花掉的电子硬币。
一枚电子硬币一旦被花掉,也就是转账交易给了另外一个人,那么该枚电子硬币就会消失,代之以一枚或者多枚新的电子硬币。其实原来的电子硬币也不是消失了,而是成为了新的电子硬币的一部分。想象一下金币的融化和重铸。
所以,比特币网络上,真正存在着的,是一枚一枚的电子硬币,或者叫比特硬币。这些硬币面额皆有不同,都是BTC本位。比如0.1 BTC的硬币,0.3 BTC的硬币,1.2 BTC的硬币,这一共是三枚硬币,互不相同。
即使是面额相同的两枚比特硬币,也不是同一枚硬币,因为他们的交易历史并不相同。
所以我在1月28号文章《NFT的核心精神是数字物品的物理化,而非原子物品的上链》中说,比特币的实物形式,比特硬币,其实是非同质化的(non-fungible),是一种NFT(比喻)。
中本聪为什么要这么设计?为什么不采用更为普遍、用户最习以为常的账户模型呢?
在今天这个金融全面数字化的时代,我们最习惯的使用金融系统的方式已经是账户模型。到银行开户(开立账户),向账户转账,从账户向外转账,等等。
但是比特币不是中心化系统,没有一个中心机构负责审查和批准你开设账户。
比特币系统里只有散落的硬币。这些硬币可以属于某一个私钥控制,也可以被多个私钥共同控制(多签地址),甚至可以不受任何私钥控制(比如黑洞地址,或者通过解谜来解锁这枚硬币),等等。
作为对比,账户系统则要么需要设计开户(注册),这显然是以牺牲“抗审查“、“无需许可”和隐私性为代价的,比如EOS;要么就用地址(address)来模拟账户(account),比如以太坊。
和硬币模型有一个很大的不同在于,账户是有状态的。比如最简单的账户数据,余额,就是账户的一个状态数据。
智能合约运行过程中产生的大量中间数据,都有可能会成为账户下面的状态数据。
这就造成一个很大的问题,状态爆炸(state bloating)。
时至今日,比特币从2009年1月3号上线,12年多过去了,现在比特币全节点账本尺寸是371GB(2021年10月24日数据)。
以太坊从2014年上线至今7年左右时间,包含完整状态历史数据的存档节点的尺寸已经高达8.8TB,也就是8800GB多,是比特币账本尺寸的23.7倍。而以太坊在2014-2017年的前几年其实使用量很少,生态还没有发展起来。可想而知,随着以太坊生态的快速繁荣,其全量数据的尺寸将出现多么巨大的爆炸性增长。
为了暂时应对这个问题,以太坊不要求所谓的全节点保留全部的历史状态数据,而是只保留过去128个区块(快速同步则进一步减少到64个区块)的状态数据(以及一周的trace数据)。这个代价就是以太坊所谓的全节点其实是阉割版的全节点,它并不具有全部的历史状态数据,从而无法完成一些对深度历史的回溯,比如查询一个远古区块的某账户余额。
通过这样的折衷,以太坊的阉割版全节点的数据尺寸下降到了1TB多,也就是1000GB多(2021年10月25日数据),仍然是比特币真·全节点账本尺寸的2.7倍。
硬币模型没有状态。每一枚硬币要么不被花掉,要么被花掉。没有中间状态。所以对比特币而言,所谓某个地址的余额,其实是客户端根据发送到该地址的所有硬币的面额累加起来得到的。比特币系统并不记录和维护这么一个状态数据。
这样就带来一个好处,硬币的花费是可以并行不悖的。我可以签署一笔交易花费我地址里的一个硬币给张三,然后同时签署另一笔交易花费我地址里的另一个硬币给李四。我可以同时把这两笔交易广播出去,等待矿工确认。
而对于以太坊的账户模型,则无法并发修改账户的状态。因为一笔交易会修改账户余额,后一笔交易必须在前一笔交易修改结果的基础上再修改,才能保证最终结果的正确性。比如我的账户现在有100 ETH,一笔交易扣除10 ETH,剩90 ETH,另一笔交易再扣除10 ETH,剩80 ETH,这是对的。但是如果两笔扣除10 ETH的交易并发操作了,都读取到了账户余额100 ETH,然后计算扣除10 ETH后应为90 ETH,写入两次90 ETH,我的余额还剩90 ETH,这显然就是错误的了。
所以以太坊必须引入一个所谓的nonce值来给交易确定顺序,让交易一个一个顺序进行,不能并行。引入nonce的问题大家拍脑袋也能想得到,这会严重限制客户端的分布式。在多台设备上同时操作账户的话,如何保证nonce的顺序化,甚至如何生成nonce,都是一个需要解决的问题。
而硬币模型则天然避免的这样的问题。
对于硬币模型,如果要试图把一个硬币花两遍,这就是所谓的双花攻击(double-spending attack)。在账户模型下,没有双花攻击,只有重放攻击(replay attack),就是重复对账户此前的交易。这个问题对于合约账户而言会引出一个过去造成过巨额资产损失的重入漏洞。
账户模型有一个比硬币模型的好处,那就是更容易支持智能合约。硬币模型由于没有状态,所以不容易(或者无法)支持完全的智能合约。
以太坊当初也是为了实现图灵完备(turing-complete)的智能合约支持,所以才舍弃了UTXO和硬币模型,改回去了账户模型,开了一个小小的倒车。
有智能合约支持的账户模型,就把账户分成了两类:由人类掌控的所谓外部控制账户,以及由合约掌控的智能合约控制账户。
合约控制账户是去中心化资产管理的重要基础。它对资产的托管,实现了脱离人为控制的去中心化。
比特币可能会采用其他路线来探索完备智能合约的支持,那就是保持一层的无状态,而把状态和合约控制账户放到二层去实现。
我们即将迎来比特币的一个重要升级,引入Taproot技术。这或许会推动我们向这个方向迈出关键的一步。
让我们拭目以待吧。
(公众号:刘教链。知识星球:公众号回复“星球”) (免责声明:本文内容均不构成任何投资建议。加密货币为极高风险品种,有随时归零的风险,请谨慎参与,自我负责。)