美文网首页公信宝
公信宝智能合约编写讲义

公信宝智能合约编写讲义

作者: 剑有偏锋 | 来源:发表于2019-02-27 20:29 被阅读41次

    大家好,我是币须达摩团队的smith,今天给大家展示公信链上的智能合约如何编写,在这节课中已做一个任务列表为案例(todolist)

    一 智能合约

    首先介绍一下智能合约,智能合约是尼克萨博提出的,那么长一段的定义。对开发者的定义是,安全环境下的能持续运行的持续性脚本。

    它有三个属性
    1 合约被编写为区块链中的代码,在区块链中,但合约账本是公开账本。
    2 当到达触发事件,合同根据条件自行执行。
    3 监管人员可以使用区块链来了解市场中的活动,同时保持各个参与者的隐私

    自动售货机就是智能合约的鼻祖,拥有硬币的人都可用购买物品,相对安全的执行环境。

    二 需求

    好了合约的概念讲完了。我们就通过公信链的智能合约,做个todolist,需求就是新增,删除,完成任务条目。

    三 环境准备

    @@@@发送 我把相关链接发到下面

    1 下载智能合约IDE
    https://github.com/gxchain/gxchain-alpha/releases/latest
    2 注册测试账户
    https://testnet.wallet.gxchain.org/#/
    3 认领测试网代币
    https://testnet.gxchain.org/gxc/get_token?init0
    4 测试网区块浏览器
    https://testnet.explorer.gxchain.org/#/account/damo-test

    5 我们使用ide是用测试环境,看这篇文章 《智能合约IDE的用法》
    https://docs.gxchain.org/zh/contract/deploy.html#%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6ide%E6%96%B9%E5%BC%8F

    四 智能合约基本结构-解析helloworld

    大家下载的功夫,我们看看智能合约的基本结构
    1

    1  #include <graphenelib/contract.hpp>   =》智能合约的父类 
    2  #include <graphenelib/dispatcher.hpp> =》事务分发相关,GRAPHENE_ABI就在这定义   
    @@@展示下GRAPHENE_ABI位置
    3  #include <graphenelib/print.hpp> =》打印日志相关
    4  #include <graphenelib/types.h>    =》合约用到的基本数据类型
    5  #include <graphenelib/multi_index.hpp> =》多索引容器,
    @@@@展示下迭代器和增删改的接口位置
    using namespace graphene; 
    
    6  class todolist : public contract=>然后接下来是定义合约类,需要继承合约contract,这就是contract的定义.仅定义了_self    
    @@@@@展示下contract.hpp的定义
    
    
    7 ///@abi action /// 给action加注释,方便导出abi, ABI(Application Binary Interface): 应用程序二进制接口 .描述了合约的接口,数据类型等
    
    void hi(std::string user)然后是action名称要符合规范小于等于12位,a~z 1~5构成,即这里的hi函数名
    
    8 GRAPHENE_ABI(helloworld, (hi))   // 实现apply函数接口,公信链把事务分发给对应合约处理
    

    五 好了,大家对一个基本合约的构造已经了解了,

    然后看多索引表的基本结构

    //@abi table todo i64    // 给加入abi注释,方便导出abi
          struct todo{
              uint64_t id;                          //定义主键成员
    
              std::string description;    //我们写todolist的内容
              uint64_t completed;        //
              
              uint64_t primary_key() const {return id;} //定义一级索引函数,这个函数的函数名和类型都是固定的,不能改动(大家可以查查公信链给的样例,每个合约都有这个函数定义),用于指定唯一主键,这里把id作为主键
              GRAPHENE_SERIALIZE(todo, (id)(description)(completed)) //序列化和反序列号table成员。
          };
          
          typedef multi_index<N(todo), todo> todo_index;//定义多索引容器类型,一个是table名称,一个是多索引表的类型
          todo_index todos; //定义成员多索引容器对象,需要在构造函数中用todos(_self, _self)初始化=》code,scope=>code默认指合约用户id,scope即范围,可以和code一样,或调用者的用户id
    

    @@@@我们这就新建一个合约,以hello为模板,工程名叫todoadv吧
    <1 删去他的hi函数
    <2 删去他的GRAPHENE_ABI宏的action定义
    <3 引用multi_index.hpp 头文件

    #include <graphenelib/multi_index.hpp>
    #include <graphenelib/system.h> //断言相关
    #include <graphenelib/global.h>//获取区块链信息相关
    

    总的

    #include <graphenelib/contract.hpp>
    #include <graphenelib/dispatcher.hpp>
    #include <graphenelib/print.hpp>
    #include <graphenelib/types.h>
    #include <graphenelib/multi_index.hpp>
    #include <graphenelib/system.h>
    #include <graphenelib/global.h>
    

    <4 替换helloworld为todolist
    把我们的table定义拷进去,在构造函数下面初始化todos(_self, _self)

      private:
          //@abi table todo i64 
          struct todo{
              uint64_t id;
              std::string description;
              uint64_t completed;
              
              uint64_t primary_key() const {return id;}
              GRAPHENE_SERIALIZE(todo, (id)(description)(completed))
          };
          
          typedef multi_index<N(todo), todo> todo_index;
          todo_index todos;
    

    在构造函数下面初始化todos(_self, _self)

    六 多索引表增删改的接口原型,都在multi_index.hpp

    1 增加操作
    这里还有三个知识点
    《1 执行emplace要指定资源付费人,payer是合约资源付费人,
    写self就是合约用户本身付费,
    交易发起交易人付费,可以取 get_trx_sender();
    《2 后面是lamda表达式,这个即引用传值[&]和引用调用auto&todo
    《3 available_primary_key,即multi_index提供的,获取当前表的下一个可用主键值
    @@@@@@然后编写在ide编写增加操作接口,复制进去,编译下没问题

        /// @abi action
        void create(const std::string& description){
            uint64_t sender = get_trx_sender();
            todos.emplace(sender, [&](auto& todo){
                todo.id = todos.available_primary_key();
                todo.description = description;
                todo.completed = 0;
            });
        }
    

    2 查询删除操作
    删除操作比较简洁,erase即可。需要先判断索引是否存在
    find函数,即返回满足查询条件的索引
    @@@@@@然后再ide编写查询删除接口,复制进去,编译下没问题

        /// @abi action
        void destory(const uint32_t id){
            auto it = todos.find(id);
            graphene_assert(it != todos.end(), "todo does not exist!");
            todos.erase(it);
            
            print("todo#", id, " destory");
        }
    

    3 查询修改操作
    修改操作的化,即modify传要修改的索引,付费用户id,和lambda表达式。
    给变量赋值即可,也是需要先查询索引是否存在
    @@@@@@然后再ide编写查询修改接口,复制进去,编译下没问题

        /// @abi action
        void complete(const uint32_t id){
            auto it = todos.find(id);
            graphene_assert(it != todos.end(), "todo does not exist!");
            
            if ( 0 == it->completed) {
                uint64_t sender = get_trx_sender();
                todos.modify(it,sender, [&](auto& todo){
                    todo.completed = 1;
                });
                
                print("todo#", id, " complete");
            }
        }
    

    查询有四个函数,大家根据情况调用即可。begin和end大家使用容器也接触比较多
    有find
    lower_bound
    upper_bound
    get

    合约编写完了,我就就编译部署上区块链吧
    @@@
    编译部署好了,我们看看区块链浏览器的数据

    现在是部署合约,如果合约有更新,就重新编译下,按一下这里的刷新按钮。
    比如我们新增一个t action

    /// @abi action
      void t(){
          print("hello#", id, " complete");
      }
    

    再这个api宏后面加action名称
    GRAPHENE_ABI(todolist, (create)(complete)(t))

    好了,合约部分讲完,我们讲下合约和前端交互

    七 前端和智能合约交互

    需要下载前端的代码,这里用到react和gscatter
    @@@@@@发送链接
    https://github.com/dharmachain/gxc-todolist

    gscatter-js使用的demo可以参考这里。gscatter-js主要负责账户相关功能(保存私钥和授权等)
    https://github.com/gxchain/gscatter-js/tree/master/mock-sites

    api的使用,,文档在这里(我们用到了两个api,分别是获取table的数据getTableObjects,以及调用合约的参数callContract)
    https://gxchain.github.io/gxclient-node/api/

    原型就是如下所示
    主要用到了 https://gxchain.github.io/gxclient-node/api/#contract-api
    《1 getTableObjects 获取合约table数据
    getTableObjects(contract_name, table_name, start, limit) ⇒ Promise.<any>

    《2 callContract 调用合约
    callContract(contract_name, method_name, params, amount_asset, broadcast) ⇒ Promise.<any>

    前端我们写好了,安装好了,我们就跑一下
    npm run start运行
    看跑起来了, 点击完成,然后刷新区块浏览器
    删除个试试, 点击完成,然后刷新区块浏览器
    完成个任务试试, 点击完成,然后刷新区块浏览器

    最后

    ok,课程讲完了,更详细的学习资源,大家可用看一下链接,谢谢大家
    最后,可用加入公信链开发者群, 夜神舞可以给入群指引

    https://docs.gxchain.org/zh/contract/ 官方文档
    https://mp.weixin.qq.com/s/HZ-_pJ5gvjGjPpQtBEI98A 官方视频教程《简介与运行原理》
    https://mp.weixin.qq.com/s/xtmxOPI9YAUrJkgsBcPR5A 官方视频教程 《内置数据类型与持久化存储》
    https://mp.weixin.qq.com/s/2WE2D0orGQWi3XxQVTtobQ 官方视频教程《火箭入门GXChain开发系列第三篇 | 智能合约内置API介绍、演示》
    https://mp.weixin.qq.com/s/3diKqSiCAuYsy7kpX6nfqw 官方视频教程《火箭入门GXChain开发系列第四篇 | 实战:口令红包合约讲解》
    https://ethfans.org/topics/125 Vitalik 智能合约演讲PPT

    相关文章

      网友评论

        本文标题:公信宝智能合约编写讲义

        本文链接:https://www.haomeiwen.com/subject/yfvhyqtx.html