EOS学习笔记——编写使用数据库的智能合约

编写使用数据库的智能合约

前面一直在捣鼓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 );\
  }
2)

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值