These docs are for v1.3.0. Click to read the latest docs for v1.6.

Multi-Index DB API

Overview

EOSIO provides a set of services and interfaces that enable contract developers to
persist state across actions, and consequently transactions, boundaries. Without persistence, state that is generated during the processing of actions and transactions will be lost when processing goes out of scope. The persistence components include:

  1. Services to persist state in a database
  2. Enhanced query capabilities to find and retrieve database content
  3. C++ APIs to these services, intended for use by contract developers
  4. C APIs for access to core services, of interest to libraries and system developers

This document covers the first three topics.

The Need for Persistence Services

Actions perform the work of EOSIO contracts. Actions operate within an environment known as the action context. As illustrated in the Action "Apply" Context Diagram, an action context provides several things necessary for the execution of the action. One of those things is the action's working memory. This is where the action maintains its working state. Before processing an action, EOSIO sets up a clean working memory for the action. Variables that might have been set when another action executed are not available within the new action's context. The only way to pass state among actions is to persist it to and retrieve it from the EOSIO database.

The EOSIO Multi-Index API

The EOSIO Multi-Index API provides a C++ interface to the EOSIO database. The EOSIO Multi-Index API is patterned after Boost Multi-Index Containers. This API provides a model for object storage with rich retrieval capabilities, enabling the use of multiple indices with different sorting and access semantics. The Multi-Index API is provided by the eosio::multi_index C++ class found in the contracts/eosiolib folder of the EOSIO/eos GitHub repository. This class enables a contract written in C++ to read and modify persistent state in the EOSIO database.

The Multi-Index container interface eosio::multi_index provides a homogeneous container of an arbitrary C++ type (and it does not need to be a plain-old data type or be fixed-size) that is kept sorted in multiple indices by keys of various types that are derived from the objects. It can be compared to a traditional database table with rows, columns, and indices. It can also be easily compared to Boost Multi-index Containers. In fact many of the member function signatures of eosio::multi_index are modeled after boost::multi_index, although there are important differences.

eosio::multi_index can be conceptually viewed as tables in a conventional database in which the rows are the individual objects in the container, the columns are the member properties of the objects in the container, and the indices provide fast lookup of an object by a key compatible with an object member property.

Traditional database tables allow the index to be a user-defined function over some number of columns of the table. eosio::multi_index similarly allows the index to be any user-defined function (provided as a member function of the class/struct of the element type) but with its return value restricted to one of a limited set of supported key types.

Traditional database tables typically have a single unique primary key that allows
unambiguously identifying a particular row in the table and also provides the standard sort order for the rows in the table. eosio::multi_index supports a similar semantic, but the primary key of the object in the eosio::multi_index container must be a unique unsigned 64-bit integer. The objects in the eosio::multi_index container are sorted by the primary key index in ascending order of the unsigned 64-bit integer primary key.

EOSIO Multi-Index Iterators

A key differentiator of the EOSIO persistence services over other blockchain infrastructures is its Multi-Index iterators. Unlike some other blockchains that only provide a key-value store, EOSIO Multi-Index tables allow a contract developer to keep a collection of objects sorted by a variety of different key types, which could be derived from the data within the object. This enables rich retrieval capabilities. Up to 16 secondary indices can be defined, each having its own way of ordering and retrieving table contents.

The EOSIO Multi-Index iterators follow a pattern that is common to C++ iterators. All iterators are bi-directional const, either const_iterator or const_reverse_iterator. The iterators can be dereferenced to provide access to an object in the Multi-Index table.

Putting It All Together

How to Create Your EOSIO Multi-Index Table

Here is a summary of the steps to create your own persistent data using EOSIO Multi-Index tables.

  • Define your object(s) using C++ class or struct. Each object will be in its own Multi-Index table.
  • Define a const member function in the class/struct called primary_key that returns the uint64_t primary key value of your object.
  • Determine the secondary indices. Up to 16 additional indices are supported. A secondary index
    supports several key types, listed below.
    - idx64 - Primitive 64-bit unsigned integer key
    - idx128 - Primitive 128-bit unsigned integer key, or a 128-bit fixed-size lexicographical key
    - idx256 - 256-bit fixed-size lexicographical key
    - idx_double - Double precision floating point key
    - idx_long_double - Quadruple precision floating point key
  • Define a key extractor for each secondary index. The key extractor is a function used to obtain the keys from the elements of the Multi-Index table.

How to Use Your EOSIO Multi-Index Table