简介
此篇将编写一份以录入资产信息为业务的智能合约,包含创建、通过ID更新、通过user更新三个方法,一个主键,一个索引,来介绍智能合约的编写、发布、调用方面的内容。
智能合约的编写主要还是参考官方C++文档,用eosio的官方合约作为样板逐步掌握。
编写
合约详解请看代码内部注释。
digital_asset.hpp
#include <eosiolib/eosio.hpp>
#include <string>
class digital_asset : public eosio::contract
{
public:
digital_asset(account_name self) : contract(self) {}
/// @abi table cyassets i64
// 在hpp与cpp文件中所有@abi注释都是在供.abi生成时使用,若未写则无法正确生成.abi文件。
struct cyasset
{
cyasset() {}
uint32_t asset_id;
std::string asset_name;
// N()是一个序列化方法,一般用于account
account_name user = N(none);
std::string asset_desc;
uint32_t maximum_supply = 0;
// 定义cyasset的主键,主键类型只能是整形类的,不可为string,可以设定为自增主键
auto primary_key() const { return asset_id; }
// 自定义的索引
account_name user_key() const { return user; }
// 定义struct的序列化和反序列化
EOSLIB_SERIALIZE(cyasset, (asset_id)(asset_name)(user)(asset_desc)(maximum_supply))
};
// 自定义索引需要在这里加入声明,最多16个自定义索引
// eosio::const_mem_fun<"struct", "索引的类型", &cyasset::"索引">>
// 这里即声明了multi_index DB的结构、索引等
typedef eosio::multi_index<N(cyassets), cyasset, eosio::indexed_by<N(second_key), eosio::const_mem_fun<cyasset, account_name, &cyasset::user_key>>> cyassets;
/// @abi action
void create(const uint32_t &asset_id, const std::string &asset_name, const account_name &user, const std::string &asset_desc, const uint32_t &maximum_supply);
/// @abi action
void editbyid(const uint32_t &asset_id, const account_name &user, const uint32_t &maximum_supply);
/// @abi action
void editbyuser(const account_name &user, const uint32_t &maximum_supply);
};
digital_asset.cpp
#include "digital_asset.hpp"
using namespace eosio;
/**
* @brief Apply create action
*/
void digital_asset::create(const uint32_t &asset_id, const std::string &asset_name, const account_name &user, const std::string &asset_desc, const uint32_t &maximum_supply)
{
// 权限验证
require_auth(user);
// 从DB中获取cyassets(table)与testuser(scope)的数据
// _self当前合约名称,account_name类型
// scope是account_name类型
// 不同scope的数据是分开的,主键也是独立的
cyassets existing_user_asset(_self, testuser);
// 通过主键查询,一个object
auto itr = existing_user_asset.find(asset_id);
eosio_assert(itr == existing_user_asset.end(), "asset_id already exists");
// eosio提供的debug方法。。。。就是print打log出来分析
eosio::print("_self:", eosio::name{_self});
// emplace创建一条新数据,这里的testuser为RAM等资源的付费账号
existing_user_asset.emplace(_self, [&](auto &g) {
g.asset_id = asset_id;
g.asset_name = asset_name;
g.user = user;
g.asset_desc = asset_desc;
g.maximum_supply = maximum_supply;
});
}
/**
* @brief Apply editbyid action
*/
void digital_asset::editbyid(const uint32_t &asset_id, const account_name &user, const uint32_t &maximum_supply)
{
require_auth(user);
cyassets edit_user_asset(_self, user);
auto itr = edit_user_asset.find(asset_id);
eosio_assert(itr != edit_user_asset.end(), "asset_id not exists");
eosio_assert(user == itr->user, "this is not your asset");
// 修改数据,_self付费账号
edit_user_asset.modify(itr, _self, [&](auto &g) {
g.maximum_supply = maximum_supply;
});
}
/**
* @brief Apply editbyuser action
*/
void digital_asset::editbyuser(const account_name &user, const uint32_t &maximum_supply)
{
require_auth(user);
cyassets edit_user_asset(_self, user);
// 通过指定的索引查询
auto idx = edit_user_asset.get_index<N(second_key)>();
auto itr = idx.find(user);
eosio_assert(itr != idx.end(), "asset_id not exists");
eosio_assert(user == itr->user, "this is not your asset");
idx.modify(itr, _self, [&](auto &g) {
g.maximum_supply = maximum_supply;
});
}
EOSIO_ABI(digital_asset, (create)(editbyid)(editbyuser))
之后需要使用源码生成.abi和.wams文件,使用官方的eosiocpp
工具即可;不过官方说在未来将会弃用此工具,新的版本将使用eosio.cdt
GitHub。
$ eosiocpp -o digital_asset.wast digital_asset.cpp
$ eosiocpp -g digital_asset.abi digital_asset.cpp
至此部署智能合约前的工作已经完成。
发布
发布智能合约的过程就是提交一笔交易到eos节点上,并上传对应的.wasm与.abi文件。
方便一点可以使用eosjs,它可以自动签名并构造消息,以下是使用eosjs发布合约:
exports.setABI = function (accountName) {
abi = fs.readFileSync("D:\\digital_asset\\digital_asset.abi");
return eos.setabi(accountName, JSON.parse(abi));
};
exports.setCode = function (accountName) {
wasm = fs.readFileSync("D:\\digital_asset\\digital_asset.wasm");
return eos.setcode(accountName, 0, 0, wasm);
};
注意完整的发布合约是setcode
+setabi
,两个步骤虽然是独立分开的,但是如果abi缺少或错误会导致无法查询到multi-index DB的数据等等情况出现。
调用
同样的使用eosjs调用合约
exports.create = function (asset_id, asset_name, user, asset_desc, maximum_supply) {
return eos.transaction({
actions: [{
// 指合约对应的账号名称
account: 'cy.asset',
// 方法名称
name: 'create',
authorization: [{
actor: user,
permission: 'active'
}],
// 参数
data: {
asset_id: asset_id,
asset_name: asset_name,
user: user,
asset_desc: asset_desc,
maximum_supply: maximum_supply,
testuser: "nmaccount"
}
}]
});
};
exports.editbyid = function (asset_id, user, maximum_supply) {
return eos.transaction({
actions: [{
account: 'cy.asset',
name: 'editbyid',
authorization: [{
actor: user,
permission: 'active'
}],
data: {
asset_id: asset_id,
user: user,
maximum_supply: maximum_supply
}
}]
});
};
exports.editbyuser = function (user, maximum_supply) {
return eos.transaction({
actions: [{
account: 'cy.asset',
name: 'editbyuser',
authorization: [{
actor: user,
permission: 'active'
}],
data: {
user: user,
maximum_supply: maximum_supply
}
}]
});
};
由于eos智能合约中没有返回值,所以我们不能通过智能合约查询到我们插入的数据,但是官方提供了一个方法直接查询multi-index DB:
// 使用此方法可以查询到cy.asset合约内,nmaccount与cyassets下的数据
exports.getData = function () {
return eos.getTableRows({
json: true,
code: "cy.asset",
scope: "nmaccount",
table: "cyassets",
// table_key: "asset_id",
lower_bound: 0,
upper_bound: -1,
limit: 10,
// key_type: "i64",
// index_position: 1
});
};
这里的查询使用到了之前生成的.abi文件。
删除
目前官方还没有提出删除智能合约的方法。
但是在操作中,总会出现部署合约到错误的账号上,等等情况;而且合约一旦部署是占用RAM等资源的,如果合约没有人使用那么及时释放这部分RAM也是很有必要的。
所有只有一个方法,就是使用一个空的合约替换掉原有的智能合约,这样原有的资源即可释放;但是要注意释放掉的数据应该是无法恢复的。
(空的只能就是就是想hello word一样,甚至删除print,一个空方法)
.
.
.
.
.
.
.
【本文章出自NM1024.com,转载请注明作者出处。】
>>转载请注明原文链接地址:EOS智能合约-编写、发布、调用、删除
好,很好!