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在添加行或读取行时不会产生错误。


上一篇:部署、发行和转移代币

相关文章
相关标签/搜索