【許曉笛】開發第一個 EOS 智能合約

稍微瞭解 EOS 系統,你就會知道 EOS 的智能合約基於 WebAssembly(WASM) 技術,這種技術在性能和跨平臺兼容性之間取得了很好的平衡,通過將原始代碼編譯成字節碼,使得代碼可以在多種平臺的 WASM 虛擬機(或者叫解釋器)中執行。得到了蘋果和谷歌等科技巨頭的支持,被譽爲下一代互聯網前端技術。目前的 WebAssembly 技術支持 C/C++ 語言,並開發了 JavaScript 接口,並被 Chrome、Edge、Safari、Firefox 等幾乎所有的主流瀏覽器支持。

因爲使用了 WebAssembly,目前的 EOS 智能合約只支持 C/C++ 語言,簡單的智能合約由 3 種文件組成:.hpp文件、.cpp文件、.abi 文件。其中 hpp 爲 C++ 頭文件,一般用來定義類及其成員變量與成員函數。cpp 爲 C++ 文件,用來實現 hpp 中聲明的成員函數,實現智能合約的業務邏輯。abi(Application Binary Interface) 文件爲二進制接口文件,文件格式類似 JSON,用來定義智能合約與 EOS 系統外部交互的數據接口。

如果智能合約的非常簡單,只有一個 cpp 文件,可以省略 hpp 文件,將類與成員定義在 cpp 文件中。abi 文件應該由 C++ 程序需要的數據庫空間和外部接口生成,不過 EOS 開發了 abi 自動生成工具,可以根據智能合約代碼自動生成 abi 文件,減輕了開發工作量。所以最簡單的智能合約只需實現 cpp 文件。

Hello 智能合約

一般的操作系統上手時,慣例是編寫一個 Hello World 程序,是主動輸出一句話。但我們不一樣,我們編寫的是一個智能合約,智能合約強調的是互動,在 EOS 裏叫做 Action,Action 表示別人可以對合約做什麼動作,所有智能合約代碼都是對 Action 的迴應,是被動的。下面就是第一個 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) )

我們在代碼中定義了一個類:hello,這個類名與合約的賬戶名沒關係,類中只有一個簡單的方法:

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

這就是 EOS 智能合約裏所謂的 Action,我們定義了一個叫 hi 的 Action,參數是另一個賬戶名,函數體是打印一句話,迴應 hello。 也就是說別的賬戶可以調用這個合約的 hi Action,這個 hello 合約就會打印一句 hello 來回應。

最後一行代碼:

EOSIO_ABI( hello, (hi) )

EOSIO_ABI 是一個宏,將特定類的特定方法暴漏給系統,成爲別的賬戶可以調用的 Action。

編譯智能合約

我們使用 eosiocpp 工具將寫好的 hello.cpp 編譯成爲字節碼文件(.wast):

$ eosiocpp -o hello.wast hello.cpp

然後使用 eosiocpp 工具自動生成 abi 文件:

$ eosiocpp -g hello.abi hello.cpp
Generated hello.abi

看一下生成的 abi 文件內容:

{
"____comment": "This file was generated by eosio-abigen. DO NOT EDIT - 2018-04-16T13:37:55",
"types": [],
"structs": [{
"name": "hi",
"base": "",
"fields": [{
"name": "user",
"type": "account_name"
        }
      ]
    }
  ],
"actions": [{
"name": "hi",
"type": "hi",
"ricardian_contract": "# CONTRACT FOR hello::hi## ACTION NAME: hi\n 
      ### Parameters### Parameters\nInput paramters:Input paramters:\n 
      \n 
      * `user` (string to include in the output)* `user` (string to include in the output)\n
      \n 
      Implied parameters: Implied parameters: \n 
      \n 
      * `account_name` (name of the party invoking and signing the contract)* `account_name` (name of the party invoking and signing the contract)\n 
      \n 
      ### Intent### Intent\n 
      INTENT. The intention of the author and the invoker of this contract is to print output. It shall have no other effect.INTENT. The intention of the author and the invoker of this contract is to print output. It shall have no other effect.\n 
      \n 
      ### Term### Term\n 
      TERM. This Contract expires at the conclusion of code execution.TERM. This Contract expires at the conclusion of code execution.\n" 
    }
  ],
"tables": [],
"ricardian_clauses": [

   ...
   ...
   ...

  ]
}

我們省略了 ricardian_clauses ,也就是李嘉圖條款部分(李嘉圖合約指的是人與機器都能讀懂的合同,EOS 最近纔將其加入智能合約中)。我們看到 abi 文件中已經聲明瞭 hi 這個 Action,並說明了這個 Action 的李嘉圖合約,大概意思是本合約的輸入爲一串字符(user),本合約意圖是打印輸出,沒有其他效果。

上傳智能合約

上傳智能合約之前,我們要先給智能合約建立一個賬戶 EOS 裏賬戶和智能合約是一一對應的。使用 EOS 的 cleos 命令行工具創建賬戶:

$ cleos create account eosio hello.code EOS7ijWCBmoXBi3CgtK7DJxentZZeTkeUnaSDvyro9dq7Sd1C3dC4 EOS7ijWCBmoXBi3CgtK7DJxentZZeTkeUnaSDvyro9dq7Sd1C3dC4

命令中,hello.code 就是這個智能合約的賬戶名,EOS系統的賬戶名要求 12 字符以內。後面兩個公鑰是在本地測試網絡中有建立賬戶權限的公鑰(對應本地測試網絡中的 eosio 賬戶)。

然後就可以上傳智能合約了:

$ cleos set contract hello.code ../hello -p hello.code

使用智能合約

我們使用 user 賬戶調用 hello.codehi Action:

$ cleos push action hello.code hi '["user"]' -p user

hello.code 表示執行 hello.code 合約,hi 表示執行合約裏的 hi Action,'["user"]' 是根據 abi 寫的傳入參數, -p 參數表示使用哪個賬戶的權限 (permission)。

以下是系統迴應:

executed transaction: 4c10c1426c16b1656e802f3302677594731b380b18a44851d38e8b5275072857  244 bytes  1000 cycles
#    hello.code <= hello.code::hi               {"user":"user"}
>> Hello, user

說明執行了 hello.code 合約的 hi Action,並且系統輸出爲 Hello, user,智能合約成功對 Action 進行了迴應。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章