zoukankan      html  css  js  c++  java
  • 带数据库的智能合约

    编写使用数据库的智能合约
    前面一直在捣鼓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(), "
    ");
            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(), "
    ");
                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 );
    }

  • 相关阅读:
    JWT与Session的比较
    Java面试-TCP连接及其优化
    Java面试-动态规划与组合数
    探索Redis设计与实现12:浅析Redis主从复制
    探索Redis设计与实现11:使用快照和AOF将Redis数据持久化到硬盘中
    探索Redis设计与实现10:Redis的事件驱动模型与命令执行过程
    探索Redis设计与实现9:数据库redisDb与键过期删除策略
    探索Redis设计与实现8:连接底层与表面的数据结构robj
    探索Redis设计与实现6:Redis内部数据结构详解——skiplist
    探索Redis设计与实现7:Redis内部数据结构详解——intset
  • 原文地址:https://www.cnblogs.com/xiaocongcong888/p/9892714.html
Copyright © 2011-2022 走看看