EOSIO 指南(瞭解ABI文件)

瞭解ABI文件

介紹

以前,你使用提供的ABI文件部署了eosio.token合約,本教程將概述ABI文件如何與eosio.token合約相關聯。git

可使用eosio.cdt提供的eosio-cpp實用程序生成ABI文件,可是,有幾種狀況可能致使ABI的生成出現故障或徹底失敗,高級C++模式能夠將其提高,自定義類型有時會致使ABI生成的問題,所以,你必須瞭解ABI文件的工做原理,以便在必要時進行調試和修復。github

什麼是ABI?

應用程序二進制接口(ABI)是一個基於JSON的描述,介紹如何在JSON和二進制表示之間轉換用戶操做,ABI還描述瞭如何將數據庫狀態轉換爲JSON或從JSON轉換,經過ABI描述合約後,開發人員和用戶將可以經過JSON無縫地與你的合約進行交互。數據庫

安全說明

執行交易時能夠繞過ABI,傳遞給合約的消息和操做沒必要符合ABI,ABI是一個指南,而不是看門人。segmentfault

建立一個ABI文件

從空的ABI開始,將其命名爲eosio.token.abi安全

{
   "version": "eosio::abi/1.0",
   "types": [],
   "structs": [],
   "actions": [],
   "tables": [],
   "ricardian_clauses": [],
   "abi_extensions": [],
   "___comment" : ""
}

types

ABI容許任何客戶端或接口解釋甚至爲你的合約生成GUI,爲了使其以一致的方式工做,請描述在ABI中須要描述的任何公共操做或結構中用做參數的自定義類型。函數

內置類型

EOSIO實現了許多自定義內置類型,不須要在ABI文件中描述內置類型,若是你想熟悉EOSIO的內置類型,它們定義在這裏ui

{
   "new_type_name": "name",
   "type": "name"
}

ABI如今看起來像這樣:this

{
   "version": "eosio::abi/1.0",
   "types": [{
     "new_type_name": "name",
     "type": "name"
     }],
   "structs": [],
   "actions": [],
   "tables": [],
   "ricardian_clauses": [],
   "abi_extensions": []
}

structs

暴露於ABI的結構也須要描述,經過查看eosio.token.hpp,能夠快速肯定公共操做使用了哪些結構,這對下一步尤其重要。調試

JSON中的結構對象定義以下所示:code

{
   "name": "issue", //The name 
   "base": "",             //Inheritance, parent struct
   "fields": []            //Array of field objects describing the struct's fields. 
}

fields

{
   "name":"", // The field's name
   "type":""   // The field's type
}

eosio.token合約中,有許多結構須要定義,請注意,並不是全部結構都是顯式定義的,有些結構對應於操做的參數,如下是須要對eosio.token合約進行ABI描述的結構列表。

隱式結構

如下結構是隱式的,由於結構從未在合約中顯式定義,查看create操做,你將找到兩個參數,類型爲nameissuerasset類型的maximum_supply,爲簡潔起見,本教程不會分解每一個結構,但應用相同的邏輯,你將獲得如下結果:

create

{
  "name": "create",
  "base": "",
  "fields": [
    {
      "name":"issuer", 
      "type":"name"
    },
    {
      "name":"maximum_supply", 
      "type":"asset"
    }
  ]
}

issue

{
  "name": "issue",
  "base": "",
  "fields": [
    {
      "name":"to", 
      "type":"name"
    },
    {
      "name":"quantity", 
      "type":"asset"
    },
    {
      "name":"memo", 
      "type":"string"
    }
  ]
}

retire

{
  "name": "retire",
  "base": "",
  "fields": [
    {
      "name":"quantity", 
      "type":"asset"
    },
    {
      "name":"memo", 
      "type":"string"
    }
  ]
}

transfer

{
  "name": "transfer",
  "base": "",
  "fields": [
    {
      "name":"from", 
      "type":"name"
    },
    {
      "name":"to", 
      "type":"name"
    },
    {
      "name":"quantity", 
      "type":"asset"
    },
    {
      "name":"memo", 
      "type":"string"
    }
  ]
}

close

{
  "name": "close",
  "base": "",
  "fields": [
    {
      "name":"owner", 
      "type":"name"
    },
    {
      "name":"symbol", 
      "type":"symbol"
    }
  ]
 }

顯式結構

這些結構是顯式定義的,由於它們是實例化多索引表的條件,描述它們與定義如上所示的隱式結構沒有什麼不一樣。

account

{
  "name": "account",
  "base": "",
  "fields": [
    {
      "name":"balance", 
      "type":"asset"
    }
  ]
}

currency_stats

{
  "name": "currency_stats",
  "base": "",
  "fields": [
    {
      "name":"supply", 
      "type":"asset"
    },
    {
      "name":"max_supply", 
      "type":"asset"
    },
    {
      "name":"issuer", 
      "type":"account_name"
    }
  ]
}

actions

操做的JSON對象定義以下所示:

{
  "name": "transfer",             //The name of the action as defined in the contract
  "type": "transfer",             //The name of the implicit struct as described in the ABI
  "ricardian_contract": ""     //An optional ricardian clause to associate to this action describing its intended functionality.
}

經過聚合eosio.token合約頭文件中描述的全部公共函數來描述eosio.token合約的操做。

而後根據以前描述的結構描述每一個操做的類型,在大多數狀況下,函數名稱和結構名稱將相等,但沒必要相等。

下面是連接到其源代碼的操做列表,其中提供了示例JSON,以瞭解每一個操做的描述方式。

create

{
  "name": "create",
  "type": "create",
  "ricardian_contract": ""
}

issue

{
  "name": "issue",
  "type": "issue",
  "ricardian_contract": ""
}

retire

{
  "name": "retire",
  "type": "retire",
  "ricardian_contract": ""
}

transfer

{
  "name": "transfer",
  "type": "transfer",
  "ricardian_contract": ""
}

close

{
  "name": "close",
  "type": "close",
  "ricardian_contract": ""
}

tables

描述表,這是表的JSON對象定義:

{
  "name": "",       //The name of the table, determined during instantiation. 
  "type": "",             //The table's corresponding struct
  "index_type": "", //The type of primary index of this table
  "key_names" : [], //An array of key names, length must equal length of key_types member
  "key_types" : []  //An array of key types that correspond to key names array member, length of array must equal length of key names array.
}

eosio.token合約實例化兩個表,accountsstats

accounts表是一個i64索引,基於account struct,有一個uint64做爲它的主鍵

如下是如何在ABI中描述accounts表。

{
  "name": "accounts",
  "type": "account", // Corresponds to previously defined struct
  "index_type": "i64",
  "key_names" : ["primary_key"],
  "key_types" : ["uint64"]
}

stat表是一個i64索引,基於currenct_stats struct,有一個uint64做爲它的主鍵

如下是如何在ABI中描述stat表。

{
  "name": "stat",
  "type": "currency_stats",
  "index_type": "i64",
  "key_names" : ["primary_key"],
  "key_types" : ["uint64"]
}

你會注意到上面的表格具備相同的「key name」,將鍵命名爲類似的名稱是象徵性的,由於它可能暗示一種主觀關係,與此實現同樣,這意味着可使用任何給定的值來查詢不一樣的表。

把它們放在一塊兒

最後,一個準確描述eosio.token合約的ABI文件。

{
  "version": "eosio::abi/1.0",
  "types": [
    {
      "new_type_name": "name",
      "type": "name"
    }
  ],
  "structs": [
    {
      "name": "create",
      "base": "",
      "fields": [
        {
          "name":"issuer", 
          "type":"name"
        },
        {
          "name":"maximum_supply", 
          "type":"asset"
        }
      ]
    },
    {
       "name": "issue",
       "base": "",
       "fields": [
          {
            "name":"to", 
            "type":"name"
          },
          {
            "name":"quantity", 
            "type":"asset"
          },
          {
            "name":"memo", 
            "type":"string"
          }
       ]
    },
    {
       "name": "retire",
       "base": "",
       "fields": [
          {
            "name":"quantity", 
            "type":"asset"
          },
          {
            "name":"memo", 
            "type":"string"
          }
       ]
    },
    {
       "name": "close",
       "base": "",
       "fields": [
          {
            "name":"owner", 
            "type":"name"
          },
          {
            "name":"symbol", 
            "type":"symbol"
          }
       ]
    },
    {
      "name": "transfer",
      "base": "",
      "fields": [
        {
          "name":"from", 
          "type":"name"
        },
        {
          "name":"to", 
          "type":"name"
        },
        {
          "name":"quantity", 
          "type":"asset"
        },
        {
          "name":"memo", 
          "type":"string"
        }
      ]
    },
    {
      "name": "account",
      "base": "",
      "fields": [
        {
          "name":"balance", 
          "type":"asset"
        }
      ]
    },
    {
      "name": "currency_stats",
      "base": "",
      "fields": [
        {
          "name":"supply", 
          "type":"asset"
        },
        {
          "name":"max_supply", 
          "type":"asset"
        },
        {
          "name":"issuer", 
          "type":"name"
        }
      ]
    }
  ],
  "actions": [
    {
      "name": "transfer",
      "type": "transfer",
      "ricardian_contract": ""
    },
    {
      "name": "issue",
      "type": "issue",
      "ricardian_contract": ""
    },
    {
      "name": "retire",
      "type": "retire",
      "ricardian_contract": ""
    },
    {
      "name": "create",
      "type": "create",
      "ricardian_contract": ""
    },
    {
      "name": "close",
      "type": "close",
      "ricardian_contract": ""
    }
  ],
  "tables": [
    {
      "name": "accounts",
      "type": "account",
      "index_type": "i64",
      "key_names" : ["currency"],
      "key_types" : ["uint64"]
    },
    {
      "name": "stat",
      "type": "currency_stats",
      "index_type": "i64",
      "key_names" : ["currency"],
      "key_types" : ["uint64"]
    }
  ],
  "ricardian_clauses": [],
  "abi_extensions": []
}

代幣合約未涵蓋的狀況

向量

在ABI文件中描述向量時,只需使用[]附加類型,所以若是須要描述權限級別的向量,你能夠這樣描述:permission_level[]

結構基礎

這是一個不多使用的屬性,值得一提,你可使用base ABI結構屬性來引用另外一個繼承結構,只要該結構也在同一個ABI文件中描述,若是你的智能合約邏輯不支持繼承,Base將不執行任何操做或可能拋出錯誤。

你能夠在系統合約源代碼ABI中看到正在使用的base的示例。

此處未涵蓋額外的ABI屬性

爲簡潔起見,此處省略了ABI規範的一些屬性,可是,有一個待定的ABI規範將完整地概述ABI的每一個屬性。

李嘉圖條款

李嘉圖條款描述了特定行爲的預期結果,它也可用於在發件人和合約之間創建條款。

ABI擴展

一個通用的「面向將來」的層,容許舊客戶端跳過解析擴展數據的「塊」,目前,此屬性還沒有使用,未來,每一個擴展在該向量中都有本身的「塊」,以便舊客戶端跳過它,以及瞭解如何解釋它的新客戶端。

維護

每次更改結構、添加表、添加操做或向操做添加參數、使用新類型時,你都須要記住更新ABI文件,在許多狀況下,更新ABI文件失敗不會產生任何錯誤。

故障排除

表不返回任何行

檢查你的表是否在GLOSSARY:ABI文件中準確描述,例如,若是使用cleos在具備格式錯誤的GLOSSARY:ABI定義的合約上添加表,而後從該表中獲取行,則將收到空結果。當合約未能在其GLOSSARY:ABI文件中正確描述其表時,cleos在添加行或讀取行時不會產生錯誤。


上一篇:部署、發行和轉移代幣

相關文章
相關標籤/搜索