零基础部署测试合约(二)---合约编译
下面演示EOS智能合约编写,实例将涉及对链上多索引(multi_index)的增删改查。
实例为License合约,主要功能为
- 客户设置自己的信息
- 客户创建自己的项目
- 客户购买项目授权
- 验证项目授权
(由于演示二级索引,项目名称为索引唯一,所以实例为用户单项目)
上面的权限都是基于客户自身的权限验证,创建是创建的系统子账户,可用于系统币转账
合约代码基于C++语言,源代码分为源文件(.cpp)和头文件(.hpp)
//License.hpp
#include <eosiolib/asset.hpp>
#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
class License : public eosio::contract {
public:
License( account_name self )
:eosio::contract(self)
,accounts(_self, _self)
,projecttable(_self, _self){}
void setuserinfo(account_name owner, const std::string& company_name, const std::string& contact_info);
void makeproject(account_name owner, const std::string& project_name);
void buylicense(account_name owner, const std::string& project_name);
void testlicense(account_name owner, const std::string& project_name);
private:
//@abi table accounts i64
struct account{
account_name name;
std::string company_name;
std::string contact_info;
uint8_t level;
uint64_t primary_key()const { return name; }
EOSLIB_SERIALIZE(account, (name)(company_name)(contact_info)(level))
};
typedef eosio::multi_index<N(accounts),account> account_table;
account_table accounts;
//@abi table projecttable i64
struct project{
uint32_t pkey;
account_name owner_name;
std::string project_name;
std::string company_name;
std::string contact_info;
uint8_t status;
uint64_t primary_key()const { return pkey; }
uint64_t getowner_name() const{return owner_name;}
EOSLIB_SERIALIZE(project, (pkey)(owner_name)(project_name)(company_name)(contact_info)(status))
};
//contracts/eosiolib/multi_index.hpp
//multi_index用于封装智能合约对数据库的管理,增、删、改、查
//eosio::multi_index<N(表名),数据类型>
//一个multi_index最多支持16个二级索引
//定义二级索引使用eosio::indexed_by模板。N(byowner_name)为索引的名称
//project表数据类型,uint64_t索引类型即索引函数返回的类型(只支持uint64_t,uint128_t,double,long double,key256类型),&project::getowner_name索引函数。
typedef eosio::multi_index<N(projecttable),project, eosio::indexed_by<N(byowner_name), eosio::const_mem_fun<project, account_name, &project::getowner_name> >> projecttable_type;
projecttable_type projecttable;
};
EOSIO_ABI(License, (setuserinfo)(makeproject)(buylicense)(testlicense))
//License.cpp
#include <License.hpp>
void License::setuserinfo(account_name owner, const std::string& company_name, const std::string& contact_info){
eosio::print("License::setuserinfo line 4");
require_auth(owner);
auto account_itr = accounts.find(owner);
if(account_itr == accounts.end()){
account_itr = accounts.emplace(_self, [&](auto& account){
account.name = owner;
account.company_name = company_name;
account.contact_info = contact_info;
});
}
else{
accounts.modify(account_itr, 0, [&](auto& account) {
account.company_name = company_name;
account.contact_info = contact_info;
});
}
}
void License::makeproject(account_name owner, const std::string& project_name){
require_auth(owner);
//二级索引查找
auto customer_index = projecttable.template get_index<N(byowner_name)>();
account_name customer_acct = owner; //如果是string 可以用 eosio::string_to_name 转换
auto cust_itr = customer_index.find(customer_acct);
if (cust_itr != customer_index.end() && cust_itr->owner_name == customer_acct) {
customer_index.modify(cust_itr, 0, [&](auto& project) {
project.project_name = project_name;
project.status = cust_itr->status; //初始化未授权,须另购买
auto account_itr = accounts.find(owner);
if(account_itr != accounts.end()){
project.project_name = project_name;
project.company_name = account_itr->company_name;
project.contact_info = account_itr->contact_info;
}
});
}
else{
auto project_itr = projecttable.emplace(_self, [&](auto& project){
project.owner_name = owner;
project.project_name = project_name;
auto account_itr = accounts.find(owner);
if(account_itr != accounts.end()){
project.company_name = account_itr->company_name;
project.contact_info = account_itr->contact_info;
project.status = 0; //初始化未授权,须另购买
}
});
}
}
void License::buylicense(account_name owner, const std::string& project_name){
require_auth(owner);
bool bFind = false;
//二级索引查找
auto customer_index = projecttable.template get_index<N(byowner_name)>();
account_name customer_acct = owner; //如果是string 可以用 eosio::string_to_name 转换
auto cust_itr = customer_index.find(customer_acct);
while (cust_itr != customer_index.end() && cust_itr->owner_name == customer_acct) {
if(cust_itr->project_name == project_name){
if(cust_itr->status == 0){
//TODO 判断当前账户余额,购买转账等操作
customer_index.modify(cust_itr, 0, [&](auto& project) {
project.status = 1;
});
}
else{
eosio_assert(false, "The current project is authorized" );
}
bFind = true;
break;
}
cust_itr++;
}
eosio_assert(bFind, "owner with project not exists" );
}
void License::testlicense(account_name owner, const std::string& project_name){
require_auth(owner);
bool bFind = false;
for( const auto& project : projecttable ) {
if(project.project_name == project_name && project.owner_name == owner){
eosio_assert((project.status == 1), "The current project is not authorized" );
bFind = true;
break;
}
}
eosio_assert(bFind, "owner with project not exists" );
}