我们一起通过一个超级马里奥风格的游戏,解释 vRAM 如何为开发者赋能,帮助他们创建新一代的 dApp. 我们将这个游戏称之为 Super DAPP(🍄).
Super DAPP 智能合约包含两个指令:
- “开始游戏” 在新游戏回合开始之前,加载玩家进度和当前得分;
- “修改分数”的指令用来在游戏回合结束之后,修改玩家的分数。
在我们的例子中,一笔事务分为如下 5 步完成:
- 发起信号
- 预热
- 加载数据,执行事务
- 修改数据
- 清除缓存
发起信号
1. 使用 vRAM 的一个 dApp 智能合约,在白皮书中我们称之为 “用户合约”,会通过 DSP 节点的 EOSIO API 接收来自客户端的事务。
2. 由于执行事务所需要的数据并未存储在 RAM 而是在 vRAM 中,因此 dApp 智能合约继续运行事务会触发异常。这一报错会向 DSP 发送信号,使得 DSP 知晓需要提供服务。
3. DSP 会解析服务请求,检测在 RAM 中未找到但存在 vRAM 之中的所有必要数据。

( 客户端 App (eosjs) 通过 DSP 的 API 节点发送事务请求. DSP 本地执行事务失败。 异常信息用于服务请求的信号)
🍄在我们的例子中,玩家 Alice 准备开始 “Super DAPP” 游戏的新回合,将 “开始游戏”的事务发送给 Super DAPP 智能合约。但是,在 DSP 节点中本地执行该指令时,却发现 Alice 的进度和当前的分数在 RAM 中不存在。由于加载新的游戏回合需要用到这些数据,该事务会抛出断言错误(assertion failure)。运行该事务的 DSP 会捕获该信号,并解析服务请求。
预热
1. DSP 检测确认,该智能合约为使用对应的服务包抵押了足额的 DAPP 代币,并且仍有足够的剩余使用额度。
2. DSP 节点会转发至本地的IPFS集群,查找表示所缺失数据的文件。由于只有Merkle根(表示整个数据集的当前状态)永久驻留在RAM中,所以通过跟踪表示数据集的Merkle树,直到到达表示数据的叶子节点,才能验证数据的完整性。
3. 使用加密证明,dApp智能合约可以验证锁请求的数据没有被篡改。“预热请求”阶段结束。

(DSP 会从本地 IPFS 集群中查找所请求的文件,并从 EOS RAM 中获取用于数据完整性证明的加密证明。然后,会将文件及证明发送至 dApp 智能合约,这一过程称之为 预热请求。)
🍄 在我们的例子中,DSP 解析了服务请求后,会继续从本地 IPFS 集群中获取 Alice 的数据。将 Alice 的上次退出的进度和当前的分数的数据连同加密证明转发给 Super DAPP 合约,其中,加密证明可以帮助智能合约验证数据的完整性。
加载数据,执行事务
1. dApp 智能合约将必备的数据加载到位于 RAM 中的临时缓存数据表中。
2. 现在,因为所有的数据都能够在 RAM 中获取,所以在传播给区块链上的出块节点之前,事务可以成功执行。
3. 如果事务由于任何其他原因导致执行失败,会运行清理进程,清除无用缓存数据。

(* 验证数据有效性之后, DSP 将数据加载到 EOS RAM 之中,将事务发送至区块链上。此次执行成功,因为所用到的数据已经存储在 RAM 之中了*)
🍄 在我们的例子中,验证了数据之后,DSP 会发送事务至 BP 的P2P 端点,通过这种方式将 Alice 的分数和进度加载到 RAM 中的临时缓存表中。现在所有需要的数据都在RAM中了,可以将事务发送给出块节点。
修改数据
1. 每次智能合约要对存储在基于 vRAM 的多索引表中的数据进行修改时,它就会用修改后的数据和受更改影响的merkle树的节点发起提交事件。数据点和merkle树节点会用本地 IPFS 集群中的文件表示。
还在么? 太棒了,因为最有意思的部分来了!🍩
2. 由于本地 IPFS 集群 URI 与数据的 hash 值相同(还记得Merkle树的双重作用吗?),所以,在 DSP 将数据实际提交到本地 IPFS 集群之前,智能合约就知道了预期的URI。根据相同的逻辑,两个独立缓存相同数据或重放历史的不同 DSP 会把数据 pin 在本地 IPFS 集群下,有着相同的本地 IPFS 集群 URI。
3. 合约会将新的数据和新的 Merkles 树节点,存储在 RAM 缓存表中。
4. 合约会将新的 Merkle 树根的值永久存储在 RAM 中。
5. 与区块链上的任何事件一样,带有数据的提交事件将成为区块链链历史数据的一部分。这确保了任何 DSP 都通过回放历史的方式来恢复数据。
6. DSP通过使用 demux 服务侦听来自链上的事件流来捕获事件。当检测到事件时,DSP 将文件缓存并索引到本地 IPFS 集群中,以便快速检索。
7. DSP 将提交请求发送至合约。
最后,在EOS RAM 上 的Merkle 根节点会修改,新的数据点会缓存至 DSP 的分布式文件存储系统中。

(dApp 智能合约会通过内联操作(inline action) 的方式修改 EOS RAM 中的数据。DSP 会监听修改事件,将新的文件存储在本地 IPFS 集群节点中)
🍄 继续我们的比喻,Alice 完成了一关后,保存游戏进度。现在,她分数更高,进度也更快了。Super DAPP 合约会提交一个包含新数据的事件,修改存在 EOS RAM 中的数据。同时,DSP 会侦听到事件,并修改本地 IPFS 集群上的数据,用 RAM 中的数据来表示 Alice 最新的分数和进度。
清理缓存
1. 事务执行结束后,DSP 会向 dApp 智能合约发起清理事件,将数据从 RAM 中移除。
2. DSP 向 dApp 智能合约发起清理指令,合约会将数据从 RAM 中删除。
3. dApp 合约会将加密证据(merkle 根数据)留在 RAM 中。在下一次预热请求验证数据完整性时 ,需要使用。

(数据从 EOS RAM 中删除,但保留了加密证据(Merkle 根节点)在 RAM 中)
🍄 游戏结束后,Super DAPP 合约会将数据从 RAM 中删除,将加密证据留在 RAM 中,供下一此数据预热请求时验证数据使用。
网友评论