Properties, serialization, and initial values of the interoperability module

Hello everyone,

I am excited to publish a LIP for the roadmap objective " Define Cross-chain Messaging Protocol". This objective is part of the interoperability phase.

I’m looking forward to your feedback.

Here is the complete LIP draft:

LIP: <LIP number>
Title: Properties, serialization, and initial values of the interoperability module
Author: Alessandro Ricottone <alessandro.ricottone@lightcurve.io>
Type: Standards Track
Created: <YYYY-MM-DD>
Updated: <YYYY-MM-DD>

Abstract

The interoperability module provides basic functionalities to transmit information between interoperable chains in the Lisk ecosystem using cross-chain messages. In this LIP the properties, serialization, and initial values of this module are specified. Additionally, this LIP also provides a broad overview of the Lisk interoperability solution, motivating several design choices and presenting the new transactions that are part of the interoperability module.

Copyright

This LIP is licensed under the Creative Commons Zero 1.0 Universal.

Motivation

Interoperability has the potential to solve the scaling issue of blockchains: Instead of deploying applications and their corresponding transactions onto a single blockchain, these are implemented into separate blockchains which then communicate with each other using an interoperability protocol.

To achieve interoperability, chains in the Lisk ecosystem (the mainchain and the sidechains participating in interoperability) exchange information via cross-chain transactions. As an example, a user can issue a cross-chain transaction to transfer part of its mainchain LSK balance to a sidechain, and subsequently use it to issue one of the sidechain custom transactions.

In the Lisk protocol, cross-chain transactions are special in that, after being included in their origin ledger, some new data structures, the cross-chain messages (CCMs), are created, which are transmitted to other chains via special transactions called cross-chain update (CCU) transactions. CCUs also contain information about the chain, in the form of a certificate.

One of the main motivations for proposing a certificate-based communication between chains is the ability for all chains in the ecosystem to remain state machines. This means that all information needed to validate and advance a chain to the next block is present on the chain itself. In the Lisk interoperability solution, the only information that needs social consensus is information about the initial validators of the other chain. On the mainchain, this information is received via the sidechain registration transaction; on sidechains, in a similar way, via the mainchain registration transaction.

The interoperability module provides the data structures and functionalities necessary for interoperability between chains of the Lisk ecosystem. In this LIP, we specify the properties, serialization, and initial values of the interoperability module.

Rationale

Interoperability Transactions

The interoperability module stores the properties necessary to validate and process the following new transaction types.

Sidechain Registration Transaction

The sidechain registration transaction is used to register a sidechain on the Lisk mainchain. When this transaction is processed, a new account for the sidechain is created in the mainchain state under the interoperability storage. The properties of the account are specified below. In particular, the account is initialized with an empty inbox and outbox, while the sidechain name and the initial validators set are given in the transaction asset. The network ID is calculated from the address of the transaction sender and the genesis block ID, also given in the transaction asset.

Mainchain Registration Transaction

The mainchain registration transaction is used to register the Lisk mainchain on a sidechain. When this transaction is processed, a new account for the mainchain is created in the sidechain state under the interoperability database. The properties of the account are specified below. In particular, the account is initialized with an empty inbox and outbox, while the initial validators set is given in the transaction asset. The name and network ID of the mainchain are global protocol constants in the whole ecosystem.

This transaction also initializes another data structure in the interoperability store, containing some information about the sidechain itself. In particular, it sets the sidechain name and chain ID to the ones that have been previously registered on the mainchain via the sidechain registration transaction.

Cross-Chain Update Transactions

Figure 1: A sketch of an interoperability interaction between the Lisk mainchain and a sidechain. Information (cross-chain messages and updated state) from mainchain blocks (light blue) is collected into a cross-chain update transaction by the relayer, which then posts it on the sidechain.

CCUs are used to post the updated state of the sending chain on the receiving chain. Furthermore, they transmit the cross-chain messages that need to be sent to the receiving chain (see Figure 1). We introduce two different CCUs, one for posting on the Lisk mainchain, and the other for posting on sidechains. They differ in the way the included messages are handled: on mainchain, messages targeting another sidechain are forwarded to that sidechain outbox, while messages targeting the mainchain are simply processed. On the other hand, a CCU posted on a sidechain can only contain CCMs targeting that sidechain, being invalid otherwise.

Token and NFT Recovery Transactions

These transactions are used to recover tokens (fungible and non-fungible) that a user sent to a sidechain that later has been terminated. The user proves with an inclusion proof that they have a certain balance (or a certain non-fungible token) in the terminated sidechain. The proof is validated against the last certified state root stored in the sidechain account on mainchain. The recovered tokens are sent to the user account on the token native chain.

Message Recovery Transaction

This transaction is used to recover a pending message in the outbox of a terminated chain. The user proves with an inclusion proof that the message is in the terminated sidechain outbox. The proof is validated against the outbox root stored in the sidechain account on mainchain. The recovered message is then bounced back to the original sending chain (which could be the mainchain).

Liveness Condition

Active sidechains are required to prove their liveness to the mainchain at least once per month. This is done by including a CCU on the mainchain. If a sidechain does not post a CCU within 30 days, the sidechain account is terminated.

This rule guarantees that users do not send funds to inactive sidechains and that users who have tokens in a sidechain which stops communicating with the ecosystem can recover their tokens. The same rule applies to the mainchain account on a sidechain. At least once within 30 days, a mainchain CCU has to be included in the sidechain, otherwise, the mainchain account on the sidechain is terminated.

Life Cycle of a Sidechain

The life cycle of a sidechain can be split into 3 parts, corresponding to the 3 values of the account status property: ‘‘registered’’, ‘‘active’’, and ‘‘terminated’’.

A sidechain registers on the mainchain with a sidechain registration transaction. This transaction creates the sidechain account on mainchain, with initial status set to ‘‘registered’’. Thereafter, the mainchain account is created on a sidechain with a mainchain registration transaction, with initial status set to ‘‘registered’’.

After a sidechain has been registered on the mainchain, it cannot receive any cross-chain message and does not need to follow the liveness rule, until the first sidechain CCU has been included in the mainchain. At this point, the status of the sidechain account on mainchain is updated to ‘‘active’’ and the liveness requirement is enforced.

If no CCU is received within 30 days, the chain account is terminated and no more CCMs can be sent to or received from the sidechain. A sidechain account can also be terminated if the sidechain posts a CCU containing a CCM with an invalid schema or with an invalid sending chain ID. Finally, users can recover messages and tokens from the terminated sidechain with a recovery transaction.

Properties of the Interoperability Module

Each interoperable sidechain maintains an interoperability account for the mainchain, while the mainchain maintains an account for each registered sidechain. Correspondingly, on a sidechain we denote with ‘‘partner chain’’ the mainchain, while on mainchain we denote with ‘‘partner chain’’ the relevant sidechain.

Each chain also includes an account storing the chain name and ID in the ecosystem. This ‘‘own chain’’ account is present by default in the mainchain, while on a sidechain is created by the mainchain registration transaction.

Figure 2: A summary of the interoperability module storage. The interoperability module defines 5 stores: the account store for partner chain accounts and the own chain data, the outbox store for outbox roots, the name and network ID stores to keep track of the names and network IDs of registered sidechains (only on mainchain).

Chain Account Properties

Below we list and describe the properties of a chain account in the interoperability module.

inbox

The data structure containing information about the cross-chain messages received from the partner chain, organized in a regular Merkle tree (specified for the Lisk protocol in LIP0031). It contains the following properties:

  • root: The root of the Merkle tree.
  • appendPath: An array of hashes necessary to append new data to the tree efficiently.
  • size: The current size of the tree, i.e. the number of cross-chain messages received from the partner chain and processed.
outbox

The data structure containing information about the cross-chain messages sent to the partner chain, organized in a regular Merkle tree. It contains the following properties:

  • root: The root of the Merkle tree.
  • appendPath: An array of hashes necessary to append new data to the tree efficiently.
  • size: The current size of the tree, i.e. the number of cross-chain messages sent to the partner chain.

We give more details about the rationale regarding the inbox and outbox in a section below.

networkID

This property corresponds to the network identifier, or network ID, of the partner chain. For a sidechain account on the mainchain, it is set by the sidechain registration transaction. For the mainchain account on sidechains, it is a protocol constant.

lastCertifiedStateRoot

The value of this property is set to the state root contained in the last CCU from the partner chain. It is used to validate the inclusion proof of the cross-chain messages contained in a CCU and to verify the validity of the token recovery transaction.

lastCertifiedTimestamp

The value of this property is set to the timestamp contained in the last CCU from the partner chain. It is used to check that the partner chain fulfils the liveness requirement (see above).

lastCertifiedHeight

The value of this property is set to the height contained in the last certificate from the partner chain. It is used to validate a certificate (certificates must contain block headers with increasing heights).

partnerChainOutboxRoot

The value of this property is set to the outbox root computed from the last CCU from the partner chain. It is used to validate the cross-chain messages contained in a future CCU when the CCU does not certify a new outbox root.

partnerChainOutboxSize

This property corresponds to the size of the outbox tree of the partner chain, i.e. the number of cross-chain messages sent from the partner chain. This property is updated by the inboxUpdate property contained in CCUs from the partner chain.

partnerChainInboxSize

This property corresponds to the size of the inbox tree of the partner chain, i.e. the number of cross-chain messages received and processed by the partner chain. This property is used to verify the validity of the message recovery transaction and it is updated by a cross-chain update receipt message from the partner chain.

name

This property corresponds to the name of the sidechain as a string of characters. It has to be unique in the ecosystem.

status

This property stores the current status of the partner chain account. As explained above, there are 3 possible statuses: ‘‘active’’, ‘‘registered’’, and ‘‘terminated’’.

validators

This property stores the set of validators eligible to sign the certificates from the partner chain. It is an object containing the following properties:

  • keys: An array of BLS public keys. The set of public keys that are eligible to sign the next certificate.
  • weights: An array of integers. Each element is the weight of the corresponding key in the keys array. For DPoS chains, the value of the elements of this array is usually 1, as every active validator has the same consensus weight for the signing of the next certificate.
  • certificateThreshold: An integer setting the required cumulative weight assigned to the signatures for the first certificate from the sidechain to be valid.

Own Account Properties

The mainchain registration transaction creates a new data structure in the interoperability store of the sidechain, holding the following properties.

name

The name of the sidechain registered on mainchain with the sidechain registration transaction.

chainID

The chain ID assigned to the sidechain on mainchain after processing the sidechain registration transaction.

Message Forwarding and the Role of the Lisk Mainchain

In the Lisk ecosystem, the Lisk mainchain plays a central role, distinct from any other chain. It acts as an intermediary chain, relaying cross-chain messages between sidechains. This has a few notable advantages:

  1. Relayers only need to follow the chosen sidechain and the mainchain. All transactions sent to a given chain will go through the sidechain outbox on mainchain.
  2. The mainchain guarantees that messages are available and can be delivered to active sidechains. In the case in which the receiving sidechain is not active, the messages are returned to their sending chain. This allows the sidechain protocol to remain simple and agnostic to the state of other sidechains. In particular, transaction handling does not require knowledge of all potential receiving chains.

Inbox and Outbox

As explained above, inbox and outbox are organized as regular Merkle trees. Since the root of the tree depends on the order of insertion, all cross-chain messages have to be inserted in the receiving chain in the same order in which they were included in the sending chain, guaranteeing that they are processed in the correct order.

Using a Merkle tree also guarantees that the number of sibling hashes that are part of inclusion proofs grows only logarithmically with the number of elements in the tree. In particular, this means that the number of sibling hashes required to validate the cross-chain messages in a CCU against the partner chain lastCertifiedStateRoot grows logarithmically with the number of processed messages.

Storage of the Outbox Root

The outbox root property is duplicated and additionally stored separately from all other properties of the chain account. The storage prefix of the outbox root is the constant STORE_PREFIX_OUTBOX and the storage key is the hash of the chain ID of the partner chain. Storing the outbox root with a different storage prefix allows to separate the subtree corresponding to the outbox roots from the rest of the data in the interoperability store. This choice allows for shorter inclusion proofs for the outbox root, as the other properties of the interoperability module are not needed to recalculate the state root if the outbox root is known. In particular, the inclusion proof contained in a CCU from a sidechain posted on the mainchain will contain only one hash.

Storage of Auxiliary Data

In order to process sidechain registration transactions more efficiently, it is convenient to store on mainchain auxiliary data that can be used to check the uniqueness of the sidechain name and network ID. For instance, if an entry is already present in the name auxiliary data, it means that a chain with that name is already registered in the ecosystem.

Specification

In this section, we specify the properties that are part of the interoperability module, and the reducers that are provided by it.
The interoperability module has module ID MODULE_ID_INTEROPERABILITY (see the table below).

Notation and Constants

For the rest of this proposal let account(chainID) be the chain account in the interoperability store with storagePrefix = STORE_PREFIX_ACCOUNT and storageKey = chainID.

Furthermore, we define the following constants:

Name Type Value
Interoperability Constants
MODULE_ID_INTEROPERABILITY uint32 64
MAINCHAIN_ID bytes 1
MAINCHAIN_NAME string “lisk-mainchain”
MAINCHAIN_NETWORK_ID bytes mainchain network identifier
Interoperability Storage
STORE_PREFIX_OUTBOX bytes 0x0000
STORE_PREFIX_ACCOUNT bytes 0x8000
STORE_PREFIX_NAME bytes 0xc000
STORE_PREFIX_NETWORK_ID bytes 0xe000
Interoperability Asset IDs
ASSET_ID_SIDECHAIN_REG uint32 0
ASSET_ID_MAINCHAIN_REG uint32 1
ASSET_ID_SIDECHAIN_CCU uint32 2
ASSET_ID_MAINCHAIN_CCU uint32 3
ASSET_ID_MESSAGE_RECOVERY uint32 4
ASSET_ID_TOKEN_RECOVERY uint32 5
ASSET_ID_NFT_RECOVERY uint32 6
ASSET_ID_CCM_REGISTRATION uint32 7
ASSET_ID_CCM_CCU_RECEIPT uint32 8
ASSET_ID_CCM_CHANNEL_TERMINATED uint32 9
Chain Status
CHAIN_REGISTERED uint32 0
CHAIN_ACTIVE uint32 1
CHAIN_TERMINATED uint32 2
General Constants
EMPTY_HASH bytes SHA-256("")

uint32be

The function uint32be(x) returns the big endian uint32 serialization of an integer x, with 0<=x<2^32.
This serialization is always 4 bytes long.

List of Account status Values

The status property is an integer corresponding to the chain account state as follows:

  • CHAIN_REGISTERED: chain account registered
  • CHAIN_ACTIVE: chain account active
  • CHAIN_TERMINATED: chain account terminated

Internal Functions

appendToInboxTree

The appendToInboxTree function appends a new element to the underlying Merkle tree of the inbox of a chain account. The input parameters are the partner chain ID chainID and the 32 bytes hash value appendData.

appendToInboxTree(chainID, appendData):
    account(chainID).inbox.size++
    //update appendPath and root. 
    let inboxTree be the underlying Merkle tree of account(chainID).inbox
    inboxTree.append(appendData)
    set inbox.root = inboxTree.root
    set inbox.appendPath = inboxTree.appendPath
    set inbox.size = inboxTree.size

appendToOutboxTree

The appendToOutboxTree function appends a new element to the underlying Merkle tree of the outbox of a chain account. The input parameters are the partner chain ID chainID and the 32 bytes hash value appendData.

appendToOutboxTree(chainID, appendData):
    account(chainID).outbox.size++
    //update appendPath and root.
    let outboxTree be the underlying Merkle tree of account(chainID).outbox 
    outboxTree.append(appenData)
    set outbox.root = outboxTree.root
    set outbox.appendPath = outboxTree.appendPath
    set outbox.size = outboxTree.size

addToOutbox

The addToOutbox function adds a new CCM to the outbox of a chain account. The input parameters are the partner chain ID chainID and the cross-chain message CCM to be added.

addToOutbox(chainID, CCM)
    set CCM.index = account(chainID).outbox.size
    if CCM.originalIndex == 0:
        set CCM.originalIndex = CCM.index
    serializedMessage = byte array corresponding to the serialized CCM according to the schema in "Cross-chain Messages" LIP
    appendToOutboxTree(chainID, SHA-256(serializedMessage))
    let outboxRoot be the entry with storagePrefix=STORE_PREFIX_OUTBOX and storageKey=chainID
    set outboxRoot = account(chainID).outbox.root

isLive

The isLive function checks the liveness requirement for the partner chain. The input parameters are the partner chain ID chainID and a timestamp timestamp.

isLive(chainID, timestamp):
   if timestamp - account(chainID).lastCertifiedTimestamp <= 30*24*3600:
      return True
   else:
      return False

getPartnerChainID

The getPartnerChainID function returns the chain ID of the partner chain. On mainchain, this is always the given chain ID, while on a sidechain this is always the mainchain ID. The input parameter is the tentative partner chain ID chainID.

getPartnerChainID(chainID):
   let ownChainID be the chain ID of this chain
   if ownChainID == MAINCHAIN_ID:
      return chainID
   else:
      return MAINCHAIN_ID

createCrossChainMessage

The createCrossChainMessage function creates and returns a new CCM. It is specified in “Cross-chain Messages” LIP.

validateFormat

The validateFormat function checks that a CCM follows the correct schema and does not exceed a size limit of 10KB. It is specified in “Cross-chain Messages” LIP.

process

The process function applies or forwards CCMs, including the handling of the different error cases. It is specified in “Cross-chain Messages” LIP.

terminateChain

The terminateChain function terminates a chain account. The input parameter is the chain ID chainID.

terminateChain(chainID):
    set account(chainID).status = CHAIN_TERMINATED 
    //spawn a channel terminated cross-chain message 
    CTM = createCrossChainMessage(
        MODULE_ID_INTEROPERABILITY,
        ASSET_ID_CHANNEL_TERMINATED,
        chainID,
        0,
        {partnerChainInboxSize:account(chainID).inbox.size})
    addToOutbox(chainID, CTM)

    set account(chainID).outbox.appendPath = []
    //remove outbox root from state tree
    let stateTree be the state tree of this chain as defined in LIP "State model and state root"
    k = MODULE_ID_INTEROPERABILITY || STORE_PREFIX_OUTBOX || SHA-256(chainID)
    stateTree.remove(k)

Reducers

send

The send reducer is used to create and add a message to the outbox of a partner chain. The input parameters are a timestamp timestamp, the message module ID moduleID, the message asset ID assetID, the receiving chain ID receivingChainID, the message fee fee, the address of the account paying the fee feeAddress, and the message asset asset.

send(timestamp, moduleID, assetID, receivingChainID, fee, feeAddress, asset):
    partnerChainID = getPartnerChainID(receivingChainID)

    if not isLive(partnerChainID, timestamp):
        return liveness error

    if not account(partnerChainID).status == CHAIN_ACTIVE:
        return status error

    //handle fee using token module reducer (LIP "Introduce an interoperable token module")
    call fungibleToken.handleMessageFee(feeAddress, receivingChainID, fee), if it fails:
        return fee error

    //create cross-chain message
    CCM = createCrossChainMessage(
        moduleID, 
        assetID, 
        receivingChainID, 
        fee,
        asset)

    addToOutbox(partnerChainID, CCM)

    return success

error

The error reducer is used to add an error code to a CCM and then add it to the outbox of a partner chain. The input parameters are the cross-chain message CCM and the error code errorCode.

error(CCM, errorCode):
    set CCM.status = errorCode
    set CCM.fee = 0
    swap CCM.sendingChainID and CCM.receivingChainID

    partnerChainID = getPartnerChainID(CCM.receivingChainID)
    addToOutbox(partnerChainID, CCM)

Interoperability Module Store

The storage keys and values of the interoperability store are set as follows:

  • Interoperability account
    • storagePrefix = STORE_PREFIX_ACCOUNT.
    • storageKey = uint32be(chainID).
    • storageValue = account(chainID) serialized using the interoperabilityAccount schema presented below.
  • Outbox root
    • storagePrefix = STORE_PREFIX_OUTBOX.
    • storageKey = uint32be(chainID).
    • storageValue = account(chainID).outbox.root serialized using the outboxRoot schema presented below.
  • Own chain account
    • storagePrefix = STORE_PREFIX_ACCOUNT.
    • storageKey = uint32be(0).
    • storageValue = own chain data (name and chain ID), serialized using the ownChain schema presented below.
  • Registered name
    • storagePrefix = STORE_PREFIX_NAME.
    • storageKey = name, serialized as a utf-8 encoded string, where name is the name of the registered chain.
    • storageValue = chainID, serialized using the chainID schema presented below.
  • Registered network ID
    • storagePrefix = STORE_PREFIX_NETWORK_ID.
    • storageKey = networkID, serialized as bytes, where networkID is the network ID of the registered chain.
    • storageValue = chainID, serialized using the chainID schema presented below.

Initialization of the Interoperability Account

The properties of an interoperability account are initialized as follows.

inbox

The underlying Merkle tree of the inbox is initialized as an empty tree, as defined in LIP 0031. In particular, the inbox is initialized as follows:

  • root: Initialized to the constant EMPTY_HASH.
  • appendPath: Initialized to an empty array.
  • size: Initialized to 0.

outbox

The underlying Merkle tree of the outbox is initialized as an empty tree, as defined in LIP 0031. In particular, the outbox is initialized as follows:

  • root: Initialized to the constant EMPTY_HASH.
  • appendPath: Initialized to an empty array.
  • size: Initialized to 0.

networkID

For the mainchain account on a sidechain, this property is initialized to MAINCHAIN_NETWORK_ID. For a sidechain account on mainchain, this property is set by the [sidechain registration transaction][registration-LIP.

lastCertifiedStateRoot

This property is initialized to the constant EMPTY_HASH.

lastCertifiedTimestamp

This property is initialized to 0.

lastCertifiedHeight

This property is initialized to 0.

partnerChainOutboxRoot

This property is initialized to the constant EMPTY_HASH.

partnerChainOutboxSize

This property is initialized to 0.

partnerChainInboxSize

This property is initialized to 0.

name

For the mainchain account on a sidechain, this property is initialized to the string MAINCHAIN_NAME. For a sidechain account on mainchain, this property is set by the sidechain registration transaction.

status

This property is initialized to CHAIN_REGISTERED, corresponding to the ``registered’’ status.

validators

For the mainchain account on a sidechain, this property is initialized by a mainchain registration transaction. For a sidechain account on the mainchain, this property is set by the sidechain registration transaction.

Initialization of the Outbox Root

The outbox root is initialized to the EMPTY_HASH constant.

Initialization of the Own Chain Account

On manchain, the own chain account is present by default, set to a data structure with properties:

  • name=MAINCHAIN_NAME.
  • ID=MAINCHAIN_ID.

On a sidechain, the own chain account is initialized as part of the mainchain registration transaction processing.

Initialization of the Auxiliary Data

The auxiliary data containing the names and network IDs of all chains in the ecosystem are present only on mainchain. They are updated by the sidechain registration transaction and they are initialized with one name and one network ID entry for the mainchain:

  • Mainchain registered name
    • storagePrefix = STORE_PREFIX_NAME.
    • storageKey: MAINCHAIN_NAME.
    • storageValue: MAINCHAIN_ID, serialized using the chainID schema presented below.
  • Registered network IDs auxiliary data
    • storagePrefix = STORE_PREFIX_NETWORK_ID.
    • storageKey: MAINCHAIN_NETWORK_ID.
    • storageValue: MAINCHAIN_ID, serialized using the chainID schema presented below.

JSON Schemas

interoperabilityAccount = {
    "type": "object",
    "properties": {
        "inbox": {
            "type": "object",
            "properties": {
                "appendPath" : {
                    "type": "array",
                    "items": {
                    	"dataType": "bytes"
                    },
                    "fieldNumber": 1
                },
                "size" : {
                    "dataType" : uint64,
                    "fieldNumber": 2
                },
                "root" : {
                    "dataType" : bytes,
                    "fieldNumber": 3
                }
            },
            "required": ["appendPath", "size", "root"],
            "fieldNumber": 1
        },
        "outbox": {
            "type": "object",
            "properties": {
                "appendPath" : {
                    "type": "array",
                    "items": {
                        "dataType": "bytes"
                    },
                    "fieldNumber": 1
                },
                "size" : {
                    "dataType" : uint64,
                    "fieldNumber": 2
                },
                "root" : {
                    "dataType" : bytes,
                    "fieldNumber": 3
                }
            },
            "required": ["appendPath", "size", "root"],
            "fieldNumber": 2
        },
        "networkID" : {
            "dataType" : bytes,
            "fieldNumber": 3
        },
        "lastCertifiedStateRoot" : {
            "dataType" : bytes,
            "fieldNumber": 4
        },
            "lastCertifiedTimestamp" : {
            "dataType" : uint32,
            "fieldNumber": 5
        },
        "lastCertifiedHeight" : {
            "dataType" : uint32,
            "fieldNumber": 6
        },
        "partnerChainOutboxRoot" : {
            "dataType" : bytes,
            "fieldNumber": 7
        },
        "partnerChainOutboxSize" : {
            "dataType" : uint64,
            "fieldNumber": 8
        },
        "partnerChainInboxSize" : {
            "dataType" : uint64,
            "fieldNumber": 9
        },
        "name" : {
            "dataType" : string,
            "fieldNumber": 10
        },
        "status" : {
            "dataType" : uint32,
            "fieldNumber": 11
        },
        "validators": {
            "type": "object",
            "properties": {
                "keys": {
                    "type": "array",
                    "items": {
                        "dataType": "bytes",
                    },
                    "fieldNumber": 1
                },
                "weights": {
                    "type": "array",
                    "items": {
                        "dataType": "uint64",
                    },
                    "fieldNumber": 2
                },
                "certificateThreshold": {
                    "dataType": "uint64",
                    "fieldNumber": 3
                },
                "required": ["keys", "weights", "certificateThreshold"],      
                "fieldNumber": 12
            }
        },
    },
    "required": [
        "inbox",
        "outbox",
        "networkID",
        "lastCertifiedStateRoot",
        "lastCertifiedTimestamp",
        "lastCertifiedHeight",
        "partnerChainOutboxRoot",
        "partnerChainOutboxSize",
        "partnerChainInboxSize",
        "name",
        "status",
        "validators"
    ]
}
outboxRoot = {
    "type": "object",
    "properties": {
        "root" : {
            "dataType" : bytes,
            "fieldNumber": 1
        }
    },
    "required": ["root"]
}
ownChain = {
    "type": "object",
    "properties": {
        "name" : {
            "dataType" : string,
            "fieldNumber": 1
        },
        "ID" : {
            "dataType" : uint32,
            "fieldNumber": 2
        }
    },
    "required": ["name", "ID"]
}
chainID = {
    "type": "object",
    "properties": {
        "ID" : {
            "dataType" : uint32,
            "fieldNumber": 1
        }
    },
    "required": ["ID"]
}

Backwards Compatibility

This proposal, together with LIP “Chain registration”, LIP “Cross-chain messages”, LIP “Introduce cross-chain update transactions”, and LIP “Sidechain recovery transactions”, is part of the interoperability module.
Chains adding this module will need to do so with a hard fork.

2 Likes