编写使用数据库的智能合约
前面一直在捣鼓EOS网络搭建的相关东西。然而今天比较不走运的是,兴致勃勃的把源码版本升到4.0,在编译的时候如我所猜想的出现了一系列问题,正一筹莫展的时候,导师突然问了我一个关于合约如何操作数据库的问题。没办法,前面没怎么关注这一块,于是乎吞吞吐吐没能回答老师的问题。心想,反正现在源码有问题,搭不了网络,干脆花点时间看看合约的内容。
于是乎,就有了今天的学习笔记,内容如下:
直接上实例合约源码
addressbook.cpp源码:
#include <eosiolib/eosio.hpp>
#include <string>
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)定义结构体
该结构体的成员变量为表的字段,成员函数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));
};
其中宏EOSLIB_SERIALIZE定义如下
#define EOSLIB_SERIALIZE( TYPE, MEMBERS ) \
template<typename DataStream> \
friend DataStream& operator << ( DataStream& ds, const TYPE& t ){ \
return ds BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_MEMBER_OP, <<, MEMBERS );\
}\
template<typename DataStream> \
friend DataStream& operator >> ( DataStream& ds, TYPE& t ){ \
return ds BOOST_PP_SEQ_FOR_EACH( EOSLIB_REFLECT_MEMBER_OP, >>, MEMBERS );\
}