EOS 合约基础教程 - Hello World

经过前面的铺垫,我们终于要开始开发合约了,作为见面礼,本章节,我们先来写一个输出 Hello World 的最简单的合约。

EOS 合约说明

EOS 合约使用 C++11 来开发。但千万不要害怕,因为 EOS 合约仅使用 C++ 中极少部分的功能。

P.S 想用更多功能也是可以的,准备更多的 EOS 吧。

EOS 为了方便大家开发 EOS 合约,提供了一些工具和类库,这些工具和类库都开源在 GitHub 上,地址为 https://github.com/EOSIO/eosio.cdt

EOS 使用了 C++11 中最重要的特性 属性。 也就是使用 [[]]

预备工作

首先,在你最喜欢的目录下创建一个合约目录 hello

mkdir hello
cd    hello

注意: 合约目录非常重要,因为 EOS 的合约部署是以目录来进行的。

然后在 hello 目录下创建一个文件 hello.cpp

touch hello.cpp

文件名无所谓,惯例是合约名 + .cpp

接着使用你最喜欢的编辑器,打开 hello.cpp 文件,开始输入合约代码。

Hello World 合约

  1. 首先,EOS 合约需要引入头文件,最重要的头文件是 <eosiolib/eosio.hpp> ,该头文件包含了大量的其它头文件。

    #pragma once
    #include <eosiolib/action.hpp>
    #include <eosiolib/print.hpp>
    #include <eosiolib/multi_index.hpp>
    #include <eosiolib/dispatcher.hpp>
    #include <eosiolib/contract.hpp>
    

    源代码在 https://github.com/EOSIO/eosio.cdt/blob/master/libraries/eosiolib/eosio.hpp

    同时还包含了三个最重要的宏定义

    #define CONTRACT class [[eosio::contract]]
    #define ACTION   [[eosio::action]] void
    #define TABLE struct [[eosio::table]]
    

    这三个宏定义分别用来修饰一个 合约动作

    hello.cpp

    #include <eosiolib/eosio.hpp>
    
  2. 其次,我们要引入命名空间 eosio 。EOS 把所有的类和函数都放在 eosio 命名空间下。

    #include <eosiolib/eosio.hpp>
    
    using namespace eosio;
    
  3. 再次,EOS 中所有的合约都必须继承自一个基础合约 eosio::contract 。 该基础合约在 <eosiolib/contract.hpp> 头文件中定义

    #include <eosiolib/eosio.hpp>
    
    using namespace eosio;
    
    class hello : public contract {};
    
  4. EOS 合约可以包含一些动作 ( action ) 和一些用于存储数据的表 table,这些表都是一个结构体 struct。 如果不用存储数据,那么表是可以忽略的。

    EOS 合约中的动作都需要 [[eosio::action]] 属性来修饰。

    #include <eosiolib/eosio.hpp>
    
    using namespace eosio;
    
    class hello : public contract {
    public:
        using contract::contract;
    
        [[eosio::action]]
        void hi( name user ) {}
    };
    
  5. 如果要输出信息,比如一些字符串等,可以使用 eosio::print() 方法。

    eosio::print() 方法在 <eosiolib/print.hpp> 头文件中定义

    #include <eosiolib/eosio.hpp>
    #include <eosiolib/print.hpp>
    
    using namespace eosio;
    
    class hello : public contract {
    public:
        using contract::contract;
    
        [[eosio::action]]
        void hi() {
            print("Hello World");
        }
    };
    
  6. 一个 EOS 合约中可以有多个动作 action ,当 EOS 接收到一个事务后,会将该事务分发给相应的合约,或者说,调用相应的合约的动作。

    为了确保合约的哪个动作可以调用,需要使用 EOSIO_DISPATCH 宏来告诉 EOS。

    EOSIO_DISPATCH 宏在 <eosiolib/dispatcher.hpp> 头文件中定义,该宏的第一个参数是合约的名字,第二个参数,是多个小括号 () 扩起来的多个动作的方法名。

    #include <eosiolib/eosio.hpp>
    #include <eosiolib/print.hpp>
    
    using namespace eosio;
    
    class hello : public contract {
    public:
        using contract::contract;
    
        [[eosio::action]]
        void hi() {
            print("Hello World");
        }
    };
    
    EOSIO_DISPATCH( hello, (hi))
    

把上面的所有代码综合在一起,一个最基本的合约就完成了

hello.cpp

#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>

using namespace eosio;

class hello : public contract {
  public:
      using contract::contract;

      [[eosio::action]]
      void hi() {
         print("Hello World");
      }
};
EOSIO_DISPATCH( hello, (hi))

编译合约

好了,我们终于完成了 hello.cpp 合约的代码。现在,我们使用 eosio-cpp 命令来编译合约

eosio-cpp -o hello.wasm hello.cpp --abigen

选项说明

选项 说明
-o hello.wasm 该选项用于指定合约编译后的输出文件。必须是以 .wasm 作为文件扩展名
hello.cpp 合约源文件
--abigen 该选项用户指定合约编译时同时生成 abi 文件

运行该命令输出结果如下

[yufei@www.twle.cn hello]$ eosio-cpp -o hello.wasm hello.cpp --abigen
Warning, empty ricardian clause file
Warning, empty ricardian clause file
Warning, action <hi> does not have a ricardian contract

编译完成后,当前 hello 目录就会多出两个文件

yufeideMacBook-Pro:hello yufei$ tree .
.
├── hello.abi
├── hello.cpp
└── hello.wasm

部署合约

部署合约的前提就是需要存在一个账户。在前面的章节中,我们创建了一个 hello 账户,接下来我们就使用在这个账户上部署合约

部署合约需要使用到 cleos set contract 命令。

cleos set contract hello ../hello -p hello@active

选项说明

选项 说明
cleos set contract 部署合约的命令
hello 部署合约的账户,必须已经存在
../hello 合约所在的目录名,该目录下必须包含和目录相同的 .wasm.abi 文件
-p hello@active 该选项用于指定权限,该权限必须包含 hello 账户的 active 权限

该命令的运行结果如下

Reading WASM from ../hello/hello.wasm...
Skipping set abi because the new abi is the same as the existing abi
Publishing contract...
executed transaction: e3863e68840c354c67b4955e14bed8792fb37f7b7166e1df4b5a30e0a7f714f2  1344 bytes  518 us
#         eosio <= eosio::setcode               {"account":"hello","vmtype":0,"vmversion":0,"code":"0061736d0100000001300960017f006000017f60027f7f01...

运行合约下的动作

好了,我们已经部署好了我们的合约了,部署好了之后,我们就应该改变认识了。

只能说是 hello 账户下部署了一个合约,该合约下有一个动作 hi

如果我们要执行这个账户下的合约的 hi 动作,需要使用到 cleos push action 命令。该命令的语法如下

cleos push action hello hi '[]' -p hello@active

参数说明

选项 说明
cleos push action 执行合约动作的命令
hello 合约所在的账户名
hi 要执行的合约的动作,必须是已经导出的,也就是 EOSIO_DISPATCH( hello, (hi)) 中定义的
-p hello@active 用于执行合约的权限,可以是任意权限,只要该合约运行

运行上面的命令,输出结果如下

executed transaction: 843a65cd56420c6f749a10cf221fdf36716067cd1718c8348c38a304ba752ab0  96 bytes  270 us
#         hello <= hello::hi                    ""
>> Hello World

看到最后的那个 >> Hello World 吗? 这个就是 print("Hello World"); 的输出结果

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.