1. 概述
官方關(guān)于智能合約介紹的文檔:
https://developers.eos.io/eosio-cpp/docs/introduction
Hello World智能合約文檔:
https://developers.eos.io/eosio-cpp/docs/hello-world
基于EOSIO
的區(qū)塊鏈?zhǔn)褂?a target="_blank" rel="nofollow">WebAssembly(WASM)執(zhí)行用戶生成的應(yīng)用程序和代碼。WASM
是一種新興的Web
標(biāo)準(zhǔn)力试,得到了Google
,Microsoft
饲做,Apple
和其他公司的廣泛支持鸥昏。目前,用于構(gòu)建編譯為WASM
的應(yīng)用程序的最成熟的工具鏈?zhǔn)?a target="_blank" rel="nofollow">clang / llvm及其C / C ++
編譯器。為獲得最佳兼容性脂矫,建議使用EOSIO
工具鏈。
第三方開發(fā)的其他工具鏈包括:Rust
霉晕,Python
和Solidity
羹唠。雖然這些其他語言可能看起來更簡(jiǎn)單,但它們的性能可能會(huì)影響可以構(gòu)建的應(yīng)用程序的規(guī)模娄昆。我們希望C ++
將成為開發(fā)高性能和安全智能合約的最佳語言佩微,并計(jì)劃在可預(yù)見的未來使用C ++
。
在使用C++
編寫完成合約代碼后萌焰,通過EOSIO
軟件中提供的eosiocpp
工具哺眯,將C++
代碼編譯生成WASM
(wasm
的文本格式是后綴是wast
)文件和abi
文件,再利用cleos
工具(將代碼部署到鏈上扒俯,也就是存到區(qū)塊數(shù)據(jù)中奶卓。
2. EOS智能合約與以太坊智能合約的區(qū)別
以下內(nèi)容節(jié)選自全面理解EOS——4.測(cè)試智能合約與EOS發(fā)幣
1.名稱不同
在EOS中具有賬號(hào)的概念,智能合約名也就是賬號(hào)名撼玄。而以太坊中的合約是一個(gè)個(gè)不同的地址夺姑。
2.升級(jí)方式不同
以太坊的合約不可升級(jí),一旦部署之后掌猛,代碼不可修改盏浙。如果需要修改,只能在一個(gè)新的地址上重新部署荔茬。而EOS的智能合約和賬號(hào)綁定后废膘,賬號(hào)可直接升級(jí)智能合約的代碼,其實(shí)就相當(dāng)于向鏈上重新上傳了代碼慕蔚。
3.資源消耗不同
以太坊智能合約的執(zhí)行需要消耗gas丐黄,也就是每個(gè)步驟都有手續(xù)費(fèi),手續(xù)費(fèi)不夠就不會(huì)繼續(xù)執(zhí)行孔飒,之前的操作也會(huì)被回滾灌闺,而且手續(xù)費(fèi)也不退艰争。而EOS的智能合約不需要首先費(fèi),但是部署合約要消耗RAM
桂对,傳送信息和執(zhí)行合約需要消耗抵押而得的CPU
和網(wǎng)絡(luò)帶寬
园细。
3.文件結(jié)構(gòu)
eosiocpp工具可以初始化一份新的合約,簡(jiǎn)化我們的工作接校。
使用eosiocpp
創(chuàng)建一份智能合約:
yuyangdeMacBook-Pro:eos yuyang$ eosiocpp -n hello
此命令會(huì)在當(dāng)前目錄創(chuàng)建一個(gè)名為hello
的文件夾猛频,里面包含三個(gè)文件:
hello.abi
abi文件
hello.cpp
包含合同函數(shù)實(shí)現(xiàn)的源文件
hello.hpp
頭文件:包含變量,常量蛛勉,和cpp文件
的函數(shù)引用
如果.cpp
文件是使用eosiocpp
工具生成的鹿寻,則生成的.cpp
文件將類似于以下內(nèi)容:
#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
文件的內(nèi)容如下:
/**
* @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 創(chuàng)建賬號(hào)
創(chuàng)建名為hello.code
的賬號(hào)用于部署合約:
打開并解鎖錢包:
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 *"
]
生成密鑰對(duì):
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
導(dǎo)入密鑰對(duì)到錢包:
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
創(chuàng)建賬號(hào):
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
查看賬號(hào):
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
中的內(nèi)容:
#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中定義了對(duì)外可調(diào)用的函數(shù)hi方法诽凌,在hi方法中打印了調(diào)用者的賬戶名
生成.wast
文件
yuyangdeMacBook-Pro:eos yuyang$ cd hello
yuyangdeMacBook-Pro:hello yuyang$ eosiocpp -o hello.wast hello.cpp
多了hello.wasm
和hello.wast
文件
將剛才創(chuàng)建的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
應(yīng)用程序二進(jìn)制接口(ABI)是一個(gè)基于JSON的描述,介紹如何在JSON和二進(jìn)制表示之間轉(zhuǎn)換用戶操作侣诵。ABI還描述了如何將數(shù)據(jù)庫狀態(tài)轉(zhuǎn)換為JSON或從JSON轉(zhuǎn)換痢法。通過ABI描述合同后,開發(fā)人員和用戶將能夠通過JSON無縫地與您的合同進(jìn)行交互杜顺。
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 合約交互
在執(zhí)行調(diào)用命令之前财搁,我們先簡(jiǎn)單地了解EOS中的一個(gè)概念:transaction
和action
。
qction
表示單個(gè)操作躬络,而transaction
是一個(gè)或多個(gè)action
的集合尖奔。action
是合約和賬戶之間進(jìn)行通信的方式。action
可以單獨(dú)執(zhí)行穷当,或者組合起來作為一個(gè)整體執(zhí)行提茁。EOS
中的action
就相當(dāng)于以太坊中的transaction
。
調(diào)用合約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
如果看不到合約執(zhí)行時(shí)的打印內(nèi)容馁菜≤畋猓可以重啟nodeos
,并且加上--contracts-console
參數(shù)啟動(dòng)汪疮,以查看合約的輸出內(nèi)容:
yuyangdeMacBook-Pro:nodeos yuyang$ nodeos --contracts-console
或者編輯配置文件~/Library/Application Support/eosio/nodeos/config
中的config.ini
峭火,找到以下內(nèi)容:
# print contract's output to console (eosio::chain_plugin)
contracts-console = false
將false
改為true
再次調(diào)用合約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
的打印內(nèi)容
再查看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]
由于此時(shí)合約授權(quán)所有人調(diào)用hi
方法,所以也可以進(jìn)行如下操作:
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
如果我們希望授權(quán)者和調(diào)用者為同一個(gè)賬戶铲咨,可以加入以下代碼:
void hi( account_name user ) {
require_auth( user );
print( "Hello, ", name{user} );
}
重新編譯wast
文件躲胳,生成abi
文件,再次部署合約并調(diào)用纤勒,如果此時(shí)授權(quán)者和調(diào)用者并非同一個(gè)賬戶,合約會(huì)拋出錯(cuò)誤:
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]
我們重新將授權(quán)者設(shè)為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
將授權(quán)者設(shè)為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