【跟着源码学】EOS智能合约之eosio.system – part1

26次阅读

共计 2577 个字符,预计需要花费 7 分钟才能阅读完成。

本系列还是着眼于了解 EOS 的设计理念,力求在繁杂的版本变更,以及各种区块链技术文章当中,根据源码整理出一个清晰简明的 eos 实现,而暂时不着眼研究 C ++ 工程开发的奇淫巧技,主要是因为还需要时(目)间(前)继(领)续(悟)修(不)炼(到)。
正文

代码链接
这个 multi_index 是什么呢?
在 eoslib 目录下有 multi_index.hpp,自然而然的来看看这里面有什么线索。
在这里,找到了如下解释:

EOSIO Multi-Index API provides a C++ interface to the EOSIO database. It is patterned after Boost Multi Index Container.
EOSIO Multi-Index table requires exactly a uint64_t primary key. For the table to be able to retrieve the primary key,
the object stored inside the table is required to have a const member function called primary_key() that returns uint64_t.
EOSIO Multi-Index table also supports up to 16 secondary indices. The type of the secondary indices could be any of:
uint64_t
uint128_t
uint256_t
double
long double

原来 multi_index 是跟 EOSIO 数据库相关的 API。相对应的,官方开发者文档有 DB API 的描述,简要解释一下使用场景:
比如开发一个游戏 DApp,用户有自己的 Action(很难翻译,可以理解为执行一个函数,比如 randint(6),模拟了一次掷骰子,返回结果从 1 至 6)操作,该游戏智能合约要记录每位用户游戏 Actions,本次合约执行完毕后数据不能丢失,就需要将数据存储到 EOS 数据库中。
Action 在被称为 Action 执行上下文的环境中运作。如下图所示,

Action 上下文提供执行 Action 所需的几件事情。其中一件事是 Action 的工作内存。这是 Action 执行的地方。在处理一个 Action 之前,EOSIO 为该 Action 进行一次内存清理工作。在新 Action 的上下文中当另一个 Action 执行时可能已经被设置的变量不可用。在 Action 中传递状态的唯一方法是将其持久存储并从 EOSIO 数据库中检索。
声明
看到这里,感觉引入概念越来越多,暂时先搬运了一些现成资料(见参考),再后续学习中慢慢消化。
这里提到了 eosio::multi_index table 借鉴了 Boost 库中的 multi_index 容器(Boost 库中的 mult_index)。可以在概念上看作传统数据库中的表格,其中行是容器中的单个对象,列是容器中对象的成员属性,并且索引通过与一个键兼容的键提供对对象的快速查找 对象成员属性。
传统的数据库表允许索引成为表中某些列数的用户定义函数。eosio::multi_index 同样允许索引是任何用户定义的函数。但其返回值仅限于受支持的一组受限密钥类型之一。
传统数据库表通常有一个唯一的主键,它允许明确标识表中的特定行,并为表中的行提供标准排序顺序。eosio::multi_index 支持类似的语义,但是该对象的主键在 eosio::multi_index 容器必须是唯一的无符号 64 位整数。eosio::multi_index 中的对象容器按主键索引按无符号 64 位整数主键的升序排序。
智能合约无法直接操作存储在硬盘中的数据表,而是需要使用 multi_index 作为中间工具(或者叫容器),每个 multi_index 实例都与一个特定账户的特定数据表进行交互(取决于实例化时的参数)。EOS 智能合约与 EOS 数据库的数据交互如下图所示。

每一个 multi_index 都相当于传统数据库的一个数据表(table),但将传统数据库的行与列的形式改为了单纯的列。也就是说 multi_index 是一个线性排列的表,只有一列,每一行都只存储一个对象。但是一般来说 multi_index 存储的对象都是结构体或者类,里面含有多个成员变量,所以 multi_index 存储数据的灵活性也是不亚于传统数据库的。
我们使用官方的“汽车维修店”示例,我们建立一个数据表,储存每个汽车维修店客户的账户名、保养时间、车辆里程。那么 multi_index 数据表储存的项目中,每个都是如下的结构体:
struct service_rec {
uint64_t pkey; // 主键
account_name customer; // 车主用户名
uint32_t service_date; // 维修保养时间
uint32_t odometer; // 车辆里程
}
在传统数据库中,需要建立一个 4 列的数据表,用来储存每个用户的这个 4 个数据,而 multi_index 的每个数据表只有一列,只存储每个用户的 service_rec 整个结构体即可。下图为 multi_index 数据结构。

多索引迭代器(multi_index iterator),与仅提供键值 (key-value) 存储的其他区块链不同,EOSIO Multi-Index 表允许合约开发人员保存按照各种不同键类型排序的对象集合,这些键类型可以从对象内的数据派生。这使得丰富的检索功能。最多可以定义 16 个二级索引,每个索引都有自己的排序和检索表格内容的方式。
EOSIO 多索引迭代器遵循 C ++ 迭代器通用的模式。所有迭代器都是双向常量,可以是 const_iterator 或 const_reverse_iterator。迭代器可以取消引用以提供对多索引表中的对象的访问。
在 EOS 数据库中,可以将迭代器比喻为一个“电梯”,在整个数据表中上下穿梭。所有对数据的操作必须通过迭代器完成。典型的数据修改过程是这样的:首先使用迭代器的 find()方法,在特定的索引中寻找需要的数据,比如在车主用户名索引中寻找某个用户。迭代器会移动到需要的数据对象上。然后就可以使用迭代器的 modify()方法修改当前迭代器对应的数据。下图为迭代器指向用户 Sue 的情况。

参考
EOS 多索引表 EOS 数据库与持久化 API —— 架构

正文完
 0