lisk-framework
Version:
Lisk blockchain application platform
236 lines • 12.4 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.ValidatorsMethod = void 0;
const lisk_cryptography_1 = require("@liskhq/lisk-cryptography");
const lisk_validator_1 = require("@liskhq/lisk-validator");
const base_method_1 = require("../base_method");
const constants_1 = require("./constants");
const generator_key_registration_1 = require("./events/generator_key_registration");
const validator_keys_1 = require("./stores/validator_keys");
const bls_keys_1 = require("./stores/bls_keys");
const bls_key_registration_1 = require("./events/bls_key_registration");
const validators_params_1 = require("./stores/validators_params");
class ValidatorsMethod extends base_method_1.BaseMethod {
init(args) {
this._blockTime = args.config.blockTime;
}
async registerValidatorKeys(methodContext, validatorAddress, blsKey, generatorKey, proofOfPossession) {
this._validateLengths({ validatorAddress, blsKey, proofOfPossession });
const validatorAccount = {
generatorKey,
blsKey,
};
lisk_validator_1.validator.validate(validator_keys_1.validatorKeysSchema, validatorAccount);
const validatorsSubStore = this.stores.get(validator_keys_1.ValidatorKeysStore);
const addressExists = await validatorsSubStore.has(methodContext, validatorAddress);
if (addressExists) {
this.events.get(generator_key_registration_1.GeneratorKeyRegistrationEvent).log(methodContext, validatorAddress, {
generatorKey,
result: 2,
});
throw new Error('This address is already registered as validator.');
}
const blsKeysSubStore = this.stores.get(bls_keys_1.BLSKeyStore);
const blsKeyExists = await blsKeysSubStore.has(methodContext, blsKey);
if (blsKeyExists) {
this.events.get(bls_key_registration_1.BlsKeyRegistrationEvent).log(methodContext, validatorAddress, {
blsKey,
proofOfPossession,
result: 3,
});
throw new Error(`The BLS key ${blsKey.toString('hex')} has already been registered in the chain.`);
}
if (!lisk_cryptography_1.bls.popVerify(blsKey, proofOfPossession)) {
this.events.get(bls_key_registration_1.BlsKeyRegistrationEvent).log(methodContext, validatorAddress, {
blsKey,
proofOfPossession,
result: 4,
});
throw new Error('Invalid proof of possession for the given BLS key.');
}
await validatorsSubStore.set(methodContext, validatorAddress, validatorAccount);
await blsKeysSubStore.set(methodContext, blsKey, { address: validatorAddress });
this.events
.get(generator_key_registration_1.GeneratorKeyRegistrationEvent)
.log(methodContext, validatorAddress, { generatorKey, result: 0 });
this.events.get(bls_key_registration_1.BlsKeyRegistrationEvent).log(methodContext, validatorAddress, {
blsKey,
proofOfPossession,
result: 0,
});
}
async registerValidatorWithoutBLSKey(methodContext, validatorAddress, generatorKey) {
this._validateLengths({ validatorAddress });
const validatorAccount = {
generatorKey,
blsKey: constants_1.INVALID_BLS_KEY,
};
lisk_validator_1.validator.validate(validator_keys_1.validatorKeysSchema, validatorAccount);
const validatorsSubStore = this.stores.get(validator_keys_1.ValidatorKeysStore);
const addressExists = await validatorsSubStore.has(methodContext, validatorAddress);
if (addressExists) {
this.events.get(generator_key_registration_1.GeneratorKeyRegistrationEvent).log(methodContext, validatorAddress, {
generatorKey,
result: 2,
});
throw new Error('This address is already registered as validator.');
}
await validatorsSubStore.set(methodContext, validatorAddress, validatorAccount);
this.events
.get(generator_key_registration_1.GeneratorKeyRegistrationEvent)
.log(methodContext, validatorAddress, { generatorKey, result: 0 });
return true;
}
async getAddressFromBLSKey(methodContext, blsKey) {
this._validateLengths({ blsKey });
const blsKeysSubStore = this.stores.get(bls_keys_1.BLSKeyStore);
const blsKeyExists = await blsKeysSubStore.has(methodContext, blsKey);
if (!blsKeyExists) {
throw new Error(`The BLS key ${blsKey.toString('hex')} has not been registered in the chain.`);
}
return blsKeysSubStore.get(methodContext, blsKey);
}
async getValidatorKeys(methodContext, address) {
this._validateLengths({ validatorAddress: address });
const validatorsSubStore = this.stores.get(validator_keys_1.ValidatorKeysStore);
const addressExists = await validatorsSubStore.has(methodContext, address);
if (!addressExists) {
throw new Error('No validator account found for the input address.');
}
return validatorsSubStore.get(methodContext, address);
}
async setValidatorBLSKey(methodContext, validatorAddress, blsKey, proofOfPossession) {
this._validateLengths({ validatorAddress, blsKey, proofOfPossession });
const validatorsSubStore = this.stores.get(validator_keys_1.ValidatorKeysStore);
const addressExists = await validatorsSubStore.has(methodContext, validatorAddress);
if (!addressExists) {
this.events.get(bls_key_registration_1.BlsKeyRegistrationEvent).log(methodContext, validatorAddress, {
blsKey,
proofOfPossession,
result: 1,
});
throw new Error('This address is not registered as validator. Only validators can register a BLS key.');
}
const blsKeysSubStore = this.stores.get(bls_keys_1.BLSKeyStore);
const blsKeyExists = await blsKeysSubStore.has(methodContext, blsKey);
if (blsKeyExists) {
this.events.get(bls_key_registration_1.BlsKeyRegistrationEvent).log(methodContext, validatorAddress, {
blsKey,
proofOfPossession,
result: 3,
});
throw new Error(`The BLS key ${blsKey.toString('hex')} has already been registered in the chain.`);
}
const validatorAccount = await validatorsSubStore.get(methodContext, validatorAddress);
if (!lisk_cryptography_1.bls.popVerify(blsKey, proofOfPossession)) {
this.events.get(bls_key_registration_1.BlsKeyRegistrationEvent).log(methodContext, validatorAddress, {
blsKey,
proofOfPossession,
result: 4,
});
throw new Error('Invalid proof of possession for the given BLS key.');
}
validatorAccount.blsKey = blsKey;
await validatorsSubStore.set(methodContext, validatorAddress, validatorAccount);
await blsKeysSubStore.set(methodContext, blsKey, { address: validatorAddress });
this.events.get(bls_key_registration_1.BlsKeyRegistrationEvent).log(methodContext, validatorAddress, {
blsKey,
proofOfPossession,
result: 0,
});
return true;
}
async setValidatorGeneratorKey(methodContext, validatorAddress, generatorKey) {
this._validateLengths({ validatorAddress, generatorKey });
const validatorsSubStore = this.stores.get(validator_keys_1.ValidatorKeysStore);
const addressExists = await validatorsSubStore.has(methodContext, validatorAddress);
if (!addressExists) {
this.events
.get(generator_key_registration_1.GeneratorKeyRegistrationEvent)
.log(methodContext, validatorAddress, { generatorKey, result: 1 });
throw new Error('This address is not registered as validator. Only validators can register a generator key.');
}
const validatorAccount = await validatorsSubStore.get(methodContext, validatorAddress);
validatorAccount.generatorKey = generatorKey;
await validatorsSubStore.set(methodContext, validatorAddress, validatorAccount);
this.events
.get(generator_key_registration_1.GeneratorKeyRegistrationEvent)
.log(methodContext, validatorAddress, { generatorKey, result: 0 });
return true;
}
async isKeyRegistered(methodContext, blsKey) {
const blsKeysSubStore = this.stores.get(bls_keys_1.BLSKeyStore);
return blsKeysSubStore.has(methodContext, blsKey);
}
async getGeneratorsBetweenTimestamps(methodContext, startTimestamp, endTimestamp) {
if (endTimestamp < startTimestamp) {
throw new Error('End timestamp must be greater than or equal to start timestamp.');
}
const result = {};
const startSlotNumber = Math.floor(startTimestamp / this._blockTime) + 1;
const endSlotNumber = Math.floor(endTimestamp / this._blockTime) - 1;
if (startSlotNumber > endSlotNumber) {
return {};
}
let totalSlots = endSlotNumber - startSlotNumber + 1;
const { validators } = await this.stores
.get(validators_params_1.ValidatorsParamsStore)
.get(methodContext, constants_1.EMPTY_KEY);
const generatorAddresses = validators.map(validator => validator.address.toString('binary'));
const baseSlots = Math.floor(totalSlots / generatorAddresses.length);
if (baseSlots > 0) {
totalSlots -= baseSlots * generatorAddresses.length;
for (const generatorAddress of generatorAddresses) {
result[generatorAddress] = baseSlots;
}
}
for (let slotNumber = startSlotNumber; slotNumber < startSlotNumber + totalSlots; slotNumber += 1) {
const slotIndex = slotNumber % generatorAddresses.length;
const generatorAddress = generatorAddresses[slotIndex];
if (Object.prototype.hasOwnProperty.call(result, generatorAddress)) {
result[generatorAddress] += 1;
}
else {
result[generatorAddress] = 1;
}
}
return result;
}
async getValidatorsParams(methodContext) {
return this.stores.get(validators_params_1.ValidatorsParamsStore).get(methodContext, constants_1.EMPTY_KEY);
}
async setValidatorsParams(methodContext, validatorSetter, preCommitThreshold, certificateThreshold, validators) {
const validatorsSubStore = this.stores.get(validator_keys_1.ValidatorKeysStore);
const validatorsWithKey = [];
for (const validator of validators) {
const keys = await validatorsSubStore.get(methodContext, validator.address);
validatorsWithKey.push({
...validator,
generatorKey: keys.generatorKey,
blsKey: keys.blsKey,
});
}
await this.stores.get(validators_params_1.ValidatorsParamsStore).set(methodContext, constants_1.EMPTY_KEY, {
certificateThreshold,
preCommitThreshold,
validators: validatorsWithKey,
});
validatorSetter.setNextValidators(preCommitThreshold, certificateThreshold, validatorsWithKey);
}
_validateLengths(args) {
if (args.validatorAddress && args.validatorAddress.length !== constants_1.ADDRESS_LENGTH) {
throw new Error(`Validator address must be ${constants_1.ADDRESS_LENGTH} bytes long.`);
}
if (args.blsKey && args.blsKey.length !== constants_1.BLS_PUBLIC_KEY_LENGTH) {
throw new Error(`BLS public key must be ${constants_1.BLS_PUBLIC_KEY_LENGTH} bytes long.`);
}
if (args.proofOfPossession && args.proofOfPossession.length !== constants_1.BLS_POP_LENGTH) {
throw new Error(`Proof of possesion must be ${constants_1.BLS_POP_LENGTH} bytes long.`);
}
if (args.generatorKey && args.generatorKey.length !== constants_1.ED25519_PUBLIC_KEY_LENGTH) {
throw new Error(`Generator key must be ${constants_1.ED25519_PUBLIC_KEY_LENGTH} bytes long.`);
}
}
}
exports.ValidatorsMethod = ValidatorsMethod;
//# sourceMappingURL=method.js.map
;