Dapp开发EOS开发

EOS开发(五)Hello World智能合约

2018-08-30  本文已影响47人  yuyangray

1. 概述

官方关于智能合约介绍的文档:
https://developers.eos.io/eosio-cpp/docs/introduction

Hello World智能合约文档:
https://developers.eos.io/eosio-cpp/docs/hello-world

基于EOSIO的区块链使用WebAssembly(WASM)执行用户生成的应用程序和代码。WASM是一种新兴的Web标准,得到了GoogleMicrosoftApple和其他公司的广泛支持。目前,用于构建编译为WASM的应用程序的最成熟的工具链是clang / llvm及其C / C ++编译器。为获得最佳兼容性,建议使用EOSIO工具链。

第三方开发的其他工具链包括:RustPythonSolidity。虽然这些其他语言可能看起来更简单,但它们的性能可能会影响可以构建的应用程序的规模。我们希望C ++将成为开发高性能和安全智能合约的最佳语言,并计划在可预见的未来使用C ++

在使用C++编写完成合约代码后,通过EOSIO软件中提供的eosiocpp工具,将C++代码编译生成WASMwasm的文本格式是后缀是wast)文件和abi文件,再利用cleos工具(将代码部署到链上,也就是存到区块数据中。

2. EOS智能合约与以太坊智能合约的区别

以下内容节选自全面理解EOS——4.测试智能合约与EOS发币

1.名称不同

在EOS中具有账号的概念,智能合约名也就是账号名。而以太坊中的合约是一个个不同的地址。

2.升级方式不同

以太坊的合约不可升级,一旦部署之后,代码不可修改。如果需要修改,只能在一个新的地址上重新部署。而EOS的智能合约和账号绑定后,账号可直接升级智能合约的代码,其实就相当于向链上重新上传了代码。

3.资源消耗不同

以太坊智能合约的执行需要消耗gas,也就是每个步骤都有手续费,手续费不够就不会继续执行,之前的操作也会被回滚,而且手续费也不退。而EOS的智能合约不需要首先费,但是部署合约要消耗RAM,传送信息和执行合约需要消耗抵押而得的CPU网络带宽

3.文件结构

eosiocpp工具可以初始化一份新的合约,简化我们的工作。

使用eosiocpp创建一份智能合约:

yuyangdeMacBook-Pro:eos yuyang$ eosiocpp -n hello

此命令会在当前目录创建一个名为hello的文件夹,里面包含三个文件:

hello.abi

abi文件

hello.cpp

包含合同函数实现的源文件

hello.hpp

头文件:包含变量,常量,和cpp文件的函数引用

如果.cpp文件是使用eosiocpp工具生成的,则生成的.cpp文件将类似于以下内容:

#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) )

可能官方文档没更新,我这里的.cpp文件的内容如下:

/**
 *  @file
 *  @copyright defined in eos/LICENSE.txt
 */
#include <hello.hpp>

/**
 *  The init() and apply() methods must have C calling convention so that the blockchain can lookup and
 *  call these methods.
 */
extern "C" {

    /// The apply method implements the dispatch of events to this contract
    void apply( uint64_t receiver, uint64_t code, uint64_t action ) {
       eosio::print( "Hello World: ", eosio::name(code), "->", eosio::name(action), "\n" );
    }

} // extern "C"

4.Hello World智能合约

4.1 创建账号

创建名为hello.code的账号用于部署合约:

打开并解锁钱包:

yuyangdeMacBook-Pro:cleos yuyang$ cleos wallet open
Opened: default
yuyangdeMacBook-Pro:cleos yuyang$ cleos wallet list
Wallets:
[
  "default"
]
yuyangdeMacBook-Pro:cleos yuyang$ cleos wallet unlock --password PW5KQwfoDJDUUTTEdZzTpSHYfmvSWxL23jefVHLi6UL74Uw9em6WA
Unlocked: default
yuyangdeMacBook-Pro:cleos yuyang$ cleos wallet list
Wallets:
[
  "default *"
]

生成密钥对:

yuyangdeMacBook-Pro:cleos yuyang$ cleos create key --to-console
Private key: 5JixXRHHAnxL68LnyvSBTKszZiZgHFAQctHVVYAFp4fwijFE8SZ
Public key: EOS64rVEsvzXnTiGSoYaMockxcvxdj7eM57anUoW1eNcSgxmijXTK
yuyangdeMacBook-Pro:cleos yuyang$ cleos create key --to-console
Private key: 5KhJsLuwzQ8ShdrTVnvgmXZT4J1iGHF16YAyyGFPxeMNVgWVyZF
Public key: EOS8JLJVwbQv9Dp4nnLg8Bso4RvXgsY3MeNBTU5LfLcD8WgKL5jUT

导入密钥对到钱包:

yuyangdeMacBook-Pro:cleos yuyang$ cleos wallet import --private-key 5JixXRHHAnxL68LnyvSBTKszZiZgHFAQctHVVYAFp4fwijFE8SZ
imported private key for: EOS64rVEsvzXnTiGSoYaMockxcvxdj7eM57anUoW1eNcSgxmijXTK
yuyangdeMacBook-Pro:cleos yuyang$ cleos wallet import --private-key 5KhJsLuwzQ8ShdrTVnvgmXZT4J1iGHF16YAyyGFPxeMNVgWVyZF
imported private key for: EOS8JLJVwbQv9Dp4nnLg8Bso4RvXgsY3MeNBTU5LfLcD8WgKL5jUT

创建账号:

yuyangdeMacBook-Pro:cleos yuyang$ cleos create account eosio hello.code EOS64rVEsvzXnTiGSoYaMockxcvxdj7eM57anUoW1eNcSgxmijXTK EOS8JLJVwbQv9Dp4nnLg8Bso4RvXgsY3MeNBTU5LfLcD8WgKL5jUT
executed transaction: 7904dc63327d21b01b097f80ec6272a4ca656b3120efe5e9f39738cd5b5c263f  200 bytes  3394 us
#         eosio <= eosio::newaccount            {"creator":"eosio","name":"hello.code","owner":{"threshold":1,"keys":[{"key":"EOS64rVEsvzXnTiGSoYaMo...
2018-08-29T03:35:56.708 thread-0   main.cpp:455                  print_result   warning: transaction executed locally, but may not be confirmed by the network yet

查看账号:

yuyangdeMacBook-Pro:cleos yuyang$ cleos get account hello.code
permissions: 
    owner     1:    1 EOS64rVEsvzXnTiGSoYaMockxcvxdj7eM57anUoW1eNcSgxmijXTK
       active     1:    1 EOS8JLJVwbQv9Dp4nnLg8Bso4RvXgsY3MeNBTU5LfLcD8WgKL5jUT
memory: 
    quota:       unlimited  used:      2.66 KiB  

net bandwidth: 
    used:               unlimited
    available:          unlimited
    limit:              unlimited

cpu bandwidth:
    used:               unlimited
    available:          unlimited
    limit:              unlimited

4.2 编写代码并生成wast和abi文件

使用下面代码覆盖hello.cpp中的内容:

#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
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中定义了对外可调用的函数hi方法,在hi方法中打印了调用者的账户名

生成.wast文件

yuyangdeMacBook-Pro:eos yuyang$ cd hello
yuyangdeMacBook-Pro:hello yuyang$ eosiocpp -o hello.wast hello.cpp

多了hello.wasmhello.wast文件

将刚才创建的hello文件夹中的hello.abi文件删除,我们要重新生成abi文件

yuyangdeMacBook-Pro:hello yuyang$ eosiocpp -g hello.abi hello.cpp
2018-08-29T03:45:49.132 thread-0   abi_generator.hpp:68          ricardian_contracts  ] Warning, no ricardian clauses found for hello

2018-08-29T03:45:49.133 thread-0   abi_generator.hpp:75          ricardian_contracts  ] Warning, no ricardian contract found for hi

Generated hello.abi ...

ABI
应用程序二进制接口(ABI)是一个基于JSON的描述,介绍如何在JSON和二进制表示之间转换用户操作。ABI还描述了如何将数据库状态转换为JSON或从JSON转换。通过ABI描述合同后,开发人员和用户将能够通过JSON无缝地与您的合同进行交互。

4.3 部署合约

yuyangdeMacBook-Pro:cleos yuyang$ cleos set contract hello.code ../../../hello -p hello.code@active
Reading WASM from ../../../hello/hello.wasm...
Publishing contract...
executed transaction: 14fc91fcdb35775b42a98e71267959aae508d0858406610da7b59520f20aebd3  1800 bytes  5738 us
#         eosio <= eosio::setcode               {"account":"hello.code","vmtype":0,"vmversion":0,"code":"0061736d01000000013b0c60027f7e006000017e600...
#         eosio <= eosio::setabi                {"account":"hello.code","abi":"0e656f73696f3a3a6162692f312e30000102686900010475736572046e616d6501000...
2018-08-29T06:22:51.809 thread-0   main.cpp:455                  print_result   warning: transaction executed locally, but may not be confirmed by the network yet

4.4 合约交互

在执行调用命令之前,我们先简单地了解EOS中的一个概念:transactionaction

qction表示单个操作,而transaction是一个或多个action的集合。action是合约和账户之间进行通信的方式。action可以单独执行,或者组合起来作为一个整体执行。EOS中的action就相当于以太坊中的transaction

调用合约hi方法:

yuyangdeMacBook-Pro:cleos yuyang$ cleos push action hello.code hi '["user"]' -p user@active
executed transaction: 9f109157ea7ea19bd069b6befa28c707cd5a40777c8827a9e474c926f5d9d0e0  104 bytes  2159 us
#    hello.code <= hello.code::hi               {"user":"user"}
2018-08-29T06:43:16.925 thread-0   main.cpp:455                  print_result   warning: transaction executed locally, but may not be confirmed by the network yet

如果看不到合约执行时的打印内容。可以重启nodeos,并且加上--contracts-console参数启动,以查看合约的输出内容:

yuyangdeMacBook-Pro:nodeos yuyang$ nodeos --contracts-console

或者编辑配置文件~/Library/Application Support/eosio/nodeos/config中的config.ini,找到以下内容:

# print contract's output to console (eosio::chain_plugin)
contracts-console = false

false改为true

再次调用合约hi方法:

yuyangdeMacBook-Pro:cleos yuyang$ cleos push action hello.code hi '["user"]' -p user@active
executed transaction: 89eed32e56d38ef91db92633568f40343f8e9389ceb0df5c15c7c46c51319d23  104 bytes  7449 us
#    hello.code <= hello.code::hi               {"user":"user"}
>> Hello, user
2018-08-29T06:48:46.087 thread-0   main.cpp:455                  print_result   warning: transaction executed locally, but may not be confirmed by the network yet

可以看到>> Hello, user的打印内容

再查看nodeos中的输出:

2018-08-29T06:48:46.005 thread-0   producer_plugin.cpp:1302      produce_block        ] Produced block 0000d235ac33678d... #53813 @ 2018-08-29T06:48:46.000 signed by eosio [trxs: 0, lib: 53812, confirmed: 0]
2018-08-29T06:48:46.085 thread-0   apply_context.cpp:28          print_debug          ] 
[(hello.code,hi)->hello.code]: CONSOLE OUTPUT BEGIN =====================
Hello, user
[(hello.code,hi)->hello.code]: CONSOLE OUTPUT END   =====================
2018-08-29T06:48:46.503 thread-0   producer_plugin.cpp:1302      produce_block        ] Produced block 0000d236ab3eb059... #53814 @ 2018-08-29T06:48:46.500 signed by eosio [trxs: 1, lib: 53813, confirmed: 0]

由于此时合约授权所有人调用hi方法,所以也可以进行如下操作:

yuyangdeMacBook-Pro:cleos yuyang$ cleos push action hello.code hi '["user"]' -p tester@active
executed transaction: 5c5232d118c8cf60d593435fdaeef6905163cfeeb30473fe97050e71459d7095  104 bytes  303 us
#    hello.code <= hello.code::hi               {"user":"user"}
>> Hello, user
2018-08-29T07:41:36.166 thread-0   main.cpp:455                  print_result   warning: transaction executed locally, but may not be confirmed by the network yet

如果我们希望授权者和调用者为同一个账户,可以加入以下代码:

void hi( account_name user ) {
   require_auth( user );
   print( "Hello, ", name{user} );
}

重新编译wast文件,生成abi文件,再次部署合约并调用,如果此时授权者和调用者并非同一个账户,合约会抛出错误:

yuyangdeMacBook-Pro:cleos yuyang$ cleos push action hello.code hi '["tester"]' -p user@active
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.

nodeos日记输出:

2018-08-29T08:15:36.002 thread-0   producer_plugin.cpp:1302      produce_block        ] Produced block 0000fae9ce9a18be... #64233 @ 2018-08-29T08:15:36.000 signed by eosio [trxs: 0, lib: 64232, confirmed: 0]
2018-08-29T08:15:36.436 thread-0   http_plugin.cpp:472           handle_exception     ] FC Exception encountered while processing chain.push_transaction
2018-08-29T08:15:36.436 thread-0   http_plugin.cpp:473           handle_exception     ] Exception Details: 3090004 missing_auth_exception: Missing required authority
missing authority of tester
    {"account":"tester"}
    thread-0  apply_context.cpp:131 require_authorization
pending console output: 
    {"console":""}
    thread-0  apply_context.cpp:61 exec_one
2018-08-29T08:15:36.503 thread-0   producer_plugin.cpp:1302      produce_block        ] Produced block 0000faea889f31c9... #64234 @ 2018-08-29T08:15:36.500 signed by eosio [trxs: 0, lib: 64233, confirmed: 0]

我们重新将授权者设为tester,正常

yuyangdeMacBook-Pro:cleos yuyang$ cleos push action hello.code hi '["tester"]' -p tester@active
executed transaction: bd9ed2dd386de13ce622c6c6184acd7085c8cc84a5ee0f86d58ae1abbaa5100e  104 bytes  332 us
#    hello.code <= hello.code::hi               {"user":"tester"}
>> Hello, tester
2018-08-29T08:16:59.641 thread-0   main.cpp:455                  print_result   warning: transaction executed locally, but may not be confirmed by the network yet

将授权者设为user,正常

yuyangdeMacBook-Pro:cleos yuyang$ cleos push action hello.code hi '["user"]' -p user@active
executed transaction: aabe5baab544c9386f5162b8327e34735fa2530e6497d64b356dfe380f53587a  104 bytes  293 us
#    hello.code <= hello.code::hi               {"user":"user"}
>> Hello, user
2018-08-29T08:18:10.926 thread-0   main.cpp:455                  print_result   warning: transaction executed locally, but may not be confirmed by the network yet
上一篇下一篇

猜你喜欢

热点阅读