在一个账本模型的区块链,比如 Conflux 或者 Ethereum中,账本信息是区别于交易信息的重要组成部分。区块链系统在处理这两类信息时所消耗的存储资源是完全不同的。
比如我有一个账号,张三给我转了3块钱,李四给我转了4块钱,我又给王五转了5块钱,现在剩下了2块钱。那么一段时间之后,当我再次发出一笔交易时,处理这笔交易的全节点需要知道我的账户里有2块钱,来判断我的余额是否充足。而我的账户经历了哪些转账变成了2块钱,并不是处理新交易所必须的信息。
在 Conflux 的设计中,当经过足够久的时间过后,我和张三、李四、王五这些人的转账记录会被全节点删去,只留下相应区块的哈希值(这部分实现的细节详见文章 Conflux 研究院 | 如何存储历史数据);但无论经过多久,我的账户余额信息都会被全节点存储。
那么,除了我的账户余额信息外,还有哪些信息是执行交易时所必须读取的呢?那就是智能合约的变量信息。
如果智能合约维护了一些变量,并允许与合约交互的交易读取和修改这些变量,这些变量就必须被全节点存储,不能随便删掉。对于全节点而言,交易信息对存储的占用是临时的。交易发生一段时间后,全节点可以安全地删除交易信息,让档案节点提供查询服务,自己专注于通过共识协议维护区块链系统的正常运行。然而,智能合约的变量信息需要被所有全节点永久存储,需要所有存活的全节点持续付出存储成本。如果将存储费用一次性支付给打包该笔交易的节点(矿工),则无法体现其他全节点实际付出的存储成本。
为此,Conflux 引入了存储押金机制。当执行智能合约时,如果由于修改变量占用了存储空间,交易发起人就要支付存储押金。当被修改的变量被置为 0 时,Conflux 将不再存储相应变量的内容(也就是说,没有被显式地存储的变量默认值即为0),此时,为该变量支付的存储押金会被退还给当初的支付者。
这样,为占用存储空间支付的钱将成为押金而非费用。在存储空间的使用期间,押金会产生年化 4.08% 的利息,这些利息将直接分配给矿工,用于补偿矿工们的存储成本。存储押金的价格锁定为 1 CFX/KB。例如,如果当前共有 100 GB 的数据需要存储,那么存储押金总量大约是一亿 CFX,平均每个区块产生的利息约为 0.06 CFX。
如果一个用户修改了智能合约的变量,而这个变量之前已经有另一个人付过押金了,那么智能合约就会将先前支付的押金退还,并要求这个修改变量的用户支付押金。
在 DeFi 大火的背景下,智能合约所承担的功能也日趋复杂,经常出现用户调用 A 合约,A 合约再调用 B 合约的情况。在 Conflux 的存储押金机制设计中,无论合约经过了几层调用,都由最初发起交易的用户支付整个交易执行期间产生的所有存储押金。
为了避免用户在执行恶意或有故障的合约时,为支付存储押金而承受意外损失,用户在发起交易时,需要指定存储上限 Storage Limit,即预期这笔交易所占用的存储字节的量。如果交易执行结束后,所占用的存储空间超过了 Storage Limit,则交易的执行会失败。如果在交易执行前,用户的余额不足以支付 Storage Limit 的存储押金,交易也会失败。这种类型的交易失败,是 Conflux 的新开发者比较最常遇到的问题。
需要注意的是,存储押金和 Gas 费用不同。Gas 所代表的计算资源,是在交易执行期间,被一个又一个指令执行消耗掉的。而存储押金所代表的存储资源,是在交易执行结束后,将执行结果从缓存写入到硬盘时,才开始消耗的。这导致存储押金和 Gas 费用的逻辑有很大不同。
首先,存储押金并不会在交易执行前被锁定。打个比方说,如果交易发起人的账户有 10 CFX,交易费需要支付 5 CFX,那么在交易执行期间,发起人可用的余额只有 5 CFX。但如果交易的发起人付完交易费的账户余额有 5 CFX,Storage Limit 是 3KB (需要 3 CFX) 的存储押金,那么交易执行期间,账户可用的余额是 5 CFX 而不是 2 CFX。但是,如果填写 Storage Limit 过大,例如 7KB,将会导致交易前检查的失败。
另外,交易执行过程中会实时检查剩余的 Gas 是否足够,一旦不足,会立刻停止执行。而修改合约变量时,却不会立即收取存储押金,也不会实时检查存储押金是否充足。也就是说,如果一笔交易的执行过程中,申请了大量的存储,但在同一笔交易中又释放了这些存储空间,那么这笔交易不会被收取任何存储押金费用,也不会因为 Storage Limit 不足而失败。正如之前所说,存储资源的消耗是在交易执行结束,交易执行结果从缓存写入硬盘后才产生的。所以,存储押金的收取也是在整个交易执行结束后进行,而 Storage Limit 检查是在关注“新增存储占用 减 新增存储释放”的差值。
不过,除了存储押金机制,Conflux 还有代付费机制。当这两个机制结合在一起的时候,情况又会变得有哪些不同呢?我们将在下期文章中介绍,当存储押金遇上代付费机制。