编写使用数据库的智能合约
前面一直在捣鼓EOS网络搭建的相关东西。然而今天比较不走运的是,兴致勃勃的把源码版本升到4.0,在编译的时候如我所猜想的出现了一系列问题,正一筹莫展的时候,导师突然问了我一个关于合约如何操作数据库的问题。没办法,前面没怎么关注这一块,于是乎吞吞吐吐没能回答老师的问题。心想,反正现在源码有问题,搭不了网络,干脆花点时间看看合约的内容。
于是乎,就有了今天的学习笔记,内容如下:
直接上实例合约源码
addressbook.cpp源码:
include <eosiolib/eosio.hpp>
include
using eosio::indexed_by;
using eosio::const_mem_fun;
using std::string;
class addressbook : public eosio::contract {
public:
//构造函数
explicit addressbook(action_name self) : contract(self) {}
//添加联系人
//@abi action
void add(const account_name account, const string& name, uint64_t phone) {
//获取授权,如果没有授权,Action调用会中止,事务会回滚
require_auth(account);
//eosio::multi_index(多索引表)可以用来读取和修改EOS数据库
//address_index是自己定义的eosio::multi_index
//实例化address数据表(multi_index),参数用于建立对表的访问权限
//如果访问自己的合约则具有读写权限,访问其他人的合约则具有只读权限
address_index addresses(_self, _self);
//multi_index的find函数通过主键(primary_key)查询数据,返回迭代器itr
//auto关键字会自动匹配类型
auto itr = addresses.find(account);
//如果判断条件不成立,则终止执行并打印错误信息
eosio_assert(itr == addresses.end(), "Address for account already exists");
//添加数据
//使用存储需要付费,第一个参数account是付费的账户
addresses.emplace(account, [&](auto& address){
address.account = account;
address.name = name;
address.phone = phone;
});
}
//修改联系人信息
//@abi action
void update(const account_name account, const string& name, uint64_t phone) {
require_auth(account);
address_index addresses(_self, _self);
auto itr = addresses.find(account);
//如果没有找到account,打印错误信息并终止
eosio_assert(itr != addresses.end(), "Address for account not found");
addresses.modify(itr, account, [&](auto& address){
address.account = account;
address.name = name;
address.phone = phone;
});
}
//删除联系人
//@abi action
void remove(const account_name account) {
require_auth(account);
address_index addresses(_self, _self);
auto itr = addresses.find(account);
eosio_assert(itr != addresses.end(), "Address for account not found");
//删除
addresses.erase(itr);
}
//设置联系人为特别关注
//@abi action
void like(const account_name account) {
//无需获取授权,每个人都可以调用like Action
address_index addresses(_self, _self);
auto itr = addresses.find(account);
eosio_assert(itr != addresses.end(), "Address for account not found");
//修改相应的liked字段
addresses.modify(itr, 0, [&](auto& address){
//打印提示信息
eosio::print("Liking: ", address.name.c_str(), "\n");
address.liked++;
});
}
//功能和like()相同,但通过phone查询数据,而不是主键
//@abi action
void likebyphone(uint64_t phone) {
address_index addresses(_self, _self);
//获取自定义索引
auto phone_index = addresses.get_index<N(phone)>();
auto itr = phone_index.lower_bound(phone);
for(; itr != phone_index.end() && itr->phone == phone; ++itr) {
phone_index.modify(itr, 0, [&](auto& address){
eosio::print("Liking: ", address.name.c_str(), "\n");
address.liked++;
});
}
}
private:
//定义address表,i64表示索引使用默认的uint64_t类型
//@abi table address i64
struct address {
uint64_t account;
string name;
uint64_t phone;
uint64_t liked;
//定义address表的主键,address表是一个multi-index表
uint64_t primary_key() const { return account; }
uint64_t get_phone() const {return phone; }
EOSLIB_SERIALIZE(address, (account)(name)(phone)(liked));
};
//默认通过主键索引,使用indexed_by,可以通过自定义函数进行索引
//这里是get_phone,即通过phone字段进行索引
typedef eosio::multi_index< N(address), address,
indexed_by<N(phone), const_mem_fun<address, uint64_t, &address::get_phone>>>
address_index;
};
EOSIO_ABI(addressbook, (add)(update)(remove)(like)(likebyphone))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
该合约业务逻辑是实现一个通讯录的功能,其中包括增加联系人、更新联系人信息、删除联系人以及将联系人标记为特别关注。
接下来我们来一步步来看该合约是如何实现的。
创建表格
1)定义结构体
该结构体的成员变量为表的字段,成员函数primary_key()定义主键,get_phone()定义二级索引,EOSLIB_SERIALIZE宏定义序列化表字段如下:
struct address {
uint64_t account;
string name;
uint64_t phone;
uint64_t liked;
//定义address表的主键,address表是一个multi-index表
uint64_t primary_key() const { return account; }
uint64_t get_phone() const {return phone; }
EOSLIB_SERIALIZE(address, (account)(name)(phone)(liked));
};
1
2
3
4
5
6
7
8
9
10
11
12
其中宏EOSLIB_SERIALIZE定义如下
define EOSLIB_SERIALIZE( TYPE, MEMBERS ) \
template
friend DataStream& operator << ( DataStream& ds, const TYPE& t ){
return ds BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_MEMBER_OP, <<, MEMBERS );
}
template
friend DataStream& operator >> ( DataStream& ds, TYPE& t ){
return ds BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_MEMBER_OP, >>, MEMBERS );
}