以前,你使用提供的ABI文件部署了eosio.token
合約,本教程將概述ABI文件如何與eosio.token
合約相關聯。git
可使用eosio.cdt
提供的eosio-cpp
實用程序生成ABI文件,可是,有幾種狀況可能致使ABI的生成出現故障或徹底失敗,高級C++模式能夠將其提高,自定義類型有時會致使ABI生成的問題,所以,你必須瞭解ABI文件的工做原理,以便在必要時進行調試和修復。github
應用程序二進制接口(ABI)是一個基於JSON的描述,介紹如何在JSON和二進制表示之間轉換用戶操做,ABI還描述瞭如何將數據庫狀態轉換爲JSON或從JSON轉換,經過ABI描述合約後,開發人員和用戶將可以經過JSON無縫地與你的合約進行交互。數據庫
安全說明
執行交易時能夠繞過ABI,傳遞給合約的消息和操做沒必要符合ABI,ABI是一個指南,而不是看門人。segmentfault
從空的ABI開始,將其命名爲eosio.token.abi
安全
{ "version": "eosio::abi/1.0", "types": [], "structs": [], "actions": [], "tables": [], "ricardian_clauses": [], "abi_extensions": [], "___comment" : "" }
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": [] }
暴露於ABI的結構也須要描述,經過查看eosio.token.hpp
,能夠快速肯定公共操做使用了哪些結構,這對下一步尤其重要。調試
JSON中的結構對象定義以下所示:code
{ "name": "issue", //The name "base": "", //Inheritance, parent struct "fields": [] //Array of field objects describing the struct's fields. }
{ "name":"", // The field's name "type":"" // The field's type }
在eosio.token
合約中,有許多結構須要定義,請注意,並不是全部結構都是顯式定義的,有些結構對應於操做的參數,如下是須要對eosio.token
合約進行ABI描述的結構列表。
如下結構是隱式的,由於結構從未在合約中顯式定義,查看create操做,你將找到兩個參數,類型爲name
的issuer
和asset
類型的maximum_supply
,爲簡潔起見,本教程不會分解每一個結構,但應用相同的邏輯,你將獲得如下結果:
{ "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": "transfer", "base": "", "fields": [ { "name":"from", "type":"name" }, { "name":"to", "type":"name" }, { "name":"quantity", "type":"asset" }, { "name":"memo", "type":"string" } ] }
{ "name": "close", "base": "", "fields": [ { "name":"owner", "type":"name" }, { "name":"symbol", "type":"symbol" } ] }
這些結構是顯式定義的,由於它們是實例化多索引表的條件,描述它們與定義如上所示的隱式結構沒有什麼不一樣。
{ "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":"account_name" } ] }
操做的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,以瞭解每一個操做的描述方式。
{ "name": "create", "type": "create", "ricardian_contract": "" }
{ "name": "issue", "type": "issue", "ricardian_contract": "" }
{ "name": "retire", "type": "retire", "ricardian_contract": "" }
{ "name": "transfer", "type": "transfer", "ricardian_contract": "" }
{ "name": "close", "type": "close", "ricardian_contract": "" }
描述表,這是表的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合約實例化兩個表,accounts和stats。
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文件失敗不會產生任何錯誤。
檢查你的表是否在GLOSSARY:ABI文件中準確描述,例如,若是使用cleos
在具備格式錯誤的GLOSSARY:ABI定義的合約上添加表,而後從該表中獲取行,則將收到空結果。當合約未能在其GLOSSARY:ABI文件中正確描述其表時,cleos
在添加行或讀取行時不會產生錯誤。