基于EOS3.0实现todolist上篇-智能合约

环境 ubuntu16.04 64位

一 编写todolist的合约代码

mkdir todo
vim todo.cpp 输入以下合约内容

#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
using namespace eosio;

class todo_contract : public eosio::contract {
public:
    todo_contract(account_name self)
    :eosio::contract(self),
    todos(_self, _self)
    {}

    //@abi action
    void create(account_name author, const uint32_t id, const std::string& description){
        todos.emplace(author, [&](auto& new_todo) {
            new_todo.id = id;
            new_todo.description = description;
            new_todo.completed = 0;
        });
    
        eosio::print("todo#", id, " created");
    }

    //@abi action
    void complete(account_name author, const uint32_t id) {
        auto todo_lookup = todos.find(id);
        eosio_assert(todo_lookup != todos.end(), "Todo does not exist");
        todos.modify(todo_lookup, author, [&](auto& modifiable_todo){
            modifiable_todo.completed = 1;
        });
    
        eosio::print("todo#", id, " marked as complete");
    }

    //@abi action
    void destroy(account_name author, const uint32_t id) {
        auto todo_lookup = todos.find(id);
        todos.erase(todo_lookup);
    
        eosio::print("todo#", id, " destroyed");
    }

private:
    //@abi table todos i64
    struct todo{
        uint64_t id;               //结构体id
        std::string description;   //todolist的描述信息
        uint64_t completed;        //todolist的完成情况,0未完成  1完成
    
        //主键函数
        uint64_t primary_key() const {return id;}
        //声明序列化宏,第一个参数todo为结构体名称   (id)(description)(completed)为结构体内的对象
        EOSLIB_SERIALIZE(todo, (id)(description)(completed))

    };

    typedef eosio::multi_index<N(todos), todo> todo_table; //声明自定义的多索引容器类型; 
    todo_table todos;
};

EOSIO_ABI(todo_contract, (create)(complete)(destroy))

备注:“typedef eosio::multi_index<N(todos), todo> todo_table; //声明自定义的多索引容器类型;
todo_table todos;”声明完成后,可以使用以下功能:

todos.emplace(scope, [&]( auto& g ) { ... }) 添加数据;
todos.find(primary_key) 用关键字查找;
todos.modify(itr, scope, [&]( auto& g ) { ... }) 修改数据;
todos.erase(itr) 删除
todos.begin() 数据起始
todos.end() 数据末尾

二 运行eos客户端,启动私有网络

nodeos -e -p eosio --plugin eosio::wallet_api_plugin --plugin eosio::chain_api_plugin --plugin eosio::account_history_api_plugin

eosio generated block bcc817bc... #637 @ 2018-05-10T09:22:13.000 with 0 trxs, lib: 636
eosio generated block 527d07ae... #638 @ 2018-05-10T09:22:13.500 with 0 trxs, lib: 637

三 编译合约

eosiocpp -o todo.wast todo.cpp && eosiocpp -g todo.abi todo.cpp

In file included from todo.cpp:1:
In file included from /usr/local/include/eosiolib/eosio.hpp:7:
In file included from /usr/local/include/eosiolib/action.hpp:7:
In file included from /usr/local/include/eosiolib/datastream.hpp:9:
In file included from /home/li/opt/boost_1_66_0/include/boost/container/flat_map.hpp:26:
In file included from /home/li/opt/boost_1_66_0/include/boost/container/new_allocator.hpp:24:
/home/li/opt/boost_1_66_0/include/boost/container/throw_exception.hpp:56:21: warning: 
      address of array 'msg' will always evaluate to 'true'
      [-Wpointer-bool-conversion]
      BOOST_ASSERT(!msg);
                   ~^~~
/home/li/opt/boost_1_66_0/include/boost/assert.hpp:60:36: note: expanded from
      macro 'BOOST_ASSERT'
# define BOOST_ASSERT(expr) assert(expr)
                                   ^~~~
/usr/local/include/musl/upstream/include/assert.h:8:28: note: expanded from
      macro 'assert'
#define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__, ...
                           ^
In file included from todo.cpp:1:
In file included from /usr/local/include/eosiolib/eosio.hpp:7:
In file included from /usr/local/include/eosiolib/action.hpp:7:
In file included from /usr/local/include/eosiolib/datastream.hpp:9:
In file included from /home/li/opt/boost_1_66_0/include/boost/container/flat_map.hpp:26:
In file included from /home/li/opt/boost_1_66_0/include/boost/container/new_allocator.hpp:24:
/home/li/opt/boost_1_66_0/include/boost/container/throw_exception.hpp:64:25: warning: 
      address of array 'msg' will always evaluate to 'true'
      [-Wpointer-bool-conversion]
      BOOST_ASSERT_MSG(!msg, str);
                       ~^~~
/home/li/opt/boost_1_66_0/include/boost/assert.hpp:61:46: note: expanded from
      macro 'BOOST_ASSERT_MSG'
# define BOOST_ASSERT_MSG(expr, msg) assert((expr)&&(msg))
                                             ^~~~
/usr/local/include/musl/upstream/include/assert.h:8:28: note: expanded from
      macro 'assert'
#define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__, ...
                           ^
In file included from todo.cpp:1:
In file included from /usr/local/include/eosiolib/eosio.hpp:7:
In file included from /usr/local/include/eosiolib/action.hpp:7:
In file included from /usr/local/include/eosiolib/datastream.hpp:9:
In file included from /home/li/opt/boost_1_66_0/include/boost/container/flat_map.hpp:26:
In file included from /home/li/opt/boost_1_66_0/include/boost/container/new_allocator.hpp:24:
/home/li/opt/boost_1_66_0/include/boost/container/throw_exception.hpp:72:25: warning: 
      address of array 'msg' will always evaluate to 'true'
      [-Wpointer-bool-conversion]
      BOOST_ASSERT_MSG(!msg, str);
                       ~^~~
/home/li/opt/boost_1_66_0/include/boost/assert.hpp:61:46: note: expanded from
      macro 'BOOST_ASSERT_MSG'
# define BOOST_ASSERT_MSG(expr, msg) assert((expr)&&(msg))
                                             ^~~~
/usr/local/include/musl/upstream/include/assert.h:8:28: note: expanded from
      macro 'assert'
#define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__, ...
                           ^
In file included from todo.cpp:1:
In file included from /usr/local/include/eosiolib/eosio.hpp:7:
In file included from /usr/local/include/eosiolib/action.hpp:7:
In file included from /usr/local/include/eosiolib/datastream.hpp:9:
In file included from /home/li/opt/boost_1_66_0/include/boost/container/flat_map.hpp:26:
In file included from /home/li/opt/boost_1_66_0/include/boost/container/new_allocator.hpp:24:
/home/li/opt/boost_1_66_0/include/boost/container/throw_exception.hpp:80:25: warning: 
      address of array 'msg' will always evaluate to 'true'
      [-Wpointer-bool-conversion]
      BOOST_ASSERT_MSG(!msg, str);
                       ~^~~
/home/li/opt/boost_1_66_0/include/boost/assert.hpp:61:46: note: expanded from
      macro 'BOOST_ASSERT_MSG'
# define BOOST_ASSERT_MSG(expr, msg) assert((expr)&&(msg))
                                             ^~~~
/usr/local/include/musl/upstream/include/assert.h:8:28: note: expanded from
      macro 'assert'
#define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__, ...
                           ^
In file included from todo.cpp:1:
In file included from /usr/local/include/eosiolib/eosio.hpp:7:
In file included from /usr/local/include/eosiolib/action.hpp:7:
In file included from /usr/local/include/eosiolib/datastream.hpp:9:
In file included from /home/li/opt/boost_1_66_0/include/boost/container/flat_map.hpp:26:
In file included from /home/li/opt/boost_1_66_0/include/boost/container/new_allocator.hpp:24:
/home/li/opt/boost_1_66_0/include/boost/container/throw_exception.hpp:88:25: warning: 
      address of array 'msg' will always evaluate to 'true'
      [-Wpointer-bool-conversion]
      BOOST_ASSERT_MSG(!msg, str);
                       ~^~~
/home/li/opt/boost_1_66_0/include/boost/assert.hpp:61:46: note: expanded from
      macro 'BOOST_ASSERT_MSG'
# define BOOST_ASSERT_MSG(expr, msg) assert((expr)&&(msg))
                                             ^~~~
/usr/local/include/musl/upstream/include/assert.h:8:28: note: expanded from
      macro 'assert'
#define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__, ...
                           ^
5 warnings generated.
Generated todo.abi ...

四 部署合约

cleos set contract bytemaster ../todo -p bytemaster

Reading WAST...
Assembling WASM...
Publishing contract...
executed transaction: d1713c2589a8fffe5a54b7312dc10aff3b9e45cc74ec8f9556616213a86d7747  4712 bytes  2200576 cycles
#         eosio <= eosio::setcode               {"account":"bytemaster","vmtype":0,"vmversion":0,"code":"0061736d01000000017e1460047f7e7f7f0060037f7...
#         eosio <= eosio::setabi                {"account":"bytemaster","abi":{"types":[],"structs":[{"name":"todo","base":"","fields":[{"name":"id"...

注意:
(1)如钱包锁定,请使用命令解锁“ cleos wallet unlock --password 钱包私钥”,不然提示

Error 3030002: signatures do not satisfy declared authorizations
Ensure that you have the related private keys inside your wallet and you wallet is unlocked.

(2)用户用上一章创建的bytemaster,如未创建,参考《使用EOS3.0发行代币》创建用户。(https://www.jianshu.com/p/596593bd308f

五 调用合约create action

cleos push action bytemaster create '["bytemaster", 1, "hello world Message"]' -p bytemaster

executed transaction: fa3b73feba3475e444be13992403f31161bc39c678f00bdb060ae26e30dce8ff  256 bytes  106496 cycles
#    bytemaster <= bytemaster::create           {"author":"bytemaster","id":1,"description":"hello world Message"}
>> todo#1 created

获取数据
cleos get table bytemaster bytemaster todos

{
  "rows": [{
      "id": 1,
      "description": "hello world Message",
      "completed": 0
    }
  ],
  "more": false
}

六 总结

(1)了解多索引容器使用,了解数据增删改
(2)了解智能合约编写结构
(3)巩固智能合约编写发布流程

七 引用

https://steemit.com/eos/@eos-asia/part-2-building-a-to-do-list-with-eos-or-working-with-persistent-data-in-eos 《Part 2: Building a To-do list with EOS》

https://mp.weixin.qq.com/s/QVzKIrhYpw7JdrWe38TEJw 《[EOS智能合约]第二节:用EOS开发一个To-do List小应用》

https://github.com/EOSIO/eos/wiki/Persistence-API 《Persistence-API》
https://eosfans.io/wiki/eosiodb 《EOSIO 3.0 数据库使用指南

推荐阅读更多精彩内容