摘要:这里的是封装的,返回中,当前索引的迭代器之后遍历该迭代器,就可以获得所有某个特定值的所有数据。
上一章我们细致地学习了
索引和迭代器的关系;
如何生成和使用索引以及迭代器
介绍了multi_index的相关操作
相信大家对multi_index已经有了比较全面的理论理解以及掌握了一些基础的操作。这一章将会教大家如何完整地构建一个智能合约,并在合约中直观地操作multi_index。
摘要这一章主要以实操为主,会有较大篇幅的代码,希望大家最好可以照着文章自己操作一遍。
这一章将会以一个简单的智能合约例子,简单了解一个完整的EOS智能合约长什么样。希望大家通过这一章的学习,不仅可以有能力构建一个简单的智能合约,并且对multi_index在EOS智能合约中的重要性,会有更加深刻的认识。
头文件:*.hppC++的源代码文件分为两类:头文件(Header file)和源文件(Source code file)。
头文件用于存放对类型定义、函数声明、全局变量声明等实体的声明,作为对外接口;
源程序文件存放类型的实现、函数体、全局变量定义;
我们先来看头文件里的代码:
#include#include #include using namespace eosio; using std::string;
最前面按惯例都是import,接着往下看:
class app : public contract { public: using contract::contract; app(account_name self) : contract(self) {} // @abi action void hello(const account_name account); // @abi action void create(const account_name account, const string& username, uint32_t age, const string& bio); // @abi action void get(const account_name account); // @abi action void update(const account_name account, const string& username, uint32_t age, const string& bio); // @abi action void remove(const account_name account); // @abi action void byage(uint32_t age); // @abi action void agerange(uint32_t young, uint32_t old);
这里定义了源文件里的方法接口,接下来就到了最核心的multi_index的相关定义:
private: // @abi table profile i64 struct profile { account_name account; string username; uint32_t age; string bio; account_name primary_key() const { return account; } uint64_t by_age() const { return age; } EOSLIB_SERIALIZE(profile, (account)(username)(age)(bio)) }; typedef eosio::multi_index< N(profile), profile, // N(name of interface) indexed_by< N(age), const_mem_fun> > profile_table; };
这里定义了multi_index表的结构 (struct profile),主键以及按年龄的索引定义。(上一章详细讲过)
最后再加上EOSIO_ABI的声明:
EOSIO_ABI(app, (hello)(create)(get)(update)(remove)(byage)(agerange))
这里只需要简单地把所有方法串联在一起就可以了。
上述可以看到hpp头文件里的内容很简单,只包含了最简单的变量和接口的声明。而与之配套的*.cpp文件就要复杂一些,里面对这些接口都做了具体的实现。
源文件首先肯定是引用头文件:
#include1. 添加数据void app::hello(account_name account) { print("Hello ", name{account}); }
void app::create(const account_name account, const string& username, uint32_t age, const string& bio) { require_auth(account); profile_table profiles(_self, _self); auto itr = profiles.find(account); eosio_assert(itr == profiles.end(), "Account already exists"); profiles.emplace(account, [&](auto& p) { p.account = account; p.username = username; p.age = age; p.bio = bio; }); }
require_auth语句和以太坊中的require(msg.sender == xxx)类似,都对调用者的身份做了限制。
profile_table是一种类型,可以理解成表示multi_index表,后面的profiles(_self, _self)才是真正构建一个multi_index表的实例。profiles里的两个参数依次就是我们前面提到过的code和scope,分别表示表的拥有账户以及代码层次结构的范围标识符(已经忘记的小伙伴可以翻看上一章内容)。
当profiles表实例化完成之后,紧接着就是插入数据。关于插入数据的操作上一章我们有过详细的介绍,这里就不再赘述了。主要注意防止主键重复的操作。
2. 根据主键获取相关信息void app::get(const account_name account) { profile_table profiles(_self, _self); auto itr = profiles.find(account); eosio_assert(itr != profiles.end(), "Account does not exist"); print("Account: ", name{itr->account}, " , "); print("Username: ", itr->username.c_str(), " , "); print("Age: ", itr->age , " , "); print("Bio: ", itr->bio.c_str()); }
这里也很简单,先把multi_index表实例化,之后要求查询的结果不能为空 (即itr != profiles.end()),如果不为空的话,就返回主键对应的其他字段的信息。
这些操作都是通过我们上一章介绍过的迭代器来完成。
3. 根据主键更新信息void app::update(const account_name account, const string& username, uint32_t age, const string& bio) { require_auth(account); profile_table profiles(_self, _self); auto itr = profiles.find(account); eosio_assert(itr != profiles.end(), "Account does not exist"); profiles.modify(itr, account, [&](auto& p) { p.username = username; p.age = age; p.bio = bio; }); }
和之前的操作类似,确保主键不为空的情况下,更新该主键对应的其他字段的信息。
4. 根据主键删除数据void app::remove(const account_name account) { require_auth(account); profile_table profiles(_self, _self); auto itr = profiles.find(account); eosio_assert(itr != profiles.end(), "Account does not exist"); profiles.erase(itr); print(name{account} , " deleted!"); }5. 通过自定义的自定义索引实现查询
前面四个介绍的都是主键相关的增删改查的操作,别忘了我们在上一章中还曾经定义过自定义索引by_age(),即以年龄为条件进行筛选。具体实现如下:
void app::byage(uint32_t age) { print("Checking age: ", age, " "); profile_table profiles(_self, _self); // get an interface to the "profiles" containter // that looks up a profile by its age auto age_index = profiles.get_index(); auto itr = age_index.lower_bound(age); for(; itr != age_index.end() && itr->age == age; ++itr) { print(itr->username.c_str(), " is ", itr->age, " years old "); } }
这里我们使用了在头文件里定义过的名为age的index,重新得到了一张以age排序的multi_index。
这里的lower_bound是EOS封装的API,返回age_index中,当前索引≥age的迭代器;之后遍历该迭代器,就可以获得所有age≥某个特定值的所有数据。
和lower_bound相对应的,就是upper_bound方法,用法和lower_bound类似。如下就实现了同时指定age上下限的查询:
void app::agerange(uint32_t young, uint32_t old) { profile_table profiles(_self, _self); auto age_index = profiles.get_index合约部署(); auto begin = age_index.lower_bound(young); auto end = age_index.upper_bound(old); for_each(begin, end, [&](auto& p) { print(p.username.c_str(), " is ", p.age, " years old "); }); }
把前文中所有的hpp和cpp的代码片段拼接成完整的hpp和cpp文件进行编译:
#使用 -o 生成wast文件和wasm文件 eosiocpp -o ./app.wast ./app.cpp #使用 -g 生成abi文件 eosiocpp -g ./app.abi ./app.cpp
生成wast和abi文件的详细内容我们之前章节介绍过了,这里也不赘述了。这时我们的当前文件夹下会出现app.wast和app.abi文件。
部署合约:
cleos set contract eosio ./ ./app.wast app.abi -p eosio@active
(该命令前文也详细介绍过每个参数的含义,详情参考第五篇)
下图为成功部署合约的画面:
合约调用 1. 查看表内容cleos get table eosio eosio profile
通过上述指令查看表中的内容,参数eosio eosio profile分别表示前文提到过的code、scope和表名。
结果如下图:
因为在头文件里声明过,可以看到该表已存在,但是内容为空。
2. 插入数据执行如下命令往表中插入数据,然后再次查询:
// 插入 cleos push action eosio create "["eosio","hammer","25","programmer"]" -p eosio@active // 再次查询 cleos get table eosio eosio profile
这时就可以看到表中保存了我们刚插入的一条数据。
还记得我们曾经创建过一个叫做testeosio的账户么?我们再使用那个账户往表中插入一条数据(记得先unlock钱包哦):
// 切换账号插入数据 cleos push action eosio create "["testeosio","maggie","23","waitress"]" -p testeosio@active // 查询 cleos get table eosio eosio profile
这时我们可以看到:
数据确实添加进入表中了。
传入数据的第一个参数必须是调用该方法的账户名,还记得代码中的require_auth么?
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/24295.html
摘要:是企业与区块链相遇的地方。的框架旨在成为开发区块链解决方案的支柱。以太坊,主要是针对工程师使用进行区块链以太坊开发的详解。 如果你想将区块链合并到一个Java项目中,现在我们来看看就是这个细分领域中三个最大的OSS玩家。 好的伙计们,我们都听说过比特币,以太坊或其他加密货币,其中有一些时髦的名字围绕着我们常见的新闻,但我们作为Java开发人员知道如何轻松地与这些区块链技术进行交互吗?以...
摘要:我们目前正处于一个新兴的区块链开发行业中。,一种在以太坊开发人员中流行的新的简单编程语言,因为它是用于开发以太坊智能合约的语言。它是全球至少万开发人员使用的世界上最流行的编程语言之一。以太坊,主要是针对工程师使用进行区块链以太坊开发的详解。 我们目前正处于一个新兴的区块链开发行业中。区块链技术处于初期阶段,然而这种颠覆性技术已经成功地风靡全球,并且最近经历了一场与众不同的繁荣。由于许多...
摘要:在新智能合约的构造函数中,将引用我们的合约工厂的地址。以太坊,主要是针对工程师使用进行区块链以太坊开发的详解。以太坊入门教程,主要介绍智能合约与应用开发,适合入门。这里是原文用工厂模式管理多个智能合约 我们写了一份小的计算合约作为Hello World。如果我们可以创建一个允许用户创建自己的计数器的合约怎么办? showImg(https://segmentfault.com/img/...
摘要:许多人正试图学习如何在上开发智能合约。但是,这些智能合约是由编写的,并编译成,这对大多数非程序员来说似乎很奇怪。在这里,你可以将其视为可以在浏览器中加载和运行的文件。将代码编译成的格式编译代码有很多种方法。 许多人正试图学习如何在EOS上开发智能合约。但是,这些智能合约是由C++编写的,并编译成WebAssembly,这对大多数非c++程序员来说似乎很奇怪。因此,在深入了解EOS之前,...
摘要:本文简单的介绍一下如何安装智能合约开发工具包,简称,是与智能合约编制相关的工具集合。对于初学者来说,可以通过使用来编译智能合约和生成。 本文简单的介绍一下如何安装EOS智能合约开发工具包(Contract Development Toolkit),简称CDT,是与智能合约编制相关的工具集合。对于EOSIO初学者来说,可以通过使用CDT来编译智能合约和生成ABI。 从1.3.x开始,CD...
阅读 1690·2021-09-22 10:02
阅读 1933·2021-09-02 15:40
阅读 2837·2019-08-30 15:55
阅读 2248·2019-08-30 15:44
阅读 3595·2019-08-30 13:18
阅读 3228·2019-08-30 11:00
阅读 1947·2019-08-29 16:57
阅读 565·2019-08-29 16:41