lisk-framework
Version: 
Lisk blockchain application platform
168 lines • 8.41 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculateNewActiveValidators = exports.emptyActiveValidatorsUpdate = exports.getDecodedCCMAndID = exports.getEncodedCCMAndID = exports.getIDFromCCMBytes = exports.getTokenIDLSK = exports.getMainchainID = exports.verifyLivenessConditionForRegisteredChains = exports.chainAccountToJSON = exports.checkCertificateTimestamp = exports.checkLivenessRequirement = exports.isOutboxRootWitnessEmpty = exports.isInboxUpdateEmpty = exports.swapReceivingAndSendingChainIDs = exports.sortValidatorsByBLSKey = exports.computeValidatorsHash = exports.isValidName = exports.validNameChars = exports.handlePromiseErrorWithNull = exports.getEncodedSidechainTerminatedCCMParam = exports.getCCMSize = exports.validateFormat = void 0;
const lisk_codec_1 = require("@liskhq/lisk-codec");
const lisk_cryptography_1 = require("@liskhq/lisk-cryptography");
const lisk_validator_1 = require("@liskhq/lisk-validator");
const lisk_chain_1 = require("@liskhq/lisk-chain");
const constants_1 = require("./constants");
const schemas_1 = require("./schemas");
const state_machine_1 = require("../../state_machine");
const schema_1 = require("../../engine/consensus/certificate_generation/schema");
const certificates_1 = require("./certificates");
const validateFormat = (ccm) => {
    lisk_validator_1.validator.validate(schemas_1.ccmSchema, ccm);
    const serializedCCM = lisk_codec_1.codec.encode(schemas_1.ccmSchema, ccm);
    for (const field of ['module', 'crossChainCommand']) {
        if (!new RegExp(lisk_chain_1.NAME_REGEX).test(ccm[field])) {
            throw new Error(`Cross-chain message ${field} name must be alphanumeric.`);
        }
    }
    if (serializedCCM.byteLength > constants_1.MAX_CCM_SIZE) {
        throw new Error(`Cross-chain message size is larger than ${constants_1.MAX_CCM_SIZE}.`);
    }
};
exports.validateFormat = validateFormat;
const getCCMSize = (ccm) => {
    const serializedCCM = lisk_codec_1.codec.encode(schemas_1.ccmSchema, ccm);
    return BigInt(serializedCCM.byteLength);
};
exports.getCCMSize = getCCMSize;
const getEncodedSidechainTerminatedCCMParam = (ccm, receivingChainAccount) => {
    const params = {
        chainID: ccm.receivingChainID,
        stateRoot: receivingChainAccount.lastCertificate.stateRoot,
    };
    const encodedParams = lisk_codec_1.codec.encode(schemas_1.sidechainTerminatedCCMParamsSchema, params);
    return encodedParams;
};
exports.getEncodedSidechainTerminatedCCMParam = getEncodedSidechainTerminatedCCMParam;
const handlePromiseErrorWithNull = async (promise) => {
    let result;
    try {
        result = await promise;
    }
    catch {
        result = null;
    }
    return result;
};
exports.handlePromiseErrorWithNull = handlePromiseErrorWithNull;
exports.validNameChars = 'a-z0-9!@$&_.';
const isValidName = (username) => new RegExp(`^[${exports.validNameChars}]+$`, 'g').test(username);
exports.isValidName = isValidName;
const computeValidatorsHash = (initValidators, certificateThreshold) => {
    const input = {
        activeValidators: initValidators,
        certificateThreshold,
    };
    const encodedValidatorsHashInput = lisk_codec_1.codec.encode(schemas_1.validatorsHashInputSchema, input);
    return lisk_cryptography_1.utils.hash(encodedValidatorsHashInput);
};
exports.computeValidatorsHash = computeValidatorsHash;
const sortValidatorsByBLSKey = (validators) => validators.sort((a, b) => a.blsKey.compare(b.blsKey));
exports.sortValidatorsByBLSKey = sortValidatorsByBLSKey;
const swapReceivingAndSendingChainIDs = (ccm) => ({
    ...ccm,
    receivingChainID: ccm.sendingChainID,
    sendingChainID: ccm.receivingChainID,
});
exports.swapReceivingAndSendingChainIDs = swapReceivingAndSendingChainIDs;
const isInboxUpdateEmpty = (inboxUpdate) => inboxUpdate.crossChainMessages.length === 0 &&
    inboxUpdate.messageWitnessHashes.length === 0 &&
    inboxUpdate.outboxRootWitness.siblingHashes.length === 0 &&
    inboxUpdate.outboxRootWitness.bitmap.length === 0;
exports.isInboxUpdateEmpty = isInboxUpdateEmpty;
const isOutboxRootWitnessEmpty = (outboxRootWitness) => outboxRootWitness.siblingHashes.length === 0 || outboxRootWitness.bitmap.length === 0;
exports.isOutboxRootWitnessEmpty = isOutboxRootWitnessEmpty;
const checkLivenessRequirement = (partnerChainAccount, txParams) => {
    if (partnerChainAccount.status === 0 &&
        txParams.certificate.equals(constants_1.EMPTY_BYTES)) {
        return {
            status: state_machine_1.VerifyStatus.FAIL,
            error: new Error(`Sending partner chain ${txParams.sendingChainID.readInt32BE(0)} has a registered status so certificate cannot be empty.`),
        };
    }
    return {
        status: state_machine_1.VerifyStatus.OK,
    };
};
exports.checkLivenessRequirement = checkLivenessRequirement;
const checkCertificateTimestamp = (txParams, certificate, header) => {
    if (txParams.certificate.equals(constants_1.EMPTY_BYTES)) {
        return;
    }
    if (certificate.timestamp >= header.timestamp) {
        throw Error('Certificate is invalid due to invalid timestamp.');
    }
};
exports.checkCertificateTimestamp = checkCertificateTimestamp;
const chainAccountToJSON = (chainAccount) => {
    const { lastCertificate, name, status } = chainAccount;
    return {
        lastCertificate: (0, certificates_1.certificateToJSON)(lastCertificate),
        name,
        status,
    };
};
exports.chainAccountToJSON = chainAccountToJSON;
const verifyLivenessConditionForRegisteredChains = (blockTimestamp, certificateBytes) => {
    const certificate = lisk_codec_1.codec.decode(schema_1.certificateSchema, certificateBytes);
    lisk_validator_1.validator.validate(schema_1.certificateSchema, certificate);
    const limitSecond = constants_1.LIVENESS_LIMIT / 2;
    if (blockTimestamp - certificate.timestamp > limitSecond) {
        throw new Error(`The first CCU with a non-empty inbox update cannot contain a certificate older than ${limitSecond} seconds.`);
    }
};
exports.verifyLivenessConditionForRegisteredChains = verifyLivenessConditionForRegisteredChains;
const getMainchainID = (chainID) => {
    const networkID = chainID.slice(0, 1);
    return Buffer.concat([networkID, Buffer.alloc(constants_1.CHAIN_ID_LENGTH - 1, 0)]);
};
exports.getMainchainID = getMainchainID;
const getTokenIDLSK = (chainID) => {
    const networkID = chainID.slice(0, 1);
    return Buffer.concat([networkID, Buffer.alloc(7, 0)]);
};
exports.getTokenIDLSK = getTokenIDLSK;
const getIDFromCCMBytes = (ccmBytes) => lisk_cryptography_1.utils.hash(ccmBytes);
exports.getIDFromCCMBytes = getIDFromCCMBytes;
const getEncodedCCMAndID = (ccm) => {
    const encodedCCM = lisk_codec_1.codec.encode(schemas_1.ccmSchema, ccm);
    return { encodedCCM, ccmID: (0, exports.getIDFromCCMBytes)(encodedCCM) };
};
exports.getEncodedCCMAndID = getEncodedCCMAndID;
const getDecodedCCMAndID = (ccmBytes) => {
    const decodedCCM = lisk_codec_1.codec.decode(schemas_1.ccmSchema, ccmBytes);
    return {
        decodedCCM,
        ccmID: (0, exports.getIDFromCCMBytes)(ccmBytes),
    };
};
exports.getDecodedCCMAndID = getDecodedCCMAndID;
const emptyActiveValidatorsUpdate = (value) => value.blsKeysUpdate.length === 0 &&
    value.bftWeightsUpdate.length === 0 &&
    value.bftWeightsUpdateBitmap.length === 0;
exports.emptyActiveValidatorsUpdate = emptyActiveValidatorsUpdate;
const calculateNewActiveValidators = (activeValidators, blskeysUpdate, bftWeightsUpdate, bftWeightsUpdateBitmap) => {
    const newValidators = blskeysUpdate.map(blsKey => ({
        blsKey,
        bftWeight: BigInt(0),
    }));
    const newActiveValidators = [...activeValidators, ...newValidators];
    newActiveValidators.sort((a, b) => a.blsKey.compare(b.blsKey));
    const intBitmap = BigInt(`0x${bftWeightsUpdateBitmap.toString('hex')}`);
    let weightUsed = 0;
    for (let i = 0; i < newActiveValidators.length; i += 1) {
        if (((intBitmap >> BigInt(i)) & BigInt(1)) === BigInt(1)) {
            newActiveValidators[i].bftWeight = bftWeightsUpdate[weightUsed];
            weightUsed += 1;
        }
    }
    if (weightUsed !== bftWeightsUpdate.length) {
        throw new Error('No BFT weights should be left.');
    }
    return newActiveValidators.filter(v => v.bftWeight > BigInt(0));
};
exports.calculateNewActiveValidators = calculateNewActiveValidators;
//# sourceMappingURL=utils.js.map