Lisk Framework Overview

Logo

What is the Lisk Framework

Lisk Framework is an application framework responsible for establishing and maintaining the interactions between the modules of a Lisk blockchain application.

Lisk Framework aims to provide a consistent and intuitive interface between each module and component. Currently, Lisk Framework contains chain, api and network modules.

Architecture Overview

The architecture of Lisk Framework follows the research documented in LIP0005. The diagram below provides a high-level overview of the architecture:

Logo

Modules

Modules are individual building blocks for Lisk Core.

Core Modules

Core Modules are shipped along with the Lisk Core distribution itself. These modules constitute the minimum requirements to run a functional Lisk Core instance.

List of Core Modules
  • Chain Module: handles all events and actions, that are related to the blockchain system.

  • API Module: provides HTTP API endpoints, that enable users and other programs to interact with the Lisk blockchain through the API.

  • Network Module: handles peer-to-peer communication of nodes in the network.

Custom Modules

The implementation of each module is up-to user but it must inherit from BaseModule class and implement its methods.

Custom Modules can be plugged into Lisk Core and may offer new features/capabilities for the application, or replace Core modules functionalities. They extend the existing instance with a specific (and circumscribed) set of features.

const BaseModule = require('lisk-framework/src/modules/base_module')

// Exported as main file to javascript package
export default class MyModule extends BaseModule {
    /**
    * @param {Object} options - An object of module options
    */
    constructor(options) { (1)
     super(options);
    }

    /**
    * @return {string} alias - Return the module alias as string.
    * */
    static get alias(){ return 'moduleAlias'; }, (2)

    /**
    * @return {Object} info - JSON object referring the version, module name and module author.
    */
    static get info(){ (3)
        return {
            author: '',
            version: '',
            name: '',
            };
    },

    /**
    * @param {Channel} channel - An instance of a communication channel.
    * @return {Promise<void>}
    */
    async load(channel) {}, (4)


    /**
     * @return {Object} defaults - JSON object with default options for the module.
     */
    get defaults() { return {}; }, (5)

    /**
     * @return {Array} events - String Array of events.
     */
    get events() { return []; }, (6)

    /**
     * @return {Object} actions - Contains all available action names as key, and the corresponding function as value.
     */
    get actions() { (7)
        return {
            action1: action => {},
        }
    },

    /**
     * @return {Promise<void>}
     */
    async unload() {}, (8)
};
1 Constructor of the module.
2 Required. A unique module identifier, that can be accessed through out the system. If some module already registered with the same alias, it will throw an error.
3 Required. Package meta information.
4 Required. Method which will be invoked by controller to load the module. Make sure all loading logic get completed during the life cycle of load. Controller emit an event lisk:ready which you can use to perform some activities which you want to perform when every other module is loaded.
5 Supported configurations for the module with default values.
6 List of valid events which this module wants to register with the controller. Each event name will be prefixed by module alias, e.g. moduleName:event1. Listing an event means to register the event in the application. Any module can subscribe or publish that event in the application.
7 Object of valid actions which this module want to register with the controller. Each action name will be prefixed by module alias, e.g. moduleName:action1. Source module can define the action while others can invoke that action.
8 Method to be invoked by controller to perform the cleanup.

Module Communication

Modules communicate with each other through event-based channels. Modules running in different processes communicate with each other over IPC channels.

By default, modules will run in the same process as the controller, which loads the module. To load a module in a child process, make sure you have ipc enabled in the config and set the environment variable LISK_CHILD_PROCESS_MODULES with the module alias.

If the respective module is using a lot of CPU power, loading a module in a child process can prevent CPU usage bottlenecks.

Multiple modules can be defined by using commas like: LISK_CHILD_PROCESS_MODULES=httpApi,chain.

Module Life Cycle

The controller will load/unload each module one after another. A modules’ life cycle consists of following events in the right order:

Loading

  • channel.moduleAlias:registeredToBus

  • channel.moduleAlias:loading:started

  • channel.moduleAlias:loading:finished

Channels

  • InMemory Channel

  • Child Process Channel

Communicates with modules which reside in the same process as the controller.

By default, modules will load in the same process as the controller.

Communicates with modules which do not reside in the same process as the Controller.

The following methods are available for every module to use:

subscribe

Used to subscribe to events occurring on the controller.

channel.subscribe("moduleAlias:someEvent", eventObject => {});

This function accepts two arguments. The first is the event name prefixed with the name of the relevant module. The second argument is a callback which accepts one argument, which will be an instance of an event object.

publish

Used to publish events to the controller, which will be delivered to all events subscribers.

channel.publish('myModule:myContext:myEvent', eventObject);

This function accepts two arguments. The first one is the event name prefixed with the name of the relevant module. The second argument is the data object to be passed along the event.

invoke

Used to invoke an action for a module.

result = await channel.invoke('moduleAlias:someEvent', actionObject);

This function accepts two arguments. The first one is the event name prefixed with the name of the relevant module. The second argument is the data object to be passed along the action.

Event objects

An event object is a simple JavaScript object with the following attributes.

Property Type Description

name

string

The name of the event which is triggered.

module

string

The name of the target module for which event was triggered.

data

mixed

The data which was sent while publishing the event.

Action objects

An action object is a simple javascript object with attributes listed below.

Property Type Description

name

string

Name of the action which is invoked.

module

string

The name of the target module for which action was invoked.

source

string

The name of source module which invoked that action.

params

mixed

The data which was associated with the invocation for the action.

Controller

The controller is responsible for initialization the communication bus and any other dependencies required to load the modules. If any module is configured to load as a child process, then it is the controller’s responsibility to do so. The controller defines a set of events, that each component can subscribe to.

The following events and actions are available for all enabled modules and are at the same time accessible by all enabled modules.

Events

Each module can also define its own custom events or actions and will register that list with the controller at the time of initialization. The controller contains a complete list of events which may occur in the modules of Lisk Core at any given time.

Event Description

moduleAlias:registeredToBus

Triggered when the module has completed registering its events and actions with the controller. So when this event is triggered, the subscriber of the event can be sure that the controller has whitelisted its requested events and actions.

moduleAlias:loading:started

Triggered just before the controller calls the module’s load method.

moduleAlias:loading:error

Triggered if any error occurred during the call of the module’s load method.

moduleAlias:loading:finished

Triggered just after the module’s load method has completed execution.

moduleAlias:unloading:started

Triggered just before the controller calls the module’s unload method.

moduleAlias:unloading:error

Triggered if any error occurred during the call of module’s unload method.

moduleAlias:unloading:finished

Triggered just after the module’s unload method has completed execution.

lisk:ready

Triggered when the controller has finished initializing the modules and each module has been successfully loaded.

Actions

Action Description

lisk:getComponentConfig

A controller action to get the configuration of any component defined in controller space.

Components

Components are shared objects within the controller layer which any module can utilize. Components can use channels if required for implementation behavior. The following components are available currently.

Cache

This component provides basic caching capabilities, generic enough for any module to use if required.

Logger

Logger is responsible for all application-level logging activity. The logger component can be passed to any module, where it can be extended by adding module-specific behaviour.

Storage

The storage component is responsible for all database activity in the system. It exposes an interface with specific features for getting or setting particular database entities and a raw handler to the database object so that any module can extend it for its own use.

Find more details about the storage component in the dedicated LIP.

Configuration of the Lisk Framework

Configuration options are located in * framework/src/modules/<module-name>/defaults/config.js for each module. - framework/src/components/<component-name>/defaults/config.js for each component.

Each config.js file consists of 2 parts:

  1. JSON-schema specification for all available config options

  2. Default values for the available config options for this specific module.

Please don’t change the default values in these files directly as they will be overwritten on software updates. Instead define the custom configuration options inside your blockchain application.

Get Involved

Reason How

Introduce yourself to our community

Lisk Discord

Found a bug

Open a new issue

Found a security issue

See our bounty program

Want to share your research

Propose your research

Want to develop with us

Create a fork