How to create a plugin

In this chapter, you’ll learn how to create & customize a new plugin for a blockchain client.

Sample code

View the complete sample code of this guide on GitHub in the Lisk SDK examples repository.

As defined in the Hello World application overview, the plugin shall provide the following functionality:

  1. The plugin should retrieve all events from the blockchain.

  2. The plugin should filter out the events generated by the Hello module.

  3. A plugin should accept a custom configuration based on which it should sync on-chain newHello events with the plugin’s database.

  4. The plugin should store all newHello events in a database.

  5. The plugin should provide an endpoint to fetch hello messages, their sender addresses, and the height of the block where such an event was emitted.

Prerequisites

To use this guide, it is assumed that the following criteria have been met:

  1. Lisk Commander is installed, and a basic blockchain client is already initialized, as explained in the guide Creating a new blockchain client.

  2. A new module HelloModule is created and contains all the functionalities as described in the guides for How to create a module

1. Generating the plugin’s file & folder structure

While in the root folder of the Hello client, generate a skeleton for the new plugin with Lisk Commander.

The command generate:plugin expects the following argument:

  • Plugin alias: The name of the plugin. It needs to be a string in camelCase, and always starts with a lower case letter. No numbers, hyphens, etc., are allowed.

lisk generate:plugin helloInfo

This will generate the following files:

Using template "lisk-ts"
Generating plugin skeleton
Registering plugin...
identical .liskrc.json
   create src/app/plugins/hello_info/hello_info_plugin.ts
   create test/unit/plugins/hello_info/hello_info_plugin.spec.ts

No change to package.json was detected. No package manager install will be executed.


Finished creating plugin

The hello_client directory will update and will look like the following:

hello/hello_client/src/app/
├── bin/
├── config/
├── src/
│    ├── app/
│    │    ├── app.ts
│    │    ├── index.ts
│    │    ├── modules/
│    │    ├── modules.ts
│    │    ├── plugins/
│    │    │   └──  hello_info/ (1)
│    │    │      └── hello_info_plugin.ts (2)
│    │    └── plugins.ts (3)
│    └── commands/
├── test/
│    ├── integration/
│    ├── network/
│    ├── unit/
│    │    ├── modules/
│    │    └── plugins/
│    │       └──  hello_info/
└──  └──            └── hello_info_plugin.spec.ts (4)
1 The plugin’s root folder hello_info is created under src/app/plugins/.
2 hello_info_plugin.ts contains the bare-bone HelloInfoPlugin class.
3 The plugins.ts file registers all the plugins with the hello_client.
4 Contains the unit tests for the plugin.

After updating the directory, the Lisk Commander will also automatically register the plugin with the client by adding it to the plugins.ts file.

Once the first plugin is added to the application, a manual change in plugins.ts is required:

  • Remove the underscore from the _app parameter and change it to app

Otherwise, you will run into the following error, when trying to start the client:

reference error : app is not defined
hello_client/src/app/plugins.ts
import { Application } from 'lisk-sdk';
import { HelloInfoPlugin } from "./plugins/hello_info/hello_info_plugin";

export const registerPlugins = (app: Application): void => {

    app.registerPlugin(new HelloInfoPlugin());
};

2. The "HelloInfoPlugin" class

The HelloInfoPlugin class is defined in the hello_info_plugin.ts file and it contains the plugin’s skeleton along with default functions for a plugin.

hello_client/src/app/plugins/hello_info/hello_info_plugin.ts
import { BasePlugin } from 'lisk-sdk';

export class HelloInfoPlugin extends BasePlugin {
	public name: 'helloInfo';

	public get nodeModulePath(): string {
		return __filename;
	}

	public async load(): Promise<void> {
	}

	public async unload(): Promise<void> {}
}

Each plugin’s class must extend from the BasePlugin, which is imported from the lisk-sdk package.

A plugin is highly customizable and can be implemented in any way as per the business needs. However, the only mandatory parts of a plugin are the nodeModulePath(), load() and unload() functions. Their efficacy is discussed in the Plugin Anatomy section.

It is worth mentioning that, our goal is to familiarize you with how to create and customize plugins in a blockchain client, our implementation of a plugin can undoubtedly differ from yours depending on your business logic.

Now that we have the bare-bone structure for our HelloInfoPlugin, let’s customize it.