Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

[docs] How Tos update based on new template/format #1109

Merged
merged 22 commits into from
Jun 23, 2021
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/05_best-practices/04_data-design-and-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
content_title: Data design and migration
---

EOSIO based blockchains allow developers to easily update their smart contract code. However, a few things need to be considered when it comes to data update and/or migration. The main structure for storing data in EOSIO based blockchains is the multi index table. Once a multi index table has been created with a first version of a smart contract, it has some limitations when it comes to changing its structure. Below you will find a few possible approaches which you can consider when you design your smart contract data and its migration.
EOSIO based blockchains allow developers to easily update their smart contract code. However, a few things need to be considered when it comes to data update and/or migration. The main structure for storing data in EOSIO based blockchains is the multi-index table. Once a multi-index table has been created with a first version of a smart contract, it has some limitations when it comes to changing its structure. Below you will find a few possible approaches which you can consider when you design your smart contract data and its migration.

# How to modify the structure of a multi index table
# How to modify the structure of a multi-index table

Modifying a multi-index table structure that has already been deployed to an EOSIO-based blockchain may be done by selecting one of the different strategies outlined below, depending on your requirements:

Expand All @@ -28,9 +28,9 @@ To learn how to modify the structure using ABI variants read this [tutorial](../

#### 2.3.1. Migration without downtime, but slower

1. Create the new version of your multi index table alongside the old one;
1. Create the new version of your multi-index table alongside the old one;
2. Transfer data from the old table to the new one. You may do so as part of your normal access pattern, first checking the new table to see if the entry you seek is present and if not, check the original table, and if it's present, migrate it while adding the data for the new field, then remove it from the original table to save RAM costs.
3. You must retain both versions of your multi index table until you have completed this migration, at which point you may update your contract to remove the original version of your multi index table.
3. You must retain both versions of your multi-index table until you have completed this migration, at which point you may update your contract to remove the original version of your multi-index table.

#### 2.3.2. Migration with downtime, but faster

Expand Down
13 changes: 13 additions & 0 deletions docs/06_how-to-guides/10_compile/01_compile-a-contract-via-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ content_title: How to compile a smart contract via CLI

This guide provides instructions how to compile a smart contract using the command line interface (CLI).

## Reference

See the following code reference:

* The [`eosio-cpp`](https://developers.eos.io/manuals/eosio.cdt/v1.8/command-reference/eosio-cpp) tool.

## Before you begin

* You have the source of the contract saved in a local folder, e.g. `./examples/hello/`
Expand All @@ -25,6 +31,13 @@ Follow the following steps to compile your contract.
eosio-cpp -abigen ../src/hello.cpp -o hello.wasm -I ../include/
```

Where:
- `eosio-cpp` = Is the [`eosio-cpp`](https://developers.eos.io/manuals/eosio.cdt/v1.8/command-reference/eosio-cpp) tool.
- `-abigen` = It instructs the `eosio-cpp` tool to generate ABI file.
- `../src/hello.cpp` = Is the input cpp source file to be compiled.
- `-o hello.wasm` = It instructs the `eosio-cpp` tool who to name the output wasm file.
- `-I ../include/` = It tells `eosio-cpp` tool what the include folder path is, in this particular case it is relative path.

3. Verify the following two files were generated:

* the compiled binary wasm: `hello.wasm`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class [[eosio::contract]] smrtcontract : public contract {
1. Use the `KV_NAMED_INDEX` macro with two parameters.
2. Pass the name of the index as the first parameter. The parameter must be a qualified `eosio::name`. See documentation for the [eosio name restrictions](https://developers.eos.io/welcome/latest/glossary/index#account-name).
3. Pass the name of the property for which the index is defined as the second parameter.
4. Call `init()` of the base class in the constructor of `address_table` type and pass the contract name as the first parameter and the primary index defined previously as the second parameter.
4. Call `init()` of the base class in the constructor of `address_table` type and pass the contract name as the first parameter and `account_name` index defined previously, by the KV_NAMED_INDEX macro, as the second parameter.

Refer to the following reference implementation of a unique index on property `account_name` using macro `KV_NAMED_INDEX`:

Expand All @@ -85,6 +85,7 @@ class [[eosio::contract]] smrtcontract : public contract {
1. Use the `eosio::kv::table::index` template class with two parameters.
2. Pass the name of the index as the first parameter. The parameter must be a qualified `eosio:name`. See documentation for the [eosio name restrictions](https://developers.eos.io/welcome/latest/glossary/index#account-name).
3. Pass the reference to the property for which the index is defined, `&person::personal_id`, as the second parameter.
4. Call `init()` of the base class in the constructor of `address_table` type and pass the contract name as the first parameter and the `personal_id_idx` index defined previously as the second parameter.

Refer to the following reference implementation of a unique index on property `personal_id` using `eosio::kv::table::index` template class:

Expand Down Expand Up @@ -112,8 +113,9 @@ class [[eosio::contract]] smrtcontract : public contract {
1. Use the `KV_NAMED_INDEX` with two parameters.
2. Pass the name of the index as the first parameter. The parameter must be a qualified `eosio::name`. See documentation for the [eosio name restrictions](https://developers.eos.io/welcome/latest/glossary/index#account-name).
3. Pass the name of the property for which the index is defined as the second parameter.
4. Call `init()` of the base class in the constructor of `address_table` type and pass the contract name as the first parameter and `first_name` index defined previously, by the KV_NAMED_INDEX macro, as the second parameter.

The property used for the second parameter must be of template type `std::tuple`. The first parameter must be the type of the property indexed non-uniquely, in our case the type `std::string` is used because `first_name` is the property indexed non-uniquely. And the last parameter of the tuple type must be the type of a property name which is unique. In our case the type `eosio::name` is used because property `account_name` is unique. Multiple properties can be indexed non-uniquely as well. In this case the first parameters types correspond to the properties being indexed. And, as previously already mentioned, the last parameter correspond to the type of a property name which is unique.
The property used for the second parameter must be of template type `std::tuple`. The first parameter must be the type of the property indexed non-uniquely, in our case the type `std::string` is used because `first_name` is the property indexed non-uniquely. And the last parameter of the tuple type must be the type of a property name which is unique. In our case the type `eosio::name` is used because property `account_name` is unique. Multiple properties can be indexed non-uniquely as well. In this case the first parameter types correspond to the properties being indexed. And, as previously already mentioned, the last parameter correspond to the type of a property name which is unique.

Refer to the following reference implementation of a non-unique index on property `account_name` using macro `KV_NAMED_INDEX`:

Expand Down Expand Up @@ -146,8 +148,10 @@ class [[eosio::contract]] smrtcontract : public contract {
1. Use the `eosio::kv::table::index` template class.
2. Pass as the first parameter the name of the index. It must be a qualified `eosio:name`, see documentation for the [eosio name restrictions](https://developers.eos.io/welcome/latest/glossary/index#account-name).
3. Pass the reference to the property for which the index is defined, `&person::last_name`, as the second parameter.
4. Call `init()` of the base class in the constructor of `address_table` type and pass the contract name as the first parameter and the `last_name_idx` index defined previously as the second parameter.

The property used for the second parameter must be of template type `std::tuple`. The first parameter must be the type of the property indexed non-uniquely, in our case the type `std::string` is used because `first_name` is the property indexed non-uniquely. And the last parameter of the tuple type must be the type of a property name which is unique. In our case the type `eosio::name` is used because property `account_name` is unique. Multiple properties can be indexed non-uniquely as well. In this case the first parameters types correspond to the properties being indexed. And, as previously already mentioned, the last parameter correspond to the type of a property name which is unique.

The property used for the second parameter must be of template type `std::tuple`. The first parameter must be the type of the property indexed non-uniquely, in our case the type `std::string` is used because `first_name` is the property indexed non-uniquely. And the last parameter of the tuple type must be the type of a property name which is unique. In our case the type `eosio::name` is used because property `account_name` is unique. Multiple properties can be indexed non-uniquely as well. In this case the first parameter types correspond to the properties being indexed. And, as previously already mentioned, the last parameter correspond to the type of a property name which is unique.

Refer to the following reference implementation of a non-unique index on property `last_name` using `eosio::kv::table::index` template class:

Expand All @@ -169,7 +173,7 @@ class [[eosio::contract]] smrtcontract : public contract {
&person::last_name};

address_table(eosio::name contract_name) {
init(contract_name, last_name)
init(contract_name, last_name_idx)
}
};
public:
Expand Down
186 changes: 117 additions & 69 deletions docs/06_how-to-guides/40_multi-index/how-to-define-a-primary-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,76 +2,124 @@
content_title: How to define a primary index
---

A primary key is required when defining a multi index table structure. See the following example:

1. Include the `eosio.hpp` header and declare the `eosio` namespace usage
```
#include <eosio/eosio.hpp>
using namespace eosio;
```
2. Define the data structure for the multi index table
```cpp
struct [[eosio::table]] test_table {
};
```
3. Add to the data structure the fields which define the multi index table
```diff
// the data structure which defines each row of the table
struct [[eosio::table]] test_table {
+ // this field stores a name for each row of the multi index table
+ name test_primary;
+ // additional data stored in table row, e.g. an uint64_t type data
+ uint64_t datum;
};
```
4. Add the definition of the primary index for the multi index table. The primary index type must be uint64_t and must be unique
```diff
// the data structure which defines each row of the table
struct [[eosio::table]] test_table {
// this field stores a name for each row of the multi index table
name test_primary;
// additional data stored in table row
uint64_t datum;
+ // mandatory definition for primary key getter
+ uint64_t primary_key( ) const { return test_primary.value; }
};
```
## Overview

This guide provides instructions on how to define a primary index for a multi-index table.

## Reference

See the following code reference:

* The [`multi-index`](../../classeosio_1_1multi__index) class.

## Before you begin

Make sure you have the following prerequisites in place:

* An EOSIO development environment, for details consult the [Get Started Guide](https://developers.eos.io/welcome/latest/getting-started-guide/index),

## Procedure

Complete the following steps to define a primary index for the multi-index table `testtab`.

### 1. Preparation And Initialization

Include the `eosio.hpp` header and declare the `eosio` namespace usage.

```cpp
#include <eosio/eosio.hpp>
using namespace eosio;
```

### 2. Define The Table Data Structure

Define the data structure for the multi-index table.

```cpp
struct [[eosio::table]] test_table {
};
```

Add to the data structure the properties which define it. Each property corresponds to a field of the multi-index table. A primary key is required when defining a multi-index table structure, therefore you need to know which is the multi-index table field that is the primary key for your multi-index table. The corresponding property for the primary key field must store unique values. In this case it is the `test_primary` data member of type `eosio::name`.

```diff
// the data structure which defines each row of the table
struct [[eosio::table]] test_table {
+ // this property stores a name for each row of the multi-index table
+ name test_primary;
+ // additional data stored in table row, e.g. an uint64_t type data
+ uint64_t datum;
};
```

### 3. Define The Primary Index

Add definition of the primary index for the multi-index table. The primary index type must be uint64_t, it must be unique and it must be named `primary_key()`, otherwise the compiler (eosio-cpp) will generate an error saying it can not find the field to use as the primary key:

```diff
// the data structure which defines each row of the table
struct [[eosio::table]] test_table {
// this property stores a name for each row of the multi-index table
name test_primary;
// additional data stored in table row
uint64_t datum;
+ // mandatory definition for primary key getter
+ uint64_t primary_key( ) const { return test_primary.value; }
};
```

[[info | Secondary indexes information]]
| Other, secondary, indexes if they will be defined can have duplicates. You can have up to 16 additional indexes and the field types can be uint64_t, uint128_t, uint256_t, double or long double.

5. For ease of use, define a type alias `test_tables` based on the `eosio::multi_index` template type, parametarized with a random name `"testtaba"` and the `test_table` data structure defined above
```diff
// the data structure which defines each row of the table
struct [[eosio::table]] test_table {
// this field stores a name for each row of the multi index table
name test_primary;
// additional data stored in table row
uint64_t datum;
// mandatory definition for primary key getter
uint64_t primary_key( ) const { return test_primary.value; }
};

+ typedef eosio::multi_index<"testtaba"_n, test_table> test_tables;
```

Declare the multi index table as a data member of type `test_tables`, as defined above.
```diff
// the data structure which defines each row of the table
struct [[eosio::table]] test_table {
// this field stores a name for each row of the multi index table
name test_primary;
// additional data stored in table row
uint64_t datum;
// mandatory definition for primary key getter
uint64_t primary_key( ) const { return test_primary.value; }
};

typedef eosio::multi_index<"testtaba"_n, test_table> test_tables;
+ test_tables testtab;
```

Now you have instantiated the `testtab` as a multi index table which has a primary index defined for its `test_primary` data member.
| Other, secondary, indexes if they will be defined can have duplicates. You can have up to 16 additional indexes and the corresponding property types can be uint64_t, uint128_t, uint256_t, double or long double.

### 4. Define A Multi-Index Type Alias

For ease of use, define a type alias `test_table_t` based on the `eosio::multi_index` template type, parametarized with a random name `"testtaba"` and the `test_table` data structure defined above.

```diff
// the data structure which defines each row of the table
struct [[eosio::table]] test_table {
// this property stores a name for each row of the multi-index table
name test_primary;
// additional data stored in table row
uint64_t datum;
// mandatory definition for primary key getter
uint64_t primary_key( ) const { return test_primary.value; }
};

+ typedef eosio::multi_index<"testtaba"_n, test_table> test_table_t;
```

### 5. Instantiate The Multi-Index Table

Declare the `testtab` multi-index table as a data member of type `test_table_t`.

```diff
// the data structure which defines each row of the table
struct [[eosio::table]] test_table {
// this property stores a name for each row of the multi-index table
name test_primary;
// additional data stored in table row
uint64_t datum;
// mandatory definition for primary key getter
uint64_t primary_key( ) const { return test_primary.value; }
};

typedef eosio::multi_index<"testtaba"_n, test_table> test_table_t;
+ test_table_t testtab;
```

Now you have instantiated the `testtab` as a multi-index table which has a primary index defined for its `test_primary` data member.

[[info | Full example location]]
| A full example project demonstrating the instantiation and usage of multi index table can be found [here](/~https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example).
| A full example project demonstrating the instantiation and usage of multi-index table can be found [here](/~https://github.com/EOSIO/eosio.cdt/tree/master/examples/multi_index_example).

## Summary

In conclusion, the above instructions show how to define a primary index for a multi-index table.

## Next Steps

The following option is available when you complete the procedure:

* You can [insert data in the multi-index table](./how-to-insert-data-into-a-multi-index-table).
* You can [iterate and retrieve data](./how-to-iterate-and-retrieve-a-multi_index-table) from the multi-index table.
Loading