UNPKG

lisk-framework

Version:

Lisk blockchain application platform

155 lines 8.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DynamicRewardModule = void 0; const lisk_utils_1 = require("@liskhq/lisk-utils"); const lisk_validator_1 = require("@liskhq/lisk-validator"); const base_module_1 = require("../base_module"); const constants_1 = require("./constants"); const constants_2 = require("../reward/constants"); const state_machine_1 = require("../../state_machine"); const method_1 = require("./method"); const endpoint_1 = require("./endpoint"); const schemas_1 = require("./schemas"); const reward_minted_1 = require("../reward/events/reward_minted"); const end_of_round_timestamp_1 = require("./stores/end_of_round_timestamp"); const calculate_reward_1 = require("../reward/calculate_reward"); const schemas_2 = require("../reward/schemas"); const utils_1 = require("./utils"); class DynamicRewardModule extends base_module_1.BaseModule { constructor() { super(); this.method = new method_1.DynamicRewardMethod(this.stores, this.events); this.configSchema = schemas_1.configSchema; this.endpoint = new endpoint_1.DynamicRewardEndpoint(this.stores, this.offchainStores); this.stores.register(end_of_round_timestamp_1.EndOfRoundTimestampStore, new end_of_round_timestamp_1.EndOfRoundTimestampStore(this.name, 0)); this.events.register(reward_minted_1.RewardMintedEvent, new reward_minted_1.RewardMintedEvent(this.name)); } addDependencies(tokenMethod, randomMethod, validatorMethod, posMethod) { this._tokenMethod = tokenMethod; this._randomMethod = randomMethod; this._validatorMethod = validatorMethod; this._posMethod = posMethod; this.endpoint.addDependencies(this._validatorMethod, this._posMethod); } metadata() { return { ...this.baseMetadata(), endpoints: [ { name: this.endpoint.getDefaultRewardAtHeight.name, request: schemas_2.getDefaultRewardAtHeightRequestSchema, response: schemas_2.getDefaultRewardAtHeightResponseSchema, }, { name: this.endpoint.getAnnualInflation.name, request: schemas_2.getAnnualInflationRequestSchema, response: schemas_2.getAnnualInflationResponseSchema, }, { name: this.endpoint.getRewardTokenID.name, response: schemas_2.getRewardTokenIDResponseSchema, }, { name: this.endpoint.getExpectedValidatorRewards.name, request: schemas_1.getExpectedValidatorRewardsRequestSchema, response: schemas_1.getExpectedValidatorRewardsResponseSchema, }, ], }; } async init(args) { const { moduleConfig } = args; const config = lisk_utils_1.objects.mergeDeep({}, { ...constants_1.defaultConfig, tokenID: `${args.genesisConfig.chainID}00000000`, }, moduleConfig); lisk_validator_1.validator.validate(schemas_1.configSchema, config); this._moduleConfig = { ...config, brackets: config.brackets.map(bracket => BigInt(bracket)), rewardReductionFactorBFT: BigInt(config.rewardReductionFactorBFT), tokenID: Buffer.from(config.tokenID, 'hex'), }; this.method.init({ config: this._moduleConfig }); this.endpoint.init(this._moduleConfig, args.genesisConfig.blockTime); } async initGenesisState(context) { await this.stores .get(end_of_round_timestamp_1.EndOfRoundTimestampStore) .set(context, constants_1.EMPTY_BYTES, { timestamp: context.header.timestamp }); } async beforeTransactionsExecute(context) { const defaultReward = await this._getDefaultBlockReward(context.getMethodContext(), context.header); const [blockReward, reduction] = await this._getBlockRewardDeduction(context.getMethodContext(), context.header, context.assets, defaultReward); context.contextStore.set(constants_1.CONTEXT_STORE_KEY_DYNAMIC_BLOCK_REWARD, blockReward); context.contextStore.set(constants_1.CONTEXT_STORE_KEY_DYNAMIC_BLOCK_REDUCTION, reduction); } async afterTransactionsExecute(context) { let blockReward = (0, state_machine_1.getContextStoreBigInt)(context.contextStore, constants_1.CONTEXT_STORE_KEY_DYNAMIC_BLOCK_REWARD); let reduction = (0, state_machine_1.getContextStoreNumber)(context.contextStore, constants_1.CONTEXT_STORE_KEY_DYNAMIC_BLOCK_REDUCTION); if (blockReward !== BigInt(0)) { const userSubstoreExists = await this._tokenMethod.userSubstoreExists(context, context.header.generatorAddress, this._moduleConfig.tokenID); if (userSubstoreExists) { await this._tokenMethod.mint(context.getMethodContext(), context.header.generatorAddress, this._moduleConfig.tokenID, blockReward); await this._posMethod.updateSharedRewards(context.getMethodContext(), context.header.generatorAddress, this._moduleConfig.tokenID, blockReward); } else { blockReward = BigInt(0); reduction = constants_2.REWARD_REDUCTION_NO_ACCOUNT; } } const isEndOfRound = await this._posMethod.isEndOfRound(context.getMethodContext(), context.header.height); if (isEndOfRound) { await this.stores .get(end_of_round_timestamp_1.EndOfRoundTimestampStore) .set(context, constants_1.EMPTY_BYTES, { timestamp: context.header.timestamp }); } this.events.get(reward_minted_1.RewardMintedEvent).log(context, context.header.generatorAddress, { amount: blockReward, reduction, }); } async _getBlockRewardDeduction(context, header, assets, defaultReward) { const isSeedRevealValid = await this._randomMethod.isSeedRevealValid(context, header.generatorAddress, assets); if (!isSeedRevealValid) { return [BigInt(0), constants_2.REWARD_REDUCTION_SEED_REVEAL]; } if (!header.impliesMaxPrevotes) { return [ defaultReward / this._moduleConfig.rewardReductionFactorBFT, constants_2.REWARD_REDUCTION_MAX_PREVOTES, ]; } return [defaultReward, constants_2.REWARD_NO_REDUCTION]; } async _getDefaultBlockReward(context, header) { const roundLength = this._posMethod.getRoundLength(context); const { timestamp } = await this.stores.get(end_of_round_timestamp_1.EndOfRoundTimestampStore).get(context, constants_1.EMPTY_BYTES); const generatorsMap = await this._validatorMethod.getGeneratorsBetweenTimestamps(context, timestamp, header.timestamp); const defaultReward = (0, calculate_reward_1.calculateDefaultReward)(this._moduleConfig, header.height); const minimalRewardActiveValidators = (0, utils_1.getMinimalRewardActiveValidators)(this._moduleConfig, defaultReward); if (Object.keys(generatorsMap).length >= roundLength) { return minimalRewardActiveValidators; } const validatorsParams = await this._validatorMethod.getValidatorsParams(context); let bftWeightSum = BigInt(0); let bftValidator; for (const v of validatorsParams.validators) { bftWeightSum += v.bftWeight; if (v.address.equals(header.generatorAddress)) { bftValidator = v; } } if (!bftValidator) { throw new Error('Invalid generator. Validator params does not include the validator.'); } const stakeRewardActiveValidators = await (0, utils_1.getStakeRewardActiveValidators)(context, this._validatorMethod, defaultReward, minimalRewardActiveValidators); if (bftValidator.bftWeight > BigInt(0)) { return (minimalRewardActiveValidators + (bftValidator.bftWeight * stakeRewardActiveValidators) / bftWeightSum); } return defaultReward; } } exports.DynamicRewardModule = DynamicRewardModule; //# sourceMappingURL=module.js.map