How to create a module configuration

On this page, you’ll learn how to:

  • Define a config schema for a module

  • Set a default module config

  • Set custom configurations for a module

  • Make module configurations accessible inside the command of a module

To allow the developer to configure a module in the config.json file, create the corresponding configuration schema and pass the values to the module in the init() method of the module.

This allows you to overwrite the default configurations of a module conveniently by updating the config.json file of the Hello client.

Who should configure the module?
The module-specific configs should be set by the blockchain developer, and should not be changed or customized by a node operator, because it might cause the node to hard fork, as other nodes wouldn’t share the same module config values in that case.

1. Define a module schema

At first, define a default configuration inside of module.ts. These configuration values will be used if no custom values are set by the developer in config.json.

For the Hello module, we want to provide configuration options for the following values:

  1. maximum Hello message length

  2. minimum Hello message length

  3. List of blacklisted words

Therefore, we define the module default config as follows:

hello_client/src/app/modules/hello/module.ts
export const defaultConfig = {
    maxMessageLength: 256,
    minMessageLength: 3,
    blacklist: ["illegalWord1"]
};

In our example, we define the following default config:

Default config values
  1. maximum Hello message length: 256

  2. minimum Hello message length: 3

  3. List of blacklisted words: "illegalWord1"

Once the default config is created, define the corresponding module config interface in types.ts:

hello_client/src/app/modules/hello/types.ts
import { JSONObject } from 'lisk-sdk';

export interface ModuleConfig {
    maxMessageLength: number;
    minMessageLength: number;
    blacklist: string[];
}

export type ModuleConfigJSON = JSONObject<ModuleConfig>;

The config schema is required to validate the module config defined in config.json, so add the respective config schema to schema.ts as well:

hello_client/src/app/modules/hello/schema.ts
export const configSchema = {
    $id: '/hello/config',
    type: 'object',
    properties: {
         maxMessageLength: {
            type: 'integer',
            format: 'uint32',
        },
        minMessageLength: {
            type: 'integer',
            format: 'uint32',
        },
        blacklist: {
            type: 'array',
            items: {
                type: 'string',
                minLength: 1,
                maxLength: 40,
            },
        },
    },
    required: [
        'maxMessageLength',
        'minMessageLength',
        'blacklist'
    ],
};

2. Define a module configuration file

Open the configuration file that was created in the guide Blockchain client configuration, and add the config option for the Hello module like this:

hello_client/config/custom_config.json
{
  // [...]
  "modules": {
    "hello": {
      "maxMessageLength": 300,
      "minMessageLength": 5,
      "blacklist": ["illegalWord1", "badWord2", "censoredWord3"]
    }
  },
  "plugins": {}
}

In the example, we increase the max message length to 300, the min message length to 5, and we add two additional words to the blacklist: badWord2 and censoredWord3

3. Initialize the module config

Now, to make the custom config accessible in the module, retrieve the config options in the init() method like so:

hello_client/src/app/modules/hello/module.ts
import {
    BaseModule, BlockAfterExecuteContext, BlockExecuteContext, BlockVerifyContext,
    GenesisBlockExecuteContext, InsertAssetContext, ModuleInitArgs,
    ModuleMetadata, TransactionExecuteContext, TransactionVerifyContext,
    VerificationResult, codec, utils
} from 'lisk-sdk';
import { validator } from '@liskhq/lisk-validator';
import { createHelloSchema, CreateHelloParams, configSchema } from './schema';
import { ModuleConfigJSON } from './types';
// [...]
export const defaultConfig = {
	blacklist: ["illegalWord1"],
	maxMessageLength: 256,
	minMessageLength: 3
};

export class HelloModule extends BaseModule {
    // [...]

    public async init(args: ModuleInitArgs): Promise<void> {
        // Get the module config defined in the config.json of the node
        const { moduleConfig } = args;
        // Overwrite the default module config with values from config.json, if set
        const config = utils.objects.mergeDeep({}, defaultConfig, moduleConfig) as ModuleConfigJSON;
        // Validate the config with the config schema
        validator.validate<ModuleConfigJSON>(configSchema, config);
    }
    // [...]
}

The configuration options which we defined in the custom_config.json file used by the node, are merged with the defaultConfig that is defined above the HelloModule class. This will overwrite every value of the default config with the value of the user-defined config. If no value is set in the node config, it will use the value of the defaultConfig.

Once the configs are merged, the module config is validated against the config schema defined in step Define a module schema.

4. Testing the custom module config

To verify that the config options which we defined in step Define a module configuration file are really used during the verification of a command, we first need to create the new command type and then send some "Create Hello" transactions to the node.

Please check out the guide How to create a command, especially the section → Try the new command out for further details on how to test and verify the config values.