UNPKG

lisk-framework

Version:

Lisk blockchain application platform

176 lines 8.75 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RegisterMainchainCommand = void 0; const lisk_codec_1 = require("@liskhq/lisk-codec"); const lisk_cryptography_1 = require("@liskhq/lisk-cryptography"); const constants_1 = require("../../constants"); const schemas_1 = require("../../schemas"); const state_machine_1 = require("../../../../state_machine"); const utils_1 = require("../../utils"); const base_interoperability_command_1 = require("../../base_interoperability_command"); 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 own_chain_account_1 = require("../../stores/own_chain_account"); const chain_account_updated_1 = require("../../events/chain_account_updated"); const invalid_registration_signature_1 = require("../../events/invalid_registration_signature"); const ccm_send_success_1 = require("../../events/ccm_send_success"); const errors_1 = require("../../errors"); class RegisterMainchainCommand extends base_interoperability_command_1.BaseInteroperabilityCommand { constructor() { super(...arguments); this.schema = schemas_1.mainchainRegParams; } addDependencies(validatorsMethod) { this._validatorsMethod = validatorsMethod; } async verify(context) { const { ownName, mainchainValidators, mainchainCertificateThreshold, ownChainID } = context.params; const mainchainID = (0, utils_1.getMainchainID)(context.chainID); const chainAccountSubstore = this.stores.get(chain_account_1.ChainAccountStore); const mainchainAccountExists = await chainAccountSubstore.has(context, mainchainID); if (mainchainAccountExists) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('Mainchain has already been registered.'), }; } if (!ownChainID.equals(context.chainID)) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error(`Invalid ownChainID property.`), }; } if (!(0, utils_1.isValidName)(ownName)) { return { status: state_machine_1.VerifyStatus.FAIL, error: new errors_1.InvalidNameError('ownName'), }; } let totalWeight = BigInt(0); for (let i = 0; i < mainchainValidators.length; i += 1) { const currentValidator = mainchainValidators[i]; if (mainchainValidators[i + 1] && currentValidator.blsKey.compare(mainchainValidators[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 positive integer.'), }; } totalWeight += currentValidator.bftWeight; if (totalWeight > constants_1.MAX_UINT64) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('Total BFT weight exceeds maximum value.'), }; } } if (mainchainCertificateThreshold < totalWeight / BigInt(3) + BigInt(1)) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('Certificate threshold is too small.'), }; } if (mainchainCertificateThreshold > totalWeight) { return { status: state_machine_1.VerifyStatus.FAIL, error: new Error('Certificate threshold is too large.'), }; } return { status: state_machine_1.VerifyStatus.OK, }; } async execute(context) { const { getMethodContext, params: { ownChainID, ownName, mainchainValidators, mainchainCertificateThreshold, aggregationBits, signature, }, } = context; const methodContext = getMethodContext(); const { validators, certificateThreshold } = await this._validatorsMethod.getValidatorsParams(getMethodContext()); const activeValidators = validators.filter(v => v.bftWeight > BigInt(0)); const keyList = []; const weights = []; (0, utils_1.sortValidatorsByBLSKey)(activeValidators); for (const v of activeValidators) { keyList.push(v.blsKey); weights.push(v.bftWeight); } const message = lisk_codec_1.codec.encode(schemas_1.registrationSignatureMessageSchema, { ownName, ownChainID, mainchainValidators, mainchainCertificateThreshold, }); if (!lisk_cryptography_1.bls.verifyWeightedAggSig(keyList, aggregationBits, signature, constants_1.MESSAGE_TAG_CHAIN_REG, ownChainID, message, weights, certificateThreshold)) { this.events.get(invalid_registration_signature_1.InvalidRegistrationSignatureEvent).error(context, ownChainID); throw new Error('Invalid signature property.'); } const mainchainTokenID = (0, utils_1.getTokenIDLSK)(context.chainID); const chainSubstore = this.stores.get(chain_account_1.ChainAccountStore); const mainchainAccount = { name: constants_1.CHAIN_NAME_MAINCHAIN, lastCertificate: { height: 0, timestamp: 0, stateRoot: constants_1.EMPTY_HASH, validatorsHash: (0, utils_1.computeValidatorsHash)(mainchainValidators, mainchainCertificateThreshold), }, status: 0, }; const mainchainID = (0, utils_1.getMainchainID)(context.chainID); await chainSubstore.set(context, mainchainID, mainchainAccount); const channelSubstore = this.stores.get(channel_data_1.ChannelDataStore); await channelSubstore.set(context, mainchainID, { 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, mainchainID, { activeValidators: mainchainValidators, certificateThreshold: mainchainCertificateThreshold, }); const outboxRootSubstore = this.stores.get(outbox_root_1.OutboxRootStore); await outboxRootSubstore.set(context, mainchainID, { root: constants_1.EMPTY_HASH }); this.events.get(chain_account_updated_1.ChainAccountUpdatedEvent).log(methodContext, mainchainID, mainchainAccount); const encodedParams = lisk_codec_1.codec.encode(schemas_1.registrationCCMParamsSchema, { name: constants_1.CHAIN_NAME_MAINCHAIN, chainID: mainchainID, messageFeeTokenID: mainchainTokenID, minReturnFeePerByte: constants_1.MIN_RETURN_FEE_PER_BYTE_BEDDOWS, }); const ownChainAccount = { name: ownName, chainID: ownChainID, nonce: BigInt(0), }; const ccm = { nonce: ownChainAccount.nonce, module: constants_1.MODULE_NAME_INTEROPERABILITY, crossChainCommand: constants_1.CROSS_CHAIN_COMMAND_REGISTRATION, sendingChainID: ownChainAccount.chainID, receivingChainID: mainchainID, fee: BigInt(0), status: 0, params: encodedParams, }; await this.internalMethod.addToOutbox(context, mainchainID, ccm); ownChainAccount.nonce += BigInt(1); await this.stores.get(own_chain_account_1.OwnChainAccountStore).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, mainchainID, ccmID, { ccm, }); } } exports.RegisterMainchainCommand = RegisterMainchainCommand; //# sourceMappingURL=register_mainchain.js.map