開發 DApp 時要調用在區塊鍊上的以太坊智能合約,就需要智能合約的 ABI。本文希望更多了解 ABI,如為什麼需要 ABI?如何解讀 Ethereum 的智能合約 ABI?以及如何取得合約的 ABI?
數字貓合約 ABI
ABI(Application Binary Interface)
如果了解 API 就很容易了解 ABI。簡單來說,API 是程式與程式間互動的接口。這個接口包含程式提供外界存取所需的 functions、variables 等。ABI 也是程式間互動的接口,但程式是被編譯後的 binary code。是以同樣的接口,但傳遞的是 binary 格式的資訊。是以 ABI 就要描述如何 decode/encode 程式間傳遞的 binary 資訊。下圖以 Linux 為例,描述 Linux 中 API、ABI 和程式的關系。
Linux API and ABI
編譯和部署智能合約
在 Ethereum 智能合約可以被大家使用前,必須先被部署到區塊鍊上。
從智能合約的代碼到使用智能合約,大概包含幾個步驟:
- 編寫智能合約的代碼(一般是用 Solidity 寫)
- 編譯智能合約的代碼變成可在 EVM 上執行的 bytecode(binary code)。同時可以通過編譯取得智能合約的 ABI
- 部署智能合約,實際上是把 bytecode 存儲在鍊上(通過一個transaction),并取得一個專屬于這個合約的位址
- 如果要寫個程式調用這個智能合約,就要把資訊發送到這個合約的位址(一樣的也是通過一個 transaction)。Ethereum 節點會根據輸入的資訊,選擇要執行合約中的哪一個 function 和要輸入的參數
而要如何知道這這個智能合約提供哪些 function 以及應該要傳入什麼樣的參數呢?這些資訊就是記錄在智能合約的 ABI!
Ethereum 智能合約 ABI
Ethereum 智能合約 ABI 用一個 array 表示,其中會包含數個用 JSON 格式表示的 Function 或 Event。根據最新的 Solidity 檔案:
Function
共有 7 個參數:
-
:a string,function 名稱name
-
:a string,"function", "constructor", or "fallback"type
-
:an array,function 輸入的參數,包含:inputs
-
:a string,參數名name
-
:a string,參數的 data type(e.g. uint256)type
-
:an array,如果輸入的參數是 tuple(struct) type 才會有這個參數。描述 struct 中包含的參數類型components
-
-
:an array,function 的傳回值,和outputs
使用相同表示方式。如果沒有傳回值可忽略,值為inputs
[]
-
:payable
,function 是否可收 Ether,預設為true
false
-
constant
,function 是否會改寫區塊鍊狀态,反之為true
false
-
:a string,其值可能為以下其中之一:"pure"(不會讀寫區塊鍊狀态)、"view"(隻讀不寫區塊鍊狀态)、"payable" and "nonpayable"(會改區塊鍊狀态,且如可收 Ether 為 "payable",反之為 "nonpayable")stateMutability
仔細看會發現
payable
和
constant
這兩個參數所描述的內容,似乎已包含在
stateMutability
中。
事實也确實是這樣的,在
Solidity v0.4.16中把
constant
這個修飾function 的 key words 分成:
view
(neither reads from nor writes to the state)和
pure
(does not modify the state),并從 v0.4.17 開始 Type Checker 會強制檢查。
constant
改為隻用來修飾不能被修改的 variable。并在 ABI 中加入
stateMutability
這個參數統一表示,
payable
constant
目前保留是為了向後相容。這個改動詳細的內容和讨論可參考:
https://github.com/ethereum/solidity/issues/992Event
共有 4 個參數:
-
: a string,event 的名稱name
-
: a string,always "event"type
-
: an array,輸入參數,包含:inputs
-
: a string,參數名稱name
-
: a string,參數的 data type(e.g. uint256)type
-
: an array,如果輸入參數是 tuple(struct) type 才會有這個參數。描述 struct 中包含的資訊類型components
-
:indexed
,如果這個參數被定義為 indexed ,反之為true
false
-
-
anonymous
,如果 event 被定義為 anonymoustrue
更新智能合約狀态需要發送 transaction,transaction 需要等待驗證,是以更新合約狀态是非同步的,無法馬上取得傳回值。使用 Event 可以在狀态更新成功後,将相關資訊記錄到 Log,并讓監聽這個 Event 的 DApp 或任何應用這個接口的程式收到通知。每筆 transaction 都有對應的 Log。
是以簡單來說,Event 可用來:1. 取得 function 更新合約狀态的傳回值 2. 也可作為合約另外的存儲空間。
Event 的參數分為:有
indexed
,和其他沒有
indexed
的。有
indexed
的參數可以使用 filter,例如同一個 Event,我可以選擇隻監聽從特定 address 發出來的交易。每筆 Log 的資訊同樣分為兩個部分:Topics(長度最多為 4 的 array) 和 Data。有
indexed
的參數會存儲存在 Log 的 Topics,其他的存在 Data。如果定義為
anonymous
,就不會産生以下示例中的 Topics[0],其值為 Event signature 的 hash,作為這個 Event 的 ID。
Event
event Set(address indexed _from, uint value)
用一個簡單的智能合約舉個例子
這個智能合約包含:
-
:一個可修改的 state variable,會自動産生一個隻能讀取的data
functiondata()
-
:一個修改set()
值的 functiondata
-
:一個在每次修寫Set()
時記錄 Log 的 eventdata
智能合約 Source Code:
pragma solidity ^0.4.20;
contract SimpleStorage {
uint public data;
event Set(address indexed _from, uint value);
function set(uint x) public {
data = x;
Set(msg.sender, x);
}
}
智能合約 ABI:
[{
"constant": true,
"inputs": [],
"name": "data",
"outputs": [{"name": "","type": "uint256"}],
"payable": false,
"stateMutabㄒility": "view",
"type": "function"
},
{
"anonymous": false,
"inputs": [{"indexed": true,"name": "_from","type": "address"},{"indexed": false,"name": "value","type": "uint256"}],
"name": "Set",
"type": "event"
},
{
"constant": false,
"inputs": [{"name": "x","type": "uint256"}],
"name": "set",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}]
取得 Ethereum 智能合約 ABI
Solidity Compiler
可以用 Solidity Compiler 取得合約 ABI,我使用 JavaScript 版本的 Compiler 為例。
安裝:
npm install solc -g
取得合約 ABI:
solcjs simpleStorage.sol --abi
會生成一個 simpleStorage_sol_SimpleStorage.abi 檔案,裡面就是合約ABI 內容。
也可以取得合約的 binary code:
solcjs your_contract.sol --bin
Remix
同樣的使用 Solidity Compiler,也可以用 Remix。在合約的 Details 可以看到完整的 ABI。可以在 Settings 中指定 Compiler 版本。
Remix
Etherscan
許多知名合約會把合約 source code 放上 Etherscan 做驗證,可以同時看到h 合約ABI。
另外 Etherscan 提供
API,可用來取得經過驗證的合約 ABI。
順便安利兩個區塊鍊、以太坊開發DApp的實戰教程:
1. 适合區塊鍊新手的以太坊DApp開發:
http://xc.hubwiz.com/course/5a952991adb3847553d205d12. 用區塊鍊、星際檔案系統(IPFS)、Node.js和MongoDB來建構電商平台:
http://xc.hubwiz.com/course/5abbb7acc02e6b6a59171dd6