EOS · 2018年8月30日 1

EOS智能合约-Hello World与Token

简介

此篇将演示如何在EOS的测试网络中创建、加载、调用HelloWorld智能合约,以及Token合约的使用方式。

本文内容从官方:智能合约教程翻译修改所得。

为了能够顺利完成此教程需要确保:

  • 至少拥有一个账号与钱包,这里将使用之前创建的钱包:nm1024、账号:nmaccount
  • nodeos、cleos、keosd配置等无问题,可以运行;
  • 将节点账户eosio的密钥导入钱包。

加载BIOS系统合约

bios的全称是 Basic Input/Output System(基本输入输出系统),一个默认的系统合约。通过此合约,可以直接控制其他帐户的资源分配,并调用其他特权API。为合约执行预留CPU、网络活动带宽,以及预留内存。一般情况下不用去管它,只要保证它顺利加载就行。

eosio.bios合约可以在EOSIO源代码文件夹中找到:contracts/eosio.bios。以下的命令,都假定是在EOSIO源代码的根目录/data/eos执行。但是也可以通过指定完整路径${EOSIO_SOURCE}/build/contracts/eosio.bios

在加载bios合约之前需要解锁钱包账户,保证nodeos开始运行。

$ cd /data/eos
# 这里必须解锁eosio账号密钥所在的钱包
$ cleos wallet unlock -n nm1024 --password PW5KC4AVeEspMmMQYYr3JNcejsWuBX5pnsSJtsQayGF9BkaeJLhRL
$ cleos set contract eosio build/contracts/eosio.bios -p eosio@active

Reading WASM from build/contracts/eosio.bios/eosio.bios.wasm...
Publishing contract...
executed transaction: 8d111339fbcd75cbf1dcfc3eccc6ca3514ba4f3be0fe1c93d7ceb1241c73092a  3720 bytes  1594 us
#         eosio <= eosio::setcode               {"account":"eosio","vmtype":0,"vmversion":0,"code":"0061736d0100000001621260037f7e7f0060057f7e7e7e7e...
#         eosio <= eosio::setabi                {"account":"eosio","abi":"0e656f73696f3a3a6162692f312e30050c6163636f756e745f6e616d65046e616d650f7065...

这个命令的结果是,cleos发起一个包含两个操作的交易:eosio::setcodeeosio::setabi。最后一个参数是-p eosio@active。该参数告诉cleos,用eosio账户的active权限签署此操作,即使用我们先前导入钱包的eosio账户私钥对操作进行签名。

在创建账号的时候填入了两个密钥,owner_key与active_key即代表了两种权限,这里选择active权限密钥签署此次操作。

代码定义了合约如何运行,abi描述了参数如何在二进制和json之间进行转换。虽然abi在技术上是可选的,但为了便于使用,所有的EOSIO工具都依赖于它,所以还是必须的

任何时候你执行一个交易,都会看到类似这样的输出:

executed transaction: 8d111339fbcd75cbf1dcfc3eccc6ca3514ba4f3be0fe1c93d7ceb1241c73092a  3720 bytes  1594 us
#         eosio <= eosio::setcode               {"account":"eosio","vmtype":0,"vmversion":0,"code":"0061736d0100000001621260037f7e7f0060057f7e7e7e7e...
#         eosio <= eosio::setabi                {"account":"eosio","abi":"0e656f73696f3a3a6162692f312e30050c6163636f756e745f6e616d65046e616d650f7065...

以上输出的形式如下:

#         ${executor} <= ${contract}:${action} ${args...}

此处bios仅为合约部署的示例。

在一个完整的EOS环境中eosio.bioseosio.msigeosio.systemeosio.token、都需要部署。eosio.system合约建议使用eosio账号部署;

这里就不一一说明了;一旦部署了eosio.system那么在注册账号等操作的时候会需要RAM、NET、CPU三种资源,而且只能注册12字符长度的账号。
详见此篇文章

Hello World智能合约

现在创建第一个“Hello world”合约。创建一个名为“hello”的新文件夹,进入该文件夹然后使用以下内容创建一个文件“hello.cpp”(我这里的路径为/data/test-contract/hello/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) )

使用如下命令将代码编译为Web程序集(.wast):

$ cd /data/test-contract/hello/
$ eosiocpp -o hello.wast hello.cpp

完成之后会在这个文件夹下生成两个文件,hello.wasmhello.wast

生成hello.abi:

$ eosiocpp -g hello.abi hello.cpp
2018-08-30T06:00:20.590 thread-0   abi_generator.hpp:68          ricardian_contracts  ] Warning, no ricardian clauses found for hello

2018-08-30T06:00:20.590 thread-0   abi_generator.hpp:75          ricardian_contracts  ] Warning, no ricardian contract found for hi

Generated hello.abi ...

eosiocpp从v1.2.0弃用,将在v1.3.0中删除,由eosio.wasmsdk替代此功能。
eos里边每个账户只能发布一个合约,所以认为账户与合约是对应的,账户下可以没有合约,如果有则只能有一个。
所以在这里需要新建一个账户发布hello合约(为了方便两个公钥可以使用同一个):

$ cleos create key --to-console
Private key: 5JoipUnVqidXRenzzWDNpbnWWF9EbQm3StAXwGNhsRxuEXdGaLf
Public key: EOS5dbmrWAc7hdgw6sQJJzLHuzzQjyX8vGR6xuyDZB5cBY9uoiGtf

$ cleos wallet import -n nm1024 --private-key 5JoipUnVqidXRenzzWDNpbnWWF9EbQm3StAXwGNhsRxuEXdGaLf
imported private key for: EOS5dbmrWAc7hdgw6sQJJzLHuzzQjyX8vGR6xuyDZB5cBY9uoiGtf

# 创建合约账户
$ cleos create account eosio hello.code EOS5dbmrWAc7hdgw6sQJJzLHuzzQjyX8vGR6xuyDZB5cBY9uoiGtf EOS5dbmrWAc7hdgw6sQJJzLHuzzQjyX8vGR6xuyDZB5cBY9uoiGtf
executed transaction: aa4a55bfb5fb728784d38006226a0cd1d08403f893ebaa48f27824ff4f8e29ac  200 bytes  417 us
#         eosio <= eosio::newaccount            {"creator":"eosio","name":"hello.code","owner":{"threshold":1,"keys":[{"key":"EOS5dbmrWAc7hdgw6sQJJz...
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

# 上传合约
$ cleos set contract hello.code ../hello -p hello.code@active
Reading WASM from ../hello/hello.wasm...
Publishing contract...
executed transaction: c081e3288b4fe52e2e38d8931e20c8c1c427b5b8a285a6ff1b846d9bf077fa70  1800 bytes  653 us
#         eosio <= eosio::setcode               {"account":"hello.code","vmtype":0,"vmversion":0,"code":"0061736d01000000013b0c60027f7e006000017e600...
#         eosio <= eosio::setabi                {"account":"hello.code","abi":"0e656f73696f3a3a6162692f312e30000102686900010475736572046e616d6501000...
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

运行合约:

$ cleos push action hello.code hi '["nmaccount"]' -p nmaccount@active
executed transaction: 3386b4622b552b3be07eeeafe3149a4c500056ed78cf54f6b8c126c5fac56f37  104 bytes  365 us
#    hello.code <= hello.code::hi               {"user":"nmaccount"}
>> Hello, nmaccount
warning: transaction executed locally, but may not be confirmed by the network yet    ]

此处'["nmaccount"]'仅仅是一个参数,-p nmaccount@active是执行合约并授权的账户;这个合约允许任何人授权。如果想限定授权人与参数为同一人可以将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 ) {
        require_auth( user );
        print( "Hello, ", name{user} );
    }
};

EOSIO_ABI( hello, (hi) )

这样的话就会对参数进行权限的验证,如果和执行人不匹配会抛出错误


如果运行之后没有发现>> Hello, nmaccount这行输出,那么需要使用nodeos --contracts-console来运行nodeos,打开了以后在上边运行合约的命令执行完后会在nodeos端看到:

2018-08-30T06:22:58.001 thread-0   producer_plugin.cpp:1302      produce_block        ] Produced block 000020417d7c6d75... #8257 @ 2018-08-30T06:22:58.000 signed by eosio [trxs: 0, lib: 8256, confirmed: 0]
2018-08-30T06:22:58.500 thread-0   producer_plugin.cpp:1302      produce_block        ] Produced block 000020422841fb6d... #8258 @ 2018-08-30T06:22:58.500 signed by eosio [trxs: 0, lib: 8257, confirmed: 0]
2018-08-30T06:22:58.508 thread-0   apply_context.cpp:28          print_debug          ] 
[(hello.code,hi)->hello.code]: CONSOLE OUTPUT BEGIN =====================
Hello, nmaccount
[(hello.code,hi)->hello.code]: CONSOLE OUTPUT END   =====================
2018-08-30T06:22:59.002 thread-0   producer_plugin.cpp:1302      produce_block        ] Produced block 000020434ea899e8... #8259 @ 2018-08-30T06:22:59.000 signed by eosio [trxs: 1, lib: 8258, confirmed: 0]

Ricardian Contract(李嘉图合约)

在官方的介绍中说了,每个智能合约都必须有一个匹配的李嘉图合约。李嘉图合约规定了与智能合约的每个行为相关的具有法律约束力的行为。并列出了Hello World合约的李嘉图合约。

## CONTRACT FOR HELLO WORLD

### Parameters
Input parameters: NONE

Implied parameters: 

* _**account_name**_ (name of the party invoking and signing the contract)

### Intent
INTENT. The intention of the author and the invoker of this contract is to print output. It shall have no other effect.

### Term
TERM. This Contract expires at the conclusion of code execution.

### Warranty
WARRANTY. {{ account_name }} shall uphold its Obligations under this Contract in a timely and workmanlike manner, using knowledge and recommendations for performing the services which meet generally acceptable standards set forth by EOSIO Blockchain Block Producers.

### Default
DEFAULT. The occurrence of any of the following shall constitute a material default under this Contract: 

### Remedies
REMEDIES. In addition to any and all other rights a party may have available according to law, if a party defaults by failing to substantially perform any provision, term or condition of this Contract, the other party may terminate the Contract by providing written notice to the defaulting party. This notice shall describe with sufficient detail the nature of the default. The party receiving such notice shall promptly be removed from being a Block Producer and this Contract shall be automatically terminated. 

### Force Majeure
FORCE MAJEURE. If performance of this Contract or any obligation under this Contract is prevented, restricted, or interfered with by causes beyond either party's reasonable control ("Force Majeure"), and if the party unable to carry out its obligations gives the other party prompt written notice of such event, then the obligations of the party invoking this provision shall be suspended to the extent necessary by such event. The term Force Majeure shall include, without limitation, acts of God, fire, explosion, vandalism, storm or other similar occurrence, orders or acts of military or civil authority, or by national emergencies, insurrections, riots, or wars, or strikes, lock-outs, work stoppages, or supplier failures. The excused party shall use reasonable efforts under the circumstances to avoid or remove such causes of non-performance and shall proceed to perform with reasonable dispatch whenever such causes are removed or ceased. An act or omission shall be deemed within the reasonable control of a party if committed, omitted, or caused by such party, or its employees, officers, agents, or affiliates. 

### Dispute Resolution
DISPUTE RESOLUTION. Any controversies or disputes arising out of or relating to this Contract will be resolved by binding arbitration under the default rules set forth by the EOSIO Blockchain. The arbitrator's award will be final, and judgment may be entered upon it by any court having proper jurisdiction. 

### Entire Agreement
ENTIRE AGREEMENT. This Contract contains the entire agreement of the parties, and there are no other promises or conditions in any other agreement whether oral or written concerning the subject matter of this Contract. This Contract supersedes any prior written or oral agreements between the parties. 

### Severability
SEVERABILITY. If any provision of this Contract will be held to be invalid or unenforceable for any reason, the remaining provisions will continue to be valid and enforceable. If a court finds that any provision of this Contract is invalid or unenforceable, but that by limiting such provision it would become valid and enforceable, then such provision will be deemed to be written, construed, and enforced as so limited. 

### Amendment
AMENDMENT. This Contract may be modified or amended in writing by mutual agreement between the parties, if the writing is signed by the party obligated under the amendment. 

### Governing Law
GOVERNING LAW. This Contract shall be construed in accordance with the Maxims of Equity. 

### Notice
NOTICE. Any notice or communication required or permitted under this Contract shall be sufficiently given if delivered to a verifiable email address or to such other email address as one party may have publicly furnished in writing, or published on a broadcast contract provided by this blockchain for purposes of providing notices of this type. 

### Waiver of Contractual Right
WAIVER OF CONTRACTUAL RIGHT. The failure of either party to enforce any provision of this Contract shall not be construed as a waiver or limitation of that party's right to subsequently enforce and compel strict compliance with every provision of this Contract. 

### Arbitrator's Fees to Prevailing Party
ARBITRATOR’S FEES TO PREVAILING PARTY. In any action arising hereunder or any separate action pertaining to the validity of this Agreement, both sides shall pay half the initial cost of arbitration, and the prevailing party shall be awarded reasonable arbitrator's fees and costs.

### Construction and Interpretation
CONSTRUCTION AND INTERPRETATION. The rule requiring construction or interpretation against the drafter is waived. The document shall be deemed as if it were drafted by both parties in a mutual effort. 

### In Witness Whereof
IN WITNESS WHEREOF, the parties hereto have caused this Agreement to be executed by themselves or their duly authorized representatives as of the date of execution, and authorized as proven by the cryptographic signature on the transaction that invokes this contract.

但是官方没有详细说明Ricardian Contract(李嘉图合约)是个什么东西,最后搜到一篇关于李嘉图合约EOS上的李嘉图合约介绍详细的文章。

发布Token

官方提供了Token合约/data/eos/build/contracts/eosio.token,使用它的方式和其他合约一样,创建一个账户,并使用该账户创建Token合约:

$ cleos create key --to-console
Private key: 5K36o9rDwiPJ6keAMts4mYXWDW66NKJ7RkNy8HpiKVUf7PMX8Ja
Public key: EOS5NmsA43mgqWxx2KRJzeSgY9v6Exj4hbdWvfYXjWVrxmJwgqSgs

$ cleos wallet unlock -n nm1024 --password PW5KC4AVeEspMmMQYYr3JNcejsWuBX5pnsSJtsQayGF9BkaeJLhRL
Unlocked: nm1024

$ cleos wallet import -n nm1024 --private-key 5K36o9rDwiPJ6keAMts4mYXWDW66NKJ7RkNy8HpiKVUf7PMX8Ja
imported private key for: EOS5NmsA43mgqWxx2KRJzeSgY9v6Exj4hbdWvfYXjWVrxmJwgqSgs

$ cleos create account eosio eosio.token EOS5NmsA43mgqWxx2KRJzeSgY9v6Exj4hbdWvfYXjWVrxmJwgqSgs EOS5NmsA43mgqWxx2KRJzeSgY9v6Exj4hbdWvfYXjWVrxmJwgqSgs
executed transaction: 708863a27ad97feb7d05ad26bd6f51034f92124d735301b94721bbd0e2790bc6  200 bytes  568 us
#         eosio <= eosio::newaccount            {"creator":"eosio","name":"eosio.token","owner":{"threshold":1,"keys":[{"key":"EOS5NmsA43mgqWxx2KRJz...
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

$ cleos set contract eosio.token build/contracts/eosio.token -p eosio.token@active
Reading WASM from build/contracts/eosio.token/eosio.token.wasm...
Publishing contract...
executed transaction: eddba86f5c9075031bbc213f4acd042731cd826b6dda9f1e9f8a4a8bf5383d2c  8104 bytes  1957 us
#         eosio <= eosio::setcode               {"account":"eosio.token","vmtype":0,"vmversion":0,"code":"0061736d01000000017e1560037f7e7f0060057f7e...
#         eosio <= eosio::setabi                {"account":"eosio.token","abi":"0e656f73696f3a3a6162692f312e30010c6163636f756e745f6e616d65046e616d65...
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

然后试试创建Token:

$ cleos push action eosio.token create '[ "eosio", "1000000000.0000 CYB"]' -p eosio.token@active
executed transaction: c8c482dd7d0738a3a2f2fac15e9b0ed81c44718c47a89627a9d6f5d33683deb3  120 bytes  1557 us
#   eosio.token <= eosio.token::create          {"issuer":"eosio","maximum_supply":"1000000000.0000 CYB"}
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

这行命令表示创建最大供应量1000000000个的CYB,币的最小精度是0.0001。其中[ "eosio", "1000000000.0000 CYB"]可以改为'{"issuer":"eosio", "maximum_supply":"1000000000.0000 CYB"}'来体现参数对应关系。

然后将Token派发给指定人,并查看余额:

$ cleos push action eosio.token issue '[ "nmaccount", "100.0000 CYB", "memo" ]' -p eosio@active
executed transaction: 3c7ab21daa7000146a6f024271db18708301c4db23eb143af553a429c9f0a6ed  128 bytes  2015 us
#   eosio.token <= eosio.token::issue           {"to":"nmaccount","quantity":"100.0000 CYB","memo":"memo"}
#   eosio.token <= eosio.token::transfer        {"from":"eosio","to":"nmaccount","quantity":"100.0000 CYB","memo":"memo"}
#         eosio <= eosio.token::transfer        {"from":"eosio","to":"nmaccount","quantity":"100.0000 CYB","memo":"memo"}
#     nmaccount <= eosio.token::transfer        {"from":"eosio","to":"nmaccount","quantity":"100.0000 CYB","memo":"memo"}
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

$ cleos get table eosio.token nmaccount accounts
{
  "rows": [{
      "balance": "100.0000 CYB"
    }
  ],
  "more": false
}

# 使用currency balance
$ cleos get currency balance eosio.token nmaccount CYB
100.0000 CYB

这次输出包含几个不同的操作:一个issue和三个transfer。虽然我们签署执行的是issue,但是issue内部执行inline transfer(Inline通信模式),inline transfer通知发送和接收的帐户。这里的输出表明了被调用的Action处理的数据、触发的顺序、是否生成输出。

从技术上讲,是可以直接修改余额。但是,智能合约约定规定了所有帐户余额要通过使用它们内部的转移操作来实现。它还要求通知资金的发送方和接收方,以便它们可以自动处理。

接下来我们试试转账的功能,这里需要新建另外一个账号:

$ cleos create key --to-console
Private key: 5JC8P1rQJ2D9vMwacSivHG9kvHxtbzB6tk8chVPzU9hCrNURh1W
Public key: EOS57zTJCWoA6viGYi6y8mUKjfatSFZHxwVFmLdWoXpKDEC2Rx9GR

$ cleos wallet import -n nm1024 --private-key 5JC8P1rQJ2D9vMwacSivHG9kvHxtbzB6tk8chVPzU9hCrNURh1W
imported private key for: EOS57zTJCWoA6viGYi6y8mUKjfatSFZHxwVFmLdWoXpKDEC2Rx9GR

$ cleos create account eosio user EOS57zTJCWoA6viGYi6y8mUKjfatSFZHxwVFmLdWoXpKDEC2Rx9GR EOS57zTJCWoA6viGYi6y8mUKjfatSFZHxwVFmLdWoXpKDEC2Rx9GR
executed transaction: d95ddc6e1d7974b193f4d082e428ea765732dce4cf2fa0cad1ad5d893409b11b  200 bytes  647 us
#         eosio <= eosio::newaccount            {"creator":"eosio","name":"user","owner":{"threshold":1,"keys":[{"key":"EOS57zTJCWoA6viGYi6y8mUKjfat...
warning: transaction executed locally, but may not be confirmed by the network yet    ] 

$ cleos push action eosio.token transfer '[ "nmaccount", "user", "50.0000 CYB", "m" ]' -p nmaccount@active
executed transaction: d9c3e3d2d1e72339c7f8acedc1254c9a9d748edcc7f76e39b23200f641538b28  128 bytes  1348 us
#   eosio.token <= eosio.token::transfer        {"from":"nmaccount","to":"user","quantity":"50.0000 CYB","memo":"m"}
#     nmaccount <= eosio.token::transfer        {"from":"nmaccount","to":"user","quantity":"50.0000 CYB","memo":"m"}
#          user <= eosio.token::transfer        {"from":"nmaccount","to":"user","quantity":"50.0000 CYB","memo":"m"}
warning: transaction executed locally, but may not be confirmed by the network yet    ]

.
.
.
.
.
.
.
【本文章出自NM1024.com,转载请注明作者出处。】






>>转载请注明原文链接地址:EOS智能合约-Hello World与Token