深刻以太坊智能合約 ABI

開發 DApp 時要調用在區塊鏈上的 Ethereum 智能合約,就須要智能合約的 ABI。本文但願更多瞭解 ABI,如爲何須要 ABI?如何解讀 Ethereum 的智能合約 ABI?以及如何取得智能的 ABI?git

數字貓合約 ABI

ABI(Application Binary Interface)

若是理解 API 就很容易瞭解 ABI。簡單來講,API 是程序與程序間互動的接口。這個接口包含程序提供外界存取所需的 functions、variables 等。ABI 也是程序間互動的接口,但程序是被編譯後的 binary code。因此一樣的接口,但傳遞的是 binary 格式的信息。因此 ABI 就要描述如何 decode/encode 程序間傳遞的 binary 信息。下圖以 Linux 爲例,描述 Linux 中 API、ABI 和程序的關係。github

Linux API and ABI

編譯和部署智能合約

在 Ethereum 智能合約能夠被你們使用前,必須先被部署到區塊鏈上。npm

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

  1. 編寫智能合約的代碼(通常是用 Solidity 寫)
  2. 編譯智能合約的代碼變成可在 EVM 上執行的 bytecode(binary code)。同時能夠經過編譯取得智能合約的 ABI
  3. 部署智能合約,其實是把 bytecode 存儲在鏈上(經過一個transaction),並取得一個專屬於這個合約的地址
  4. 若是要寫個程序調用這個智能合約,就要把信息發送到這個合約的地址(同樣的也是經過一個 transaction)。Ethereum 節點會根據輸入的信息,選擇要執行合約中的哪個 function 和要輸入的參數

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

Ethereum 智能合約 ABI

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

Function

共有 7 個參數:3d

  1. name:a string,function 名稱code

  2. type:a string,"function", "constructor", or "fallback"component

  3. inputs:an array,function 輸入的參數,包含:教程

    • name:a string,參數名

    • type:a string,參數的 data type(e.g. uint256)

    • components:an array,若是輸入的參數是 tuple(struct) type 纔會有這個參數。描述 struct 中包含的參數類型

  4. outputs:an array,function 的返回值,和 inputs 使用相同表示方式。若是沒有返回值可忽略,值爲 []

  5. payabletrue,function 是否可收 Ether,預設爲 false

  6. constanttrue,function 是否會改寫區塊鏈狀態,反之爲 false

  7. stateMutability:a string,其值可能爲如下其中之一:"pure"(不會讀寫區塊鏈狀態)、"view"(只讀不寫區塊鏈狀態)、"payable" and "nonpayable"(會改區塊鏈狀態,且如可收 Ether 爲 "payable",反之爲 "nonpayable")

仔細看會發現 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/992

Event

共有 4 個參數:

  1. name: a string,event 的名稱

  2. type: a string,always "event"

  3. inputs: an array,輸入參數,包含:

    • name: a string,參數名稱

    • type: a string,參數的 data type(e.g. uint256)

    • components: an array,若是輸入參數是 tuple(struct) type 纔會有這個參數。描述 struct 中包含的信息類型

    • indexedtrue,若是這個參數被定義爲 indexed ,反之爲 false

  4. anonymoustrue,若是 event 被定義爲 anonymous

更新智能合約狀態須要發送 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)

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

這個智能合約包含:

  • 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 作驗證,能夠同時看到h 合約ABI。

Etherscan

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

安利兩個區塊鏈、以太坊開發DApp的實戰教程: 1.適合區塊鏈新手的以太坊DApp開發:

http://xc.hubwiz.com/course/5a952991adb3847553d205d1

2.用區塊鏈、星際文件系統(IPFS)、Node.js和MongoDB來構建電商平臺:

http://xc.hubwiz.com/course/5abbb7acc02e6b6a59171dd6

相關文章
相關標籤/搜索