EOS智能合约入门

1 准备工作

首先在本地将私有链运行起来:

sudo nodeos -e -p eosio --plugin eosio::wallet_api_plugin --plugin eosio::chain_api_plugin --plugin eosio::history_api_plugin

私有链默认存储的位置在~/.local/share/eosio/nodeos路径下面。

然后新建一个账户acctoken以便运行eosio.token智能合约。

cleos create account eosio acctoken EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV

ps:创建账户命令的格式是:cleos create account creator name OwnerKey ActiveKey

  • 创建账户用create account命令

  • 是由账户eosio创建的

  • 新创建的账户名为acctoken

  • 这里OwnerKey和ActiveKey都设置为EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV

2 发布基础智能合约eosio.bios

eosio.bios是这个合约是EOS很多基本action的基础系统,所以要保证这个合约的有效执行。这个合约可以让你能够直接控制资源分配,并且有权限访问API。在公链上,这个合约将管理已募集和待募集token,以储备带宽给CPU、内存以及网络活动使用。

这个默认合约eosio.bios可以在EOS源码位置contracts/eosio.bios找到。可以通过cleos来指定这个合约执行:

~/eos$ cleos set contract eosio build/contracts/eosio.bios -p eosio
Reading WAST/WASM from build/contracts/eosio.bios/eosio.bios.wast...
Assembling WASM...
Publishing contract...
executed transaction: 36736dabac246732ef389fb5dd47099887854e25178a320b0e288324b5c87a9c  3288 bytes  2200576 cycles
#         eosio <= eosio::setcode               {"account":"eosio","vmtype":0,"vmversion":0,"code":"0061736d0100000001581060037f7e7f0060057f7e7e7e7e...
#         eosio <= eosio::setabi                {"account":"eosio","abi":{"types":[],"structs":[{"name":"set_account_limits","base":"","fields":[{"n...

ps:发布合约命令的格式是:cleos set contract creator contractpath 

  • 发布合约用set contract 
  • 是由账户eosio创建的
  • 合约位置在build/contracts/eosio.bios路径下
  • -p eosio:发布合约这个action是由eosio进行签名的

3 在EOS上发行代币

EOS上面发行代币非常简单,就是先发行eosio.token智能合约,然后依据这个智能合约再发行自己的代币。

发布eos.token智能合约

使用以下命令发布eosio.token智能合约:

~/eos$ cleos set contract acctoken build/contracts/eosio.token -p acctoken
Reading WAST/WASM from build/contracts/eosio.token/eosio.token.wasm...
Using already assembled WASM...
Publishing contract...
executed transaction: 913da06943c5d00e9adcf6a84b33857d0e7a9507168b7fa907d21b5806cb8235  8192 bytes  1474 us
#         eosio <= eosio::setcode               {"account":"acctoken","vmtype":0,"vmversion":0,"code":"0061736d01000000017e1560037f7e7f0060057f7e7e7...
#         eosio <= eosio::setabi                {"account":"acctoken","abi":"0e656f73696f3a3a6162692f312e30010c6163636f756e745f6e616d65046e616d65050...
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

发行代币

就像以太坊token那样,我们在EOS上可以更加方便的创建一个基于EOS的代币。首先,去token合约中的头文件eosio.token.hpp,查看一下token相关的接口都有哪些,其中有一个create函数,我们正是将要使用这个函数来创建token,所以我们可以留意一下它的参数都包括哪些。

class token : public contract {
      public:
         token( account_name self ):contract(self){}

         void create( account_name issuer,
                      asset        maximum_supply);

         void issue( account_name to, asset quantity, string memo );

         void transfer( account_name from,
                        account_name to,
                        asset        quantity,
                        string       memo );

使用下列命令来调用create函数创建代币:

~/eos$ cleos push action acctoken create '["eosio","1000000000.0000 EOS"]' -p acctoken
executed transaction: 932ab81c295f54259a21992911c4aca1c1d118902341d28d9acad5d47c9f3f9f  208 bytes  12981 us
#      acctoken <= acctoken::create             {"issuer":"eosio","maximum_supply":"1000000000.0000 EOS"}
warning: transaction executed locally, but may not be confirmed by the network yet    ] 
  • 调用智能合约的格式是cleos push action contract_publisher function_name parameter
  • 这里调用了create函数来创建代币,带了俩个参数eosio和1000000000.0000 EOS
  • 代币发行账户是eosio,代币最大发行10亿,单位是EOS

ps:账户和合约的关系是:

  • 可以使用某个账户作为合约发布者,那么该账户就拥有了此合约的操作权,后续对该合约的操作不必再写合约名字,直接使用该账户加上合约内部函数即可。
  • 一个账户可以发布多次不同的合约,但是以最后一次为有效,因为作为合约code的hash是只有一个,每次部署新的合约会覆盖原有的。

代币发放

我们已经有了EOS代币,我们现在将代币发行100个给inita账户,通过调用issue函数:

~/eos$ cleos push action acctoken issue '["inita","100.0000 EOS","memo"]' -p eosio
executed transaction: 66cc35d5c3102f36f7eb6eda8f786b6a2e997e5723e94614fbe6d0b3f9150941  216 bytes  2091 us
#      acctoken <= acctoken::issue              {"to":"inita","quantity":"100.0000 EOS","memo":"memo"}
#      acctoken <= acctoken::transfer           {"from":"eosio","to":"inita","quantity":"100.0000 EOS","memo":"memo"}
#         eosio <= acctoken::transfer           {"from":"eosio","to":"inita","quantity":"100.0000 EOS","memo":"memo"}
#         inita <= acctoken::transfer           {"from":"eosio","to":"inita","quantity":"100.0000 EOS","memo":"memo"}
warning: transaction executed locally, but may not be confirmed by the network yet    ]

查询inita账户余额:

~/eos$ cleos get currency balance acctoken inita EOS
100.0000 EOS

转账

调用transfer函数来进行转账

~/eos$ cleos push action acctoken transfer '["inita","initb","25.0000 EOS","memo"]' -p inita
executed transaction: 3b24a573903e689c66d990fe420232ac0cbb88375195406f87f2ab13ed4f1eb5  224 bytes  895 us
#      acctoken <= acctoken::transfer           {"from":"inita","to":"initb","quantity":"25.0000 EOS","memo":"memo"}
#         inita <= acctoken::transfer           {"from":"inita","to":"initb","quantity":"25.0000 EOS","memo":"memo"}
#         initb <= acctoken::transfer           {"from":"inita","to":"initb","quantity":"25.0000 EOS","memo":"memo"}
warning: transaction executed locally, but may not be confirmed by the network yet    ] 
lzj@lzj-VirtualBox:~/eos$ cleos get currency balance acctoken inita
75.0000 EOS
lzj@lzj-VirtualBox:~/eos$ cleos get currency balance acctoken initb
25.0000 EOS

4 创建自己的Hello World智能合约

合约代码

我们先创建一个名为hello的文件夹,然后新建一个hello.cpp

#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, ", name{user} );
      }
};

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合约入口的标准写法

编译合约

使用命令先生成wast文件

$ sudo eosiocpp -o hello.wast hello.cpp

然后继续生成abi文件:

hello$ sudo eosiocpp -g hello.abi hello.cpp 
2018-12-03T08:31:31.770 thread-0   abi_generator.hpp:68          ricardian_contracts  ] Warning, no ricardian clauses found for hello

2018-12-03T08:31:31.771 thread-0   abi_generator.hpp:75          ricardian_contracts  ] Warning, no ricardian contract found for hi

Generated hello.abi ...

发布hello合约

创建了一个账户acchello

~/eos$ cleos create account eosio acchello EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
executed transaction: be27102f4789b9c1f65db7166e883c822e4e7d6be25f490b22dd4ff0006955d1  288 bytes  561 us
#         eosio <= eosio::newaccount            {"creator":"eosio","name":"acchello","owner":{"threshold":1,"keys":[{"key":"EOS6MRyAjQq8ud7hVNYcfnVP...
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

然后使用acchello发布智能合约:

~/eos$ cleos set contract acchello contracts/hello/ -p acchello
Reading WAST/WASM from contracts/hello/hello.wasm...
Using already assembled WASM...
Publishing contract...
executed transaction: b2dd4a0c48d1e2ddee1b432bdf7f9a5ff122ed01a50aaa23e27c817978bf5348  1896 bytes  515 us
#         eosio <= eosio::setcode               {"account":"acchello","vmtype":0,"vmversion":0,"code":"0061736d01000000013b0c60027f7e006000017e60027...
#         eosio <= eosio::setabi                {"account":"acchello","abi":"0e656f73696f3a3a6162692f312e30000102686900010475736572046e616d650100000...
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

调用hello智能合约

:~/eos$ cleos push action acchello hi '["bush"]' -p acchello
executed transaction: 139a54fea8bf3dc20dc622f0c7494325ea4e0bc3decbd8c8b7a2e24b2b378f6b  192 bytes  356 us
#      acchello <= acchello::hi                 {"user":"bush"}
>> Hello, bush
warning: transaction executed locally, but may not be confirmed by the network yet    ]

ps:有人会反应执行了hi函数不在控制台打印字符串,原因是需要在nodeos启动参数里加上--contracts-console参数

加入权限

目前我们的hello合约是不限制hi参数的,也就是说其实我们是没有“bush”这个签名人的,也就是说这个参数中无论是否传入账户名,都可以输出。我们期望智能合约hi函数的参数必须是有效账户名,同时只有该账户拥有当前action的签名权。所以,我们要修改hello.cpp文件。

/// @abi action 
      void hi( account_name user ) {
         require_auth(user);// 只有该user账户有权签名当前action
         print( "Hello, ", name{user} );
      }

重新编译并发布智能合约,再传入非有效账户名时,或者用其他账户签名的时候就会报错:

~/eos$ cleos push action acchello hi '["bush"]' -p acchello
Error 3090004: Missing required authority

~/eos$ cleos push action acchello hi '["acchello"]' -p acchello
executed transaction: bc0d46e8bed951733967a78dfd198578eec8bb4087c621480f79fe8dd6c1f73d  192 bytes  553 us
#      acchello <= acchello::hi                 {"user":"acchello"}
>> Hello, acchello
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

猜你喜欢

转载自blog.csdn.net/liuzhijun301/article/details/84783215