【Ethereum 智能合約開發筆記】深入智能合約 ABI

Anderson Chen
Taipei Ethereum Meetup
8 min readFeb 26, 2018

--

虛擬貓咪合約 ABI

開發 DApp 時要呼叫在區塊鏈上的 Ethereum 智能合約,就需要智能合約的 ABI。本篇希望更多瞭解 ABI,像是為什麼需要 ABI?如何解讀 Ethereum 的智能合約 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 智能合約可以被大家使用前,必須先被部署到區塊鏈上。

從智能合約的原始碼到使用智能合約,大概包含幾個步驟:

  1. 撰寫智能合約的原始碼(一般是用 Solidity 寫)
  2. 編譯智能合約的原始碼成可在 EVM 上執行的 bytecode(binary code)。同時可以透過編譯取得智能合約的 ABI
  3. 部署智能合約,實際上是把 bytecode 儲存在鏈上(透過一個 transaction),並取得一個專屬這個合約的地址
  4. 如果要寫個程式呼叫這個智能合約,就要把資料發送到這個合約的地址(一樣透過一個 transaction)。Ethereum 節點會根據輸入的資料,選擇要執行合約中的哪一個 function 和要輸入的參數

而要如何知道這個智能合約提供哪些 function 以及應該要傳入什麼樣的參數呢?這些資訊就是記錄在智能合約的 ABI!

Ethereum 智能合約 ABI

Ethereum 智能合約 ABI 用一個 array 表示,其中會包含數個用 JSON 格式表示的 FunctionEvent。根據最新的 Solidity 文件:

Function

共有 7 個欄位:

仔細看會發現 payableconstant 這兩個欄位所描述的內容,似乎已包含在 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 這個欄位統一表示,payableconstant 目前保留是為了向後兼容。這個改動詳細的內容和討論可參考:

Event

共有 4 個欄位:

更新智能合約狀態需要發送 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 Set(address indexed _from, uint value)

要詳細了解 Solidity Event 可參考 Technical Introduction to Events and Logs in Ethereum中文翻譯)。

用一個簡單的智能合約舉例

這個智能合約包含:

  • data:一個可改寫的 state variable,會自動產生一個只能讀取的 data() function
  • set():一個改寫 data 值的 function
  • Set():一個在每次改寫 data 時紀錄 Log 的 event

智能合約 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 做驗證,可以同時看到合約 ABI。

Etherscan

另外 Etherscan 提供 API,可用來取得經驗證的合約 ABI。

--

--