Schemas

Schemas are used in various places in the Lisk SDK to encode and decode the data that is retrieved or pushed to the database.

Schemas are specifically used in the following:

  • modules to define the accountSchema, which consists of module-specific properties that are added to each account by the module.

  • assets, for the schema, which defines the data structure and formats of the transaction asset.

  • modules and/or assets, to decode/encode other specific data from the database, such as blocks, transactions, account state, and chain state data.

Schema Format

Schemas must be defined as shown below, which is a modified JSON schema (see the JSON schema reference).

It is required to use camelCase for the key naming.
If the data type of a property is either an object or an array, the type property must be used instead of dataType.

If the schema is used for serialization it is recommended to put all properties as required to guarantee the uniqueness of encoding.

const myAssetSchema = {
    $id: "lisk/nft/create", (1)
    type: "object", (2)
    required: ["minPurchaseMargin", "initValue", "name"], (3)
    properties: { (4)
      minPurchaseMargin: {
        dataType: "uint32",
        fieldNumber: 1,
      },
      initValue: {
        dataType: "uint64",
        fieldNumber: 2,
      },
      name: {
        dataType: "string",
        fieldNumber: 3,
      },
    },
    default: { (5)
      minPurchaseMargin: 0,
      initValue: 1,
      name: "",
    },
  };
1 Unique identifier of the schema throughout the system. The $id doesn’t need to follow a particular format, except that it needs to be unique throughout the application.
2 Root type must be type object.
3 Required properties.
4 Properties of the schema.
5 Default property values.

Data types

The application data is stored in specific data types and structures in the database.

A schema always defines the data types that will be used in the database to store specific data. When the data is retrieved from the database by a module or plugin of the blockchain application, it is returned as a JavaScript object or JSON, depending on the context:

JavaScript object

These data types are used internally in the blockchain application to handle data from the database.

JSON

Data that is provided by actions and events is always returned in JSON format.

Table 1. Table: Data types of the different data structures
Data type JavaScript object JSON

string

string

string

uint32

number

number

sint32

number

number

uint64

BigInt

string

sint64

BigInt

string

bytes

Buffer

string in hex format

boolean

boolean

boolean

Decoding and encoding data

To conveniently decode and encode the data structures stored on the blockchain, such as blocks, transactions, account state, and chain state, use the codec library. The library can be imported from the following NPM packages:

  • lisk-sdk

  • @liskhq/lisk-client

  • @liskhq/lisk-codec

Example: Importing the codec library from the lisk-sdk package
const {
    codec,
} = require('lisk-sdk');

const CHAIN_STATE_KEY = "myContext:moreContext";

const schema = {
    $id: "lisk/myContext/moreContext",
    type: "object",
    required: ["myCounter"],
    properties: {
        myCounter: {
            dataType: "uint32",
            fieldNumber: 1,
        },
    },
    default: {
      myCounter: 0
    }
};

// Get data from the database
let counterBuffer = await stateStore.chain.get(
    CHAIN_STATE_KEY
);

// Decode the retrieved data with the schema
let counter = codec.decode(
    schema,
    counterBuffer
);

// Mutate the retrieved data
counter.myCounter++;

// Post the data back to the database
await stateStore.chain.set(
    CHAIN_STATE_KEY,
    // Encode the data again before sending it to the DB
    codec.encode(schema, counter)
);

Converting between formats

Some data is stored as Buffer in the database, but in other parts of the application, the data is expected as a hexadecimal string.

In these cases, it is necessary to convert between Buffer and string as described below:

String to Buffer

Use Buffer.from(data, 'hex') to convert a hex string to a Buffer.

this._channel.subscribe('app:block:new', async (data) => {
  const { block } = data;
  const { payload } = codec.decode(
    this.schemas.block,
    Buffer.from(block, 'hex'),
  );
  // ...
});

Buffer to String

Use .toString('hex') to convert a Buffer to a hex string.

this._channel.publish('srs:configCreated', {
  address: transaction._senderAddress.toString('hex'),
  // ...
});