深入解析ABI

本文在 區塊鏈技術中文社區 同步發表

什麼是ABI

n

ABI是Application Binary Interface的縮寫,字面意思 應用二進位介面,可以通俗的理解為 合約的介面說明。當合約被編譯後,那麼它的abi也就確定了。

我們先來看個極簡單的合約和它的abi

n

pragma solidity ^0.4.4;ncontract test { n string public a;n function modify_a(string val) {n a = val;n }n}n

編譯後的位元組碼

n

6060604052341561000c57fe5b5b60e18061001b6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630dbe671f146044578063efa3b144146067575bfe5b3415604b57fe5b60516098565b6040518082815260200191505060405180910390f35b3415606e57fe5b60826004808035906020019091905050609e565b6040518082815260200191505060405180910390f35b60005481565b60006005820260008190555060005490505b9190505600a165627a7a72305820e7910925075fb58319dd637b47520b821714dd11ad896cb6d8272151aff714690029n

abi

n

[{"constant":true,"inputs":[],"name":"a","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"val","type":"uint256"}],"name":"modify_a","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"}]modify_a","outputs":[],"payable":false,"type":"function"}]n

為了看起來更方便,把它格式化一下

n

[n {n "constant": true,n "inputs": [nn ],n "name": "a",n "outputs": [n {n "name": "",n "type": "uint256"n }n ],n "payable": false,n "type": "function"n },n {n "constant": false,n "inputs": [n {n "name": "val",n "type": "uint256"n }n ],n "name": "modify_a",n "outputs": [n {n "name": "",n "type": "uint256"n }n ],n "payable": false,n "type": "function"n }n]n

可以看到,解析之後是一個數組,它包含兩個對象,每個對象都對應著一個合約方法,這裡因為a是public類型的,編譯的時候會自動為它生成get()方法,所以這個合約實際是包含兩個方法的,解析之後的json應該不難看懂,下面對幾個關鍵字做以解釋

n

  • type 方法類型,包括function, constructor, fallback(預設方法)可以預設,默認為function
  • n

  • name 方法名
  • n

  • inputs 方法參數,它是一個對應數組,數組裡的每個對象都是一個參數說明
    • name 參數名
    • n

    • type 參數類型
    • n

  • n

  • outputs 方法返回值,格式和inputs類型,如果沒有返回值可以預設
  • n

  • constant 布爾值,如果為true指明方法不會修改合約的狀態變數
  • n

  • payable 布爾值,標明方法是否可以接收ether
  • n

構造方法和預設方法不能有name 和 outputs , 預設方法也不能有inputs

向一個沒有payable標註的方法發送ether會拋異常

n

abigen部分源碼解析

n

以上是一個小demo和對abi的解釋,接下來看看源碼中abigen部分。在cmd 下每個包都是一個獨立的可編譯執行的程序,其中就包括abigen,簡單的說就是abi生成器,類似於php yii框架中的gii工具,正常編譯後可以調用abigen命令查看一下

n

luren5@ubuntu:~/Project/src/github.com/ethereum/go-ethereum/cmd/abigen$ abigennNo contract ABI (--abi) or Solidity source (--sol) specifiedn

從這個源中可以看到,這個命令需要一些參數

n

abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind")n binFlag = flag.String("bin", "", "Path to the Ethereum contract bytecode (generate deploy method)")n typFlag = flag.String("type", "", "Struct name for the binding (default = package name)")nn solFlag = flag.String("sol", "", "Path to the Ethereum contract Solidity source to build and bind")n solcFlag = flag.String("solc", "solc", "Solidity compiler to use if source builds are requested")n excFlag = flag.String("exc", "", "Comma separated types to exclude from binding")nn pkgFlag = flag.String("pkg", "", "Package name to generate the binding into")n outFlag = flag.String("out", "", "Output file for the generated binding (default = stdout)")n langFlag = flag.String("lang", "go", "Destination language for the bindings (go, java, objc)")n

我們來對這些參數做些解析

abi 將要綁定的存儲ABI json文件的路徑

bin 對應的存儲合約編譯後的位元組碼的文件

type 結構名,默認為包名

n

sol 將要綁定的存儲合約源碼的文件的路徑

solc 指定Solidity編譯器版本

exc 需要排除綁定的合約

n

pkg 將要生成的文件的包名

out 輸出的目標文件,默認是直接指印到終端

lang 目標文件的語句,可以是go、java或者objc

n

if *solFlag != "" {n …n} else {n …n}n

從源碼中可以看出,上述所列的參數 abi``bin``type 為一組,sol``solc``exc 為一組,abigen的輸入源有兩種,一種是合約的源碼,abigen裡面去調用compiler.CompileSolidity(*solcFlag, *solFlag) 去編譯,第二種是輸入已經編譯好的合約位元組碼和對應的abi。 目標和結果都一樣,生成與合約綁定的合約調用代碼,lang 是生成語言的類型,pkg 生成代碼的包,out指定輸出文件

n

// Generate the contract bindingn code, err := bind.Bind(types, abis, bins, *pkgFlag, lang)n if err != nil {n fmt.Printf("Failed to generate ABI binding: %vn", err)n os.Exit(-1)n }n // Either flush it out to a file or display on the standard outputn if *outFlag == "" {n fmt.Printf("%sn", code)n returnn }n if err := ioutil.WriteFile(*outFlag, []byte(code), 0600); err != nil {n fmt.Printf("Failed to write ABI binding: %vn", err)n os.Exit(-1)n }n

來做個演示

n

合約文件 test.sol, 合約內容即上面展示的部分。執行以下

n

abigen --sol test.sol -pkg ccaa --lang go --out cc.gon

發現生成了一個cc.go文件,它就是這個合約的綁定文件,裡面有各種可以與合約交互的方法,具體用法將在下一節講解

n

package ccaanimport (n "math/big"n "strings"n

包名即前面指定的 ccaa

如果一個sol源文件裡面有多個合約,例如 test, test1, test2 現在只需要生成 test, test2這兩個合約的綁定,那麼可以通過 exc 參數來排除(exclude)的

n

exclude[strings.ToLower(kind)] = truen……nif exclude[strings.ToLower(name)] {n continuen}n

abigen --sol test.sol -pkg ccaa --exc test.sol:test1 --lang go --out cc.gon

推薦閱讀:

比特幣,萊特幣,以太坊,以太經典,BCH,Dash, XRP價格分析(76)--1/14/2018
AWARE:催生區塊鏈時代的伯克希爾?
遭遇「屠殺」,數字貨幣還遠未到稱王之時
面向區塊鏈開發
比特幣,萊特幣,以太坊,以太經典,BCH,Dash, XRP價格分析(67)--12/20/2017

TAG:以太坊 | 区块链Blockchain |