EOS · 2018年9月13日 1

EOS智能合约-编写、发布、调用、删除

简介

此篇将编写一份以录入资产信息为业务的智能合约,包含创建、通过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.cdtGitHub

$ 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智能合约-编写、发布、调用、删除