EOS合约开发第九章-hello world合约

hello world合约

一、合约开发

我们编写一个简单的eos合约程序,这个程序只有基本的功能,即打印hello, world。以下是程序的代码:

#include <eosiolib/eosio.hpp>
using namespace eosio;

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

      /// @abi action 
      void hi( account_name user ) {
         print( "Hello, World!" );
      }
};

EOSIO_ABI( hello, (hi) )

第1行引用了eosio标准库,eosio标准库定义了eos开发需要的一些基本数据结构、函数以及常用的宏。

第2行指定名字空间eosio,eosio标准库中定义的开发接口都在名字空间eosio中。

第4行定义了一个合约类,该类从contract类派生,contract类是在eosio标准库中被定义。

第8行注释使用了@abi,这个注释将被eosio编译工具eosiocpp使用,eosiocpp工具可以根据@abi注释来生成abi文件。

第9~11行,是该合约的方法函数,也被称为action,执行合约时需要指定方法以及参数,最终在合约的方法函数中被执行。在这里例子中,该方法只做了一件事情,调用eosio标准库接口打印hello, world。

第14行是一个宏,该宏定义了eos合约入口的标准写法,其展开后的代码如下:

extern "C" { \
   void apply( uint64_t receiver, uint64_t code, uint64_t action ) { \
      auto self = receiver; \
      if( action == N(onerror)) { \
         /* onerror is only valid if it is for the "eosio" code account and authorized by "eosio"'s "active permission */ \
         eosio_assert(code == N(eosio), "onerror action's are only valid from the \"eosio\" system account"); \
      } \
      if( code == self || action == N(onerror) ) { \
         hello thiscontract( self ); \
         switch( action ) { \
            BOOST_PP_SEQ_FOR_EACH( EOSIO_API_CALL, hello, (hi) ) \
         } \
         /* does not allow destructor of thiscontract to run: eosio_exit(0); */ \
      } \
   } \
}

我们给出EOSIO_API_CALL的宏定义如下:

#define EOSIO_API_CALL( r, OP, elem ) \
   case ::eosio::string_to_name( BOOST_PP_STRINGIZE(elem) ): \
      eosio::execute_action( &thiscontract, &OP::elem ); \
      break;

这里的宏实现是一个简单的标准eos合约入口实现,很多是注释以及目前我们不太关注的,我们只关注action处理流程。

第2行apply是合约调用的总入口,相当于程序的main入口函数。

第9行声明一个hello合约对象并传入code参数。

第10~11行根据action参数来调用对应的函数方法从而来执行action。

你也完全可以不使用该宏来实现eos合约的入口,按照自己的需要实现自己的合约入口。

以上eos合约是一个简单的Hello world合约,但其完整展示了一个eos合约开发的基础。

二、合约编译

合约一般需要生产两份文件,一个是wast格式的执行程序,一个是abi格式描述的程序调用接口。

我们使用eos自带的编译工具eosiocpp来生成以上两份文件。

生成wast执行程序:

eosiocpp -o helloworld.wast helloworld.cpp

生成abi调用接口描述文件

eosiocpp -g helloworld.abi helloworld.cpp

注意,要将数据类型、函数接口、数据定义输出到abi文件,需要在代码中使用注释@abi来声明。

三、合约部署

在合约部署之前需要一个合约账户,首先创建一个账户:

[kingnet@pdev1 helloworld]$ cleos --wallet-url http://localhost:9800 --url http://localhost:9800 create account eosio helloworld EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
executed transaction: ef008c05652f9479a14faff60708052a909d217e6794b590a8f162dad0cd1d12  200 bytes  388 us
#         eosio <= eosio::newaccount            {"creator":"eosio","name":"helloworld","owner":{"threshold":1,"keys":[{"key":"EOS6MRyAjQq8ud7hVNYcfn...
warning: transaction executed locally, but may not be confirmed by the network yet

我们使用eos自带的命令行工具cleos来部署该合约:

[kingnet@pdev1 helloworld]$ cleos --wallet-url http://localhost:9800 --url http://localhost:9800 set contract helloworld /home/kingnet/tangy/eos/mycontracts/helloworld/
Reading WAST/WASM from /home/kingnet/tangy/eos/mycontracts/helloworld/helloworld.wasm...
Using already assembled WASM...
Publishing contract...
executed transaction: 2a2f7bdadb134b2521868bdc04853494965bc023d44ad0eff2510578275a32b9  1784 bytes  643 us
#         eosio <= eosio::setcode               {"account":"helloworld","vmtype":0,"vmversion":0,"code":"0061736d0100000001370b60027f7e006000017e600...
#         eosio <= eosio::setabi                {"account":"helloworld","abi":{"types":[],"structs":[{"name":"hi","base":"","fields":[{"name":"user"...
warning: transaction executed locally, but may not be confirmed by the network yet

注意部署一个合约需要合约的wast程序文件和abi二进制接口文件。

一个合约账户只能部署一份合约代码,在一个合约账户上进行多次合约部署将导致覆盖,最后部署的合约总是会完全覆盖以前的合约。

四、调用合约

调用合约需要指定合约账户、action以及参数,调用请求将发送到对应的合约账户,合约账户收到请求后执行合约账户上部署的合约代码处理请求,处理请求的入口函数就是上面helloworld合约中的apply。

我们也使用eos自带的命令行工具cleos来调用该合约:

[kingnet@pdev1 helloworld]$ cleos --wallet-url http://localhost:9800 --url http://localhost:9800 push action helloworld hi '{"user":"eosio"}' -p eosio
executed transaction: 02294aff437df847e58d3f9c716ff1a3b5863ed4e1570a62a25779c3c8d00e97  104 bytes  1279 us
#    helloworld <= helloworld::hi               {"user":"eosio"}
>> Hello, World!
warning: transaction executed locally, but may not be confirmed by the network yet

其中-p指定了调用该合约使用的账户以及权限,默认使用active权限,以上合约使用eosio@active来执行该合约。

注意:

1. 在abi中定义的action都可以用来发起合法的合约调用,无论合约有没有处理该action。

2. abi中没有定义的action都不能在合约上发起合法的合约调用,无论合约有没有处理该action,这类不合法合约调用会给出以下错误提示:

[kingnet@pdev1 helloworld]$ cleos --wallet-url http://localhost:9800 --url http://localhost:9800 push action helloworld hi1 '{"user":"eosio"}' -p eosio
Error 3050002: Invalid Action Arguments
Error Details:
'{"user":"eosio"}' is invalid args for action 'hi1' code 'helloworld'
Invalid cast from object_type to string

合约执行后打印Hello, World!。我们成功完成第一个EOS合约。

猜你喜欢

转载自blog.csdn.net/bedrock_stable/article/details/80297935