Plugins
Plugins offer useful features to the application and external services, which are part of the off-chain logic of the blockchain application. In other words, a plugin will never change the state of the blockchain itself, contrary to the modules, which hold the on-chain logic of the blockchain application.
For a more practical guide how to create a new plugin, check out the guide Creating a new plugin. If you wish to view an example of a fully implemented plugin, check out the following examples:
|
Adding a plugin to the application
Plugins need to be registered to become available in the application.
If the application was bootstrapped with Lisk Commander, they are registered in the file src/app/plugins.ts
.
plugins.ts
import { Application } from 'lisk-sdk';
import { SomePlugin } from "some-plugin"; (1)
import { OtherPlugin } from "other-plugin";
const customConfig = {
port: 5555,
host: "127.0.0.1"
};
export const registerPlugins = (app: Application): void => {
app.registerPlugin(SomePlugin); (2)
app.registerPlugin(OtherPlugin, customConfig); (3)
};
1 | Import the plugin from an NPM package or from a local path. |
2 | Add this line to register the plugin to the application. |
3 | Optional: provide a custom configuration for the plugin. If no custom config option is provided, the plugin will use the default config options, defined in Plugin defaults. |
The plugin class
All custom plugins must extend the BasePlugin
exposed by the SDK.
The interface for the BasePlugin
is described in the Lisk Framework reference.
const { BasePlugin } = require("lisk-sdk");
class ForgerPlugin extends BasePlugin {
}
Plugin Alias
The unique identifier of the plugin.
It is used as prefix in the alias of events and actions, and as a key label to to add the properties of the Plugin defaults to the application configuration.
public static get alias(): string {
return 'forger';
}
Plugin info
Plugin meta information.
public static get info(): PluginInfo {
return {
author: packageJSON.author,
version: packageJSON.version,
name: packageJSON.name,
};
}
Plugin defaults
The configuration schema for this plugin.
After registering the plugin with the application, it can be configured in the application configuration, using the defined schema here.
The configuration options can then be accessed in the plugin under the variable this.options
.
get defaults() {
return {
$id: '#/plugins/lisk-dashboard/config',
type: 'object',
properties: {
applicationName: {
type: 'string',
description: 'Application name to be shown near Logo',
},
applicationUrl: {
type: 'string',
format: 'uri',
description: 'URL to connect',
},
port: {
type: 'integer',
minimum: 1,
maximum: 65535,
},
host: {
type: 'string',
format: 'ip',
},
},
required: [],
default: {
applicationUrl: 'ws://localhost:8080/ws',
port: 4005,
host: '127.0.0.1',
applicationName: 'Lisk',
},
}
};
Interfaces
Plugins can expose interfaces (Actions and Events), which allow other plugins and external tools to interact with the plugin.
View the "Interfaces" section of the Communication page to see an overview of the different interfaces and their accessibility in modules, plugins, and external services. |
Actions
Actions are functions which can be invoked via Remote-Procedure-Calls (RPC) by plugins and external services, to request data from the plugin.
public get actions(): ActionsDefinition {
return {
getVoters: async () =>
controllers.voters.getVoters(this._channel, this.codec, this._forgerPluginDB),
getForgingInfo: async () =>
controllers.forgingInfo.getForgingInfo(this._channel, this.codec, this._forgerPluginDB),
};
}
Events
Events are published by the plugin on relevant occasions. Other plugins and external services can subscribe to these events and as a result, they will be notified immediately every time a new event is published.
public get events(): EventsDefinition {
return ['block:created', 'block:missed'];
}
Execution logic
load()
The load()
method will be invoked by the controller to load the plugin.
It contains the plugin logic that is executed when the plugin is loaded in the application.
It can be used to retrieve, mutate, store and/or publish data in a specific manner, depending on the purpose of the plugin.
The channel
, which is available inside of the load()
function, allows access to the RPC endpoints of a Lisk node in order to subscribe to events or to invoke certain actions within the application to retrieve the desired data.
The following variables are accessible in the load()
function:
-
channel
: See Channel for plugins. -
this.options
: The Plugin defaults, as defined in the application configuration.
public async load(channel: BaseChannel): Promise<void> {
// Merge custom plugin configuration with default options
const options = objects.mergeDeep({}, config.defaultConfig.default, this.options) as Options;
this._channel = channel;
this._forgerPluginDB = await getDBInstance(options.dataPath);
this._channel.once('app:ready', async () => {
// Fetch and set forger list from the app
await this._setForgersList();
// Fetch and set transactions fees
await this._setTransactionFees();
// Sync the information
this._syncingWithNode = true;
await this._syncForgerInfo();
this._syncingWithNode = false;
// Listen to new block and delete block events
this._subscribeToChannel();
});
}