首页 > EOS柚子 > 正文

EOS编写HelloWorld智能合约以及遇到的各种坑

闪马块讯 2019-02-28 18:06

本文所有实践都是基于EOS dawn-v4.1.0,请切到该分支然后实践

  

切换命令:git checkout dawn-v4.1.0

HelloWorld源码

#include

#include

using namespace eosio;

class hello : public eosio::contract {

  public:

      using contract::contract;

      /// @abi action

      void hi( account_name user ) {

         print( “Hello, “, name{user} );

      }

};

EOSIO_ABI( hello, (hi) )

‘EOSIO_ABI’是一个生成智能合约初始化函数apply的宏,生成的apply函数是智能合约的入口,它采用switch case的方式调用具体action对应的函数

#define EOSIO_ABI( TYPE, MEMBERS )

extern “C” {

   void apply( uint64_t receiver, uint64_t code, uint64_t action ) {

      auto self = receiver;

      if( code == self ) {

         TYPE thiscontract( self );

         switch( action ) {

            EOSIO_API( TYPE, MEMBERS )

         }

         /* does not allow destructor of thiscontract to run: eosio_exit(0); */

      }

   }

}

编译

生成wast文件

$ eosiocpp -o hello.wast hello.cpp

     编译完成后,会生成两个新文件,hello.wast, hello.wasm

$ ls

hello.cpphello.wasmhello.wast

      .wast文件是wasm的代码文本格式,.wasm是汇编代码二级制格式

生成abi文件

$ eosiocpp -g hello.abi hello.cpp

764454ms thread-0   abi_generator.hpp:68          ricardian_contracts  ] Warning, no ricardian clauses found for hello

764454ms thread-0   abi_generator.hpp:75          ricardian_contracts  ] Warning, no ricardian contract found for hi

部署智能合约创建新账号

    我们知道智能合约是附着在账号上的,因而需要为合约准备一个账号

创建key并导入到钱包

$ cleos create key

Private key: 5JdchMrwMwD1PsZKCjpbaCQ4aJ3cFKzSWmCQfRzKCiGrDWds3PU

Public key: EOS7KBTMkUq4VPakqsZUnZfBbMbS2U7cn9qSa3q6G5ZzEeUeNSVgv

$ cleos wallet import 5JdchMrwMwD1PsZKCjpbaCQ4aJ3cFKzSWmCQfRzKCiGrDWds3PU

以上面的key创建账号

$ cleos create account eosio hello.code EOS7KBTMkUq4VPakqsZUnZfBbMbS2U7cn9qSa3q6G5ZzEeUeNSVgv EOS7KBTMkUq4VPakqsZUnZfBbMbS2U7cn9qSa3q6G5ZzEeUeNSVgv

executed transaction: 9cdfd59700f8fb13b9a3b330d75f9e1d6a014d54f5bec21cee9afe35c8c49b99  200 bytes  5304 us

#         eosio <= eosio::newaccount            {“creator”:”eosio”,”name”:”hello.code”,”owner”:{“threshold”:1,”keys”:[{“key”:”EOS7KBTMkUq4VPakqsZUnZ…

warning: transaction executed locally, but may not be confirmed by the network yet

将合约代码绑定到账号

    这里需要注意的是,xxx.wasm文件的目录必须是xxx,这里的hello.cpp, hello.wasm的目录就必须是hello,因为该命令会搜索xx/xx.wasm文件,这里会搜索hello/hello.wasm文件

$ cleos set contract hello.code ./hello -p hello.code

Reading WAST/WASM from ./hello/hello.wasm…

Using already assembled WASM…

Publishing contract…

executed transaction: b26872e44b439ce289f7c449f959a7c9ad574045f69c53039ff365e79e1b8494  1800 bytes  5647 us

#         eosio <= eosio::setcode               {“account”:”hello.code”,”vmtype”:0,”vmversion”:0,”code”:”0061736d01000000013b0c60027f7e006000017e600…

#         eosio <= eosio::setabi                {“account”:”hello.code”,”abi”:”00010c6163636f756e745f6e616d650675696e74363401026869000104757365720c6…

warning: transaction executed locally, but may not be confirmed by the network yet

执行智能合约函数

$cleos push action hello.code hi ‘[“args.user”]’ -p args.user

“非法参数”错误

    结果报如下错误

itleaks$cleos push action hello.code hi ‘[“args.user”]’ -p args.user

Error 3050002: Invalid Action Arguments

Ensure that your arguments follow the contract abi!

You can check the contract’s abi by using ‘cleos get code’ command.

Error Details:

‘[“args.user”]’ is invalid args for action ‘hi’ code ‘hello.code’. expected ‘[{“name”:”user”,”type”:”account_name”}]’

Couldn’t parse uint64_t

   这是什么鬼?参数'[“arg.user”]’可是官方的文档的描述。从这个错误log可以看出系统需要的是account_name,且尝试解释为uint64_t时出错的, 我们传了一个字母字符串”args.user”过去,如果尝试解释uint64_t确实会报错。于是改成数字再次尝试

$ cleos push action hello.code hi ‘[“1234”]’ -p args.user

executed transaction: 48060522d3bc73a34075256ba2f6657cce0473dd2a9ee1a3669f89d349b65973  104 bytes  6623 us

#    hello.code <= hello.code::hi               {“user”:1234}

>> Hello, ……….2h2

warning: transaction executed locally, but may not be confirmed by the network yet

   让我吃惊的是确实成功了。那问题是这个参数确实就应该要传数字吗?但是官网确实是传的字母类型的账号名啊。且expected的数据类型不是account_name吗?怎么就成了uint64_t了呢?

   为了进一步解开这个疑惑,我们来看看nodeos程序段的错误log

疑点1:account_name怎么变成uint64_t类型了?

‘[“args.user”]’ is invalid args for action ‘hi’ code ‘hello.code’. expected ‘[{“name”:”user”,”type”:”account_name”}]’

    {“args”:[“args.user”],”action”:”hi”,”code”:”hello.code”,”proto”:[{“name”:”user”,”type”:”account_name”}]}

    thread-0  chain_plugin.cpp:673 abi_json_to_bin

Couldn’t parse uint64_t

    {}

    thread-0  string.cpp:113 to_uint64

    {“i”:”args.user”}

    thread-0  string.cpp:116 to_uint64

    {“*this”:”args.user”}

    thread-0  variant.cpp:403 as_uint64

    {“type”:”account_name”,”var”:”args.user”}

    thread-0  abi_serializer.cpp:328 variant_to_binary

    {“type”:”hi”,”var”:[“args.user”]}

    thread-0  abi_serializer.cpp:328 variant_to_binary

    {“type”:”hi”,”var”:[“args.user”]}

    thread-0  abi_serializer.cpp:340 variant_to_binary

    {“params.code”:”hello.code”,”params.action”:”hi”,”params.args”:[“args.user”]}

    thread-0  chain_plugin.cpp:676 abi_json_to_bin

    从上面的Log可知这个错误跟abi相关,于是查看hello.abi

    uint64终于出现了,原来abi将account_name重新定义为uint64,所以才会出现前面的错误。

疑点2:官方程序eosio.system为啥可以直接用字母账号名?

    查看eosio.system.abi

    看到区别没,eosio.system.abi里account_name被定义为name而不是uint64。

都是account_name,为啥生成的abi文件一个定义为name而另一个定义为uint64呢?这个

我会单独写一篇博文来解读

“非法参数”错误解决

    通过上面分析,我们知道差异在account_name的类型定义,因而手动将hello.abi文件中的account_name的type改为name就可解决这个问题,更新code后再次执行,果然成功了

$ cleos push action hello.code hi ‘[“args.user”]’ -p args.user

executed transaction: f694bfbc0c4d26751aa35a57bc1695fb24ff1a7606934dea64edd1e15f79664d  104 bytes  2444 us

#    hello.code <= hello.code::hi               {“user”:”args.user”}

>> Hello, args.user

warning: transaction executed locally, but may not be confirmed by the network yet

智能合约权限检测实践

    前面的智能合约没有执行任何权限检测,因而在hi函数里新增一个权限检测

class hello : public eosio::contract {

  public:

      using contract::contract;

      /// @abi action

      void hi( account_name user) {

         require_auth(user);

         print( “Hello, “, name{user} );

      }

};

    红色字体的意思是执行”hi” action的权限必须是作为参数传进来的user

    如果使用hello.code账号执行则会报错

$ cleos push action hello.code hi ‘[“args.user”]’ -p hello.code

Error 3090004: missing required authority

Ensure that you have the related authority inside your transaction!;

If you are currently using ‘cleos push action’ command, try to add the relevant authority using -p option.

Error Details:

missing authority of args.user

    将参数换成hello.code执行成功

$ cleos push action hello.code hi ‘[“hello.code”]’ -p hello.code

executed transaction: 49db2db96c3719992af6e31d378385ac99ff611453ef81fd03cbcb822d223bd5  104 bytes  1752 us

#    hello.code <= hello.code::hi               {“user”:”hello.code”}

>> Hello, hello.code

warning: transaction executed locally, but may not be confirmed by the network yet

源码一键实践

    从以下github网页下载源码,即可一键实践执行该智能合约

https://github.com/itleaks/eos-contract

阅读更多

上一篇:EOS引力区廖洋阳:社群如何协助公链构建更加健全的生态 | 链茶访

下一篇:【曝光】EOS生态跑路,打着币圈旗号的资金盘又能挺多久?

您可能喜欢:

关于我们联系我们作者投稿
Copyright © 2013 比特巴手机版
币圈人都爱上的网站,新闻行情教程人物测评资讯大全