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 ]
[email protected]:~/eos$ cleos get currency balance acctoken inita
75.0000 EOS
[email protected]:~/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 ]