UNPKG

lisk-framework

Version:

Lisk blockchain application platform

176 lines 8.63 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RegisterSidechainCommand = void 0; const lisk_codec_1 = require("@liskhq/lisk-codec"); const base_interoperability_command_1 = require("../../base_interoperability_command"); const constants_1 = require("../../constants"); const schemas_1 = require("../../schemas"); const utils_1 = require("../../utils"); const state_machine_1 = require("../../../../state_machine"); const chain_account_1 = require("../../stores/chain_account"); const channel_data_1 = require("../../stores/channel_data"); const chain_validators_1 = require("../../stores/chain_validators"); const outbox_root_1 = require("../../stores/outbox_root"); const registered_names_1 = require("../../stores/registered_names"); const chain_account_updated_1 = require("../../events/chain_account_updated"); const own_chain_account_1 = require("../../stores/own_chain_account"); const ccm_send_success_1 = require("../../events/ccm_send_success"); const errors_1 = require("../../errors"); class RegisterSidechainCommand extends base_interoperability_command_1.BaseInteroperabilityCommand { constructor() { super(...arguments); this.schema = schemas_1.sidechainRegParams; } addDependencies(feeMethod, tokenMethod) { this._feeMethod = feeMethod; this._tokenMethod = tokenMethod; } async verify(context) { const { transaction, params: { sidechainValidators, sidechainCertificateThreshold, chainID, name }, } = context; if (!(0, utils_1.isValidName)(name)) { return { status: state_machine_1.VerifyStatus.FAIL, error: new errors_1.InvalidNameError(), }; } const nameSubstore = this.stores.get(registered_names_1.RegisteredNamesStore); const nameExists = await nameSubstore.has(context, Buffer.from(name, 'ascii')); if (nameExists) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('Name already registered.'), }; } const chainAccountSubstore = this.stores.get(chain_account_1.ChainAccountStore); const chainAccountExists = await chainAccountSubstore.has(context, chainID); if (chainAccountExists) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('Chain ID already registered.'), }; } if (chainID[0] !== context.chainID[0]) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('Chain ID does not match the mainchain network.'), }; } if (chainID.equals(context.chainID)) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('Chain ID cannot be the mainchain chain ID.'), }; } let totalBftWeight = BigInt(0); for (let i = 0; i < sidechainValidators.length; i += 1) { const currentValidator = sidechainValidators[i]; if (sidechainValidators[i + 1] && currentValidator.blsKey.compare(sidechainValidators[i + 1].blsKey) > -1) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('Validators blsKeys must be unique and lexicographically ordered'), }; } if (currentValidator.bftWeight <= BigInt(0)) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('Validator bft weight must be greater than 0'), }; } totalBftWeight += currentValidator.bftWeight; } if (totalBftWeight > constants_1.MAX_UINT64) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error(`Validator bft weight must not exceed ${constants_1.MAX_UINT64}`), }; } if (sidechainCertificateThreshold < totalBftWeight / BigInt(3) + BigInt(1)) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('Certificate threshold below minimum bft weight '), }; } if (sidechainCertificateThreshold > totalBftWeight) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('Certificate threshold above maximum bft weight'), }; } if (transaction.fee < constants_1.CHAIN_REGISTRATION_FEE) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('Insufficient transaction fee.'), }; } return { status: state_machine_1.VerifyStatus.OK, }; } async execute(context) { const { getMethodContext, params: { sidechainCertificateThreshold, sidechainValidators, chainID, name }, } = context; const methodContext = getMethodContext(); const chainSubstore = this.stores.get(chain_account_1.ChainAccountStore); const sidechainAccount = { name, lastCertificate: { height: 0, timestamp: 0, stateRoot: constants_1.EMPTY_HASH, validatorsHash: (0, utils_1.computeValidatorsHash)(sidechainValidators, sidechainCertificateThreshold), }, status: 0, }; await chainSubstore.set(context, chainID, sidechainAccount); const mainchainTokenID = (0, utils_1.getTokenIDLSK)(context.chainID); const channelSubstore = this.stores.get(channel_data_1.ChannelDataStore); await channelSubstore.set(context, chainID, { inbox: { root: constants_1.EMPTY_HASH, appendPath: [], size: 0 }, outbox: { root: constants_1.EMPTY_HASH, appendPath: [], size: 0 }, partnerChainOutboxRoot: constants_1.EMPTY_HASH, messageFeeTokenID: mainchainTokenID, minReturnFeePerByte: constants_1.MIN_RETURN_FEE_PER_BYTE_BEDDOWS, }); const chainValidatorsSubstore = this.stores.get(chain_validators_1.ChainValidatorsStore); await chainValidatorsSubstore.set(context, chainID, { activeValidators: sidechainValidators, certificateThreshold: sidechainCertificateThreshold, }); const outboxRootSubstore = this.stores.get(outbox_root_1.OutboxRootStore); await outboxRootSubstore.set(context, chainID, { root: constants_1.EMPTY_HASH }); const registeredNamesSubstore = this.stores.get(registered_names_1.RegisteredNamesStore); await registeredNamesSubstore.set(context, Buffer.from(name, 'ascii'), { chainID }); this._feeMethod.payFee(context.getMethodContext(), constants_1.CHAIN_REGISTRATION_FEE); await this._tokenMethod.initializeEscrowAccount(context.getMethodContext(), chainID, mainchainTokenID); this.events.get(chain_account_updated_1.ChainAccountUpdatedEvent).log(methodContext, chainID, sidechainAccount); const encodedParams = lisk_codec_1.codec.encode(schemas_1.registrationCCMParamsSchema, { name, chainID, messageFeeTokenID: mainchainTokenID, minReturnFeePerByte: constants_1.MIN_RETURN_FEE_PER_BYTE_BEDDOWS, }); const ownChainAccountSubstore = this.stores.get(own_chain_account_1.OwnChainAccountStore); const ownChainAccount = await ownChainAccountSubstore.get(methodContext, constants_1.EMPTY_BYTES); const ccm = { nonce: ownChainAccount.nonce, module: constants_1.MODULE_NAME_INTEROPERABILITY, crossChainCommand: constants_1.CROSS_CHAIN_COMMAND_REGISTRATION, sendingChainID: ownChainAccount.chainID, receivingChainID: chainID, fee: BigInt(0), status: 0, params: encodedParams, }; await this.internalMethod.addToOutbox(context, chainID, ccm); ownChainAccount.nonce += BigInt(1); await ownChainAccountSubstore.set(context, constants_1.EMPTY_BYTES, ownChainAccount); const { ccmID } = (0, utils_1.getEncodedCCMAndID)(ccm); this.events .get(ccm_send_success_1.CcmSendSuccessEvent) .log(methodContext, ownChainAccount.chainID, chainID, ccmID, { ccm, }); } } exports.RegisterSidechainCommand = RegisterSidechainCommand; //# sourceMappingURL=register_sidechain.js.map