EOS智能合约访问数据库

1 multi-index介绍

EOS的智能合约可以将数据永久存储在区块链数据库中。智能合约通过multi-index接口来与数据库打交道。通过eosio::multi_index智能合约能够写入、读取和修改eosio数据库的数据。eosio::multi_index在概念上和传统数据库的“表(table)”类似,数据“行(rows)”是独立的对象(通常是class对象或struct对象),数据“列(columns)”是对象的成员属性(class或struct的成员属性)。multi_index支持主键(primary key),但必须是唯一的无符号64位整型(uint64_t)。multi_index按主键排序时,使用升序。

创建multi-index表

  • 使用C++类(class)或结构体(struct)定义对象
  • 在class或struct中,定义一个const成员函数:primary_key(),返回uint64_t类型的主键值
  • 确定二级索引(最多支持16个),二级索引不局限于uint64_t,它支持更多类型
  • 为每个二级索引定义extractor,即一个函数,用于从Multi-Index表的函数中获取键,这个函数会被indexed_by(后面会讲)用到

一个完整的multi-index表定义如下:

//@abi table address i64
struct address {
    uint64_t account;
    string name;
    uint64_t phone;
    uint64_t liked;

    //定义address表的主键
    uint64_t primary_key() const { return account; }
    //定义extractor,二级索引是phone
    uint64_t get_phone() const {return phone; }

    //序列化
    EOSLIB_SERIALIZE(address, (account)(name)(phone)(liked))
}

实例化multi-index表

//第一个参数是表名(即address),第二个参数是表对象的类型(address)
typedef multi_index  address_table_type;

// 构造函数,有两个参数uint64_t类型参数:code, scope
// code: 拥有这张multi_index表的账户,该账户拥有对合约数据的读写权限
// scope: code层级内的范围标识符
address_table_type addresses(_self, _self);

使用multi-index表

  • 添加对象到表中用emplace

       const_iterator emplace( unit64_t payer, Lambda&& constructor )

       payer:为新对象使用的存储付费的账户 
       constructor:lambda函数,可以让新创建的对象就地初始化

  • 从表中删除对象用erace

       void erase( const object_type& obj )

      obj:待更新对象的引用

  • modify修改现有对象

     void modify( const object_type &obj, uint64_t payer, Lambda&& updater )

      obj:待更新对象的引用

      payer:为新对象使用的存储付费的账户 

     updater:用于更新目标对象的lambda函数

  •    get查询表中对象

    const object_type& get( uint64_t primary ) const

    primary:主键值

    返回主键对应的对象引用

  •    find查询表中对象

    const object_type& find( uint64_t primary ) const

    primary:主键值

    返回主键对应的对象引用

2 multi-index使用示例

这个例子用来维护一个todolist的数据库表。直接上代码如下:

#include 
#include 

class todolist : public eosio::contract
{
  public:
    using eosio::contract::contract;
    // @abi table todos i64
    struct todo
    {
        uint64_t id;             // 待办事项主键id
        std::string description; // 待办事项的描述参数
        uint64_t completed;      // 标记一个待办事项是否已完成

        uint64_t primary_key() const { return id; }
        EOSLIB_SERIALIZE(todo, (id)(description)(completed))
    };

    typedef eosio::multi_index todo_table;

    // @abi action
    void create(account_name author, const uint32_t id, const std::string &description)
    {
        todo_table todos(_self, author);
        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)
    {
        todo_table todos(_self, author);
        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)
    {
        todo_table todos(_self, author);
        auto todo_lookup = todos.find(id);
        todos.erase(todo_lookup);

        eosio::print("todo#", id, " destroyed");
    }
};

EOSIO_ABI(todolist, (create)(complete)(destroy))

编译该智能合约。

~/eos_contract/multi_index$ sudo eosiocpp -o multi_index.wast multi_index.cpp 
lzj@lzj-VirtualBox:~/eos_contract/multi_index$ sudo eosiocpp -g multi_index.abi multi_index.cpp 
2018-12-04T07:52:20.770 thread-0   abi_generator.hpp:68          ricardian_contracts  ] Warning, no ricardian clauses found for todolist

2018-12-04T07:52:20.770 thread-0   abi_generator.hpp:75          ricardian_contracts  ] Warning, no ricardian contract found for create

2018-12-04T07:52:20.770 thread-0   abi_generator.hpp:75          ricardian_contracts  ] Warning, no ricardian contract found for complete

2018-12-04T07:52:20.771 thread-0   abi_generator.hpp:75          ricardian_contracts  ] Warning, no ricardian contract found for destroy

Generated multi_index.abi ...

接下来创建用来发布智能合约的账户accmulti:

~/eos_contract$ cleos create account eosio accmulti EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
executed transaction: 47238b1a8489fff221bd72a7f8cf21e8294fc75bdc2da46acbbd1197f7ec8565  288 bytes  1172 us
#         eosio <= eosio::newaccount            {"creator":"eosio","name":"accmulti","owner":{"threshold":1,"keys":[{"key":"EOS6MRyAjQq8ud7hVNYcfnVP...
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

发布智能合约:

~/eos_contract$ cleos set contract accmulti multi_index -p accmulti
Reading WAST/WASM from multi_index/multi_index.wasm...
Using already assembled WASM...
Publishing contract...
executed transaction: f1127afc36606c40fad5880ac590ff8ef594126c6a652c9a6c5e569e105f63ec  5232 bytes  921 us
#         eosio <= eosio::setcode               {"account":"accmulti","vmtype":0,"vmversion":0,"code":"0061736d01000000016e1260047f7e7f7f0060037f7e7...
#         eosio <= eosio::setabi                {"account":"accmulti","abi":"0e656f73696f3a3a6162692f312e30000404746f646f00030269640675696e7436340b6...
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

创建新条目:

~/eos_contract$ cleos push action accmulti create '["accmulti","1","play basketball"]' -p accmulti
executed transaction: e18fd3d35a61d6b5889f697d7333cae40d2dc1fe5eacbc8dc4a4f2566fbf8add  208 bytes  535 us
#      accmulti <= accmulti::create             {"author":"accmulti","id":1,"description":"play basketball"}
>> todo#1 created
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

查询数据表:

~/eos_contract$ cleos get table accmulti accmulti todos
{
  "rows": [{
      "id": 1,
      "description": "play basketball",
      "completed": 0
    }
  ],
  "more": false
}

这里completed是0,现在通过调用complete函数让其完成:

~/eos_contract$ cleos push action accmulti complete '["accmulti",1]' -p accmulti
executed transaction: 5101e086a02244465211f1a36192d677d9fa96230bc46212c34548c7a6921918  192 bytes  501 us
#      accmulti <= accmulti::complete           {"author":"accmulti","id":1}
>> todo#1 marked as complete
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

再次查询,completed字段已经变为1:

~/eos_contract$ cleos get table accmulti accmulti todos
{
  "rows": [{
      "id": 1,
      "description": "play basketball",
      "completed": 1
    }
  ],
  "more": false
}

再添加俩条记录:

~/eos_contract$ cleos push action accmulti create '["accmulti",2,"go shopping"]' -p accmulti
executed transaction: 16ef3ed34ad3b492ef264de6ed8d8f0bfa6e88a0f31862d6b6762dc80a76c410  208 bytes  1096 us
#      accmulti <= accmulti::create             {"author":"accmulti","id":2,"description":"go shopping"}
>> todo#2 created
warning: transaction executed locally, but may not be confirmed by the network yet    ] 
lzj@lzj-VirtualBox:~/eos_contract$ cleos push action accmulti create '["accmulti",3,"go to swim"]' -p accmulti
executed transaction: 01002f611c889eacf837b9c88625e974553288ec211bc7aa6e7ee02ce4f64a4b  208 bytes  1885 us
#      accmulti <= accmulti::create             {"author":"accmulti","id":3,"description":"go to swim"}
>> todo#3 created
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

查询:

~/eos_contract$ cleos get table accmulti accmulti todos
{
  "rows": [{
      "id": 1,
      "description": "play basketball",
      "completed": 1
    },{
      "id": 2,
      "description": "go shopping",
      "completed": 0
    },{
      "id": 3,
      "description": "go to swim",
      "completed": 0
    }
  ],
  "more": false
}

执行删除操作:

lzj@lzj-VirtualBox:~/eos_contract$ cleos push action accmulti destroy '["accmulti",2]' -p accmulti
executed transaction: 0fdf687a5f4363a90b33c8ab1c08a3ea9448fa6df23d73a23844575009bd5329  192 bytes  489 us
#      accmulti <= accmulti::destroy            {"author":"accmulti","id":2}
>> todo#2 destroyed
warning: transaction executed locally, but may not be confirmed by the network yet    ]

查询,可以看到键位2的数据项已经被删除了:

~/eos_contract$ cleos get table accmulti accmulti todos
{
  "rows": [{
      "id": 1,
      "description": "play basketball",
      "completed": 1
    },{
      "id": 3,
      "description": "go to swim",
      "completed": 0
    }
  ],
  "more": false
}

 

你可能感兴趣的:(EOS)