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
;