本文共 9458 字,大约阅读时间需要 31 分钟。
原文链接:
智能合约操作链数据库是很常见的应用场景。EOS提供了专门的工具来做这件事(相当于Ethereum的leveldb),专业术语叫做持久化API,本文将完整严密地介绍这个工具以及对它的使用测试。
关键字:EOS,智能合约,链数据库,eosio::multi_index,constructor,emplace,erase,find。
首先来看EOS中智能合约涉及到持久化的场景需求。一个action在执行时会有上下文变量出现,包括事务机制的处理,这些内容会应用链上分配的内存资源,而如果没有持久化技术,执行超过作用域时就会丢失掉这些上下文数据。因此要使用持久化技术将关键内容记录在链数据库中,任何时候使用都不受影响。持久化技术应该包括:
这是模仿boost::multi_index开发的一套库。它使用C++编写,提供了合约与数据库的交互持久化接口。
Multi-Index Iterators:不同于其他key-value数据库,multi_index提供了不同类型的key对应的值也是可迭代的复杂集合类型。
创建表
使用Multi-Index表
一般来讲,对数据库的操作无外乎增删改查,
下面我们通过一个智能合约操作底层数据库的实例,来演示对持久化api,multi_index的使用。过程中,也会展示相应api的定义。
首先,创建一个service表,用来创建服务记录报告,它包含的字段有:
#includeusing namespace eosio;class vehicle : public eosio::contract {public: /// @abi table struct service_rec { uint64_t pkey; account_name customer; uint32_t service_date; uint32_t odometer; auto primary_key() const { return pkey; } account_name get_customer() const { return customer; } EOSLIB_SERIALIZE(service_rec, (pkey)(customer)(service_date)(odometer)) }; typedef multi_index service_table_type; using contract::contract; /// @abi action void exec(account_name owner, account_name customer) { print("Hello, ", name{customer}); service_table_type service_table(current_receiver(), owner);// 构造器,第一个参数是code代表表的拥有者,目前是current_receiver(),也可以使用contract基类的构造器初始化时的账户名_self,第二个参数是scope,在代码层次范围的标识符,这里就使用传入的owner账户。 uint64_t pkeyf;// 主键 service_table.emplace(owner, [&](auto &s_rec) { s_rec.pkey = service_table.available_primary_key();// 主键自增 pkeyf = s_rec.pkey; print(pkeyf);// 打印主键内容 s_rec.customer = customer; s_rec.service_date = 2000; s_rec.odometer = 1000; }); service_rec result = service_table.get(pkeyf); print("_", result.pkey); print("_", result.customer); print("_", result.service_date); print("_", result.odometer); }};EOSIO_ABI(vehicle, (exec))
使用eosiocpp工具生成abi文件和wast文件。
<br/>eosiocpp -g vehicle.abi vehicle.cpp | eosiocpp -o vehicle.wasm vehicle.cpp<br/>
然后在终端中部署该合约,<br/>cleos set contract one work/CLionProjects/github.com/eos/contracts/vehicle <br/>
调用合约的exec方法,并输出结果: liuwenbin@liuwenbin-H81M-DS2:~$ cleos push action one exec '["one","two"]' -p oneexecuted transaction: 3a45eaeb06732ad0c53ba7b157003e1c503f74ed447029d82cecbe12926cc9a9 112 bytes 365 us# one <= one::exec {"owner":"one","customer":"two"}>> Hello, two13_13_14927180964919508992_2000_1000warning: transaction executed locally, but may not be confirmed by the network yet
通过输出结果,可以知道主键为13,customer账户名被转为无符号32位整型数据14927180964919508992,服务时间为2000,里程表为1000。我们已经成功将数据存入了multi_index并取了出来。
删除的话可以通过service_table.erase(result);来删除掉对应记录。find涉及二级索引,迭代器等操作,end判断等multi_index的api操作没有给出具体实例,未来在其他合约使用时会直接说明。
为了更好的熟悉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))
这里加入了对数据的增删改查功能。然后我们使用
<br/>eosiocpp -o todolist.wast todolist.cpp && eosiocpp -g todolist.abi todolist.cpp<br/>
创建对应的abi和wast文件。接下来创建用户todo.user, liuwenbin@liuwenbin-H81M-DS2:~$ cleos create account eosio todo.user EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CVexecuted transaction: 7d7191e2935c6fd0024f571e228ee11d51f4f44a64ed2ce977326fb27679f0c6 200 bytes 174 us# eosio <= eosio::newaccount {"creator":"eosio","name":"todo.user","owner":{"threshold":1,"keys":[{"key":"EOS6MRyAjQq8ud7hVNYcfnV...warning: transaction executed locally, but may not be confirmed by the network yet
部署合约,
liuwenbin@liuwenbin-H81M-DS2:~$ cleos set contract todo.user work/VSCode-Projects/eos/contracts/todolist -p todo.userReading WAST/WASM from work/VSCode-Projects/eos/contracts/todolist/todolist.wasm...Using already assembled WASM...Publishing contract...executed transaction: 03befa58d6a54970db708beaa0520179277b01addf1ec647a76a9b3f6459ff57 5128 bytes 2203 us# eosio <= eosio::setcode {"account":"todo.user","vmtype":0,"vmversion":0,"code":"0061736d01000000016e1260047f7e7f7f0060037f7e...# eosio <= eosio::setabi {"account":"todo.user","abi":{"types":[],"structs":[{"name":"todo","base":"","fields":[{"name":"id",...warning: transaction executed locally, but may not be confirmed by the network yet
创建新条目,
liuwenbin@liuwenbin-H81M-DS2:~$ cleos push action todo.user create '["todo.user",1,"hello, world"]' -p todo.userexecuted transaction: 54d9825971370a242fa51fa7cc587a6478dd7852039c263d91058c6b1163a4bc 120 bytes 336 us# todo.user <= todo.user::create {"author":"todo.user","id":1,"description":"hello, world"}>> todo#1 created
查询,
liuwenbin@liuwenbin-H81M-DS2:~$ cleos get table todo.user todo.user todos{ "rows": [{ "id": 1, "description": "hello, world", "completed": 0 } ], "more": false}
完成事项,
liuwenbin@liuwenbin-H81M-DS2:~$ cleos push action todo.user complete '["todo.user",1]' -p todo.userexecuted transaction: 11423637cb321969961b3ce0305c93ba7f95a83b6d82c1a4e31a08c569f2dcaa 104 bytes 312 us# todo.user <= todo.user::complete {"author":"todo.user","id":1}>> todo#1 marked as completewarning: transaction executed locally, but may not be confirmed by the network yet
再次查询,completed字段已置为1,
liuwenbin@liuwenbin-H81M-DS2:~$ cleos get table todo.user todo.user todos{ "rows": [{ "id": 1, "description": "hello, world", "completed": 1 } ], "more": false}
创建多条记录,
liuwenbin@liuwenbin-H81M-DS2:~$ cleos push action todo.user create '["todo.user",2,"eos funk"]' -p todo.userexecuted transaction: 35f417a4d7438e6ea9ffd837e3c261fca0cb3926b534dc6603fdb38f94d5cd77 120 bytes 329 us# todo.user <= todo.user::create {"author":"todo.user","id":2,"description":"eos funk"}>> todo#2 createdwarning: transaction executed locally, but may not be confirmed by the network yetliuwenbin@liuwenbin-H81M-DS2:~$ cleos push action todo.user create '["todo.user",10,"go to bank"]' -p todo.userexecuted transaction: cd4cd2c85500e93a79eb5c3b3852a0a96a9fb220696c63f2683b473d58a6ca34 120 bytes 311 us# todo.user <= todo.user::create {"author":"todo.user","id":10,"description":"go to bank"}>> todo#10 createdwarning: transaction executed locally, but may not be confirmed by the network yet
查询,
liuwenbin@liuwenbin-H81M-DS2:~$ cleos get table todo.user todo.user todos{ "rows": [{ "id": 1, "description": "hello, world", "completed": 1 },{ "id": 2, "description": "eos funk", "completed": 0 },{ "id": 10, "description": "go to bank", "completed": 0 } ], "more": false}
删除一条数据,
liuwenbin@liuwenbin-H81M-DS2:~$ cleos push action todo.user destroy '["todo.user",2]' -p todo.userexecuted transaction: c87e37f4521e0ce2a865acbeb63c0f3a0681b9b5a0a6c5db8cd53584d6d13dca 104 bytes 2198 us# todo.user <= todo.user::destroy {"author":"todo.user","id":2}>> todo#2 destroyedwarning: transaction executed locally, but may not be confirmed by the network yet
再次查询,
liuwenbin@liuwenbin-H81M-DS2:~$ cleos get table todo.user todo.user todos{ "rows": [{ "id": 1, "description": "hello, world", "completed": 1 },{ "id": 10, "description": "go to bank", "completed": 0 } ], "more": false}
这是一个完整的,通过multi_index进行curd的一个例子(第一个例子是官方文档给出的,其中内容有bug)。
通过本篇文章的学习,我们掌握了如何在EOS中使用智能合约调用multi_index实现数据的持久化。
转载于:https://blog.51cto.com/13625500/2329663