我们上篇文章中讲到完成一个Dapp的搭建需要两个主要的部分,即智能合约的编写以及前段的构建,今天我们首先来一步步看智能合约中主要有哪些内容以及是如何编写的。
在智能合约中,数据的存储是较为重要的一环,我们在做源码分析的时候都知道数据是存储在Multi-Index(多索引表)里面的,本文将介绍如何创建一个多索引表以及如何通过action来更新表中的内容的,同时我们引入了智能合约中使用的ABI的概念。
1、第二课
在元素战争游戏中,我们需要存储玩家的游戏状态、细节等信息,在这里我们使用eos系统中的Multi-index来实现,对于不太熟悉boost multi-index的朋友们来说,你可以简单的把multi-idnex想象成一个关系型数据库,知道他是用来存储数据的就可以了。如何来创建一个多索引表呢?
1、首先让我们来创建一个用户信息表user_info,user_info中包含了以下内容:
- 用户名
- 赢的次数(初始化为0)
- 输的次数(初始化为0)
用户名是一个uint64的account_name类型,而赢的次数和输的次数均为int整型。为了查询我们存储的数据,我们还需要定义一个类似主键的东西,我们称之为primary_key()。primary_key()需要实现,返回当前用户名即可。
代码语言:javascript复制 // @abi table users
struct user_info {
account_name name;
uint16_t win_count = 0;
uint16_t lost_count = 0;
auto primary_key() const { return name; }
};
2、然后我们typedef一个名为users_table,在这里需要主要user_info要和上一步定义的结构体名一样,不然编译就会失败。我们的typedef包含两部分内容
- 表名
- 刚声明的结构体的名
typedef eosio::multi_index<N(users), user_info> users_table;
3、声明一个多索引变量
代码语言:javascript复制users_table _users;
4、在构造函数中初始化这个变量
那么这一系列的操作中主要包含哪些信息呢:
- code(合约账户名),_users(self,self),提供了code和scope
- scope
- table name,N(user)提供了表名
- primary key,primary_key()返回了主键信息
此处需说明:上面声明的一个表适用于整个智能合约范围内。
多索引表定义号之后,我们来尝试使用login这个action来更新多索引表,login这个action是为了验证用户是否有权限登陆元素战争的,因此我们需要使用require_auth()这个函数来获取用户相应的权限,如果玩家是第一次玩这个游戏,我们就需要在多索引表中创建这个用户的相关信息。
代码语言:javascript复制//声明
void login(account_name username);
//实现
void cardgame::login(account_name username) {
// Ensure this action is authorized by the player
require_auth(username);
// Create a record in the table if the player doesn't exist in our app yet
auto user_iterator = _users.find(username);
if (user_iterator == _users.end()) {
user_iterator = _users.emplace(username, [&](auto& new_user) {
new_user.name = username;
});
}
}
接下来再来看ABI,ABI定义了我们智能合约中的数据结构和action的信息,因此在部署智能合约之前我们需要创建一个和我们智能合约对应的ABI文件,eos官方已经提供了一个自动化生成ABI文件的工具--eosiocpp。eosiocpp可以检测到我们ABI中的信息,为了规范我们需要再表名之前写上@abi table table_name (此处需特别注意),不然就会出现表中数据查询为空的情况,感兴趣的朋友也可以试一下,这和我们平时的注释内容是有区别的哦。在开发者指引手册中有详细的介绍ABI的文件生成
https://developers.eos.io/eosio-cpp/v1.2.0/docs/abi
以及如何手写一个ABI文件
https://developers.eos.io/eosio-cpp/v1.2.0/docs/how-to-write-an-abi
每个action均需使用EOSIO_ABI来包含,不然在部署完合约之后使用push action的时候会提示你该action不存在,如下:
代码语言:javascript复制EOSIO_ABI(cardgame, (login))
然后使用eosiocpp命令来生成ABI文件如下:
代码语言:javascript复制eosiocpp -g cardgame.abi cardgame.cpp
至此,我们便完成了简单的智能合约的编写,更多的功能实现会再接下来的文章中介绍,同时智能合约的部署、前端和智能合约之间的通信也会一步步进行。