Architectural overview


The Lisk Framework is an application framework which integrates the Lisk Elements packages in order to form a functioning Lisk blockchain application. Its modular architecture allows developers to extend on-chain logic with user defined modules and transaction assets. In addition, the developer can add off-chain logic in custom plugins. The plugins can be registered to the blockchain application optionally to provide additional services and features.

The Lisk Framework provides a consistent and intuitive interface between each module and plugin.

The diagram shown below provides a high-level overview of the architecture:


On-Chain Architecture

The on-chain architecture is a layer of abstraction that provides a collection of features to configure and run any business logic on the blockchain.

In short, the on-chain logic:

  • introduces state mutations through blocks or transactions.

  • is part of the blockchain protocol.

  • is verifiable by anyone by synchronizing with the blockchain.

  • is handled in "modules".

More information can be found in section On-chain architecture

Off-Chain Architecture

Custom plugins can be registered with the application to add any logic that doesn’t require state changes on the blockchain. This could be a simple use case such as creating an HTTP API for a blockchain or providing some aggregation service.

In short, the off-chain logic:

  • introduces new blockchain application features.

  • is not part of the blockchain protocol.

  • is optional to execute on a full node.

  • is handled in "plugins".

More information can be found in the section Off-chain architecture

Communication Architecture

In most use cases, external applications need to communicate with the blockchain. This could be a frontend, a CLI or any app developed independently in any other technology stack. The communication architecture provides two industry standard communication formats, one is Inter Process Communication (IPC) and the other is Web Sockets (WS). Connect either to the IPC or the WS interface to communicate with the blockchain.

More information can be found in the section Communication architecture


The framework architecture is constructed of three different layer of abstractions: Node, Modules and Plugins (see the architecture diagram). The Application object encapsulates all together to provide a user-facing interface.

The Application class is the entry point to create a blockchain application. It can be instantiated in two ways:

//Initiates the Application including all default modules
const app = Application.defaultApplication(genesisBlock, config);
//Initiates the Application without default modules
const app = new Application(genesisBlock, config);

genesisBlock represents the Genesis block and config represents the Configuration for the application.

The recommended method to create an Application instance is to use the defaultApplication, since it comes with the default modules. If the class constructor is used, the modules need to be registered manually.


The application config object is passed to the Application and must follow the configuration schema.

It is not necessary to include all options that are included in the schema. The application will use the default configuration options in case a config option is not specified.
Configuration schema
let config = {
  // Required. Default: ~/.lisk
  // rootPath defines the root path for all data to be stored
  rootPath: string,
  // Required. Default: alpha-sdk-app
  // label defines the process name and folder within the root path
  label: string,
  // Required. Default: 0.0.0
  // version must follow semver format
  version: string,
  // Required. Default: 2.0
  // network version defines a P2P network version
  networkVersion: string,
  // Required.
  // rpc defines communication behavior
  rpc: {
    // Default: false
    // enabled creates IPC socket if true
    enable: boolean,
    // Default: ipc
    // enabled communication through 'ipc' or 'ws'
    // Default: 8080
    // In case of `mode` is set to `ws`, this port used
    port: 8080
  // Required.
  // forging holds delegate information for forging
  forging: {
    // Optional. Default: 2
    // waitThreshold defines the extra waiting time for the last block before forging
    waitThreshold: number,
    // Optional.
    // delegates holds the delegate information for forging
    delegates: {
      // Required.
      // address defines the address of the delegate
      address: string,
      // Required.
      // encryptedPassphrase defines the encrypted passphrase
      encryptedPassphrase: string,
      // Required.
      // hashOnion holds the seed reveal to put in block header
      hashOnion: {
        // Required.
        // count holds the total number of hash onions
        count: number,
        // Required.
        // distance holds a distance between each hash onion
        distance: number,
        // Required.
        // hashes holds the seed reveal for every distance
        hashes: string[]
    // Optional. Default: false
    // force defines whether to use a default password and enable forging by default
    force?: boolean,
    // Optional.
    // defaultPassword defines a password to use to decrypt the encrypted Passphrase
    defaultPassword?: string
  // Required.
  // network holds the network information of the node
  network: {
    // Required. Default: 5000
    // port defines an open port for P2P incoming connections
    port: number,
    // Required.
    // seedPeers defines an entry point of the network
    seedPeers: { ip: string, port: number }[],
    // Optional.
    // blacklistedIPs defines IP address which the node will reject the connection for both outbound and inbound connections
    blacklistedIPs?: string[],
    // Optional.
    // fixedPeers defines peers which will always try to connect for outbound connections
    fixedPeers?: { ip: string, port: number }[],
    // Optional.
    // whitelistedPeers defines peers that are always allowed to connect to the node on inbound connections
    whitelistedPeers?: { ip: string, port: number }[],
    // Optional. Default: 86400000 (24h)
    // peerBanTime defines the length of banning in milliseconds
    peerBanTime?: number,
    // Optional.
    // connectTimeout defines a timeout for a connection
    connectTimeout?: number,
    // Optional.
    // actTimeout defines a timeout for response from a peer
    ackTimeout?: number,
    // Optional. Default: 20
    // maxOutboundConnections defines a maximum number of outbound connection allowed
    maxOutboundConnections?: number,
    // Optional. Default: 100
    // maxInboundConnections defines a maximum number of inbound connection allowed
    maxInboundConnections?: number,
    // Optional. Default: 16
    // sendPeerLimit defines a maximum peer to send information when “send” is called
    sendPeerLimit?: number,
    // Optional. Default: 200
    // maxPeerDiscoveryResponseLength defines a maximum length for the peer information response of peer discovery
    maxPeerDiscoveryResponseLength?: number,
    // Optional. Default: 3048576
    // wsMaxPayload defines maximum size of the payload allowed per communication
    wsMaxPayload?: number,
    // Optional. Default: true
    // advertiseAddress defines whether to announce the IP/Port other peers
    advertiseAddress?: boolean
  // Optional.
  // logger holds information for the logging
  logger: {
    // Optional. Default: lisk.log
    // logFileName defines a name for the log file
    logFileName: string,
    // Optional. Default: info
    // fileLogLevel defines the log level output for the file logging
    fileLogLevel: string,
    // Optional. Default: none
    // consoleLogLevel defines the log level output for the console logging
    consoleLogLevel: string
  // Required.
  // genesisConfig holds the blockchain protocol configuration
  // it is also passed to the module constructor
  genesisConfig: {
    // Since all genesis config options will be passed to all modules, the developer can add an extra config specific for a module
    myCustomProperty: unknown,
    // Optional. Default: 68
    // bftThreshold defines a threshold for pre-vote and pre-commit
    bftThreshold: number,
    // Optional. Default: Lisk
    // communityIdentifier defines a community identifier used to create the network identifier
    communityIdentifier: string,
    // Optional. Default: 10
    // blockTime defines the frequency of blocks to be created
    blockTime: number,
    // Optional. Default: 15360 (15kb)
    // maxPayloadLength defines a maximum payload size allowed in a block in bytes
    maxPayloadLength: number,
    // Optional.
    // rewards defines a block reward schedule
    rewards: {
      // Optional. Default: [‘500000000’, ‘400000000’, ‘300000000’, ‘200000000’, ‘100000000’]
      // milestones defines the block reward for every distance
      milestones: string[],
      // Optional. Default: 2160
      // offset defines at which height the block reward is given
      offset: number,
      // Optional. Default: 3000000
      // distance defines the duration of the each milestone
      distance: number
    // Optional. Default: 1000
    // minFeePerByte defines a minimum fee per byte for a transaction
    minFeePerByte: number,
    // Optional.
    // baseFees defines a additional base fee to be included in the calculation of the minimum fee for a transaction
    baseFees: {
      moduleID: number,
      assetID: number,
      baseFee: string,
    // Optional. Default: 101
    // Number of actively forging delegates.
    activeDelegates: number,
    // Optional. Default: 2
    // The offset of rounds from the current round, which will be used to calculate the vote weights for the next forging round.
    delegateListRoundOffset: number,
    // Optional. Default: 2
    // Number of random standy delegates that are allowed to forge each round.
    standbyDelegates: number,
  // Optional.
  // transactionPool defines custom properties of the transaction pool
  transactionPool: {
    // Optional. Default: 4096
    // maxTransactions defines a maximum number of transactions in the pool
    maxTransactions?: number,
    // Optional. Default: 64
    // maxTransactionsPerAccount defines a maximum number of transactions in the pool per sender account
    maxTransactionsPerAccount?: number,
    // Optional. Default: 10800000
    // transactionExpiryTime defines timeout of the transaction in the pool in milliseconds
    transactionExpiryTime?: number,
    // Optional. Default: 0
    // minEntranceFeePriority defines a minimum fee priority required to be added to the transaction pool
    minEntranceFeePriority?: string,
    // Optional. Default: 10
    // minReplacementFeeDifference defines a minimum fee difference to replace a transaction with the same nonce
    minReplacementFeeDifference?: string,
  // Optional.
  // plugins holds a config which is passed to a particular plugin.
  // pluginAlias is a variable name that is dependant on the installed plugin
  plugins: {
    httpApi: {
      port: number, //default: 4000,
      whiteList: string[], //default: [''],
      cors: {
        origin: string, //default: '*',
        methods?: string[], //default: ['GET', 'POST', 'PUT'],
      limits: {
        max: number, //default: 0,
        delayMs: number, //default: 0,
        delayAfter: number, //default: 0,
        windowMs: number, //default: 60000,
        headersTimeout: number, //default: 5000,
        serverSetTimeout: number, //default: 20000,

More information about how to configure a blockchain application can be found in the guide Configuring a blockchain application.

Genesis block

A genesis block must be given to the application, and all networks should have a different genesis block.

The genesis block describes the very first block in the blockchain. It defines the initial state of the blockchain on start of the network.

The genesis block is not forged by a delegate, such as all of the other blocks which come after the genesis block. Instead it is defined by the developer, when creating the Application instance of the blockchain application.

The Lisk SDK exposes an object genesisBlockDevnet that holds all of the required important information to spin up a local development network.

Genesis block schema
const genesisBlock = {
  header: {
    generatorPublicKey: "",
    // height can be either 0 or regenesis height
    height: number,
    // empty buffer or merkle root of the previous blocks from previous network
    previousBlockID: Buffer,
    reward: 0n,
    signature: "",
    // timestamp of the blockchain in unix timestamp in second
    timestamp: number,
    // transactionRoot is alway empty hash
    transactionRoot: Buffer.from('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', 'hex'),
    version: 0,
    asset: {
      // number of initial round to use the initDelegates
      initRounds: number,
      // address of initial delegates
      initDelegates: Buffer[],
      // encoded accounts for the initial state
      accounts: Buffer[],
  payload: [],
A valid genesis block can be created using @liskhq/lisk-genesis.