lisk-framework
Version:
Lisk blockchain application platform
209 lines • 11.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SidechainInteroperabilityModule = void 0;
const lisk_codec_1 = require("@liskhq/lisk-codec");
const lisk_validator_1 = require("@liskhq/lisk-validator");
const base_interoperability_module_1 = require("../base_interoperability_module");
const method_1 = require("./method");
const cc_method_1 = require("./cc_method");
const register_mainchain_1 = require("./commands/register_mainchain");
const endpoint_1 = require("./endpoint");
const schemas_1 = require("../schemas");
const chain_account_1 = require("../stores/chain_account");
const channel_data_1 = require("../stores/channel_data");
const own_chain_account_1 = require("../stores/own_chain_account");
const terminated_state_1 = require("../stores/terminated_state");
const terminated_outbox_1 = require("../stores/terminated_outbox");
const internal_method_1 = require("./internal_method");
const commands_1 = require("./commands");
const initialize_state_recovery_1 = require("./commands/initialize_state_recovery");
const recover_state_1 = require("./commands/recover_state");
const cc_commands_1 = require("./cc_commands");
const constants_1 = require("../constants");
const utils_1 = require("../utils");
const errors_1 = require("../errors");
class SidechainInteroperabilityModule extends base_interoperability_module_1.BaseInteroperabilityModule {
constructor() {
super(...arguments);
this.crossChainMethod = new cc_method_1.SidechainCCMethod(this.stores, this.events);
this.internalMethod = new internal_method_1.SidechainInteroperabilityInternalMethod(this.stores, this.events, this.interoperableCCMethods);
this.method = new method_1.SidechainInteroperabilityMethod(this.stores, this.events, this.interoperableCCMethods, this.internalMethod);
this.endpoint = new endpoint_1.SidechainInteroperabilityEndpoint(this.stores, this.offchainStores);
this._mainchainRegistrationCommand = new register_mainchain_1.RegisterMainchainCommand(this.stores, this.events, this.interoperableCCMethods, this.interoperableCCCommands, this.internalMethod);
this._crossChainUpdateCommand = new commands_1.SubmitSidechainCrossChainUpdateCommand(this.stores, this.events, this.interoperableCCMethods, this.interoperableCCCommands, this.internalMethod);
this._stateRecoveryInitCommand = new initialize_state_recovery_1.InitializeStateRecoveryCommand(this.stores, this.events, this.interoperableCCMethods, this.interoperableCCCommands, this.internalMethod);
this._stateRecoveryCommand = new recover_state_1.RecoverStateCommand(this.stores, this.events, this.interoperableCCMethods, this.interoperableCCCommands, this.internalMethod);
this.commands = [
this._mainchainRegistrationCommand,
this._crossChainUpdateCommand,
this._stateRecoveryInitCommand,
this._stateRecoveryCommand,
];
this.crossChainCommand = [
new cc_commands_1.SidechainCCRegistrationCommand(this.stores, this.events, this.interoperableCCMethods, this.internalMethod),
new cc_commands_1.SidechainCCChannelTerminatedCommand(this.stores, this.events, this.interoperableCCMethods, this.internalMethod),
];
}
addDependencies(validatorsMethod, tokenMethod) {
this._validatorsMethod = validatorsMethod;
this._crossChainUpdateCommand.init(this.method, tokenMethod);
this.internalMethod.addDependencies(tokenMethod);
this.tokenMethod = tokenMethod;
}
metadata() {
return {
...this.baseMetadata(),
endpoints: [
{
name: this.endpoint.getChainAccount.name,
request: schemas_1.getChainAccountRequestSchema,
response: chain_account_1.chainDataSchema,
},
{
name: this.endpoint.getAllChainAccounts.name,
request: schemas_1.getChainAccountRequestSchema,
response: chain_account_1.allChainAccountsSchema,
},
{
name: this.endpoint.getChannel.name,
request: schemas_1.getChannelRequestSchema,
response: channel_data_1.channelSchema,
},
{
name: this.endpoint.getOwnChainAccount.name,
response: own_chain_account_1.ownChainAccountSchema,
},
{
name: this.endpoint.getTerminatedStateAccount.name,
request: schemas_1.getTerminatedStateAccountRequestSchema,
response: terminated_state_1.terminatedStateSchema,
},
{
name: this.endpoint.getTerminatedOutboxAccount.name,
request: schemas_1.getTerminatedOutboxAccountRequestSchema,
response: terminated_outbox_1.terminatedOutboxSchema,
},
{
name: this.endpoint.getChainValidators.name,
request: schemas_1.getChainValidatorsRequestSchema,
response: schemas_1.getChainValidatorsResponseSchema,
},
{
name: this.endpoint.getMainchainID.name,
request: schemas_1.getMainchainIDRequestSchema,
response: schemas_1.getMainchainIDResponseSchema,
},
{
name: this.endpoint.getCCMSchema.name,
response: schemas_1.getCCMSchemaResponseSchema,
},
],
assets: [
{
version: 0,
data: schemas_1.genesisInteroperabilitySchema,
},
],
stores: this.stores.values().map(v => ({
key: v.key.toString('hex'),
data: v.schema,
})),
};
}
async init(_args) {
this._mainchainRegistrationCommand.addDependencies(this._validatorsMethod);
}
async initGenesisState(ctx) {
const genesisBlockAssetBytes = ctx.assets.getAsset(constants_1.MODULE_NAME_INTEROPERABILITY);
if (!genesisBlockAssetBytes) {
return;
}
const genesisInteroperability = lisk_codec_1.codec.decode(schemas_1.genesisInteroperabilitySchema, genesisBlockAssetBytes);
lisk_validator_1.validator.validate(schemas_1.genesisInteroperabilitySchema, genesisInteroperability);
this._verifyChainInfos(ctx, genesisInteroperability);
const { terminatedStateAccounts, terminatedOutboxAccounts } = genesisInteroperability;
this._verifyTerminatedStateAccounts(ctx, terminatedStateAccounts, (0, utils_1.getMainchainID)(ctx.chainID));
if (terminatedOutboxAccounts.length !== 0) {
throw new Error('terminatedOutboxAccounts must be empty.');
}
await super.processGenesisState(ctx, genesisInteroperability);
}
_verifyChainInfos(ctx, genesisInteroperability) {
const { ownChainName, ownChainNonce, chainInfos, terminatedStateAccounts } = genesisInteroperability;
if (chainInfos.length === 0) {
const ifChainInfosIsEmpty = 'if chainInfos is empty.';
if (ownChainName !== '') {
throw new Error(`ownChainName must be empty string, ${ifChainInfosIsEmpty}.`);
}
if (ownChainNonce !== BigInt(0)) {
throw new Error(`ownChainNonce must be 0, ${ifChainInfosIsEmpty}.`);
}
if (terminatedStateAccounts.length !== 0) {
throw new Error(`terminatedStateAccounts must be empty, ${ifChainInfosIsEmpty}.`);
}
}
else {
if (ownChainName.length < constants_1.MIN_CHAIN_NAME_LENGTH ||
ownChainName.length > constants_1.MAX_CHAIN_NAME_LENGTH) {
throw new Error(`ownChainName.length must be between ${constants_1.MIN_CHAIN_NAME_LENGTH} and ${constants_1.MAX_CHAIN_NAME_LENGTH}`);
}
if (!(0, utils_1.isValidName)(ownChainName)) {
throw new errors_1.InvalidNameError('ownChainName');
}
if (ownChainName === constants_1.CHAIN_NAME_MAINCHAIN) {
throw new Error(`ownChainName must be not equal to ${constants_1.CHAIN_NAME_MAINCHAIN}.`);
}
if (ownChainNonce <= 0) {
throw new Error('ownChainNonce must be > 0.');
}
if (chainInfos.length !== 1) {
throw new Error('chainInfos must contain exactly one entry.');
}
const mainchainInfo = chainInfos[0];
const mainchainID = (0, utils_1.getMainchainID)(ctx.chainID);
if (!mainchainInfo.chainID.equals(mainchainID)) {
throw new Error(`mainchainInfo.chainID must be equal to ${mainchainID.toString('hex')}.`);
}
if (mainchainInfo.chainData.name !== constants_1.CHAIN_NAME_MAINCHAIN) {
throw new Error(`chainData.name must be equal to ${constants_1.CHAIN_NAME_MAINCHAIN}.`);
}
const validStatuses = [0, 1];
if (!validStatuses.includes(mainchainInfo.chainData.status)) {
throw new Error(`chainData.status must be one of ${validStatuses.join(', ')}.`);
}
if (mainchainInfo.chainData.lastCertificate.timestamp >= ctx.header.timestamp) {
throw new Error('chainData.lastCertificate.timestamp must be < header.timestamp.');
}
this._verifyChannelData(ctx, mainchainInfo);
this._verifyChainValidators(mainchainInfo);
}
}
_verifyTerminatedStateAccounts(ctx, terminatedStateAccounts, mainchainID) {
this._verifyTerminatedStateAccountsIDs(terminatedStateAccounts.map(a => a.chainID));
for (const stateAccount of terminatedStateAccounts) {
this._verifyChainID(stateAccount.chainID, mainchainID, 'stateAccount.');
if (stateAccount.chainID.equals(ctx.chainID)) {
throw new Error(`stateAccount.chainID must not be equal to OWN_CHAIN_ID.`);
}
const { terminatedStateAccount } = stateAccount;
if (terminatedStateAccount.initialized) {
if (terminatedStateAccount.stateRoot.equals(constants_1.EMPTY_HASH)) {
throw new Error(`stateAccount.stateRoot mst be not equal to "${constants_1.EMPTY_HASH.toString('hex')}", if initialized is true.`);
}
if (!terminatedStateAccount.mainchainStateRoot.equals(constants_1.EMPTY_HASH)) {
throw new Error(`terminatedStateAccount.mainchainStateRoot must be equal to "${constants_1.EMPTY_HASH.toString('hex')}", if initialized is true`);
}
}
else {
if (!terminatedStateAccount.stateRoot.equals(constants_1.EMPTY_HASH)) {
throw new Error(`stateAccount.stateRoot mst be equal to "${constants_1.EMPTY_HASH.toString('hex')}", if initialized is false.`);
}
if (terminatedStateAccount.mainchainStateRoot.equals(constants_1.EMPTY_HASH)) {
throw new Error(`terminatedStateAccount.mainchainStateRoot must be not equal to "${constants_1.EMPTY_HASH.toString('hex')}", if initialized is false.`);
}
}
}
}
}
exports.SidechainInteroperabilityModule = SidechainInteroperabilityModule;
//# sourceMappingURL=module.js.map