Nervos 是个分层的多资产价值存储公链,是一套与其他公链完全不同的独创设计。Layer 1 底层专注于安全以及系统的强健性,将使用体验、性能等等交给 Layer 2 去处理。清晰的分工也造就了许多开发时不同的体验以及权衡。在本文中,Nervos CKB 核心开发者 jjy 带大家来看看 Nervos 底层的重要特性——链下确定性,是如何让整个系统更加安全并可以减少资源消耗,以及其中有什么样的权衡。
如何获取当前的区块高度
我已经反复的听到开发者抱怨说为什么他们没有办法在他们的脚本(智能合约)中读取当前的区块高度这件事情了。
如每位开发者所知,从智能合约读取当前的区块高度是个以太坊以及其他使用 EVM 的区块链上的基本功能。那如果 CKB 真如我们所说,是下一代的区块链,那为什么他没办法做到这件上一代公链就能做到的事情呢?
嗯,我猜应该没啥人可以回答这个问题,CKB 核心团队也比较没有经常解释 CKB 的独特设计,这点我觉得核心团队应该要做的更好。
所以我决定要写这篇文章来解释这个设计的权衡之处:为什么我们不能在智能合约(脚本)中读取当前的区块高度呢。
正确的方式
让我们从验证 CKB 脚本如何读取区块高度的正确方式开始吧!
我的观察是多数的开发者是透过请求区块高度来计算两个动作之间的区块时间,抽象地用术语来说,一个用户在区块高度 X 时进行存款,并且在高度 Y 时取出。在取出这个动作发生之后,智能合约就需要去计算区块 X 到区块 Y 之间的区块数,并且根据用户的存款时间去发送奖励(注:例如流动性挖矿即是如此)或者做其他类似的事情。
以太坊上面可以直接的读取区块高度以及计算奖励。然而,在 CKB 中,我们必须采用其他方法而不是直接读取区块高度:
- 我们可以使用 transaction valid since 的功能来限制取款交易,以确保至少在存款完后的 Z 个区块后,才会发生取款交易。但是,这样一来用户可以把取款的时间延长至区块 Z 之后 ,这在某些情况下可能不合适。
- 我们可以采取两步取款来定位区块高度。首先第一步是借由 CKB syscalls 来读取用户存款的区块高度 X ,并且记录 X 这个高度在新的「准备取款 Cell」中;第二步就是我们可以使用 syscall 来读取准备取款的 cell Y 以及从这个 cell 的 data 字段来读取 X。
因此我们一样可以计算出区块时间是 Y-X。
(译注:想想 Nervos DAO 的设计就是如此)
链下确定性
那么这样做的目的是什么呢?开发者显然更喜欢更简单、更直观的方法,那么为什么 CKB 要使用如此困难的方法来完成简单的工作?!
这都是因为链下确定性。让我们先解释两个问题:以太坊合约的输入是什么?CKB 脚本的输入是什么?
如果我们将合约(或脚本)视为函数「f」,那么我们可以将智能合约的计算表示为以下形式:
在以太坊上:
output = f(tx, state tree, current blockchain)
在 CKB 上:
output = f(tx, deterministic blockchain)
在以太坊中,一个合约可以从三个输入中检索信息:tx、帐户状态树和当前区块链状态。
例如,智能合约可以从区块链中读取当前区块高度和区块哈希。
在 CKB 中,我们只允许脚本读取确定性的输入。如果用户想从区块链读取信息,那么用户首先必须在交易中包含区块哈希。因此,脚本可以读取的所有信息都是确定的。我们称之为链下确定性,这是CKB的一个基本特征。
优点
链下确定性带来了一些好处,最重要的一点是,一旦我们验证了一个交易,我们就知道它会是有效的或无效的,因为输入输出都是确定的,这个验证结果不依赖于区块链状态。
这个确定性在 CKB 中引入了一个验证策略,就是在将交易推入内存池前我们只验证一次。当我们将交易打包到一个区块中时,我们只需要检查交易输入是否仍然是未使用的,这和对交易进行完整的验证相比成本很小。
交易的这种链下确定性不仅绑定到一个节点;我们可以保证一个交易是有效的,即使我们通过 P2P 网络发送它。因为如果一个交易有效,那么它将永远有效,所以 CKB 只广播有效的交易到其他节点。如果恶意节点试图广播无效的交易,那么一旦无法验证恶意节点发送的交易,网络中的其他节点将立即禁止它。由于无效的交易不能广播到 CKB 网络中,所以 CKB 只将有效的交易打包到区块,我认为这是 CKB 的一个主要优势。
注意哦,这件事在以太坊中是不可行的,因为以太坊的交易并不是链下确定性的,一个交易可能在区块高度 42 上失败,即使它在区块高度 41 上是有效的。因此,我们永远不知道失败的交易是恶意节点故意发送的,还是因为区块链当前状态改变而失败的。
所以以太坊选择了另一种方式,就是允许节点广播无效的消息并将其打包到块中。然后,该协议允许矿工通过向发送者的账户收取最高费用来对失败的交易进行处罚。该机制旨在鼓励用户只发送有效的短信,以加强安全;但即使你是一个诚实的用户,您也可能由于意外地运行到一个无效的合约状态而发送一个失败的交易。( 当我试图将钱存入 Curve 时,我在一次失败的交易中损失了大约 50 美元。)
在区块中只包含有效的交易,还是在区块中包含失败的交易并惩罚发送者,这两种不同的设计思想来自于对一个简单问题的不同回答:我们应该允许脚本(智能合约)读取当前区块吗?
Layer 1 强健性 vs 用户体验
根据我的理解,在 Layer 1 的强健性(鲁棒性)和用户体验之间,CKB 的设计明显选择了前者。
我相信这是一个正确的选择;Layer 1 区块链唯一重要的事情是提供强健性性和安全的服务。这种权衡并不意味着 CKB 不关心用户的体验。记住 CKB 的口号——为 Layer 2 建造 Layer 1。在这种情况下,Layer 1 是为了强健性,Layer 2 (以上)才是为了用户体验。
在分层架构中,大多数人会使用高层的技术,只有少数人需要从底层直接去访问。例如,在互联网中大多数用户使用 HTTP 或 WebSocket;很少有人使用 TCP 或 UDP,几乎没有人直接使用 IP。
译注:图片为译者添加,便于不了解互联网分层架构者参照这个互联网的分层图来了解作者所言。
Source:khan Academy
https://www.khanacademy.org/c...:the-internet/xcae6f4a7ff015e7d:the-internet-protocol-suite/a/the-internet-protocols
从智能合约开发者的角度来看,您可能会发现这种设计难以理解 ,但是如果你看一下分层的架构,你会发现 Nervos 的设计非常适合 Layer 1 区块链。
一旦 Nervos 的 Layer 2 设施启动,开发者将能够轻松访问 Layer 2 提供的功能,不仅能用Layer 2 读取区块高度(这很简单),而且还可以使用其他 Layer 2 更强大的功能(这里留给开发人员自己想象的空间)。
*原文链接:
https://talk.nervos.org/t/off...
原文作者:CKB 核心开发者 jjy
译者:Williams*
// 如果你喜欢 Nervos 并且喜欢开发
// 你可以关注并私信我哦~
if (you like Nervos && you like dev) {
println("you can follow me and private letter for me~");
}