美文网首页
区块链EOS|智能合约入门3——解析abi文件

区块链EOS|智能合约入门3——解析abi文件

作者: 十里寻枫 | 来源:发表于2020-04-27 01:43 被阅读0次

      通过eosio.cdt提供的eosin-cpp 工具可以生成ABI文件。为什么要理解ABI,因为在开发的时候,自定义类型等可能会导致生成的ABI文件错误,为了能够修复错误,我们需要先理解ABI。

      ABI全称是Application Binary Interface,它是一个基于JSON格式的说明文件,用来描述action在JSON和二进制之间的转换。同时,它还用来描述怎么用JSON表示数据库状态,或根据JSON得到数据库状态。与说明文档类似,有了ABI,开发人员可以通过它理解合约。

    注:ABI只是一个说明文件,传递给合约的消息或action不一定得完全符合它。


      为了更好理解abi,现在,自己来写一个ABI文件。

      在任意一个位置,创建一个空白文件,叫eosio.token.abi,写入下列代码。

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

      接下来会逐个解释每一行。

    1. Type

      这里的types是对于自定义类型的说明。在编写代码时,有些类型的名字可能比较长,或者我们想要让类型名称更加具体,我们给这样的类型起一个别名。举一个例子,我们在编写Hello World的时候,用到了eosio中的类型name,我们现在想让它更具体一点,我们给它起个别名叫username。修改完的代码如下。

    #include <eosio/eosio.hpp>  
    
    using namespace eosio;      
    typedef name username; //给name取个别名叫username
    
    class [[eosio::contract]] helloWorld : public contract { 
      public:
          using contract::contract;  
          [[eosio::action]]   
          void hello( username user ) {  //将之前的name修改为username
              require_auth( user );
              print( "Hello World", user );
            }
    };
    

      编译该文件(eosio-cpp helloWorld.cpp -o helloWorld.wasm)。打开abi文件,会发现types变变成了如下。

    "types": [
            {
                "new_type_name": "username",
                "type": "name"
            }
        ],
    

      很直观,new_type_name是我们新起类型别名,type是类型原本的名称。
    需要注意的是,eosio内建的类型不会在abi文件中显示出来。那什么是内建类型呢,就是eosio已经帮我们定义好了的类型,上面用到到name就是一个内建类型。具体的内建类型可以在此查看

    2. Struct

      显然,这里的struct是对于合约中结构体的说明。举个例子说明。在之前eosio.token合约的hpp文件中,在代码的一百多行的位置,可以看到以下代码。

    struct [[eosio::table]] account {
                asset    balance;
    
                uint64_t primary_key()const { return balance.symbol.code().raw(); }
             };
    

      这就是其中的一个结构体。同时,打开该合同的abi文件,可以看到对应的说明,如下。name是结构体名,base是该结构体的基类(这里没有,所以为空),fields是结构体内变量的名称及其类型。

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

      但是你会发现,eosio.token.hpp里明明只定义了两个结构体,abi文件里structs却写着很多个。这是因为还有一种叫做隐性结构体(implicit struct)的东西,它们对应着合约action及其参数。
      同样用eosio.token合约举例。对比abi文件的structs和eosio.token.hpp文件的action方法名跟参数,可以发现,name就是action方法的名称,fields里边则是action方法的参数及参数对应的类型。

    3. Action

      Action这一块用于描述该合约中可供外部调用的动作。同样,举例eosio.token合约。
      hpp文件中action内容如下。

    [[eosio::action]]
             void close( const name& owner, const symbol& symbol );
             
    [[eosio::action]]
             void create( const name&   issuer,
                          const asset&  maximum_supply);
    [[eosio::action]]
             void issue( const name& to, const asset& quantity, const string& memo );
        ...
    

      abi文件对应内容如下。

    "actions": [
            {
                "name": "close",
                "type": "close",
                "ricardian_contract": ""
            },
            {
                "name": "create",
                "type": "create",
                "ricardian_contract": ""
            },
            {
                "name": "issue",
                "type": "issue",
                "ricardian_contract": ""
            },
            ...
        ]
    

      name明显就是action的名称了,type则是该方法对应的隐性结构体的名称(上面有讲到),richardian_contract是李嘉图合约(后续会解释)。

    4. Table

      同样用eosio.token合约举例。hpp文件中对于表account的定义如下。

    struct [[eosio::table]] account {
                asset    balance;
                uint64_t primary_key()const { return balance.symbol.code().raw(); }
             };
            
    typedef eosio::multi_index< "accounts"_n, account > accounts;
    

      abi的table内容如下。

    {
      "name": "accounts",     //表的名称,在实例化时确定;
      "type": "account",      //表对应的结构体;
      "index_type": "i64",    //表的主键的类型;
      "key_names" : ["primary_key"],  //字段名称,长度需与下面的key_types相同;
      "key_types" : ["uint64"] //字段的类型,需与上面的key_names对应,并且长度相同;
    }
    

    (1) name:表的名称为accounts。官方开发文档的说法是“******The eosio.token contract instantiates two tables, accounts and stat.*** ***”(关于multi_index的具体解释请看这里 )。意思是上面hpp部分的最后一行代码实例化了一个叫accounts的表。
    (2) type:这个accounts的表是基于account结构体的,所以type为account。
    (3) index_type: 索引类型为i64。
    (4) key_names:字段为"[primary_key]"。上面hpp部分的第三行决定了一个类型为uint64主键。
    (5) key_type:字段类型为["uint64"]。同上。



    注:转自CSDN文章

    相关文章

      网友评论

          本文标题:区块链EOS|智能合约入门3——解析abi文件

          本文链接:https://www.haomeiwen.com/subject/zhkewhtx.html