Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
dixia committed Jun 3, 2020
2 parents fc33648 + 6a38a51 commit 2be4554
Show file tree
Hide file tree
Showing 13 changed files with 134 additions and 56 deletions.
10 changes: 9 additions & 1 deletion docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"options": {
"docs_dir": "docs",
"disable_indices": true,
"exclude": ["get-involved", "05_community-developer-tools"]
"exclude": ["get-involved", "05_community-developer-tools", "06_eosio-blockchain-networks"]
}
},
{
Expand Down Expand Up @@ -43,6 +43,14 @@
}
},

{
"name": "collate_markdown",
"options": {
"docs_dir": "docs/06_eosio-blockchain-networks",
"output_dir": "06_eosio-blockchain-networks"
}
},


{
"name": "collate_markdown",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,22 @@
content_title: "2.3: Understanding ABI Files"
link_text: "2.3: Understanding ABI Files"
---

## Introduction

Previously you deployed the `eosio.token` contract using the provided ABI file. This tutorial will overview how the ABI file correlates to the `eosio.token` contract.

ABI files can be generated using the `eosio-cpp` utility provided by `eosio.cdt`. However, there are several situations that may cause ABI's generation to malfunction or fail altogether. Advanced C++ patterns can trip it up and custom types can sometimes cause issues for ABI generation. For this reason, it's **imperative** you understand how ABI files work, so you can debug and fix if and when necessary.
## What is an ABI?

## What is an ABI

The Application Binary Interface (ABI) is a JSON-based description on how to convert user actions between their JSON and Binary representations. The ABI also describes how to convert the database state to/from JSON. Once you have described your contract via an ABI then developers and users will be able to interact with your contract seamlessly via JSON.

[[warning | Security Note]]
| ABI can be bypassed when executing transactions. Messages and actions passed to a contract do not have to conform to the ABI. The ABI is a guide, not a gatekeeper.

## Create an ABI File

Start with an empty ABI, name it `eosio.token.abi`

```text
Expand All @@ -29,18 +34,19 @@ Start with an empty ABI, name it `eosio.token.abi`
```

## Types

An ABI enables any client or interface to interpret and even generate a GUI for your contract. For this to work consistently, describe the custom types that are used as a parameter in any public action or struct that needs to be described in the ABI.

[[info | Built-in Types]]
| EOSIO implements a number of custom built-ins. Built-in types don't need to be described in an ABI file. If you would like to familiarize yourself with EOSIO's built-ins, they are defined [here](https://github.com/EOSIO/eos/blob/master/libraries/chain/abi_serializer.cpp#L88-L126)

| EOSIO implements a number of custom built-ins. Built-in types don't need to be described in an ABI file. If you would like to familiarize yourself with EOSIO's built-ins, they are defined [here](https://github.com/EOSIO/eos/blob/de78b49b5765c88f4e005046d1489c3905985b94/libraries/chain/abi_serializer.cpp#L89-L127)

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

The ABI now looks like this:

```json
Expand All @@ -49,7 +55,7 @@ The ABI now looks like this:
"types": [{
"new_type_name": "name",
"type": "name"
}],
}],
"structs": [],
"actions": [],
"tables": [],
Expand All @@ -59,6 +65,7 @@ The ABI now looks like this:
```

## Structs

Structs that are exposed to the ABI also need to be described. By looking at eosio.token.hpp, it can be quickly determined which structs are utilized by public actions. This is particularly important for the next step.

A struct's object definition in JSON looks like the following:
Expand All @@ -70,14 +77,16 @@ A struct's object definition in JSON looks like the following:
"fields": [] //Array of field objects describing the struct's fields.
}
```

## Fields

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

In the `eosio.token` contract, there's a number of structs that require definition. Please note, not all of the structs are explicitly defined, some correspond to an actions' parameters. Here's a list of structs that require an ABI description for the `eosio.token` contract:

## Implicit Structs
Expand All @@ -102,6 +111,7 @@ The following structs are implicit in that a struct was never explicitly defined
]
}
```

### [issue](https://developers.eos.io/manuals/eosio.contracts/latest/action-reference/eosio.token/index/#issue)

```json
Expand All @@ -124,6 +134,7 @@ The following structs are implicit in that a struct was never explicitly defined
]
}
```

### [retire](https://developers.eos.io/manuals/eosio.contracts/latest/action-reference/eosio.token/index/#retire)

```json
Expand All @@ -142,6 +153,7 @@ The following structs are implicit in that a struct was never explicitly defined
]
}
```

### [transfer](https://developers.eos.io/manuals/eosio.contracts/latest/action-reference/eosio.token/index/#transfer)

```json
Expand All @@ -168,6 +180,7 @@ The following structs are implicit in that a struct was never explicitly defined
]
}
```

### [close](https://developers.eos.io/manuals/eosio.contracts/latest/action-reference/eosio.token/index/#close)

```json
Expand All @@ -186,10 +199,11 @@ The following structs are implicit in that a struct was never explicitly defined
]
}
```

## Explicit Structs
These structs are explicitly defined, as they are a requirement to instantiate a multi-index table. Describing them is no different than defining the implicit structs as demonstrated above.

### [account](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L120)
### [account](https://github.com/EOSIO/eosio.contracts/blob/f6578c45c83ec60826e6a1eeb9ee71de85abe976/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L120)

```json
{
Expand All @@ -205,6 +219,7 @@ These structs are explicitly defined, as they are a requirement to instantiate a
```

## Actions

An action's JSON object definition looks like the following:

```json
Expand All @@ -214,13 +229,14 @@ An action's JSON object definition looks like the following:
"ricardian_contract": "" //An optional ricardian clause to associate to this action describing its intended functionality.
}
```
Describe the actions of the `eosio.token` contract by aggregating all the public functions described in the `eosio.token` contract's [header file](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp).

Describe the actions of the `eosio.token` contract by aggregating all the public functions described in the `eosio.token` contract's [header file](https://github.com/EOSIO/eosio.contracts/blob/f6578c45c83ec60826e6a1eeb9ee71de85abe976/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L1).

Then describe each action's *type* according to its previously described struct. In most situations, the function name and the struct name will be equal, but are not required to be equal.

Below is a list of actions that link to their source code with example JSON provided for how each action would be described.

## [create](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L35-L37)
### [create](https://github.com/EOSIO/eosio.contracts/blob/f6578c45c83ec60826e6a1eeb9ee71de85abe976/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L35-L37)

```json
{
Expand All @@ -229,7 +245,8 @@ Below is a list of actions that link to their source code with example JSON prov
"ricardian_contract": ""
}
```
## [issue](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L45-L46)

### [issue](https://github.com/EOSIO/eosio.contracts/blob/f6578c45c83ec60826e6a1eeb9ee71de85abe976/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L45-L46)

```json
{
Expand All @@ -238,7 +255,8 @@ Below is a list of actions that link to their source code with example JSON prov
"ricardian_contract": ""
}
```
## [retire](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L55-L56)

### [retire](https://github.com/EOSIO/eosio.contracts/blob/f6578c45c83ec60826e6a1eeb9ee71de85abe976/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L55-L56)

```json
{
Expand All @@ -247,7 +265,8 @@ Below is a list of actions that link to their source code with example JSON prov
"ricardian_contract": ""
}
```
## [transfer](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L67-L71)

### [transfer](https://github.com/EOSIO/eosio.contracts/blob/f6578c45c83ec60826e6a1eeb9ee71de85abe976/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L67-L71)

```json
{
Expand All @@ -256,7 +275,8 @@ Below is a list of actions that link to their source code with example JSON prov
"ricardian_contract": ""
}
```
## [close](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L96-L97)

### [close](https://github.com/EOSIO/eosio.contracts/blob/f6578c45c83ec60826e6a1eeb9ee71de85abe976/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L96-L97)

```json
{
Expand All @@ -267,20 +287,22 @@ Below is a list of actions that link to their source code with example JSON prov
```

## Tables
Describe the tables. Here's a table's JSON object definition:

Here's a table's JSON object definition:

```json
{
"name": "", //The name of the table, determined during instantiation.
"type": "", //The table's corresponding struct
"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.
}
```
The eosio.token contract instantiates two tables, [accounts](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L134) and [stat](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L135).

The `accounts` table is an i64 index, based on the [`account` struct](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L120-L124), has a [`uint64` as it's primary key](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L123)
The eosio.token contract instantiates two tables, [accounts](https://github.com/EOSIO/eosio.contracts/blob/f6578c45c83ec60826e6a1eeb9ee71de85abe976/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L134) and [stat](https://github.com/EOSIO/eosio.contracts/blob/f6578c45c83ec60826e6a1eeb9ee71de85abe976/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L135).

The `accounts` table is an i64 index, based on the [`account` struct](https://github.com/EOSIO/eosio.contracts/blob/f6578c45c83ec60826e6a1eeb9ee71de85abe976/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L120-L124), has a [`uint64` as it's primary key](https://github.com/EOSIO/eosio.contracts/blob/f6578c45c83ec60826e6a1eeb9ee71de85abe976/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L123)

Here's how the accounts table would be described in the ABI

Expand All @@ -293,7 +315,8 @@ Here's how the accounts table would be described in the ABI
"key_types" : ["uint64"]
}
```
The `stat` table is an i64 index, based on the [`currency_stats` struct](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L126-L132), has a [`uint64` as it's primary key](https://github.com/EOSIO/eosio.contracts/blob/master/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L131)

The `stat` table is an i64 index, based on the [`currency_stats` struct](https://github.com/EOSIO/eosio.contracts/blob/f6578c45c83ec60826e6a1eeb9ee71de85abe976/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L126-L132), has a [`uint64` as it's primary key](https://github.com/EOSIO/eosio.contracts/blob/f6578c45c83ec60826e6a1eeb9ee71de85abe976/contracts/eosio.token/include/eosio.token/eosio.token.hpp#L131)

Here's how the stat table would be described in the ABI

Expand All @@ -306,9 +329,11 @@ Here's how the stat table would be described in the ABI
"key_types" : ["uint64"]
}
```

You'll notice the above tables have the same "key name." Naming your keys similar names is symbolic in that it can potentially suggest a subjective relationship. As with this implementation, implying that any given value can be used to query different tables.

## Putting it all Together

Finally, an ABI file that accurately describes the `eosio.token` contract.

```json
Expand Down Expand Up @@ -481,27 +506,39 @@ Finally, an ABI file that accurately describes the `eosio.token` contract.
```

## Cases not Covered by Token Contract
## Vectors

### Vectors

When describing a vector in your ABI file, simply append the type with `[]`, so if you need to describe a vector of permission levels, you would describe it like so: `permission_level[]`

## Struct Base
### Struct Base

It's a rarely used property worth mentioning. You can use **base** ABI struct property to reference another struct for inheritance, as long as that struct is also described in the same ABI file. Base will do nothing or potentially throw an error if your smart contract logic does not support inheritance.

You can see an example of base in use in the system contract [source code](https://github.com/EOSIO/eosio.contracts/blob/4e4a3ca86d5d3482dfac85182e69f33c49e62fa9/eosio.system/include/eosio.system/eosio.system.hpp#L46) and [ABI](https://github.com/EOSIO/eosio.contracts/blob/4e4a3ca86d5d3482dfac85182e69f33c49e62fa9/eosio.system/abi/eosio.system.abi#L262)
## Extra ABI Properties Not Covered Here

### Extra ABI Properties

A few properties of the ABI specification were skipped here for brevity, however, there is a pending ABI specification that will outline every property of the ABI in its entirety.

## Ricardian Clauses
### Ricardian Clauses

Ricardian clauses describe the intended outcome of a particular actions. It may also be utilized to establish terms between the sender and the contract.

## ABI Extensions
### ABI Extensions

A generic "future proofing" layer that allows old clients to skip the parsing of "chunks" of extension data. For now, this property is unused. In the future each extension would have its own "chunk" in that vector so that older clients skip it and newer clients that understand how to interpret it.

## Maintenance
Every time you change a struct, add a table, add an action or add parameters to an action, use a new type, you will need to remember to update your ABI file. In many cases failure to update your ABI file will not produce any error.

Every time you change a struct, add a table, add an action or add parameters to an action, use a new type, you will need to remember to update your ABI file. In many cases forgetting to update your ABI file will not produce any error.

## Troubleshooting
## Table returns no rows

### Table returns no rows

Check that your table is accurately described in the ABI file. For example, If you use `cleos` to add a table on a contract with a malformed ABI definition and then get rows from that table, you will receive an empty result. `cleos` will not produce an error when adding a row nor reading a row when a contract has failed to properly describe its tables in its ABI.

## What's Next?
- [Data Persistence](./04_data-persistence.md): Learn how data persistence works on EOSIO by writing a simple smart contract that functions as an address book.
## What's Next

- [Data Persistence](./04_data-persistence.md): Learn how data persistence works on EOSIO by writing a simple smart contract that functions as an address book.
Loading

0 comments on commit 2be4554

Please sign in to comment.